【建议收藏】数据库源码学习调试利器之 CGDB

CGDB 是 GDB 的一个前端工具,通过提供更丰富的界面来增强 GDB 的用户体验。如果更喜欢在增强型终端中操作,可以使用 CGDB 来代替 GDB。

作者:赵黎明,爱可生 MySQL DBA 团队成员,熟悉 Oracle、MySQL 等数据库,擅长数据库性能问题诊断、事务与锁问题的分析等,负责处理客户 MySQL 及我司自研 DMP 平台日常运维中的问题,对开源数据库相关技术非常感兴趣。 爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。

本文约 2000 字,预计阅读需要 10 分钟。

简介

CGDB (Curses-based GDB):是一个基于文本界面的 GDB 前端,主要用于在终端中提供更丰富的用户界面,CGDB 使用 Curses 库 创建了一个简单的功能界面,帮助用户更方便地使用 GDB,它在 GDB 的基础上增加了一些功能,使得调试过程更加直观和高效。

CGDB 的运行依赖 GDB 环境,因此,在调试前必须先安装符合其版本要求的 GDB

简单来说,CGDB 是 GDB 的一个前端工具,通过提供更丰富的界面来增强 GDB 的用户体验。如果更喜欢在增强型终端中操作,可以使用 CGDB 来代替 GDB。

版本选择

本次选择安装 gdb 9.2 的版本,原因主要有以下两个:

  1. CentOS 7.5 中自带 gdb 的版本 7.6.1-120.el7,而 cgdb 要求 gdb 版本为 7.12 及以上。
  2. 安装 gdb 9.0 以上版本的,还可以用于调试 OBServer,否则会报版本错误。

安装 CGDB

安装步骤:

bash 复制代码
-- 安装依赖
yum -y install automake flex texinfo ncurses-devel readline-devel gcc-c++

-- 下载源码包
git clone https://github.com/cgdb/cgdb.git

-- 编译源码
cd cgdb
./autogen.sh
./configure --prefix=/usr/local
make && make install

如果在执行 make 时报错:error: 'for' loop initial declarations are only allowed in C99 mode,可在进行编译配置时加上参数:CFLAGS="-std=c99",如:CFLAGS="-std=c99" ./configure --prefix=/usr/local

安装 GDB

注意事项:

  • 尽量不装 10.x 及以上的高版本。可能会报错:A compiler with support for C++11 language features is required
  • CentOS 7.5 默认的 gcc 版本较低(4.8.5),原则上只要够用就行,没必要追求高版本。

安装步骤:

bash 复制代码
-- 安装依赖
yum -y install gcc gcc-c++ texinfo

-- 下载源码包
wget ftp://ftp.gnu.org/gnu/gdb/gdb-9.2.tar.gz

-- 解压并编译
tar zxf gdb-9.2.tar.gz -C /tmp
cd /tmp/gdb-9.2
mkdir build && cd build
/tmp/gdb-9.2/configure
make && make install

查看 gdb 的版本,确认是否升级成功。

执行 cgdb,进入调试界面。

查看帮助

  • 键入 help + 回车键,可查看所有的 gdb 的指令和说明
  • 键入 ESC + :help + 回车键,可查看所有 cgdb 的指令和说明

具体指令和说明不在文中展示。

下面我们通过几个常用的场景示例,演示 CGDB 和 GDB 的使用过程和效果。

调试示例

示例 1:调试 MySQL 获取源码

查看 mysqld 的进程号,此处为 26238。

在 gdb 窗口执行 att 26238,将其 attach 到 mysqld 进程上。

绿色箭头代表代码当前执行的位置,会展示代码所处行号,内存地址,代码文件等信息。

按 ESC 键,会进入上半部分的代码展示窗口,能像在 vim 中那样用快捷键上下移动光标进行查看。

如果要返回 gdb 的窗口,按 i 键即可,就能继续执行调试命令了。

根据打印的源码文件和位置,去官网代码库中找到对应的文件,再搜索相应的函数,就可以获取对应的源码内容了。

示例 2:调试 MySQL 线程

执行 info threads,打印所有线程。

依次执行 threadbt,查看当前线程及该线程的 backtrace。

多次执行 s,一行一行地进行单步调试,注意调试期间 thread 是否发生变化。

当前为 ID 1 的线程,如果要切换到某个 thread,可以执行 thread [thread_id] 进行切换。

以下是 49 号线程打印的 backtrace 信息示例,可获取函数调用的顺序、调用的函数名、函数出现在源码文件中的位置。

示例 3:使用 cgdb ./mysqld 调试

采用此方式调试 mysqld 时,当其还未被 attach 到 mysqld 上时,并不会阻塞新的连接。

