利用GDB调试 MSQL(2)

简介: 利用GDB调试 MSQL

6. 数据库插入

插入操作前,切换schema和查询都是没问题的:

mysql> use gdb
Database changed
mysql> show tables;
+---------------+
| Tables_in_gdb |
+---------------+
| test          |
+---------------+
1 row in set (0.00 sec)
mysql> select * from test;
+------+
| id   |
+------+
|    1 |
|    2 |
+------+
2 rows in set (0.00 sec)

插入一条 id=3 的数据,出现了等待:

  1. mysql> insert into test values (3);

7. 分析断点信息

断点触发,如下:

(gdb) c

Continuing.
[Switching to Thread 0x2b15faf02700 (LWP 21617)]
Breakpoint 1, Sql_cmd_insert::mysql_insert (this=0x2b1614008348, thd=0x2b1614003af0, table_list=0x2b1614007db8) at /gdb/mysql-5.7.25/sql/sql_insert.cc:423
423 DBUG_ENTER("mysql_insert");

bt 命令展示栈帧:

(gdb) bt
#0 Sql_cmd_insert::mysql_insert (this=0x2b1614008348, thd=0x2b1614003af0, table_list=0x2b1614007db8) at /gdb/mysql-5.7.25/sql/sql_insert.cc:423
#1 0x000000000176256e in Sql_cmd_insert::execute (this=0x2b1614008348, thd=0x2b1614003af0) at /gdb/mysql-5.7.25/sql/sql_insert.cc:3118
#2 0x000000000153b093 in mysql_execute_command (thd=0x2b1614003af0, first_level=true) at /gdb/mysql-5.7.25/sql/sql_parse.cc:3596
#3 0x0000000001540820 in mysql_parse (thd=0x2b1614003af0, parser_state=0x2b15faf01690) at /gdb/mysql-5.7.25/sql/sql_parse.cc:5570
#4 0x0000000001536131 in dispatch_command (thd=0x2b1614003af0, com_data=0x2b15faf01df0, command=COM_QUERY) at /gdb/mysql-5.7.25/sql/sql_parse.cc:1484
#5 0x0000000001534f9a in do_command (thd=0x2b1614003af0) at /gdb/mysql-5.7.25/sql/sql_parse.cc:1025
#6 0x00000000016658dc in handle_connection (arg=0x39610f0) at /gdb/mysql-5.7.25/sql/conn_handler/connection_handler_per_thread.cc:306
#7 0x0000000001ced592 in pfs_spawn_thread (arg=0x5508e50) at /gdb/mysql-5.7.25/storage/perfschema/pfs.cc:2190
#8 0x00002b15cd699e25 in start_thread () from /lib64/libpthread.so.0
#9 0x00002b15ce80ebad in clone () from /lib64/libc.so.6

接下来输入 n 会逐行输出,我们这里直接 continue,阻塞的 insert 也完成了:

mysql> insert into test values (3);
Query OK, 1 row affected (2 min 49.57 sec)

发布一个特殊版本的mysql

有些函数所在源码的位置比较好理解,比如上面的 insert 功能,或者 delete 功能。是不是可以通过修改 delete 函数,打包一个数据永不会被删除的 mysql 呢?

定位函数位置

先追踪mysql进程:

