1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
use libdw_sys as ffi;

use std::ffi::CStr;
use std::ptr;
use std::slice;

#[inline]
pub fn gnu_debuglink<'elf>(
    elf: &'elf libelf::Elf<'_>,
) -> libelf::Result<Option<(&'elf CStr, u32)>> {
    let mut crc = 0;
    let namep = unsafe { ffi::dwelf_elf_gnu_debuglink(elf.as_ptr(), &mut crc) };
    if namep.is_null() {
        match libelf::Error::check() {
            Some(error) => Err(error),
            None => Ok(None),
        }
    } else {
        Ok(Some(unsafe { (CStr::from_ptr(namep), crc) }))
    }
}

#[inline]
pub fn gnu_debugaltlink<'dw>(
    dwarf: &'dw libdw::Dwarf<'_>,
) -> libdw::Result<Option<(&'dw CStr, &'dw [u8])>> {
    let mut namep = ptr::null();
    let mut build_idp = ptr::null();
    let build_id_len =
        unsafe { ffi::dwelf_dwarf_gnu_debugaltlink(dwarf.as_ptr(), &mut namep, &mut build_idp) };
    if build_id_len < 0 {
        Err(libdw::Error::last())
    } else if build_id_len > 0 {
        Ok(Some(unsafe {
            (
                CStr::from_ptr(namep),
                slice::from_raw_parts(build_idp as *const u8, build_id_len as usize),
            )
        }))
    } else {
        Ok(None)
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn self_debuglink() {
        use std::env;
        let exe = env::current_exe().unwrap();
        let elf = libelf::Elf::open(exe).unwrap();
        let link = super::gnu_debuglink(&elf).unwrap();
        assert!(link.is_none());
    }

    #[test]
    fn self_debugaltlink() {
        use std::env;
        let exe = env::current_exe().unwrap();
        let dwarf = libdw::Dwarf::open(exe).unwrap();
        let link = super::gnu_debugaltlink(&dwarf).unwrap();
        assert!(link.is_none());
    }
}