MySQL代码学习第二——用gdb简单跟踪

上文已经编译安装了一份MySQL8.0.15,也初始化完成了。

古雷:MySQL代码学习第一——MySQL8.0.15源码编译zhuanlan.zhihu.com《MySQL代码学习第二——用gdb简单跟踪》

可以开始走走看看了。

因为编译安装了GCC的关系,还是少不了这个

export LD_LIBRARY_PATH=/usr/local/gcc-5.5.0/lib64

[root@localhost ~]# export LD_LIBRARY_PATH=/usr/local/gcc-5.5.0/lib64
[root@localhost ~]# cd /usr/local/mysql80/bin/
[root@localhost bin]# gdb mysqld
GNU gdb (GDB) Red Hat Enterprise Linux (7.2-90.el6)
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <GNU General Public License>
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:
<Bugs in GDB>...
Reading symbols from /usr/local/mysql80/bin/mysqld...done.
(gdb) 

这就成功进入gdb了,激动地用 l 命令看一下代码(不输入命令时回车键表示继续上一命令)。l 后面可以跟行号、函数名等等。

(gdb) l
1	/* Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
2	
3	   This program is free software; you can redistribute it and/or modify
4	   it under the terms of the GNU General Public License, version 2.0,
5	   as published by the Free Software Foundation.
6	
7	   This program is also distributed with certain software (including
8	   but not limited to OpenSSL) that is licensed under separate terms,
9	   as designated in a particular file or component or in included license
10	   documentation.  The authors of MySQL hereby grant you an additional
(gdb) 
11	   permission to link the program and your derivative works with the
12	   separately licensed software that they have included with MySQL.
13	
14	   This program is distributed in the hope that it will be useful,
15	   but WITHOUT ANY WARRANTY; without even the implied warranty of
16	   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17	   GNU General Public License, version 2.0, for more details.
18	
19	   You should have received a copy of the GNU General Public License
20	   along with this program; if not, write to the Free Software
(gdb) 
21	   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
22	
23	extern int mysqld_main(int argc, char **argv);
24	
25	int main(int argc, char **argv) { return mysqld_main(argc, argv); }
(gdb) l mysqld_main
5754	#ifdef _WIN32
5755	int win_main(int argc, char **argv)
5756	#else
5757	int mysqld_main(int argc, char **argv)
5758	#endif
5759	{
5760	  // Substitute the full path to the executable in argv[0]
5761	  substitute_progpath(argv);
5762	  sysd::notify_connect();
5763	  sysd::notify("STATUS=SERVER_BOOTING\n");
(gdb) 
5764	
5765	  /*
5766	    Perform basic thread library and malloc initialization,
5767	    to be able to read defaults files and parse options.
5768	  */
5769	  my_progname = argv[0];
5770	
5771	#ifndef _WIN32
5772	#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE
5773	  pre_initialize_performance_schema();

如果是第一次用gdb,或者是第一次开始看MySQL代码,肯定会有点小激动的。

一路 l 下去,这个函数好长好长,mysqld 启动真是干了不少事情。终于,看起来是启动完毕,等待连接了。

6728	
6729	  mysqld_socket_acceptor->connection_event_loop();

来设个断点

(gdb) b 6729
Breakpoint 1 at 0x2f044e5: file /data/source/mysql-8.0.15/sql/mysqld.cc, line 6729.
(gdb) info b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x0000000002f044e5 /data/source/mysql-8.0.15/sql/mysqld.cc:6729

运行一下

