C 如何在.so中从运行时地址查找符号偏移量
我需要能够将指令指针(从回溯)转换成一个文件和程序终止后的行号。在执行过程中,我可以存储稍后进行脱机分析所需的任何其他信息,但分析必须脱机进行 现在,除了发出指令指针,我还发出一组结构,其中包含来自C 如何在.so中从运行时地址查找符号偏移量,c,linux,elf,C,Linux,Elf,我需要能够将指令指针(从回溯)转换成一个文件和程序终止后的行号。在执行过程中,我可以存储稍后进行脱机分析所需的任何其他信息,但分析必须脱机进行 现在,除了发出指令指针,我还发出一组结构,其中包含来自dl\u iterate\u phdr的一些信息。我包括模块名称、基址的dlpi_addr字段以及标记为可执行的第一个phdr的p_memsz字段 然后,在我的脱机工具中,我使用保存的大小和地址表为给定地址标识模块。我从指令地址中减去dlpi\u addr,并将其传递给addr2line 这似乎在大多
dl\u iterate\u phdr
的一些信息。我包括模块名称、基址的dlpi_addr
字段以及标记为可执行的第一个phdr
的p_memsz
字段
然后,在我的脱机工具中,我使用保存的大小和地址表为给定地址标识模块。我从指令地址中减去dlpi\u addr
,并将其传递给addr2line
这似乎在大多数情况下都有效,但有时我认为它有点不正确(例如,它发现了一个相邻的符号——我知道行号信息并不总是正确的)。对于主可执行文件,它也完全失败。我很确定我只是没有正确处理所有的抵消
一般来说,我需要做什么才能使其正常工作?我知道有几个库可以做到这一点(lldb
,libdwarf
),但它们没有很好的文档记录。我还试图在主程序和离线工具之间传递尽可能少的信息,例如,我不想将内存映射作为字符串转储
以下是一些示例数据:
dl_iterate_phdr回调代码:
for ( ElfW(Half) i = 0; i < info->dlpi_phnum; i++ )
{
const ElfW(Phdr)& header = info->dlpi_phdr[i];
// Find the executable segment
if ( (header.p_flags & PF_X) && (header.p_type == PT_LOAD) )
{
if ( info->dlpi_addr == getauxval(AT_SYSINFO_EHDR) )
{
// vdso section.
continue;
}
printf("Module %d\n", modules->m_Count);
printf("Module name: %s\n", info->dlpi_name);
printf("Start address: %p\n", info->dlpi_addr);
printf("Length: %jx\n", (uintmax_t)header.p_memsz);
...
}
}
cat/proc//映射
00400000-00408000 r-xp 00000000 fc:01 56098817 /path/to/main/executable
00607000-00608000 r--p 00007000 fc:01 56098817 /path/to/main/executable
00608000-00609000 rw-p 00008000 fc:01 56098817 /path/to/main/executable
010cc000-010ed000 rw-p 00000000 00:00 0 [heap]
7ff924000000-7ff924021000 rw-p 00000000 00:00 0
7ff924021000-7ff928000000 ---p 00000000 00:00 0
7ff92c000000-7ff92c021000 rw-p 00000000 00:00 0
7ff92c021000-7ff930000000 ---p 00000000 00:00 0
7ff931a1a000-7ff931a1b000 ---p 00000000 00:00 0
7ff931a1b000-7ff93221b000 rw-p 00000000 00:00 0
7ff93221b000-7ff93221c000 ---p 00000000 00:00 0
7ff93221c000-7ff932a1c000 rw-p 00000000 00:00 0
7ff932a1c000-7ff932a33000 r-xp 00000000 fc:01 56360961 /path/to/yet/another.so
7ff932a33000-7ff932c32000 ---p 00017000 fc:01 56360961 /path/to/yet/another.so
7ff932c32000-7ff932c33000 r--p 00016000 fc:01 56360961 /path/to/yet/another.so
7ff932c33000-7ff932cc3000 rw-p 00017000 fc:01 56360961 /path/to/yet/another.so
7ff932cc3000-7ff932ccf000 r-xp 00000000 fc:01 56229891 /path/to/another.so
7ff932ccf000-7ff932ece000 ---p 0000c000 fc:01 56229891 /path/to/another.so
7ff932ece000-7ff932ecf000 r--p 0000b000 fc:01 56229891 /path/to/another.so
7ff932ecf000-7ff932ed0000 rw-p 0000c000 fc:01 56229891 /path/to/another.so
7ff932ed0000-7ff932f60000 rw-p 00000000 00:00 0
7ff932f60000-7ff93311a000 r-xp 00000000 fc:01 17039726 /lib/x86_64-linux-gnu/libc-2.19.so
7ff93311a000-7ff93331a000 ---p 001ba000 fc:01 17039726 /lib/x86_64-linux-gnu/libc-2.19.so
7ff93331a000-7ff93331e000 r--p 001ba000 fc:01 17039726 /lib/x86_64-linux-gnu/libc-2.19.so
7ff93331e000-7ff933320000 rw-p 001be000 fc:01 17039726 /lib/x86_64-linux-gnu/libc-2.19.so
7ff933320000-7ff933325000 rw-p 00000000 00:00 0
7ff933325000-7ff93333b000 r-xp 00000000 fc:01 17039378 /lib/x86_64-linux-gnu/libgcc_s.so.1
7ff93333b000-7ff93353a000 ---p 00016000 fc:01 17039378 /lib/x86_64-linux-gnu/libgcc_s.so.1
7ff93353a000-7ff93353b000 rw-p 00015000 fc:01 17039378 /lib/x86_64-linux-gnu/libgcc_s.so.1
7ff93353b000-7ff933640000 r-xp 00000000 fc:01 17039591 /lib/x86_64-linux-gnu/libm-2.19.so
7ff933640000-7ff93383f000 ---p 00105000 fc:01 17039591 /lib/x86_64-linux-gnu/libm-2.19.so
7ff93383f000-7ff933840000 r--p 00104000 fc:01 17039591 /lib/x86_64-linux-gnu/libm-2.19.so
7ff933840000-7ff933841000 rw-p 00105000 fc:01 17039591 /lib/x86_64-linux-gnu/libm-2.19.so
7ff933841000-7ff933927000 r-xp 00000000 fc:01 8390197 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19
7ff933927000-7ff933b26000 ---p 000e6000 fc:01 8390197 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19
7ff933b26000-7ff933b2e000 r--p 000e5000 fc:01 8390197 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19
7ff933b2e000-7ff933b30000 rw-p 000ed000 fc:01 8390197 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19
7ff933b30000-7ff933b45000 rw-p 00000000 00:00 0
7ff933b45000-7ff933b5e000 r-xp 00000000 fc:01 17039713 /lib/x86_64-linux-gnu/libpthread-2.19.so
7ff933b5e000-7ff933d5d000 ---p 00019000 fc:01 17039713 /lib/x86_64-linux-gnu/libpthread-2.19.so
7ff933d5d000-7ff933d5e000 r--p 00018000 fc:01 17039713 /lib/x86_64-linux-gnu/libpthread-2.19.so
7ff933d5e000-7ff933d5f000 rw-p 00019000 fc:01 17039713 /lib/x86_64-linux-gnu/libpthread-2.19.so
7ff933d5f000-7ff933d63000 rw-p 00000000 00:00 0
7ff933d63000-7ff933d66000 r-xp 00000000 fc:01 17039596 /lib/x86_64-linux-gnu/libdl-2.19.so
7ff933d66000-7ff933f65000 ---p 00003000 fc:01 17039596 /lib/x86_64-linux-gnu/libdl-2.19.so
7ff933f65000-7ff933f66000 r--p 00002000 fc:01 17039596 /lib/x86_64-linux-gnu/libdl-2.19.so
7ff933f66000-7ff933f67000 rw-p 00003000 fc:01 17039596 /lib/x86_64-linux-gnu/libdl-2.19.so
7ff933f67000-7ff933f8a000 r-xp 00000000 fc:01 17039716 /lib/x86_64-linux-gnu/ld-2.19.so
7ff934047000-7ff934049000 rw-p 00000000 00:00 0
7ff93405e000-7ff93407e000 rw-p 00000000 00:00 0
7ff9340b2000-7ff9340c0000 rw-p 00000000 00:00 0
7ff9340dc000-7ff934152000 rw-p 00000000 00:00 0
7ff93415f000-7ff934166000 rw-p 00000000 00:00 0
7ff934172000-7ff934175000 rw-p 00000000 00:00 0
7ff93417b000-7ff93417c000 rw-p 00000000 00:00 0
7ff934185000-7ff934189000 rw-p 00000000 00:00 0
7ff934189000-7ff93418a000 r--p 00022000 fc:01 17039716 /lib/x86_64-linux-gnu/ld-2.19.so
7ff93418a000-7ff93418b000 rw-p 00023000 fc:01 17039716 /lib/x86_64-linux-gnu/ld-2.19.so
7ff93418b000-7ff93418c000 rw-p 00000000 00:00 0
7ffd31892000-7ffd318b6000 rw-p 00000000 00:00 0 [stack]
7ffd31913000-7ffd31915000 r--p 00000000 00:00 0 [vvar]
7ffd31915000-7ffd31917000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
readelf-l可执行文件
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x0000000000400040 0x0000000000400040
0x00000000000001f8 0x00000000000001f8 R E 8
INTERP 0x0000000000000238 0x0000000000400238 0x0000000000400238
0x000000000000001c 0x000000000000001c R 1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x0000000000007276 0x0000000000007276 R E 200000
LOAD 0x0000000000007db8 0x0000000000607db8 0x0000000000607db8
0x0000000000000389 0x00000000000004c0 RW 200000
DYNAMIC 0x0000000000007dd8 0x0000000000607dd8 0x0000000000607dd8
0x0000000000000220 0x0000000000000220 RW 8
NOTE 0x0000000000000254 0x0000000000400254 0x0000000000400254
0x0000000000000044 0x0000000000000044 R 4
GNU_EH_FRAME 0x0000000000004a40 0x0000000000404a40 0x0000000000404a40
0x000000000000078c 0x000000000000078c R 4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 10
GNU_RELRO 0x0000000000007db8 0x0000000000607db8 0x0000000000607db8
0x0000000000000248 0x0000000000000248 R 1
数学示例:
饼图
可执行文件,dlpi\u addr
应始终为0)
你应该试着创造一个新的机会,让我们告诉你你做错了什么。从一个简单的主二进制文件开始,显示您得到的地址、从
nm
的输出、dlpi\u addr等。dlpi\u addr
不是映射的起始地址,而是相对于PT\u LOAD
程序头中映射的p\u vaddr
地址的偏移量。将这些值加在一起,您将得到绝对虚拟地址范围。只是想知道,地址空间布局随机化不应该阻止这种分析吗?这意味着加载的程序不会以可预测的方式显示在内存中。不,目标不是预测/未来/运行,而是分析以前的运行。即使有了这些,你也无法预测符号在未来的运行中会落在哪里。我希望我只是错过了一个主要部分,比如处理一些偏移。我会得到一个复制,或者至少一些示例数据和代码片段,只要我能找到合适的计算机(不幸的是,我现在正在旅行,所以可能不会马上)。我相信一个例子是为了获得主可执行文件的正确地址,我不得不假装将模块大小计算为_etext-0x40000,但同时,我不得不/不/将0x40000作为模块的起始地址(即0)。我相信(从内存中)phdr info声明的起始偏移量为0x40040。也就是说,我知道我说的太含糊了。我会尽快得到更多的细节。这很有意义,而且听起来它可以解决从主可执行文件中正确检测符号的问题。为了计算符号的偏移量以便用addr2line查找它们,我是否只需减去dlpi_addr,而忽略p_vaddr?然后,逻辑将是:对于(dlpi_addr+p_vaddr,dlpi_addr+p_vaddr+p_memsz)中的符号,只需减去dlpi_addr(不考虑p_vaddr),即可计算addr2line的偏移量。@Falcon:对。ELF文件寻址(例如符号表)中的虚拟地址与运行时的虚拟地址之间的转换纯粹是对dlpi\u addr
的加减。顺便说一句,我认为主非饼图程序的差异也适用于预链接处理的共享库,虽然我自己从未使用过prelink,可能是弄错了。现在我回到办公室,今天我将尝试一下这个公式。如果它不起作用,我会找到一个看起来错误的示例符号来发布其他信息。关于PIE,这通常需要一个特殊的构建标志,不是吗?我肯定没有明确启用它。使用上面的计算解决了问题。主可执行文件是186个公共linux库中唯一一个p_vaddr为其设计的示例!=0谢谢你的帮助!
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x0000000000400040 0x0000000000400040
0x00000000000001f8 0x00000000000001f8 R E 8
INTERP 0x0000000000000238 0x0000000000400238 0x0000000000400238
0x000000000000001c 0x000000000000001c R 1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x0000000000007276 0x0000000000007276 R E 200000
LOAD 0x0000000000007db8 0x0000000000607db8 0x0000000000607db8
0x0000000000000389 0x00000000000004c0 RW 200000
DYNAMIC 0x0000000000007dd8 0x0000000000607dd8 0x0000000000607dd8
0x0000000000000220 0x0000000000000220 RW 8
NOTE 0x0000000000000254 0x0000000000400254 0x0000000000400254
0x0000000000000044 0x0000000000000044 R 4
GNU_EH_FRAME 0x0000000000004a40 0x0000000000404a40 0x0000000000404a40
0x000000000000078c 0x000000000000078c R 4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 10
GNU_RELRO 0x0000000000007db8 0x0000000000607db8 0x0000000000607db8
0x0000000000000248 0x0000000000000248 R 1