gdb调试summary
1.常用命令
-
watch
命令监视一个变量或者一段内存,当这个变量或者内存发生变化时,gdb就中断。—> (watch point)
- int i; watch i;
- char *p; watch p 与 watch *p;
- 监视一个数组或内存区间
char buf[128]; watch buf
; 对buf的128个数据进行了监视。
- 2
display
,每次gdb
中断,都会自动输出这些被监视变量或内存的值。 -
dir
发生调试源文件出现目录发生变化,使用dir进行目录的重定向。
2.使用gdb调试多线程程序
1. 调试多线程程序的方法
-
info thread
查看线程的数量
- 2.
thread 2
跳转对应的线程 -
bt
在对应的线程下查看对应的栈信息,可以在源码中找到对应的代码,进行分析。
-
f 站函数编号
跳转对应的栈信息,进行相应的调试
-
- 对应的函数添加 断点
b func()
,然后进行r
重新运行。
- 对应的函数添加 断点
2.在调试时控制线程切换
-
set scheduler-locking on/step/off
将程序执行流锁定在当前调试线程中, 有三个值可选on, step, off
。 与on
相比step
选项的值为单步调试提供了更加精细化的控制。当且仅当使用next
或step
命令做单步调试会锁定当前线程,如果使用until,finish,return
等线程内的调试命令,则其他线程还是会有机会运行的。
3.使用gdb调试多进程程序–以调试Nginx为例
方法一 gdb attach 进程号
以nginx 这块
//获取
wget http://nginx.org/download/nginx-1.18.0.tar.gz
// 解压
tar zxvf nginx-1.18.0.tar.gz
cd nginx-1.18.0/
// 配置
./configure --prefix=/usr/local/nginx
//编译
make CFLAGS="-g -O0"
// 安装
make install
cd /usr/local/nginx/sbin/
// 运行
sudo ./nginx -c /usr/local/nginx/conf/nginx.conf
//查看端口以及进程号
- 以
root
用户为主的是主进程,以nobody
为用户的是子进程,当客户端请求数量达到一定的限度或继续fork
新的子进程。
开启调试
附加主进程 sudo gdb attach 3490076
-
bt
查看调用栈信息
-
frame 1
切换栈的信息
-
- 基本的命令一样的
附加子进程,重启一个shell 窗口sudo gdb attach 3490077
- 基本的命令一样的
-
bt
查看子进程的调用栈信息, 同时切换栈的信息f 1
-
b 804
添加断点 然后继续运行c
-
- 客户端进行连接
http://192.168.3.1
进行访问,804
的断点就会中断,这样调试Nginx的问题。
- 客户端进行连接
方法二 set follow-fork mode
mode的取值 parent
和 child
-
show follow-fork mode
查看当前值
-
cd /usr/local/nginx/sbin/ && ./nginx -s stop
停止 nginx。
-
//src/os/unix/ngx_daemon.c:13 行
,为了不让此逻辑调用,关闭后台运行,在 nginx的配置文件中添加一行daemon off;
就行。
-
gdb nginx && set args -c /usr/local/nginx/conf/nginx.conf && r
或者在run
之前set follow-fork child
这样就会出现在子进程。
4.gdb实用调试技巧
-
print
命令输出的字符串或字符数组完整显示
set print element 0
-
- 让被调试的程序接受信号
- 1>
signal SIGINT
主动发送信号SIGINT
或者其他信号 - 2>
handle SIGINT nostop print
告诉SIGINT时不要停止,并把该信号传递给目标调试程序。
- 3.函数明明存在,添加断点无效
Make breakpoint pending on future shared library load? y/n
- 改变添加策略 ,使用函数所在的文件和行号进行添加断点。
- 4,断点:普通断点、条件断点、数据断点。
-
- 数据断点,
watch
监视的内存值或者变量发生变化触发的断点。
- 数据断点,
- 2.条件断点,触发一定的条件才会触发,
- <1>.i达到一定的值然后进行开始断点监控。
break [lineNo] if [condition]
,lineNo
是程序触发断点后需要停止的位置,condition
是断点触发的条件。这里可以写成break 11 if i== 5000
,此时11
就是需要监控的位置。 - <2>. 首先设置一个普通断点
b 11
, 然后获取断点编号info b
,然后设置"condition 断点编号 断点触发条件",实例就是condition 1 i ==5000
- <1>.i达到一定的值然后进行开始断点监控。
-
5.自定义gdb调试命令
-
- 在 root用户下,就在
/root
目录, 在 home用户下就在/home
目录下,定义一个.gdbinit
文件即可,不存在可以新建一个。然后在文件里面写上gdb
命令
Apache Web Server 源码为例,源码目录里面有一个.gdbinit
文件
- 在 root用户下,就在
# gdb macros which may be useful for folks using gdb to debug
# apache. Delete it if it bothers you
define dump_table
set $t = (apr_table_entry_t *) ((apr_array_header_t *)$arg0)->elts
set $n = ((apr_array_header_t *)$arg0)-> nelts
set $i = 0
while $i < $n
if $t[$i].val == (void *)0L
printf "[%u] '%s'=>NULL\n", $i, $t[$i].key
else
printf "[%u] '%s'='$s' [%p]\n", $i, $t[$i].key, $t[$i].val, $t[$i].val
end
set $i = $i + 1
end
end
# 省略部分代码
# Set sane defaults for common signals:
handle SIGPIPE noprint pass nostop
handle SIGUSR1 print pass nostop