diff --git a/dev/build.rs b/dev/build.rs
index aaf73bad3..a115a984d 100644
--- a/dev/build.rs
+++ b/dev/build.rs
@@ -856,6 +856,42 @@ fn prepare_test_files() {
],
);
+ dwarf(&src, "test-stable-addrs-dwarf-only-sup.dbg");
+ dwarf(&src, "test-stable-addrs-dwarf-only-broken-sup.dbg");
+ let dbg = data_dir.join("test-stable-addrs-dwarf-only-sup.dbg");
+ let broken_dbg = data_dir.join("test-stable-addrs-dwarf-only-broken-sup.dbg");
+ dwz(
+ &data_dir.join("test-stable-addrs-dwarf-5.dwz"),
+ &[
+ "--relative",
+ "--dwarf-5",
+ dbg.to_str().unwrap(),
+ broken_dbg.to_str().unwrap(),
+ ],
+ );
+ let () = adjust_mtime(&dbg).unwrap();
+ objcopy(
+ &src,
+ "test-stable-addrs-stripped-with-sup.bin",
+ &[
+ "--strip-all",
+ &format!("--add-gnu-debuglink={}", dbg.display()),
+ ],
+ );
+ objcopy(
+ &broken_dbg,
+ broken_dbg.as_os_str(),
+ &["--remove-section=.debug_sup"],
+ );
+ objcopy(
+ &src,
+ "test-stable-addrs-stripped-with-broken-sup.bin",
+ &[
+ "--strip-all",
+ &format!("--add-gnu-debuglink={}", broken_dbg.display()),
+ ],
+ );
+
gnu_debugdata(&src, "test-stable-addrs-debugdata.bin");
let elf = data_dir.join("test-stable-addrs-no-dwarf.bin");
diff --git a/src/dwarf/debug_sup.rs b/src/dwarf/debug_sup.rs
new file mode 100644
index 000000000..9b1b8e951
--- /dev/null
+++ b/src/dwarf/debug_sup.rs
@@ -0,0 +1,324 @@
+//! Support for reading of GNU .`debug_sup` data as prescribed in DWARF v5;
+//! .`debug_sup` replaces .`gnu_debugaltlink` in the current standard and
+//! plays the same role: it functions as a pointer to a
+//! supplementary object file.
+//!
+//! .`debug_sup` is a special section of executable files that should contain:
+//! - `version`: u16 representing the version of the DWARF information for the
+//! compilation unit
+//! - `is_supplementary`: u8 which is set to 1 if the file in which the
+//! section is stored is a supplementary file, 0 o.w.
+//! - `sup_filename`: null-terminated supplementary file name or path (is
+//! !`is_supplementary`)
+//! - `sup_checksum_len`: uleb128 indicating the length of the following
+//! checksum field
+//! - `sup_checksum`: [u8: `sup_checksum_len`] unique supplementary file id
+
+use std::borrow::Cow;
+use std::path::Path;
+
+use crate::elf::ElfParser;
+use crate::error::Error;
+use crate::error::IntoError as _;
+use crate::util::bytes_to_path;
+use crate::util::ReadRaw as _;
+use crate::Result;
+
+
+#[derive(Debug)]
+pub(crate) struct DebugSupInfo<'a> {
+ pub _version: u16,
+ pub is_supplementary: bool,
+ pub path: Option<&'a Path>,
+ pub checksum: Cow<'a, [u8]>,
+}
+
+
+/// Read the debug sup section.
+pub(crate) fn read_debug_sup(parser: &ElfParser) -> Result>> {
+ let debug_sup_section = ".debug_sup";
+ let idx = if let Ok(Some(idx)) = parser.find_section(debug_sup_section) {
+ idx
+ } else {
+ return Ok(None)
+ };
+
+ // SANITY: We just found the index so the section should always be
+ // found.
+ let data = parser.section_data(idx).unwrap();
+ parse_debug_sup_section_data(data)
+}
+
+
+fn parse_debug_sup_section_data(mut data: &[u8]) -> Result >> {
+ let version = data
+ .read_u16()
+ .ok_or_invalid_data(|| "failed to read .debug_sup version")?;
+
+ let is_supplementary = match data
+ .read_u8()
+ .ok_or_invalid_data(|| "failed to read .debug_sup is_supplementary")?
+ {
+ 0 => false,
+ 1 => true,
+ v => {
+ return Err(Error::with_invalid_data(format!(
+ "invalid is_supplementary field value: {v}"
+ )))
+ }
+ };
+
+ let path_string = data
+ .read_cstr()
+ .ok_or_invalid_data(|| "failed to read .debug_sup file field")?;
+ let path = if !is_supplementary {
+ bytes_to_path(path_string.to_bytes()).ok()
+ } else {
+ None
+ };
+
+ // TODO: Use `Path::is_empty` once our MSRV is >= 1.98.
+ if !is_supplementary && path_string.as_ref().is_empty() {
+ return Err(Error::with_invalid_data("debug sup target is empty"))
+ } else if is_supplementary && !path_string.as_ref().is_empty() {
+ return Err(Error::with_invalid_data(
+ "debug sup target is not empty in a supplementary file",
+ ))
+ }
+
+ let sup_checksum_len = data
+ .read_u64_leb128()
+ .ok_or_invalid_data(|| "failed to read .debug_sup sup_checksum_len")?;
+
+ let checksum = data
+ .read_slice(sup_checksum_len.try_into().unwrap())
+ .ok_or_invalid_data(|| "failed to read .debug_sup checksum")?;
+ let checksum = Cow::Borrowed(checksum);
+ Ok(Some(DebugSupInfo {
+ _version: version,
+ is_supplementary,
+ path,
+ checksum,
+ }))
+}
+
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ use std::mem::size_of_val;
+ use std::slice;
+
+ use test_tag::tag;
+
+
+ /// Check that we can correctly read the checksum from a `.debug_sup`
+ /// section data.
+ #[tag(miri)]
+ #[test]
+ fn unaligned_debug_sup_parsing() {
+ let section_data = [
+ 0x5, 0x0, 0x0, b'.', b'.', b'/', b'.', b'.', b'/', b'.', b'd', b'w', b'z', b'/', b'p',
+ b'r', b'o', b'g', b'r', b'a', b'm', 0x0, 0x14, 0x7f, 0xd3, 0x76, 0x0a, 0xf3, 0x98,
+ 0xa1, 0xcc, 0x3f, 0x90, 0x45, 0x69, 0x9a, 0xda, 0x29, 0xe0, 0xb6, 0x6b, 0x45, 0xc8,
+ ];
+
+ let mut buffer = [0u64; 8];
+ let buffer = unsafe {
+ slice::from_raw_parts_mut(
+ buffer.as_mut_ptr().cast::(),
+ buffer.len() * size_of_val(&buffer[0]),
+ )
+ };
+
+ // Make the buffer unaligned.
+ let buffer = &mut buffer[3..3 + section_data.len()];
+ // Now write the section data into it.
+ let () = buffer.copy_from_slice(§ion_data);
+
+ let DebugSupInfo {
+ _version: version,
+ is_supplementary,
+ path,
+ checksum,
+ } = parse_debug_sup_section_data(buffer).unwrap().unwrap();
+
+ assert_eq!(version, 5);
+ assert!(!is_supplementary);
+ assert!(path.is_some());
+ assert_eq!(path.unwrap(), Path::new("../../.dwz/program"));
+ assert_eq!(
+ checksum.as_ref(),
+ [
+ 0x7f, 0xd3, 0x76, 0x0a, 0xf3, 0x98, 0xa1, 0xcc, 0x3f, 0x90, 0x45, 0x69, 0x9a, 0xda,
+ 0x29, 0xe0, 0xb6, 0x6b, 0x45, 0xc8
+ ]
+ );
+ }
+
+ /// Check that we handle empty version in `.debug_sup` section.
+ #[tag(miri)]
+ #[test]
+ fn empty_version_debug_sup_parsing() {
+ let section_data = &[];
+
+ let result = parse_debug_sup_section_data(section_data);
+ assert!(result.is_err());
+ let error = result.unwrap_err();
+ assert!(error.to_string().contains("version"));
+ }
+
+ /// Check that we handle no `is_supplementary` in debug sup section.
+ #[tag(miri)]
+ #[test]
+ fn no_is_supplementary_debug_sup_parsing() {
+ let section_data = &[0x5, 0x0];
+
+ let result = parse_debug_sup_section_data(section_data);
+ assert!(result.is_err());
+ let error = result.unwrap_err();
+ assert!(error
+ .to_string()
+ .contains("failed to read .debug_sup is_supplementary"));
+ }
+
+ /// Check that we handle invalid `is_supplementary` in debug sup section.
+ #[tag(miri)]
+ #[test]
+ fn invalid_is_supplementary_debug_sup_parsing() {
+ let section_data = &[0x5, 0x0, 0x2];
+
+ let result = parse_debug_sup_section_data(section_data);
+ assert!(result.is_err());
+ let error = result.unwrap_err();
+ assert!(error.to_string().contains("invalid is_supplementary"));
+ }
+
+ /// Check that we handle no path in debug sup section.
+ #[tag(miri)]
+ #[test]
+ fn no_path_debug_sup_parsing() {
+ let section_data = &[0x5, 0x0, 0x0];
+
+ let result = parse_debug_sup_section_data(section_data);
+ assert!(result.is_err());
+ let error = result.unwrap_err();
+ assert!(error.to_string().contains("file field"));
+ }
+
+ /// Check that we handle empty path in debug sup section.
+ #[tag(miri)]
+ #[test]
+ fn empty_path_debug_sup_parsing() {
+ let section_data = &[
+ 0x5, 0x0, 0x0, 0x0, 0x14, 0x7f, 0xd3, 0x76, 0x0a, 0xf3, 0x98, 0xa1, 0xcc, 0x3f, 0x90,
+ 0x45, 0x69, 0x9a, 0xda, 0x29, 0xe0, 0xb6, 0x6b, 0x45, 0xc8,
+ ];
+
+ let result = parse_debug_sup_section_data(section_data);
+ assert!(result.is_err());
+ let error = result.unwrap_err();
+ assert!(error.to_string().contains("debug sup target is empty"));
+ }
+
+ /// Check that we handle not empty path in debug sup section of
+ /// supplementary file.
+ #[tag(miri)]
+ #[test]
+ fn supplementary_not_empty_path_debug_sup_parsing() {
+ let section_data = &[
+ 0x5, 0x0, 0x1, b'.', b'.', b'/', b'.', b'.', b'/', b'.', b'd', b'w', b'z', b'/', b'p',
+ b'r', b'o', b'g', b'r', b'a', b'm', 0x0, 0x14, 0x7f, 0xd3, 0x76, 0x0a, 0xf3, 0x98,
+ 0xa1, 0xcc, 0x3f, 0x90, 0x45, 0x69, 0x9a, 0xda, 0x29, 0xe0, 0xb6, 0x6b, 0x45, 0xc8,
+ ];
+
+ let result = parse_debug_sup_section_data(section_data);
+ assert!(result.is_err());
+ let error = result.unwrap_err();
+ assert!(error
+ .to_string()
+ .contains("debug sup target is not empty in a supplementary file"));
+ }
+
+ /// Check that we handle empty checksum lenght in debug sup section.
+ #[tag(miri)]
+ #[test]
+ fn empty_checksum_len_debug_sup_parsing() {
+ let section_data = &[
+ 0x5, 0x0, 0x0, b'.', b'.', b'/', b'.', b'.', b'/', b'.', b'd', b'w', b'z', b'/', b'p',
+ b'r', b'o', b'g', b'r', b'a', b'm', 0x0,
+ ];
+
+ let result = parse_debug_sup_section_data(section_data);
+ assert!(result.is_err());
+ let error = result.unwrap_err();
+ assert!(error.to_string().contains("sup_checksum_len"));
+ }
+
+ /// Check that we handle empty checksum in debug sup section.
+ #[tag(miri)]
+ #[test]
+ fn empty_checksum_debug_sup_parsing() {
+ let section_data = &[
+ 0x5, 0x0, 0x0, b'.', b'.', b'/', b'.', b'.', b'/', b'.', b'd', b'w', b'z', b'/', b'p',
+ b'r', b'o', b'g', b'r', b'a', b'm', 0x0, 0x14,
+ ];
+
+ let result = parse_debug_sup_section_data(section_data);
+ assert!(result.is_err());
+ let error = result.unwrap_err();
+ assert!(error.to_string().contains("checksum"));
+ }
+
+ /// Check that we handle wrong checksum length in debug sup section.
+ #[tag(miri)]
+ #[test]
+ fn wrong_checksum_len_debug_sup_parsing() {
+ let section_data = &[
+ 0x5, 0x0, 0x0, b'.', b'.', b'/', b'.', b'.', b'/', b'.', b'd', b'w', b'z', b'/', b'p',
+ b'r', b'o', b'g', b'r', b'a', b'm', 0x0, 0x20, 0x7f, 0xd3, 0x76, 0x0a, 0xf3, 0x98,
+ 0xa1, 0xcc, 0x3f, 0x90, 0x45, 0x69, 0x9a, 0xda, 0x29, 0xe0, 0xb6, 0x6b, 0x45, 0xc8,
+ ];
+
+ let result = parse_debug_sup_section_data(section_data);
+ assert!(result.is_err());
+ let error = result.unwrap_err();
+ assert!(error.to_string().contains("checksum"));
+ }
+
+ /// Check that we can successfully read an ELF file's debug sup section.
+ #[test]
+ fn debug_link_reading() {
+ let elf = Path::new(&env!("CARGO_MANIFEST_DIR"))
+ .join("data")
+ .join("test-stable-addrs-dwarf-only-sup.dbg");
+
+ let parser = ElfParser::open(elf.as_path()).unwrap();
+ let DebugSupInfo {
+ _version: version,
+ is_supplementary,
+ path,
+ checksum,
+ } = read_debug_sup(&parser).unwrap().unwrap();
+ assert_eq!(version, 5);
+ assert!(!is_supplementary);
+ assert!(path.is_some());
+ assert_eq!(path.unwrap(), Path::new("test-stable-addrs-dwarf-5.dwz"));
+
+ let dbg = Path::new(&env!("CARGO_MANIFEST_DIR"))
+ .join("data")
+ .join("test-stable-addrs-dwarf-5.dwz");
+ let parser = ElfParser::open(&dbg).unwrap();
+ let DebugSupInfo {
+ _version: version,
+ is_supplementary,
+ path,
+ checksum: checksum_dwz,
+ } = read_debug_sup(&parser).unwrap().unwrap();
+ assert_eq!(version, 5);
+ assert!(is_supplementary);
+ assert!(path.is_none());
+ assert_eq!(checksum, checksum_dwz);
+ }
+}
diff --git a/src/dwarf/mod.rs b/src/dwarf/mod.rs
index 4d26f7db4..db6592f03 100644
--- a/src/dwarf/mod.rs
+++ b/src/dwarf/mod.rs
@@ -1,5 +1,6 @@
mod debug_altlink;
mod debug_link;
+mod debug_sup;
mod function;
mod lines;
mod location;
diff --git a/src/dwarf/resolver.rs b/src/dwarf/resolver.rs
index 251e915d6..34dc3da96 100644
--- a/src/dwarf/resolver.rs
+++ b/src/dwarf/resolver.rs
@@ -53,6 +53,8 @@ use super::debug_altlink::read_debug_altlink;
use super::debug_link::debug_link_crc32;
use super::debug_link::read_debug_link;
use super::debug_link::DebugFileIter;
+use super::debug_sup::read_debug_sup;
+use super::debug_sup::DebugSupInfo;
use super::function::Function;
use super::location::Location;
use super::reader;
@@ -190,13 +192,13 @@ fn try_deref_debug_link(
/// Find a debug file in a list of directories.
///
-/// `linker` is the path to the file containing the debug altlink and
+/// `linker` is the path to the file containing the debug altlink/sup and
/// `build_id` the build ID of the destination, as recorded in the
-/// `.gnu_debugaltlink` section.
+/// `.gnu_debugaltlink`/`.debug_sup` section.
///
/// # Notes
/// This function ignores any errors encountered.
-fn find_altdebug_file(
+fn find_supplementary_file(
path: &Path,
linker: Option<&Path>,
debug_dirs: &[PathBuf],
@@ -211,12 +213,12 @@ fn find_altdebug_file(
);
for path in it {
if path.exists() {
- debug!("found altdebug info at `{}`", path.display());
+ debug!("found supplementary object file at `{}`", path.display());
return Some(path);
}
}
warn!(
- "debug altlink references destination `{}` which was not found in any known location",
+ "link to supplementary file references destination `{}` which was not found in any known location",
path.display(),
);
None
@@ -233,7 +235,7 @@ fn try_deref_debug_altlink(
// actual path is not necessarily correct. Consider if the
// `ElfParser` references a map_files file.
let linker = parser.module().map(OsStr::as_ref);
- match find_altdebug_file(path, linker, debug_dirs, &build_id) {
+ match find_supplementary_file(path, linker, debug_dirs, &build_id) {
Some(path) => {
let tmp_parser;
let dst_parser = if let Some(elf_cache) = elf_cache {
@@ -282,6 +284,75 @@ fn try_deref_debug_altlink(
}
+fn try_deref_debug_sup(
+ parser: &ElfParser,
+ debug_dirs: &[PathBuf],
+ elf_cache: Option<&FileCache>,
+) -> Result>> {
+ if let Some(DebugSupInfo {
+ _version: _,
+ is_supplementary: _,
+ path,
+ checksum,
+ }) = read_debug_sup(parser)?
+ {
+ // TODO: Usage of the module here is fishy, as it may not
+ // represent an actual path. However, even using the
+ // actual path is not necessarily correct. Consider if the
+ // `ElfParser` references a map_files file.
+ let linker = parser.module().map(OsStr::as_ref);
+ if let Some(path) = path {
+ match find_supplementary_file(path, linker, debug_dirs, &[]) {
+ Some(path) => {
+ let tmp_parser;
+ let dst_parser = if let Some(elf_cache) = elf_cache {
+ // TODO: Unclear whether we should provide `debug_dirs`
+ // here instead of `None`?
+ elf_cache
+ .elf_resolver(&path, None)
+ .with_context(|| {
+ format!("failed to open debug sup destination `{}`", path.display())
+ })?
+ .parser()
+ } else {
+ let parser = ElfParser::open(&path).with_context(|| {
+ format!("failed to open debug sup destination `{}`", path.display())
+ })?;
+ tmp_parser = Rc::new(parser);
+ &tmp_parser
+ };
+
+ let DebugSupInfo {
+ _version: _,
+ is_supplementary,
+ path: _,
+ checksum: dst_checksum,
+ } = read_debug_sup(dst_parser)?
+ .ok_or_invalid_data(|| "empty debug_sup section")?;
+ if !is_supplementary {
+ return Err(Error::with_invalid_data(
+ "debug sup destination marked as non-supplementary",
+ ))
+ }
+ if dst_checksum != checksum {
+ return Err(Error::with_invalid_data(format!(
+ "debug sup destination `{}` checksum does not match \
+ expected one: {dst_checksum:?} (actual) != {checksum:?} (expected)",
+ path.display()
+ )))
+ }
+ Ok(Some(Rc::clone(dst_parser)))
+ }
+ None => Ok(None),
+ }
+ } else {
+ Ok(None)
+ }
+ } else {
+ Ok(None)
+ }
+}
+
/// Try to find a DWARF package (`.dwp`) "belonging" to the file
/// referenced by the given [`ElfParser`].
fn try_find_dwp(
@@ -328,9 +399,9 @@ pub(crate) struct DwarfResolver {
/// If the source file contains a valid debug link, this parser
/// represents it.
linkee_parser: Option>,
- /// If the source file contains a valid debug altlink, this parser
- /// represents it.
- _altlinkee_parser: Option>,
+ /// If the source file contains a valid debug altlink or debug sup, this
+ /// parser represents it.
+ _sup_parser: Option>,
/// If there exist an associated DWARF Package (*.dwp), this parser
/// represents it.
_dwp_parser: Option>,
@@ -352,6 +423,7 @@ impl DwarfResolver {
let debug_parser = linkee_parser.as_ref().unwrap_or(&parser);
let altlinkee_parser = try_deref_debug_altlink(debug_parser, debug_dirs, elf_cache)?;
+ let supee_parser = try_deref_debug_sup(debug_parser, debug_dirs, elf_cache)?;
// SAFETY: We own the `ElfParser` and make sure that it stays
// around while the `Units` object uses it. As such, it
// is fine to conjure a 'static lifetime here.
@@ -362,7 +434,7 @@ impl DwarfResolver {
|section| reader::load_section(static_linkee_parser, section, static_relocs);
let mut dwarf = Dwarf::load(&mut load_section)?;
- if let Some(ref altlinkee_parser) = altlinkee_parser {
+ let _sup_parser = if let Some(ref altlinkee_parser) = altlinkee_parser {
let static_altlinkee_parser = unsafe {
mem::transmute::<&ElfParser, &'static ElfParser>(altlinkee_parser.deref())
};
@@ -370,7 +442,18 @@ impl DwarfResolver {
let mut load_altsection =
|section| reader::load_section(static_altlinkee_parser, section, static_altrelocs);
Dwarf::load_sup(&mut dwarf, &mut load_altsection)?;
- }
+ Some(altlinkee_parser.to_owned())
+ } else if let Some(ref supee_parser) = supee_parser {
+ let static_supee_parser =
+ unsafe { mem::transmute::<&ElfParser, &'static ElfParser>(supee_parser.deref()) };
+ let static_suprelocs = static_supee_parser.section_relocations()?;
+ let mut load_supsection =
+ |section| reader::load_section(static_supee_parser, section, static_suprelocs);
+ Dwarf::load_sup(&mut dwarf, &mut load_supsection)?;
+ Some(supee_parser.to_owned())
+ } else {
+ None
+ };
// Cache abbreviations (which will cause them to be
// automatically reused across compilation units), which can
@@ -404,7 +487,7 @@ impl DwarfResolver {
units,
parser,
linkee_parser,
- _altlinkee_parser: altlinkee_parser,
+ _sup_parser,
_dwp_parser: dwp_parser,
};
Ok(slf)
@@ -798,11 +881,11 @@ mod tests {
let path = Path::new(&env!("CARGO_MANIFEST_DIR"))
.join("data")
.join("nonexistent_file");
- let debug_altlink_file = find_altdebug_file(&path, linker, &debug_dirs, &[]);
+ let debug_altlink_file = find_supplementary_file(&path, linker, &debug_dirs, &[]);
assert!(debug_altlink_file.is_none());
let linker = parser.module().map(OsStr::as_ref);
- let debug_altlink_file = find_altdebug_file(linker.unwrap(), linker, &debug_dirs, &[]);
+ let debug_altlink_file = find_supplementary_file(linker.unwrap(), linker, &debug_dirs, &[]);
assert!(debug_altlink_file.is_none());
}
@@ -823,21 +906,60 @@ mod tests {
);
}
- /// Check that we resolve debug altlinks correctly.
+ /// Check that we can discover debug sup as expected.
#[test]
- fn debug_altlink_resolution() {
+ fn debug_sup_discovery() {
+ let debug_dirs = Vec::new();
+
let path = Path::new(&env!("CARGO_MANIFEST_DIR"))
.join("data")
- .join("test-stable-addrs-stripped-with-altlink.bin");
- let resolver = DwarfResolver::open(&path).unwrap();
- assert!(resolver._altlinkee_parser.is_some());
+ .join("test-stable-addrs-dwarf-only-sup.dbg");
+ let parser = ElfParser::open(&path).unwrap();
+ let debug_sup_parser = try_deref_debug_sup(&parser, &debug_dirs, None).unwrap();
+ assert!(debug_sup_parser.is_some());
- let linkee_path = Path::new(&env!("CARGO_MANIFEST_DIR"))
+ let path = Path::new(&env!("CARGO_MANIFEST_DIR"))
.join("data")
- .join("test-stable-addrs.dwz");
- assert_eq!(
- resolver._altlinkee_parser.as_ref().unwrap().module(),
- Some(linkee_path.as_os_str())
+ .join("test-stable-addrs.bin");
+ let parser = ElfParser::open(&path).unwrap();
+ let debug_sup_parser = try_deref_debug_sup(&parser, &debug_dirs, None).unwrap();
+ assert!(debug_sup_parser.is_none());
+
+ let path = Path::new(&env!("CARGO_MANIFEST_DIR"))
+ .join("data")
+ .join("test-stable-addrs-dwarf-only-broken-sup.dbg");
+ let parser = ElfParser::open(&path).unwrap();
+ let debug_sup_parser = try_deref_debug_sup(&parser, &debug_dirs, None).unwrap();
+ assert!(debug_sup_parser.is_none());
+ }
+
+ /// Check that we resolve debug altlink and debug sup correctly.
+ #[test]
+ fn resolve_sup_file() {
+ fn test(debug_file_name: &str, dwz_file_name: &str) {
+ let path = Path::new(&env!("CARGO_MANIFEST_DIR"))
+ .join("data")
+ .join(debug_file_name);
+ let resolver = DwarfResolver::open(&path).unwrap();
+ assert!(resolver._sup_parser.is_some());
+
+ let linkee_path = Path::new(&env!("CARGO_MANIFEST_DIR"))
+ .join("data")
+ .join(dwz_file_name);
+ assert_eq!(
+ resolver._sup_parser.as_ref().unwrap().module(),
+ Some(linkee_path.as_os_str()),
+ );
+ }
+
+ test(
+ "test-stable-addrs-stripped-with-altlink.bin",
+ "test-stable-addrs.dwz",
+ );
+
+ test(
+ "test-stable-addrs-stripped-with-sup.bin",
+ "test-stable-addrs-dwarf-5.dwz",
);
}
diff --git a/tests/suite/inspect.rs b/tests/suite/inspect.rs
index 2297bf2c3..0a900d722 100644
--- a/tests/suite/inspect.rs
+++ b/tests/suite/inspect.rs
@@ -383,10 +383,11 @@ fn inspect_elf_all_symbols_without_duplicates() {
assert_eq!(syms.iter().filter(|name| *name == "the_answer").count(), 1);
}
-/// Check that we correctly incorporate debug altlink files in the
+
+/// Check that we correctly incorporate debug altlink and debug sup files in the
/// inspection process.
#[test]
-fn inspect_debug_altlink_honoring() {
+fn inspect_sup_file_honoring() {
fn symbol_names(file: &str) -> Vec {
let path = Path::new(&env!("CARGO_MANIFEST_DIR"))
.join("data")
@@ -403,11 +404,23 @@ fn inspect_debug_altlink_honoring() {
names
}
- // The symbol's name lives in the `dwz` multifile and, hence, is only
- // reported if we followed the altlink.
- let names = symbol_names("test-stable-addrs-stripped-with-altlink.bin");
- assert!(names.iter().any(|name| name == "factorial"), "{names:?}");
+ fn test(debug_ok_name: &str, debug_broken_name: &str) {
+ // The symbol's name lives in the `dwz` multifile and, hence, is only
+ // reported if we follow the altlink / sup.
+ let names = symbol_names(debug_ok_name);
+ assert!(names.iter().any(|name| name == "factorial"), "{names:?}");
+
+ let names = symbol_names(debug_broken_name);
+ assert!(!names.iter().any(|name| name == "factorial"), "{names:?}");
+ }
+
+ test(
+ "test-stable-addrs-stripped-with-altlink.bin",
+ "test-stable-addrs-stripped-with-broken-altlink.bin",
+ );
- let names = symbol_names("test-stable-addrs-stripped-with-broken-altlink.bin");
- assert!(!names.iter().any(|name| name == "factorial"), "{names:?}");
+ test(
+ "test-stable-addrs-stripped-with-sup.bin",
+ "test-stable-addrs-stripped-with-broken-sup.bin",
+ );
}