gdb调试积累

1、p打印字符串时不省略

默认情况下,gdb调试时,太长的字符串只显示一部分,如果想要完全显示,可以设置:set print element 0

2、查看产生coredump文件的进程

(1)gdb -c corefile   使用gdb调试core文件

(2)info auxv          索引31对应的是core文件的应用程序

调试coredump文件命令:gdb  coredump应用程序  coredump文件

info threads 显示所有线程

bt 显示线程堆栈信息

thread thread_num   切换线程

frame num  切换栈

info r 显示当前帧的寄存器信息 (每一帧的寄存器信息都是不相同的)

3、ulimit不生效规避

有时候通过  ulimit -c 0   设置不产生coredump文件不生效,规避方法可以设置core文件名相同,产生路径为一个空间比较大的地方,以免根分区被占满。

(1)echo "0" > /proc/sys/kernel/core_uses_pid                  控制生成coredump文件名是一个,保证始终只生成一个coredump文件

(2)echo "/opt/usr/core"  > /proc/sys/kernel/core_pattern             控制生成的coredump文件路径

为保证系统重启也能生效,将上面两个命令写到/etc/profile里面。

4、基本常识

4.1 前提

用gdb调试的程序必须在编译时加 -g 参数,生成带调试信息的程序。

4.2 启动调试

gdb programname         直接运行并调试

gdb at pid                 附加到已经运行的进程上调试

4.3 设置程序参数

set args 可指定运行时参数。(如:set args 10 20 30 40 50 ) 
show args 命令可以查看设置好的运行参数。 
run (r) 启动程序 
不指定运行参数 r 
指定运行参数r 10 20 30 40 50

4.4 设置断点

break 设置断点,可以简写为b 
b 10设置断点,在源程序第10行 
b func设置断点,在func函数入口处

C++中可以使用 
class::function或function(type,type)格式来指定函数名。如果有名称空间,可以使用namespace::class::function或者function(type,type)格式来指定函数名。 
break filename:linenum 
在源文件filenamelinenum行处停住 
break filename:function 
在源文件filenamefunction函数的入口处停住 
break class::functionfunction(type,type) 
在类class的function函数的入口处停住 
break namespace::class::function 
在名称空间为namespace的类class的function函数的入口处停住

4.5 查询断点

查询所有断点:info b

4.6 观察点

watch 为表达式(变量)expr设置一个观察点。当表达式值有变化时,马上停住程序。 
rwatch表达式(变量)expr被读时,停住程序。 
awatch 表达式(变量)的值被读或被写时,停住程序。 
info watchpoints列出当前所设置了的所有观察点。

4.7 条件断点

设置一个条件断点 
b test.c:8 if intValue == 5 
condition 与break if类似,只是condition只能用在已存在的断点上 
修改断点号为bnum的停止条件为expression 
condition bnum expression 

清楚断点号为bnum的停止条件 
condition bnum 
ignore 忽略停止条件几次 
表示忽略断点号为bnum的停止条件count次 
Ignore bnum count

4.8 为停止点设定运行命令

commands [bnum]

… command-list …

end

4.9 调试命令

  1. run 运行程序,可简写为r
  2. next 单步跟踪,函数调用当作一条简单语句执行,可简写为n
  3. step 单步跟踪,函数调进入被调用函数体内,可简写为s
  4. finish 退出函数
  5. until 在一个循环体内单步跟踪时,这个命令可以运行程序直到退出循环体,可简写为u。
  6. continue 继续运行程序,可简写为c
  7. stepisinextini 单步跟踪一条机器指令,一条程序代码有可能由数条机器指令完成,stepi和nexti可以单步执行机器指令。
  8. info program 来查看程序的是否在运行,进程号,被暂停的原因。

4.10 自动显示

display expr

display/fmt expr

display/fmt addr

4.11 设置变量值

set  xx=yy

4.12 强制函数返回

return

return expression

4.13 强制调用函数

call name

print name

4.14 线程断点

break linespec thread threadno

break linespec thread threadno if …

threadno是线程ID,可以通过info threads查看。当你的程序被GDB停住时,所有的运行线程都会被停住。这方便你你查看运行程序的总体情况。而在你恢复程序运行时,所有的线程也会被恢复运行。那怕是主进程在被单步调试时。

4.15 显示栈帧

bt 

bt full

frame n

up

down

4.16 其他

print h@10       显示数组h后面的10个值

whatis xx         识别变量类型

shell + 命令,可以在gdb时执行shell命令

在gdb里面用print errno有时会:
Cannot access memory at address 0x8
这是由于errno本身是一个宏,而gdb有时不能正确的处理errno这个宏。
可以试试如下命令:
p *__errno_location()

使用“info functions”命令可以列出可执行文件的所有函数名称

执行“set step-mode on”命令,这样gdb就不会跳过没有调试信息的函数

frame n  up down

i frame
i registers

crtl+D,模拟EOF使程序结束。

 

