使用readelf 和dwarfdump获取指令的文件名和行号

  • 比如进程中指令地址为0x0000aaaad96c0828编译时必须带-g,而且没有strip
[root@user mnt]# touch /tmp/memleak_print
[root@user mnt]# stack_id=0xcc3 with outstanding allocations: total_size=16 nr_allocs=4
0000aaaad96c0828: alloc_v3 @ 0x814+0x14
0000aaaad96c084c: alloc_v2 @ 0x838+0x14
0000aaaad96c0870: alloc_v1 @ 0x85c+0x14
0000aaaad96c08ac: main @ 0x880+0x2c
0000ffffb5ba73fc: <no-symbol>
0000ffffb5ba74cc: __libc_start_main @ 0x27434+0x98
0000aaaad96c0730: _start @ 0x700+0x30
  • 获取elf文件中的指令地址
/// 116代表进程号
[root@user mnt]# cat /proc/116/maps
起始地址     结束地址     属性 偏移地址 主从设备号 inode编号             文件名
aaaad96c0000-aaaad96c1000 r-xp 00000000 00:19 689872                     /mnt/test_memleak
aaaad96d0000-aaaad96d1000 r--p 00000000 00:19 689872                     /mnt/test_memleak
aaaad96d1000-aaaad96d2000 rw-p 00001000 00:19 689872                     /mnt/test_memleak
aaaae8803000-aaaae8824000 rw-p 00000000 00:00 0                          [heap]
ffffb5b80000-ffffb5d09000 r-xp 00000000 fe:00 136                        /lib/libc.so.6
ffffb5d09000-ffffb5d18000 ---p 00189000 fe:00 136                        /lib/libc.so.6
ffffb5d18000-ffffb5d1c000 r--p 00188000 fe:00 136                        /lib/libc.so.6
ffffb5d1c000-ffffb5d1e000 rw-p 0018c000 fe:00 136                        /lib/libc.so.6
ffffb5d1e000-ffffb5d2a000 rw-p 00000000 00:00 0 
ffffb5d36000-ffffb5d60000 r-xp 00000000 fe:00 120                        /lib/ld-linux-aarch64.so.1
ffffb5d6a000-ffffb5d6c000 rw-p 00000000 00:00 0 
ffffb5d6c000-ffffb5d6e000 r--p 00000000 00:00 0                          [vvar]
ffffb5d6e000-ffffb5d6f000 r-xp 00000000 00:00 0                          [vdso]
ffffb5d6f000-ffffb5d71000 r--p 00029000 fe:00 120                        /lib/ld-linux-aarch64.so.1
ffffb5d71000-ffffb5d73000 rw-p 0002b000 fe:00 120                        /lib/ld-linux-aarch64.so.1
ffffea6ca000-ffffea6eb000 rw-p 00000000 00:00 0                          [stack]
fffffffff000-1000000000000 --xp 00000000 00:00 0                         [uprobes]

找到属性里面有x可执行的这一条
aaaad96c0000-aaaad96c1000 r-xp 00000000 00:19 689872                     /mnt/test_memleak

起始地址 = aaaad96c0000
结束地址 = aaaad96c1000
偏移地址 = 00000000

elf文件中的指令地址 = 进程中的指令地址 - 起始地址 + 偏移地址
                    = 0000aaaad96c0828 - aaaad96c0000 + 00000000
                    = 0x828
  • 获取函数名
