如何使用自定义elf解释器调试程序?

时间:2015-02-11 20:35:27

标签: debugging gdb ld elf

我可以像这样调试一些程序(比如/ bin / ls):

[ks@localhost ~]$ gdb -q --args /bin/ls
Reading symbols from /bin/ls...Reading symbols from /bin/ls...(no debugging symbols found)...done.
(no debugging symbols found)...done.
Missing separate debuginfos, use: debuginfo-install coreutils-8.22-19.fc21.x86_64
(gdb) start 
Temporary breakpoint 1 at 0x402990
Starting program: /usr/bin/ls 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".

Temporary breakpoint 1, 0x0000000000402990 in main ()
(gdb) 

在这里,我可以在main处设置临时断点并停在此处。

但我必须使用这样的自定义精灵解释器来运行程序:

[ks@localhost ~]$ gdb -q --args /lib64/ld-linux-x86-64.so.2 /bin/ls
Reading symbols from /lib64/ld-linux-x86-64.so.2...Reading symbols from /usr/lib/debug/usr/lib64/ld-2.20.so.debug...done.
done.
(gdb) start 
Function "main" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Temporary breakpoint 1 (main) pending.
Starting program: /usr/lib64/ld-linux-x86-64.so.2 /bin/ls
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
1234            glibc-2.20      python     tmp
[Inferior 1 (process 2610) exited normally]
Missing separate debuginfos, use: debuginfo-install libacl-2.2.52-7.fc21.x86_64 libattr-2.4.47-9.fc21.x86_64 libcap-2.24-7.fc21.x86_64 pcre-8.35-8.fc21.x86_64
(gdb) 

这里gdb没有在main停止,因为没有加载/ bin / ls的符号。 在这种情况下,如何强制gdb加载符号并在main处停止?

1 个答案:

答案 0 :(得分:13)

以下是如何做到这一点:

cat t.c
#include <stdio.h>
#include <stdlib.h>

int main()
{
  printf("Hello\n");
  return 0;
}

gcc -g t.c
gdb -q --args /usr/lib64/ld-linux-x86-64.so.2 ./a.out
(gdb) start
Function "main" not defined.
Starting program: /usr/lib64/ld-linux-x86-64.so.2 ./a.out
Hello
[Inferior 1 (process 7134) exited normally]

到目前为止,一切都与你观察到的相符。现在为解决方案:

(gdb) set stop-on-solib-events 1
(gdb) r
Starting program: /usr/lib64/ld-linux-x86-64.so.2 ./a.out
Stopped due to shared library event (no libraries added or removed)
(gdb) c
Continuing.
Stopped due to shared library event:
  Inferior loaded /usr/lib64/ld-linux-x86-64.so.2
(gdb) c
Continuing.
Stopped due to shared library event:
  Inferior loaded /usr/lib64/libc.so.6

此时,./a.out也已加载,您可以通过以下方式确认:

(gdb) info proc map
process 7140
Mapped address spaces:

          Start Addr           End Addr       Size     Offset objfile
            0x400000           0x401000     0x1000        0x0 /tmp/a.out
            0x600000           0x601000     0x1000        0x0 /tmp/a.out
            0x601000           0x602000     0x1000     0x1000 /tmp/a.out
      0x555555554000     0x555555579000    0x25000        0x0 /usr/lib64/ld-2.19.so
      0x555555779000     0x55555577a000     0x1000    0x25000 /usr/lib64/ld-2.19.so
      0x55555577a000     0x55555577c000     0x2000    0x26000 /usr/lib64/ld-2.19.so
      0x7ffff7c2a000     0x7ffff7c2d000     0x3000        0x0
      0x7ffff7c2d000     0x7ffff7df0000   0x1c3000        0x0 /usr/lib64/libc-2.19.so
      0x7ffff7df0000     0x7ffff7fef000   0x1ff000   0x1c3000 /usr/lib64/libc-2.19.so
      0x7ffff7fef000     0x7ffff7ff3000     0x4000   0x1c2000 /usr/lib64/libc-2.19.so
      0x7ffff7ff3000     0x7ffff7ff5000     0x2000   0x1c6000 /usr/lib64/libc-2.19.so
      0x7ffff7ff5000     0x7ffff7ff9000     0x4000        0x0
      0x7ffff7ff9000     0x7ffff7ffa000     0x1000        0x0 /etc/ld.so.cache
      0x7ffff7ffa000     0x7ffff7ffd000     0x3000        0x0
      0x7ffff7ffd000     0x7ffff7fff000     0x2000        0x0 [vdso]
      0x7ffffffde000     0x7ffffffff000    0x21000        0x0 [stack]
  0xffffffffff600000 0xffffffffff601000     0x1000        0x0 [vsyscall]

不幸的是,GDB不明白它还应该为./a.out加载符号。你必须告诉它:

(gdb) add-symbol-file ./a.out
The address where ./a.out has been loaded is missing

有人会认为GDB需要的地址来自上面的info proc map0x400000。一个人会错的。 GDB需要的实际地址是.text部分的开头,你可以从readelf获得:

readelf -WS ./a.out | grep text
   [13] .text             PROGBITS        0000000000400440 000440 000182 00  AX  0   0 16

回到GDB:

(gdb) add-symbol-file ./a.out 0x0000000000400440
add symbol table from file "./a.out" at
    .text_addr = 0x400440
Reading symbols from ./a.out...done.

现在我们可以打破main

(gdb) b main
Breakpoint 1 at 0x400531: file t.c, line 6.
(gdb) c
Continuing.

Breakpoint 1, main () at t.c:6
6     printf("Hello\n");
(gdb) n
Hello
7     return 0;

瞧!

P.S。重新运行二进制文件可能会给你带来一些小问题:

(gdb) r
Starting program: /usr/lib64/ld-linux-x86-64.so.2 ./a.out
Error in re-setting breakpoint 1: Cannot access memory at address 0x40052d
Error in re-setting breakpoint 1: Cannot access memory at address 0x40052d
Stopped due to shared library event (no libraries added or removed)

这种情况正在发生,因为ld-linux尚未映射./a.out。但你可以继续:

(gdb) c
Continuing.
Stopped due to shared library event:
  Inferior loaded /usr/lib64/ld-linux-x86-64.so.2
(gdb) c
Continuing.
Stopped due to shared library event:
  Inferior loaded /usr/lib64/libc.so.6

现在,./a.out也已加载,因此您可以重新启用断点:

(gdb) enable
(gdb) continue
Continuing.

Breakpoint 1, main () at t.c:6
6     printf("Hello\n");