在 Linux DWARF 可执行文件的地址获取符号名称

Getting symbol name at address in Linux DWARF executable

在使用调试符号构建的应用程序中,我需要一个函数,该函数给出一个地址 returns 该地址处的符号名称(如果存在)。

我知道 dladdr() 但它只适用于共享库中的符号,不适用于可执行库或静态库中的符号。

作为它应该如何工作的一个例子,在 gdb 中我可以做 info symbol 0x... 并且它给了我一个名字。对于同一个地址,我应该能够做到 symbolName(0x...) 并且我应该得到相同的名称。

我猜对此没有现成的解决方案,所以我很乐意自己实现它,但我不确定从哪里开始。我可以解析可执行文件的 DWARF 信息,但我不确定在 DWARF 中的何处查看。

谢谢

I'm guessing that there isn't an readily available solution for this so I'm happy to implement this myself, but I'm not sure where to start.

查看 this 答案(及其链接)。

I can parse DWARF info of the executable

虽然 DWARF 包含您要查找的信息,但符号 table 也包含您要查找的信息。后者至少比解析和使用容易 100 倍。

一种解决方案是对当前可执行文件中的符号使用 ELF,对动态加载库中的符号使用 dladdr()

这是完整的代码,在 Rust 中(使用 goblin crate 来读取 ELF):

use std::collections::HashMap;
use std::ffi::CString;
use goblin::elf::Elf;

/// Returns a map from addresses to symbols in the current executable.
fn addr_to_sym() -> HashMap<u64, String> {
    let exec_path = std::fs::read_link("/proc/self/exe");
    println!("exec_path: {:#?}", exec_path);

    let mut addr_to_sym: HashMap<u64, String> = HashMap::new();

    if let Ok(exec_path) = exec_path {
        if let Ok(exec_bytes) = std::fs::read(exec_path) {
            if let Ok(elf) = Elf::parse(&exec_bytes) {
                for sym in elf.syms.iter() {
                    if let Some(Ok(str)) = elf.strtab.get(sym.st_name) {
                        if sym.st_value == 0 {
                            // Can't find address of the symbol in the current binary, try dlsym
                            let dyn_addr = unsafe {
                                libc::dlsym(libc::RTLD_DEFAULT, CString::new(str).unwrap().as_ptr())
                            };
                            if !dyn_addr.is_null() {
                                addr_to_sym.insert(dyn_addr as u64, str.to_owned());
                            }
                        } else {
                            addr_to_sym.insert(sym.st_value, str.to_owned());
                        }
                    }
                }
            }
        }
    }

    addr_to_sym
}

使用此映射,我可以在当前可执行文件(包括静态链接的依赖项)和动态依赖项中找到符号。