GDBを使用してMSQLをデバッグする

GDBの概要

GDBは、Linuxシステムで非常に一般的なデバッグツールであり、次の機能があります。

  • プログラムを起動し、その
    動作に影響を与える可能性のあるものを指定します。
  • 指定した条件でプログラムを停止させます。
  • プログラムが停止したときに何が起こったかを調べます。
  • プログラムの内容を変更して、あるバグの影響を修正して実験し、別のバグについて学習できるようにします。

一般的に使用されるパラメータコマンド:

  • 情報スレッド:すべてのスレッドを表示
  • スレッドn:スレッドを指定します
  • b:どこかのブレークポイント
  • c:降り続ける
  • s:コード行を実行し、コード関数が呼び出された場合は、関数を入力します
  • n:コード行を実行します。関数呼び出しは入力されません
  • p:変数の値を出力します
  • リスト:コードのテキスト情報を出力します
  • bt:スレッドのスタックフレームを表示する
  • info b:現在のブレークポイント情報をすべて表示

環境構築のデバッグ

Linuxの直下でgdbを使用する場合、これは市場で最も簡単で効果的な方法です。

  1. gdbをインストールします
yum install -y cmake make gcc gcc-c++ ncurses-devel bison gdb
  1. ソースコードをダウンロードして解凍します
wget https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-boost-5.7.25.tar.gz

tar zxvf mysql-boost-5.7.25.tar.gz

mkdir -p /gdb/mysql/

mkdir -p /gdb/data/
  1. データベースをインストールします
cmake -DCMAKE_INSTALL_PREFIX=/gdb/mysql/ -DMYSQL_DATADIR=/gdb/data/ -DSYSCONFDIR=/gdb/mysql/ -DWITH_INNOBASE_STORAGE_ENGINE=1 -DWITH_ARCHIVE_STORAGE_ENGINE=1 -DWITH_BLACKHOLE_STORAGE_ENGINE=1 -DWITH_FEDERATED_STORAGE_ENGINE=1 -DWITH_PARTITION_STORAGE_ENGINE=1 -DMYSQL_UNIX_ADDR=/gdb/mysql/mysql3.sock -DMYSQL_TCP_PORT=3306 -DENABLED_LOCAL_INFILE=1 -DEXTRA_CHARSETS=all -DDEFAULT_CHARSET=utf8 -DDEFAULT_COLLATION=utf8_general_ci -DMYSQL_USER=mysql -DWITH_BINLOG_PREALLOC=ON -DWITH_BOOST=/gdb/mysql-5.7.25/boost/boost_1_59_0 -DWITH_DEBUG=1

-DWITH_DEBUG = 1が最も重要であり、その機能はDBUGを開くことです。

make&&make install
  1. データベースを初期化します
vim /etc/my.cnf
    #简易配置下my.cnf文件
    [client]
    port            = 3306
    socket          = /gdb/data/mysqld.sock

    [mysqld]
    port            = 3306
    socket          =/gdb/data/mysqld.sock
    skip-external-locking
    key_buffer_size = 8M
    max_allowed_packet = 1M
    table_open_cache = 64
    sort_buffer_size = 512K
    net_buffer_length = 8K
    read_buffer_size = 128K
    read_rnd_buffer_size = 256K
    myisam_sort_buffer_size = 8M
    lower_case_table_names=1
    innodb_buffer_pool_size=300M
    log-bin=mysql-bin
    character_set_server=utf8
    binlog_format=row
    datadir=/gdb/data
    log-error =/gdb/data/error.log
    pid-file = /gdb/data/mysql.pid

    innodb_log_file_size=512M
    innodb_log_files_in_group = 3
    sql_mode=''
    autocommit=1

    server-id       = 1
    max_connections=1500
    wait_timeout=70
    interactive_timeout=70

    skip-name-resolve

    [mysqldump]
    quick
    max_allowed_packet = 16M

    [myisamchk]
    key_buffer_size = 20M
    sort_buffer_size = 20M
    read_buffer = 2M
    write_buffer = 2M
  1. データベースを起動します

mysqlユーザーが次のディレクトリにファイルを生成する権限を持つように権限を付与します
。chown-Rmysql:mysql / gdb / data

データベースコマンドを初期化します。

cd /gdb/mysql/bin
./mysqld --initialize --user=mysql --basedir=/gdb/mysql --datadir=/gdb/data

データベースを起動します。

cd /gdb/mysql/support-files
 ./mysql.server start

ブレークポイントのデバッグを挿入

  1. mysqlプロセスIDを表示する
[root@ops sql]# ps aux | grep mysql
root       629  0.0  0.0 112724   972 pts/2    S+   14:52   0:00 grep -E --color=auto mysql
root     20926  0.0  0.0 113312  1628 pts/0    S    11:15   0:00 /bin/sh /gdb/mysql/bin/mysqld_safe --datadir=/gdb/data --pid-file=/gdb/data/mysql.pid
mysql    21357  0.0  5.8 1740820 223820 pts/0  Sl   11:15   0:01 /gdb/mysql/bin/mysqld --basedir=/gdb/mysql --datadir=/gdb/data --plugin-dir=/gdb/mysql/lib/plugin --user=mysql --log-error=/gdb/data/error.log --pid-file=/gdb/data/mysql.pid --socket=/gdb/data/mysqld.sock --port=3306

