From 1b6a04ca5504955c571d1c97504fb45ea0befee4 Mon Sep 17 00:00:00 2001
From: Valentin Popov <valentin@popov.link>
Date: Mon, 8 Jan 2024 01:21:28 +0400
Subject: Initial vendor packages

Signed-off-by: Valentin Popov <valentin@popov.link>
---
 vendor/addr2line/tests/correctness.rs        | 126 +++++++++++++++++++++++++
 vendor/addr2line/tests/output_equivalence.rs | 135 +++++++++++++++++++++++++++
 vendor/addr2line/tests/parse.rs              | 114 ++++++++++++++++++++++
 3 files changed, 375 insertions(+)
 create mode 100644 vendor/addr2line/tests/correctness.rs
 create mode 100644 vendor/addr2line/tests/output_equivalence.rs
 create mode 100644 vendor/addr2line/tests/parse.rs

(limited to 'vendor/addr2line/tests')

diff --git a/vendor/addr2line/tests/correctness.rs b/vendor/addr2line/tests/correctness.rs
new file mode 100644
index 0000000..73ee462
--- /dev/null
+++ b/vendor/addr2line/tests/correctness.rs
@@ -0,0 +1,126 @@
+use addr2line::Context;
+use fallible_iterator::FallibleIterator;
+use findshlibs::{IterationControl, SharedLibrary, TargetSharedLibrary};
+use object::Object;
+use std::borrow::Cow;
+use std::fs::File;
+use std::sync::Arc;
+
+fn find_debuginfo() -> memmap2::Mmap {
+    let path = std::env::current_exe().unwrap();
+    let file = File::open(&path).unwrap();
+    let map = unsafe { memmap2::Mmap::map(&file).unwrap() };
+    let file = &object::File::parse(&*map).unwrap();
+    if let Ok(uuid) = file.mach_uuid() {
+        for candidate in path.parent().unwrap().read_dir().unwrap() {
+            let path = candidate.unwrap().path();
+            if !path.to_str().unwrap().ends_with(".dSYM") {
+                continue;
+            }
+            for candidate in path.join("Contents/Resources/DWARF").read_dir().unwrap() {
+                let path = candidate.unwrap().path();
+                let file = File::open(&path).unwrap();
+                let map = unsafe { memmap2::Mmap::map(&file).unwrap() };
+                let file = &object::File::parse(&*map).unwrap();
+                if file.mach_uuid().unwrap() == uuid {
+                    return map;
+                }
+            }
+        }
+    }
+
+    return map;
+}
+
+#[test]
+fn correctness() {
+    let map = find_debuginfo();
+    let file = &object::File::parse(&*map).unwrap();
+    let module_base = file.relative_address_base();
+
+    let endian = if file.is_little_endian() {
+        gimli::RunTimeEndian::Little
+    } else {
+        gimli::RunTimeEndian::Big
+    };
+
+    fn load_section<'data: 'file, 'file, O, Endian>(
+        id: gimli::SectionId,
+        file: &'file O,
+        endian: Endian,
+    ) -> Result<gimli::EndianArcSlice<Endian>, gimli::Error>
+    where
+        O: object::Object<'data, 'file>,
+        Endian: gimli::Endianity,
+    {
+        use object::ObjectSection;
+
+        let data = file
+            .section_by_name(id.name())
+            .and_then(|section| section.uncompressed_data().ok())
+            .unwrap_or(Cow::Borrowed(&[]));
+        Ok(gimli::EndianArcSlice::new(Arc::from(&*data), endian))
+    }
+
+    let dwarf = gimli::Dwarf::load(|id| load_section(id, file, endian)).unwrap();
+    let ctx = Context::from_dwarf(dwarf).unwrap();
+    let mut split_dwarf_loader = addr2line::builtin_split_dwarf_loader::SplitDwarfLoader::new(
+        |data, endian| gimli::EndianArcSlice::new(Arc::from(&*data), endian),
+        None,
+    );
+
+    let mut bias = None;
+    TargetSharedLibrary::each(|lib| {
+        bias = Some((lib.virtual_memory_bias().0 as u64).wrapping_sub(module_base));
+        IterationControl::Break
+    });
+
+    #[allow(unused_mut)]
+    let mut test = |sym: u64, expected_prefix: &str| {
+        let ip = sym.wrapping_sub(bias.unwrap());
+
+        let frames = ctx.find_frames(ip);
+        let frames = split_dwarf_loader.run(frames).unwrap();
+        let frame = frames.last().unwrap().unwrap();
+        let name = frame.function.as_ref().unwrap().demangle().unwrap();
+        // Old rust versions generate DWARF with wrong linkage name,
+        // so only check the start.
+        if !name.starts_with(expected_prefix) {
+            panic!("incorrect name '{}', expected {:?}", name, expected_prefix);
+        }
+    };
+
+    test(test_function as u64, "correctness::test_function");
+    test(
+        small::test_function as u64,
+        "correctness::small::test_function",
+    );
+    test(auxiliary::foo as u64, "auxiliary::foo");
+}
+
+mod small {
+    pub fn test_function() {
+        println!("y");
+    }
+}
+
+fn test_function() {
+    println!("x");
+}
+
+#[test]
+fn zero_function() {
+    let map = find_debuginfo();
+    let file = &object::File::parse(&*map).unwrap();
+    let ctx = Context::new(file).unwrap();
+    for probe in 0..10 {
+        assert!(
+            ctx.find_frames(probe)
+                .skip_all_loads()
+                .unwrap()
+                .count()
+                .unwrap()
+                < 10
+        );
+    }
+}
diff --git a/vendor/addr2line/tests/output_equivalence.rs b/vendor/addr2line/tests/output_equivalence.rs
new file mode 100644
index 0000000..ef026e3
--- /dev/null
+++ b/vendor/addr2line/tests/output_equivalence.rs
@@ -0,0 +1,135 @@
+use std::env;
+use std::ffi::OsStr;
+use std::path::Path;
+use std::process::Command;
+
+use backtrace::Backtrace;
+use findshlibs::{IterationControl, SharedLibrary, TargetSharedLibrary};
+use libtest_mimic::{Arguments, Failed, Trial};
+
+#[inline(never)]
+fn make_trace() -> Vec<String> {
+    fn foo() -> Backtrace {
+        bar()
+    }
+    #[inline(never)]
+    fn bar() -> Backtrace {
+        baz()
+    }
+    #[inline(always)]
+    fn baz() -> Backtrace {
+        Backtrace::new_unresolved()
+    }
+
+    let mut base_addr = None;
+    TargetSharedLibrary::each(|lib| {
+        base_addr = Some(lib.virtual_memory_bias().0 as isize);
+        IterationControl::Break
+    });
+    let addrfix = -base_addr.unwrap();
+
+    let trace = foo();
+    trace
+        .frames()
+        .iter()
+        .take(5)
+        .map(|x| format!("{:p}", (x.ip() as *const u8).wrapping_offset(addrfix)))
+        .collect()
+}
+
+fn run_cmd<P: AsRef<OsStr>>(exe: P, me: &Path, flags: Option<&str>, trace: &str) -> String {
+    let mut cmd = Command::new(exe);
+    cmd.env("LC_ALL", "C"); // GNU addr2line is localized, we aren't
+    cmd.env("RUST_BACKTRACE", "1"); // if a child crashes, we want to know why
+
+    if let Some(flags) = flags {
+        cmd.arg(flags);
+    }
+    cmd.arg("--exe").arg(me).arg(trace);
+
+    let output = cmd.output().unwrap();
+
+    assert!(output.status.success());
+    String::from_utf8(output.stdout).unwrap()
+}
+
+fn run_test(flags: Option<&str>) -> Result<(), Failed> {
+    let me = env::current_exe().unwrap();
+    let mut exe = me.clone();
+    assert!(exe.pop());
+    if exe.file_name().unwrap().to_str().unwrap() == "deps" {
+        assert!(exe.pop());
+    }
+    exe.push("examples");
+    exe.push("addr2line");
+
+    assert!(exe.is_file());
+
+    let trace = make_trace();
+
+    // HACK: GNU addr2line has a bug where looking up multiple addresses can cause the second
+    // lookup to fail. Workaround by doing one address at a time.
+    for addr in &trace {
+        let theirs = run_cmd("addr2line", &me, flags, addr);
+        let ours = run_cmd(&exe, &me, flags, addr);
+
+        // HACK: GNU addr2line does not tidy up paths properly, causing double slashes to be printed.
+        // We consider our behavior to be correct, so we fix their output to match ours.
+        let theirs = theirs.replace("//", "/");
+
+        assert!(
+            theirs == ours,
+            "Output not equivalent:
+
+$ addr2line {0} --exe {1} {2}
+{4}
+$ {3} {0} --exe {1} {2}
+{5}
+
+
+",
+            flags.unwrap_or(""),
+            me.display(),
+            trace.join(" "),
+            exe.display(),
+            theirs,
+            ours
+        );
+    }
+    Ok(())
+}
+
+static FLAGS: &str = "aipsf";
+
+fn make_tests() -> Vec<Trial> {
+    (0..(1 << FLAGS.len()))
+        .map(|bits| {
+            if bits == 0 {
+                None
+            } else {
+                let mut param = String::new();
+                param.push('-');
+                for (i, flag) in FLAGS.chars().enumerate() {
+                    if (bits & (1 << i)) != 0 {
+                        param.push(flag);
+                    }
+                }
+                Some(param)
+            }
+        })
+        .map(|param| {
+            Trial::test(
+                format!("addr2line {}", param.as_ref().map_or("", String::as_str)),
+                move || run_test(param.as_ref().map(String::as_str)),
+            )
+        })
+        .collect()
+}
+
+fn main() {
+    if !cfg!(target_os = "linux") {
+        return;
+    }
+    let args = Arguments::from_args();
+    libtest_mimic::run(&args, make_tests()).exit();
+}
diff --git a/vendor/addr2line/tests/parse.rs b/vendor/addr2line/tests/parse.rs
new file mode 100644
index 0000000..4dafe38
--- /dev/null
+++ b/vendor/addr2line/tests/parse.rs
@@ -0,0 +1,114 @@
+use std::borrow::Cow;
+use std::env;
+use std::fs::File;
+use std::path::{self, PathBuf};
+
+use object::Object;
+
+fn release_fixture_path() -> PathBuf {
+    if let Ok(p) = env::var("ADDR2LINE_FIXTURE_PATH") {
+        return p.into();
+    }
+
+    let mut path = PathBuf::new();
+    if let Ok(dir) = env::var("CARGO_MANIFEST_DIR") {
+        path.push(dir);
+    }
+    path.push("fixtures");
+    path.push("addr2line-release");
+    path
+}
+
+fn with_file<F: FnOnce(&object::File<'_>)>(target: &path::Path, f: F) {
+    let file = File::open(target).unwrap();
+    let map = unsafe { memmap2::Mmap::map(&file).unwrap() };
+    let file = object::File::parse(&*map).unwrap();
+    f(&file)
+}
+
+fn dwarf_load<'a>(object: &object::File<'a>) -> gimli::Dwarf<Cow<'a, [u8]>> {
+    let load_section = |id: gimli::SectionId| -> Result<Cow<'a, [u8]>, gimli::Error> {
+        use object::ObjectSection;
+
+        let data = object
+            .section_by_name(id.name())
+            .and_then(|section| section.data().ok())
+            .unwrap_or(&[][..]);
+        Ok(Cow::Borrowed(data))
+    };
+    gimli::Dwarf::load(&load_section).unwrap()
+}
+
+fn dwarf_borrow<'a>(
+    dwarf: &'a gimli::Dwarf<Cow<'_, [u8]>>,
+) -> gimli::Dwarf<gimli::EndianSlice<'a, gimli::LittleEndian>> {
+    let borrow_section: &dyn for<'b> Fn(
+        &'b Cow<'_, [u8]>,
+    ) -> gimli::EndianSlice<'b, gimli::LittleEndian> =
+        &|section| gimli::EndianSlice::new(section, gimli::LittleEndian);
+    dwarf.borrow(&borrow_section)
+}
+
+#[test]
+fn parse_base_rc() {
+    let target = release_fixture_path();
+
+    with_file(&target, |file| {
+        addr2line::ObjectContext::new(file).unwrap();
+    });
+}
+
+#[test]
+fn parse_base_slice() {
+    let target = release_fixture_path();
+
+    with_file(&target, |file| {
+        let dwarf = dwarf_load(file);
+        let dwarf = dwarf_borrow(&dwarf);
+        addr2line::Context::from_dwarf(dwarf).unwrap();
+    });
+}
+
+#[test]
+fn parse_lines_rc() {
+    let target = release_fixture_path();
+
+    with_file(&target, |file| {
+        let context = addr2line::ObjectContext::new(file).unwrap();
+        context.parse_lines().unwrap();
+    });
+}
+
+#[test]
+fn parse_lines_slice() {
+    let target = release_fixture_path();
+
+    with_file(&target, |file| {
+        let dwarf = dwarf_load(file);
+        let dwarf = dwarf_borrow(&dwarf);
+        let context = addr2line::Context::from_dwarf(dwarf).unwrap();
+        context.parse_lines().unwrap();
+    });
+}
+
+#[test]
+fn parse_functions_rc() {
+    let target = release_fixture_path();
+
+    with_file(&target, |file| {
+        let context = addr2line::ObjectContext::new(file).unwrap();
+        context.parse_functions().unwrap();
+    });
+}
+
+#[test]
+fn parse_functions_slice() {
+    let target = release_fixture_path();
+
+    with_file(&target, |file| {
+        let dwarf = dwarf_load(file);
+        let dwarf = dwarf_borrow(&dwarf);
+        let context = addr2line::Context::from_dwarf(dwarf).unwrap();
+        context.parse_functions().unwrap();
+    });
+}
-- 
cgit v1.2.3