调试利器GDB-中

Posted dengqiangjiayou

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了调试利器GDB-中相关的知识,希望对你有一定的参考价值。

GDB调试利器-中

  • 数据断点

    • GDB中支持数据断点的设置
    • watch命令用于监视变量是否被改变(本质为硬件断点)
    • watch命令的用法:watch var_name
  • GDB中的内存查看

    • GDB中可以检查任意内存区域中的数据
    • 命令语法:x /Nuf expression
      • N - 需要打印的单元数
      • u - 每个单元的大小
      • f - 数据打印格式
        比如: x /4bx 0x804a024 :打印出以0x804a024地址为首的连续4个byte,并且以16进制呈现
    • x命令中参数u对应的单位
      | 格式 | 打印方式 |
      | ------------------------- |
      | b | 单字节 |
      |h | 双字节 |
      | w | 四字节 |
      | g | 八字节 |
    • GDB中的打印格式
      | 格式 | 打印方式 |
      | -------------------- |
      | x | 十六进制 |
      | d | 有符号十进制 |
      | u | 无符号十进制 |
      | o | 八进制 |
      | t | 二进制 |
      | a | 地址 |
      | c | 字符 |
      | f | 浮点数 |
  • 使用watch查看数据

    topeet@ubuntu:~/Desktop/Code$ ls
    func.c  test.c  test.c~
    topeet@ubuntu:~/Desktop/Code$ gcc -g test.c -lpthread -o test.out
    topeet@ubuntu:~/Desktop/Code$ ./test.out 
    g_var = 0
    g_var = 0
    g_var = 0
    g_var = 0
    g_var = 0
    g_var = 1
    g_var = 1
    g_var = 1
    g_var = 1
    g_var = 1
    topeet@ubuntu:~/Desktop/Code$ gdb test.out 
    GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2.1) 7.4-2012.04
    Copyright (C) 2012 Free Software Foundation, Inc.
    License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
    and "show warranty" for details.
    This GDB was configured as "x86_64-linux-gnu".
    For bug reporting instructions, please see:
    <http://bugs.launchpad.net/gdb-linaro/>...
    Reading symbols from /home/topeet/Desktop/Code/test.out...done.
    (gdb) start
    Temporary breakpoint 1 at 0x40062e: file test.c, line 16.
    Starting program: /home/topeet/Desktop/Code/test.out 
    [Thread debugging using libthread_db enabled]
    Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
    
    Temporary breakpoint 1, main () at test.c:16
    16	    int i = 0;
    (gdb) watch g_var
    Hardware watchpoint 2: g_var
    (gdb) info breakpoints 
    Num     Type           Disp Enb Address            What
    2       hw watchpoint  keep y                      g_var
    (gdb) continue 
    Continuing.
    [New Thread 0x7ffff77f2700 (LWP 9615)]
    g_var = 0
    g_var = 0
    g_var = 0
    g_var = 0
    g_var = 0
    [Switching to Thread 0x7ffff77f2700 (LWP 9615)]
    Hardware watchpoint 2: g_var
    
    Old value = 0
    New value = 1
    thread_func (args=0x0) at test.c:12 //执行到第12行时g_var被改写了
    12	}
    (gdb) 
    (gdb) print g_var 
    $1 = 1
    (gdb) print /a &g_var 
    $2 = 0x601048 <g_var>
    (gdb) x /4bx 0x601048
    0x601048 <g_var>:	0x01	0x00	0x00	0x00 //由以下判断系统的大小端
    (gdb) x /1bx 0x601048
    0x601048 <g_var>:	0x01
    (gdb) x /1wx 0x601048
    0x601048 <g_var>:	0x00000001 //(这里为了更严谨一点可以再定义一个变量看其地址是从高地址申请到低地址还是相反)
    (gdb) 
    
    
  • 函数调用栈的查看(backtrace和frame)

    • backtrace
      • 查看函数调用的顺序(函数调用栈的信息)
    • frame N
      • 切换到栈编号为N的上下文中
    • info frame
      • 查看当前函数调用的栈帧信息
  • 栈帧信息(函数调用过程相关的记录)

    参数
    返回地址
    Old ebp
    寄存器信息
    局部变量
    其他数据信息

    2个重要的寄存器:ebp、esp

    • 深入info命令
      | 命令 | 功能说明 |
      | ------------- |
      | info registers | 查看当前寄存器的值 |
      | info args | 查看当前函数参数的值 |
      | info locals | 查看当前局部变量的值 |
      | info frame | 查看当前栈帧的详细信息 |
      | info variable | 查看程序中的变量符号|
      | info functions | 查看程序中的函数符号 |
topeet@ubuntu:~/Desktop/Code$ gdb test.out 
GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2.1) 7.4-2012.04
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
For bug reporting instructions, please see:
<http://bugs.launchpad.net/gdb-linaro/>...
Reading symbols from /home/topeet/Desktop/Code/test.out...done.
(gdb) start
Temporary breakpoint 1 at 0x40054c: file test.c, line 19.
Starting program: /home/topeet/Desktop/Code/test.out 

