- 生成core文件:
mkdir -p /home/mogo/data/corefile && echo "/home/mogo/data/corefile/core-%e-%p-%t" > /proc/sys/kernel/core_pattern 设置coredump目录
gdb /home/mogo/autopilot/lib/drivers_radar/drivers_radar_conti_node 镜像内
gdb /home/mogo/data/jp_ws/install/lib/drivers_radar/drivers_radar_conti_node 代码对应可执行文件 /home/mogo/data/corefile/core-drivers_radar_c-347148-1687162948 coredump文件
- gdb设置命令行参数
- gdb调试步骤
- 设置必要的命令行参数
- 设置断点
- run
- 必要触发,如查看线程
-
- 使用frame命令切换到特定的栈帧以查看局部变量和调用链
-
- 打印变量
- gdb调试堆栈信息一堆问号如 #0 0x0000000000000000 in ?? () 看这里跟踪:[C++11 std::thread异常coredump导致调用堆栈丢失问题的跟踪和解决(std::teminate) - 知乎]
今日分享的内容是建立在gdb环境与编译环境都正常的情况下所做的调试工作。 如何安装gdb以及如何搭建可以生成调试信息的编译环境可以自行百度,有很多的文章可以参考,我们重点介绍 gdb过程中产生 #0 0x0000000000000000 in ?? () 信息的问题如何定位调试。 这里我使用的是printf+gdb的方式,由于堆栈信息是一堆0和问号,我们通过gdb无法直接定位,所以我们先加打印大致定位到死在哪个接口,假设打印跟踪到的接口我们定义为My_test()。 一、首次运行coredump文件 利用gdb运行coredump文件,在gdb环境下运行run命令,可以看到如下的信息: Thread 4 “go” received signal SIGSEGV, Segmentation fault. 说明线程id为4挂掉了。那么如何找到线程Id为4的线程呢,接下来还有如下打印 [Switching to Thread 0x7ffff3a32700 (LWP 393021)] 0x7ffff3a32700为线程的堆栈地址,记住此地址0x7ffff3a32700 该步骤gdb命令调用过程如下: gdb ./go core.629415 (go是我的可执行程序,core是coredump文件) (gdb) run(运行程序) 二、再次运行coredump文件 退出步骤一中的gdb,重新运行coredump文件,在我们之前printf定位到的函数处加入断点,然后启动单步调试,再打印出所有的线程信息来,找到步骤一中挂掉的线程堆栈地址,然后进入该线程,打印线程堆栈即可看到是哪个线程挂掉了。 该步骤gdb命令调用过程如下: gdb ./go core.629415 (go是我的可执行程序,core是coredump文件) (gdb) b My_test (在My_test函数加断点) (gdb) run(运行程序) (gdb) info threads(打印线程信息) Id Target Id Frame 1 Thread 0x7ffff7fd6780 (LWP 777965) “go” 0x00007ffff6cc933d in read () at …/sysdeps/unix/syscall-template.S:84 2 Thread 0x7ffff471a700 (LWP 778007) “go” 0x00007ffff6cd9ad3 in epoll_wait () at …/sysdeps/unix/syscall-template.S:84 3 Thread 0x7ffff7f10700 (LWP 778008) “go” 0x00007ffff6ccf693 in select () at …/sysdeps/unix/syscall-template.S:84 4 Thread 0x7ffff3a32700 (LWP 778009) “go” 0x00007ffff6cd9ad3 in epoll_wait () at …/sysdeps/unix/syscall-template.S:84 (gdb) thread 4(切换到挂掉的线程0x7ffff3a32700) (gdb) bt(查看该线程中的堆栈信息) bt完之后即可查看到出问题的线程了。接下来排查对应的线程就可以了。 加断点的目的是为了让程序不再往下走,以便我们在程序奔溃前找到对应的线程号并切进去查看堆栈,如果程序奔溃后再切到线程后bt的话 就是一堆0和问号什么都看不到,更找不到是哪个线程挂了。 这种一堆0和问号的问题多注意排查线程中memset.memcpy,这种函数,初始化赋值或者拷贝内存的时候拷贝的多了就有可能把线程的堆栈冲掉而导致出现堆栈信息为0?的现象。