有没有办法在Linux(特别是RHEL)中找到生成当前可执行文件的目标文件?我知道可以使用“nm”查找导出的符号,“ldd”查找相关共享对象。但我找不到命令来查找由哪些目标文件(.o)组成的可执行文件的名称。这是否可能?
对象文件的原始名称没有存储在DWARF调试信息中。
每个对象文件都有一个.debug_info
部分中的DW_TAG_compile_unit
条目。该条目包含一个引用,指向“导出编译单元的主要源文件”,但不包括对象文件的名称。 DWARF标准 包含可为每个编译单元存储的属性列表(第3.1.1节,页码44,pdf页58)。
您可以使用以下命令查看存储的信息:
$ readelf --debug-dump=info --dwarf-depth=1 hw
输出:
Contents of the .debug_info section:
<some compilation units removed>
Compilation Unit @ offset 0x133:
Length: 0x8b (32-bit)
Version: 4
Abbrev Offset: 0x64
Pointer Size: 4
<0><13e>: Abbrev Number: 1 (DW_TAG_compile_unit)
<13f> DW_AT_producer : (indirect string, offset: 0x131): GNU C11 5.3.0 -mtune=generic -march=pentiumpro -g
<143> DW_AT_language : 12 (ANSI C99)
<144> DW_AT_name : (indirect string, offset: 0x163): hw.c
<148> DW_AT_comp_dir : (indirect string, offset: 0x168): /home/mikel/src/hw
<14c> DW_AT_low_pc : 0x80483db
<150> DW_AT_high_pc : 0x2e
<154> DW_AT_stmt_list : 0xea
<1><158>: ...
<some compilation units removed>
您也可以使用objdump
(只要可执行文件和对象是使用调试信息编译的):
# gcc -g -c -o /tmp/some_object.o /tmp/some_object.c
# gcc -g -o /tmp/file /tmp/file.c /tmp/some_object.o
# objdump -g /tmp/file | awk 'BEGIN{out=0} /Directory Table/{out=1} /Line Number Statements/{out=0} {if(out){print $0}}'
The Directory Table (offset 0x1b):
1 /tmp
The File Name Table (offset 0x21):
Entry Dir Time Size Name
1 1 0 0 file.c
The Directory Table (offset 0x5a):
1 /tmp
The File Name Table (offset 0x60):
Entry Dir Time Size Name
1 1 0 0 some_object.c
awk
是用来提取相关信息的(如果不使用,将会在可执行文件和对象文件中获取完整的调试信息)。
我没有足够的声望来添加评论,但是为了扩展Mikel Rychliski的建议使用readelf,您可以使用awk提取源文件的路径:
readelf --debug-dump=info --dwarf-depth=1 hw exe_to_examine | awk '/DW_AT_name/ {file=$8} /DW_AT_comp_dir/ {print $8 "/" file}'
ldd
)获取它。然而,如果链接是静态的,那么唯一的方法就是通过调试信息。你可以在RHEL(或Fedora)安装debuginfo包。以下是说明。
然后按照这里描述的方法使用gdb info sources
:
这将给您一个源文件列表。但要实际获取目标文件,您需要深入了解构建工具(rpmbuild
)。要实际运行rpmbuild,您需要获取源RPM包,可以使用此处列出的说明进行获取:
.o
文件导致了可执行文件的生成。类似Mikels答案,但是使用另一种工具,可能会给你更干净的输出。
过去我曾经有幸参与开发一个名为DIVA的调试信息分析器工具。它是免费且开源的,你可以在这里找到它:
https://github.com/SNSystems/DIVA
虽然使用DIVA无法找到链接到生成可执行文件的对象文件,但可以使用它来查找编译单元。
我快速地组合了一个小例子如下:
a.cpp
int a() {
return 1;
}
a.h
int a();
b.cpp
int b() {
return 2;
}
b.h
int b();
c.cpp
#include "a.h"
#include "b.h"
int main() {
return a + b;
}
使用以下选项使用clang编译它们
$ clang a.cpp b.cpp c.cpp -o test.elf -g -O0
$ diva --show-none test.elf
这应该产生以下输出
{InputFile} "test.elf"
{CompileUnit} "a.cpp"
{CompileUnit} "b.cpp"
{CompileUnit} "c.cpp"