(gdb) attach 21357
Attaching to process 21357
Reading symbols from /gdb/mysql/bin/mysqld...done.
Reading symbols from /lib64/libpthread.so.0...(no debugging symbols found)...done.
[New LWP 5584]
[New LWP 5583]
[New LWP 21617]
[New LWP 21387]
[New LWP 21386]
[New LWP 21384]
[New LWP 21383]
[New LWP 21382]
[New LWP 21381]
[New LWP 21380]
[New LWP 21379]
[New LWP 21378]
[New LWP 21377]
[New LWP 21376]
[New LWP 21375]
[New LWP 21374]
[New LWP 21373]
[New LWP 21369]
[New LWP 21368]
[New LWP 21367]
[New LWP 21366]
[New LWP 21365]
[New LWP 21364]
[New LWP 21363]
[New LWP 21362]
[New LWP 21361]
[New LWP 21360]
[New LWP 21359]
[New LWP 21358]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Loaded symbols for /lib64/libpthread.so.0
Reading symbols from /lib64/libcrypt.so.1...(no debugging symbols found)...done.
Loaded symbols for /lib64/libcrypt.so.1
Reading symbols from /lib64/libdl.so.2...(no debugging symbols found)...done.
Loaded symbols for /lib64/libdl.so.2
Reading symbols from /lib64/librt.so.1...(no debugging symbols found)...done.
Loaded symbols for /lib64/librt.so.1
Reading symbols from /lib64/libstdc++.so.6...(no debugging symbols found)...done.
Loaded symbols for /lib64/libstdc++.so.6
Reading symbols from /lib64/libm.so.6...(no debugging symbols found)...done.
Loaded symbols for /lib64/libm.so.6
Reading symbols from /lib64/libgcc_s.so.1...(no debugging symbols found)...done.
Loaded symbols for /lib64/libgcc_s.so.1
Reading symbols from /lib64/libc.so.6...(no debugging symbols found)...done.
Loaded symbols for /lib64/libc.so.6
Reading symbols from /lib64/ld-linux-x86-64.so.2...(no debugging symbols found)...done.
Loaded symbols for /lib64/ld-linux-x86-64.so.2
Reading symbols from /lib64/libfreebl3.so...Reading symbols from /lib64/libfreebl3.so...(no debugging symbols found)...done.
(no debugging symbols found)...done.
Loaded symbols for /lib64/libfreebl3.so
Reading symbols from /lib64/libnss_files.so.2...(no debugging symbols found)...done.
Loaded symbols for /lib64/libnss_files.so.2
Reading symbols from /lib64/libnss_sss.so.2...Reading symbols from /lib64/libnss_sss.so.2...(no debugging symbols found)...done.
(no debugging symbols found)...done.
Loaded symbols for /lib64/libnss_sss.so.2
0x00002b15ce803f0d in poll () from /lib64/libc.so.6
Missing separate debuginfos, use: debuginfo-install glibc-2.17-222.el7.x86_64 libgcc-4.8.5-39.el7.x86_64 libstdc++-4.8.5-39.el7.x86_64 nss-softokn-freebl-3.34.0-2.el7.x86_64 sssd-client-1.16.0-19.el7.x86_64

delete函数这里打上断点:

(gdb) b Sql_cmd_delete::mysql_delete
Breakpoint 1 at 0x175198b: file /gdb/mysql-5.7.25/sql/sql_delete.cc, line 50.

数据库执行delete语句触发断点:

mysql> delete from test where id =3;

gbk断点信息:

Breakpoint 1, Sql_cmd_delete::mysql_delete (this=0x2b16040020c8, thd=0x2b1604007e30, limit=18446744073709551615) at /gdb/mysql-5.7.25/sql/sql_delete.cc:50
50 DBUG_ENTER("mysql_delete");

查看相关栈帧:

#0  Sql_cmd_delete::mysql_delete (this=0x2b16040020c8, thd=0x2b1604007e30, limit=18446744073709551615) at /gdb/mysql-5.7.25/sql/sql_delete.cc:50
#1 0x0000000001755cc6 in Sql_cmd_delete::execute (this=0x2b16040020c8, thd=0x2b1604007e30) at /gdb/mysql-5.7.25/sql/sql_delete.cc:1392
#2 0x000000000153b12f in mysql_execute_command (thd=0x2b1604007e30, first_level=true) at /gdb/mysql-5.7.25/sql/sql_parse.cc:3606
#3 0x0000000001540820 in mysql_parse (thd=0x2b1604007e30, parser_state=0x2b15faf43690) at /gdb/mysql-5.7.25/sql/sql_parse.cc:5570
#4 0x0000000001536131 in dispatch_command (thd=0x2b1604007e30, com_data=0x2b15faf43df0, command=COM_QUERY) at /gdb/mysql-5.7.25/sql/sql_parse.cc:1484
#5 0x0000000001534f9a in do_command (thd=0x2b1604007e30) at /gdb/mysql-5.7.25/sql/sql_parse.cc:1025
#6 0x00000000016658dc in handle_connection (arg=0x54b6510) at /gdb/mysql-5.7.25/sql/conn_handler/connection_handler_per_thread.cc:306
#7 0x0000000001ced592 in pfs_spawn_thread (arg=0x5508e50) at /gdb/mysql-5.7.25/storage/perfschema/pfs.cc:2190
#8 0x00002b15cd699e25 in start_thread () from /lib64/libpthread.so.0
#9 0x00002b15ce80ebad in clone () from /lib64/libc.so.6