readelf -s test_memleak | grep FUNC
     3: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND _[...]@GLIBC_2.34 (2)
     5: 0000000000000000     0 FUNC    WEAK   DEFAULT  UND _[...]@GLIBC_2.17 (3)
     6: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND malloc@GLIBC_2.17 (3)
     7: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND sleep@GLIBC_2.17 (3)
     9: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND abort@GLIBC_2.17 (3)
    10: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND free@GLIBC_2.17 (3)
    39: 0000000000000734    20 FUNC    LOCAL  DEFAULT   13 call_weak_fn
    47: 0000000000000750     0 FUNC    LOCAL  DEFAULT   13 deregister_tm_clones
    48: 0000000000000780     0 FUNC    LOCAL  DEFAULT   13 register_tm_clones
    50: 00000000000007c0     0 FUNC    LOCAL  DEFAULT   13 __do_global_dtors_aux
    54: 0000000000000810     0 FUNC    LOCAL  DEFAULT   13 frame_dummy
    61: 0000000000000814    36 FUNC    LOCAL  DEFAULT   13 alloc_v3
    62: 0000000000000838    36 FUNC    LOCAL  DEFAULT   13 alloc_v2
    63: 000000000000085c    36 FUNC    LOCAL  DEFAULT   13 alloc_v1
    73: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_mai[...]
    77: 0000000000000000     0 FUNC    WEAK   DEFAULT  UND __cxa_finalize@G[...]
    80: 00000000000008e0     0 FUNC    GLOBAL HIDDEN    14 _fini
    82: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND malloc@GLIBC_2.17
    83: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND sleep@GLIBC_2.17
    87: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND abort@GLIBC_2.17
    90: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND free@GLIBC_2.17
    91: 0000000000000700    52 FUNC    GLOBAL DEFAULT   13 _start
    94: 0000000000000880    96 FUNC    GLOBAL DEFAULT   13 main
    97: 0000000000000628     0 FUNC    GLOBAL HIDDEN    11 _init


0x828 执行到了 alloc_v3 的函数内部
    61: 0000000000000814    36 FUNC    LOCAL  DEFAULT   13 alloc_v3
    62: 0000000000000838    36 FUNC    LOCAL  DEFAULT   13 alloc_v2
  • 获取文件名
llvm-dwarfdump -i test_memleak | grep DW_TAG_subprogram -A11
0x00000098:   DW_TAG_subprogram
                DW_AT_external  (true)
                DW_AT_name  ("free")
                DW_AT_decl_file ("/usr/aarch64-linux-gnu/include/stdlib.h")
                DW_AT_decl_line (555)
                DW_AT_decl_column   (0x0d)
                DW_AT_prototyped    (true)
                DW_AT_declaration   (true)
                DW_AT_sibling   (0x000000ab)

0x000000a5:     DW_TAG_formal_parameter
                  DW_AT_type    (0x00000041 "void *")
--
0x000000ab:   DW_TAG_subprogram
                DW_AT_external  (true)
                DW_AT_name  ("sleep")
                DW_AT_decl_file ("/usr/aarch64-linux-gnu/include/unistd.h")
                DW_AT_decl_line (464)
                DW_AT_decl_column   (0x15)
                DW_AT_prototyped    (true)
                DW_AT_type  (0x0000005d "unsigned int")
                DW_AT_declaration   (true)
                DW_AT_sibling   (0x000000c2)

0x000000bc:     DW_TAG_formal_parameter
--
0x000000c2:   DW_TAG_subprogram
                DW_AT_external  (true)
                DW_AT_name  ("malloc")
                DW_AT_decl_file ("/usr/aarch64-linux-gnu/include/stdlib.h")
                DW_AT_decl_line (540)
                DW_AT_decl_column   (0x0e)
                DW_AT_prototyped    (true)
                DW_AT_type  (0x00000041 "void *")
                DW_AT_declaration   (true)
                DW_AT_sibling   (0x000000d9)

0x000000d3:     DW_TAG_formal_parameter
--
0x000000d9:   DW_TAG_subprogram
                DW_AT_external  (true)
                DW_AT_name  ("main")
                DW_AT_decl_file ("/home/anlan/Desktop/perf/arm32/libbpf-bootstrap/examples/c/test_memleak.c")
                DW_AT_decl_line (47)
                DW_AT_decl_column   (0x05)
                DW_AT_prototyped    (true)
                DW_AT_type  (0x00000043 "int")
                DW_AT_low_pc    (0x0000000000000880)
                DW_AT_high_pc   (0x00000000000008e0)
                DW_AT_frame_base    (DW_OP_call_frame_cfa)
                DW_AT_call_all_tail_calls   (true)
