Linux GDB调试

一、准备工作

编译选项设置

-g、-ggdb
GCC为此提供了两个选项:-g和-ggdb。后者添加特定于GDB的调试信息,而前者则为您正在使用的任何目标操作系统以适当的格式生成信息,使其成为更具可移植性的选项。
在我们的特殊情况下,目标操作系统始终是Linux,使用-g还是-ggdb没有什么区别。
这两个选项都允许指定调试信息的级别从0到3。
0:不产生任何调试信息,相当于省略-g或ggdb开关;
1:这产生最少的信息,但包括函数名和外部变量,这足以产生回溯;
2:这是默认值,包含有关局部变量和行号的信息,以便您可以执行源代码级调试和单步执行代码;
:这包括额外的信息,除其他事项外,意味着GDB可以正确处理宏扩展

-gdwarf-2
产生DWARF version2 的格式的调试信息

备注:编译时添加-gdwarf-2和-g3这两个参数就可以调试宏定义。

代码优化级别

编译器优化倾向于破坏源代码行和机器码行之间的关系,这使得遍历源代码变得不可预测。gdb调试需要在不进行优化的情况下进行编译,省略-O编译开关,或者使用-Og,该开关启用不会干扰调试的优化。

二、命令说明

启动命令

gdb [option] 程序名 [corefile]

-q: 不显示gdb版本信息
示例: gdb -q ./test

调试命令

run(r): 开始调试程序

where: 显示导致段错误的执行函数树

backtrace(bt): 打印函数调用堆栈

frame(f): 选择特定的堆栈帧进行检查

list[m,n]: m,n是要显示包含错误首次出现位置的起始行和结尾行,不带参数的list命令将显示附近的10行代码

print(r): 打印变量

break(b): 设置断点
    break linenum(行号)
    break funcname(函数名)
   break filename:linenum
   break filename:funcname

continue(c): 从断点以后继续执行,并非单步

delete(d): 删除一个端点
    语法格式:delete 断点编号
    断点编号是由"info break"获取的

info break: 查看已设置断点的信息

set variable: set variable varname=value;varname是变量名称,value是变量的新值
    示例 set args -c conf/nginx.conf

step(s): 当遇到一个函数的时候,step将进入函数,每次执行一条语句,相当于vs中的F10命令

next(n): 当遇到一个函数的时候,next将执行整个函数,相当于vs中的F5命令

return: 相当于在函数中直接return ,并且将value作为返回值返回给调用者

DIR: 加载源文件目录,如果调试的文件不在当前目录下,需要将文件目录加载到程序中,如果在当前目录下不需要加载目录

until: 跳出循环
    until linenum 执行到一个比当前行号大的行,或者也可以指定在当前frame中的某一行

finish: 执行,直到选定的frame执行结束,然后打印返回值,将其放入历史值中,停止

set print elements N: 指定打印的长度,对长字符串特别有用
    set print element 0 输出完整的字符串
    set print pretty 设置GDB打印结构的时候,每行一个成员,并且有相应的缩进,缺省是关闭的

三、拦截信号

Handle命令可控制信号的处理,他有两个参数,一个是信号名,另一个是接受到信号时该作什么。几种可能的参数是:

* nostop 接收到信号时,不要将它发送给程序,也不要停止程序。

* stop 接受到信号时停止程序的执行,从而允许程序调试;显示一条表示已接受到信号的消息(禁止使用消息除外)

* print 接受到信号时显示一条消息

* noprint 接受到信号时不要显示消息(且隐含着不停止程序运行)

* pass 将信号发送给程序,从而允许你的程序去处理它、停止运行或采取别的动作。

* nopass 停止程序运行,但不要将信号发送给程序。

# 截获SIGPIPE信号,程序停止并打印信息
handle SIGPIPE stop print

# 忽略SIGUSR1信号
handle SIGUSR1 nostop noprint

 四、多线程调试

info threads: 列出程序中的所有线程
thread number: 选择特定的线程进行检查

五、多进程调试

set follow-fork-mode [parent|child] 命令用于控制GDB在程序调用fork()后应该跟踪哪个进程:父进程还是子进程。这个命令对于调试涉及fork()调用的程序特别有用。
parent:GDB在fork()之后继续调试父进程,子进程则继续独立运行。
child:GDB在fork()之后调试子进程,父进程则继续独立运行。

 

posted on 2016-08-16 11:02  寒魔影  阅读(404)  评论(0)    收藏  举报

导航