(gdb) r --defaults-file=/data/mysql8015/my.cnf
Starting program: /usr/local/mysql80/bin/mysqld --defaults-file=/data/mysql8015/my.cnf
[Thread debugging using libthread_db enabled]
warning: File "/usr/local/gcc-5.5.0/lib64/libstdc++.so.6.0.21-gdb.py" auto-loading has been declined by your `auto-load safe-path' set to "/usr/share/gdb/auto-load:/usr/lib/debug:/usr/bin/mono-gdb.py".
To enable execution of this file add
	add-auto-load-safe-path /usr/local/gcc-5.5.0/lib64/libstdc++.so.6.0.21-gdb.py
line to your configuration file "/root/.gdbinit".
To completely disable this security protection add
	set auto-load safe-path /
line to your configuration file "/root/.gdbinit".
For more information about this security protection see the
"Auto-loading safe path" section in the GDB manual.  E.g., run from the shell:
	info "(gdb)Auto-loading safe path"
[New Thread 0x7fffe62c9700 (LWP 36499)]
[New Thread 0x7fffe5440700 (LWP 36500)]
[Thread 0x7fffe5440700 (LWP 36500) exited]
[New Thread 0x7fffe5440700 (LWP 36501)]
[New Thread 0x7fffdffff700 (LWP 36502)]
[New Thread 0x7fffdf5fe700 (LWP 36503)]
[New Thread 0x7fffdebfd700 (LWP 36504)]
[New Thread 0x7fffc7fff700 (LWP 36505)]
[New Thread 0x7fffde1fc700 (LWP 36506)]
[New Thread 0x7fffdd7fb700 (LWP 36507)]
[New Thread 0x7fffdcdfa700 (LWP 36508)]
[New Thread 0x7fffcf9af700 (LWP 36509)]
[New Thread 0x7fffcefae700 (LWP 36510)]
[New Thread 0x7fffce5ad700 (LWP 36511)]
[New Thread 0x7fffc65fd700 (LWP 36512)]
[New Thread 0x7fffc5bfc700 (LWP 36513)]
[New Thread 0x7fffc51fb700 (LWP 36514)]
[New Thread 0x7fff9bfff700 (LWP 36515)]
[New Thread 0x7fff9b5fe700 (LWP 36516)]
[New Thread 0x7fff9abfd700 (LWP 36517)]
[New Thread 0x7fff9a1fc700 (LWP 36518)]
[New Thread 0x7fff997fb700 (LWP 36519)]
[New Thread 0x7fff98dfa700 (LWP 36520)]
[New Thread 0x7fff77fff700 (LWP 36521)]
[New Thread 0x7fff6f5fe700 (LWP 36522)]
[New Thread 0x7fff775fe700 (LWP 36523)]
[New Thread 0x7fff76bfd700 (LWP 36524)]
[New Thread 0x7fff761fc700 (LWP 36525)]
[Thread 0x7fffe62c9700 (LWP 36499) exited]
[New Thread 0x7fffe47db700 (LWP 36526)]
[New Thread 0x7fffe4795700 (LWP 36527)]
[New Thread 0x7fffe474f700 (LWP 36528)]
[New Thread 0x7fffe4709700 (LWP 36529)]
[New Thread 0x7fffe62c9700 (LWP 36530)]
[Thread 0x7fffe62c9700 (LWP 36530) exited]
[New Thread 0x7fffe62c9700 (LWP 36531)]
[Thread 0x7fffe62c9700 (LWP 36531) exited]
[New Thread 0x7fffe62c9700 (LWP 36532)]
[New Thread 0x7fff757fb700 (LWP 36533)]
[New Thread 0x7fff74dfa700 (LWP 36534)]
[New Thread 0x7fff6ffff700 (LWP 36535)]
[New Thread 0x7fffe46c3700 (LWP 36536)]
[New Thread 0x7fffe467c700 (LWP 36537)]
[New Thread 0x7fff6ebfd700 (LWP 36538)]

Breakpoint 1, mysqld_main(int, char**) () at /data/source/mysql-8.0.15/sql/mysqld.cc:6729
6729	  mysqld_socket_acceptor->connection_event_loop();
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.212.el6.x86_64 keyutils-libs-1.4-5.el6.x86_64 krb5-libs-1.10.3-65.el6.x86_64 libcom_err-1.41.12-24.el6.x86_64 libselinux-2.0.94-7.el6.x86_64 nss-softokn-freebl-3.14.3-23.el6_7.x86_64 openssl-1.0.1e-57.el6.x86_64 zlib-1.2.3-29.el6.x86_64

在断点停下来了。

在另一个终端窗口看一眼日志

[root@localhost ~]# tail -1 /data/mysql8015/datadir/mysqlerror.log 
2019-04-11T08:01:47.302757Z 0 [System] [MY-010931] [Server] /usr/local/mysql80/bin/mysqld: ready for connections. Version: '8.0.15-debug'  socket: '/data/mysql8015/datadir/mysql.sock'  port: 3306  Source distribution.

的确是启动完成,等待连接了。

用n和s到处逛来逛去,有可能会迷路。逛的时候要经常用bt看看逛到哪了,从哪逛过来的。

这是看以前记录的do_command函数,先在do_command设置了断点,再继续逛的。客户端那边要连接进去执行个命令,比如show databases什么的。

(gdb) bt
#0  mysql_parse(THD*, Parser_state*, bool) () at /data/source/mysql-8.0.15/sql/sql_parse.cc:4991
#1  0x00000000030725c5 in dispatch_command(THD*, COM_DATA const*, enum_server_command) () at /data/source/mysql-8.0.15/sql/sql_parse.cc:1715
#2  0x0000000003070b89 in do_command(THD*) () at /data/source/mysql-8.0.15/sql/sql_parse.cc:1263
#3  0x000000000320d420 in handle_connection () at /data/source/mysql-8.0.15/sql/conn_handler/connection_handler_per_thread.cc:305
#4  0x00000000045bf5fb in pfs_spawn_thread () at /data/source/mysql-8.0.15/storage/perfschema/pfs.cc:2836
#5  0x0000003165e07aa1 in start_thread () from /lib64/libpthread.so.0
#6  0x0000003165ae8c4d in clone () from /lib64/libc.so.6

函数名称都是用来帮助理解的。

再跟一阵

(gdb) bt
#0  mysql_execute_command(THD*, bool) () at /data/source/mysql-8.0.15/sql/sql_parse.cc:2560
#1  0x000000000307c504 in mysql_parse(THD*, Parser_state*, bool) () at /data/source/mysql-8.0.15/sql/sql_parse.cc:5105
#2  0x00000000030725c5 in dispatch_command(THD*, COM_DATA const*, enum_server_command) () at /data/source/mysql-8.0.15/sql/sql_parse.cc:1715
#3  0x0000000003070b89 in do_command(THD*) () at /data/source/mysql-8.0.15/sql/sql_parse.cc:1263
#4  0x000000000320d420 in handle_connection () at /data/source/mysql-8.0.15/sql/conn_handler/connection_handler_per_thread.cc:305
#5  0x00000000045bf5fb in pfs_spawn_thread () at /data/source/mysql-8.0.15/storage/perfschema/pfs.cc:2836
#6  0x0000003165e07aa1 in start_thread () from /lib64/libpthread.so.0
#7  0x0000003165ae8c4d in clone () from /lib64/libc.so.6

用p来看变量,结果老报错

(gdb) p lex
No symbol "lex" in current context.
(gdb) p all_tables
No symbol "all_tables" in current context.

有人说要用新版本的gdb,下个源码包,继续编吧

[root@localhost gdb-8.2]# CC=/usr/local/gcc-5.5.0/bin/gcc
[root@localhost gdb-8.2]# CXX=/usr/local/gcc-5.5.0/bin/g++
[root@localhost gdb-8.2]# export CC CXX
[root@localhost gdb-8.2]# export LD_LIBRARY_PATH=/usr/local/gcc-5.5.0/lib64
[root@localhost gdb-8.2]# ./configure --prefix=/usr/local/gdb82
[root@localhost gdb-8.2]# make
[root@localhost gdb-8.2]# make install
[root@localhost gdb-8.2]# ls /usr/local/gdb82/
bin  include  lib  share

环境变量得加上自动配置了,不然每次太累了

[root@localhost ~]# tail -7 .bash_profile 
PATH=/usr/local/gdb82/bin:$PATH:$HOME/bin
export PATH
CC=/usr/local/gcc-5.5.0/bin/gcc
CXX=/usr/local/gcc-5.5.0/bin/g++
export CC CXX
export LD_LIBRARY_PATH=/usr/local/gcc-5.5.0/lib64
 

重新登录,看一下是不是生效了

[root@localhost ~]# which gdb
/usr/local/gdb82/bin/gdb
[root@localhost ~]# echo $CC $CXX $LD_LIBRARY_PATH
/usr/local/gcc-5.5.0/bin/gcc /usr/local/gcc-5.5.0/bin/g++ /usr/local/gcc-5.5.0/lib64

行了,这回不用每次都重新输入环境变量了。再次开启gdb mysqld之旅。注意一开始有个python的错误,需要后面处理一下

[root@localhost ~]# gdb /usr/local/mysql80/bin/mysqld
Python Exception <type 'exceptions.ImportError'> No module named gdb: 
gdb: warning: 
Could not load the Python gdb module from `/usr/local/gdb82/share/gdb/python'.
Limited Python support is available from the _gdb module.
Suggest passing --data-directory=/path/to/gdb/data-directory.

