- 终于有机会总结gdb了
- 打开寄存器窗口
- 首先声明一点吧,这是我一直以来的没有搞明白的地方。
- 下面的这个程序我还弄不明白,继续debug
- list命令
- p命令
- run
- break
- 单步执行 next和step
- finish
- watch
- 查看函数体内的变量值
- assemble
- gdb查看内存指令–x
- 使用案例
终于有机会总结gdb了
打开寄存器窗口
layout regs
显示的窗口如下:
┌──Register group: general─────────────────────────────────────────────────────────────────────────────────────┐
│zero 0x0 0 │
│ra 0x252ea 0x252ea <__real_libc_init(void*, void (*)(), int (*)(int, char**, char**), structors_a│
│sp 0x3ffffff640 0x3ffffff640 │
│gp 0xf4e28 0xf4e28 <je_extents_rtree+337096> │
│tp 0x1555568fc0 0x1555568fc0 │
│t0 0x253a8 152488 │
│t1 0x3c412 246802 │
│t2 0x8f2b8 586424 │
│fp 0x88028 0x88028 <__FINI_ARRAY__> │
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
B+>│0x25078 <main+2> sd ra,8(sp) │
│0x2507a <main+4> auipc a0,0xfffec │
│0x2507e <main+8> addi a0,a0,1215 │
│0x25082 <main+12> auipc ra,0x22 │
│0x25086 <main+16> jalr -1426(ra) │
│0x2508a <main+20> li a0,0 │
│0x2508c <main+22> ld ra,8(sp) │
│0x2508e <main+24> addi sp,sp,16 │
│0x25090 <main+26> ret │
└───────────────────────────────────────────────────────────────────────────────────────────────────────────┘
remote Thread 12044.12044 In: main L4 PC: 0x25078
(gdb)
如果想查看浮点寄存器,可以使用“tui reg float”命令
首先声明一点吧,这是我一直以来的没有搞明白的地方。
(gdb) b main
Breakpoint 1 at 0x5555555546e9: file my.c, line 21.
(gdb) c
Starting program: /home/yubo/test/my
Breakpoint 1, main () at my.c:21
21 n = 1;
(gdb) s
22 n++;
(gdb) p n
$1 = 1
在这段代码中,我设置了一个断点并且运行起来,注意,断点处,21,这个21的n=1还没有被执行,只是下一次将要执行的语句,例证就是22的代码,你看,在22处, 虽然打印了n++,但是你打印 p n
, 则还是n,说明n没有加1,所以这就是下一条语句要执行的过程。
下面的这个程序我还弄不明白,继续debug
#include<stdio.h>
int main()
{
int a[5] = { 1,2,3,4,5};
int *ptr1 = (int *)(&a + 1);
int *ptr2 = ((int *)(int)a + 1);
printf("%x,%x",ptr1[-1],*ptr2);
return 0;
}
list命令
list num
显示源代码的num行的周围几行。
list function
显示函数。
p命令
打印结构体元素
使用这个命令,还可以查看结构体的各元素值
p *pstDate
打印数组元素
如果你想查看一个数组的各个元素,别像我似的傻乎乎的一个个 p a[i],节省生命的做 法应该是:
p ArrayVal@itemnum
什么意思?意思就是打印数组ArrayVal的前itemnum个元素。
格式控制
p /x Val 十六进制
/c 字符?
/f 浮点型?
查看内存变量
x
我也不知道这一个有什么作用现在为止
查看局部变量
info local
run
set args num1 num2 num3 ..
使用show args查看设置的参数。
break
break function
你可以在一个函数前面加上b,到时候就可以在这个函数设置断点了。
break lines
break filename:linenum
在源文件filename的linenum行设置断点
break filename:function
在源文件的filename的function设置断点
break *address
在程序运行的内存空间地址处停住.
break
没有参数时,表示在下一条指令处停住。
break if
比如,设置
break if i = 10;
就是在循环体内当i等于10的时候停住。
方便一点的话,可以使用
filename:line_numbers if i == 5
比如, 我想在文件gdb.c的循环体for内当I等于5的停下来,则:
break gdb.c:6 if i == 5
单步执行 next和step
在调用函数的那行,设置个断点,然后step就进入函数体内。
扩展的用法是next
finish
运行程序直到当前函数完成返回,并打印函数的返回时的堆栈地址、返回值及参数值。
until
使用until退出循环体。这一条十分重要哈^_^.
stepi(si) 和nexti(ni)
stepi用于单步跟踪一条机器指令,另外使用
display/i $pc
在打印出程序代码的同时打印出机器指令。
watch
watch
rwatch
awatch
info watchpoints: 列出当前所设置的所有观察点。
查看函数体内的变量值
当我们使用 s 命令进入函数体内时,除了简单的 p 打印,还要更加丰富些,比如,使用backtrace(bt)
(gdb) bt
#0 add_range (low=1, high=10) at main.c:6
#1 0x080483c1 in main () at main.c:14
从这里可以看出add_range()函数是main函数调用的,main传进来的参数是low=1,high=10,main的帧为1,add_range()的帧为0,使用i(info)来看函数局部变量的值。
如果想查看main函数的当前局部变量也可以,先使用frame(f)命令,选择1号栈再查看局部变量的值:
(gdb) f 1
#1 0x080483c1 in main () at main.c:14
14 result[0] = add_range(1, 10);
(gdb) i locals
result = {0, 0, 0, 0, 0, 0, 134513196, 225011984, -1208685768, -1081160480,
...
-1208623680}
assemble
disassembles /rm
这个函数就会显示当前函数的汇编信息,其中,/r
是十六进制(raw instructions), /m
,如果你对intel 的汇编语法感兴趣,可以使用这个命令。
x/i $pc
这条命令是AT&T的语法格式的。
下面是一个简单的Hello.c的反汇编,
(gdb) disassemble /m main
Dump of assembler code for function main:
7 {
0x0000000000027936 <+0>: addi sp,sp,-16
8 int a=10;
9 int b=10;
10 printf("Hello world\n");
0x000000000002793a <+4>: auipc a0,0xfffea
0x000000000002793e <+8>: addi a0,a0,-1025 # 0x11539
0x0000000000027942 <+12>: auipc ra,0x22
0x0000000000027946 <+16>: jalr -1502(ra) # 0x49364 <puts(char const*)>
11 printf("int a+b = %d\n", sum(a, b));
0x000000000002794e <+24>: addi a0,a0,1573 # 0x13f6f
0x0000000000027952 <+28>: li a1,20
0x0000000000027954 <+30>: auipc ra,0x22
0x0000000000027958 <+34>: jalr -1664(ra) # 0x492d4 <printf(char const*, ...)>
12 return 0;
0x000000000002795c <+38>: li a0,0
0x000000000002795e <+40>: ld ra,8(sp)
0x0000000000027960 <+42>: addi sp,sp,16
0x0000000000027962 <+44>: ret
请仔细看这段代码,这是riscv64的反汇编:)
gdb查看内存指令–x
使用案例
一次性查看结构体各个成员的值
比如,我有一个结构体结构是这样的:
/*一个有权值的边集在图中*/
struct Edge{
int src, dest, weight;
};
/* V: 顶点数 E:边数,无向图*/
struct Graph{
int V,E;
struct Edge* edge;
};
先定义一个graph,在完成一次loop操作后,这时我想查看其中的各个域的值,可以一次一次的使用:
p graph@v
等进行查看,不过这样查看效率可是不高,所以在gdb中,需要使用脚本:
(gdb) set $i=5
(gdb) while ($i!=0)
>print graph->edge[$i]
>set $i = $i - 1
>end
$5 = {src = 2, dest = 4, weight = 7}
$6 = {src = 4, dest = 1, weight = 6}
$7 = {src = 0, dest = 4, weight = 5}
$8 = {src = 49, dest = 0, weight = 0}
$9 = {src = 3, dest = 2, weight = 4}