Skip to content

Commit 8db66bc

Browse files
bobrikd-e-s-o
authored andcommitted
Search /usr/lib/debug/.build-id for debug files
Signed-off-by: Ivan Babrou <[email protected]>
1 parent eda2b90 commit 8db66bc

File tree

3 files changed

+77
-8
lines changed

3 files changed

+77
-8
lines changed

src/dwarf/debug_link.rs

Lines changed: 69 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,17 @@ use std::path::Path;
1919
use std::path::PathBuf;
2020

2121
use crate::elf::ElfParser;
22+
use crate::elf::BUILD_ID_DEBUG_DIR;
23+
use crate::elf::BUILD_ID_DEBUG_EXTENSION;
2224
use crate::error::IntoError as _;
2325
use crate::util::align_up_usize;
2426
use crate::util::bytes_to_os_str;
2527
use crate::util::ReadRaw as _;
28+
use crate::BuildId;
2629
use crate::Result;
2730

28-
2931
enum State {
32+
BuildId,
3033
FixedDir {
3134
idx: usize,
3235
},
@@ -47,6 +50,8 @@ pub(crate) struct DebugFileIter<'path> {
4750
canonical_linker: Option<&'path Path>,
4851
/// The debug link target file.
4952
linkee: &'path OsStr,
53+
/// The build id of the binary.
54+
build_id: Option<BuildId<'path>>,
5055
/// The iteration state.
5156
state: State,
5257
}
@@ -56,12 +61,14 @@ impl<'path> DebugFileIter<'path> {
5661
fixed_dirs: &'path [PathBuf],
5762
canonical_linker: Option<&'path Path>,
5863
linkee: &'path OsStr,
64+
build_id: Option<BuildId<'path>>,
5965
) -> Self {
6066
Self {
6167
fixed_dirs,
6268
canonical_linker,
6369
linkee,
64-
state: State::FixedDir { idx: 0 },
70+
build_id,
71+
state: State::BuildId,
6572
}
6673
}
6774

@@ -84,6 +91,38 @@ impl Iterator for DebugFileIter<'_> {
8491

