使用GDB调试mysql源码


摘要:通过GDB调试mysql5.6的启动过程

安装GDB

[root@mysql2 src]# wget http://ftp.gnu.org/gnu/gdb/gdb-7.6.1.tar.gz
[root@mysql2 src]# tar -zxvf gdb-7.6.1.tar.gz
[root@mysql2 src]# cd gdb-7.6.1
[root@mysql2 gdb-7.6.1]# ./configure
[root@mysql2 gdb-7.6.1]# make && make install
[root@mysql2 gdb-7.6.1]# whereis gdb
gdb: /usr/local/bin/gdb /usr/share/gdb
[root@mysql2 gdb-7.6.1]# gdb -v
GNU gdb (GDB) 7.6.1
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-unknown-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
[root@mysql2 ~]# gdb
GNU gdb (GDB) 7.6.1
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-unknown-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
(gdb) help
List of classes of commands:
aliases -- Aliases of other commands
breakpoints -- Making program stop at certain points
data -- Examining data
files -- Specifying and examining files
internals -- Maintenance commands
obscure -- Obscure features
running -- Running the program
stack -- Examining the stack
status -- Status inquiries
support -- Support facilities
tracepoints -- Tracing of program execution without stopping the program
user-defined -- User-defined commands
Type "help" followed by a class name for a list of commands in that class.
Type "help all" for the list of all commands.
Type "help" followed by command name for full documentation.
Type "apropos word" to search for commands related to "word".
Command name abbreviations are allowed if unambiguous.
(gdb)

开启DEBUG模式编译源码

[root@mysql2 ~]# mkdir -p {/opt/debug_mysql,/opt/debug_mysql/run,/data/debug_mysql/data,/data/debug_mysql/tmp,/data/debug_mysql/log/iblog,/data/debug_mysql/log/binlog}
[root@mysql2 mysql-5.6.35]#cmake \
-DCMAKE_INSTALL_PREFIX=/opt/debug_mysql \
-DINSTALL_DATADIR=/data/debug_mysql/data \
-DDEFAULT_CHARSET=utf8 \
-DDEFAULT_COLLATION=utf8_general_ci \
-DEXTRA_CHARSETS=all \
-DWITH_SSL=yes \
-DWITH_EMBEDDED_SERVER=1 \
-DENABLED_LOCAL_INFILE=1 \
-DWITH_MYISAM_STORAGE_ENGINE=1 \
-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=/opt/debug_mysql/run/mysql.sock \
-DMYSQL_TCP_PORT=3307 \
-DENABLED_LOCAL_INFILE=1 \
-DSYSCONFDIR=/etc \
-DWITH_DEBUG=1 #添加此项开启DEBUG模式
[root@mysql2 mysql-5.6.35]# make && make install
[root@mysql2 opt]# /opt/debug_mysql/scripts/mysql_install_db --defaults-file=/opt/my3307.cnf --basedir=/opt/debug_mysql

调试mysqld的启动过程

找到mysqld的启动入口

对mysqld的入口函数(mysqld_main)做断点:

[root@mysql2 ~]# gdb --args /opt/debug_mysql/bin/mysqld
GNU gdb (GDB) 7.6.1
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-unknown-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /opt/debug_mysql/bin/mysqld...done.
(gdb) b mysqld_main
Breakpoint 1 at 0x63bfbf: file /opt/mysql-5.6.35/sql/mysqld.cc, line 5250.
(gdb)

查看源码文件mysqld.cc的第5250行:
图1
说明这个mysqld_main就是mysqld启动的入口函数

启动mysqld

(gdb) n
The program is not being run.
(gdb) r
Starting program: /opt/debug_mysql/bin/mysqld
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Breakpoint 1, mysqld_main (argc=1, argv=0x7fffffffe578) at /opt/mysql-5.6.35/sql/mysqld.cc:5250
5250 my_progname= argv[0];

mysqld_main本身作为第一个参数传递给my_progname启动。