修改源码

可以看到 #1 是 Sql_cmd_delete::execute ,这个就是 delete 处理的函数,去源代码中找到相应函数:

把正真实现删除逻辑的代码给注释掉,返回的 res 值直接赋成 true:

  1. bool Sql_cmd_delete::execute(THD thd)
  2. {
  3. DBUG_ASSERT(thd->lex->sql_command == SQLCOM_DELETE);

  4. LEX const lex= thd->lex;
  5. SELECT_LEX const select_lex= lex->select_lex;
  6. SELECT_LEX_UNIT const unit= lex->unit;
  7. TABLE_LIST const first_table= select_lex->get_table_list();
  8. TABLE_LIST const all_tables= first_table;

  9. if (delete_precheck(thd, all_tables))
  10. return true;
  11. DBUG_ASSERT(select_lex->offset_limit == 0);
  12. unit->set_limit(select_lex);

  13. / Push ignore / strict error handler /
  14. Ignore_error_handler ignore_handler;
  15. Strict_error_handler strict_handler;
  16. if (thd->lex->is_ignore())
  17. thd->push_internal_handler(&ignore_handler);
  18. else if (thd->is_strict_mode())
  19. thd->push_internal_handler(&strict_handler);

  20. /注释以下删除逻辑的代码/
  21. /
  22. MYSQL_DELETE_START(const_cast<char>(thd->query().str));
  23. bool res = mysql_delete(thd, unit->select_limit_cnt);
  24. MYSQL_DELETE_DONE(res, (ulong) thd->get_row_count_func());
  25. /

  26. /直接返回true/
  27. bool res =true;

  28. / Pop ignore / strict error handler */
  29. if (thd->lex->is_ignore() || thd->is_strict_mode())
  30. thd->pop_internal_handler();

  31. return res;
  32. }

然后上文的方法去重新编译mysql,启动后就会发现delete语句无法删除数据了。

调试总结

如果想深入学习源码,就可以从栈帧出发,但是这是基于知道函数接口功能的前提下进行的,如果不知道某个功能会调用什么函数,断点调试就很难进行了。

直接去读完 mysql 所有源码,成本太高,而且 mysql 的代码结构并不友好,耗时耗力不值得。最好的方案还是遇到问题时或针对特殊的一个功能点按需去寻找函数入口,然后逐步深入分析。

希望这篇文章可以帮到想接触mysql源码调试的同学,以后我遇到特殊的问题也会通过gdb去调试涉及的相关函数,大家可以持续关注~


全文完。


Enjoy MySQL :)

            </div>
