Skip to main content

readelf

··2556 字·
debug tools linux elf debug tools
Table of Contents
elf-debug - 这篇文章属于一个系列。
§ 3: 本文

介绍 readelf 命令的功能用法。

readelf 和 objdump 相比:

  1. objdump 可以对二进制文件根据调试符号表进行反汇编,但是 readelf 不行;
  2. 两者都会使用 build-id 和 gnu debuglink 机制从 /usr/lib/debug 查找当前二进制的 debuginfo 文件,然后显示其内容;

通用选项:

  1. -W/--wide :可以使输出宽度超过 80 字符。

1 显示 ELF header
#

readelf -h/--file-headers: 显示 ELF file header

root@lima-ebpf-dev:~# readelf -h hello
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              DYN (Position-Independent Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x1060
  Start of program headers:          64 (bytes into file)
  Start of section headers:          14720 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         13
  Size of section headers:           64 (bytes)
  Number of section headers:         37
  Section header string table index: 36

2 显示 program headers 列表(Segments):
#

readelf -l/–program-headers/–segments: 显示 program headers 的内容(也称为 Segments):

  • PHDR:
  • INTERP:/lib64/ld-linux-x86-64.so.2
  • LOAD
  • DYNAMIC;
  • NOTE
  • GNU_PROPERTY
  • GNU_EH_FRAME: 在 C++ exception resolution 场景使用。
  • GNU_STACK
  • GNU_RELRO
root@lima-ebpf-dev:~# readelf -l -W hello # -W/--wide 表示输出宽度可以超过 80 字符。

Elf file type is DYN (Position-Independent Executable file)
Entry point 0x1060
There are 13 program headers, starting at offset 64

Program Headers:
  Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
  PHDR           0x000040 0x0000000000000040 0x0000000000000040 0x0002d8 0x0002d8 R   0x8
  INTERP         0x000318 0x0000000000000318 0x0000000000000318 0x00001c 0x00001c R   0x1
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  LOAD           0x000000 0x0000000000000000 0x0000000000000000 0x000628 0x000628 R   0x1000
  LOAD           0x001000 0x0000000000001000 0x0000000000001000 0x000185 0x000185 R E 0x1000
  LOAD           0x002000 0x0000000000002000 0x0000000000002000 0x000114 0x000114 R   0x1000
  LOAD           0x002db8 0x0000000000003db8 0x0000000000003db8 0x000258 0x000260 RW  0x1000
  DYNAMIC        0x002dc8 0x0000000000003dc8 0x0000000000003dc8 0x0001f0 0x0001f0 RW  0x8
  NOTE           0x000338 0x0000000000000338 0x0000000000000338 0x000030 0x000030 R   0x8
  NOTE           0x000368 0x0000000000000368 0x0000000000000368 0x000044 0x000044 R   0x4
  GNU_PROPERTY   0x000338 0x0000000000000338 0x0000000000000338 0x000030 0x000030 R   0x8
  GNU_EH_FRAME   0x00200c 0x000000000000200c 0x000000000000200c 0x00003c 0x00003c R   0x4
  GNU_STACK      0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW  0x10
  GNU_RELRO      0x002db8 0x0000000000003db8 0x0000000000003db8 0x000248 0x000248 R   0x1

 Section to Segment mapping:
  Segment Sections...
   00
   01     .interp
   02     .interp .note.gnu.property .note.gnu.build-id .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt
   03     .init .plt .plt.got .plt.sec .text .fini
   04     .rodata .eh_frame_hdr .eh_frame
   05     .init_array .fini_array .dynamic .got .data .bss
   06     .dynamic
   07     .note.gnu.property
   08     .note.gnu.build-id .note.ABI-tag
   09     .note.gnu.property
   10     .eh_frame_hdr
   11
   12     .init_array .fini_array .dynamic .got
root@lima-ebpf-dev:~#

3 显示所有 Sections
#

readelf -S/--sections/--section-headers :显示所有 section headers 列表;

  • 带有 S 标识的表示是字符串 Sections,如 .comment;
  • 使用 -W 来显示超过 80 字符的宽度;
  • 只显示当前文件,而不查找 debuginfo 文件;
root@lima-ebpf-dev:~# readelf -S -W hello
There are 37 section headers, starting at offset 0x3980:

Section Headers:
  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0
  [ 1] .interp           PROGBITS        0000000000000318 000318 00001c 00   A  0   0  1
  [ 2] .note.gnu.property NOTE            0000000000000338 000338 000030 00   A  0   0  8
  [ 3] .note.gnu.build-id NOTE            0000000000000368 000368 000024 00   A  0   0  4
  [ 4] .note.ABI-tag     NOTE            000000000000038c 00038c 000020 00   A  0   0  4
  [ 5] .gnu.hash         GNU_HASH        00000000000003b0 0003b0 000024 00   A  6   0  8
  [ 6] .dynsym           DYNSYM          00000000000003d8 0003d8 0000a8 18   A  7   1  8
  [ 7] .dynstr           STRTAB          0000000000000480 000480 00008d 00   A  0   0  1
  [ 8] .gnu.version      VERSYM          000000000000050e 00050e 00000e 02   A  6   0  2
  [ 9] .gnu.version_r    VERNEED         0000000000000520 000520 000030 00   A  7   1  8
  [10] .rela.dyn         RELA            0000000000000550 000550 0000c0 18   A  6   0  8
  [11] .rela.plt         RELA            0000000000000610 000610 000018 18  AI  6  24  8
  [12] .init             PROGBITS        0000000000001000 001000 00001b 00  AX  0   0  4
  [13] .plt              PROGBITS        0000000000001020 001020 000020 10  AX  0   0 16
  [14] .plt.got          PROGBITS        0000000000001040 001040 000010 10  AX  0   0 16
  [15] .plt.sec          PROGBITS        0000000000001050 001050 000010 10  AX  0   0 16
  [16] .text             PROGBITS        0000000000001060 001060 000117 00  AX  0   0 16
  [17] .fini             PROGBITS        0000000000001178 001178 00000d 00  AX  0   0  4
  [18] .rodata           PROGBITS        0000000000002000 002000 00000b 00   A  0   0  4
  [19] .eh_frame_hdr     PROGBITS        000000000000200c 00200c 00003c 00   A  0   0  4
  [20] .eh_frame         PROGBITS        0000000000002048 002048 0000cc 00   A  0   0  8
  [21] .init_array       INIT_ARRAY      0000000000003db8 002db8 000008 08  WA  0   0  8
  [22] .fini_array       FINI_ARRAY      0000000000003dc0 002dc0 000008 08  WA  0   0  8
  [23] .dynamic          DYNAMIC         0000000000003dc8 002dc8 0001f0 10  WA  7   0  8
  [24] .got              PROGBITS        0000000000003fb8 002fb8 000048 08  WA  0   0  8
  [25] .data             PROGBITS        0000000000004000 003000 000010 00  WA  0   0  8
  [26] .bss              NOBITS          0000000000004010 003010 000008 00  WA  0   0  1
  [27] .comment          PROGBITS        0000000000000000 003010 00002d 01  MS  0   0  1
  [28] .debug_aranges    PROGBITS        0000000000000000 00303d 000030 00      0   0  1
  [29] .debug_info       PROGBITS        0000000000000000 00306d 0000a6 00      0   0  1
  [30] .debug_abbrev     PROGBITS        0000000000000000 003113 00005e 00      0   0  1
  [31] .debug_line       PROGBITS        0000000000000000 003171 00005b 00      0   0  1
  [32] .debug_str        PROGBITS        0000000000000000 0031cc 0000df 01  MS  0   0  1
  [33] .debug_line_str   PROGBITS        0000000000000000 0032ab 00000d 01  MS  0   0  1
  [34] .symtab           SYMTAB          0000000000000000 0032b8 000378 18     35  18  8
  [35] .strtab           STRTAB          0000000000000000 003630 0001e0 00      0   0  1
  [36] .shstrtab         STRTAB          0000000000000000 003810 00016a 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  D (mbind), l (large), p (processor specific)
root@lima-ebpf-dev:~#
  • .text section 里装载了可执行代码;
  • .data section 里面装载了被初始化的数据;
  • .bss section 里面装载了未被初始化的数据;
  • 以 .rec 打头的 sections 里面装载了重定位条目;
  • .symtab 或者 .dynsym section 里面装载了符号信息;
  • .strtab 或者 .dynstr section 里面装载了字符串信息;

readelf -e/–headers:等效为 -h -l -S,即同时显示 ELF/Program/Section headers 的内容。

4 显示符号表(.dynsym & .symtab)
#

readelf -s/–syms/–symbols: 显示符号表(symbol table):’.dynsym’ 和 ‘.symtab’:

  • 只显示当前文件,而不查找 debuginfo 文件;
root@lima-ebpf-dev:~# readelf -s hello

Symbol table '.dynsym' contains 7 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND _[...]@GLIBC_2.34 (2)
     2: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_deregisterT[...]
     3: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND puts@GLIBC_2.2.5 (3)
     4: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
     5: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_registerTMC[...]
     6: 0000000000000000     0 FUNC    WEAK   DEFAULT  UND [...]@GLIBC_2.2.5 (3)

Symbol table '.symtab' contains 37 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS Scrt1.o
     2: 000000000000038c    32 OBJECT  LOCAL  DEFAULT    4 __abi_tag
     3: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
     4: 0000000000001090     0 FUNC    LOCAL  DEFAULT   16 deregister_tm_clones
     5: 00000000000010c0     0 FUNC    LOCAL  DEFAULT   16 register_tm_clones
     6: 0000000000001100     0 FUNC    LOCAL  DEFAULT   16 __do_global_dtors_aux
     7: 0000000000004010     1 OBJECT  LOCAL  DEFAULT   26 completed.0
     8: 0000000000003dc0     0 OBJECT  LOCAL  DEFAULT   22 __do_global_dtor[...]
     9: 0000000000001140     0 FUNC    LOCAL  DEFAULT   16 frame_dummy
    10: 0000000000003db8     0 OBJECT  LOCAL  DEFAULT   21 __frame_dummy_in[...]
    11: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS test.c
    12: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
    13: 0000000000002110     0 OBJECT  LOCAL  DEFAULT   20 __FRAME_END__
    14: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS
    15: 0000000000003dc8     0 OBJECT  LOCAL  DEFAULT   23 _DYNAMIC
    16: 000000000000200c     0 NOTYPE  LOCAL  DEFAULT   19 __GNU_EH_FRAME_HDR
    17: 0000000000003fb8     0 OBJECT  LOCAL  DEFAULT   24 _GLOBAL_OFFSET_TABLE_
    18: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_mai[...]
    19: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_deregisterT[...]
    20: 0000000000004000     0 NOTYPE  WEAK   DEFAULT   25 data_start
    21: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND puts@GLIBC_2.2.5
    22: 0000000000004010     0 NOTYPE  GLOBAL DEFAULT   25 _edata
    23: 0000000000001178     0 FUNC    GLOBAL HIDDEN    17 _fini
    24: 0000000000001149    26 FUNC    GLOBAL DEFAULT   16 hello
    25: 0000000000004000     0 NOTYPE  GLOBAL DEFAULT   25 __data_start
    26: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
    27: 0000000000004008     0 OBJECT  GLOBAL HIDDEN    25 __dso_handle
    28: 0000000000002000     4 OBJECT  GLOBAL DEFAULT   18 _IO_stdin_used
    29: 0000000000004018     0 NOTYPE  GLOBAL DEFAULT   26 _end
    30: 0000000000001060    38 FUNC    GLOBAL DEFAULT   16 _start
    31: 0000000000004010     0 NOTYPE  GLOBAL DEFAULT   26 __bss_start
    32: 0000000000001163    20 FUNC    GLOBAL DEFAULT   16 main
    33: 0000000000004010     0 OBJECT  GLOBAL HIDDEN    25 __TMC_END__
    34: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_registerTMC[...]
    35: 0000000000000000     0 FUNC    WEAK   DEFAULT  UND __cxa_finalize@G[...]
    36: 0000000000001000     0 FUNC    GLOBAL HIDDEN    12 _init
root@lima-ebpf-dev:~#

5 显示 .note 开头的 sections
#

readelf -n: 显示 core notes Section,即以 .note 开头的 section,例如:

  • .note.gnu.property
  • .note.gnu.build-id:包含用于查找 debug file 的 build-id;
  • .note.ABI-tag
root@lima-ebpf-dev:~# readelf -n hello

Displaying notes found in: .note.gnu.property
  Owner                Data size        Description
  GNU                  0x00000020       NT_GNU_PROPERTY_TYPE_0
      Properties: x86 feature: IBT, SHSTK
        x86 ISA needed: x86-64-baseline

Displaying notes found in: .note.gnu.build-id
  Owner                Data size        Description
  GNU                  0x00000014       NT_GNU_BUILD_ID (unique build ID bitstring)
    Build ID: 7e31292c839740f24092f371f1e85cd9ad74a79b

Displaying notes found in: .note.ABI-tag
  Owner                Data size        Description
  GNU                  0x00000010       NT_GNU_ABI_TAG (ABI version tag)
    OS: Linux, ABI: 3.2.0
root@lima-ebpf-dev:~#

6 显示重定位 sections
#

readefl -r/–relocs:显示重定位 section:

root@lima-ebpf-dev:~# readelf -r hello

Relocation section '.rela.dyn' at offset 0x550 contains 8 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000003db8  000000000008 R_X86_64_RELATIVE                    1140
000000003dc0  000000000008 R_X86_64_RELATIVE                    1100
000000004008  000000000008 R_X86_64_RELATIVE                    4008
000000003fd8  000100000006 R_X86_64_GLOB_DAT 0000000000000000 __libc_start_main@GLIBC_2.34 + 0
000000003fe0  000200000006 R_X86_64_GLOB_DAT 0000000000000000 _ITM_deregisterTM[...] + 0
000000003fe8  000400000006 R_X86_64_GLOB_DAT 0000000000000000 __gmon_start__ + 0
000000003ff0  000500000006 R_X86_64_GLOB_DAT 0000000000000000 _ITM_registerTMCl[...] + 0
000000003ff8  000600000006 R_X86_64_GLOB_DAT 0000000000000000 __cxa_finalize@GLIBC_2.2.5 + 0

Relocation section '.rela.plt' at offset 0x610 contains 1 entry:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000003fd0  000300000007 R_X86_64_JUMP_SLO 0000000000000000 puts@GLIBC_2.2.5 + 0
root@lima-ebpf-dev:~#

7 显示 gnu version
#

readelf -V/–version-info

  • .gnu.version
  • .gnu.version_r
root@lima-ebpf-dev:~# readelf -V hello

Version symbols section '.gnu.version' contains 7 entries:
 Addr: 0x000000000000050e  Offset: 0x00050e  Link: 6 (.dynsym)
  000:   0 (*local*)       2 (GLIBC_2.34)    1 (*global*)      3 (GLIBC_2.2.5)
  004:   1 (*global*)      1 (*global*)      3 (GLIBC_2.2.5)

Version needs section '.gnu.version_r' contains 1 entry:
 Addr: 0x0000000000000520  Offset: 0x000520  Link: 7 (.dynstr)
  000000: Version: 1  File: libc.so.6  Cnt: 2
  0x0010:   Name: GLIBC_2.2.5  Flags: none  Version: 3
  0x0020:   Name: GLIBC_2.34  Flags: none  Version: 2

8 打印指定 Sections 内容
#

  • readelf -x/--hex-dump=<number|name>: 使用 16 进制打印指定 Sections 的内容。
  • ~readelf -p/–string-dump=<number|name>~: 使用文本打印指定 Sections 的内容;
  • 可以使用 readelf -S 来显示所有 sections number 和 name,同时有 S 标志的表示是字符串 Section:
root@lima-ebpf-dev:~# readelf -S hello |grep comm
  [27] .comment          PROGBITS         0000000000000000  00003010
root@lima-ebpf-dev:~# readelf -p .comment hello

String dump of section '.comment':
  [     0]  GCC: (Ubuntu 11.3.0-1ubuntu1~22.04.1) 11.3.0

9 显示 DWARF 内容
#

readelf -w 打印二进制的 DWARF 内容,即各种以 .debug_XX 开头的 Section 内容:

  • .eh_frame: 在 C++ exception resolution 场景使用;
  • 会查找 debuginfo 文件来获得 DWARF 内容;
root@lima-ebpf-dev:~# readelf -w hello
Contents of the .eh_frame section:


00000000 0000000000000014 00000000 CIE
  Version:               1
  Augmentation:          "zR"
  Code alignment factor: 1
  Data alignment factor: -8
  Return address column: 16
  Augmentation data:     1b
  DW_CFA_def_cfa: r7 (rsp) ofs 8
  DW_CFA_offset: r16 (rip) at cfa-8
  DW_CFA_nop
  DW_CFA_nop

00000018 0000000000000014 0000001c FDE cie=00000000 pc=0000000000001060..0000000000001086
  DW_CFA_advance_loc: 4 to 0000000000001064
  DW_CFA_undefined: r16 (rip)
  DW_CFA_nop
  DW_CFA_nop
  DW_CFA_nop
  DW_CFA_nop
...
Contents of the .debug_line_str section:

  0x00000000 74657374 2e63002f 726f6f74 00       test.c./root.

root@lima-ebpf-dev:~#

readelf -wX 或则 readelf –debug-dump=YY 来打印对应 DWARF debug section 的内容。

  • X/=YY,例如 -wa 等效为 –debug-dump abbrev

  • -w –debug-dump[a/=abbrev, A/=addr, r/=aranges, c/=cu_index, L/=decodedline, f/=frames, F/=frames-interp, g/=gdb_index, i/=info, o/=loc, m/=macro, p/=pubnames, t/=pubtypes, R/=Ranges, l/=rawline, s/=str, O/=str-offsets, u/=trace_abbrev, T/=trace_aranges, U/=trace_info]

    Display the contents of DWARF debug sections

例子:

root@lima-ebpf-dev:~# readelf --debug-dump=abbrev hello |head -6
Contents of the .debug_abbrev section (loaded from hello):

  Number TAG (0x0)
   1      DW_TAG_base_type    [no children]
    DW_AT_byte_size    DW_FORM_data1
    DW_AT_encoding     DW_FORM_data1
root@lima-ebpf-dev:~# readelf -wa hello |head -6
Contents of the .debug_abbrev section (loaded from hello):

  Number TAG (0x0)
   1      DW_TAG_base_type    [no children]
    DW_AT_byte_size    DW_FORM_data1
    DW_AT_encoding     DW_FORM_data1
root@lima-ebpf-dev:~#

如果二进制被 strip,则本身不再包含调试符号表,这时 readelf 会根据 .gnu_debuglink Sections 中的 debug 文件名(需要单独添加该 Section),或根据 .note.gnu.build-id 在 /usr/lib/debug 下查找单独的 debug file。

elf-debug - 这篇文章属于一个系列。
§ 3: 本文

相关文章

objdump
··3921 字
debug tools linux elf debug tools

介绍 objdump 命令的功能用法。

Linux elf 符号表(symtab)
··1492 字
debug linux elf debug

介绍 Linux elf 二进制文件的符号表(symtab)生成和管理机制。

Linux elf 调试符号表(.debug_XX)
··4804 字
debug linux elf debug

介绍 Linux elf 二进制文件的调试符号表(.debug_XX)生成和管理机制。

add package meta to elf file
··1759 字
elf tools linux elf tools

介绍向 elf 二进制文件中添加自定义 package meta 信息的方法。