gdb常用命令及参考文档


前言

本文的目的只是为了列述gdb常用命令,供日常调试时自查

使能方式

编译的时候加上-g 去掉-s选项

-s strip - Discard symbols from object files.
-fvisibility=hidden 这个也不能加
-g gdb 编译 -g3 3只是级别。这个级别会产生更多的额外debug信息。3这个级别可以调试宏。

启动方式

gdb -xxx
# 如果想要增加更多启动参数
gdb --args  ./SSDTEST.exe -slot 1 -ns 1 -sn 1   #后面加上所有的参数

常用命令

!

在gdb内部使用!开头的命令,可以直接调用外部命令,如

(gdb) ! grep heap /proc/1131/maps
00c7d000-00d94000 rw-p 00000000 00:00 0         [heap]

help

帮助信息

proc

显示/proc中的一些信息

(gdb) help info proc
Show /proc process information about any running process.
Specify any process id, or use the program being debugged by default.

List of info proc subcommands:

info proc all -- List all available /proc info
info proc cmdline -- List command line arguments of the process
info proc cwd -- List current working directory of the process
info proc exe -- List absolute filename for executable of the process
info proc mappings -- List of mapped memory regions
info proc stat -- List process info from /proc/PID/stat
info proc status -- List process info from /proc/PID/status

l/list

list 显示多行源代码

b、break + line 或者函数名

加断点

  1. 如果是多个文件,可以对某个文件的某一行打断点, 例:对gdb_test.c的第三行打断点 b gdb_test.c:3
  2. 可以对某个函数进行打断点 例:对本程序中func()函数打断点 b func
    同理也可以对多个文件中的某一个文件的函数打断点,例: b gdb_test.c:func
break-if

利用break if命令,可以设置一个条件断点,如下

break line-or-function if expr 

例:

break 46 if testsize==100

delete、 clear

如果我们想删除某个断点,有两种方法:

  1. delete 命令 简写d
    • delete break 删除所有的断点
    • delete break n 删除某个断点 n为断点号
  2. clear 命令
    • clear 行号 删除设在某一行的断点

info

info、delete、clear 后面可以加很多东西, 包括,break, watch, display

命令功能
info break/breakpoint查看断点
info break/breakpoint N查看第N个断点
info local或locals 查看当前stack frame局部变量
info variables查看全局和静态变量
info args查看当前stack frame参数
info thread查看所有的thread

r/run

开始

n

单步执行,但是不会进入函数内部

s/step

单步执行,会进入函数内部

p/print

print查看当前某个变量 p空格后面加变量名

打印数组

可以用以下各式打印数组,头指针头加@数量

p *arrayPtr@256

set

使用set或者print可以修改变量的值

print array[1] = 12
set variable array[1] = 12

finish

跳出某个函数

c/continue

继续运行

kill

退出调试

file

装入需要调试的exe file

watch

监视变量

start

开始执行程序,在main函数的第一条语句前面停下来

display/disp

跟踪查看某个变量, 每次停下来都现实哦

catch

捕捉

catch assert -- Catch failed Ada assertions
catch catch -- Catch an exception ####重要
catch exception -- Catch Ada exceptions
catch exec -- Catch calls to exec
catch fork -- Catch calls to fork
catch load -- Catch loads of shared libraries
catch signal -- Catch signals by their names and/or numbers
catch syscall -- Catch system calls by their names and/or numbers
catch throw -- Catch an exception
catch unload -- Catch unloads of shared libraries
catch vfork -- Catch calls to vfork

x

查看内存
格式: x /nfu <addr>
说明:
x 是 examine 的缩写
n表示要显示的内存单元的个数
f表示显示方式, 可取如下值
x 按十六进制格式显示变量。
d 按十进制格式显示变量。
u 按十进制格式显示无符号整型。
o 按八进制格式显示变量。
t 按二进制格式显示变量。
a 按十六进制格式显示变量。
i 指令地址格式
c 按字符格式显示变量。
f 按浮点数格式显示变量。
u表示一个地址单元的长度
b表示单字节,
h表示双字节,
w表示四字节,
g表示八字节

举例

x/3uh buf
技巧

可以使用如下命令,把一个内存地址转化为一个指针并打印

p *(struct virtio_net*)0x20007ffefa00

backtrace/bt

查看函数调用信息(堆栈)

frame/f

查看站帧(目前运行到的地方)

args

启动程序的三种方式

  1. gdb ${你的程序} 进入gdb后,输入run(简写r) ${arg1} ${arg2} … ${argN}
  2. gdb --args ${你的程序} ${arg1} ${arg2} … ${argN} 进入gdb后,运行run。
  3. gdb进入gdb后,输入file ${你的程序}。然后使用set args ${arg1} ${arg2} … ${argN} 设定好你的程序参数,再运行run。

信号调试

handle <signal> <keywords...>
  • 在GDB中定义一个信号处理。信号可以以SIG开头或不以SIG开头,可以用定义一个要处理信号的范围(如:SIGIO- SIGKILL,表示处理从SIGIO信号到SIGKILL的信号,其中包括SIGIO, SIGIOT,SIGKILL三个信号),也可以使用关键字 all来标明要处理所有的信号。一旦被调试的程序接收到信号,运行程序马上会被GDB停住,以供调试。其可以是以下几种关键字的一个或多个。
