不是说,所有的C写的代码,拿过来就可以调试了,不是的
前提条件是:用户需要开启代码的调试选项
- 关闭优化
-O0 - 开启调试
-g
-O0:关闭所有优化。
- 编译速度最快。
- 保留源代码与汇编指令的对应关系,方便调试。
- 生成的代码体积大、执行速度慢。
-g:在可执行文件中生成调试信息。
- 用于调试器(如
gdb)定位源代码行、变量名、函数名。 - 不影响程序逻辑或性能。
对于大型项目,一般会进行封装,用户在编译和时候,比如:configure --eanble-debug 具体的看用户的代码的设计(Autotools工具)。
程序运行控制
run [args]:启动程序start:启动到 maincontinue/c:继续执行step/s:单步进入函数next/n:单步但跳过函数finish:运行到当前函数返回kill:终止程序
用户的执行的程序的调试,这是调试部分的开始部分,通过gdb调试程序
gdb --args /usr/local/sbin/gluster help--args 是为了增加用户的将参数,程序运行时候会基于args 参数
什么是断点 :程序运行到此处暂停的,断开的点的意思
break [file:line]/break [func]:设置断点delete [num]:删除断点info breakpoints:查看断点disable/enable [num]:禁用/启用断点- 条件断点:
break foo if x>0
一般用户查看函数:info func 这样就可以打断点了
更多的打断点方式,这里就不在重复了,很多请自行查询,最好!
print var / p var:查看变量display var:自动显示变量info locals:局部变量info args:函数参数backtrace / bt:调用栈frame [num]:切换栈帧info registers:寄存器list [line/function]:查看代码
解释下
用户进入函数,执行程序,内核会记录调用路径,什么函数,调用了谁,也就是所谓的调用栈!
某一个栈的层次,被称之为一个Frame
每一个函数内部,有所谓的局部变量和全局变量
x/[nfu] addr:查看内存set var var=value:修改变量set $reg=value:修改寄存器
catch throw:捕捉 C++ 异常handle SIGSEGV stop print pass:设置信号处理signal SIGSEGV:手动发送信号
- 调试共享库:
set solib-search-path /path/to/libs - 多线程调试:
info threads/thread 2 - 远程调试:
target remote <ip>:<port>
内存和指针针对的是特定的内存地址的,查看也就是没有名称只知道地址的内容查看
信号处理方式:
handle SIGSEGV stop print pass
- GDB 信号处理配置命令。
- 参数含义:
stop:遇到信号时暂停程序。print:打印信号信息。pass:信号继续传递给程序(程序仍会收到 SIGSEGV)。
- 示例:
(gdb) handle SIGSEGV stop print pass
表示:程序触发段错误时,GDB 会中断、显示信息,同时信号仍传递给程序。
多进程调试
set follow-fork-mode child
show follow-fork-mode- Child:GDB 会跟踪 fork 出来的子进程,父进程在 fork 后暂停,直到你 detach 或继续它。
- Parent(默认):GDB 会跟踪 父进程,子进程在 fork 后继续运行,不受 GDB 控制。
一开始用户学习:从实践出发,学习整个过程,不要特别在意某一个特点知识。
Ahmedabad