本文首发于个人公众号 Linux云计算网络(id: cloud_dev),专一于干货分享,号内有 10T 书籍和视频资源,后台回复 「1024」 便可领取,欢迎你们关注,二维码文末能够扫。html
GDB(GNU Debugger)是 UNIX 及 UNIX-like 下的强大调试工具,能够调试 ada, c, c++, asm, minimal, d, fortran, objective-c, go, java,pascal 等语言,这一份指南咱们主要以 c 来做为例子。java
# gdb helloworld
Reading symbols from helloWorld...(no debugging symbols found)...done.
# gdb helloworld
Reading symbols from helloWorld...done.
复制代码
上面一种有 no debugging symbols found
表示不可调试,下面是可调式的。linux
或者 readelf 查看段信息:c++
1# readelf -S helloworld|grep debug
2 [28] .debug_aranges PROGBITS 0000000000000000 0000106d
3 [29] .debug_info PROGBITS 0000000000000000 0000109d
4 [30] .debug_abbrev PROGBITS 0000000000000000 0000115b
5 [31] .debug_line PROGBITS 0000000000000000 000011b9
6 [32] .debug_str PROGBITS 0000000000000000 000011fc
复制代码
若是没有输出任何 debug 信息,也不能调试。objective-c
加上 -g
选项:shell
gcc -g -o xxx xxx.c
复制代码
b 行号或函数
添加断点编程
r
跑到下一个断点vim
s
单步跟踪数组
n
单步执行bash
p
查看当前程序的运行数据 好比:p a
输出a变量的值 输出格式能够设置: 好比p/d a
十进制输出a变量的值
p array@idx
能够查看数组 array 中 idx 处的值
设置display,好比 display a
这样之后每次调试都会输出a变量的值
x
查看内存地址中的值 语法:x/
l
查看原程序代码,l 9
列出第9行附件的源码(l 2,8
列出2-8行之间的数据),l func
列出指定函数附件的源码
p x=8
在调试过程当中修改变量x的值,下面生效
jump
实现跳转,能够是文件的行号,也能够是file:line,也能够是+num这种格式 jump address是代码行的内存地址
signal
产生信号量
return
强制返回
call
强制调用
until(简写u)
当在一个循环体内时,运行退出循环
until +行号
运行至某行停住,不只仅跳出循环
finish
当前函数执行完,并打印函数返回时的堆栈地址和返回值及参数值等信息
skip
在 step 时跳过一些不想关注的函数或者某个文件的代码,如 skip function add
表示跳过函数 add,skip file step.c
跳过文件 step.c,info skip
查看跳过的信息。
c
继续执行 跳到下一个断点
bt
查看堆栈
where
报错时查看哪里出错,与 bt
相似
info b
查看断点状况
q
退出
ptype
输出结构体类型
info registers
显示寄存器值, info all-registers
显示全部寄存器
info breakpoints
能够查看全部已设置的端点
info breakpoints
查看全部断点b 9
或者 b test.c:9
根据行号设置断点b func
根据函数名设置断点b test.c:9 if b==0
根据程序某个条件会出现问题,设置该条件断点(这样当出现问题时,会卡主,用来判断是不是该问题)rbreak print*
对全部 print 开头的函数都设断点,rbreak test.c:.
对test.c 中全部函数设断点tbreak test.c:9
设 临时断点 ,即这个断点只生效一次ignore 1 30
忽略某个断点的前面 30 次执行,从第 31 次开始生效,节约时间watch a
观察某个值或表达式,何时发生变化disable/enable num
禁用/启用全部/某个断点clear
清除全部断点,用于清除某个函数,某行的断点,如 clear func
、clear linenum
delete
删除全部断点,包括watchpoints, catchpoints,用于删除断点号的断点,如 delete bnum
p 'test.c'::a
打印某个文件的变量,p 'main'::b
打印某个函数定义的变量p *p@10
打印指针指向的内容,@后面为打印的长度p *$.next
打印链表linkNode的下一个节点内容p/x c
按十六进制打印内容(x:十六进制,d:十进制,o:八进制,t:二进制,c:字符格式,f:浮点格式)x addr
查看内存地址值display e
程序断住显示某个变量的值启动调试后,不想退出程序而编辑源码,如何作呢?
gdb 模式下用的默认编辑器是 /bin/ex
,若是没有或者想换成其余编辑器,如VIM,能够这样:
export EDITOR=/usr/bin/vim
复制代码
gdb 模式下编辑源码:
(gdb)edit 3 # 编辑第三行
(gdb)edit func # 编辑func函数
(gdb)edit test.c:5 #编辑test.c第五行
复制代码
完了以后,从新编译程序( 注意必定要带上 shell 命令,代表是shell命令 ):
(gdb)shell gcc -g -o main main.c test.c
复制代码
或者这样:
启动是带上 tui(Text User Interface),能够在多个窗口调试:
gdb main -tui
复制代码
1. 启动的时候带上参数
gdb --args xxx 参数
复制代码
2. 启动以后 run 带上参数
# gdb xxx
(gdb)run 参数
复制代码
3. 启动以后 set args 设置参数
# gdb xxx
(gdb) set args 参数
复制代码
ps -ef | grep xxx
或 pidof
进程名gdb
模式,输入 attach pid
或者直接这样:gdb <program> pid
(或 gdb <program> --pid pid
),gdb 会 自动 attach。
若是出现以下错误:
Could not attach to process. If your uid matches the uid of the target
process, check the setting of /proc/sys/kernel/yama/ptrace_scope, or try
again as the root user. For more details, see /etc/sysctl.d/10-ptrace.conf
ptrace: Operation not permitted.
复制代码
切换到 root 用户,将 /etc/sysctl.d/10-ptrace.conf
中的
kernel.yama.ptrace_scope = 1
复制代码
改成:
kernel.yama.ptrace_scope = 0
复制代码
gdb
模式,输入 set follow-fork-mode mode
(mode 可选 parent、child,表示调试父进程仍是子进程)已运行程序一般没有调试信息,但若是不能中止当前程序从新启动调试,能够:
一样的代码,再编译出一个带调试信息的版本,而后:
# gdb
(gdb) file hello
Reading symbols from hello...done.
(gdb)attach 20829
复制代码
gdb
有一组命令可以辅助多线程的调试:
info threads
:显示当前可调式的全部线程,线程 ID 前有 “*” 表示当前被调试的线程。thread id
:调试目标 id 指定的线程set scheduler-locking [on|off|step]
:多线程环境下,会存在多个线程运行,这会影响调试某个线程的结果,这个命令能够设置调试的时候多个线程的运行状况,on
表示只有当前调试的线程会继续执行,off
表示不屏蔽任何线程,全部线程均可以执行,step
表示在单步执行时,只有当前线程会执行。coredump 调试依赖于 core 文件,core 文件是程序非法执行后 core dump 后产生的文件。这是 Linux 系统的一种保护机制,当出现某些连开发和测试费了九牛二虎之力都没能发现的问题时,Linux 系统还提供了最后一道屏障,经过 core 文件就可让这些问题原形毕露。
要想让程序崩溃时产生 core 文件,须要开启,输入 ulimit -c
,若是输出为 0,表示默认关闭 core dump。
有两种方式能够开启,一种就是经过 ulimit 命令,一种是在程序中写代码开启,这里只讲第一种,第二种参考文末的引用1。
ulimit -c unlimied # 表示不限制core文件大小
ulimit -c 10 # 设置最大大小,单位为块,一块默认为512字节
复制代码
上面是临时开启,永久开启要修改 /etc/security/limits.conf
文件,增长一行:
# /etc/security/limits.conf
# <domain> <type> <item> <value>
* soft core unlimited
复制代码
这样就能够生成 core 文件,文件名就是 core,而且默认在当前程序所在目录下生成,若是要指定目录,则能够 echo "/tmp/corefile-%e-%p-%t" > /proc/sys/kernel/core_pattern
设置 core 文件保存在目录 "/tmp/corefile" 下,文件名格式为 “core-命令名-pid-时间戳”
还能够经过 echo 1 > /proc/sys/kernel/core_uses_pid
使得生成的 core 文件变成 core.pid
,pid 是该进程的 pid。
使用
gdb <program> core文件名
复制代码
或者 gdb 启动后,使用
-core <file>
-c <file>
来调试 core 文件
下面是一个例子:
#include <stdio.h>
int func(int *p) {
int y = *p;
return y;
}
int main() {
int *p = NULL;
return func(p);
}
复制代码
编译:gdb -g -o core_dump core_dump.c
,用 gdb 查看 core 文件
root@root:~$ gcc core_demo.c -o core_demo -g
root@root:~$ ./core_demo
Segmentation fault (core dumped)
root@root:~$ gdb core_demo core_demo.core.24816
...
Core was generated by './core_demo'.
Program terminated with signal 11, Segmentation fault.
#0 0x080483cd in func (p=0x0) at core_demo.c:5
5 int y = *p;
(gdb) where
#0 0x080483cd in func (p=0x0) at core_demo.c:5
#1 0x080483ef in main () at core_demo.c:12
(gdb) info frame
Stack level 0, frame at 0xffd590a4:
eip = 0x80483cd in func (core_demo.c:5); saved eip 0x80483ef
called by frame at 0xffd590c0
source language c.
Arglist at 0xffd5909c, args: p=0x0
Locals at 0xffd5909c, Previous frame's sp is 0xffd590a4
Saved registers:
ebp at 0xffd5909c, eip at 0xffd590a0
(gdb)
复制代码
能够看到,咱们能够还原 core_demo 执行时的场景,并使用 where 查看当前程序调用函数栈帧,还可使用 gdb 中的命令查看寄存器,变量等信息。
开启 GDB 调试时出现:
Missing separate debuginfos, use: debuginfo-install libgcc-4.8.5-28.el7_5.1.x86_64 numactl-libs-2.0.9-7.el7.x86_64
复制代码
解决:
/etc/yum.repos.d/CentOS-Debuginfo.repo
中的enabled
参数,将其值修改成 1yum install nss-softokn-debuginfo --nogpgcheck
debuginfo-install glibc
若是出现下面的问题: -bash: debuginfo-install: command not found
,则先安装yum-utils
,使用命令: yum install yum-utils
use: debuginfo-install libgcc-4.8.5-28.el7_5.1.x86_64 numactl-libs-2.0.9-7.el7.x86_64
3 GDB 调试利器
公众号后台回复“加群”,带你进入高手如云交流群
个人公众号 「Linux云计算网络」(id: cloud_dev) ,号内有 10T 书籍和视频资源,后台回复 「1024」 便可领取,分享的内容包括但不限于 Linux、网络、云计算虚拟化、容器Docker、OpenStack、Kubernetes、工具、SDN、OVS、DPDK、Go、Python、C/C++编程技术等内容,欢迎你们关注。