8592
fn next(&mut self) -> Option<Self::Item> {
8693
match &mut self.state {
94+
State::BuildId => {
95+
self.state = State::FixedDir { idx: 0 };
96+
97+
let Some(build_id) = self.build_id.as_ref() else {
98+
return self.next()
99+
};
100+
101+
// Technically we can check just 2 bytes with the code below,
102+
// but anything that short is probably bogus and worth skipping.
103+
if build_id.len() < 8 {
104+
return self.next();
105+
}
106+
107+
let mut path = PathBuf::from(BUILD_ID_DEBUG_DIR);
108+
109+
let mut build_id_iter = build_id.iter();
110+
111+
if let Some(first) = build_id_iter.next() {
112+
path.push(format!("{first:02x}"));
113+
} else {
114+
return self.next();
115+
}
116+
117+
path.push(format!(
118+
"{}.{BUILD_ID_DEBUG_EXTENSION}",
119+
build_id_iter
120+
.map(|byte| format!("{byte:02x}"))
121+
.collect::<String>()
122+
));
123+
124+
self.report_or_next(path)
125+
}
87126
State::FixedDir { idx } => {
88127
if let Some(dir) = self.fixed_dirs.get(*idx) {
89128
*idx += 1;
@@ -309,17 +348,27 @@ mod tests {
309348
#[test]
310349
fn debug_file_iteration() {
311350
let fixed_dirs = [PathBuf::from("/usr/lib/debug")];
312-
let files = DebugFileIter::new(fixed_dirs.as_slice(), None, OsStr::new("libc.so.debug"))
313-
.collect::<Vec<_>>();
351+
let files = DebugFileIter::new(
352+
fixed_dirs.as_slice(),
353+
None,
354+
OsStr::new("libc.so.debug"),
355+
None,
356+
)
357+
.collect::<Vec<_>>();
314358
let expected = vec![PathBuf::from("/usr/lib/debug/libc.so.debug")];
315359
assert_eq!(files, expected);
316360

317361
let fixed_dirs = DEFAULT_DEBUG_DIRS
318362
.iter()
319363
.map(PathBuf::from)
320364
.collect::<Vec<_>>();
321-
let files = DebugFileIter::new(fixed_dirs.as_slice(), None, OsStr::new("libc.so.debug"))
322-
.collect::<Vec<_>>();
365+
let files = DebugFileIter::new(
366+
fixed_dirs.as_slice(),
367+
None,
368+
OsStr::new("libc.so.debug"),
369+
None,
370+
)
371+
.collect::<Vec<_>>();
323372
let expected = vec![
324373
PathBuf::from("/usr/lib/debug/libc.so.debug"),
325374
PathBuf::from("/lib/debug/libc.so.debug"),
@@ -331,6 +380,7 @@ mod tests {
331380
fixed_dirs.as_slice(),
332381
Some(Path::new("/usr/lib64/libc.so")),
333382
OsStr::new("libc.so.debug"),
383+
Some(BuildId::Owned(vec![0xbe, 0xef, 0xbe, 0xef])), // too short
334384
)
335385
.collect::<Vec<_>>();
336386

@@ -350,10 +400,14 @@ mod tests {
350400
fixed_dirs.as_slice(),
351401
Some(Path::new("/usr/lib64/libc.so")),
352402
OsStr::new("libc.so.debug"),
403+
Some(BuildId::Owned(vec![
404+
0xbe, 0xef, 0xbe, 0xef, 0xfe, 0xed, 0xba, 0xbe,
405+
])),
353406
)
354407
.collect::<Vec<_>>();
355408

356409
let expected = vec![
410+
PathBuf::from("/usr/lib/debug/.build-id/be/efbeeffeedbabe.debug"),
357411
PathBuf::from("/usr/lib/debug/libc.so.debug"),
358412
PathBuf::from("/lib/debug/libc.so.debug"),
359413
PathBuf::from("/usr/lib64/libc.so.debug"),
@@ -371,8 +425,16 @@ mod tests {
371425
fixed_dirs.as_slice(),
372426
Some(Path::new("/usr/lib64/libc.so")),
373427
OsStr::new("libc.so"),
428+
Some(BuildId::Owned(vec![
429+
0xbe, 0xef, 0xbe, 0xef, 0xfe, 0xed, 0xba, 0xbe,
430+
])),
374431
)
375432
.collect::<Vec<_>>();
376-
assert_eq!(files, Vec::<PathBuf>::new());
433+
assert_eq!(
434+
files,
435+
vec![PathBuf::from(
436+
"/usr/lib/debug/.build-id/be/efbeeffeedbabe.debug"
437+
)]
438+
);
377439
}
378440
}

src/dwarf/resolver.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use crate::elf::ElfResolverData;
2525
use crate::elf::DEFAULT_DEBUG_DIRS;
2626
use crate::error::IntoCowStr;
2727
use crate::file_cache::FileCache;
28+
use crate::helper::read_elf_build_id;
2829
use crate::inspect::FindAddrOpts;
2930
use crate::inspect::ForEachFn;
3031
use crate::inspect::Inspect;
@@ -117,7 +118,10 @@ fn try_canonicalize(path: &Path) -> io::Result<Cow<'_, Path>> {
117118
/// This function ignores any errors encountered.
118119
fn find_debug_file(file: &OsStr, linker: Option<&Path>, debug_dirs: &[PathBuf]) -> Option<PathBuf> {
119120
let canonical_linker = linker.and_then(|linker| try_canonicalize(linker).ok());
120-
let it = DebugFileIter::new(debug_dirs, canonical_linker.as_deref(), file);
121+
let build_id = canonical_linker
122+
.as_ref()
123+
.and_then(|linker| read_elf_build_id(linker).unwrap_or_default());
124+
let it = DebugFileIter::new(debug_dirs, canonical_linker.as_deref(), file, build_id);
121125
for path in it {
122126
if path.exists() {
123127
debug!("found debug info at `{}`", path.display());

src/elf/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ pub(crate) mod types;
1111
// of concerns that is not a workable location.
1212
pub(crate) static DEFAULT_DEBUG_DIRS: &[&str] = &["/usr/lib/debug", "/lib/debug/"];
1313

14+
pub(crate) static BUILD_ID_DEBUG_DIR: &str = "/usr/lib/debug/.build-id";
15+
pub(crate) static BUILD_ID_DEBUG_EXTENSION: &str = "debug";
16+
1417
pub(crate) use parser::BackendImpl;
1518
pub(crate) use parser::ElfParser;
1619
pub(crate) use parser::StaticMem;

0 commit comments

Comments
 (0)