Temporary breakpoint 1, main () at test.c:19
19	    int s = 0;
(gdb) continue 
Continuing.
sum = 55
[Inferior 1 (process 9690) exited normally]
(gdb) break sum if n==0  //打一个条件断点
Breakpoint 2 at 0x40051f: file test.c, line 6.
(gdb) info breakpoints 
Num     Type           Disp Enb Address            What
2       breakpoint     keep y   0x000000000040051f in sum at test.c:6
	stop only if n==0
(gdb) continue 
The program is not being run.
(gdb) run
Starting program: /home/topeet/Desktop/Code/test.out 

Breakpoint 2, sum (n=0) at test.c:6
6	    int ret = 0;
(gdb) backtrace 
#0  sum (n=0) at test.c:6
#1  0x0000000000400539 in sum (n=1) at test.c:10
#2  0x0000000000400539 in sum (n=2) at test.c:10
#3  0x0000000000400539 in sum (n=3) at test.c:10
#4  0x0000000000400539 in sum (n=4) at test.c:10
#5  0x0000000000400539 in sum (n=5) at test.c:10
#6  0x0000000000400539 in sum (n=6) at test.c:10
#7  0x0000000000400539 in sum (n=7) at test.c:10
#8  0x0000000000400539 in sum (n=8) at test.c:10
#9  0x0000000000400539 in sum (n=9) at test.c:10
#10 0x0000000000400539 in sum (n=10) at test.c:10
#11 0x000000000040055d in main () at test.c:21  //可以查看变量的调用情况当然也可以查看函数调用的过程/路径
(gdb) next
8	    if( n > 0 )
(gdb) info args
n = 0
(gdb) frame 7  //切换栈帧
#7  0x0000000000400539 in sum (n=7) at test.c:10
10	        ret = n + sum(n-1);
(gdb) info args
n = 7
(gdb) 
(gdb) frame 0 //切换栈帧,继续分析
#0  sum (n=0) at test.c:8
8	    if( n > 0 )
(gdb) info registers //打印出重要的寄存器信息
rax            0x0	0
rbx            0x0	0
rcx            0x0	0
rdx            0x7fffffffe2b8	140737488347832
rsi            0x7fffffffe2a8	140737488347816
rdi            0x0	0
rbp            0x7fffffffdfc0	0x7fffffffdfc0
rsp            0x7fffffffdfa0	0x7fffffffdfa0
r8             0x7ffff7dd4e80	140737351863936
r9             0x7ffff7dea600	140737351951872
r10            0x7fffffffe050	140737488347216
r11            0x7ffff7a32e50	140737348054608
r12            0x400450	4195408
r13            0x7fffffffe2a0	140737488347808
r14            0x0	0
r15            0x0	0
rip            0x400526	0x400526 <sum+18>
eflags         0x206	[ PF IF ]
cs             0x33	51
ss             0x2b	43
ds             0x0	0
es             0x0	0
fs             0x0	0
---Type <return> to continue, or q <return> to quit---
(gdb) info frame //当前函数调用的详细信息,或者说栈帧的详细信息
Stack level 0, frame at 0x7fffffffdfd0:
 rip = 0x400526 in sum (test.c:8); saved rip 0x400539
 called by frame at 0x7fffffffe000
 source language c.
 Arglist at 0x7fffffffdfc0, args: n=0
 Locals at 0x7fffffffdfc0, Previous frame's sp is 0x7fffffffdfd0 //sp指针的话应该是函数的执行流程指针,这段话的意思应该是 在这个函数调用之前sp的地址是0x7fffffffdfd0
 Saved registers:
  rbp at 0x7fffffffdfc0, rip at 0x7fffffffdfc8
(gdb) 
(gdb) x /1wx 0x7fffffffdfc0 
0x7fffffffdfc0:	0xffffdff0 //在这个函数调用之前rbp为首连续4个字节的数据是0xffffdff0(这个就先不验证了,对这些寄存器的概念还有点模糊)这个可以看上面的栈帧信息,一位在在返回地址下面有一个Old ebp,说明是previous old ebp 。

相关程序:

#include <stdio.h>


int sum(int n)
{
    int ret = 0;
    
    if( n > 0 )
    {
        ret = n + sum(n-1);
    }
    
    return ret;
}


int main()
{
    int s = 0;
    
    s = sum(10);
    
    printf("sum = %d\\n", s);
    
    return 0;
}

以上是关于调试利器GDB-中的主要内容,如果未能解决你的问题,请参考以下文章

调试利器GDB-上

调试利器GDB(下)

调试利器GDB-中

调试利器GDB-中

调试利器GDB-下

调试利器GDB-下