文件、目录权限的初始化

(gdb) n
5254 if (my_init()) // init my_sys library & pthreads
(gdb) s
my_init () at /opt/mysql-5.6.35/mysys/my_init.c:69
69 if (my_init_done)
(gdb) n
72 my_init_done= 1;
(gdb) n
74 my_umask= 0660; /* Default umask for new files */
(gdb) n
75 my_umask_dir= 0700; /* Default umask for new directories */
(gdb) n
78 if ((str= getenv("UMASK")) != 0)
(gdb) n
81 if ((str= getenv("UMASK_DIR")) != 0)
(gdb) n
84 init_glob_errs();
(gdb) n
86 instrumented_stdin.m_file= stdin;
(gdb) n
87 instrumented_stdin.m_psi= NULL; /* not yet instrumented */
(gdb) n
88 mysql_stdin= & instrumented_stdin;

线程初始化

(gdb) n
90 if (my_thread_global_init())
(gdb) s
my_thread_global_init () at /opt/mysql-5.6.35/mysys/my_thr_init.c:120
120 if (my_thread_global_init_done)
(gdb) n
122 my_thread_global_init_done= 1;
(gdb) n
134 pthread_mutexattr_init(&my_fast_mutexattr);
(gdb) n
135 pthread_mutexattr_settype(&my_fast_mutexattr,
(gdb) n
143 pthread_mutexattr_init(&my_errorcheck_mutexattr);
(gdb) n
144 pthread_mutexattr_settype(&my_errorcheck_mutexattr,
(gdb) n
148 DBUG_ASSERT(! THR_KEY_mysys_initialized);
(gdb) n
149 if ((pth_ret= pthread_key_create(&THR_KEY_mysys, NULL)) != 0)
(gdb) s
155 THR_KEY_mysys_initialized= TRUE;
(gdb) n
156 mysql_mutex_init(key_THR_LOCK_malloc, &THR_LOCK_malloc, MY_MUTEX_INIT_FAST);
(gdb) n
157 mysql_mutex_init(key_THR_LOCK_open, &THR_LOCK_open, MY_MUTEX_INIT_FAST);
(gdb) n
158 mysql_mutex_init(key_THR_LOCK_charset, &THR_LOCK_charset, MY_MUTEX_INIT_FAST);
(gdb) n
159 mysql_mutex_init(key_THR_LOCK_threads, &THR_LOCK_threads, MY_MUTEX_INIT_FAST);

图2
图3

mutex初始化

(gdb) n
my_init () at /opt/mysql-5.6.35/mysys/my_init.c:94
94 safe_mutex_global_init(); /* Must be called early */
(gdb) n
102 if ((home_dir= getenv("HOME")) != 0)
(gdb) n
103 home_dir= intern_filename(home_dir_buff, home_dir);
(gdb) n
106 DBUG_ENTER("my_init");
(gdb) n
107 DBUG_PROCESS((char*) (my_progname ? my_progname : "unknown"));
(gdb) n
109 DBUG_PRINT("exit", ("home: '%s'", home_dir));
(gdb) n
113 DBUG_RETURN(0);
(gdb) n
115 } /* my_init */

加载配置文件

(gdb) n
mysqld_main (argc=1, argv=0x7fffffffe578) at /opt/mysql-5.6.35/sql/mysqld.cc:5261
5261 orig_argc= argc;
(gdb) s
5262 orig_argv= argv;
(gdb) n
5263 my_getopt_use_args_separator= TRUE;
(gdb) n
5264 my_defaults_read_login_file= FALSE;
(gdb) n
5265 if (load_defaults(MYSQL_CONFIG_NAME, load_default_groups, &argc, &argv))

图4
图5
下图可以看到win平台上mysqld加载my.cnf配置文件的顺序:
图6
下图可以看到linux平台上mysqld加载my.cnf配置文件的顺序:
图7
依次查找my.cnf的顺序是:/etc、/etc/mysql、当前目录、当前用户家目录

设置字符集

(gdb) n
5274 system_charset_info= &my_charset_utf8_general_ci;

初始化各种status变量

(gdb) n
5276 init_sql_statement_names();
(gdb) s
init_sql_statement_names () at /opt/mysql-5.6.35/sql/mysqld.cc:3599
3599 char *first_com= (char*) offsetof(STATUS_VAR, com_stat[0]);

初始化系统变量

(gdb) n
5277 sys_var_init();
(gdb) s
sys_var_init () at /opt/mysql-5.6.35/sql/set_var.cc:61
61 DBUG_ENTER("sys_var_init");

图8

初始化performance_schema

(gdb) s
init_pfs_instrument_array () at /opt/mysql-5.6.35/storage/perfschema/pfs_server.cc:218
218 my_init_dynamic_array(&pfs_instr_config_array, sizeof(PFS_instr_config*), 10, 10);

图9

为performance schema初始化做早期准备

(gdb) n
mysqld_main (argc=2, argv=0x17edd20) at /opt/mysql-5.6.35/sql/mysqld.cc:5288
5288 ho_error= handle_early_options();
(gdb) s
handle_early_options () at /opt/mysql-5.6.35/sql/mysqld.cc:6865
6865 vector<my_option> all_early_options;

图10

初始化key_LOCK_error_log

(gdb) n
5358 init_error_log_mutex();

图11

初始化key_LOCK_audit_mask

(gdb) s
5368 mysql_audit_initialize();
(gdb) s
mysql_audit_initialize () at /opt/mysql-5.6.35/sql/sql_audit.cc:316
316 init_audit_psi_keys();

图12

初始化logger

(gdb) n
mysqld_main (argc=2, argv=0x17edd20) at /opt/mysql-5.6.35/sql/mysqld.cc:5374
5374 logger.init_base();
(gdb) s
LOGGER::init_base (this=0x179a4c0 <logger>) at /opt/mysql-5.6.35/sql/log.cc:912
912 DBUG_ASSERT(inited == 0);

图13
图14

初始化公共变量

(gdb) s
5404 if (init_common_variables())

图15

检查data home目录

(gdb) n
5465 check_data_home(mysql_real_data_home);
(gdb) n
5466 if (my_setwd(mysql_real_data_home,MYF(MY_WME)) && !opt_help)
(gdb) s
my_setwd (dir=0x17931a0 <mysql_real_data_home> "/opt/debug_mysql/data/", MyFlags=16) at /opt/mysql-5.6.35/mysys/my_getwd.c:98
98 DBUG_ENTER("my_setwd");

检查用户

(gdb) n
mysqld_main (argc=2, argv=0x17edd20) at /opt/mysql-5.6.35/sql/mysqld.cc:5469
5469 if ((user_info= check_user(mysqld_user)))
(gdb) s
check_user (user=0x0) at /opt/mysql-5.6.35/sql/mysqld.cc:2100
2100 uid_t user_id= geteuid();
文章目录
  1. 1. 安装GDB
  2. 2. 开启DEBUG模式编译源码
  3. 3. 调试mysqld的启动过程
    1. 3.1. 找到mysqld的启动入口
    2. 3.2. 启动mysqld
    3. 3.3. 文件、目录权限的初始化
    4. 3.4. 线程初始化
    5. 3.5. mutex初始化
    6. 3.6. 加载配置文件
    7. 3.7. 设置字符集
    8. 3.8. 初始化各种status变量
    9. 3.9. 初始化系统变量
    10. 3.10. 初始化performance_schema
    11. 3.11. 为performance schema初始化做早期准备
    12. 3.12. 初始化key_LOCK_error_log
    13. 3.13. 初始化key_LOCK_audit_mask
    14. 3.14. 初始化logger
    15. 3.15. 初始化公共变量
    16. 3.16. 检查data home目录
    17. 3.17. 检查用户
|