-g内s存泄露查看工具:perf
参考:
一、ROS2程序
编译要求
- 要使用GDB调试某个程序,编译时需要加上
-g
编译选项:add_compile_options(-g)
,或者set(CMAKE_<LANG>_FLAGS "${CMAKE_CXX_FLAGS} -g")
启动方法
- 不使用
ros2 run
的指令启动节点,而是进入节点可执行程序所在目录(install/
里面),在控制台输入$ ./app
- GDB调试启动:进入可执行程序所在目录,在控制台输入
$ gdb ./app
二、GDB调试指令
在控制台以gdb启动程序后通过指令控制程序执行,然后通过指令控制调试。
常用指令
gdb常用指令.png
指令用法
以gdb ./filename
方式启动GDB调试只是附加一个调试文件,并没有启动这个程序,需要输入指令来控制程序的启动和执行。
-
run
: 启动程序,在GDB界面按Ctrl + C
让GDB中断,再次输入r
,GDB会询问是否重启程序,输入y
或yes
-
continue
: 当GDB触发断点或者Ctrl + C
中断后,输入c
即可 -
break
: 简写b
,用于添加断点,方式如下
-
break FunctionName
: 在函数的入口处添加一个断点 -
break LineNo
: 在当前文件行号为LineNo处添加一个断点 -
break FileName:LineNo
: 在FileName文件行号LineNo处添加一个断点 -
break FileName:FunctionName
: 在FileName文件FunctionName函数的入口处添加断点 -
break -/+offset
: 在当前程序暂停位置的前/后offset行处下断点 -
break...if cond
: 下条件断点
- 断点管理指令
-
info break
或i b
: 显示当前所有断点信息 -
disable 断点编号
: 禁用断点 -
enable 断点编号
: 启用断点 -
delete 断点编号
: 删除断点
- 查看堆栈
-
backtrace
或者bt
: 查看当前调用堆栈 -
frame 堆栈编号
或者f 堆栈编号
: 切换到其他堆栈处
-
list
: 输出上一次list命令显示的代码后面的代码,第一次则显示当前位置附近代码
-
list -
: 显示上一次list显示的前面的代码 -
list LineNo
: 显示当前文件LineNo行附近代码 -
list FileName:LineNo
: 显示FileName文件第LineNo行附近的代码 -
list FunctionName
: 显示当前文件FunctionName函数附近的代码 -
list FileName:FunctionName
: 显示FileName文件FunctionName函数附近的代码 -
list from,to
: 其中from和to是代码位置,显示这之间代码 -
show listsize
: 查看list显示的代码行数 -
set listsize count
: 设置list显示的代码行数为count
-
print
和 type`: 查看变量
-
print param
: 在调试过程中查看变量的值 -
print param=value
: 在调试过程中修改变量的值 -
print a+b+c
: 可以进行一定的表达式计算,这里是计算a、b、c三个变量之和 -
print func()
: 输出func函数执行的结果,常见的用途是打印系统函数执行失败原因:print strerror(errno) -
print *this
: 在c++对象中,可以输出当前对象的各成员变量的值
-
whatis
和ptype
: 查看变量类型
-
whatis val
: 用于查看变量类型 -
ptype val
: 可以查看复合数据类型,打印出该类型的成员变量
-
thread
: 命令
-
info thread
: 查看当前进程的所有线程运行情况 -
thread 线程编号
: 切换到具体编号的线程上去
-
next
和step
: 单步调试
-
next
: 单步步过(step over),即遇到函数直接跳过,不进入函数内部 -
step
: 单步步入(step into),即遇到函数会进入函数内部
-
return
和finish
: 退出函数命令
-
return
: 立即退出当前函数,剩下的代码不会执行了,return 还可以指定函数的返回值 -
finish
: 会继续执行完该函数剩余代码再正常退出
-
until
: 与break
命令类似 jump
-
jump LineNo
,跳转到代码的 LineNo 行的位置 -
jump +10
,跳转到距离当前代码下10行的位置 -
jump *0x12345678
,跳转到 0x12345678 地址的代码处,地址前要加星号 - 中间跳过的代码是不会执行的
- 跳到的位置后如果没有断点,那么GDB会自动继续往后执行
-
disassemble
: 查看某段代码的汇编指令 -
set args
和show args
: 设置程序启动参数
- 很多程序启动需要我们传递参数,set args 就是用来设置程序启动参数的,show args 命令用来查询通过 set args 设置的参数
-
set args args1
: 设置单个启动参数 args1 -
set args "-p" "password"
,如果单个参数之间有空格,可以使用引号将参数包裹起来 -
set args args1 args2 args3
,设置多个启动参数,参数之间用空格隔开 -
set args
,不带参数,则清除之前设置的参数
-
tbreak
: 添加一个临时断点,断点一旦被触发就自动删除,使用方法同 break -
watch
: 命令用来监视一个变量或者一段内存,当这个变量或者内存的值发生变化时,GDB就会中断下来。被监视的某个变量或内存地址会产生一个 watch point(观察点)
watch 整型变量
-
watch 指针变量
,监视的是指针变量本身 -
watch *指针变量
,监视的是指针所指的内容 watch 数组变量或内存区间
- 当 watch 的变量或内存因超出作用域失效时,GDB 会有提示信息
- 通过 info watch 命令可以查看当前所有监视的变量,通过 delete watch编号 可以删除对某个变量的监视
-
call
: 执行指定函数
-
call func()
: 执行 func() 函数,同 print func()
-
help
: 查看目标命令的具体用法
三、GDB多线程调试
用GDB调试多线程程序时,该程序的编译需要添加 -lpthread
参数。
一些命令
-
info thread
: 查看当前调试程序启动了多少个线程,并打印出各个线程信息 -
thread 线程编号
: 将该编号的线程切换为当前线程 -
thread apply 线程编号1 线程编号2 ... command
: 将GDB命令作用指定对应编号的线程,可以指定多个线程,若要指定所有线程,用 all 替换线程编号 -
break location thread 线程编号
: 在 location 位置设置普通断点,该断点只作用在特定编号的线程上
一些术语
-
all-stop mode
: 全停模式,当程序由于任何原因在GDB下停止时,不止当前的线程停止,所有的执行线程都停止。这样允许你检查程序的整体状态,包括线程切换,不用担心当下会有什么改变 -
non-stop mode
: 不停模式,调试器(如VS2008和老版本的GDB)往往只支持 all-stop 模式,但在某些场景中,我们可能需要调试个别的线程,并且不想在调试过程中影响其他线程的运行,这样可以把GDB的调式模式由 all-stop 改成 non-stop,7.0 版本的GDB引入了 non-stop 模式。在 non-stop 模式下 continue、next、step 命令只针对当前线程 -
record mode
: 记录模式 -
replay mode
: 回放模式 -
scheduler-locking
: 调度锁 -
schedule-multiple
: 多进程调度
设置线程锁
使用GDB调试多线程程序时,默认的调试模式是:一个线程暂停运行,其他线程也随即暂停;一个线程启动运行,其他线程也随即启动。但在一些场景中,我们希望只让特定线程运行,其他线程都维持在暂停状态,即要防止线程切换,要达到这种效果,需要借助 set scheduler-locking 命令。
-
set scheduler-locking on
,锁定线程,只有当前或指定线程可以运行 -
set scheduler-locking off
,不锁定线程,会有线程切换 -
set scheduler-locking step
,当单步执行某一线程时,其他线程不会执行,同时保证在调试过程中当前线程不会发生改变。但如果在该模式下执行 continue、until、finish 命令,则其他线程也会执行 -
show scheduler-locking
,查看线程锁定状态