gdb(二)

八、反向调试

使用前输入$ target record命令,然后再使用各种反向调试命令

If you run into the error: Target child does not support this command. then try adding target record at the beginning of execution, after starting run.

Edit: Since GDB 7.6 target record is deprecated, use target record-full instead.

reverse-continue

反向运行程序知道遇到一个能使程序中断的事件(比如断点,观察点,异常)。

reverse-step

反向运行程序到上一次被执行的源代码行。

reverse-stepi

反向运行程序到上一条机器指令

reverse-next

反向运行到上一次被执行的源代码行,但是不进入函数。

reverse-nexti

反向运行到上一条机器指令,除非这条指令用来返回一个函数调用、整个函数将会被反向执行。

reverse-finish

反向运行程序回到调用当前函数的地方。

set exec-direction [forward | reverse]

设置程序运行方向,可以用平常的命令step和continue等来执行反向的调试命令。

九、内存与堆栈

help x

堆栈信息

  • (gdb) bt(backtrace) <-n>(只打印栈底下n层信息)
  • 查看某一层栈信息:
    1. (gdb) f(frame) n(栈深度)
    2. (gdb) i(info) f(frame)
    3. (gdb) up n(向栈的上面移动)
    4. (gdb) down n(向栈的下面移动)

内存信息

可以使用examine命令(简写是x)来查看内存地址中的值。x命令的语法如下所示:x/<n/f/u> <addr> n、f、u是可选的参数。

  • n是一个正整数,表示需要显示的内存单元的个数,也就是说从当前地址向后显示几个内存单元的内容,一个内存单元的大小由后面的u定义。

  • f 表示显示的格式,参见下面。如果地址所指的是字符串,那么格式可以是s,如果地十是指令地址,那么格式可以是i。

  • u 表示从当前地址往后请求的字节数,如果不指定的话,GDB默认是4个bytes。u参数可以用下面的字符来代替,b表示单字节,h表示双字节,w表示四字节,g表示八字节。当我们指定了字节长度后,GDB会从指内存定的内存地址开始,读写指定字节,并把其当作一个值取出来。

  • 表示一个内存地址。

n/f/u三个参数可以一起使用。例如:

命令:x/3uh 0x54320 表示,从内存地址0x54320读取内容,h表示以双字节为一个单位,3表示输出三个单位,u表示按十六进制显示。

输出格式

一般来说,GDB会根据变量的类型输出变量的值。但你也可以自定义GDB的输出的格式。例如,你想输出一个整数的十六进制,或是二进制来查看这个整型变量的中的位的情况。要做到这样,你可以使用GDB的数据显示格式:

x 按十六进制格式显示变量。

d 按十进制格式显示变量。

u 按十进制格式显示无符号整型。

o 按八进制格式显示变量。

t 按二进制格式显示变量。

a 按十六进制格式显示变量。

c 按字符格式显示变量。

f 按浮点数格式显示变量。

十、command

如果想在程序停止在断点的时候,打印信息,或给一些有价值的变量赋值以便定位bug,或者是激活其他断点,可以为这个断点设置一些指令集,完成这些操作。gdb的commands指令帮你实现这个功能能。

用法:

commands [range...] #breakpoint number
... command-list ...
end

eg1.
 break foo if x>0
     commands       //指令集设置命令
     silent         //断点触发时不打印断点信息
     printf "x is %d\n",x
     continue
     end            //指令集设置结束时必须用end结束
     
eg2.

     commands 3    
     silent
     set x = y + 4
     cont
     end

十一、改变程序行为

gdb可以改变程序的执行

改变执行顺序

  • jump line(file:line)
  • jump +num
  • jump

产生信号量

signal

signal命令与shell的kill命令区别:系统的kill命令发信号给被调试程序时,是由gdb截获;而signal命令则直接发给被调试程序。

强制函数返回

return

强制调用函数

call

expr可以是函数名,显示函数返回值(void不显示)。

attach到进程

如果程序已经运行,或者是调试陷入死循环而无法返回控制台进程,可以使用attach命令。

attach pid

通过ps aux可以查看进程的pid,然后使用bt查看栈帧。

以top为例操作步骤为:

\1. ps -aux查看进程pid,为16974.

\2. sudo gdb attach 16974,使用gdb 附着到top命令。

\3. 使用bt full查看,当前栈帧。此时使用print等查看信息。

\4. 还可以通过info proc查看进程信息。

当现实内容多的时候,GDB会强制分页,现实就会暂停。但是可能并不需要,可以通过set pagination off关闭。

十二、线程与进程

线程:https://www.cnblogs.com/xuxm2007/archive/2011/04/01/2002162.html

进程:https://blog.csdn.net/qq_34328833/article/details/60139291

多进程调试避免使用断点,可能出现内存越界问题。

十三、调试技巧

  1. 程序出错终止时,使用bt 与 f命令,查看栈帧信息,不断向上回溯,回到出错的地方。
  2. 使用tmux,运行程序a、b,若2个程序之间非血缘关系的进程,也非exec关系,则开启2个gdb调试。
  3. 内存错误(参考http://scottmcpeak.com/memory-errors/)

方法:
a. Making the bug more robust
I know of two main techniques for reducing the fragility of a memory bug:
- Don't re-use memory.
- Put empty space between memory blocks.
b. Using hardware watchpoints

posted @ 2020-02-17 21:07  friedCoder  阅读(217)  评论(0)    收藏  举报