MySQL のGDBによるデバッグ環境構築メモ

MySQL5.1からは、自作のストレージエンジンや自作の関数用のAPIが公開されている。
自作のストレージエンジンは気軽には作れないと思うが、自作の関数については検討の価値ありだと思う。
その際に役立つかもしれないデバッグ環境の構築メモ。

その前に、ここ の手順で、ソースを取得してデバッグオプション付きでMySQLをビルドしておく。

gdbデバッグするには、下記のライブラリが「not stripped」でなければならない。そうじゃない場合は、glibcの再コンパイルが必要。CentOS5は「not stripped」なので問題ない。

# file -L /lib/libthread_db.so.1
/lib/libthread_db.so.1: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), for GNU/Linux 2.6.9, not stripped
# file -L /lib/libpthread.so.0
/lib/libpthread.so.0: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), for GNU/Linux 2.6.9, not stripped

mysql-test ディレクトリに移動

# cd <MYSQLのソースディレクトリ>/mysql-test

テストケース作成

# vi t/example.test
select 1;

テストケースexampleを実行

# ./mysql-test-run --record example
Logging: ./mysql-test-run --record example
081006 21:26:45 [ERROR] Fatal error: Please read "Security" section of the manual to find out how to run mysqld as root!

081006 21:26:45 [ERROR] Aborting

というエラーが出てうまくいかなかった。どうやらmysqldの起動時にroot権限というのが問題らしい。
というわけで、mysqlユーザにて上記を再度やり直し。

# su - mysql

mysql-test ディレクトリに移動

$ cd /home/mysql/mysql-server/mysql-5.1/mysql-test

テストケース作成

$ vi t/example.test
select 1;
select now();

テスト実行

$ ./mysql-test-run --record example
Logging: ./mysql-test-run --record example
MySQL Version 5.1.30
Using dynamic switching of binlog format
Skipping ndbcluster, mysqld not compiled with ndbcluster
Skipping SSL, mysqld not compiled with SSL
Using MTR_BUILD_THREAD      = 0
Using MASTER_MYPORT         = 9306
Using MASTER_MYPORT1        = 9307
Using SLAVE_MYPORT          = 9308
Using SLAVE_MYPORT1         = 9309
Using SLAVE_MYPORT2         = 9310
Using IM_PORT               = 9313
Using IM_MYSQLD1_PORT       = 9314
Using IM_MYSQLD2_PORT       = 9315
Killing Possible Leftover Processes
Removing Stale Files
Creating Directories
Installing Master Database
=======================================================

TEST                           RESULT         TIME (ms)
-------------------------------------------------------

main.example                   [ pass ]              2
-------------------------------------------------------
Stopping All Servers
All 1 tests were successful.
The servers were restarted 1 times
Spent 0.002 of 3 seconds executing testcases

2つのテストケースが正常にpassしているのがわかる。

続いてgdbによるデバッグ ※要 X-Window、xterm (無い場合はWindows側にCygwinのXを入れて起動しておき、WindowsのX側でxhost + して、Linux側でexport DISPLAY=:0.0 しておいてもOK)

$ ./mysql-test-run --gdb example

するとgdb が起動した状態の xterm が立ち上がりMySQLサーバーをgdbにてデバッグできる。
このexample.testが完了しても、デバッグウィンドウは開いたままになる。
このあと、mysqlクライアントで接続して任意のブレイクポイントを設定して、任意のクエリを実行してデバッグができる。
ちなみにこの時のサーバーのポートは9306で動作してる。

サーバーに接続して、クエリを実行する。

$ ../client/mysql -uroot -h127.0.0.1 --port=9306 test

mysql> select 1;

デバッグウィンドウでは、ブレイクポイント mysql_parse() でちゃんと止まる。

Breakpoint 2, mysql_parse (thd=0x8919508, inBuf=0x8972930 "select 1", 
    length=8, found_semicolon=0xb743b114) at sql_parse.cc:5655
5655      DBUG_ENTER("mysql_parse");
(gdb) 

これで一通りデバッグ環境ができたので、自作関数などのテストが簡単になった。

操作 おすすめブレークポイント
SELECT mysql_select()
INSERT mysql_insert()
UPDATE mysql_update()
DELETE mysql_delete()
クエリキャッシュから答えが返っているかどうか Query_cache::send_result_to_client()
クライアントから通信パケットを読む my_net_read()
クライアントに通信パケットを書く my_net_write()
認証の接続 check_connection()
レプリケーションマスター側の更新ログ MYSQL_LOG::write(Log_event *)
レプリケーションスレーブの起動 start_slave_threads()
スレーブ上のネットワークI/Oを処理するレプリケーションスレッドの実行 handle_slave_io()
スレーブ上のSQLコマンドを処理するレプリケーションスレッドの実行 handle_slave_sql()
テーブルオープン open_table()
テーブル定義ファイル(.frm)の読み込み openfrm()
MyISAMテーブルのオープン ha_myisam::open()
InnoDBテーブルのオープン ha_innobase::open()
テーブルロックの取得 mysql_lock_tables()
トランザクションのコミット ha_commit_trans()


参考文献 Understanding MySQL Internals