gdb是linux调试跟踪进程、线程的必备工具,开发中常用的几个方法总结如下。
- info threads
显示当前可调试的所有线程,每个线程会有一个GDB为其分配的ID,后面操作线程的时候会用到这个ID。
前面有*的是当前调试的线程。
- thread ID
切换当前调试的线程为指定ID的线程。
- thread apply ID1 ID2 command
让一个或者多个线程执行GDB命令command。
- thread apply all command
让所有被调试线程执行GDB命令command,如:thread apply all bt
- set scheduler-locking off|on|step
在使用step或者continue命令调试当前被调试线程的时候,只让被调试程序执行,
off 不锁定任何线程,也就是所有线程都执行,这是默认值。
on 只有当前被调试程序会执行。
step 在单步的时候,除了next过一个函数的情况(这其实是一个设置断点然后continue的行为)以外,只有当前线程会执行。
- set follow-fork-mode child 设置gdb在fork之后跟踪子进程;
- set follow-fork-mode parent 跟踪父进程
- set print element 0 设置打印完整数组内容
- handle SIGUSR2 nostop noprint 设置中断信号量的处理方式:不中断、不打印。
core文件分析方法
core时errno标识:
* bit 0 == 0: no page found 1: protection fault
* bit 1 == 0: read access 1: write access
* bit 2 == 0: kernel-mode access 1: user-mode access
* bit 3 == 1: use of reserved bit detected
* bit 4 == 1: fault was an instruction fetch
比如,errno=4,则表示用户指令读取不存在的地址。
addr2line -e app ipaddr ---- app进程core在指令地址ipaddr处,则本命令可以返回core代码行;
addr2line -e sofile offset ---- 进程core在动态库sofile,偏移地址为offset,获取偏移地址的方法如下:
demon[3702]:segfault at b771c488 ip b771c4b3 sp bfc8b1a0 error 7 in libmodule.so[b771c000+1000]
segfault at b771c488 --- 程序异常时访问的地址;
ip b771c4b3 --- 程序异常时执行的指令地址IP;
sp bfc8b1a0 --- 程序的堆栈地址sp;
libmodule.so[b771c000+1000] --- 模块libmodule.so加载的地址b771c000,空间占用1000。
上面的b771c000是libmodule.so的载入地址,b771c4b3是异常时指令地址;
addr2line -e libmodule.so ip地址-模块载入地址(b771c4b3-b771c000)
此处也可根据程序ip指令地址 -模块载入地址,然后反汇编(objdump -D)相应的动态库,在反汇编中查找相应的差值。
unix下使用的是dbx
dbx 可执行文件 core
stop at "/home/abc/BBB/main/agent.c":1872
stop in 函数
continue
step
其他常用手段:
suse9/suse10系统查看进程线程信息:
watch -n 1 ps -o pid,lwp,psr,pcpu,cmd -L -p #pid
SUSE10上可直接用top看,只是需要按 H 展开线程
# top -p #pid