Skip to content

Commit fc20f4b

Browse files
committed
Fix debugaltlink path resolution
1 parent 866fd4a commit fc20f4b

File tree

1 file changed

+81
-43
lines changed

1 file changed

+81
-43
lines changed

src/symbolize/gimli/elf.rs

Lines changed: 81 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ impl Mapping {
2121
let object = Object::parse(&map)?;
2222

2323
// Try to locate an external debug file using the build ID.
24-
if let Some(path_debug) = object.build_id_debug_path() {
24+
if let Some(path_debug) = object.build_id().and_then(locate_build_id) {
2525
if let Some(mapping) = Mapping::new_debug(path_debug, None) {
2626
return Some(mapping);
2727
}
@@ -251,44 +251,6 @@ impl<'a> Object<'a> {
251251
None
252252
}
253253

254-
// The format of build id paths is documented at:
255-
// https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html
256-
fn build_id_debug_path(&self) -> Option<PathBuf> {
257-
const BUILD_ID_PATH: &[u8] = b"/usr/lib/debug/.build-id/";
258-
const BUILD_ID_SUFFIX: &[u8] = b".debug";
259-
260-
if !debug_path_exists() {
261-
return None;
262-
}
263-
264-
let build_id = self.build_id()?;
265-
if build_id.len() < 2 {
266-
return None;
267-
}
268-
269-
fn hex(byte: u8) -> u8 {
270-
if byte < 10 {
271-
b'0' + byte
272-
} else {
273-
b'a' + byte - 10
274-
}
275-
}
276-
277-
let mut path = Vec::with_capacity(
278-
BUILD_ID_PATH.len() + BUILD_ID_SUFFIX.len() + build_id.len() * 2 + 1,
279-
);
280-
path.extend(BUILD_ID_PATH);
281-
path.push(hex(build_id[0] >> 4));
282-
path.push(hex(build_id[0] & 0xf));
283-
path.push(b'/');
284-
for byte in &build_id[1..] {
285-
path.push(hex(byte >> 4));
286-
path.push(hex(byte & 0xf));
287-
}
288-
path.extend(BUILD_ID_SUFFIX);
289-
Some(PathBuf::from(OsString::from_vec(path)))
290-
}
291-
292254
// The contents of the ".gnu_debuglink" section is documented at:
293255
// https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html
294256
fn gnu_debuglink_path(&self, path: &Path) -> Option<(PathBuf, u32)> {
@@ -305,14 +267,14 @@ impl<'a> Object<'a> {
305267
Some((path_debug, crc))
306268
}
307269

308-
// The format if the ".gnu_debugaltlink" section is based on gdb.
270+
// The format of the ".gnu_debugaltlink" section is based on gdb.
309271
fn gnu_debugaltlink_path(&self, path: &Path) -> Option<(PathBuf, &'a [u8])> {
310272
let section = self.section_header(".gnu_debugaltlink")?;
311273
let data = section.data(self.endian, self.data).ok()?;
312274
let len = data.iter().position(|x| *x == 0)?;
313275
let filename = &data[..len];
314276
let build_id = &data[len + 1..];
315-
let path_sup = locate_debuglink(path, filename)?;
277+
let path_sup = locate_debugaltlink(path, filename, build_id)?;
316278
Some((path_sup, build_id))
317279
}
318280
}
@@ -362,8 +324,55 @@ fn debug_path_exists() -> bool {
362324
}
363325
}
364326

365-
// Search order matches gdb, documented at:
366-
// https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html
327+
/// Locate a debug file based on its build ID.
328+
///
329+
/// The format of build id paths is documented at:
330+
/// https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html
331+
fn locate_build_id(build_id: &[u8]) -> Option<PathBuf> {
332+
const BUILD_ID_PATH: &[u8] = b"/usr/lib/debug/.build-id/";
333+
const BUILD_ID_SUFFIX: &[u8] = b".debug";
334+
335+
if build_id.len() < 2 {
336+
return None;
337+
}
338+
339+
if !debug_path_exists() {
340+
return None;
341+
}
342+
343+
let mut path =
344+
Vec::with_capacity(BUILD_ID_PATH.len() + BUILD_ID_SUFFIX.len() + build_id.len() * 2 + 1);
345+
path.extend(BUILD_ID_PATH);
346+
path.push(hex(build_id[0] >> 4));
347+
path.push(hex(build_id[0] & 0xf));
348+
path.push(b'/');
349+
for byte in &build_id[1..] {
350+
path.push(hex(byte >> 4));
351+
path.push(hex(byte & 0xf));
352+
}
353+
path.extend(BUILD_ID_SUFFIX);
354+
Some(PathBuf::from(OsString::from_vec(path)))
355+
}
356+
357+
fn hex(byte: u8) -> u8 {
358+
if byte < 10 {
359+
b'0' + byte
360+
} else {
361+
b'a' + byte - 10
362+
}
363+
}
364+
365+
/// Locate a file specified in a `.gnu_debuglink` section.
366+
///
367+
/// `path` is the file containing the section.
368+
/// `filename` is from the contents of the section.
369+
///
370+
/// Search order is based on gdb, documented at:
371+
/// https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html
372+
///
373+
/// gdb also allows the user to customize the debug search path, but we don't.
374+
///
375+
/// gdb also supports debuginfod, but we don't yet.
367376
fn locate_debuglink(path: &Path, filename: &[u8]) -> Option<PathBuf> {
368377
let path = fs::canonicalize(path).ok()?;
369378
let parent = path.parent()?;
@@ -400,3 +409,32 @@ fn locate_debuglink(path: &Path, filename: &[u8]) -> Option<PathBuf> {
400409

401410
None
402411
}
412+
413+
/// Locate a file specified in a `.gnu_debugaltlink` section.
414+
///
415+
/// `path` is the file containing the section.
416+
/// `filename` and `build_id` are the contents of the section.
417+
///
418+
/// Search order is based on gdb:
419+
/// - filename, which is either absolute or relative to `path`
420+
/// - the build ID path under `BUILD_ID_PATH`
421+
///
422+
/// gdb also allows the user to customize the debug search path, but we don't.
423+
///
424+
/// gdb also supports debuginfod, but we don't yet.
425+
fn locate_debugaltlink(path: &Path, filename: &[u8], build_id: &[u8]) -> Option<PathBuf> {
426+
let filename = Path::new(OsStr::from_bytes(filename));
427+
if filename.is_absolute() {
428+
if filename.is_file() {
429+
return Some(filename.into());
430+
}
431+
} else {
432+
let mut f = PathBuf::from(path);
433+
f.push(filename);
434+
if f.is_file() {
435+
return Some(f);
436+
}
437+
}
438+
439+
locate_build_id(build_id)
440+
}

0 commit comments

Comments
 (0)