Ring3程序编译时添加-g参数编译:
汇总常用gdb命令,持续添加…
命令 | 说明 |
---|---|
break | 当不带参数时,在所选栈帧中执行的下一条指令处设置断点 |
break “function” | 在function入口处添加断点 |
break “line” | 在当前源码文件指定行的开始处打断点 |
break “filename:line” | 在源码文件filename的line行处下断点 |
break “filename:function” | 在源码文件filename的function函数下断点 |
break “address” | 在address处下断点 |
break … if cond | 在cond值非零时停住程序 |
info break | 查看所有断点信息 |
list(l) | 从第一行开始例出原码(实测没有显示头文件) |
回车键 | 直接回车表示,重复上一次命令 |
run(r ) | 运行程序 |
nest(n) | 单条语句执行,不进入函数 |
reverse-next | 反向步进程序,执行完子程序调用 |
step(s) | 单条语句执行,进入函数 |
reverse-step | 反向步进程序,直到到达另一个源码行的开头 |
return “expression” | 将expression的值作为函数的返回值并使函数直接返回 |
continue(c) | 继续运行程序 |
print(p) | 打印变量的值 |
bt | 查看函数堆栈 |
finish | 退出函数 |
quit(q) | 退出程序,结束调试 |
symbols(s) | 从指定文件中读取符号表 s file |
thread(t) | 查看调试进程的pid号 |
help | 列出出gdb的命令种类 |
help + 类 | ex:help breakpoints显示断点相关命令 |
watch | 监视某个变量或者是表达式的值 |
catch | 设置捕捉点来补捉程序运行时的一些事件 |
show disassembly-flavor | gdb默认反汇编为att格式的指令 |
set disassembly-flavor intel | 将反汇编格式设置为NASM |
x /24xb + 0x555555554704 | 以16进制方式显示起始地址为0x555555554704的24字节数据 |
info reg | 查看寄存器的值 |
info threads | 打印出所有线程的信息 |
info frame | 打印出指定栈帧的详细信息 |
info proc | 查看proc里的进程信息 |
info register edx | 查看edx寄存器的值 |
使用qemu + gdb 调试Linux内核时发现,并不是内核所有的函数都可以下断点的,需要找内核的导出函数;
//调试源码
#include <stdio.h>
void main()
{
printf("%s %d %s", "Hello world", 233, "\n");
printf("%s %d %s", "Hello world", 233, "\n");
}
//反汇编main函数
(gdb) disassemble main
Dump of assembler code for function main:
0x0000555555554625 <+0>: push rbp
0x0000555555554626 <+1>: mov rbp,rsp
=> 0x0000555555554629 <+4>: lea rcx,[rip+0xd4] # 0x555555554704
0x0000555555554630 <+11>: mov edx,0xe9
0x0000555555554635 <+16>: lea rsi,[rip+0xca] # 0x555555554706
0x000055555555463c <+23>: lea rdi,[rip+0xcf] # 0x555555554712
0x0000555555554643 <+30>: mov eax,0x0
0x0000555555554648 <+35>: call 0x555555554520 <printf@plt>
0x000055555555464d <+40>: lea rcx,[rip+0xb0] # 0x555555554704
0x0000555555554654 <+47>: mov edx,0xe9
0x0000555555554659 <+52>: lea rsi,[rip+0xa6] # 0x555555554706
0x0000555555554660 <+59>: lea rdi,[rip+0xab] # 0x555555554712
0x0000555555554667 <+66>: mov eax,0x0
0x000055555555466c <+71>: call 0x555555554520 <printf@plt>
0x0000555555554671 <+76>: nop
0x0000555555554672 <+77>: pop rbp
0x0000555555554673 <+78>: ret
End of assembler dump.
// i r 查看当前寄存器的值
(gdb) i r
rax 0x555555554625 93824992232997
rbx 0x0 0
rcx 0x555555554680 93824992233088
rdx 0x7fffffffe578 140737488348536
rsi 0x7fffffffe568 140737488348520
rdi 0x1 1
rbp 0x7fffffffe480 0x7fffffffe480
rsp 0x7fffffffe480 0x7fffffffe480
r8 0x7ffff7dd0d80 140737351847296
r9 0x7ffff7dd0d80 140737351847296
r10 0x0 0
r11 0x1 1
r12 0x555555554540 93824992232768
r13 0x7fffffffe560 140737488348512
r14 0x0 0
r15 0x0 0
rip 0x555555554629 0x555555554629 <main+4>
eflags 0x246 [ PF ZF IF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
//十六进制形式查看给定内存地址的值
(gdb) x /24xb 0x555555554704
0x555555554704: 0x0a 0x00 0x48 0x65 0x6c 0x6c 0x6f 0x20
0x55555555470c: 0x77 0x6f 0x72 0x6c 0x64 0x00 0x25 0x73
0x555555554714: 0x20 0x25 0x64 0x20 0x25 0x73 0x00 0x00
//字符串形式查看给定内存地址的值
(gdb) x /4s 0x555555554704
0x555555554704: "\n"
0x555555554706: "Hello world"
0x555555554712: "%s %d %s"
0x55555555471b: ""
//指令形式查看指定地址处的数据
(gdb) x /24i 0x555555554704
0x555555554704: or al,BYTE PTR [rax]
0x555555554706: rex.W
0x555555554707: gs ins BYTE PTR es:[rdi],dx
0x555555554709: ins BYTE PTR es:[rdi],dx
0x55555555470a: outs dx,DWORD PTR ds:[rsi]
0x55555555470b: and BYTE PTR [rdi+0x6f],dh
0x55555555470e: jb 0x55555555477c
0x555555554710: add BYTE PTR fs:[rip+0x64252073],ah # 0x5555b97a678a
0x555555554717: and BYTE PTR [rip+0x1000073],ah # 0x555556554790
0x55555555471d: sbb eax,DWORD PTR [rbx]
0x55555555471f: cmp edi,DWORD PTR [rax]
0x555555554721: add BYTE PTR [rax],al
0x555555554723: add BYTE PTR [rsi],al
0x555555554725: add BYTE PTR [rax],al
0x555555554727: add ah,dh
0x555555554729: std
0x55555555472a: (bad)
0x55555555472b: inc DWORD PTR [rax+rax*1-0x1ec0000]
0x555555554732: (bad)
0x555555554733: jmp FWORD PTR [rax+rax*1-0x1dc0000]
0x55555555473a: (bad)
0x55555555473b: call QWORD PTR [rax+rax*1+0x0]
0x55555555473f: add BYTE PTR [rcx],cl
0x555555554741: (bad)
//打印线程信息
(gdb) info threads
Id Target Id Frame
* 1 process 4663 "a.out" main () at format.c:5
//打印指定栈帧信息
(gdb) info frame
Stack level 0, frame at 0x7fffffffe490:
rip = 0x555555554629 in main (format.c:5); saved rip = 0x7ffff7a05b97
source language c.
Arglist at 0x7fffffffe480, args:
Locals at 0x7fffffffe480, Previous frame's sp is 0x7fffffffe490
Saved registers:
rbp at 0x7fffffffe480, rip at 0x7fffffffe488
//查看proc里的进程信息
(gdb) info proc
process 4663
cmdline = '/mnt/hgfs/share/linux_c/int/a.out'
cwd = '/mnt/hgfs/share/linux_c/int'
exe = '/mnt/hgfs/share/linux_c/int/a.out'
从上面gdb分析的结果来看在call printf之前,会将参数从左到右依次压入栈中;