这篇文章对于一些经常用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)

源链接

Hacking more

...