此时只能设置断点,查看某个函数在源码文件中的位置。

由于没有线程及其帧栈信息,并不能做进一步的调试。

示例 4:分析 coredump 文件

当程序异常崩溃时,如果配置过 coredump,就可以通过分析 coredump 文件来排查程序崩溃的原因。

第一个 coredump,是通过执行 kill -SIGSEGV [pid] (也就是 signal 11)将 mysqld 进程杀死后产生的,其实从文件命名上就可获知,mysqld-11 后面紧跟的这个 11,就是对应信号量的编号。

在 cgdb 中也打印了 mysqld 崩溃的原因,是收到了 SIGSEGV(11) 的信号量,即最常见的 Segmentaion fault

第二个 coredump,是在用 cgdb 调试时生成的,期间执行过 run 命令,将 mysqld 进程重启过,产生了 mysqld-5 的 coredump 文件。

在 cgdb 中也打印了 mysqld 崩溃的原因,是收到了 SIGTRAP(5) 的信号量。

如果对信号量不太熟悉,可用 kill -l 命令查看,它会输出所有信号量。

示例 5:使用 cgdb -p 调试

与之前先进入 cgdb 调试台,再执行 attach [pid] 的方式并无区别,后者会在 cgdb/gdb 进程中显示 mysqld 进程号。

要注意的是,这两种方式都会直接阻塞 mysql 客户端,因为此时 mysqld 会被阻塞,导致无法建立新的连接。

用 SIGSTOP/SIGCONT 的信号量来观测效果

Tips:信号量名中的 SIG 是可以被省略的,如:kill -SIGSTOP [pid]kill -STOP [pid] 是等效的。

示例 6:单独起一个 mysqld 调试

该方式可以在不影响已运行 mysqld 的基础上,对同版本的 mysqld 单独进行调试。

建议下载带 boost 的 MySQL 源码包,然后编译为 Debug 版本,可以打印更多的 debugging symbols 信息,方便调试。

示例 7:修改 MySQL 最大连接数

当 MySQL 的连接数满导致无法登陆实例时,可以用 cgdb 来救急。

下图中,当客户端连接实例时报错:"Too many connections",直接用 cgdb/gdb 来调大 max_connections 参数的值。

如果服务器上有多个 mysqld 进程时,建议直接指定 pid,否则可能改到了另一个 MySQL 实例上。

用 cgdb 修改
用 gdb 修改

总结

  • 本文简单介绍了 CGDB 及其基本使用方法。
  • 利用 CGDB 调试工具,能帮助我们梳理程序在运行时各种函数的调用逻辑,这对于学习和研究程序源码非常有帮助。
  • 当程序崩溃时,如果能拿到故障现场的 coredump 文件,可通过 CGDB 去分析程序崩溃的原因,如:在特定场景下,在调用某个函数时触发了程序的 bug 而引发的崩溃。
  • 当 MySQL 连接数被打满后,除了我们已知的 extra_port 方法之外,还可以用 CGDB 来解决。
  • 注意,生产环境严禁使用 CGDB 直接进行调试。

更多技术文章,请访问:opensource.actionsky.com/

关于 SQLE

SQLE 是一款全方位的 SQL 质量管理平台,覆盖开发至生产环境的 SQL 审核和管理。支持主流的开源、商业、国产数据库,为开发和运维提供流程自动化能力,提升上线效率,提高数据质量。

相关推荐
双子座断点9 分钟前
QStringList 使用详解
数据库
bw87672068716 分钟前
金融工程--pine-script 入门
数据库·金融
三日看尽长安花1 小时前
【Redis:原理、架构与应用】
数据库·redis·架构
尘浮生3 小时前
Java项目实战II基于Spring Boot的美食烹饪互动平台的设计与实现(开发文档+数据库+源码)
java·开发语言·数据库·spring boot·微信小程序·小程序·美食
forestqq3 小时前
构建后端为etcd的CoreDNS的容器集群(七)、编写适合阅读的域名管理脚本
运维·数据库·etcd
hongkid3 小时前
MongoDB常用操作
数据库·mongodb
岁岁岁平安3 小时前
mysql上课总结(1)(mysql中的常见的存储引擎)(面试)
数据库·mysql·innodb·存储引擎
幽兰的天空5 小时前
python实现excel数据导入数据库
数据库
尘佑不尘6 小时前
shodan5,参数使用,批量查找Mongodb未授权登录,jenkins批量挖掘
数据库·笔记·mongodb·web安全·jenkins·1024程序员节
传输能手6 小时前
从三方云服务器将数据迁移至本地,如何保障安全高效?
大数据·服务器·数据库