分割窗口:

  • layout:用于分割窗口,可以一边查看代码,一边测试:
  • layout src:显示源代码窗口
  • layout asm:显示反汇编窗口
  • layout regs:显示源代码/反汇编和CPU寄存器窗口
  • layout split:显示源代码和反汇编窗口
  • Ctrl + L:刷新窗口

 

5 寄存器、栈调试

5.1 问题场景

  • 优化的代码在printf或其它glibc函数处core
  • 没有检查返回值的函数调用异常导致的异常
  • 优化的代码的计算异常的中间过程分析
  • 栈溢出导致的core
  • 局部变量越界导致栈异常的core

通常调试的代码基本上都是在未开启优化的情况下,各个变量都可以直接查看,因此造成很多人调试时基本上不会看寄存器,但是对于线上的生产环境,可能会因为性能的因素,需要打开代码优化,此时出现异常需要调试时就通常需要查看寄存器了,下列是gdb调试中需要了解的寄存器。

  • $rip 指令寄存器,指向当前执行的代码位置
  • $rsp 栈指针寄存器,指向当前栈顶
  • $rax,$rbx,$rcx,$rdx,$rsi,$rdi,$rbp,$r8,$r9,$r10,$r11,$r12,$r13,$r14,$r15 通用寄存器

5.2 函数入参

一般linux下会优先将参数压到寄存器中,只有当寄存器不够所有的参数时,才会将入参压到栈上,一般入参的压栈顺序为$rdi、$rsi、$rdx、$rcx、$r8、$r9。多的参数会被压到栈上。

i r            //查看所有寄存器值

查看某个寄存器值:p/s (char*)$rdi

p/d $rsi

函数返回值由$rax保存返回

显示汇编代码:layout asm

栈帧:

6、辅助命令

nm

nm用来列出目标文件的符号清单。

objdump

ogjdump工具用来显示二进制文件的信息,就是以一种可阅读的格式让你更多地了解二进制文件可能带有的附加信息。

$objdump -d myprogrammer

  • -f 显示文件头信息
  • -D 反汇编所有section (-d反汇编特定section)
  • -h 显示目标文件各个section的头部摘要信息
  • -x 显示所有可用的头信息,包括符号表、重定位入口。-x 等价于 -a -f -h -r -t 同时指定。
  • -i 显示对于 -b 或者 -m 选项可用的架构和目标格式列表。
  • -r 显示文件的重定位入口。如果和-d或者-D一起使用,重定位部分以反汇编后的格式显示出来。
  • -R 显示文件的动态重定位入口,仅仅对于动态目标文件有意义,比如某些共享库。
  • -S 尽可能反汇编出源代码,尤其当编译的时候指定了-g这种调试参数时,效果比较明显。隐含了-d参数。
  • -t 显示文件的符号表入口。类似于nm -s提供的信息

readelf

这个工具和objdump命令提供的功能类似,但是它显示的信息更为具体,并且它不依赖BFD库。

$readelf -all a.out

ELF文件类型

ELF(Executable and Linking Format)是一种对象文件的格式,用于定义不同类型的对象文件(Object files)中都放了什么东西、以及都以什么样的格式去放这些东西。它自最早在 System V 系统上出现后,被 xNIX 世界所广泛接受,作为缺省的二进制文件格式来使用。可以说,ELF是构成众多xNIX系统的基础之一。

ELF文件有三种类型:

  1. 可重定位的对象文件(Relocatable file)

    由汇编器汇编生成的 .o 文件

  2. 可执行的对象文件(Executable file)

    可执行应用程序

  3. 可被共享的对象文件(Shared object file)

    动态库文件,也即 .so 文件

 

size

size这个工具用来查看程序运行时各个段的实际内存占用:$size a.out

file

$file a.out

查看文件类型,也可以查看core文件是由谁生成的。

strings

一个文件中包含二进制数据和文本数据,如果只需要查看其文本信息,使用这个命令就很方便;过滤掉非字符数据,将文本信息输出:

$strings <objfile>

fuser

显示所有正在使用着指定的file, file system 或者 sockets的进程信息;

$fuser -m -u redis-server
redis-server: 11552rce(weber) 22912rce(weber) 25501rce(weber)

使用了-m和-u选项,用来查找所有正在使用redis-server的所有进程的PID以及该进程的OWNER;

fuser通常被用在诊断系统的”resource busy”问题。如果你希望kill所有正在使用某一指定的file, file system or sockets的进程的时候,你可以使用-k选项:

$fuser –k /path/to/your/filename

xxd

以十六进制方式显示文件,只显示文本信息:

$xxd a.out

od

通常使用od命令查看特殊格式的文件内容。通过指定该命令的不同选项可以以十进制、八进制、十六进制和ASCII码来显示文件。

ldd

用来查看程式运行所需的共享库,常用来解决程式因缺少某个库文件而不能运行的一些问题。ldd -r xxx

/opt/app/todeav1/test$ldd test
libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x00000039a7e00000)
libm.so.6 => /lib64/libm.so.6 (0x0000003996400000)
  • 第一列:程序需要依赖什么库
  • 第二列: 系统提供的与程序需要的库所对应的库
  • 第三列:库加载的开始地址
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值