diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 1f75bde..d2708dc 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -20,6 +20,8 @@ jobs: runs-on: ${{matrix.os}} steps: - uses: actions/checkout@v3 + with: + submodules: true - name: Set env (macOS) if: matrix.os == 'macOS-latest' run: | diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..c3723fc --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "testinput"] + path = testinput + url = https://github.com/gimli-rs/object-testfiles diff --git a/Cargo.toml b/Cargo.toml index 94afc44..46acc95 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -75,6 +75,11 @@ name = "output_equivalence" harness = false required-features = ["bin"] +[[test]] +name = "testinput" +harness = false +required-features = ["bin"] + [[test]] name = "correctness" required-features = ["loader", "fallible-iterator"] diff --git a/src/lib.rs b/src/lib.rs index 2d8d055..e12d8ef 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -395,10 +395,10 @@ impl RangeAttributes { } else if let (Some(begin), Some(end)) = (self.low_pc, self.high_pc) { add_range(gimli::Range { begin, end }); } else if let (Some(begin), Some(size)) = (self.low_pc, self.size) { - add_range(gimli::Range { - begin, - end: begin + size, - }); + // If `begin` is a -1 tombstone, this will overflow and the check in + // `add_range` will ignore it. + let end = begin.wrapping_add(size); + add_range(gimli::Range { begin, end }); } Ok(added_any) } diff --git a/testinput b/testinput new file mode 160000 index 0000000..76d453e --- /dev/null +++ b/testinput @@ -0,0 +1 @@ +Subproject commit 76d453e88cdf8cdeecae9283c6b34a834c9977b8 diff --git a/testoutput/dwarf/tombstone-loc-0 b/testoutput/dwarf/tombstone-loc-0 new file mode 100644 index 0000000..d3fab2e --- /dev/null +++ b/testoutput/dwarf/tombstone-loc-0 @@ -0,0 +1,6 @@ +0x0000000000001040 +main +/object/testfiles/dwarf/tombstone.cpp:9 +0x0000000000001044 +main +/object/testfiles/dwarf/tombstone.cpp:14 diff --git a/testoutput/dwarf/tombstone-loc-1 b/testoutput/dwarf/tombstone-loc-1 new file mode 100644 index 0000000..cff434d --- /dev/null +++ b/testoutput/dwarf/tombstone-loc-1 @@ -0,0 +1,6 @@ +0x0000000000001740 +main +/object/testfiles/dwarf/tombstone.cpp:9 +0x0000000000001744 +main +/object/testfiles/dwarf/tombstone.cpp:14 diff --git a/testoutput/dwarf/tombstone-loc-addend b/testoutput/dwarf/tombstone-loc-addend new file mode 100644 index 0000000..e02a70e --- /dev/null +++ b/testoutput/dwarf/tombstone-loc-addend @@ -0,0 +1,12 @@ +0x0000000000000000 +_Z2f1v +/object/testfiles/dwarf/tombstone.cpp:3 +0x0000000000000004 +_Z2f1v +/object/testfiles/dwarf/tombstone.cpp:8 +0x00000000000005a0 +main +/object/testfiles/dwarf/tombstone.cpp:9 +0x00000000000005a4 +main +/object/testfiles/dwarf/tombstone.cpp:14 diff --git a/testoutput/dwarf/tombstone-loc-max b/testoutput/dwarf/tombstone-loc-max new file mode 100644 index 0000000..cff434d --- /dev/null +++ b/testoutput/dwarf/tombstone-loc-max @@ -0,0 +1,6 @@ +0x0000000000001740 +main +/object/testfiles/dwarf/tombstone.cpp:9 +0x0000000000001744 +main +/object/testfiles/dwarf/tombstone.cpp:14 diff --git a/testoutput/dwarf/tombstone-loclists-0 b/testoutput/dwarf/tombstone-loclists-0 new file mode 100644 index 0000000..c1644f0 --- /dev/null +++ b/testoutput/dwarf/tombstone-loclists-0 @@ -0,0 +1,12 @@ +0x0000000000000000 +_Z2f1v +/object/testfiles/dwarf/tombstone.cpp:3 +0x0000000000000004 +_Z2f1v +/object/testfiles/dwarf/tombstone.cpp:8 +0x0000000000001040 +main +/object/testfiles/dwarf/tombstone.cpp:9 +0x0000000000001044 +main +/object/testfiles/dwarf/tombstone.cpp:14 diff --git a/testoutput/dwarf/tombstone-loclists-addend b/testoutput/dwarf/tombstone-loclists-addend new file mode 100644 index 0000000..e02a70e --- /dev/null +++ b/testoutput/dwarf/tombstone-loclists-addend @@ -0,0 +1,12 @@ +0x0000000000000000 +_Z2f1v +/object/testfiles/dwarf/tombstone.cpp:3 +0x0000000000000004 +_Z2f1v +/object/testfiles/dwarf/tombstone.cpp:8 +0x00000000000005a0 +main +/object/testfiles/dwarf/tombstone.cpp:9 +0x00000000000005a4 +main +/object/testfiles/dwarf/tombstone.cpp:14 diff --git a/testoutput/dwarf/tombstone-loclists-max b/testoutput/dwarf/tombstone-loclists-max new file mode 100644 index 0000000..cff434d --- /dev/null +++ b/testoutput/dwarf/tombstone-loclists-max @@ -0,0 +1,6 @@ +0x0000000000001740 +main +/object/testfiles/dwarf/tombstone.cpp:9 +0x0000000000001744 +main +/object/testfiles/dwarf/tombstone.cpp:14 diff --git a/tests/testinput.rs b/tests/testinput.rs new file mode 100644 index 0000000..122e029 --- /dev/null +++ b/tests/testinput.rs @@ -0,0 +1,76 @@ +use std::path::PathBuf; +use std::process::Command; +use std::{env, fs}; + +use libtest_mimic::{Arguments, Failed, Trial}; + +fn main() { + if cfg!(target_os = "windows") { + // Tests don't currently handle newline differences on Windows. + return; + } + + let args = Arguments::from_args(); + libtest_mimic::run(&args, make_tests()).exit(); +} + +fn make_tests() -> Vec { + let testinput = PathBuf::from("testinput/dwarf"); + let testoutput = PathBuf::from("testoutput/dwarf"); + + let mut tests = Vec::new(); + let mut dirs = vec![(testinput, testoutput)]; + while let Some((in_dir, out_dir)) = dirs.pop() { + for entry in out_dir.read_dir().unwrap() { + let entry = entry.unwrap(); + let out_path = entry.path(); + let mut in_path = in_dir.clone(); + in_path.push(entry.file_name()); + + let file_type = entry.file_type().unwrap(); + if file_type.is_dir() { + dirs.push((in_path, out_path)); + } else if file_type.is_file() { + tests.push(Trial::test( + format!("addr2line -e {}", in_path.display()), + move || run_test(in_path, out_path), + )); + } + } + } + tests +} + +fn run_test(in_path: PathBuf, out_path: PathBuf) -> Result<(), Failed> { + let mut exe = env::current_exe().unwrap(); + assert!(exe.pop()); + if exe.file_name().unwrap().to_str().unwrap() == "deps" { + assert!(exe.pop()); + } + exe.push("addr2line"); + assert!(exe.is_file()); + + let mut cmd = Command::new(exe); + cmd.env("RUST_BACKTRACE", "1"); + cmd.arg("--exe").arg(in_path).arg("--all").arg("-afi"); + + let output = cmd.output().unwrap(); + assert!(output.status.success()); + let out_data = output.stdout; + + if env::var_os("ADDR2LINE_TESTOUTPUT_UPDATE").is_some() { + fs::write(out_path, &out_data).unwrap(); + return Ok(()); + } + + let expect_out_data = fs::read(out_path).unwrap(); + if out_data != expect_out_data { + let out_str = String::from_utf8_lossy(&out_data); + let expect_out_str = String::from_utf8_lossy(&expect_out_data); + return Err( + format!("output mismatch\nexpected:\n{expect_out_str}\nactual:\n{out_str}").into(), + ); + } + + Ok(()) +}