--
0x00000141:   DW_TAG_subprogram
                DW_AT_name  ("alloc_v1")
                DW_AT_decl_file ("/home/anlan/Desktop/perf/arm32/libbpf-bootstrap/examples/c/test_memleak.c")
                DW_AT_decl_line (40)
                DW_AT_decl_column   (15)
                DW_AT_prototyped    (true)
                DW_AT_type  (0x00000041 "void *")
                DW_AT_low_pc    (0x000000000000085c)
                DW_AT_high_pc   (0x0000000000000880)
                DW_AT_frame_base    (DW_OP_call_frame_cfa)
                DW_AT_call_all_tail_calls   (true)
                DW_AT_sibling   (0x0000017e)
--
0x0000017e:   DW_TAG_subprogram
                DW_AT_name  ("alloc_v2")
                DW_AT_decl_file ("/home/anlan/Desktop/perf/arm32/libbpf-bootstrap/examples/c/test_memleak.c")
                DW_AT_decl_line (33)
                DW_AT_decl_column   (15)
                DW_AT_prototyped    (true)
                DW_AT_type  (0x00000041 "void *")
                DW_AT_low_pc    (0x0000000000000838)
                DW_AT_high_pc   (0x000000000000085c)
                DW_AT_frame_base    (DW_OP_call_frame_cfa)
                DW_AT_call_all_tail_calls   (true)
                DW_AT_sibling   (0x000001bb)
--
0x000001bb:   DW_TAG_subprogram
                DW_AT_name  ("alloc_v3")
                DW_AT_decl_file ("/home/anlan/Desktop/perf/arm32/libbpf-bootstrap/examples/c/test_memleak.c")
                DW_AT_decl_line (7)
                DW_AT_decl_column   (0x0f)
                DW_AT_prototyped    (true)
                DW_AT_type  (0x00000041 "void *")
                DW_AT_low_pc    (0x0000000000000814)
                DW_AT_high_pc   (0x0000000000000838)
                DW_AT_frame_base    (DW_OP_call_frame_cfa)
                DW_AT_call_all_tail_calls   (true)


alloc_v3 指令地址范围 DW_AT_low_pc ~ DW_AT_high_pc
0x828 属于 alloc_v3 内部的指令地址
0000aaaad96c0828 执行到了 alloc_v3 的函数内部 文件名是 test_memleak.c
  • 获取行号
dwarfdump -l test_memleak

.debug_line: line number info for a single cu
Source lines (from CU-DIE at .debug_info offset 0x0000000c):

            NS new statement, BB new basic block, ET end of text sequence
            PE prologue end, EB epilogue begin
            IS=val ISA number, DI=val discriminator value
<pc>        [lno,col] NS BB ET PE EB IS= DI= uri: "filepath"
0x00000814  [   8, 1] NS uri: "/home/anlan/Desktop/perf/arm32/libbpf-bootstrap/examples/c/test_memleak.c"
0x00000820  [   9,18] NS
0x0000082c  [  11,12] NS
0x00000830  [  12, 1] NS
0x00000838  [  34, 1] NS
0x00000844  [  35,18] NS
0x00000850  [  37,12] NS
0x00000854  [  38, 1] NS
0x0000085c  [  41, 1] NS
0x00000868  [  42,18] NS
0x00000874  [  44,12] NS
0x00000878  [  45, 1] NS
0x00000880  [  48, 1] NS
0x00000890  [  49,15] NS
0x00000898  [  50,12] NS
0x0000089c  [  51, 9] NS
0x000008a0  [  53,12] NS
0x000008a4  [  55,15] NS
0x000008b0  [  57, 9] NS
0x000008b8  [  59,15] NS
0x000008c0  [  59,12] NS
0x000008c8  [  61,13] NS
0x000008d0  [  53,20] NS
0x000008dc  [  55,13] NS
0x000008e0  [  55,13] NS ET

0x828 在 0x00000820 与 0x0000082c 之间,所以行号为 9
  • 使用addr2line
addr2line -e test_memleak 0x828
/home/anlan/Desktop/perf/arm32/libbpf-bootstrap/examples/c/test_memleak.c:9
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。