段错误?死锁?Core Dump不会用?3个GDB技巧让你调试效率翻倍

段错误?死锁?Core Dump不会用?3个GDB技巧让你调试效率翻倍
段错误死锁Core Dump不会用3个GDB技巧让你调试效率翻倍嵌入式开发里最浪费时间的事情是什么不是写代码是找bug。尤其是那些我代码逻辑没问题啊怎么就崩了的bug。今天聊3个GDB实战技巧每一个都是我在调试Linux驱动和嵌入式应用时反复用到的。不扯理论直接上命令。技巧一搞定段错误——从Core Dump回溯现场段错误是嵌入式开发者的老朋友了。指针飞了、数组越界、栈溢出结果都是SIGSEGV。第一步打开Core Dump默认系统不开core dump先打开ulimit-cunlimitedecho/tmp/core.%p.%e/proc/sys/kernel/core_pattern这样程序崩溃后/tmp/core.1234.myapp就有了。第二步回溯现场gdb ./myapp /tmp/core.1234.myapp(gdb)bt(gdb)bt full(gdb)info registersbt看调用栈bt full看每层函数的局部变量值。80%的段错误一看到崩溃在哪个函数、传了什么参数马上就能定位。第三步查看内存有时候崩溃在memcpy里bt看到的是libc的栈帧没用。这时候看参数(gdb) frame 1 # 切到上一帧调用memcpy的代码 (gdb) info args (gdb) p src (gdb) p dst (gdb) p/x *src20 # 打印src指向的前20个字节真实案例一次调试WiFi驱动skb-data指向了已释放的内存。运行几小时后随机崩溃。bt一看在memcpy打印src发现地址在kmalloc-128 slab之外一查是上层模块提前kfree_skb了。半小时定位之前纯靠加printk搞了三天没找到。技巧二条件断点自动化——调试时序问题嵌入式里最恶心的一类bug跑100次偶尔崩1次。条件断点就是干这个的。条件断点(gdb) break gpio_irq_handler if irq_num 42 (gdb) break kmalloc if size 4096 (gdb) break my_func if strcmp(name, sensor0) 0自动打印继续调试中断处理或者驱动probe时不想每次都手动敲命令(gdb) break device_probe (gdb) commands printf Probing %s\n, pdev-name print devm_kzalloc(pdev, 0x1000) continue end观察点Watchpoint调试哪个不要脸的改了我的变量(gdb) watch my_global_var # 写触发 (gdb) rwatch my_global_var # 读触发 (gdb) awatch my_global_var # 读写都触发真实案例调试一个I2C触摸屏驱动g_touch_state总是不对。怀疑被别的模块改了但找不到。watch g_touch_state一上断下来发现是DMA完成回调里直接写了共享内存——但锁机制没覆盖这个路径。5分钟找到之前printk打了一百行没看出来。技巧三远程调试gdbserver——嵌入式板子的标配嵌入式开发程序跑在ARM/MIPS板子上调试器在主机的x86上。用gdbserver板子端# 编译带调试符号的目标程序arm-linux-gnueabihf-gcc-g-O0-omyapp myapp.c# 板子上启动gdbservergdbserver :2345 ./myapp主机端arm-linux-gnueabihf-gdb ./myapp(gdb)target remote192.168.1.100:2345(gdb)continue剩下的和在本地一样break、next、print全部操作远程板子的内存和寄存器。小技巧加载内核模块调试符号调试驱动时# 板子上insmod mydriver.kocat/sys/module/mydriver/sections/.textcat/sys/module/mydriver/sections/.datacat/sys/module/mydriver/sections/.bss# GDB里(gdb)add-symbol-file mydriver.o 0x.text地址-s.data 0x.data地址-s.bss 0x.bss地址然后就可以在驱动函数里打断点、单步调试了。比printk刷日志爽一百倍。target remoteadd-symbol-file断点/单步BKPT指令主机 x86gdbserver on ARM板被调试进程GDB 符号解析内核模块符号硬件调试寄存器课后练习写一个故意段错误的程序比如解引用空指针编译后用gdb的bt定位到具体行用watchpoint找出谁改了全局变量配置一个gdbserverQEMU的远程调试环境验证远程断点可用一句话总结三个技巧吃透了大部分嵌入式调试场景不用再加printk重编。尤其Core Dump和远程调试省的是实打实的编译部署时间一次省半小时一个月下来够你摸好几天的鱼。