18. 重定向输出
问题:若GDB与进程所属终端不同,则进程的输出不会出现GDB中
解决办法:重定向被调试进程的标准输出和标准错误
18.1 重定向
① 查看GDB所属终端的设备文件
② 关闭进程的「STDOUT_FILENO」 「STDERR_FILENO」
③ 在进程中以「只写」方式打开GDB的终端设备文件「/dev/pts/1」,达到重新生成「STDOUT_FILENO」 「STDERR_FILENO」目的
18.2 恢复
调试结束后,恢复过程步骤如下:
① 关闭进程的「STDOUT_FILENO」 「STDERR_FILENO」
② 查看进程所属终端
③ 在进程中以「只写」方式打开进程的终端设备文件「/dev/pts/4」,达到重新生成「STDOUT_FILENO」 「STDERR_FILENO」目的
18.3 标准
标准作法为,在文件「~/.gdbinit」中定义重定向函数,在GDB中直接调用
① vim ~/.gdbinit
② 重定向
③
恢复
17. .gdbinit文件
文件「.gdbinit」本质上是一个脚本,GDB 在启动的时候会按一定的路径顺序寻找该文件(通常先当前目录,然后用户HOME目录),一旦找到,就会自动执行里面的命令
用途:
①可以把一些常用命令放在这个文件里,这样就不用每次进入 gdb 后再去手动输入这些命令;
②可以把命令序列定义成一个新命令,这样只要在 gdb 里面输入这个新命令就可以自动执行命令序列
格式:
define 「CmdName」
「Cmd Sequence」
end
示例:
另外,如果用户已经在 gdb 里后,再去修改 .gdbinit ,只要通过:
(gdb) source ~/.gdbinit
便可以让那些新增加的改动生效
16. 执行shell命令
命令:shell 「Cmd」
作用:在GDB中执行shell命令
示例:
15. 调用函数
命令:call 「FunctionName」
作用:在程序的当前上下文环境中调用函数「FunctionName」
示例:
14. 信号处理
查看
命令:handle 「SigName」
作用:查看信号处理动作
示例:
设置
命令:handle 「SigName」 「Action」
作用:设置信号处理动作
动作:
◇「stop」「nostop」:当GDB收到待发往被调试进程的信号时,是否停止程序的执行。只要「Stop」为「Yes」,则「Print」为「Yes」,即只要停止,就打印输出
◇「print」「noprint」:当GDB收到待发往被调试进程的信号时,是否打印提示消息。只要「Print」为「No」,则「Stop」为「No」,即只要不打印输出,就不停止
◇「pass」「nopass」:程序继续运行后,是否将该信号,传递给被调试进程
说明:GDB调试过程中,所有发往被调试进程的信号,会先被GDB拦截,GDB视「Stop」决定是否停止程序的执行,视「Print」决定是否打印输出。待程序继续执行后(「c」),根据「Pass to program」决定是否将该信号发往被调试进程
13. until
◇ until
执行程序,直到到达当前循环体外的下一行源代码
◇ until 「FileName」:「n」
一直执行到文件「FileName」的第「n」行。注意,此时第「n」行代码并未执行,而处于等待执行状态
◇ until 「Namespace」::「ClassName」::「FuncName」
一直执行到「FuncName」函数
12. 中断点
中断点包括断点、临时断点以及观察点
△ 查看所有中断点
info b
△ 禁用中断点
disable 「BreakNo1」 「BreakNo2」...
命令简写:dis
△ 开启中断点
enable 「BreakNo1」 「BreakNo2」...
命令简写:en
△ 删除中断点
delete 「BreakNo1」 「BreakNo2」...
命令简写:d
△ 删除所有中断点
delete
命令简写:d
△ 设置触发条件
「cmd」「args」if 「condition」
参数:「cmd」可为「break」,「watch」,「rwatch」
示例:
b main.cpp:11 if m > 13 b main.cpp:11 if msg.length()==14 b main.cpp:11 if strlen(data)==14
wa m if m > 37 rw val if n == -20
△ 修改触发条件
condition 「BreakNo」 「Condition」
命令简写:cond
若中断点无触发条件,则进行添加;若中断点原有触发条件,则进行替换
△ 删除触发条件
condition 「BreakNo」
命令简写:cond
△ 忽略中断若干次
ignore 「BreakNo」 「Count」
设置中断点「BreakNo」忽略接下来的「Count」次命中
如果中断点既设置了中断条件,又设置了忽略次数,则先计算中断条件后递减忽略次数
11. 命令列表
命令:commands 「BreakNo」
功能:一旦命中「BreakNo」对应的断点或者观察点,自动执行编辑的命令
参数: 「BreakNo」为断点或者观察点的编号
简写:comm
示例:
查看所有中断点
为「24」号断点编辑命令列表
命令列表以「end」结束,上述命令列表的作用是,每当断点「24」命中,即打印变量「m」和「n」的值,然后「continue」继续执行,效果如下
10. 观察点
观察点用于监视表达式。注意,变量也为表达式
观察点不依赖于设定的位置,但是与表达式的作用域有关。也就是说,观察点必须在程序运行时才可设置,且用到的符号必须在当前上下文中可见
超出作用域,比如子函数执行结束,则在局部变量上设置的观察点,将自动删除:
10.1 watch
命令:watch 「Expression」
功能:每当表达式「Expression」的值发生改变之后,自动中断程序,并打印变化前和变化后的值
简写:wa或wat
说明:
① 中断发生的时机,是在表达式的值发生改变之后,即
wa 「m」
程序代码为
9 ++m;
10 --n;
则中断位于第「10」行,此时,变量「m」的值已经改变,GDB会自动显示「m」变化前和变化后的值
② 若赋值操作没有改变表达式的当前值,则中断不会触发,即
wa 「m」
程序代码为
11 int tmp = m;
12 m = tmp;第「12」行的赋值不会引发中断
10.2 rwatch
命令:rwatch 「Expression」
功能:每当需要引用表达式「Expression」的值之前,自动中断程序,并打印表达式的当前值
简写:rw
说明:中断发生的时机,是在引用表达式的值之前,即
rw 「m」
程序代码为
11 int tmp = m;
则中断打到第「11」行,此时第「11」行代码并未执行,而第「10」行代码刚刚执行结束
10.3 使用
△ watch 「Condition」
△ watch 「Expression」
△ rwatch 「Expression」
△ 查看所有观察点
9. 命令简写
GDB并未定义特定命令的简写,现有简写取自命令的字符前缀
只要能通过前缀唯一识别命令,即为该命令的简写
8. 断点
8.1 普通断点
命令:break,简写:b
△ 设置断点
b 「FileName」:「n」
在文件 「file」的第「n」行设置一个断点
需要注意的是,当断点打到第「n」行时,第「n」行的代码并未执行,此时第「n-1」行代码刚刚执行完,第「n」行的代码处于待执行状态
b 「Namespace」::「ClassName」::「FuncName」
在函数「FuncName」设置一个断点
△ 查看所有断点
info b
8.2 临时断点
与普通断点类似,但命中后会自动删除
命令:tbreak,简写:tb
8.3 添加触发条件
命令:condition 「BreakNo」「Condition」
作用:为断点「BreakNo」
7. list
功能:显示源程序代码
命令简写:l
◇ 显示以文件「FileName」第「n」行为中心的上下五行代码
list 「FileName」:「n」
示例:
◇ 显示以函数「FuncName」为中心的上下五行代码
list「FuncName」
示例:
「GdbFunc」函数位于另一个文件「include.h」
◇ 显示文件「FileName」第「m」行到第「n」行的代码
list 「FileName」:「m」,「n」
示例:
断点命中源文件「main.cpp」第「12」行
list命令显示「main.cpp」第「12」行到第「17」行的代码
◇ 继续显示接下来的代码
list
不带参数,将接着上一次 list 命令的,输出下边的内容
6.调试运行中的进程
gdb /path/exe pid
进程运行异常时,比如死循环或者死锁时,可以通过该方法,查看进程当前的状态
进入gdb后,可以通过:
① bt
查看当前进程状态
② info thread
查看所有线程
③ thread
查看当前线程
④ thread no
切换线程,no为目标线程号
5. 打印变量
设置结构体显示格式:set print pretty on
打印指针地址:p ptr
打印指针变量:p *ptr
4. 进入特定栈
f 栈号
输入f 5,即可进入崩溃链中的指定环节,即cloudsee_transport.cc:116行,函数CCloudSeeTransport::SetupThread()里的崩溃点。
3. 查看堆栈
bt
2. 查看崩溃信息
where
1. 查看core文件
gdb exefile core