相关实践学习
阿里云图数据库GDB入门与应用
图数据库(Graph Database,简称GDB)是一种支持Property Graph图模型、用于处理高度连接数据查询与存储的实时、可靠的在线数据库服务。它支持Apache TinkerPop Gremlin查询语言,可以帮您快速构建基于高度连接的数据集的应用程序。GDB非常适合社交网络、欺诈检测、推荐引擎、实时图谱、网络/IT运营这类高度互连数据集的场景。 GDB由阿里云自主研发,具备如下优势: 标准图查询语言:支持属性图,高度兼容Gremlin图查询语言。 高度优化的自研引擎:高度优化的自研图计算层和存储层,云盘多副本保障数据超高可靠,支持ACID事务。 服务高可用:支持高可用实例,节点故障迅速转移,保障业务连续性。 易运维:提供备份恢复、自动升级、监控告警、故障切换等丰富的运维功能,大幅降低运维成本。 产品主页:https://www.aliyun.com/product/gdb
相关文章
|
NoSQL 算法 安全
Redlock 算法-主从redis分布式锁主节点宕机锁丢失的问题
Redlock 算法-主从redis分布式锁主节点宕机锁丢失的问题
738 0
|
机器学习/深度学习 算法 数据可视化
深度解读DBSCAN聚类算法:技术与实战全解析
深度解读DBSCAN聚类算法:技术与实战全解析
2851 0
|
开发者
「代码强迫症?」从0到1实现项目代码拼写检查 vscode 插件:project-spell-checker(一)
「代码强迫症?」从0到1实现项目代码拼写检查 vscode 插件:project-spell-checker(一)
556 0
|
Cloud Native 前端开发 JavaScript
前端开发者必看:不懂云原生你就OUT了!揭秘如何用云原生技术提升项目部署与全栈能力
【10月更文挑战第23天】随着云计算的发展,云原生逐渐成为技术热点。前端开发者了解云原生有助于提升部署与运维效率、实现微服务化、掌握全栈开发能力和利用丰富技术生态。本文通过示例代码介绍云原生在前端项目中的应用,帮助开发者更好地理解其重要性。
377 0
|
存储 前端开发
Flutter Provider状态管理---MVVM架构实战
Flutter Provider状态管理—MVVM架构实战 在Flutter中,状态管理是一个非常重要的概念。Flutter Provider是一种状态管理的解决方案,它提供了一种简单,灵活和高效的方法来管理Flutter应用程序中的状态。本文将详细介绍Flutter Provider的使用,以及如何在MVVM架构中使用它。
796 0
|
机器学习/深度学习 人工智能 自然语言处理
探索软件测试中的人工智能应用
在数字化时代的浪潮下,软件测试领域正经历着一场由人工智能(AI)引领的变革。本文将深入探讨AI如何在软件测试中扮演关键角色,从自动化测试脚本的智能生成到缺陷预测模型的构建,再到测试用例的优化与管理,AI技术正在逐步提高测试效率,减少人力成本,并增强测试的全面性和准确性。文章将通过实例分析,阐述AI在软件测试中的应用现状和未来趋势,为测试工程师提供新的视角和工具,以适应不断变化的技术环境。
|
人工智能 算法 数据可视化
智慧停车场车位引导及反向寻车解决方案
智慧停车场导航系统结合了先进的室内定位技术和导航算法,旨在解决大型公共场所停车难、找车难等问题。系统不仅提供精准的停车引导、反向寻车及停车场内导航服务,还通过大数据分析优化停车场管理和用户体验,是提升现代城市智能化水平的重要组成部分。
1431 0
|
存储 前端开发 JavaScript
|
存储 Java API
Android即时通讯设计——腾讯IM接入和WebSocket接入
之前项目的群聊是用数据库直接操作的,体验很差,消息很难即时反馈,所以最后考虑到了使用腾讯的IM完成群聊的接入,不过中途还是有点小坎坷的,接入完成之后发现体验版一个群聊只有20人,当时看到体验版支持100个用户也就忍了,现在一个群聊只能20用户,忍不了了,所以暂时找到了**WebSocket**作为临时的解决方案(等有钱了再换),同时支持50个用户在线聊天,也算还行,勉强够用,下面就介绍两种实现方案的接入,正文即将开始~~
789 0
Android即时通讯设计——腾讯IM接入和WebSocket接入
|
存储 并行计算 网络协议
PyTorch并行与分布式(二)分布式通信包torch.distributed
PyTorch并行与分布式(二)分布式通信包torch.distributed
1333 0