6

当我使用 -g 编译程序并获得核心转储时,我可以使用它gdb来读取可执行文件和核心转储来调试程序在崩溃之前遇到的情况。提供的功能之一gdblist选项,可以列出使用可执行文件和核心转储编译的源代码。我strings -a与可执行文件和核心转储一起使用,我什至找不到一个iffor声明,而我确信代码中有很多声明。那么代码是从哪里来的呢?我在一台计算机上编译代码并在另一台计算机上运行它,因此源代码在生成核心转储的计算机上不可用,并且它似乎不在可执行文件或核心转储中。有什么建议么?我真的想从可执行文件和核心转储中打印所有源代码,这可能吗?我的意思是不运行gdb,我确信可以编写一个使用 gdb 并且可以列出整个代码的脚本,但我有兴趣自己做,gdb因为我想了解源代码是从哪里获取的已格式化,我想尽可能多地了解它。

4

1 回答 1

6

行信息位于.debug_line可执行文件的 DWARF 部分中:

$readelf -wL ./a.out 
Decoded dump of debug contents of section .debug_line:

CU: bla.c:
File name                            Line number    Starting address
bla.c                                          2            0x4004b6
bla.c                                          3            0x4004ba
bla.c                                          4            0x4004bf

本节将指令指针地址映射到给定文件中的行号。

为了找到文件的内容,您需要能够找到相关的源文件。如果移动/重命名源文件,GDB 将无法打印源代码:

mv bla.c bla2.c
gdb ./a.out
(gdb) 中断主要
(gdb) 运行
(gdb) 列表
1 黑色.c

DWARF 部分包含有关源文件在编译时所在路径的.debug_info一些信息,可用于查找相关文件:

$objdump -Wi -wa ./a.out

./a.out:文件格式elf64-x86-64
./a.out

.debug_info 部分的内容:

  编译单元@偏移量 0x0:
   长度:0x4e(32 位)
   版本:4
   缩写偏移量:0x0
   指针大小:8
 : 缩写数字: 1 (DW_TAG_compile_unit)
       DW_AT_producer:(间接字符串,偏移量:0x0):GNU C 4.9.1 -mtune=generic -march=x86-64 -g
       DW_AT_language : 1 (ANSI C)
       DW_AT_name :(间接字符串,偏移量:0x59):bla.c
       DW_AT_comp_dir:(间接字符串,偏移量:0x31):/home/myself/temp/bla
       DW_AT_low_pc:0x4004b6
       DW_AT_high_pc:0xb
       DW_AT_stmt_list:0x0
 : 缩写编号: 2 (DW_TAG_subprogram)
       DW_AT_外部:1
       DW_AT_name :(间接字符串,偏移量:0x2c):main
       DW_AT_decl_file:1
       DW_AT_decl_line : 2
       DW_AT_type :
       DW_AT_low_pc:0x4004b6
       DW_AT_high_pc:0xb
       DW_AT_frame_base : 1 字节块: 9c (DW_OP_call_frame_cfa)
       DW_AT_GNU_all_call_sites:1
 : 缩写编号:3 (DW_TAG_base_type)
       DW_AT_byte_size : 4
       DW_AT_encoding:5(有符号)
       DW_AT_name : 整数
 : 缩写编号: 0

每个DW_TAG_compile_unit都有关于用于查找相关源文件的源文件名和路径的信息。

如果您想自己完成这一切,您可能应该阅读DWARF 规范的一些相关部分并使用诸如 libdw 之类的库(它是elfutils的一部分)。

于 2014-12-31T14:51:33.467 回答