注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

gmd20的个人空间

// 编程和生活

 
 
 

日志

 
 

addr2line 显示指定地址的对应源文件行数的原理和ELF格式的 .debug_line 段  

2011-08-02 13:08:31|  分类: 默认分类 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
addr2line 常见的用处就是根据程序崩溃时候打印的堆栈地址,用来查看出错的源代码的行数。这个其中的原理就是,如果指定 -g选项给 gcc的话,最终的生成elf文件包含有几个.debug段,像.debug_line 就包含每个汇编指令对应的地址和源代码行数源代码名字等信息。程序加载的时候,应该是加载到固定的虚拟地址上去,所有这个文件里面的地址和运行时的地址应 该是固定的或者不变的偏移什么的,感兴趣的可以自己去看一下linux执行elf时候,是怎么加载和映射.text代码段的。
因为有这个几个.debug_line段的存在,所有是可以知道每个地址或者说指定对应的源码行数的,反过来亦然。像objdump  或者 gdb应该都是可以解析这个 .debug_line 段的,可以查看代码证实一下。比如下面这样

objdump -S -d a.out

int naive_match (char s[], char p[], int m , int n)
{
 8048444:       55                      push   %ebp
 8048445:       89 e5                   mov    %esp,%ebp
 8048447:       83 ec 28                sub    $0x28,%esp
     int i=0,j=0;
 804844a:       c7 45 f4 00 00 00 00    movl   $0x0,-0xc(%ebp)
 8048451:       c7 45 f0 00 00 00 00    movl   $0x0,-0x10(%ebp)
     for (i = 0; i< m - n + 1; i++) {        
 8048458:       c7 45 f4 00 00 00 00    movl   $0x0,-0xc(%ebp)
 804845f:       e9 81 00 00 00          jmp    80484e5 <naive_match+0xa1>
          int ii = i;
 8048464:       8b 45 f4                mov    -0xc(%ebp),%eax
 8048467:       89 45 ec                mov    %eax,-0x14(%ebp)
          for ( j = 0; j< n;j++) {
 804846a:       c7 45 f0 00 00 00 00    movl   $0x0,-0x10(%ebp)
 8048471:       eb 66                   jmp    80484d9 <naive_match+0x95>
                if (s[ii] == p[j]) {
 8048473:       8b 45 ec                mov    -0x14(%ebp),%eax



 gdb a.out
(gdb) disassemble /m  naive_match

Dump of assembler code for function naive_match:
13    {
   0x08048444 <+0>:    push   %ebp
   0x08048445 <+1>:    mov    %esp,%ebp
   0x08048447 <+3>:    sub    $0x28,%esp

14         int i=0,j=0;
   0x0804844a <+6>:    movl   $0x0,-0xc(%ebp)
   0x08048451 <+13>:    movl   $0x0,-0x10(%ebp)

15         for (i = 0; i< m - n + 1; i++) {        
   0x08048458 <+20>:    movl   $0x0,-0xc(%ebp)
   0x0804845f <+27>:    jmp    0x80484e5 <naive_match+161>
   0x080484e1 <+157>:    addl   $0x1,-0xc(%ebp)
   0x080484e5 <+161>:    mov    0x14(%ebp),%eax
   0x080484e8 <+164>:    mov    0x10(%ebp),%edx
   0x080484eb <+167>:    mov    %edx,%ecx
   0x080484ed <+169>:    sub    %eax,%ecx
   0x080484ef <+171>:    mov    %ecx,%eax
   0x080484f1 <+173>:    add    $0x1,%eax
   0x080484f4 <+176>:    cmp    -0xc(%ebp),%eax



如果用strip -d  命令把 这个elf文件的几个debug删掉,那么addr2line 和这objdump gdb应该都不能显示代码行数和汇编的关系了。
可 以使用objdump  -x  a.out  或者readelf  --sections  a.out  命令查看elf文件的各个段。readelf -wl a.out  和readelf --debug-dump a.out 命令还可以查看这几个段的内容的。

“SYMBOL TABLE”符号表段.symtab  应该只是保存函数名和变量名等基本的符号的地址和长度等信息的,所以backtrace函数等可以根据地址得到出错的是哪个函数和在函数中的偏移,但具体 到源码的哪一行还是要靠这个.debug_line这里面的信息的。

gdb 里面可以通过file 或者 add-symbol-file来加载符号表的。但如果需要源码行数信息就需要用-g 重新编译程序以生成 .debug_line  section 才能查看了。



======================================================================

objdump  -x  a.out

a.out:     file format elf32-i386
a.out
architecture: i386, flags 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
start address 0x08048390

Program Header:
    PHDR off    0x00000034 vaddr 0x08048034 paddr 0x08048034 align 2**2
         filesz 0x00000100 memsz 0x00000100 flags r-x
  INTERP off    0x00000134 vaddr 0x08048134 paddr 0x08048134 align 2**0
         filesz 0x00000013 memsz 0x00000013 flags r--
    LOAD off    0x00000000 vaddr 0x08048000 paddr 0x08048000 align 2**12
         filesz 0x00000ac4 memsz 0x00000ac4 flags r-x
    LOAD off    0x00000f14 vaddr 0x08049f14 paddr 0x08049f14 align 2**12
         filesz 0x00000108 memsz 0x000010cc flags rw-
 DYNAMIC off    0x00000f28 vaddr 0x08049f28 paddr 0x08049f28 align 2**2
         filesz 0x000000c8 memsz 0x000000c8 flags rw-
    NOTE off    0x00000148 vaddr 0x08048148 paddr 0x08048148 align 2**2
         filesz 0x00000044 memsz 0x00000044 flags r--
   STACK off    0x00000000 vaddr 0x00000000 paddr 0x00000000 align 2**2
         filesz 0x00000000 memsz 0x00000000 flags rw-
   RELRO off    0x00000f14 vaddr 0x08049f14 paddr 0x08049f14 align 2**0
         filesz 0x000000ec memsz 0x000000ec flags r--

Dynamic Section:
  NEEDED               libc.so.6
  INIT                 0x080482f8
  FINI                 0x08048a5c
  GNU_HASH             0x0804818c
  STRTAB               0x0804821c
  SYMTAB               0x080481ac
  STRSZ                0x0000006e
  SYMENT               0x00000010
  DEBUG                0x00000000
  PLTGOT               0x08049ff4
  PLTRELSZ             0x00000028
  PLTREL               0x00000011
  JMPREL               0x080482d0
  REL                  0x080482c8
  RELSZ                0x00000008
  RELENT               0x00000008
  VERNEED              0x08048298
  VERNEEDNUM           0x00000001
  VERSYM               0x0804828a

Version References:
  required from libc.so.6:
    0x0d696914 0x00 03 GLIBC_2.4
    0x0d696910 0x00 02 GLIBC_2.0

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .interp       00000013  08048134  08048134  00000134  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
...
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 12 .text         000006cc  08048390  08048390  00000390  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
.
 14 .rodata       00000048  08048a78  08048a78  00000a78  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
...
 22 .data         00000008  0804a014  0804a014  00001014  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 23 .bss          00000fc0  0804a020  0804a020  0000101c  2**5
                  ALLOC
 24 .comment      00000054  00000000  00000000  0000101c  2**0
                  CONTENTS, READONLY
 25 .debug_aranges 00000020  00000000  00000000  00001070  2**0
                  CONTENTS, READONLY, DEBUGGING
 26 .debug_pubnames 0000005f  00000000  00000000  00001090  2**0
                  CONTENTS, READONLY, DEBUGGING
 27 .debug_info   000002a3  00000000  00000000  000010ef  2**0
                  CONTENTS, READONLY, DEBUGGING
 28 .debug_abbrev 000000cd  00000000  00000000  00001392  2**0
                  CONTENTS, READONLY, DEBUGGING
 29 .debug_line   00000119  00000000  00000000  0000145f  2**0
                  CONTENTS, READONLY, DEBUGGING
 30 .debug_frame  000000c4  00000000  00000000  00001578  2**2
                  CONTENTS, READONLY, DEBUGGING
 31 .debug_str    000000c6  00000000  00000000  0000163c  2**0
                  CONTENTS, READONLY, DEBUGGING
 32 .debug_loc    00000124  00000000  00000000  00001702  2**0
                  CONTENTS, READONLY, DEBUGGING
 33 .debug_pubtypes 00000012  00000000  00000000  00001826  2**0
                  CONTENTS, READONLY, DEBUGGING
SYMBOL TABLE:
08048134 l    d  .interp    00000000              .interp
.
080482f8 l    d  .init    00000000              .init
08048328 l    d  .plt    00000000              .plt
08048390 l    d  .text    00000000              .text
....
00000000       F *UND*    00000000              printf@@GLIBC_2.0
08048504 g     F .text    000000aa              caculate_jump
0804a01c g       *ABS*    00000000              __bss_start
00000000       F *UND*    00000000              __stack_chk_fail@@GLIBC_2.4
0804afe0 g       *ABS*    00000000              _end
080485ae g     F .text    0000011a              caculate_jump_enhance
0804a01c g       *ABS*    00000000              _edata
08048444 g     F .text    000000c0              naive_match
08048a25 g     F .text    00000000              .hidden __i686.get_pc_thunk.bx
08048799 g     F .text    00000225              main
080482f8 g     F .init    00000000              _init






readelf  --sections  a.out
There are 38 section headers, starting at offset 0x19a0:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .interp           PROGBITS        08048134 000134 000013 00   A  0   0  1
..
  [13] .text             PROGBITS        08048390 000390 0006cc 00  AX  0   0 16
  [14] .fini             PROGBITS        08048a5c 000a5c 00001c 00  AX  0   0  4
  [15] .rodata           PROGBITS        08048a78 000a78 000048 00   A  0   0  4
...
  [23] .data             PROGBITS        0804a014 001014 000008 00  WA  0   0  4
  [24] .bss              NOBITS          0804a020 00101c 000fc0 00  WA  0   0 32
  [25] .comment          PROGBITS        00000000 00101c 000054 01  MS  0   0  1
  [26] .debug_aranges    PROGBITS        00000000 001070 000020 00      0   0  1
  [27] .debug_pubnames   PROGBITS        00000000 001090 00005f 00      0   0  1
  [28] .debug_info       PROGBITS        00000000 0010ef 0002a3 00      0   0  1
  [29] .debug_abbrev     PROGBITS        00000000 001392 0000cd 00      0   0  1
  [30] .debug_line       PROGBITS        00000000 00145f 000119 00      0   0  1
  [31] .debug_frame      PROGBITS        00000000 001578 0000c4 00      0   0  4
  [32] .debug_str        PROGBITS        00000000 00163c 0000c6 01  MS  0   0  1
  [33] .debug_loc        PROGBITS        00000000 001702 000124 00      0   0  1
  [34] .debug_pubtypes   PROGBITS        00000000 001826 000012 00      0   0  1
  [35] .shstrtab         STRTAB          00000000 001838 000166 00      0   0  1
  [36] .symtab           SYMTAB          00000000 001f90 000500 10     37  54  4
  [37] .strtab           STRTAB          00000000 002490 000260 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings)
  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)






readelf -wl a.out
Raw dump of debug contents of section .debug_line:

  Offset:                      0x0
  Length:                      277
  DWARF Version:               2
  Prologue Length:             29
  Minimum Instruction Length:  1
  Initial value of 'is_stmt':  1
  Line Base:                   -5
  Line Range:                  14
  Opcode Base:                 13

 Opcodes:
  Opcode 1 has 0 args
  Opcode 2 has 1 args
  Opcode 3 has 1 args
  Opcode 4 has 1 args
  Opcode 5 has 1 args
  Opcode 6 has 0 args
  Opcode 7 has 0 args
  Opcode 8 has 0 args
  Opcode 9 has 1 args
  Opcode 10 has 0 args
  Opcode 11 has 0 args
  Opcode 12 has 1 args

 The Directory Table is empty.

 The File Name Table:
  Entry    Dir    Time    Size    Name
  1    0    0    0    main.c

 Line Number Statements:
  Extended opcode 2: set Address to 0x8048444
  Advance Line by 12 to 13
  Copy
  Special opcode 90: advance Address by 6 to 0x804844a and Line by 1 to 14
  Special opcode 202: advance Address by 14 to 0x8048458 and Line by 1 to 15
  Special opcode 174: advance Address by 12 to 0x8048464 and Line by 1 to 16
  Special opcode 90: advance Address by 6 to 0x804846a and Line by 1 to 17
  Special opcode 132: advance Address by 9 to 0x8048473 and Line by 1 to 18
  Advance PC by constant 17 to 0x8048484
  Special opcode 76: advance Address by 5 to 0x8048489 and Line by 1 to 19
  .........
  Advance PC by 26 to 0x80489be
  Extended opcode 1: End of Sequence





readelf --debug-dump a.out
Contents of the .debug_aranges section:

  Length:                   28
  Version:                  2
  Offset into .debug_info:  0x0
  Pointer Size:             4
  Segment Size:             0

    Address    Length
    08048444 0000057a
    00000000 00000000

Contents of the .debug_pubnames section:

  Length:                              91
  Version:                             2
  Offset into .debug_info section:     0x0
  Size of area in .debug_info section: 675

    Offset    Name
    86        naive_match
    103       caculate_jump
    14d       caculate_jump_enhance
    197       kmp
    1fd       main

Contents of the .debug_info section:

  Compilation Unit @ offset 0x0:
   Length:        0x29f (32-bit)
   Version:       2
   Abbrev Offset: 0
   Pointer Size:  4
 <0><b>: Abbrev Number: 1 (DW_TAG_compile_unit)
    < c>   DW_AT_producer    : (indirect string, offset: 0x34): GNU C 4.5.2    
    <10>   DW_AT_language    : 1    (ANSI C)
    <11>   DW_AT_name        : (indirect string, offset: 0x76): main.c    
    <15>   DW_AT_comp_dir    : (indirect string, offset: 0xae): /home/widebright/桌面    
    <19>   DW_AT_low_pc      : 0x8048444    
。。。。。。
    <298>   DW_AT_type        : <0x282>    
    <29c>   DW_AT_location    : 5 byte block: 3 40 a0 4 8     (DW_OP_addr: 804a040)

Contents of the .debug_abbrev section:

  Number TAG
   1      DW_TAG_compile_unit    [has children]
    DW_AT_producer     DW_FORM_strp
    DW_AT_language     DW_FORM_data1
...


Raw dump of debug contents of section .debug_line:

  Offset:                      0x0
  Length:                      277
  DWARF Version:               2
  Prologue Length:             29
  Minimum Instruction Length:  1
  Initial value of 'is_stmt':  1
  Line Base:                   -5
  Line Range:                  14
  Opcode Base:                 13

 Opcodes:
  Opcode 1 has 0 args
  Opcode 2 has 1 args
  Opcode 3 has 1 args
  Opcode 4 has 1 args
  Opcode 5 has 1 args
  Opcode 6 has 0 args
  Opcode 7 has 0 args
  Opcode 8 has 0 args
  Opcode 9 has 1 args
  Opcode 10 has 0 args
  Opcode 11 has 0 args
  Opcode 12 has 1 args

 The Directory Table is empty.

 The File Name Table:
  Entry    Dir    Time    Size    Name
  1    0    0    0    main.c

 Line Number Statements:
  Extended opcode 2: set Address to 0x8048444
  Advance Line by 12 to 13
  Copy
  Special opcode 90: advance Address by 6 to 0x804844a and Line by 1 to 14
...
  Special opcode 76: advance Address by 5 to 0x80489a4 and Line by 1 to 142
  Advance PC by 26 to 0x80489be
  Extended opcode 1: End of Sequence


Contents of the .debug_frame section:

00000000 00000010 ffffffff CIE
  Version:               1
  Augmentation:          ""
  Code alignment factor: 1
  Data alignment factor: -4
  Return address column: 8

  DW_CFA_def_cfa: r4 (esp) ofs 4
  DW_CFA_offset: r8 (eip) at cfa-4
  DW_CFA_nop
  DW_CFA_nop
.....

Contents of the .debug_str section:

  0x00000000 63616375 6c617465 5f6a756d 7000756e caculate_jump.un
  0x00000010 7369676e 65642063 68617200 73686f72 signed char.shor
  0x00000020 7420756e 7369676e 65642069 6e74006d t unsigned int.m
  0x00000030 61696e00 474e5520 4320342e 352e3200 ain.GNU C 4.5.2.
  0x00000040 6c6f6e67 206c6f6e 6720756e 7369676e long long unsign
  0x00000050 65642069 6e740061 72676300 6e616976 ed int.argc.naiv
  0x00000060 655f6d61 74636800 6c6f6e67 206c6f6e e_match.long lon
  0x00000070 6720696e 74006d61 696e2e63 0073686f g int.main.c.sho
  0x00000080 72742069 6e740061 72677600 6c6f6e67 rt int.argv.long
  0x00000090 20646f75 626c6500 63616375 6c617465  double.caculate
  0x000000a0 5f6a756d 705f656e 68616e63 65002f68 _jump_enhance./h
  0x000000b0 6f6d652f 77696465 62726967 68742fe6 ome/widebright/.
  0x000000c0 a18ce99d a200                       ......

Contents of the .debug_loc section:

    Offset   Begin    End      Expression
    00000000 08048444 08048445 (DW_OP_breg4 (esp): 4)
    00000000 08048445 08048447 (DW_OP_breg4 (esp): 8)
    00000000 08048447 08048503 (DW_OP_breg5 (ebp): 8)
    00000000 08048503 08048504 (DW_OP_breg4 (esp): 4)
    00000000 <End of list>
.......
    000000e0 <End of list>

Contents of the .debug_pubtypes section:

  Length:                              14
  Version:                             2
  Offset into .debug_info section:     0x0
  Size of area in .debug_info section: 675

    Offset    Name









使用strip -d 命令可以删掉调试段,这些段在发布的时候是不需要的,就是占用很大空间。
strip -d a.out


readelf --sections  a.out
There are 29 section headers, starting at offset 0x1160:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .interp           PROGBITS        08048134 000134 000013 00   A  0   0  1
  [ 2] .note.ABI-tag     NOTE            08048148 000148 000020 00   A  0   0  4
  [ 3] .note.gnu.build-i NOTE            08048168 000168 000024 00   A  0   0  4
  [ 4] .gnu.hash         GNU_HASH        0804818c 00018c 000020 04   A  5   0  4
  [ 5] .dynsym           DYNSYM          080481ac 0001ac 000070 10   A  6   1  4
  [ 6] .dynstr           STRTAB          0804821c 00021c 00006e 00   A  0   0  1
  [ 7] .gnu.version      VERSYM          0804828a 00028a 00000e 02   A  5   0  2
  [ 8] .gnu.version_r    VERNEED         08048298 000298 000030 00   A  6   1  4
  [ 9] .rel.dyn          REL             080482c8 0002c8 000008 08   A  5   0  4
  [10] .rel.plt          REL             080482d0 0002d0 000028 08   A  5  12  4
  [11] .init             PROGBITS        080482f8 0002f8 000030 00  AX  0   0  4
  [12] .plt              PROGBITS        08048328 000328 000060 04  AX  0   0  4
  [13] .text             PROGBITS        08048390 000390 0006cc 00  AX  0   0 16
  [14] .fini             PROGBITS        08048a5c 000a5c 00001c 00  AX  0   0  4
  [15] .rodata           PROGBITS        08048a78 000a78 000048 00   A  0   0  4
  [16] .eh_frame         PROGBITS        08048ac0 000ac0 000004 00   A  0   0  4
  [17] .ctors            PROGBITS        08049f14 000f14 000008 00  WA  0   0  4
  [18] .dtors            PROGBITS        08049f1c 000f1c 000008 00  WA  0   0  4
  [19] .jcr              PROGBITS        08049f24 000f24 000004 00  WA  0   0  4
  [20] .dynamic          DYNAMIC         08049f28 000f28 0000c8 08  WA  6   0  4
  [21] .got              PROGBITS        08049ff0 000ff0 000004 04  WA  0   0  4
  [22] .got.plt          PROGBITS        08049ff4 000ff4 000020 04  WA  0   0  4
  [23] .data             PROGBITS        0804a014 001014 000008 00  WA  0   0  4
  [24] .bss              NOBITS          0804a020 00101c 000fc0 00  WA  0   0 32
  [25] .comment          PROGBITS        00000000 00101c 000054 01  MS  0   0  1
  [26] .shstrtab         STRTAB          00000000 001070 0000ee 00      0   0  1
  [27] .symtab           SYMTAB          00000000 0015e8 000440 10     28  42  4
  [28] .strtab           STRTAB          00000000 001a28 00024e 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings)
  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)





strip -d  a.out 把这几个调试段删掉,addr2line 也拿不到源码行数的信息了

addr2line  -a 0x8048464  a.out
0x08048464
??:0
0x0000000a
??:0


没有strip 之前是这样的
gcc -g main.c
$ addr2line  -a 0x8048464  a.out
0x08048464
/home/widebright/桌面/main.c:16
0x0000000a
??:0
  评论这张
 
阅读(2503)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017