从VS转gdb的人会觉得GDB比较难用,其实gdb使用熟练了比VS可能还方便。可以说不会gdb的人,没法真正懂Linux编程。
有正在学习C语言的朋友,可以进Q群121811911下载软件资料和视频,我们一起进步。
编译具有调试符号的程序
gcc编译时,带上-g选项才能产生具有调试符号的程序。才能供gdb进行有源码调试
$ gcc -g justtest.c
反汇编
disassemb命令是反汇编
(gdb) disassemble main
Dump of assembler code for function main:
0x000000000040057d <+0>: push %rbp
0x000000000040057e <+1>: mov %rsp,%rbp
0x0000000000400581 <+4>: sub $0x20,%rsp
0x0000000000400585 <+8>: mov %edi,-0x14(%rbp)
0x0000000000400588 <+11>: mov %rsi,-0x20(%rbp)
0x000000000040058c <+15>: movl $0x12345678,-0x4(%rbp)
...
0x00000000004005c6 <+73>: retq
End of assembler dump.
/r选项是反汇编时带上机器码
(gdb) disassemble /r main
Dump of assembler code for function main:
0x000000000040057d <+0>: 55 push %rbp
0x000000000040057e <+1>: 48 89 e5 mov %rsp,%rbp
0x0000000000400581 <+4>: 48 83 ec 20 sub $0x20,%rsp
0x0000000000400585 <+8>: 89 7d ec mov %edi,-0x14(%rbp)
0x0000000000400588 <+11>: 48 89 75 e0 mov %rsi,-0x20(%rbp)
...
0x00000000004005bb <+62>: e8 90 fe ff ff callq 0x400450 <write@plt>
0x00000000004005c0 <+67>: b8 00 00 00 00 mov $0x0,%eax
0x00000000004005c5 <+72>: c9 leaveq
0x00000000004005c6 <+73>: c3 retq
End of assembler dump.
/m选项是反汇编时带上源码(如果有的话)
(gdb) disassemble /m main
Dump of assembler code for function main:
4 {
0x000000000040057d <+0>: push %rbp
0x000000000040057e <+1>: mov %rsp,%rbp
0x0000000000400581 <+4>: sub $0x20,%rsp
0x0000000000400585 <+8>: mov %edi,-0x14(%rbp)
0x0000000000400588 <+11>: mov %rsi,-0x20(%rbp)
5 int nValue = 0x12345678;
0x000000000040058c <+15>: movl $0x12345678,-0x4(%rbp)
6 printf("%p:%08X\n", &nValue, nValue);
0x0000000000400593 <+22>: mov -0x4(%rbp),%edx
0x0000000000400596 <+25>: lea -0x4(%rbp),%rax
0x000000000040059a <+29>: mov %rax,%rsi
0x000000000040059d <+32>: mov $0x400654,%edi
0x00000000004005a2 <+37>: mov $0x0,%eax
0x00000000004005a7 <+42>: callq 0x400460 <printf@plt>
7 write(0, "hello,world\n", 13);
...
也可以两个选项一起用:
disassemble /rm main
设置反汇编的风格
反汇编的语法默认是GNU风格的,可以使用命令设置为Intel风格
(gdb) set disassembly-flavor intel
(gdb) disassemble main
Dump of assembler code for function main:
0x000000000040057d <+0>: push rbp
0x000000000040057e <+1>: mov rbp,rsp
0x0000000000400581 <+4>: sub rsp,0x20
0x0000000000400585 <+8>: mov DWORD PTR [rbp-0x14],edi
0x0000000000400588 <+11>: mov QWORD PTR [rbp-0x20],rsi
0x000000000040058c <+15>: mov DWORD PTR [rbp-0x4],0x12345678
...
0x00000000004005c5 <+72>: leave
0x00000000004005c6 <+73>: ret
End of assembler dump.
单步调试
next:单步步过
step:单步步入
以上是源码级别的单步。如果是汇编级别的单步,则使用:
nexti/stepi(两者效果一样)
自动显示反汇编代码
如果gdb匹配了源文件,则即使使用stepi,那么自动回显的内容依然是源码级别的,需要手动敲disassemble来查看当前汇编内容,很不方便。这时,可以通过display命令达到自动回显的目的:
(gdb) help display
Print value of expression EXP each time the program stops.
/FMT may be used before EXP as in the "print" command.
/FMT "i" or "s" or including a size-letter is allowed,
as in the "x" command, and then EXP is used to get the address to examine
and examining is done as in the "x" command.
With no argument, display all currently requested auto-display expressions.
Use "undisplay" to cancel display requests previously made.
可知,display命令是在每次调试器断下来后,自动显示某个表达式。
我们通过命令:
display /5i $pc
然后每次停下,就会显示对应的反汇编了:
(gdb) stepi
6 printf("%p:%08X\n", &nValue, nValue);
6: x/5i $pc
=> 0x400593 <main+22>: mov -0x4(%rbp),%edx
0x400596 <main+25>: lea -0x4(%rbp),%rax
0x40059a <main+29>: mov %rax,%rsi
0x40059d <main+32>: mov $0x400654,%edi
0x4005a2 <main+37>: mov $0x0,%eax
普通断点
通过breakpoint命令下断点。breakpoint之后可接源文件行、函数名称、地址。如:
(gdb) break main
Note: breakpoint 1 also set at pc 0x40058c.
Breakpoint 3 at 0x40058c: file justtest.c, line 5.
(gdb) break 8
Breakpoint 4 at 0x4005c0: file justtest.c, line 8.
(gdb) break *0x4005c0
Note: breakpoint 4 also set at pc 0x4005c0.
Breakpoint 5 at 0x4005c0: file justtest.c, line 8.
可以使用info命令查看断点信息:
(gdb) info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep y 0x000000000040058c in main at justtest.c:5
2 breakpoint keep y 0x0000000000400593 in main at justtest.c:6
3 breakpoint keep y 0x00000000004005c0 in main at justtest.c:8
通过delete命令,可以删除指定编号的断点。
(gdb) delete breakpoints 1
也可以通过disable/enable来暂定或启用断点。
(gdb) disable breakpoints 1
内存断点
watch命令是下内存写断点:
watch ($rbp-4)
类似的,还有内存读断点rwatch,与内存访问断点(读与写)awatch命令。
查看表达式及内存寄存器等
命令查看内存
x命令(examine)命令可以用于查看内存。
(gdb) help x
Examine memory: x/FMT ADDRESS.
ADDRESS is an expression for the memory address to examine.
FMT is a repeat count followed by a format letter and a size letter.
Format letters are o(octal), x(hex), d(decimal), u(unsigned decimal),
t(binary), f(float), a(address), i(instruction), c(char), s(string)
and z(hex, zero padded on the left).
Size letters are b(byte), h(halfword), w(word), g(giant, 8 bytes).
The specified number of objects of the specified size are printed
according to the format.
如,以字节为单位,以16进制显示,查看4单位&nValue地址处的数据:
(gdb) x /4xb &nValue
0x7fffffffdf3c: 0x78 0x56 0x34 0x12
以10进制查看:
(gdb) x /4db &nValue
0x7fffffffdf3c: 120 86 52 18
按照float解释数据:
(gdb) x /1fw &nValue
0x7fffffffdf3c: 5.69045661e-28
按照double解释数据:
(gdb) x /1fg &nValue
0x7fffffffdf3c: 1.5089747817000635e-315
查看寄存器
(gdb) info registers
修改内存值
使用set命令
set *(type*)<addr>=newValue
如:
(gdb) set *(int*)0x7fffffffdf38=0x40490fda
有正在学习C语言的朋友,可以进Q群121811911下载软件资料和视频,我们一起进步。