资讯详情

【Linux工具】gdb

📅 2026/10/29 10:50:31 | 华诺云谱 👁 阅读
【Linux工具】gdb
文章目录一、调试程序1、gdb 启动(1) 使用名称拉起进程(2) 附加到已运行进程(3) 先进gdb再attach运行中的进程2、设置断点(1)按行号设断点(2) 按函数名设断点(3) 地址断点(4) 条件断点(5) 临时断点命中一次后自动删除(6) 正则表达式断点B、断点查看与管理启用 / 禁用删除断点C、观察点WatchpointD、捕获点CatchpointE、断点命令命中后自动执行保存与恢复断点七、实战技巧1. 循环中跳过前 N 次2. 条件断点 vs ignore3. 断点命中后打印再继续4. 在共享库未加载时设断点5. 多线程断点八、常用快捷键速查九、注意事项2、SIGPIPE 管道破裂信号(1) gdb 调试过程中为什么打印 SIGPIPE1. 直接原因程序收到了 SIGPIPE 信号2. GDB 的机制为什么会中断并打印后续信息3. 如何解决(2) 另一个例子管道破裂于continue2、handle 定义 GDB 的信号拦截行为核心参数关于 nopass 与 pass常见的实际应用信号范围的指定与之前 SIGPIPE 案例的关联3、常见的 signal4、gdb中的常用命令二、调试Coredump一、调试程序1、gdb 启动(1) 使用名称拉起进程cd/work_dir gdb ./h530_daemon gdb h530_daemon(2) 附加到已运行进程gdb-p1234gdb-p$(pgrep h530_daemon)gdb--pid$(pgrep h530_daemon)gdb--pid$(pgrep h530_daemon)(3) 先进gdb再attach运行中的进程pgrep h5u_autorun#查看PID 结果为1241gdb#启动gdb(gdb)attach1241#在gdb内 attach 运行中的进程2、设置断点(1)按行号设断点break文件:行breakfile.c:10#指定文件的行简写 bb file.c:func#文件中某函数(2) 按函数名设断点b 函数 b function_name#查找范围是全局所有符号有同名函数时会提示让你选具体哪个b main(3) 地址断点无符号时的唯一手段b *0x4005d6#内存地址处b *main#main 函数入口地址(4) 条件断点b funcifi5#i等于5时中断b file.c:20ifx100condition1i5#给已存在的1号断点加条件condition1#查看1号断点条件condition1i5#修改条件(5) 临时断点命中一次后自动删除tbreak func tbreak file.c:20(6) 正则表达式断点rbreak ^func_.*#匹配所有 func_ 开头的函数rbreak file.c:.*#文件中所有函数B、断点查看与管理info breakpoints# 简写 info b列出所有断点info b# 显示编号、类型、使能、地址、位置、命中次数输出字段说明字段含义Num断点编号Typebreakpoint / watchpoint / catchpointDisp命中后是否保留keep / delEnb是否启用y / nAddress内存地址What位置文件:行号 或 函数启用 / 禁用disable1# 禁用1号断点disable# 禁用所有enable1enableonce1# 启用一次后自动禁用enabledelete1# 启用一次后自动删除删除断点delete1# 删除1号断点delete# 删除所有会提示确认clearfunc# 删除函数处断点clearfile.c:20# 删除指定行断点C、观察点Watchpoint监视变量/表达式的值变化watchvar# 变量被写时中断watchexpr# 表达式值变化时中断rwatch var# 变量被读时中断awatch var# 被读或被写时中断info watchpoints# 查看所有观察点注意watch在变量离开作用域后会自动删除硬件观察点数量有限通常4个。D、捕获点Catchpoint捕获特定事件catch throw# C 抛异常catch catch# C 捕获异常catchexec# exec 调用catch fork# fork 调用catch vfork catch syscall# 系统调用catch syscallopen# 特定系统调用catch signal SIGINT# 信号catch load# 加载动态库catch unloadE、断点命令命中后自动执行给断点绑定命令序列b func commands1# 为1号断点设置命令print xcontinueend常用技巧commands1silent# 不打印断点命中信息printfx%d\n, xcontinueend保存与恢复断点save breakpoints file.bp# 保存所有断点到文件sourcefile.bp# 恢复断点七、实战技巧1. 循环中跳过前 N 次b func ignore1100# 忽略前100次命中info breakpoints# 查看 ignore 次数2. 条件断点 vs ignore条件复杂、命中稀疏 → 用condition单纯跳过前N次 → 用ignore性能更好GDB 不发信号3. 断点命中后打印再继续b func commands silent bt3# 打印3层调用栈continueend4. 在共享库未加载时设断点setbreakpoint pending on# 允许对未定义符号设断点b mylib_func# 库加载后自动生效5. 多线程断点b func thread2# 只在2号线程中断b funcifthread_id3八、常用快捷键速查命令简写作用breakb设断点tbreaktb临时断点info breakpointsi b查看断点deleted删除断点disabledis禁用断点enableen启用断点conditioncond条件断点ignore—忽略N次watch—观察点catch—捕获点commands—断点命令九、注意事项编译需带调试信息gcc -g -O0断点行号会因优化错位-O2下行号可能不准建议-O0内联函数b inline_func可能失败改用地址或加-fno-inline模板函数需用完整实例化名如b std::vectorint::push_back条件断点有开销GDB 每次命中都要求值大量循环会变慢硬件断点hbreak使用硬件寄存器数量有限但可用于只读内存pending 断点库未加载时设的断点info b显示PENDING一句话记忆b设断点i b看断点d删断点dis/en开关断点condition/ignore控命中watch看变量catch抓事件commands自动跑。2、SIGPIPE 管道破裂信号(1) gdb 调试过程中为什么打印 SIGPIPE这张截图展示了在使用 GDB 调试程序时程序因为收到了SIGPIPE信号管道破裂而中断的现象。以下是对“为什么打印这些”的详细解释分为直接原因和GDB 的机制两部分1. 直接原因程序收到了SIGPIPE信号红框内容received signal SIGPIPE, Broken pipe.SIGPIPE这是一个信号Signal。在 Linux/Unix 系统中当你试图向一个已经关闭了读取端的管道Pipe或 Socket写入数据时系统就会向当前进程发送SIGPIPE信号。默认行为SIGPIPE的默认处理动作是终止进程。触发场景你的程序里有一个线程叫monitor_tcp_cli它正在操作网络连接TCP。这通常发生在客户端对端已经关闭了连接断开了 TCP。你的程序没有检测到这个断开仍然尝试向这个连接send()或write()数据。内核发现管道/连接已断于是抛出SIGPIPE。2. GDB 的机制为什么会中断并打印后续信息GDB 的默认设置在使用 GDB 调试时GDB 默认会捕获所有的信号。当程序运行中收到信号包括SIGPIPEGDB 会暂停程序的执行并把控制权交给你调试者让你决定是忽略该信号还是继续运行。线程切换信息[Switching to Thread 0x41fc3a0 (LWP 19299)]由于 GDB 正在执行你输入的命令看起来是在调用statvfs但此时另一个线程monitor_tcp_cli突然收到了信号。GDB 为了展示错误发生的位置自动切换到了那个出问题的线程上下文。蓝色文字部分The program received a signal in another thread while making a function call from GDB.这解释了为什么你原本想调用的函数statvfs没有返回结果。因为 GDB 在“帮”你调用函数时程序里的其他线程“炸”了收到了信号导致 GDB 放弃了当前的函数调用评估。Evaluation of the expression containing the function (malloc) will be abandoned.这里提到了malloc说明你调用的statvfs内部或者 GDB 内部正在尝试分配内存但因为信号中断这个调用链被强行终止了。3. 如何解决如果你不想让 GDB 在这种信号上停下来或者想修复代码有两种思路方法 A在 GDB 中忽略该信号临时调试用你可以告诉 GDB 不要捕获SIGPIPE让程序按照操作系统的默认逻辑处理或者程序自己处理。在 GDB 中输入(gdb)handle SIGPIPE nostop noprint passnostop: 收到信号时不暂停程序。noprint: 不打印提示信息。pass: 把信号传递给程序处理通常程序会忽略它或做错误处理。方法 B修改代码根本解决这是网络编程中的经典问题。在处理 TCP Socket 时应该由程序自己处理SIGPIPE而不是让它杀掉进程。设置忽略 SIGPIPE最简单在程序初始化时或main函数开头加入#includesignal.hsignal(SIGPIPE,SIG_IGN);这样当write/send到断开的连接时不会触发SIGPIPE信号而是返回-1并将errno设置为EPIPE。你需要检查send的返回值来处理错误。使用MSG_NOSIGNAL标志推荐在调用send函数时加上MSG_NOSIGNAL标志send(sockfd,buf,len,MSG_NOSIGNAL);这样可以避免发送SIGPIPE信号直接通过返回值报错。总结截图显示的是你的程序在尝试向一个已经断开的 TCP 连接写数据导致系统发出了“断开连接”的信号GDB 捕获到这个信号后暂停了程序并打断了你正在进行的手动函数调用。(2) 另一个例子管道破裂于continue2、handle 定义 GDB 的信号拦截行为handle 本质是用 stop/print/pass 三个开关为指定信号构建 GDB 拦截/转 发策略。使用格式handle信号范围行为关键词[行为关键词...]参数由三部分组成操作对象信号范围指定要配置哪些信号。拦截策略GDB 行为GDB 自己该怎么处理这个信号停不停、打不打印。转发策略程序行为要不要把这个信号告诉正在调试的程序pass/nopass。handle命令用于告诉 GDB 如何处理各种信号Signal。你可以针对某个信号设定一系列“关键词”来控制 GDB 的行为比如是否暂停程序、是否打印提示、是否把信号传递给正在调试的程序。核心参数你提到的nostop、noprint、pass就是控制这些行为的开关。它们可以自由组合具体含义如下关键词含义stop收到该信号时暂停程序把控制权交给你调试。nostop收到该信号时不暂停程序但 GDB 可能会打印一条提示信息。print收到该信号时在 GDB 中打印一条信息。noprint收到该信号时不打印任何信息。pass允许程序看到这个信号。程序可以自行处理也可能因未处理而终止。nopass不允许程序看到这个信号。ignore与nopass同义。noignore与pass同义。关于nopass与pass你之前问到的nopass确实可以用但正如我们分析过的它会让程序“感觉不到”信号的存在导致send/write等函数失败后代码无法通过errno感知到EPIPE错误从而陷入逻辑错乱。而在信号调试场景中pass才是让程序能“看到”信号并做出反应的关键。常见的实际应用在调试网络程序时最常见的做法是将SIGPIPE的处理方式设置为nostop noprint pass把SIGPIPE信号交给程序自己去处理比如忽略它或者检查send的返回值而不是让 GDB 每次都中断下来。信号范围的指定除了直接指定单个信号你还可以指定一个范围来处理多个信号例如handle SIGIO-SIGKILL或者使用all来设置所有信号。与之前SIGPIPE案例的关联对SIGPIPE来说推荐在代码中用signal(SIGPIPE, SIG_IGN)或在send时加上MSG_NOSIGNAL来处理。GDB 中的handle SIGPIPE调试命令只是一个用来配合代码修改的临时手段让你在调试时不会被信号中断打断。按信号数值从小到大排序并将“终止核心”明确写为“终止 Core Dump”后的完整表格如下3、常见的 signal按信号数值从小到大排序英文全称列去掉“Signal”后的完整表格如下值信号名称英文全称类别默认动作说明1SIGHUPHang Up控制/定时类终止控制终端挂起用户登出或控制进程结束2SIGINTInterrupt进程终止类终止从键盘发出的中断通常由 CtrlC 触发3SIGQUITQuit进程终止类终止 Core Dump从键盘发出的退出通常由 Ctrl\ 触发4SIGILLIllegal Instruction错误/异常类终止 Core Dump执行了非法硬件指令6SIGABRTAbort错误/异常类终止 Core Dump由 abort() 函数触发的非正常终止7SIGBUSBus Error错误/异常类终止 Core Dump总线错误如内存对齐问题8SIGFPEFloating-Point Exception错误/异常类终止 Core Dump浮点运算异常如除以零9SIGKILLKill进程终止类终止最强终止信号无法被捕获、阻塞或忽略10SIGUSR1User-defined 1控制/定时类终止留给用户自定义用途11SIGSEGVSegmentation Violation错误/异常类终止 Core Dump无效的内存引用段错误12SIGUSR2User-defined 2控制/定时类终止留给用户自定义用途13SIGPIPEPipe错误/异常类终止向没有读取端的管道或套接字写入数据14SIGALRMAlarm控制/定时类终止来自 alarm() 函数的超时信号15SIGTERMTerminate进程终止类终止标准的终止请求程序可捕获并执行清理17SIGCHLDChild控制/定时类忽略子进程结束或停止时通知父进程18SIGCONTContinue停止/继续类继续让暂停的进程继续执行19SIGSTOPStop停止/继续类停止无条件停止进程同样无法被忽略20SIGTSTPTerminal Stop停止/继续类停止从终端发出的停止信号通常由 CtrlZ 触发4、gdb中的常用命令gdb ./a.out # 启动调试(gdb) break main # 在 main 函数下断点(gdb) run # 运行程序(gdb) next # 执行下一行不进入函数(gdb) step # 执行下一行进入函数(gdb) print x # 打印变量 x 的值(gdb) continue # 继续运行到下一个断点(gdb) backtrace # 看调用栈程序在哪崩溃的(gdb) quit # 退出二、调试Coredump
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