この時点でのmysqlのプロセス番号は次のとおりです。20926

  1. gdbにmysqlプロセスをアタッチします
[root@ops ~]# gdb
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-119.el7
Copyright (C) 2013 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 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 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
(gdb)
  1. ブレークポイントを見つける

今回は挿入プロセスを調べて、sql_insert.ccファイルを見つけまし
ここに画像の説明を挿入します
た。ソースコードの関数は次のとおりです。Sql_cmd_insert:: mysql_insert

  1. ブレークポイントを設定する
(gdb) b Sql_cmd_insert::mysql_insert
Breakpoint 1 at 0x175aed9: file /gdb/mysql-5.7.25/sql/sql_insert.cc, line 423.

次に、スレッドのスタックフレームを確認します。

(gdb) bt
#0  0x00002b15ce803f0d in poll () from /lib64/libc.so.6
#1  0x0000000001667f87 in Mysqld_socket_listener::listen_for_connection_event (this=0x3967430) at /gdb/mysql-5.7.25/sql/conn_handler/socket_connection.cc:852
#2  0x0000000000eb15cc in Connection_acceptor<Mysqld_socket_listener>::connection_event_loop (this=0x4f882e0) at /gdb/mysql-5.7.25/sql/conn_handler/connection_acceptor.h:66
#3  0x0000000000ea904a in mysqld_main (argc=38, argv=0x383c248) at /gdb/mysql-5.7.25/sql/mysqld.cc:5149
#4  0x0000000000ea01bd in main (argc=9, argv=0x7ffc73765b88) at /gdb/mysql-5.7.25/sql/main.cc:25
  1. データベースログイン

gdbブレークポイントを設定した後、新しいデータベース接続を開始します。
ここに画像の説明を挿入します
現時点ではログインできないことがわかります。次にgdbで実行します。

(gdb) n
Single stepping until exit from function poll,
which has no line number information.
Mysqld_socket_listener::listen_for_connection_event (this=0x3967430) at /gdb/mysql-5.7.25/sql/conn_handler/socket_connection.cc:859
859   if (retval < 0 && socket_errno != SOCKET_EINTR)

出力から、データベースがシステムソケットを取得している状態にあることがわかります。次にスキップする必要のある手順がたくさんあります。continueを直接使用します(実行可能コードの次の部分に直接)

(gdb) c
Continuing.

新しいクライアントは正常に接続します。

[root@ops bin]# mysql -uroot -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 14
Server version: 5.7.25-debug-log Source distribution

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

mysql>
  1. データベース挿入

挿入操作の前に、スキーマとクエリを切り替えることは問題ありません。

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のデータを挿入すると、待機が発生します。

mysql> insert into test values (3);
  1. ブレークポイント情報を分析する

ブレークポイントは次のようにトリガーされます。

(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が1行ずつ出力されます。ここで直接続行し、ブロッキング挿入も完了します。

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

mysqlの特別なバージョンをリリースします

上記の挿入関数や削除関数など、一部の関数のソースコードの場所は理解しやすいです。削除機能を変更してデータが削除されない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

削除関数はここにブレークポイントを置きます:

(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によって処理される関数です。ソースコードに移動して、対応する関数を見つけます。Zhengzhen
ここに画像の説明を挿入します
の削除ロジックを実装するコードをコメントアウトすると、返されるres値は直接になります。 trueに割り当てられています:

bool Sql_cmd_delete::execute(THD *thd)
{
  DBUG_ASSERT(thd->lex->sql_command == SQLCOM_DELETE);

  LEX *const lex= thd->lex;
  SELECT_LEX *const select_lex= lex->select_lex;
  SELECT_LEX_UNIT *const unit= lex->unit;
  TABLE_LIST *const first_table= select_lex->get_table_list();
  TABLE_LIST *const all_tables= first_table;

  if (delete_precheck(thd, all_tables))
    return true;
  DBUG_ASSERT(select_lex->offset_limit == 0);
  unit->set_limit(select_lex);

  /* Push ignore / strict error handler */
  Ignore_error_handler ignore_handler;
  Strict_error_handler strict_handler;
  if (thd->lex->is_ignore())
    thd->push_internal_handler(&ignore_handler);
  else if (thd->is_strict_mode())
    thd->push_internal_handler(&strict_handler);

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

/*直接返回true*/
  bool res =true;

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

  return res;
}

次に、mysqlを再コンパイルする上記の方法では、起動後、deleteステートメントでデータを削除できないことがわかります。

デバッグの概要

ソースコードを深く学びたい場合は、スタックフレームから始めることができますが、これは関数インターフェイスの関数を知っていることを前提としています。関数が呼び出す関数がわからない場合は、次のようになります。ブレークポイントでデバッグするのは難しい。

mysqlのすべてのソースコードを直接読み取るにはコストがかかりすぎ、mysqlのコード構造は使い勝手が悪く、時間と労力の価値がありません。最善の解決策は、問題が発生したとき、またはオンデマンドで特別なファンクションポイントの関数エントリを見つけて、それを徐々に詳細に分析することです。

この記事がmysqlソースコードのデバッグに触れたい学生に役立つことを願っています。将来特別な問題が発生した場合は、gdbを使用して関連関数をデバッグします。引き続き注意してください〜

参照リンク:

https://mp.weixin.qq.com/s/lLfbUpd_SMCpFm1vNQlHRQ

おすすめ

転載: blog.csdn.net/qq_40907977/article/details/114929515