暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

MYSQL 源码DEBUG编译

1821

一部分 LINUX 系统安装

选择CENTOS 7 GNOME桌面兼容XWINDOWS

192.168.2.30  SINGLEDB 1CPU 4GB内存

1.1 DNS


echo "nameserver    202.96.134.133" >>/etc/resolv.conf 
echo "nameserver  202.96.128.68  " >>/etc/resolv.conf     
echo "nameserver  202.96.154.8     " >>/etc/resolv.conf   
echo "nameserver  202.96.154.15   " >>/etc/resolv.conf   


1.2 配置好了YUM源 我使用CENTOS7自带的YUM源


第二部分下载源码

https://dev.mysql.com/downloads/mysql/


MySQL Community Server 8.0.20

Select Operation System: Source Code

Select OS Version:ALL


拉到最下面看到

Generic Linux (Architecture Independent), Compressed TAR Archive

Includes Boost Headers

点击右边下载按钮

跳的账号注册,选择最下面的蓝色小字体

No Thanks Just start my download


上传到虚机CENTOS7 /root 目录下

创建目录和用户

groupadd -g 1101 dba
useradd -u 1102  -g dba  -d /home/mysql -s /bin/bash -c "Oracle Software Owner" mysql
mkdir -p  /u01/mysql8/soft /u01/mysql8/data /u01/mysql8/binlog
mkdir -p /u01/mysql8/buildcd root
tar -zvxf mysql-boost-8.0.20.tar.gz -C u01/mysql8

cd u01/mysql8
mv mysql-8.0.20/ sourcechown -R mysql /u01/mysql8


注意 该目录下需要很大的空间,因为编译MYSQL8 需要7GB


第三部分下载VIM CSCOPE


vim插件cscope使用方法

yum -y install cscope  


建立索引文件(会生成cscope.out文件)

$ cd U01/mysql8/source

cscope -Rbqk

上面执行过后会生成三个文件,cscope.out就是生成的数据库,

cscope.in.out和cscope.po.out是q控制对应的索引。


[root@SINGLEDB mysql8020]ll *.out
-rw-r--r--. 1 root root  10903552 7月   6 06:10 cscope.in.out
-rw-r--r--. 1 root root  90794833 7月   6 06:10 cscope.out
-rw-r--r--. 1 root root 132811152 7月   6 06:10 cscope.po.out



进入源码根目录后VIM 空文件名  会出现VIM的版本号 

~                                                                            VIM - Vi IMproved                                                                              
~                                                                                                                                                                           
~                                                                               版本 7.4.160                                                                                
~                                                                         维护人 Bram Moolenaar 等                                                                          
~                                                                       修改者 <bugzilla@redhat.com>                                                                        
~                                                                     Vim 是可自由分发的开放源代码软件                                                                      
~                                                                                                                                                                           
~                                                                          成为 Vim 的注册用户!                                                                            
~                                                              输入  :help register<Enter>   查看说明                                                                       
~                                                                                                                                                                           
~                                                              输入  :q<Enter>               退出                                                                           
~                                                              输入  :help<Enter>  或  <F1>  查看在线帮助                                                                   
~                                                              输入  :help version7<Enter>   查看版本信息       


已经设置好了CSCOPE,并自动调用CSCOPE.OUT


按ECS键 进入VIM命令模式