GNU gdb (GDB) 8.2
Copyright (C) 2018 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-pc-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from /usr/local/mysql80/bin/mysqld...done.
(gdb) l do_command
1147	    0  success
1148	  @retval
1149	    1  request of thread shutdown (see dispatch_command() description)
1150	*/
1151	
1152	bool do_command(THD *thd) {
1153	  bool return_value;
1154	  int rc;
1155	  NET *net = NULL;
1156	  enum enum_server_command command;
(gdb) b 1152
Breakpoint 1 at 0x3070759: file /data/source/mysql-8.0.15/sql/sql_parse.cc, line 1155.
(gdb)  r --defaults-file=/data/mysql8015/my.cnf
Starting program: /usr/local/mysql80/bin/mysqld --defaults-file=/data/mysql8015/my.cnf
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
warning: File "/usr/local/gcc-5.5.0/lib64/libstdc++.so.6.0.21-gdb.py" auto-loading has been declined by your `auto-load safe-path' set to "$debugdir:$datadir/auto-load".
To enable execution of this file add
	add-auto-load-safe-path /usr/local/gcc-5.5.0/lib64/libstdc++.so.6.0.21-gdb.py
line to your configuration file "/root/.gdbinit".
To completely disable this security protection add
	set auto-load safe-path /
line to your configuration file "/root/.gdbinit".
For more information about this security protection see the
"Auto-loading safe path" section in the GDB manual.  E.g., run from the shell:
	info "(gdb)Auto-loading safe path"
[New Thread 0x7fffe62c9700 (LWP 15381)]
[New Thread 0x7fffe5440700 (LWP 15382)]
[Thread 0x7fffe5440700 (LWP 15382) exited]
[New Thread 0x7fffe5440700 (LWP 15383)]
[New Thread 0x7fffdffff700 (LWP 15384)]
[New Thread 0x7fffdf5fe700 (LWP 15385)]
[New Thread 0x7fffc7fff700 (LWP 15386)]
[New Thread 0x7fffdebfd700 (LWP 15387)]
[New Thread 0x7fffde1fc700 (LWP 15388)]
[New Thread 0x7fffdd7fb700 (LWP 15389)]
[New Thread 0x7fffdcdfa700 (LWP 15390)]
[New Thread 0x7fffcf9af700 (LWP 15391)]
[New Thread 0x7fffcefae700 (LWP 15392)]
[New Thread 0x7fffce5ad700 (LWP 15393)]
[New Thread 0x7fffc65fd700 (LWP 15394)]
[New Thread 0x7fffc5bfc700 (LWP 15395)]
[New Thread 0x7fffc51fb700 (LWP 15396)]
[New Thread 0x7fff93fff700 (LWP 15397)]
[New Thread 0x7fff935fe700 (LWP 15398)]
[New Thread 0x7fff92bfd700 (LWP 15399)]
[New Thread 0x7fff921fc700 (LWP 15400)]
[Thread 0x7fffc65fd700 (LWP 15394) exited]
[New Thread 0x7fffc65fd700 (LWP 15401)]
[New Thread 0x7fff917fb700 (LWP 15402)]
[New Thread 0x7fff90dfa700 (LWP 15403)]
[New Thread 0x7fff7bfff700 (LWP 15404)]
[New Thread 0x7fff7b5fe700 (LWP 15405)]
[New Thread 0x7fff7abfd700 (LWP 15406)]
[New Thread 0x7fff7a1fc700 (LWP 15407)]
[New Thread 0x7fff797fb700 (LWP 15408)]
[Thread 0x7fffe62c9700 (LWP 15381) exited]
[New Thread 0x7fffe47db700 (LWP 15409)]
[New Thread 0x7fffe4795700 (LWP 15410)]
[New Thread 0x7fffe474f700 (LWP 15411)]
[New Thread 0x7fffe4709700 (LWP 15412)]
[New Thread 0x7fffe62c9700 (LWP 15413)]
[Thread 0x7fffe62c9700 (LWP 15413) exited]
[New Thread 0x7fffe62c9700 (LWP 15414)]
[Thread 0x7fffe62c9700 (LWP 15414) exited]
[New Thread 0x7fffe62c9700 (LWP 15415)]
[New Thread 0x7fff78dfa700 (LWP 15416)]
[New Thread 0x7fff4ffff700 (LWP 15417)]
[New Thread 0x7fff4f5fe700 (LWP 15418)]
[New Thread 0x7fffe46c3700 (LWP 15419)]
[New Thread 0x7fffe467c700 (LWP 15420)]
[New Thread 0x7fff4ebfd700 (LWP 15421)]
[New Thread 0x7fffe4635700 (LWP 15422)]

开一个新终端窗口,连接数据库

[root@localhost ~]# /usr/local/mysql80/bin/mysql -S /data/mysql8015/datadir/mysql.sock -uroot -A
Welcome to the MySQL monitor.  Commands end with ; or \g.

停在这里了,断点被触发

Thread 44 "mysqld" hit Breakpoint 1, Python Exception <type 'exceptions.NameError'> Installation error: gdb.execute_unwinders function is missing: 
do_command (Python Exception <type 'exceptions.NameError'> Installation error: gdb.execute_unwinders function is missing: 
thd=0x7fff30000c00) at /data/source/mysql-8.0.15/sql/sql_parse.cc:1155
1155	  NET *net = NULL;
(gdb) l
1150	*/
1151	
1152	bool do_command(THD *thd) {
1153	  bool return_value;
1154	  int rc;
1155	  NET *net = NULL;
1156	  enum enum_server_command command;
1157	  COM_DATA com_data;
1158	  DBUG_ENTER("do_command");
1159	  DBUG_ASSERT(thd->is_classic_protocol());
(gdb) p thd
$1 = (THD *) 0x7fff30000c00

Oh yeah。变量值可以打印出来了。再四处转转。

304	      while (thd_connection_alive(thd)) {
(gdb) 
305	        if (do_command(thd)) break;
(gdb) 

n到这里的时候,另一个终端窗口的提示光标就出来了,可以输入MySQL命令了

Your MySQL connection id is 8
Server version: 8.0.15-debug Source distribution

Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> 

这篇就到这吧,好像我编译安装的gdb的python模块有问题,老报错

Python Exception <type 'exceptions.NameError'> Installation error: gdb.execute_unwinders function is missing: 

找到了解决办法,需要把python模块从源码包的解压目录下复制到gdb的安装目录中去。

[root@localhost ~]# ls /usr/local/gdb82/share/gdb/python/gdb/
[root@localhost ~]# 
[root@localhost ~]# ls /data/source/gdb-8.2/gdb/python/lib/gdb/
command  FrameDecorator.py  FrameIterator.py  frames.py  function  __init__.py  printer  printing.py  prompt.py  types.py  unwinder.py  xmethod.py
[root@localhost ~]# cd /data/source/gdb-8.2/gdb/python/lib/gdb/
[root@localhost gdb]# cp -r * /usr/local/gdb82/share/gdb/python/gdb/
[root@localhost gdb]# cd
[root@localhost ~]# gdb /usr/local/mysql80/bin/mysqld
GNU gdb (GDB) 8.2
Copyright (C) 2018 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-pc-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from /usr/local/mysql80/bin/mysqld...done.
(gdb) 

比较上次gdb mysqld一开始的输出,没有python模块缺失的提示了。

    原文作者:古雷
    原文地址: https://zhuanlan.zhihu.com/p/62091076
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