关键字说明
nostop当被调试的程序收到信号时,GDB不会停住程序的运行,但会打出消息告诉你收到这种信号。
stop当被调试的程序收到信号时,GDB会停住你的程序。
print当被调试的程序收到信号时,GDB会显示出一条信息。
noprint当被调试的程序收到信号时,GDB不会告诉你收到信号的信息。
pass/noignore当被调试的程序收到信号时,GDB不处理信号。这表示,GDB会把这个信号交给被调试程序会处理。
nopass/ignore当被调试的程序收到信号时,GDB不会让被调试程序来处理这个信号。
info signals
info handle
查看有哪些信号在被GDB检测中。

多线程调试

  1. 进程调试死锁
    1. ulimit -c unlimited 之后kill掉进程,会产生core文件
    2. thread apply all bt
      1. gdb 会打出所有线程的栈,如果你发现有那么几个栈停在 pthread_wait 或者类似调用上,大致就可以得出结论:就是它们几个儿女情长,耽误了整个进程。
    3. 也可以使用gdb attach <进程号> 直接把attach上被死锁的进程
    4. thread 5 切换到进程5
    5. 使用bt或者f查看整体栈或者当前站帧

attach

  • 常规的通过gdb cmd这种方式开启调试,特别说明的是通过attach的方法附加到一个指定的进程上去进行调试,这种方法适合于调试一个已经运行的进程,具体用法:gdb -p [pid]
  • 此时被attach的进程会阻塞,进入T模式(ps 命令看到STATE为T),如果调试完毕了,使用 detach 命令就释放了进程,它就自由运行了。

coredump 文件

  • 开启coredump
echo "ulimit -c unlimited" >> /etc/profile
  • 设置coredump的命名规则
# 在/etc/sysctl.conf文件中加入
# 例如下面这个命令,可以通过在%e前面增加/home/之类的路径使其保存到特定路径
kernel.core_pattern=%e.core.%s_%t
并保存退出,执行下面指令使其生效
sysctl -p


# 参数含义
  %%  output one '%'
  %p  pid
  %u  uid
  %g  gid
  %s  signal number
  %t  UNIX time of dump
  %h  hostname
  %e  executable filename

# 默认是这样的 |/usr/share/apport/apport %p %s %c %P
  If the first character of the pattern is a '|', the kernel will treat
  the rest of the pattern as a command to run.  The core dump will be
  written to the standard input of that program instead of to a file.
  • 通过cat /proc/sys/kernel/core_pattern 验证设置的pattern

开始调试core文件

调试的话输入: gdb filename core

filename就是产生core文件的可执行文件,core就是产生的dump文件

使用gdb dump内存

  1. 首先使用/proc/<pid>/maps/proc/<pid>/smaps确定内存地址,然后通过如下命令dump memory
(gdb) ! grep heap /proc/1131/maps
00c7d000-00d94000 rw-p 00000000 00:00 0         [heap]
(gdb) dump binary memory /tmp/python-heap.bin 0x00c7d000 0x00d94000

然后可以使用如[xxd](https://man.cx/ xxd(1))查看内存

gdb读取内存

(gdb) define xxd
dump binary memory dump.bin $arg0 $arg0+$arg1
shell xxd dump.bin
shell rm -f dump.bin
end
(gdb) xxd 0x00007f3498000000 32
0000000: 2000 001c 367f 0000 0000 00a4 347f 0000 ...6.......4...
0000010: 0000 0004 0000 0000 0000 0004 0000 0000 ................

使用gdb打印栈帧

gdb中输入

set logging file my_back_trace.txt
thread apply all bt full
quit

或者把上述命令放到一个文件gdb-instructions.txt中并执行命令

echo -ne "set logging file my_back_trace.txt\nthread apply all bt full\nquit" > gdb-instructions.txt
gdb /exe $(pidof exe) -x gdb-instructions.txt

参考链接

  1. DebuggingWithGdb python 使用gdb调试的两种方法
  2. gdb不在断点处停留的问题 set follow-fork-mode child
  3. Stopping and starting multi-thread programs 这个应该是官方教程了吧
  4. Debugging programs with multiple threads 官方文档教你多线程debug
  5. 10.19 How to Produce a Core File from Your Program
  6. 5.5.4 Thread-Specific Breakpoints 断点只打在对应的线程上
  7. linux下利用backtrace追踪函数调用堆栈以及定位段错误
  8. gdb 打印内存和数组p *arrayPtr@256
  9. Dumping memory with GDB
  10. Linux Core Dumps

调试心得

  1. 除了问题首先要仔细排查core的地方,先把core的地方看清楚
  2. 如果core的地方没有出现abort、raise之类的,说明是core的当前行segment fault了,原因大概是因为当前行有一个空悬指针之类。
  3. 第一条说的对,一定要看core、死锁出现的地方,以及附近的代码。比如spdk里面每个core一直是100%,你就根本无法从top里面判断出来到底是spin住了还是线程得不到调度卡死了。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值