読者です 読者をやめる 読者になる 読者になる

MySQL + GDB + 解析

MySQL 5.1.41 を GDB 使って解析するメモ。取っかかり編。
環境 : CentOS 5.2

ダウンロード

MySQL 5.1.41 のソースをダウンロードする。

インストール

/usr/local/mysql-5.1.41 へインストールする。

  
$ tar zxvf mysql-5.1.41.tar.gz  
$ cd mysql-5.1.41  
$ ./configure --prefix=/usr/local/mysql-5.1.41 --with-unix-socket-path=/usr/local/mysql-5.1.41/tmp/mysql.sock --with-charset=utf8 --with-extra-charsets=all --enable-thread-safe-client --with-plugins=innodb_plugin --with-readline --with-debug  
$ make  
$ make install  
$ cd /usr/local/mysql-5.1.41  
$ sudo cp share/mysql/my-medium.cnf /etc/my.cnf  

GDB

最初に mysqld を gdb 経由で実行する。

  
$ gdb ./libexec/mysqld  
GNU gdb Red Hat Linux (6.5-25.el5rh)  
Copyright (C) 2006 Free Software Foundation, Inc.  
GDB is free software, covered by the GNU General Public License, and you are  
welcome to change it and/or distribute copies of it under certain conditions.  
Type "show copying" to see the conditions.  
There is absolutely no warranty for GDB.  Type "show warranty" for details.  
This GDB was configured as "i386-redhat-linux-gnu"...Using host libthread_db library "/lib/libthread_db.so.1".  

立ち上がったら続けて、main に break ポイントを打ってみる。

  
(gdb) b main  
Breakpoint 1 at 0x81b697a: file mysqld.cc, line 4261.  

main は sql/mysqld.cc の 4261 行目にある。
とりあえず実行。

  
(gdb) r  
Starting program: /usr/local/mysql-5.1.41/libexec/mysqld  
[Thread debugging using libthread_db enabled]  
[New Thread -1209051440 (LWP 10008)]  
[Switching to Thread -1209051440 (LWP 10008)]  
  
Breakpoint 1, main (argc=1, argv=0xbf96e304) at mysqld.cc:4261  
4261      MY_INIT(argv[0]);             // init my_sys library & pthreads  

MY_INIT(argv[0]) のとこで止まった。(ちなみに MY_INIT() はマクロで、include/my_sys.h の 40 行目にある)
いま止まってるとこ付近のソースを表示する。

  
(gdb) l  
4256    int win_main(int argc, char **argv)  
4257    #else  
4258    int main(int argc, char **argv)  
4259    #endif  
4260    {  
4261      MY_INIT(argv[0]);             // init my_sys library & pthreads  
4262      /* nothing should come before this line ^^^ */  
4263  
4264      /* Set signal used to kill MySQL */  
4265    #if defined(SIGUSR2)  

main の直後 に MY_INIT() が呼ばれており、#else 〜 #endif で windows とそれ以外で main を切り分けてるのがなんとなく分かる。
ステップ実行して MY_INIT() に入る。

  
(gdb) s  
my_init () at my_init.c:73  
73        if (my_init_done)  
Current language:  auto; currently c  

my_init() へ辿り着いた。my_init() は MY_INIT() の中で呼ばれており、mysys/my_init.c の 73 行目にある。
my_init_done の値を確認する。

  
(gdb) p my_init_done  
$1 = 0 '\0'  

0 が入ってる。my_init() 実行前だから当然っちゃ当然。(my_init_done は my_bool型(typedef char))

やっぱりステップ実行は便利ですね。

参考

GDB マニュアル