:cs find s get_files


 Cscope tag: get_files
   #   行    文件名 / 上下文 / 行
   1   1021  sql/dd/impl/bootstrap/bootstrapper.cc <<GLOBAL>>
             tablespace_def->get_files();
   2    174  sql/plugin_table.h <<get_files>>
             const List<const Plugin_tablespace_file> &get_files() const {
   3    110  storage/innobase/arch/arch0log.cc <<get_files>>
             int Log_Arch_Client_Ctx::get_files(Log_Arch_Cbk *cbk_func, void *ctx) {
   4    448  storage/innobase/clone/clone0copy.cc <<init_redo_copy>>
             redo_error = m_redo_ctx.get_files(add_redo_file_callback, context);
   5     79  storage/innobase/include/arch0log.h <<m_end_lsn>>
             int get_files(Log_Arch_Cbk *cbk_func, void *ctx);
Type number and <Enter> (empty cancels): 5 


输入5 就进入该文件的头文件定义出


  int stop(byte *trailer, uint32_t &len, uint64_t &offset);

  /** Get archived data file details
  @param[in]    cbk_func        callback called for each file
  @param[in]    ctx             callback function context
  @return error code */

  int get_files(Log_Arch_Cbk *cbk_func, void *ctx);

  /** Release archived data so that system can purge it */
  void release();    


  

Type number and <Enter> (empty cancels): 3  就显示该函数的实现文件



CSCOPE其他命令参考:

使用cscope find s xxx来进行cscope的使用即可。s是参数,其他参数及意义如下:

s: 查找C语言符号,即查找函数名、宏、枚举值等出现的地方

g: 查找函数、宏、枚举等定义的位置,类似ctags所提供的功能

d: 查找本函数调用的函数

c: 查找调用本函数的函数

t: 查找指定的字符串

e: 查找egrep模式,相当于egrep功能,但查找速度快多了

f: 查找并打开文件,类似vim的find功能

i: 查找



MYSQL8的源码也有WIN版本,可以使用WIN平台下的文本加色软件来看.

源码根目录下是各个MYSQL8组件套餐,MYROUTE也在其中.

我们这样看是精态方法, 大部分代码都是CC扩展名.

需要动态看源码之间的关系,就需要用到GDB调试工具,下会我们谈源码动态看法!


动态看需要DEBUG方式编译MYSQL8


第四部分 GCC安装

编译 MySQL 8.0 版本,需要 GCC 版本 5.5.0  最好是5.5 太老了编不动,太新了编译出错!

下载

http://ftp.tsukuba.wide.ad.jp/software/gcc/releases/

上传到

/u01/rpm_install
mkdir -p u01/GCC

解压

# tar -zxvf gcc-5.5.0.tar.gz -C u01/GCC


#下载mpfr、gmp、mpc、isl等依赖包 晚上下载有点慢

cd u01/GCC/gcc-5.5.0

[root@SINGLEDB gcc-5.5.0]# ./contrib/download_prerequisites 


2020-07-06 10:20:32 URL: ftp://gcc.gnu.org/pub/gcc/infrastructure/mpfr-3.1.4.tar.bz2 [1279284] -> "./mpfr-3.1.4.tar.bz2" 
2020-07-06 10:21:30 URL: ftp://gcc.gnu.org/pub/gcc/infrastructure/mpc-1.0.3.tar.gz [669925] -> "./mpc-1.0.3.tar.gz" [1]
2020-07-06 10:23:25 URL: ftp://gcc.gnu.org/pub/gcc/infrastructure/isl-0.18.tar.bz2 [1658291] -> "./isl-0.18.tar.bz2" [1]
2020-07-06 10:30:21 URL: ftp://gcc.gnu.org/pub/gcc/infrastructure/gmp-6.1.0.tar.bz2 [2383840] -> "./gmp-6.1.0.tar.bz2" [1]
gmp-6.1.0.tar.bz2: 确定
mpfr-3.1.4.tar.bz2: 确定
mpc-1.0.3.tar.gz: 确定
isl-0.18.tar.bz2: 确定
All prerequisites downloaded successfully.


觉得太慢可以自行下载

yum -y install gmp-devel      // 编译依赖此库 

yum -y install mpfr-devel     编译依赖此库  

yum -y install libmpc-devel   编译依赖此库  

yum -y install bzip2          // 编译依赖此库


因为安装CENTOS7时只选择了桌面系统,没有带开发工具

所以编译前安装包


yum install -y glibc-headers 
yum install -y gcc-c++ 


建立编译输出目录

mkdir build

cd build

配置

../configure --enable-checking=release --enable-languages=c,c++ --disable-multilib --enable-threads=posix


参数解释:

–enable-checking=release 增加一些检查,也可以–disable-checking生成的编译器在编译过程中不做额外检查

–enable-languages=c,c++ 你要让你的gcc支持的编程语言

–disable-multilib 取消多目标库编译(取消32位库编译)

编译安装 

make && make install

然后听着音乐,看着黑客帝国式地刷屏


WAITING.....


WAITING.....

 

23*10分后 5GB.....

[root@localhost build]# gcc -v


使用内建 specs。
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/local/libexec/gcc/x86_64-unknown-linux-gnu/5.5.0/lto-wrapper
目标:x86_64-unknown-linux-gnu
配置为:../configure --enable-checking=release --enable-languages=c,c++ --disable-multilib --enable-threads=posix
线程模型:posix
gcc 版本 5.5.0 (GCC)


第五步安装CMAKE 3.5.1

安装必要的软件依赖:


yum install -y  bison bison-devel libaio-devel git 
yum install -y  ncurses-devel openssl openssl-devel 
yum install -y  make automake binutils


CMAKE版本过低去直接下载二进制版本,

https://cmake.org/download/

运行SH

#sh cmake-3.18.0-rc3-Linux-x86_64.sh 

显示前要说明 按回车键直到出现如下


Do you accept the license? [yn]: YES
Do you want to include the subdirectory cmake-3.18.0-rc3-Linux-x86_64?
Saying no will install in"/u01/rpm_install" [Yn]: 


解压完后

# cd cmake-3.18.0-rc3-Linux-x86_64/bin

然后复制到/USR/BIN  

[root@localhost bin]# cp c* usr/bin

cp:是否覆盖"/usr/bin/ccmake"?y

cp:是否覆盖"/usr/bin/cmake"?y

cp:是否覆盖"/usr/bin/cpack"?y

cp:是否覆盖"/usr/bin/ctest"?y


cd /u01/rpm_install/cmake-3.18.0-rc3-Linux-x86_64/share

cp -r cmake-3.18 /usr/share

[root@CENT0S7 ~]# cmake /V

cmake version 3.18.0-rc3

CMake suite maintained and supported by Kitware (kitware.com/cmake).


第六步 使用cmake进行生成编译环境

进入MySQL源文件目录,新建configure做为编译目录,并进入该目录:

mkdir configure

cd configure


使用cmake进行生成编译环境:注意 \ 前的空格

cmake .. \
-DWITH_BOOST=/u01/mysql8/source/boost/ \
-DWITH_DEBUG=ON \
-DWITH_SSL=bundled \
-DWITH_INNODB_MEMCACHED=ON \
-DWITH_ZLIB=system \
-DDEFAULT_CHARSET=utf8mb4 \
-DCMAKE_INSTALL_PREFIX=/u01/mysql8/soft \
-DMYSQL_DATADIR=/u01/mysql8/data \
-DWITHOUT_CSV_STORAGE_ENGINE=1 \
-DWITHOUT_BLACKHOLD_STORAGE_ENGINE=1 \
-DWITHOUT_FEDERATED_STORAGE_ENGINE=1 \
-DWITHOUT_ARCHIVE_STORAGE_ENGINE=1 \
-DWITHOUT_MRG_MYISAM_STORAGE_ENGINE=1 \
-DWITHOUT_NDBCLUSTER_STORAGE_ENGINE=1 \
-DFORCE_INSOURCE_BUILD=1 \
-DCMAKE_CXX_COMPILER=/usr/local/bin/g++ \
-DCMAKE_C_COMPILER=/usr/local/bin/gcc


这里重点是

-DWITH_DEBUG=ON    开启DEBUG模式

-DWITH_BOOST=    告诉BOOST已经下载了,目录

-DMYSQL_DATADIR=

-DCMAKE_INSTALL_PREFIX这两个是安装目录和数据目录,需要看环境改写

其他的可以照抄


如果编译出现错误,请先删除CMakeCache.txt后,再重新编译:

rm -rf CMakeCache.txt


CMAKE 环境设置OK! 显示如下开心的信息:


CMake Warning:
  Manually-specified variables were not used by the project:

    WITHOUT_BLACKHOLD_STORAGE_ENGINE
    WITHOUT_MRG_MYISAM_STORAGE_ENGINE
    WITHOUT_NDBCLUSTER_STORAGE_ENGINE
-- Build files have been written to: /u01/mysql/source/mysql-8.0.20/configure


第七步 MYSQL8的编译

设置字符模式并关机配置多点CPU

查看当前的开机默认运行方式:systemctl get-default

设置开机不自启图形界面:systemctl set-default multi-user.target

设置开机启动图形界面:systemctl set-default graphical.target

重启后进入

# cd /u01/mysql8/source/configure

编译

make


出错处理:

[  3%] Generating uca900_zh_tbls.cc, uca900_ja_tbls.cc

../runtime_output_directory/uca9dump: lib64/libstdc++.so.6: version `CXXABI_1.3.9' not found (required by ../runtime_output_directory/uca9dump)

make[2]: *** [strings/uca900_zh_tbls.cc] 错误 1

make[1]: *** [strings/CMakeFiles/strings_objlib.dir/all] 错误 2




YUM补救安装下

yum install y libstdc++

软件包 libstdc++-4.8.5-39.el7.x86_64 已安装并且是最新版本


检查下

#cd usr/lib64 

[root@localhost lib64]# ll libstdc++*

lrwxrwxrwx. 1 root root     19 7月   9 22:01 libstdc++.so.6 -> libstdc++.so.6.0.19

-rwxr-xr-x. 1 root root 991616 8月   7 2019 libstdc++.so.6.0.19

strings libstdc++.so.6.0.19 | grep 'CXXABI_'

果真没有


全系统检查一下,哪里还有SO

 [root@localhost config]# find / -name "libstdc++.so.6*"

/usr/local/lib64/libstdc++.so.6.0.21-gdb.py

/usr/local/lib64/libstdc++.so.6.0.21

/usr/local/lib64/libstdc++.so.6

/u01/rpm_install/gcc-5.5.0/build/stage1-x86_64-unknown-linux-gnu/libstdc++-v3/src/.libs/libstdc++.so.6

/u01/rpm_install/gcc-5.5.0/build/stage1-x86_64-unknown-linux-gnu/libstdc++-v3/src/.libs/libstdc++.so.6.0.21

/u01/rpm_install/gcc-5.5.0/build/x86_64-unknown-linux-gnu/libstdc++-v3/src/.libs/libstdc++.so.6

/u01/rpm_install/gcc-5.5.0/build/x86_64-unknown-linux-gnu/libstdc++-v3/src/.libs/libstdc++.so.6.0.21

/u01/rpm_install/gcc-5.5.0/build/prev-x86_64-unknown-linux-gnu/libstdc++-v3/src/.libs/libstdc++.so.6

/u01/rpm_install/gcc-5.5.0/build/prev-x86_64-unknown-linux-gnu/libstdc++-v3/src/.libs/libstdc++.so.6.0.21

检查 strings XXXX | grep 'CXXABI_'

发现有,然后复制该目录

cp u01/rpm_install/gcc-5.5.0/build/stage1-x86_64-unknown-linux-gnu/libstdc++-v3/src/.libs/libstdc++.so.6.0.21 usr/lib64

软链接

[root@mysql_8 lib64]# rm -f libstdc++.so.6

[root@mysql_8 lib64]# ln -s libstdc++.so.6.0.21 libstdc++.so.6


这下可以编译了,花了2个小时达到69%,真心累!

Scanning dependencies of target myisam_ftdump
[ 69%] Building CXX object storage/myisam/CMakeFiles/myisam_ftdump.dir/myisam_ftdump.cc.o
[ 69%] Linking CXX executable ../../runtime_output_directory/myisam_ftdump
[ 69%] Built target myisam_ftdump
Scanning dependencies of target myisamchk
[ 69%] Building CXX object storage/myisam/CMakeFiles/myisamchk.dir/myisamchk.cc.o
[ 69%] Linking CXX executable ../../runtime_output_directory/myisamchk
[ 69%] Built target myisamchk
Scanning dependencies of target myisamlog
[ 69%] Building CXX object storage/myisam/CMakeFiles/myisamlog.dir/myisamlog.cc.o
[ 69%] Linking CXX executable ../../runtime_output_directory/myisamlog
[ 69%] Built target myisamlog
Scanning dependencies of target myisampack
[ 69%] Building CXX object storage/myisam/CMakeFiles/myisampack.dir/myisampack.cc.o
[ 69%] Linking CXX executable ../../runtime_output_directory/myisampack
[ 69%] Built target myisampack
Scanning dependencies of target mytap
[ 69%] Building CXX object unittest/mytap/CMakeFiles/mytap.dir/tap.cc.o
[ 69%] Linking CXX static library libmytap.a
[ 69%] Built target mytap
Scanning dependencies of target pfs_connect_attr-t
[ 69%] Building CXX object storage/perfschema/unittest/CMakeFiles/pfs_connect_attr-t.dir/pfs_connect_attr-t.cc.o
[ 69%] Building CXX object storage/perfschema/unittest/CMakeFiles/pfs_connect_attr-t.dir/__/__/__/sql/sql_builtin.cc.o
[ 69%] Linking CXX executable ../../../runtime_output_directory/pfs_connect_attr-t


7.5GB 编译文件大小

为了快 开启并行编译命令是 4 是CPU数量 make -j 4   不过不建议 容易报错.

如果遇到错误,则继续MAKE下 重新编译都能编译过去.


安装 

make install 

安装我们指定目录下


进入安装目录

cd u01/mysql8/soft

[root@CENT0S7 soft]# dirsize
20K    ./docs
228M    ./lib
384K    ./include
1.1G    ./bin
9.0M    ./share
576M    ./mysql-test
20K    ./support-files
0    ./run
0    ./var
832K    ./man
1.9G    .
[root@CENT0S7 soft]#                                   


然后按正常二进制安装流程走了


新建数据库初始化SHELL

vim mysql_initdb.sh


./bin/mysqld --initialize --user=mysql  --basedir=/u01/mysql8/soft/  
--datadir=/u01/mysql8/data --character-set-server=UTF8MB4


注意一定要设置字符集UTF8MB4 ,最好在一行

第二个注意是初始化前DATA目录必须RM -RF 掉

初始化遇到任何ERROR而终止的话,DATA目录也必须RM -RF 掉

然后百度去处理问题

成功如下信息:

[root@localhost mysql8020debug]# sh mysql_initdb.sh 


2020-07-10T23:22:03.0111260 [System] [MY-013169] [Server] /u01/mysql/mysql8020debug/bin/mysqld (mysqld 8.0.20-debug) initializing of server in progress as process 3807
2020-07-10T23:22:03.0331451 [System] [MY-013576] [InnoDB] InnoDB initialization has started.
2020-07-10T23:22:06.6000751 [System] [MY-013577] [InnoDB] InnoDB initialization has ended.
2020-07-10T23:22:14.1451636 [Note] [MY-010454] [Server] A temporary password is generated for root@localhost: YYUgDtrs6*x#
YYUgDtrs6*x#


备份下我们的DEBUG二进制版本

[root@CENT0S7 mysql8]# tar -zcvf mysql8024_debug_cenots7.tar.gz soft/ -C build/                   


[root@CENT0S7 mysql8]# cd build/
[root@CENT0S7 build]# ll
总用量 637M
-rw-r--r--. 1 root root 637M 4月  30 23:40 mysql8024_debug_cenots7.tar.gz                         


设置服务模式

进入支持文件夹

# cd/u01/mysql8/soft/support-files

编辑服务文件 mysql.server 另外一个是多实例 mysqld_multi.server

cp mysql.server mysqld

# vim mysqld

basedir=/u01/mysql8/soft

datadir=/u01/mysql8/data

另外在207行处

  conf=/etc/my.cnf

  改成   conf=/u01/mysql8/soft/my.cnf


保存后复制到服务文件夹中  

# cp mysqld /etc/init.d/


创建配置文件

# vim u01/mysql8/soft/my.cnf


[mysqld]
basedir=/u01/mysql8/softdatadir=/u01/mysql8/data
character-set-server=UTF8MB4
socket=/tmp/mysql.sock
init_connect='SET NAMES utf8'
join_buffer_size = 128M
sort_buffer_size = 2M
read_rnd_buffer_size = 2M

[mysqld_safe]
pid-file=/u01/mysql8/soft/mysqld.pid
log-error =/u01/mysql8/soft/mysql-error.log

#InnoDB#
default-storage-engine=INNODB
innodb_buffer_pool_size=128M
innodb_log_file_size=256M
innodb_log_buffer_size=12M


启动服务: 

[root@localhost init.d]# service mysqld start


Starting MySQL.2020-07-10T23:42:54.738179Z mysqld_safe error: 
log-error set to '/u01/mysql/mysql8020debug/mysql-error.log',
 however file don't exists. Create writable for user 'mysql'.
 ERROR! The server quit without updating PID file 
(/u01/mysql/mysql8020debug/data/localhost.localdomain.pid).  


添加用户,密码和组: 

这里添加DBA组, mysql用户 mysql密码


groupadd -g 1000 dba
useradd -u 1100 -g dba -d /home/mysql -s /bin/bash -c "zabbix mysql8.0 Owner" mysql
echo "mysql" | passwd --stdin mysql

  

设置目录权限


cd /
chown root:dba u01
cd /u01
chown -R mysql:dba mysql8/



成功启动服务

[root@localhost u01]# service mysqld start

Starting MySQL... SUCCESS! 

[root@localhost u01]# service mysqld stop

Shutting down MySQL.. SUCCESS! 

[root@localhost u01]# service mysqld start


登录MYSQL服务里

新开个SHELL窗口 切换到MYSQL用户下

cd u01/mysql8/soft

[mysql@localhost mysql8024debug]$ ./bin/mysql -uroot -pYYUgDtrs6*x#


mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.0.20-debug

Copyright (c) 2000, 2020, 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> 



注意临时密码有特殊符号需要这样处理 : ./mysql -uroot -p'<6nC&pSfg9Du'

更改ROOT密码


mysql> alter user 'root'@'localhost' identified by "123456"  password expire never;
mysql> use mysql
mysql> update user set host='%' where host='localhost';
mysql> flush privileges;



   所谓动态看代码就类似我们用JAVA开发样,进入调试代码,

看函数怎么调函数,查看函数传递的变量值,设置某行为断点,当运行此行的时候就暂停,然后查相应的变量,表达式的值.步进,步出!

      不过小仙上次写C语言的使用NETBEAN 图形工具来调用GDB的,所以比较方便,不用记那么多命令。

     毕竟LINUX下好多命令,每个命令有贼多参数,参看起来又不那么友好,不可能所有参数都学一遍,经常百度下该命令,常用命令,和使用列子!


启动调试命令GDB

[root@localhost u01]# gdb

GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-51.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/>. 


输入HELP命令

(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) quit


GDB 命令简介

篇幅较长,大家稍微看看有个印象

1. 启动GDB的方法有以下几种: 

    gdb <program> 
    program也就是你的执行文件,一般在当前目录下。 

    gdb <program> core 
    用gdb同时调试一个运行程序和core文件,core是程序非法执行后core dump后产生的文件。 

    gdb <program> <PID> 
    如果你的程序是一个服务程序,那么你可以指定这个服务程序运行时的进程ID。
    gdb会自动attach上去,并调试他。program应该在PATH环境变量中搜索得到。 


2. 当以gdb <program>方式启动gdb后,gdb会在PATH路径和当前目录中搜索<program>的源文件 


3. 暂停/恢复程序运行 

调试程序中,暂停程序运行是必须的,GDB可以方便地暂停程序的运行。
你可以设置程序的在哪行停住,在什么条件下停住,在收到什么信号时停住等等。
以便于你查看运行时的变量,以及运行时的流程。 

当进程被gdb停住时,你可以使用info program 来查看程序的是否在运行,
进程号,被暂停的原因。 

在gdb中,我们可以有以下几种暂停方式:断点(BreakPoint)、
观察点(Watch Point)、捕捉点(Catch Point)、信号(Signals)、
线程停止(Thread Stops)。如果要恢复程序运行,可以使用c或是 continue命令。 

4. 设置断点(Break Points) 

我们用break命令来设置断点。下面有几点设置断点的方法: 

break <function> 
    在进入指定函数时停住。C++中可以使用class::function或function(type,type)格式来指定函数名。 

break <linenum> 
    在指定行号停住。 

break +offset 
break -offset 
    在当前行号的前面或后面的offset行停住。offiset为自然数。 

break filename:linenum
    在源文件filename的linenum行处停住。 

break filename:function
    在源文件filename的function函数的入口处停住。 

break *address 
    在程序运行的内存地址处停住。 

break 
    break命令没有参数时,表示在下一条指令处停住。 

break ... if <condition> 
    ...可以是上述的参数,condition表示条件,在条件成立时停住。
比如在循环体中,可以设置break if i==100,表示当i为100时停住程序。 

查看断点时,可使用info命令,如下所示:(注:n表示断点号) 

    info breakpoints [n] 
    info break [n] 

5. 设置观察点(WatchPoint) 

观察点一般来观察某个表达式(变量也是一种表达式)的值是否有变化了,
如果有变化,马上停住程序。我们有下面的几种方法来设置观察点: 

watch <expr> 
    为表达式(变量)expr设置一个观察点。一表达式值有变化时,马上停住程序。 

rwatch <expr> 
    当表达式(变量)expr被读时,停住程序。 

awatch <expr> 
    当表达式(变量)的值被读或被写时,停住程序。 

info watchpoints 
    列出当前所设置了的所有观察点。 

[编辑] 设置捕捉点(CatchPoint) 
你可设置捕捉点来捕捉程序运行时的一些事件。如:载入共享库(动态链接库)或是C++的异常。
设置捕捉点的格式为: 
    catch <event> 

当event发生时,停住程序。event可以是下面的内容: 

    throw 一个C++抛出的异常。(throw为关键字) 
    catch 一个C++捕捉到的异常。(catch为关键字) 
    exec 调用系统调用exec时。(exec为关键字,目前此功能只在HP-UX下有用) 
    fork 调用系统调用fork时。(fork为关键字,目前此功能只在HP-UX下有用) 
    vfork 调用系统调用vfork时。(vfork为关键字,目前此功能只在HP-UX下有用) 
    load 或 load <libname> 载入共享库(动态链接库)时。(load为关键字,目前此功能只在HP-UX下有用) 
    unload 或 unload <libname> 卸载共享库(动态链接库)时。(unload为关键字,目前此功能只在HP-UX下有用) 
    tcatch <event> 

只设置一次捕捉点,当程序停住以后,该点被自动删除。 

6. 维护停止点 

上面说了如何设置程序的停止点,GDB中的停止点也就是上述的三类。
在GDB中,如果你觉得已定义好的停止点没有用了,
你可以使用delete、clear、disable、enable这几个命令来进行维护。 

clear 
    清除所有的已定义的停止点。 

clear <function> 
clear <filename:function> 
    清除所有设置在函数上的停止点。 

clear <linenum> 
clear <filename:linenum> 
    清除所有设置在指定行上的停止点。 

delete [breakpoints] [range...] 
    删除指定的断点,breakpoints为断点号。如果不指定断点号,则表示删除所有的断点。
range 表示断点号的范围(如:3-7)。其简写命令为d。 


比删除更好的一种方法是disable停止点,disable了的停止点,GDB不会删除,
当你还需要时,enable即可,就好像回收站一样。 

disable [breakpoints] [range...] 

7. 恢复程序运行和单步调试 

当程序被停住了,你可以用continue命令恢复程序的运行直到程序结束,
或下一个断点到来。也可以使用step或next命令单步跟踪程序。 

continue [ignore-count] 
c [ignore-count] 
fg [ignore-count] 
    恢复程序运行,直到程序结束,或是下一个断点到来。ignore-count表示忽略其后的断点次数。
continue,c,fg三个命令都是一样的意思。 

step <count> 
    单步跟踪,如果有函数调用,他会进入该函数。进入函数的前提是,此函数被编译有debug信息。
很像VC等工具中的step in。后面可以加count也可以不加,不加表示一条条地执行,
加表示执行后面的count条指令,然后再停住。 

next <count> 
    同样单步跟踪,如果有函数调用,他不会进入该函数。很像VC等工具中的step over。
后面可以加count也可以不加,不加表示一条条地执行,加表示执行后面的count条指令,然后再停住。 

set step-mode 
set step-mode on 
    打开step-mode模式,于是,在进行单步跟踪时,程序不会因为没有debug信息而不停住。
这个参数很有利于查看机器码。 

set step-mode off 
    关闭step-mode模式。 

finish 
    运行程序,直到当前函数完成返回。并打印函数返回时的堆栈地址和返回值及参数值等信息。 

until 或 u 
    当你厌倦了在一个循环体内单步跟踪时,这个命令可以运行程序直到退出循环体。 

stepi 或 si 
nexti 或 ni 
    单步跟踪一条机器指令!一条程序代码有可能由数条机器指令完成,
stepi和nexti可以单步执行机器指令。
与之一样有相同功能的命令是 “display/i $pc” ,
当运行完这个命令后,
单步跟踪会在打出程序代码的同时打出机器指令(也就是汇编代码) 


查看当前MYSQLD进程号 和客户端进程

[root@localhost u01]# ps -ef | grep mysqld


MYSQL是线程模型,调试进程反而抓不到!


MYSQL客户端操作:

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| bookstore          |
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.00 sec)

mysql> use bookstore;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> show tables;
+---------------------+
| Tables_in_bookstore |
+---------------------+
| books               |
| books2              |
+---------------------+
2 rows in set (0.00 sec)

mysql> select * from books;
+----+------------------------+-------+---------------------+
| id | title                  | price | publishDate         |
+----+------------------------+-------+---------------------+
|  1 | Java编程思想           | 98.50 | 2005-01-02 00:00:00 |
|  2 | HeadFirst设计模式      | 55.70 | 2010-11-09 00:00:00 |
|  3 | 第一行Android代码      | 69.90 | 2015-06-23 00:00:00 |
|  4 | C++编程思想            | 88.50 | 2004-01-09 00:00:00 |
|  5 | HeadFirst Java         | 55.70 | 2013-12-17 00:00:00 |
|  6 | 疯狂Android            | 19.50 | 2014-07-31 00:00:00 |
+----+------------------------+-------+---------------------+
6 rows in set (0.05 sec)                                               

mysql> show processlist;
+----+-----------------+-----------+-----------+---------+-------+------------------------+------------------+
| Id | User            | Host      | db        | Command | Time  | State                  | Info             |
+----+-----------------+-----------+-----------+---------+-------+------------------------+------------------+
|  5 | event_scheduler | localhost | NULL      | Daemon  | 12096 | Waiting on empty queue | NULL             |
| 14 | root            | localhost | bookstore | Query   |     0 | starting               | show processlist |
+----+-----------------+-----------+-----------+---------+-------+------------------------+------------------+
2 rows in set (0.00 sec)

+-----------+----------------+------------------+------------------+----------------+--------------+------------+
| thread_id | processlist_id | processlist_user | processlist_host | processlist_db | thread_os_id | type       |
+-----------+----------------+------------------+------------------+----------------+--------------+------------+
|         43 |               5 | NULL              | NULL              | NULL            |        14183 | FOREGROUND |
|         46 |               7 | NULL              | NULL              | NULL            |        14187 | FOREGROUND |
|         54 |              14 | root             | localhost         | bookstore       |        24760 | FOREGROUND |
+-----------+----------------+------------------+------------------+----------------+--------------+------------+
3 rows in set (0.01 sec)


一顿操作猛如虎 重点就是抓到 进程->MYSQL线程->系统线程

注意这里是 14->54->24760


GDB 操作:

[root@localhost ~]# clear
[root@localhost ~]# ps -ef | grep mysqld
root     13815     1  0 19:11 pts/1    00:00:00 /bin/sh /u01/mysql/mysql8020debug/bin/mysqld_safe --datadir=/u01/mysql/mysql8020debug/data 
                                                --pid-file=/u01/mysql/mysql8020debug/data/localhost.localdomain.pid
mysql    14138 13815  1 19:11 pts/1    00:02:03 /u01/mysql/mysql8020debug/bin/mysqld --basedir=/u01/mysql/mysql8020debug 
                                                --datadir=/u01/mysql/mysql8020debug/data --plugin-dir=/u01/mysql/mysql8020debug/lib/plugin 
                                                 --user=mysql --log-error=/u01/mysql/mysql8020debug/mysql-error.log 
                                               --pid-file=/u01/mysql/mysql8020debug/data/localhost.localdomain.pid --socket=/tmp/mysql.sock --port=3306


##使用GDB调试MYSQLD 选择第二个 MYSQL用户下的进程14138 

##为什么不是13185 

(gdb) info thread
  Id   Target Id         Frame 
* 1    process 13815 "mysqld_safe" 0x00007f9214a9046c in waitpid () from /lib64/libc.so.6

##因为它是MYSQLD_SAFE 


[root@localhost mysql8020debug]# clear
[root@localhost mysql8020debug]# gdb -p 14138
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-51.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/>.
Attaching to process 14138
Reading symbols from /u01/mysql/mysql8020debug/bin/mysqld...
##等5秒 它读取进程DEBUG信息
done.
(no debugging symbols found)...done.
Loaded symbols for /lib64/libnss_dns.so.2
0x00007f868dde1c3d in poll () from /lib64/libc.so.6
Missing separate debuginfos, use: debuginfo-install glibc-2.17-307.el7.1.x86_64 keyutils-libs-1.5.8-3.el7.x86_64 krb5-libs-1.11.3-49.el7.x86_64 krb5-libs-1.15.1-46.el7.x86_64 libcom_err-1.42.9-17.el7.x86_64 libcom_err-1.42.9-4.el7.x86_64 libgcc-4.8.5-39.el7.x86_64 libselinux-2.2.2-6.el7.x86_64 libselinux-2.5-15.el7.x86_64 nss-softokn-freebl-3.15.4-2.el7.x86_64 openssl-libs-1.0.1e-34.el7.x86_64 openssl-libs-1.0.2k-19.el7.x86_64 pcre-8.32-12.el7.x86_64 pcre-8.32-17.el7.x86_64 sssd-client-1.11.2-65.el7.x86_64 zlib-1.2.7-13.el7.x86_64 zlib-1.2.7-18.el7.x86_64
(gdb) 
(gdb) ##等待你输入命令

##查看线程

(gdb) info thread
  Id   Target Id         Frame 
  42   Thread 0x7f867f4a7700 (LWP 14141) "mysqld" 0x00007f868fb47a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  41   Thread 0x7f867e29a700 (LWP 14142) "mysqld" 0x00007f868fb47a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  40   Thread 0x7f867da99700 (LWP 14143) "mysqld" 0x00007f868fb47a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  39   Thread 0x7f867d298700 (LWP 14144) "mysqld" 0x00007f868fb47a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  38   Thread 0x7f867ca97700 (LWP 14145) "mysqld" 0x00007f868fb47a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  37   Thread 0x7f86679ff700 (LWP 14146) "mysqld" 0x00007f868fb47a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  36   Thread 0x7f86671fe700 (LWP 14147) "mysqld" 0x00007f868fb47a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  35   Thread 0x7f86669fd700 (LWP 14148) "mysqld" 0x00007f868fb47a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  34   Thread 0x7f86661fc700 (LWP 14149) "mysqld" 0x00007f868fb47a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  33   Thread 0x7f86659fb700 (LWP 14150) "mysqld" 0x00007f868fb47a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  32   Thread 0x7f86651fa700 (LWP 14151) "mysqld" 0x00007f868fb47de2 in pthread_cond_timedwait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  31   Thread 0x7f86649f9700 (LWP 14152) "mysqld" 0x00007f868fb47de2 in pthread_cond_timedwait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  30   Thread 0x7f863dffd700 (LWP 14153) "mysqld" 0x00007f868fb47de2 in pthread_cond_timedwait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  29   Thread 0x7f863d7fc700 (LWP 14154) "mysqld" 0x00007f868fb47de2 in pthread_cond_timedwait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  28   Thread 0x7f863cffb700 (LWP 14155) "mysqld" 0x00007f868fb47de2 in pthread_cond_timedwait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  27   Thread 0x7f863c7fa700 (LWP 14156) "mysqld" 0x00007f868fb47de2 in pthread_cond_timedwait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  26   Thread 0x7f863bff9700 (LWP 14157) "mysqld" 0x00007f868fb47de2 in pthread_cond_timedwait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  25   Thread 0x7f863b7f8700 (LWP 14161) "mysqld" 0x00007f868fb47de2 in pthread_cond_timedwait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  24   Thread 0x7f863aff7700 (LWP 14162) "mysqld" 0x00007f868fb47de2 in pthread_cond_timedwait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  23   Thread 0x7f863a7f6700 (LWP 14163) "mysqld" 0x00007f868fb47de2 in pthread_cond_timedwait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  22   Thread 0x7f8639ff5700 (LWP 14166) "mysqld" 0x00007f868fb47a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  21   Thread 0x7f86397f4700 (LWP 14167) "mysqld" 0x00007f868fb4ae9d in nanosleep () from /lib64/libpthread.so.0
  20   Thread 0x7f8638ff3700 (LWP 14168) "mysqld" 0x00007f868fb47de2 in pthread_cond_timedwait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  19   Thread 0x7f862bfff700 (LWP 14169) "mysqld" 0x00007f868fb47de2 in pthread_cond_timedwait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  18   Thread 0x7f867ea42700 (LWP 14170) "xpl_worker0" 0x00007f868fb47de2 in pthread_cond_timedwait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  17   Thread 0x7f867e9fb700 (LWP 14171) "xpl_worker1" 0x00007f868fb47de2 in pthread_cond_timedwait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  16   Thread 0x7f867e9b4700 (LWP 14172) "mysqld" 0x00007f868fb47a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  15   Thread 0x7f868074c700 (LWP 14177) "mysqld" 0x00007f868fb47a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  14   Thread 0x7f862b7fe700 (LWP 14178) "mysqld" 0x00007f868fb47de2 in pthread_cond_timedwait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  13   Thread 0x7f862affd700 (LWP 14179) "mysqld" 0x00007f868fb47a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  12   Thread 0x7f862a7fc700 (LWP 14180) "mysqld" 0x00007f868fb47a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  11   Thread 0x7f8629ffb700 (LWP 14181) "mysqld" 0x00007f868fb47a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  10   Thread 0x7f86297fa700 (LWP 14182) "mysqld" 0x00007f868fb47a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  9    Thread 0x7f867e96d700 (LWP 14183) "mysqld" 0x00007f868fb47a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  8    Thread 0x7f867e925700 (LWP 14184) "mysqld" 0x00007f868dd2558a in sigwaitinfo () from /lib64/libc.so.6
  7    Thread 0x7f867e8dd700 (LWP 14185) "mysqld" 0x00007f868dde6bf9 in syscall () from /lib64/libc.so.6
  6    Thread 0x7f8628ff9700 (LWP 14187) "mysqld" 0x00007f868fb47a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  5    Thread 0x7f867c275700 (LWP 24685) "mysqld" 0x00007f868fb47a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0        
---Type <return> to continue, or q <return> to quit---
  4    Thread 0x7f86641f8700 (LWP 24725) "mysqld" 0x00007f868fb47a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  3    Thread 0x7f86641b0700 (LWP 24760) "mysqld" 0x00007f868dde1cff in ppoll () from /lib64/libc.so.6
  2    Thread 0x7f8664168700 (LWP 25684) "mysqld" 0x00007f868fb47a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
* 1    Thread 0x7f868ff58980 (LWP 14138) "mysqld" 0x00007f868dde1c3d in poll () from /lib64/libc.so.6


##在众多线程中哪个是我们的客户端线程呢?

LWP 24760==>THREAD_OS_ID


##切换到对应的线程上 3

(gdb) thread 3

[Switching to thread 3 (Thread 0x7f86641b0700 (LWP 24760))]

#0  0x00007f868dde1cff in ppoll () from lib64/libc.so.6


##打印堆栈信息:


(gdb) bt
#0  0x00007f868dde1cff in ppoll () from /lib64/libc.so.6
#1  0x00000000055a00bf in vio_io_wait (vio=0x7f8658001920, event=VIO_IO_EVENT_READ, timeout=28800000) at /u01/mysql/source/mysql-8.0.20/vio/viosocket.cc:842
#2  0x000000000559eb44 in vio_socket_io_wait (vio=0x7f8658001920, event=VIO_IO_EVENT_READ) at /u01/mysql/source/mysql-8.0.20/vio/viosocket.cc:105
#3  0x000000000559ecdd in vio_read (vio=0x7f8658001920, buf=0x7f8658006c50 "\001", size=4) at /u01/mysql/source/mysql-8.0.20/vio/viosocket.cc:168
#4  0x00000000037d61fb in net_read_raw_loop (net=0x7f86580048d8, count=4) at /u01/mysql/source/mysql-8.0.20/sql-common/net_serv.cc:1221
#5  0x00000000037d6512 in net_read_packet_header (net=0x7f86580048d8) at /u01/mysql/source/mysql-8.0.20/sql-common/net_serv.cc:1304
#6  0x00000000037d6e27 in net_read_packet (net=0x7f86580048d8, complen=0x7f86641afa80) at /u01/mysql/source/mysql-8.0.20/sql-common/net_serv.cc:1594
#7  0x00000000037d70c1 in my_net_read (net=0x7f86580048d8) at /u01/mysql/source/mysql-8.0.20/sql-common/net_serv.cc:1684
#8  0x0000000003bff056 in Protocol_classic::read_packet (this=0x7f8658002130) at /u01/mysql/source/mysql-8.0.20/sql/protocol_classic.cc:1404
#9  0x0000000003bffc1d in Protocol_classic::get_command (this=0x7f8658002130, com_data=0x7f86641afbd0, cmd=0x7f86641afbfc)
    at /u01/mysql/source/mysql-8.0.20/sql/protocol_classic.cc:2809
#10 0x0000000003616dd7 in do_command (thd=0x7f8658002db0) at /u01/mysql/source/mysql-8.0.20/sql/sql_parse.cc:1220
#11 0x00000000037db47f in handle_connection (arg=0xa13d2e0) at /u01/mysql/source/mysql-8.0.20/sql/conn_handler/connection_handler_per_thread.cc:302
#12 0x0000000005330060 in pfs_spawn_thread (arg=0xa161680) at /u01/mysql/source/mysql-8.0.20/storage/perfschema/pfs.cc:2854
#13 0x00007f868fb43ea5 in start_thread () from /lib64/libpthread.so.0
#14 0x00007f868ddec8dd in clone () from /lib64/libc.so.6


##设置断点函数 my_net_read

(gdb) b my_net_read
Breakpoint 1 at 0x37d7058: file /u01/mysql/source/mysql-8.0.20/sql-common/net_serv.cc, line 1681.

##客户端发起SQL语句

mysql> select * from books;




##你会发现它卡着,不返回任何数据


##GDB 单步调试 一路火花带闪电 你可以输入C命令 然后碰到断点函数就停下来,我们这里N 过去


(gdb) n
Single stepping until exit from function ppoll,
which has no line number information.
vio_io_wait (vio=0x7f8658001920, event=VIO_IO_EVENT_READ, timeout=28800000) at /u01/mysql/source/mysql-8.0.20/vio/viosocket.cc:846
846      } while (ret < 0 && vio_should_retry(vio) &&
(gdb) n
834      do {
(gdb) n
850      vio->poll_shutdown_flag.clear();
(gdb) n
853      switch (ret) {
(gdb) n
866          DBUG_ASSERT(pfd.revents & revents);
(gdb) n
867          break;
(gdb) n
870      MYSQL_END_SOCKET_WAIT(locker, 0);
(gdb) n
871      return ret;
(gdb) n
788      DBUG_TRACE;
(gdb) n
872    }
(gdb) n
vio_socket_io_wait (vio=0x7f8658001920, event=VIO_IO_EVENT_READ) at /u01/mysql/source/mysql-8.0.20/vio/viosocket.cc:116
116          ret = 0;
(gdb) n
117          break;
(gdb) n
120      return ret;
(gdb) n
121    }
(gdb) n
vio_read (vio=0x7f8658001920, buf=0x7f8658006c50 "\001", size=4) at /u01/mysql/source/mysql-8.0.20/vio/viosocket.cc:146
146      while ((ret = mysql_socket_recv(vio->mysql_socket, (SOCKBUF_T *)buf, size,
(gdb) n
170      return ret;
(gdb) n
138      DBUG_TRACE;
(gdb) p buf
$1 = (uchar *) 0x7f8658006c50 "\024"
(gdb) dislplay
Undefined command"dislplay".  Try "help".
(gdb) dislpaly
Undefined command"dislpaly".  Try "help".
(gdb) display
(gdb) n
171    }
(gdb) n
net_read_raw_loop (net=0x7f86580048d8, count=4) at /u01/mysql/source/mysql-8.0.20/sql-common/net_serv.cc:1224
1224        if (recvcnt == VIO_SOCKET_ERROR) {
(gdb) n
1232        else if (!recvcnt) {
(gdb) n
1237        count -= recvcnt;
(gdb) n
1238        buf += recvcnt;
(gdb) n
1240        thd_increment_bytes_received(recvcnt);
(gdb) p buf
$2 = (uchar *) 0x7f8658006c54 "\004-"
(gdb) n
1220      while (count) {
(gdb) n
1245      if (count) {
(gdb) n
1266      return count != 0;
(gdb) n
1267    }
(gdb) n
net_read_packet_header (net=0x7f86580048d8) at /u01/mysql/source/mysql-8.0.20/sql-common/net_serv.cc:1305
1305        server_extension->m_after_header(net, user_data, count, rc);
(gdb) p user_data
$3 = (void *) 0x7f8658002db0
(gdb) p count
$4 = 4
(gdb) n
1312      if (rc) return true;
(gdb) n
1314      DBUG_DUMP("packet_header", net->buff + net->where_b, NET_HEADER_SIZE);
(gdb) n
1316      pkt_nr = net->buff[net->where_b + 3];
(gdb) n
1322      if (pkt_nr != (uchar)net->pkt_nr) {
(gdb) n
1340      net->pkt_nr++;
(gdb) n
1342      return false;
(gdb) n
1343    }
(gdb) n
net_read_packet (net=0x7f86580048d8, complen=0x7f86641afa80) at /u01/mysql/source/mysql-8.0.20/sql-common/net_serv.cc:1596
1596      net->compress_pkt_nr = net->pkt_nr;
(gdb) n
1598      if (net->compress) {
(gdb) n
1614      pkt_len = uint3korr(net->buff + net->where_b);
(gdb) n
1617      if (!pkt_len) goto end;
(gdb) n
1619      pkt_data_len = max(pkt_len, *complen) + net->where_b;
(gdb) n
1622      if ((pkt_data_len >= net->max_packet) && net_realloc(net, pkt_data_len))
(gdb) n
1626      if (net_read_raw_loop(net, pkt_len)) goto error;
(gdb) n
1629      DBUG_DUMP("net read", net->buff + net->where_b, pkt_len);
(gdb) n
1630      net->reading_or_writing = 0;
(gdb) n
1631      return pkt_len;
(gdb) n
1636    }
(gdb) n
my_net_read (net=0x7f86580048d8) at /u01/mysql/source/mysql-8.0.20/sql-common/net_serv.cc:1685
1685        if (len == MAX_PACKET_LENGTH) {
(gdb) p len
$5 = 20
(gdb) n
1697        net->read_pos = net->buff + net->where_b;
(gdb) n
1698        if (len != packet_error)


## 终于发现了SQL,输入P命令 显示某个变量 值

(gdb) p net->read_pos
$6 = (unsigned char *) 0x7f8658006c50 "\003select * from booksore\005books\005books\002id\002id\f?"
(gdb) 


##继续一路火花带闪电

(gdb) n
1700        return static_cast<ulong>(len);
(gdb) p len
$7 = 20
(gdb) n
1812    }
(gdb) n
Protocol_classic::read_packet (this=0x7f8658002130) at /u01/mysql/source/mysql-8.0.20/sql/protocol_classic.cc:1405
1405      if (input_packet_length != packet_error) {
(gdb) n
1406        DBUG_ASSERT(!m_thd->net.error);
(gdb) n
1407        bad_packet = false;
(gdb) n
1408        input_raw_packet = m_thd->net.read_pos;
(gdb) n
1409        return 0;
(gdb) n
1414    }
(gdb) n
Protocol_classic::get_command (this=0x7f8658002130, com_data=0x7f86641afbd0, cmd=0x7f86641afbfc) at /u01/mysql/source/mysql-8.0.20/sql/protocol_classic.cc:2819
2819      if (input_packet_length == 0) /* safety */
(gdb) p input_packet_length
$8 = 20
(gdb) n
2826      input_raw_packet[input_packet_length] = '\0'; /* safety */
(gdb) n
2828      *cmd = (enum enum_server_command)(uchar)input_raw_packet[0];
(gdb) p cmd
$9 = (enum_server_command *) 0x7f86641afbfc
(gdb) p *cmd
$10 = COM_SLEEP
(gdb) n
2830      if (*cmd >= COM_END) *cmd = COM_END;  // Wrong command
(gdb) p COM_END
$11 = COM_END
(gdb) p *cmd
$12 = COM_QUERY
(gdb) p cmd
$13 = (enum_server_command *) 0x7f86641afbfc
(gdb) p 0x7f86641afbfc
$14 = 140215181835260
(gdb) n
2832      DBUG_ASSERT(input_packet_length);
(gdb) n
2834      input_packet_length--;
(gdb) n
2835      input_raw_packet++;
(gdb) n
2837      return parse_packet(com_data, *cmd);
(gdb) p com_data
$15 = (COM_DATA *) 0x7f86641afbd0
(gdb) n
2838    }
(gdb) n
do_command (thd=0x7f8658002db0) at /u01/mysql/source/mysql-8.0.20/sql/sql_parse.cc:1221
1221      thd->m_server_idle = false;


##开启源码代码窗口,显示行号并跳到1221行

vim /u01/mysql/source/mysql-8.0.20/sql/sql_parse.cc
set number
: 1221G


##定位到C++代码区

1208   /*
1209     Because of networking layer callbacks in place,
1210     this call will maintain the following instrumentation:
1211     - IDLE events
1212     - SOCKET events
1213     - STATEMENT events
1214     - STAGE events
1215     when reading a new network packet.
1216     In particular, a new instrumented statement is started.
1217     See init_net_server_extension()
1218   */

1219   thd->m_server_idle = true;
1220   rc = thd->get_protocol()->get_command(&com_data, &command);
1221   thd->m_server_idle = false;
1222 
1223   if (rc) {
1224 #ifndef DBUG_OFF
1225     char desc[VIO_DESCRIPTION_SIZE];
1226     vio_description(net->vio, desc);
1227     DBUG_PRINT("info", ("Got error %d reading command from socket %s",
1228                         net->error, desc));
1229 #endif  // DBUG_OFF
1230     /* Instrument this broken statement as "statement/com/error" */
1231     thd->m_statement_psi = MYSQL_REFINE_STATEMENT(
1232         thd->m_statement_psi, com_statement_info[COM_END].m_key);
1233 
1234     /* Check if we can continue without closing the connection */
1235 
1236     /* The error must be set. */
1237     DBUG_ASSERT(thd->is_error());
1238     thd->send_statement_status();
1239 
1240     /* Mark the statement completed. */
1241     MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da());
1242     thd->m_statement_psi = nullptr;
1243     thd->m_digest = nullptr;
1244 
1245     if (rc < 0) {
1246       return_value = true;  // We have to close it.
1247       goto out;
1248     }
1249     net->error = 0;
1250     return_value = false;
1251     goto out;
1252   }
1253 


##GDB端奇怪的事情,执行的不是1221后面的代码 直接跳到1256行

1223      if (rc) {
1256      vio_description(net->vio, desc);
1257      DBUG_PRINT("info", ("Command on %s = %d (%s)", desc, command,
1260      DBUG_PRINT("info", ("packet: '%*.s'; command: %d",
1263      if (thd->get_protocol_classic()->bad_packet)
1267      thd->get_protocol_classic()->get_output_packet()->shrink(
1268          thd->variables.net_buffer_length);
1270      my_net_set_read_timeout(net, thd->variables.net_read_timeout);
1272      DEBUG_SYNC(thd, "before_command_dispatch");
1274      return_value = dispatch_command(thd, &com_data, command);
1275      thd->get_protocol_classic()->get_output_packet()->shrink(
1276          thd->variables.net_buffer_length);
1280      DBUG_ASSERT(thd->m_digest == nullptr);
1281      DBUG_ASSERT(thd->m_statement_psi == nullptr);
1282      return return_value;
1164      DBUG_TRACE;
1282      return return_value;
1283    }
handle_connection (arg=0xa13d2e0) at /u01/mysql/source/mysql-8.0.20/sql/conn_handler/connection_handler_per_thread.cc:301
301          while (thd_connection_alive(thd)) {


##此时MYSQL客户端获得了结果集.

mysql> select * from books;
+----+------------------------+-------+---------------------+
| id | title                  | price | publishDate         |
+----+------------------------+-------+---------------------+
|  1 | Java编程思想           | 98.50 | 2005-01-02 00:00:00 |
|  2 | HeadFirst设计模式      | 55.70 | 2010-11-09 00:00:00 |
|  3 | 第一行Android代码      | 69.90 | 2015-06-23 00:00:00 |
|  4 | C++编程思想            | 88.50 | 2004-01-09 00:00:00 |
|  5 | HeadFirst Java         | 55.70 | 2013-12-17 00:00:00 |
|  6 | 疯狂Android            | 19.50 | 2014-07-31 00:00:00 |
+----+------------------------+-------+---------------------+
6 rows in set (19 min 9.88 sec)



##发现GDB执行的函数是在1221后面的代码

1254 #ifndef DBUG_OFF
1255   char desc[VIO_DESCRIPTION_SIZE];
1256   vio_description(net->vio, desc);
1257   DBUG_PRINT("info", ("Command on %s = %d (%s)", desc, command,
1258                       command_name[command].str));
1259 #endif  // DBUG_OFF
1260   DBUG_PRINT("info", ("packet: '%*.s'; command: %d",
1261                       thd->get_protocol_classic()->get_packet_length(),
1262                       thd->get_protocol_classic()->get_raw_packet(), command));
1263   if (thd->get_protocol_classic()->bad_packet)
1264     DBUG_ASSERT(0);  // Should be caught earlier
1265 
1266   // Reclaim some memory
1267   thd->get_protocol_classic()->get_output_packet()->shrink(
1268       thd->variables.net_buffer_length);
1269   /* Restore read timeout value */
1270   my_net_set_read_timeout(net, thd->variables.net_read_timeout);
1271 
1272   DEBUG_SYNC(thd, "before_command_dispatch");
1273 
1274   return_value = dispatch_command(thd, &com_data, command);
1275   thd->get_protocol_classic()->get_output_packet()->shrink(
1276       thd->variables.net_buffer_length);
1277 
1278 out:
1279   /* The statement instrumentation must be closed in all cases. */
1280   DBUG_ASSERT(thd->m_digest == nullptr);
1281   DBUG_ASSERT(thd->m_statement_psi == nullptr);
1282   return return_value;
1283 }



最后感觉代码量不是很多,或许BT显示堆栈函数比较少,或者N 单步调试NEXT方式没有显示更多的函数调用路径. 当然我们还是掌握了方法!


上次有两个问题没搞明白

1 是 为什么一定要开启调试线程 ? 因为MYSQL是线程模型,当是你也可以调试整个MYSQLD服务进程

  使用GDB 要先设置断点,MYSQLD遇到断点所有线程和服务都停了下来. 为此你不调试线程也可以.

  不过我们是要跟踪某个线程执行流程,执行了哪些函数? 如果调试进程是无法抓到的,.


2 是 为什么没有执行 IF(RC) {...} 里面的代码?  当时折腾了会儿,后来几天想起来 估计不符合RC的条件


[root@localhost ~]# gdp -p 6041
(gdb) b do_command
Breakpoint 1 at 0x3616c8e: file /u01/mysql/source/mysql-8.0.20/sql/sql_parse.cc, line 1161.
(gdb) n
Single stepping until exit from function poll,
which has no line number information.


GDB 挂死了!


杀伤GDB 再来,顶多重启系统


调试窗口:

(gdb) b do_command
Breakpoint 1 at 0x3616c8e: file /u01/mysql/source/mysql-8.0.20/sql/sql_parse.cc, line 1161.
(gdb) c
Continuing.


MySQL客户端窗口:

mysql> select * from books;


调试窗口:

[Switching to Thread 0x7f1f940f5700 (LWP 3398)]
Breakpoint 1, do_command (thd=0x7f1f6c006790)
    at /u01/mysql/source/mysql-8.0.20/sql/sql_parse.cc:1161
1161      NET *net = nullptr;

## 啥意思呢?

info thread
2    Thread 0x7f1f940f5700 (LWP 3398"mysqld" do_command (thd=0x7f1f6c006790)


明白了! GDB 调试服务进程时,设置断点函数后, 客户端发出SQL请求, 这时GDB处于死人状态.

为此在设置断点后输入C 命令让GDB继续下去. 然后才让客户端发SQL请求,这时GDB就触发了断点函数,并且自动切换到该线程上, 并且停止1161这行,只要N的命令就可以追踪下去了!

这样就省了我们去查客户端的进程,线程,OS线程麻烦!  不过在生产环境,也就是多用户同时发出SQL语句下,这方法估计不好使. 

不过对于我们学习内核源码来说,没有那么多客户端并发操作!


源码代码:


1158 bool do_command(THD *thd) {
1159   bool return_value;
1160   int rc;
1161   NET *net = nullptr;
1162   enum enum_server_command command;
1163   COM_DATA com_data;
1164   DBUG_TRACE;
1165   DBUG_ASSERT(thd->is_classic_protocol());


然后一路火花带闪电N下去, 遇到了RC P一下 结果真的为0

(gdb) n
1164      DBUG_TRACE;
(gdb) n
1165      DBUG_ASSERT(thd->is_classic_protocol());
(gdb) n
1171      thd->lex->set_current_select(nullptr);
(gdb) n
1179      thd->clear_error();  // Clear error message
(gdb) n
1180      thd->get_stmt_da()->reset_diagnostics_area();
(gdb) n
1188      net = thd->get_protocol_classic()->get_net();
(gdb) n
1189      my_net_set_read_timeout(net, thd->variables.net_wait_timeout);
(gdb) n
1190      net_new_transaction(net);
(gdb) n
1206      DEBUG_SYNC(thd, "before_do_command_net_read");
(gdb) n
1219      thd->m_server_idle = true;
(gdb) n
1220      rc = thd->get_protocol()->get_command(&com_data, &command);
(gdb) n
1221      thd->m_server_idle = false;
(gdb) n
1223      if (rc) {
(gdb) p rc
$1 = 0
(gdb) n
1256      vio_description(net->vio, desc);
(gdb) n
1257      DBUG_PRINT("info", ("Command on %s = %d (%s)", desc, command,
(gdb) n
1260      DBUG_PRINT("info", ("packet: '%*.s'; command: %d",
(gdb) n
1263      if (thd->get_protocol_classic()->bad_packet)
(gdb) n
1267      thd->get_protocol_classic()->get_output_packet()->shrink(
(gdb) n
1268          thd->variables.net_buffer_length);
(gdb) n
1270      my_net_set_read_timeout(net, thd->variables.net_read_timeout);
(gdb) n
1272      DEBUG_SYNC(thd, "before_command_dispatch");
(gdb) n
1274      return_value = dispatch_command(thd, &com_data, command);
(gdb) n
1275      thd->get_protocol_classic()->get_output_packet()->shrink(
(gdb) n
1276          thd->variables.net_buffer_length);
(gdb) n
1280      DBUG_ASSERT(thd->m_digest == nullptr);
(gdb) n
1281      DBUG_ASSERT(thd->m_statement_psi == nullptr);
(gdb) n
1282      return return_value;
(gdb) n
1164      DBUG_TRACE;
(gdb) n
1282      return return_value;
(gdb) n
1283    }
(gdb) n
handle_connection (arg=0xa739020)
    at /u01/mysql/source/mysql-8.0.20/sql/conn_handler/connection_handler_per_thread.cc:301
301          while (thd_connection_alive(thd)) {


在1275 1276 行的函数执行完后,客户端就收到了数据


Breakpoint 1, do_command (thd=0x7f1f6c006790)
    at /u01/mysql/source/mysql-8.0.20/sql/sql_parse.cc:1161
1161      NET *net = nullptr;
(gdb) n
1164      DBUG_TRACE;
(gdb) n
1165      DBUG_ASSERT(thd->is_classic_protocol());
(gdb) n
1171      thd->lex->set_current_select(nullptr);
(gdb) n
1179      thd->clear_error();  // Clear error message
(gdb) n
1180      thd->get_stmt_da()->reset_diagnostics_area();
(gdb) n
1188      net = thd->get_protocol_classic()->get_net();
(gdb) n
1189      my_net_set_read_timeout(net, thd->variables.net_wait_timeout);
(gdb) n
1190      net_new_transaction(net);
(gdb) n
1206      DEBUG_SYNC(thd, "before_do_command_net_read");
(gdb) n
1219      thd->m_server_idle = true;
(gdb) n
1220      rc = thd->get_protocol()->get_command(&com_data, &command);
(gdb) n
1221      thd->m_server_idle = false;
(gdb) n
1223      if (rc) {
(gdb) n
1256      vio_description(net->vio, desc);
(gdb) n
1257      DBUG_PRINT("info", ("Command on %s = %d (%s)", desc, command,
(gdb) n
1260      DBUG_PRINT("info", ("packet: '%*.s'; command: %d",
(gdb) n
1263      if (thd->get_protocol_classic()->bad_packet)
(gdb) n
1267      thd->get_protocol_classic()->get_output_packet()->shrink(
(gdb) n
1268          thd->variables.net_buffer_length);
(gdb) n
1270      my_net_set_read_timeout(net, thd->variables.net_read_timeout);
(gdb) n
1272      DEBUG_SYNC(thd, "before_command_dispatch");
(gdb) n
1274      return_value = dispatch_command(thd, &com_data, command);
(gdb) p thd
$17 = (THD *) 0x7f1f6c006790
(gdb) p com_data
$18 = {com_init_db = {db_name = 0x7f1f6c00bbe1 "select * from books", length = 19}, 
  com_refresh = {options = 225 '\341'}, com_kill = {id = 139772932701153}, 
  com_set_option = {opt_command = 1811987425}, com_stmt_execute = {
    stmt_id = 139772932701153, open_cursor = 19, parameters = 0x7f1f6c00bbe8
    parameter_count = 139772932688388, has_new_types = 32 ' '}, com_stmt_fetch = {
    stmt_id = 139772932701153, num_rows = 19}, com_stmt_send_long_data = {
    stmt_id = 139772932701153, param_number = 19, longdata = 0x7f1f6c00bbe8 "* from books"
    length = 139772932688388}, com_stmt_prepare = {
    query = 0x7f1f6c00bbe1 "select * from books", length = 19}, com_stmt_close = {
    stmt_id = 1811987425}, com_stmt_reset = {stmt_id = 1811987425}, com_query = {
    query = 0x7f1f6c00bbe1 "select * from books", length = 19}, com_field_list = {
    table_name = 0x7f1f6c00bbe1 "select * from books", table_name_length = 19
    query = 0x7f1f6c00bbe8 "* from books", query_length = 1811974660}}
(gdb) p command
$19 = COM_QUERY
(gdb) n
1275      thd->get_protocol_classic()->get_output_packet()->shrink(
(gdb) n
1276          thd->variables.net_buffer_length);


1274行的dispatch_command(thd, &com_data, command);  这个是命令分配器吗?

THD 估计是线程, COM_DATA是命令数据包, COMMAND 是命令类型



不过还是感觉有点跳跃性, 语法分析,优化分析,生成执行计划,读MVCC 之类的函数 都没有找到, 感觉就一两个函数就结束了.







各位亲,最近微信改了推送规则,公众号文章已不是按时间先后推送文章,而是根据权重推荐文章了。


如果您看我们的推文少了,或者从来不评论、不点赞、不点在看、不转发,那您以后可能就再也收不到我们的推送了。


所以,如果您以后还想收到我们的推送,可以给标个星标,经常点在看和赞,转发分享,给我们评论留言,感谢各位亲们一路支持








文章转载自海鲨数据库架构师,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论