这篇文章对于一些经常用gdb的大牛来说应该是最基本的东西了,但是这里我只想分享一些基本的工具或者其他我找到的一些有用的东西。
如果你正在从gdb向lldb转换的话,这两者在命令上还是有些不同的。LLDB已经有文档说明了两者的不同点。本文中关于LLDB的调试信息都是源于那篇说明文档的。
基本的gdb和lldb的调试命令如下:
l r (run the program)
l s (step in)
l n (step over)
l finish (step out)
l c (continue)
l q (quit the program)
可以使用enter键运行最后一条指令,这个比较有用,你可以一直步过一些重复的调用。
我一直在OSX上用LLDB。我可以调试一个我自己创建的但是crash或者出现其他意外的程序:
$ sudo lldb ./asmttpd web_root
设置断点,跳转至指定label:
(lldb) b sys_write
Breakpoint 3: where = asmttpd`sys_write, address = 0x00000000000029a
运行程序直到断点断下:
(lldb) r
Process 32236 launched: './asmttpd' (x86_64)
Process 32236 stopped
* thread #1: tid = 0xe69b9, 0x00000000000029ae asmttpd`sys_write, queue = 'com.apple.main-thread', stop reason = breakpoint 3.1
frame #0: 0x00000000000029ae
asmttpd`sys_writeasmttpd`sys_write:
-> 0x29ae <+0>: pushq %rdi
0x29af <+1>: pushq %rsi
0x29b0 <+2>: pushq %rdx
0x29b1 <+3>: pushq %r10
查看当前栈帧更多的信息:
(lldb) d
asmttpd`sys_write:
-> 0x29ae <+0>: pushq %rdi
0x29af <+1>: pushq %rsi
0x29b0 <+2>: pushq %rdx
0x29b1 <+3>: pushq %r10
0x29b3 <+5>: pushq %r8
0x29b5 <+7>: pushq %r9
0x29b7 <+9>: pushq %rbx
0x29b8 <+10>: pushq %rcx
0x29b9 <+11>: movq %rsi, %rdx
0x29bc <+14>: movq %rdi, %rsi
0x29bf <+17>: movq $0x1, %rdi
0x29c6 <+24>: movq $0x2000004, %rax
0x29cd <+31>: syscall 0x29cf <+33>: popq %rcx
0x29d0 <+34>: popq %rbx 0x29d1 <+35>: popq %r9
0x29d3 <+37>: popq %r8 0x29 <+39>: popq %r10
0x29d7 <+41>: popq %rdx 0x29d8 <+42>: popq %rsi
0x29d9 <+43>: popq %rdi 0x29da <+44>: retq
回溯查看:
(lldb) bt
* thread #1: tid = 0xe69b9, 0x00000000000029ae asmttpd`sys_write, queue = 'com.apple.main-thread', stop reason = breakpoint 3.1
* frame #0: 0x00000000000029ae asmttpd`sys_write
frame #1: 0x00000000000021b6 asmttpd`print_line + 16
frame #2: 0x0000000000002ab3 asmttpd`start + 35
frame #3: 0x00007fff9900c5ad libdyld.dylib`start + 1
frame #4: 0x00007fff9900c5ad libdyld.dylib`start + 1
查看当前栈帧的前栈帧:
(lldb) up
frame #1: 0x00000000000021b6 asmttpd`print_line + 16
asmttpd`print_line:
0x21b6 <+16>: movabsq $0x30cb, %rdi
0x21c0 <+26>: movq $0x1, %rsi
0x21c7 <+33>: callq 0x29ae ; sys_write
0x21cc <+38>: popq %rcx
返回至断点处的栈帧:
(lldb) down
frame #0: 0x00000000000029ae asmttpd`sys_write
asmttpd`sys_write:
-> 0x29ae <+0>: pushq %rdi
0x29af <+1>: pushq %rsi
0x29b0 <+2>: pushq %rdx
0x29b1 <+3>: pushq %r10
dump寄存器的值:
(lldb) register read
General Purpose Registers:
rax = 0x0000000000002a90 asmttpd`start
rbx = 0x0000000000000000
rcx = 0x00007fff5fbffaf8
rdx = 0x00007fff5fbffa40
rdi = 0x00000000000030cc start_text
rsi = 0x000000000000000f
rbp = 0x00007fff5fbffa18
rsp = 0x00007fff5fbff9b8
r8 = 0x0000000000000000
r9 = 0x00007fff7b1670c8 atexit_mutex + 24
r10 = 0x00000000ffffffff
r11 = 0xffffffff00000000
r12 = 0x0000000000000000
r13 = 0x0000000000000000
r14 = 0x0000000000000000
r15 = 0x0000000000000000
rip = 0x00000000000029ae asmttpd`sys_write
rflags = 0x0000000000000246
cs = 0x000000000000002b
fs = 0x0000000000000000
gs = 0x0000000000000000
读某一个寄存器的值:
(lldb) register read rdi
rdi = 0x00000000000030cc start_text
当你想找出一段由C代码编译的系统调用时,使用dtruss非常有用。dtruss在OSX上可以直接获得。这个命令似乎是Dtrace的一个变种。
$ cat sleep.c
#include
int main () {
struct timespec rqtp = {
2,
0
};
nanosleep(&rqtp, NULL);
}
$ clang sleep.c
$ sudo dtruss ./a.out
...all kinds of fun stuff
__semwait_signal(0xB03, 0x0, 0x1) = -1 Err#60
如果你用-g命令编译代码从而获得调试符号,你可以使用lldb的反编译命令来获得相同的汇编代码:
$ clang sleep.c -g
$ lldb a.out
(lldb) target create "a.out"
Current executable set to 'a.out' (x86_64).
(lldb) b main
Breakpoint 1: where = a.out`main + 16 at sleep.c:3, address = 0x0000000100000f40
(lldb) r
Process 33213 launched: '/Users/Nicholas/code/assembly/asmttpd/a.out' (x86_64)
Process 33213 stopped
* thread #1: tid = 0xeca04, 0x0000000100000f40 a.out`main + 16 at sleep.c:3, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x0000000100000f40 a.out`main + 16 at sleep.c:3
1 #include
2 int main () {
-> 3 struct timespec rqtp = {
4 2,
5 0
6 };
7
(lldb) disassemble
a.out`main:
0x100000f30 <+0>: pushq %rbp
0x100000f31 <+1>: movq %rsp, %rbp
0x100000f34 <+4>: subq $0x20, %rsp
0x100000f38 <+8>: leaq -0x10(%rbp), %rdi
0x100000f3c <+12>: xorl %eax, %eax
0x100000f3e <+14>: movl %eax, %esi
-> 0x100000f40 <+16>: movq 0x49(%rip), %rcx
0x100000f47 <+23>: movq %rcx, -0x10(%rbp)
0x100000f4b <+27>: movq 0x46(%rip), %rcx
0x100000f52 <+34>: movq %rcx, -0x8(%rbp)
0x100000f56 <+38>: callq 0x100000f68 ; symbol stub for: nanosleep
0x100000f5b <+43>: xorl %edx, %edx
0x100000f5d <+45>: movl %eax, -0x14(%rbp)
0x100000f60 <+48>: movl %edx, %eax
0x100000f62 <+50>: addq $0x20, %rsp
0x100000f66 <+54>: popq %rbp
0x100000f67 <+55>: retq
如果你想学习更多关于X86-64的汇编代码编程的话,可以读下writing X86-64这篇博客。
*原文地址:nickdesaulniers, 老王隔壁的白帽子编译,转载请注明来自FreeBuf黑客与极客(FreeBuf.COM)