GDB主要帮助你完成下面四个方面的功能:1、启动你的程序,可以按照你的自定义的要求随心所欲的运行程序。2、可让被调试的程序在你所指定的调置的断点处停住。(断点可以是条件表达式)3、当程序被停住时,可以检查此时你的程序中所发生的事。4、你可以改变你的程序,将一个BUG产生的影响修正从而测试其他BUG。
在学习Oracle的时候使用GDB调试,主要是关于学习Oracle的闩锁原理,那么,为什么要用GDB调试MySQL1.识别故障2.场景重现3.创建测试案例确认BUG4.定位缺陷根源5.测试和创建补丁修复BUG
下面开始学习GDB调试MySQL1、安装编译MySQL需要的软件包yum install -y cmake make gcc gcc-c++ ncurses-devel bison gdb
2、编译MySQL# git clone https://github.com/mysql/mysql-server.git# cd mysql-server# git checkout mysql-5.7.19# cd BUILD; cmake .. -DDOWNLOAD_BOOST=1 -DWITH_DEBUG=1 -DWITH_UNIT_TESTS=off# make# make install
3、连接MySQL程序3.1、查看MySQL进程ID[root@debug ~]# ps -ef | grep mysqlroot2458910 07:58 ?00:00:00 /bin/sh /usr/local/mysql/bin/mysqld_safe --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data --user=mysqlmysql24794 245890 07:58 ?00:00:01 /usr/local/mysql/bin/mysqld --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data --plugin-dir=/usr/local/mysql/lib/plugin --user=mysql --log-error=/usr/local/mysql/data/mysql-debug.log --pid-file=debug.pid --socket=/tmp/mysql.sock --port=3306root25009 249930 11:29 pts/200:00:00 grep mysql
3.2、GDB使用attach连接MySQL进程ID[root@debug ~]# gdbGNU gdb (GDB) Red Hat Enterprise Linux (7.2-92.el6)Copyright (C) 2010 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>This is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law.Type "show copying"and "show warranty" for details.This GDB was configured as "x86_64-redhat-linux-gnu".For bug reporting instructions, please see:<http://www.gnu.org/software/gdb/bugs/>.(gdb) attach 24794Attaching to process 24794Reading symbols from /usr/local/mysql/bin/mysqld...done.Reading symbols from /lib64/libpthread.so.0...(no debugging symbols found)...done.[New LWP 24969][New LWP 24824][New LWP 24821][New LWP 24820][New LWP 24819][New LWP 24818][New LWP 24817][New LWP 24816][New LWP 24815][New LWP 24814][New LWP 24813][New LWP 24812][New LWP 24811][New LWP 24810][New LWP 24809][New LWP 24808][New LWP 24806][New LWP 24805][New LWP 24804][New LWP 24803][New LWP 24802][New LWP 24801][New LWP 24800][New LWP 24799][New LWP 24798][New LWP 24797][New LWP 24796][New LWP 24795][Thread debugging using libthread_db enabled]Loaded symbols for /lib64/libpthread.so.0Reading symbols from /lib64/libcrypt.so.1...(no debugging symbols found)...done.Loaded symbols for /lib64/libcrypt.so.1Reading symbols from /lib64/libdl.so.2...(no debugging symbols found)...done.Loaded symbols for /lib64/libdl.so.2Reading symbols from /lib64/librt.so.1...(no debugging symbols found)...done.Loaded symbols for /lib64/librt.so.1Reading symbols from /usr/lib64/libstdc++.so.6...(no debugging symbols found)...done.Loaded symbols for /usr/lib64/libstdc++.so.6Reading symbols from /lib64/libm.so.6...(no debugging symbols found)...done.Loaded symbols for /lib64/libm.so.6Reading symbols from /lib64/libgcc_s.so.1...(no debugging symbols found)...done.Loaded symbols for /lib64/libgcc_s.so.1Reading symbols from /lib64/libc.so.6...(no debugging symbols found)...done.Loaded symbols for /lib64/libc.so.6Reading symbols from /lib64/ld-linux-x86-64.so.2...(no debugging symbols found)...done.Loaded symbols for /lib64/ld-linux-x86-64.so.2Reading symbols from /lib64/libfreebl3.so...(no debugging symbols found)...done.Loaded symbols for /lib64/libfreebl3.soReading symbols from /lib64/libnss_files.so.2...(no debugging symbols found)...done.Loaded symbols for /lib64/libnss_files.so.20x00007f8801dfd383 in poll () from /lib64/libc.so.6Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.209.el6_9.2.x86_64 libgcc-4.4.7-18.el6.x86_64 libstdc++-4.4.7-18.el6.x86_64 nss-softokn-freebl-3.14.3-23.el6_7.x86_64
4、设置断点4.1、查看插入语句的源码sql_insert.cc的423行的函数Sql_cmd_insert::mysql_insertbool Sql_cmd_insert::mysql_insert(THD *thd,TABLE_LIST *table_list) {DBUG_ENTER("mysql_insert");
LEX *const lex= thd->lex;int error, res;bool err= true;bool transactional_table, joins_freed= FALSE;bool changed;bool is_locked= false;ulong counter= 0;ulonglong id;
4.2、在session1中的gdb设置insert的断点(gdb) b Sql_cmd_insert::mysql_insertBreakpoint 1 at 0x17bd1b9: file /root/mysql-server/sql/sql_insert.cc, line 423.
4.3、查看断点信息,从下往上看,使用到了多个MySQL函数。(gdb) bt#00x00007f8801dfd383 in poll () from /lib64/libc.so.6#10x00000000016c1155 in Mysqld_socket_listener::listen_for_connection_event (this=0x45d8870)at /root/mysql-server/sql/conn_handler/socket_connection.cc:852#20x0000000000ece89c in Connection_acceptor<Mysqld_socket_listener>::connection_event_loop (this=0x45b5ec0)at /root/mysql-server/sql/conn_handler/connection_acceptor.h:66#30x0000000000ec6226 in mysqld_main (argc=17, argv=0x3ab4248) at /root/mysql-server/sql/mysqld.cc:5045#40x0000000000ebd2d4 in main (argc=9, argv=0x7fffb2aa7408) at /root/mysql-server/sql/main.cc:25
4.4、在设置了断点之后,在另一个session2中登录数据库,发现无法登录,hung住了,在gdb中执行next(执行下一步代码),可以看到在socket_connection.cc源码第859行无法继续,代码大致是说要获取系统的socket,还有一些监听信息,由于太多了,直接在gdb中执行continue(到下一个可执行的代码),此时session2已经登录成功。(gdb) nSingle stepping until exit from function poll,which has no line number information.Mysqld_socket_listener::listen_for_connection_event (this=0x45d8870) at /root/mysql-server/sql/conn_handler/socket_connection.cc:859859if (retval < 0 && socket_errno != SOCKET_EINTR)(gdb) n871if (retval < 0 || abort_loop)(gdb) n876MYSQL_SOCKET listen_sock= MYSQL_INVALID_SOCKET;(gdb) n877bool is_unix_socket= false;(gdb) n879for (uint i= 0; i < m_socket_map.size(); ++i)(gdb) n881if (m_poll_info.m_fds[i].revents & POLLIN)(gdb) n879for (uint i= 0; i < m_socket_map.size(); ++i)(gdb) n881if (m_poll_info.m_fds[i].revents & POLLIN)(gdb) n883listen_sock= m_poll_info.m_pfs_fds[i];(gdb) n884is_unix_socket= m_socket_map[listen_sock];(gdb) n885break;(gdb) n904for (uint retry= 0; retry < MAX_ACCEPT_RETRY; retry++)(gdb) n906socket_len_t length= sizeof(struct sockaddr_storage);(gdb) n908(struct sockaddr *)(&cAddr), &length);(gdb) n909if (mysql_socket_getfd(connect_sock) != INVALID_SOCKET ||(gdb) n… ...(gdb) cContinuing.
4.5、session2此时的select操作都是一切正常的[root@localhost:(none)][11:41:15am] MySQL-> use test;Reading table information for completion of table and column namesYou can turn off this feature to get a quicker startup with -A
Database changed[root@localhost:test][11:49:12am] MySQL-> show tables;+----------------+| Tables_in_test |+----------------+| t|| t1|+----------------+2 rows in set (0.00 sec)
[root@localhost:test][11:49:16am] MySQL-> select * from t;+------+------+| id| name |+------+------+|1 | aaa||2 | aaa||3 | aaa||4 | aaa|+------+------+4 rows in set (0.00 sec)
4.6、session2做insert操作的时候,又一次hung住了,session1打印出了断点的信息,在mysql_insert:423行,直到执行continue,session2才能正常插入数据。(gdb) cContinuing.[Switching to Thread 0x7f87e00b4700 (LWP 24824)]
Breakpoint 1, Sql_cmd_insert::mysql_insert (this=0x7f87f40147b8, thd=0x7f87f401bc60, table_list=0x7f87f4013fe0)at /root/mysql-server/sql/sql_insert.cc:423423DBUG_ENTER("mysql_insert");(gdb) n425LEX *const lex= thd->lex;(gdb) n427bool err= true;(gdb) cContinuing.