summaryrefslogtreecommitdiffstats
path: root/vendor/addr2line
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
commit698f8c2f01ea549d77d7dc3338a12e04c11057b9 (patch)
tree173a775858bd501c378080a10dca74132f05bc50 /vendor/addr2line
parentInitial commit. (diff)
downloadrustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.tar.xz
rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.zip
Adding upstream version 1.64.0+dfsg1.upstream/1.64.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/addr2line')
-rw-r--r--vendor/addr2line/.cargo-checksum.json1
-rw-r--r--vendor/addr2line/CHANGELOG.md260
-rw-r--r--vendor/addr2line/Cargo.lock430
-rw-r--r--vendor/addr2line/Cargo.toml120
-rw-r--r--vendor/addr2line/LICENSE-APACHE201
-rw-r--r--vendor/addr2line/LICENSE-MIT25
-rw-r--r--vendor/addr2line/README.md48
-rw-r--r--vendor/addr2line/bench.plot.r23
-rwxr-xr-xvendor/addr2line/benchmark.sh112
-rw-r--r--vendor/addr2line/coverage.sh5
-rw-r--r--vendor/addr2line/examples/addr2line.rs299
-rw-r--r--vendor/addr2line/rustfmt.toml1
-rw-r--r--vendor/addr2line/src/function.rs520
-rw-r--r--vendor/addr2line/src/lazy.rs29
-rw-r--r--vendor/addr2line/src/lib.rs1192
-rw-r--r--vendor/addr2line/tests/correctness.rs91
-rw-r--r--vendor/addr2line/tests/output_equivalence.rs145
-rw-r--r--vendor/addr2line/tests/parse.rs118
18 files changed, 3620 insertions, 0 deletions
diff --git a/vendor/addr2line/.cargo-checksum.json b/vendor/addr2line/.cargo-checksum.json
new file mode 100644
index 000000000..b43ad3bbf
--- /dev/null
+++ b/vendor/addr2line/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"CHANGELOG.md":"d4ef249a0a4eff26a34a1f847a3c367dfd9988b4da972ac9c16b1d258b62ad87","Cargo.lock":"290a48d58d1ebfef0f5eaec66191f6c1a41080b89e10e931c6984052008479ab","Cargo.toml":"68243a813e2e6ba40d3e939b9ade5489b3f39a58d7dc391ae447a60591315f4a","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"e99d88d232bf57d70f0fb87f6b496d44b6653f99f8a63d250a54c61ea4bcde40","README.md":"76d28502bd2e83f6a9e3576bd45e9a7fe5308448c4b5384b0d249515b5f67a5c","bench.plot.r":"6a5d7a4d36ed6b3d9919be703a479bef47698bf947818b483ff03951df2d4e01","benchmark.sh":"b35f89b1ca2c1dc0476cdd07f0284b72d41920d1c7b6054072f50ffba296d78d","coverage.sh":"4677e81922d08a82e83068a911717a247c66af12e559f37b78b6be3337ac9f07","examples/addr2line.rs":"75ef29e1d07d49d247990ad970892d64f629766bafa36afddff5a88976e58060","rustfmt.toml":"01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b","src/function.rs":"395f37cdf03201d416d66bc11abeea627be0abb4585104acd927224a26cb9369","src/lazy.rs":"14ec61761369c21d426673f549c21394221533f444b68cd2a8370952eb19f345","src/lib.rs":"5696c0aee67df576f78935c66bb124f4e5fa19cbc9b25faf8f750e7e8dda113c","tests/correctness.rs":"c9325ffdec577bf5e56f5dd72fdff4927153d0a4c34c0fda5aefaeb44a8d26fd","tests/output_equivalence.rs":"38d7b585b7a2ca43b07eef6b34c11f489d1deae138a010123c33188dfb881c11","tests/parse.rs":"9e421ea9d9348721f6c6533cdba1db5b84287fc685f870c7905dea06b596b4db"},"package":"b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b"} \ No newline at end of file
diff --git a/vendor/addr2line/CHANGELOG.md b/vendor/addr2line/CHANGELOG.md
new file mode 100644
index 000000000..914139400
--- /dev/null
+++ b/vendor/addr2line/CHANGELOG.md
@@ -0,0 +1,260 @@
+## 0.17.0 (2021/10/24)
+
+### Breaking changes
+
+* Updated `gimli` and `object` dependencies.
+
+### Changed
+
+* Use `skip_attributes` to improve performance.
+ [#236](https://github.com/gimli-rs/addr2line/pull/236)
+
+--------------------------------------------------------------------------------
+
+## 0.16.0 (2021/07/26)
+
+### Breaking changes
+
+* Updated `gimli` and `object` dependencies.
+
+--------------------------------------------------------------------------------
+
+## 0.15.2 (2021/06/04)
+
+### Fixed
+
+* Allow `Context` to be `Send`.
+ [#219](https://github.com/gimli-rs/addr2line/pull/219)
+
+--------------------------------------------------------------------------------
+
+## 0.15.1 (2021/05/02)
+
+### Fixed
+
+* Don't ignore aranges with address 0.
+ [#217](https://github.com/gimli-rs/addr2line/pull/217)
+
+--------------------------------------------------------------------------------
+
+## 0.15.0 (2021/05/02)
+
+### Breaking changes
+
+* Updated `gimli` and `object` dependencies.
+ [#215](https://github.com/gimli-rs/addr2line/pull/215)
+
+* Added `debug_aranges` parameter to `Context::from_sections`.
+ [#200](https://github.com/gimli-rs/addr2line/pull/200)
+
+### Added
+
+* Added `.debug_aranges` support.
+ [#200](https://github.com/gimli-rs/addr2line/pull/200)
+
+* Added supplementary object file support.
+ [#208](https://github.com/gimli-rs/addr2line/pull/208)
+
+### Fixed
+
+* Fixed handling of Windows paths in locations.
+ [#209](https://github.com/gimli-rs/addr2line/pull/209)
+
+* examples/addr2line: Flush stdout after each response.
+ [#210](https://github.com/gimli-rs/addr2line/pull/210)
+
+* examples/addr2line: Avoid copying every section.
+ [#213](https://github.com/gimli-rs/addr2line/pull/213)
+
+--------------------------------------------------------------------------------
+
+## 0.14.1 (2020/12/31)
+
+### Fixed
+
+* Fix location lookup for skeleton units.
+ [#201](https://github.com/gimli-rs/addr2line/pull/201)
+
+### Added
+
+* Added `Context::find_location_range`.
+ [#196](https://github.com/gimli-rs/addr2line/pull/196)
+ [#199](https://github.com/gimli-rs/addr2line/pull/199)
+
+--------------------------------------------------------------------------------
+
+## 0.14.0 (2020/10/27)
+
+### Breaking changes
+
+* Updated `gimli` and `object` dependencies.
+
+### Fixed
+
+* Handle units that only have line information.
+ [#188](https://github.com/gimli-rs/addr2line/pull/188)
+
+* Handle DWARF units with version <= 4 and no `DW_AT_name`.
+ [#191](https://github.com/gimli-rs/addr2line/pull/191)
+
+* Fix handling of `DW_FORM_ref_addr`.
+ [#193](https://github.com/gimli-rs/addr2line/pull/193)
+
+--------------------------------------------------------------------------------
+
+## 0.13.0 (2020/07/07)
+
+### Breaking changes
+
+* Updated `gimli` and `object` dependencies.
+
+* Added `rustc-dep-of-std` feature.
+ [#166](https://github.com/gimli-rs/addr2line/pull/166)
+
+### Changed
+
+* Improve performance by parsing function contents lazily.
+ [#178](https://github.com/gimli-rs/addr2line/pull/178)
+
+* Don't skip `.debug_info` and `.debug_line` entries with a zero address.
+ [#182](https://github.com/gimli-rs/addr2line/pull/182)
+
+--------------------------------------------------------------------------------
+
+## 0.12.2 (2020/06/21)
+
+### Fixed
+
+* Avoid linear search for `DW_FORM_ref_addr`.
+ [#175](https://github.com/gimli-rs/addr2line/pull/175)
+
+--------------------------------------------------------------------------------
+
+## 0.12.1 (2020/05/19)
+
+### Fixed
+
+* Handle units with overlapping address ranges.
+ [#163](https://github.com/gimli-rs/addr2line/pull/163)
+
+* Don't assert for functions with overlapping address ranges.
+ [#168](https://github.com/gimli-rs/addr2line/pull/168)
+
+--------------------------------------------------------------------------------
+
+## 0.12.0 (2020/05/12)
+
+### Breaking changes
+
+* Updated `gimli` and `object` dependencies.
+
+* Added more optional features: `smallvec` and `fallible-iterator`.
+ [#160](https://github.com/gimli-rs/addr2line/pull/160)
+
+### Added
+
+* Added `Context::dwarf` and `Context::find_dwarf_unit`.
+ [#159](https://github.com/gimli-rs/addr2line/pull/159)
+
+### Changed
+
+* Removed `lazycell` dependency.
+ [#160](https://github.com/gimli-rs/addr2line/pull/160)
+
+--------------------------------------------------------------------------------
+
+## 0.11.0 (2020/01/11)
+
+### Breaking changes
+
+* Updated `gimli` and `object` dependencies.
+
+* [#130](https://github.com/gimli-rs/addr2line/pull/130)
+ Changed `Location::file` from `Option<String>` to `Option<&str>`.
+ This required adding lifetime parameters to `Location` and other structs that
+ contain it.
+
+* [#152](https://github.com/gimli-rs/addr2line/pull/152)
+ Changed `Location::line` and `Location::column` from `Option<u64>`to `Option<u32>`.
+
+* [#156](https://github.com/gimli-rs/addr2line/pull/156)
+ Deleted `alloc` feature, and fixed `no-std` builds with stable rust.
+ Removed default `Reader` parameter for `Context`, and added `ObjectContext` instead.
+
+### Added
+
+* [#134](https://github.com/gimli-rs/addr2line/pull/134)
+ Added `Context::from_dwarf`.
+
+### Changed
+
+* [#133](https://github.com/gimli-rs/addr2line/pull/133)
+ Fixed handling of units that can't be parsed.
+
+* [#155](https://github.com/gimli-rs/addr2line/pull/155)
+ Fixed `addr2line` output to match binutils.
+
+* [#130](https://github.com/gimli-rs/addr2line/pull/130)
+ Improved `.debug_line` parsing performance.
+
+* [#148](https://github.com/gimli-rs/addr2line/pull/148)
+ [#150](https://github.com/gimli-rs/addr2line/pull/150)
+ [#151](https://github.com/gimli-rs/addr2line/pull/151)
+ [#152](https://github.com/gimli-rs/addr2line/pull/152)
+ Improved `.debug_info` parsing performance.
+
+* [#137](https://github.com/gimli-rs/addr2line/pull/137)
+ [#138](https://github.com/gimli-rs/addr2line/pull/138)
+ [#139](https://github.com/gimli-rs/addr2line/pull/139)
+ [#140](https://github.com/gimli-rs/addr2line/pull/140)
+ [#146](https://github.com/gimli-rs/addr2line/pull/146)
+ Improved benchmarks.
+
+--------------------------------------------------------------------------------
+
+## 0.10.0 (2019/07/07)
+
+### Breaking changes
+
+* [#127](https://github.com/gimli-rs/addr2line/pull/127)
+ Update `gimli`.
+
+--------------------------------------------------------------------------------
+
+## 0.9.0 (2019/05/02)
+
+### Breaking changes
+
+* [#121](https://github.com/gimli-rs/addr2line/pull/121)
+ Update `gimli`, `object`, and `fallible-iterator` dependencies.
+
+### Added
+
+* [#121](https://github.com/gimli-rs/addr2line/pull/121)
+ Reexport `gimli`, `object`, and `fallible-iterator`.
+
+--------------------------------------------------------------------------------
+
+## 0.8.0 (2019/02/06)
+
+### Breaking changes
+
+* [#107](https://github.com/gimli-rs/addr2line/pull/107)
+ Update `object` dependency to 0.11. This is part of the public API.
+
+### Added
+
+* [#101](https://github.com/gimli-rs/addr2line/pull/101)
+ Add `object` feature (enabled by default). Disable this feature to remove
+ the `object` dependency and `Context::new` API.
+
+* [#102](https://github.com/gimli-rs/addr2line/pull/102)
+ Add `std` (enabled by default) and `alloc` features.
+
+### Changed
+
+* [#108](https://github.com/gimli-rs/addr2line/issues/108)
+ `demangle` no longer ouputs the hash for rust symbols.
+
+* [#109](https://github.com/gimli-rs/addr2line/issues/109)
+ Set default `R` for `Context<R>`.
diff --git a/vendor/addr2line/Cargo.lock b/vendor/addr2line/Cargo.lock
new file mode 100644
index 000000000..630d72438
--- /dev/null
+++ b/vendor/addr2line/Cargo.lock
@@ -0,0 +1,430 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "addr2line"
+version = "0.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3e61f2b7f93d2c7d2b08263acaa4a363b3e276806c68af6134c44f523bf1aacd"
+dependencies = [
+ "gimli 0.25.0",
+]
+
+[[package]]
+name = "addr2line"
+version = "0.17.0"
+dependencies = [
+ "backtrace",
+ "clap",
+ "compiler_builtins",
+ "cpp_demangle",
+ "fallible-iterator",
+ "findshlibs",
+ "gimli 0.26.0",
+ "memmap",
+ "object",
+ "rustc-demangle",
+ "rustc-std-workspace-alloc",
+ "rustc-std-workspace-core",
+ "rustc-test",
+ "smallvec",
+ "typed-arena",
+]
+
+[[package]]
+name = "adler"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
+
+[[package]]
+name = "ansi_term"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
+dependencies = [
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "atty"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
+dependencies = [
+ "hermit-abi",
+ "libc",
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
+
+[[package]]
+name = "backtrace"
+version = "0.3.62"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "091bcdf2da9950f96aa522681ce805e6857f6ca8df73833d35736ab2dc78e152"
+dependencies = [
+ "addr2line 0.16.0",
+ "cc",
+ "cfg-if",
+ "libc",
+ "miniz_oxide",
+ "object",
+ "rustc-demangle",
+]
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "cc"
+version = "1.0.71"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "79c2681d6594606957bbb8631c4b90a7fcaaa72cdb714743a437b156d6a7eedd"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "clap"
+version = "2.33.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
+dependencies = [
+ "ansi_term",
+ "atty",
+ "bitflags",
+ "strsim",
+ "textwrap",
+ "unicode-width",
+ "vec_map",
+]
+
+[[package]]
+name = "compiler_builtins"
+version = "0.1.51"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3587b3669d6f2c1cfd34c475272dabcfef29d52703933f6f72ebb36d6bd81a97"
+
+[[package]]
+name = "cpp_demangle"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ea47428dc9d2237f3c6bc134472edfd63ebba0af932e783506dcfd66f10d18a"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "crc32fast"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "fallible-iterator"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
+
+[[package]]
+name = "findshlibs"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d691fdb3f817632d259d09220d4cf0991dbb2c9e59e044a02a59194bf6e14484"
+dependencies = [
+ "cc",
+ "lazy_static",
+ "libc",
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "flate2"
+version = "1.0.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f"
+dependencies = [
+ "cfg-if",
+ "crc32fast",
+ "libc",
+ "miniz_oxide",
+]
+
+[[package]]
+name = "getopts"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
+dependencies = [
+ "unicode-width",
+]
+
+[[package]]
+name = "gimli"
+version = "0.25.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0a01e0497841a3b2db4f8afa483cce65f7e96a3498bd6c541734792aeac8fe7"
+
+[[package]]
+name = "gimli"
+version = "0.26.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81a03ce013ffccead76c11a15751231f777d9295b845cc1266ed4d34fcbd7977"
+dependencies = [
+ "compiler_builtins",
+ "fallible-iterator",
+ "rustc-std-workspace-alloc",
+ "rustc-std-workspace-core",
+ "stable_deref_trait",
+]
+
+[[package]]
+name = "hermit-abi"
+version = "0.1.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "kernel32-sys"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
+dependencies = [
+ "winapi 0.2.8",
+ "winapi-build",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+
+[[package]]
+name = "libc"
+version = "0.2.105"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "869d572136620d55835903746bcb5cdc54cb2851fd0aeec53220b4bb65ef3013"
+
+[[package]]
+name = "memchr"
+version = "2.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
+
+[[package]]
+name = "memmap"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
+dependencies = [
+ "libc",
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "miniz_oxide"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b"
+dependencies = [
+ "adler",
+ "autocfg",
+]
+
+[[package]]
+name = "object"
+version = "0.27.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9"
+dependencies = [
+ "flate2",
+ "memchr",
+]
+
+[[package]]
+name = "rustc-demangle"
+version = "0.1.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
+
+[[package]]
+name = "rustc-serialize"
+version = "0.3.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
+
+[[package]]
+name = "rustc-std-workspace-alloc"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff66d57013a5686e1917ed6a025d54dd591fcda71a41fe07edf4d16726aefa86"
+
+[[package]]
+name = "rustc-std-workspace-core"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1956f5517128a2b6f23ab2dadf1a976f4f5b27962e7724c2bf3d45e539ec098c"
+
+[[package]]
+name = "rustc-test"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aacc7967b0ae83af208c8caf2781cbf96f01dac0157cd89f7f05324d6d4e59bb"
+dependencies = [
+ "getopts",
+ "libc",
+ "rustc-serialize",
+ "rustc_version",
+ "term",
+ "time",
+]
+
+[[package]]
+name = "rustc_version"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
+dependencies = [
+ "semver",
+]
+
+[[package]]
+name = "semver"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
+dependencies = [
+ "semver-parser",
+]
+
+[[package]]
+name = "semver-parser"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
+
+[[package]]
+name = "smallvec"
+version = "1.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309"
+
+[[package]]
+name = "stable_deref_trait"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
+
+[[package]]
+name = "strsim"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
+
+[[package]]
+name = "term"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1"
+dependencies = [
+ "kernel32-sys",
+ "winapi 0.2.8",
+]
+
+[[package]]
+name = "textwrap"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
+dependencies = [
+ "unicode-width",
+]
+
+[[package]]
+name = "time"
+version = "0.1.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
+dependencies = [
+ "libc",
+ "wasi",
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "typed-arena"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0685c84d5d54d1c26f7d3eb96cd41550adb97baed141a761cf335d3d33bcd0ae"
+
+[[package]]
+name = "unicode-width"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
+
+[[package]]
+name = "vec_map"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
+
+[[package]]
+name = "wasi"
+version = "0.10.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
+
+[[package]]
+name = "winapi"
+version = "0.2.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-build"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
diff --git a/vendor/addr2line/Cargo.toml b/vendor/addr2line/Cargo.toml
new file mode 100644
index 000000000..358995e53
--- /dev/null
+++ b/vendor/addr2line/Cargo.toml
@@ -0,0 +1,120 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies
+#
+# If you believe there's an error in this file please file an
+# issue against the rust-lang/cargo repository. If you're
+# editing this file be aware that the upstream Cargo.toml
+# will likely look very different (and much more reasonable)
+
+[package]
+name = "addr2line"
+version = "0.17.0"
+exclude = ["/benches/*", "/fixtures/*", ".github"]
+description = "A cross-platform symbolication library written in Rust, using `gimli`"
+documentation = "https://docs.rs/addr2line"
+readme = "./README.md"
+keywords = ["DWARF", "debug", "elf", "symbolicate", "atos"]
+categories = ["development-tools::debugging"]
+license = "Apache-2.0 OR MIT"
+repository = "https://github.com/gimli-rs/addr2line"
+[profile.bench]
+codegen-units = 1
+debug = true
+split-debuginfo = "packed"
+
+[profile.dev]
+split-debuginfo = "packed"
+
+[profile.release]
+debug = true
+split-debuginfo = "packed"
+
+[profile.test]
+split-debuginfo = "packed"
+
+[[example]]
+name = "addr2line"
+required-features = ["std-object"]
+
+[[test]]
+name = "output_equivalence"
+harness = false
+required-features = ["std-object"]
+
+[[test]]
+name = "correctness"
+required-features = ["default"]
+
+[[test]]
+name = "parse"
+required-features = ["std-object"]
+[dependencies.alloc]
+version = "1.0.0"
+optional = true
+package = "rustc-std-workspace-alloc"
+
+[dependencies.compiler_builtins]
+version = "0.1.2"
+optional = true
+
+[dependencies.core]
+version = "1.0.0"
+optional = true
+package = "rustc-std-workspace-core"
+
+[dependencies.cpp_demangle]
+version = "0.3"
+optional = true
+default-features = false
+
+[dependencies.fallible-iterator]
+version = "0.2"
+optional = true
+default-features = false
+
+[dependencies.gimli]
+version = "0.26"
+features = ["read"]
+default-features = false
+
+[dependencies.object]
+version = "0.27.1"
+features = ["read"]
+optional = true
+default-features = false
+
+[dependencies.rustc-demangle]
+version = "0.1"
+optional = true
+
+[dependencies.smallvec]
+version = "1"
+optional = true
+default-features = false
+[dev-dependencies.backtrace]
+version = "0.3.13"
+
+[dev-dependencies.clap]
+version = "2"
+
+[dev-dependencies.findshlibs]
+version = "0.10"
+
+[dev-dependencies.memmap]
+version = "0.7"
+
+[dev-dependencies.rustc-test]
+version = "0.3"
+
+[dev-dependencies.typed-arena]
+version = "2"
+
+[features]
+default = ["rustc-demangle", "cpp_demangle", "std-object", "fallible-iterator", "smallvec"]
+rustc-dep-of-std = ["core", "alloc", "compiler_builtins", "gimli/rustc-dep-of-std"]
+std = ["gimli/std"]
+std-object = ["std", "object", "object/std", "object/compression", "gimli/endian-reader"]
diff --git a/vendor/addr2line/LICENSE-APACHE b/vendor/addr2line/LICENSE-APACHE
new file mode 100644
index 000000000..16fe87b06
--- /dev/null
+++ b/vendor/addr2line/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/vendor/addr2line/LICENSE-MIT b/vendor/addr2line/LICENSE-MIT
new file mode 100644
index 000000000..3a03f1f85
--- /dev/null
+++ b/vendor/addr2line/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2016-2018 The gimli Developers
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/vendor/addr2line/README.md b/vendor/addr2line/README.md
new file mode 100644
index 000000000..dc6cb9344
--- /dev/null
+++ b/vendor/addr2line/README.md
@@ -0,0 +1,48 @@
+# addr2line
+
+[![](https://img.shields.io/crates/v/addr2line.svg)](https://crates.io/crates/addr2line)
+[![](https://img.shields.io/docsrs/addr2line.svg)](https://docs.rs/addr2line)
+[![Coverage Status](https://coveralls.io/repos/github/gimli-rs/addr2line/badge.svg?branch=master)](https://coveralls.io/github/gimli-rs/addr2line?branch=master)
+
+A cross-platform library for retrieving per-address debug information
+from files with DWARF debug information.
+
+`addr2line` uses [`gimli`](https://github.com/gimli-rs/gimli) to parse
+the debug information, and exposes an interface for finding
+the source file, line number, and wrapping function for instruction
+addresses within the target program. These lookups can either be
+performed programmatically through `Context::find_location` and
+`Context::find_frames`, or via the included example binary,
+`addr2line` (named and modelled after the equivalent utility from
+[GNU binutils](https://sourceware.org/binutils/docs/binutils/addr2line.html)).
+
+# Quickstart
+ - Add the [`addr2line` crate](https://crates.io/crates/addr2line) to your `Cargo.toml`
+ - Load the file and parse it with [`addr2line::object::read::File::parse`](https://docs.rs/object/*/object/read/struct.File.html#method.parse)
+ - Pass the parsed file to [`addr2line::Context::new` ](https://docs.rs/addr2line/*/addr2line/struct.Context.html#method.new)
+ - Use [`addr2line::Context::find_location`](https://docs.rs/addr2line/*/addr2line/struct.Context.html#method.find_location)
+ or [`addr2line::Context::find_frames`](https://docs.rs/addr2line/*/addr2line/struct.Context.html#method.find_frames)
+ to look up debug information for an address
+
+# Performance
+
+`addr2line` optimizes for speed over memory by caching parsed information.
+The DWARF information is parsed lazily where possible.
+
+The library aims to perform similarly to equivalent existing tools such
+as `addr2line` from binutils, `eu-addr2line` from elfutils, and
+`llvm-symbolize` from the llvm project, and in the past some benchmarking
+was done that indicates a comparable performance.
+
+## License
+
+Licensed under either of
+
+ * Apache License, Version 2.0 ([`LICENSE-APACHE`](./LICENSE-APACHE) or https://www.apache.org/licenses/LICENSE-2.0)
+ * MIT license ([`LICENSE-MIT`](./LICENSE-MIT) or https://opensource.org/licenses/MIT)
+
+at your option.
+
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
+dual licensed as above, without any additional terms or conditions.
diff --git a/vendor/addr2line/bench.plot.r b/vendor/addr2line/bench.plot.r
new file mode 100644
index 000000000..ecbf24893
--- /dev/null
+++ b/vendor/addr2line/bench.plot.r
@@ -0,0 +1,23 @@
+v <- read.table(file("stdin"))
+t <- data.frame(prog=v[,1], funcs=(v[,2]=="func"), time=v[,3], mem=v[,4], stringsAsFactors=FALSE)
+
+t$prog <- as.character(t$prog)
+t$prog[t$prog == "master"] <- "gimli-rs/addr2line"
+t$funcs[t$funcs == TRUE] <- "With functions"
+t$funcs[t$funcs == FALSE] <- "File/line only"
+t$mem = t$mem / 1024.0
+
+library(ggplot2)
+p <- ggplot(data=t, aes(x=prog, y=time, fill=prog))
+p <- p + geom_bar(stat = "identity")
+p <- p + facet_wrap(~ funcs)
+p <- p + theme(axis.title.x=element_blank(), axis.text.x=element_blank(), axis.ticks.x=element_blank())
+p <- p + ylab("time (s)") + ggtitle("addr2line runtime")
+ggsave('time.png',plot=p,width=10,height=6)
+
+p <- ggplot(data=t, aes(x=prog, y=mem, fill=prog))
+p <- p + geom_bar(stat = "identity")
+p <- p + facet_wrap(~ funcs)
+p <- p + theme(axis.title.x=element_blank(), axis.text.x=element_blank(), axis.ticks.x=element_blank())
+p <- p + ylab("memory (kB)") + ggtitle("addr2line memory usage")
+ggsave('memory.png',plot=p,width=10,height=6)
diff --git a/vendor/addr2line/benchmark.sh b/vendor/addr2line/benchmark.sh
new file mode 100755
index 000000000..ca4c4f6ec
--- /dev/null
+++ b/vendor/addr2line/benchmark.sh
@@ -0,0 +1,112 @@
+#!/bin/bash
+if [[ $# -le 1 ]]; then
+ echo "Usage: $0 <executable> [<addresses>] REFS..."
+ exit 1
+fi
+target="$1"
+shift
+
+addresses=""
+if [[ -e "$1" ]]; then
+ addresses="$1"
+ shift
+fi
+
+# path to "us"
+# readlink -f, but more portable:
+dirname=$(perl -e 'use Cwd "abs_path";print abs_path(shift)' "$(dirname "$0")")
+
+# https://stackoverflow.com/a/2358432/472927
+{
+ # compile all refs
+ pushd "$dirname" > /dev/null
+ # if the user has some local changes, preserve them
+ nstashed=$(git stash list | wc -l)
+ echo "==> Stashing any local modifications"
+ git stash --keep-index > /dev/null
+ popstash() {
+ # https://stackoverflow.com/q/24520791/472927
+ if [[ "$(git stash list | wc -l)" -ne "$nstashed" ]]; then
+ echo "==> Restoring stashed state"
+ git stash pop > /dev/null
+ fi
+ }
+ # if the user has added stuff to the index, abort
+ if ! git diff-index --quiet HEAD --; then
+ echo "Refusing to overwrite outstanding git changes"
+ popstash
+ exit 2
+ fi
+ current=$(git symbolic-ref --short HEAD)
+ for ref in "$@"; do
+ echo "==> Compiling $ref"
+ git checkout -q "$ref"
+ commit=$(git rev-parse HEAD)
+ fn="target/release/addr2line-$commit"
+ if [[ ! -e "$fn" ]]; then
+ cargo build --release --example addr2line
+ cp target/release/examples/addr2line "$fn"
+ fi
+ if [[ "$ref" != "$commit" ]]; then
+ ln -sfn "addr2line-$commit" target/release/addr2line-"$ref"
+ fi
+ done
+ git checkout -q "$current"
+ popstash
+ popd > /dev/null
+
+ # get us some addresses to look up
+ if [[ -z "$addresses" ]]; then
+ echo "==> Looking for benchmarking addresses (this may take a while)"
+ addresses=$(mktemp tmp.XXXXXXXXXX)
+ objdump -C -x --disassemble -l "$target" \
+ | grep -P '0[048]:' \
+ | awk '{print $1}' \
+ | sed 's/:$//' \
+ > "$addresses"
+ echo " -> Addresses stored in $addresses; you should re-use it next time"
+ fi
+
+ run() {
+ func="$1"
+ name="$2"
+ cmd="$3"
+ args="$4"
+ printf "%s\t%s\t" "$name" "$func"
+ if [[ "$cmd" =~ llvm-symbolizer ]]; then
+ /usr/bin/time -f '%e\t%M' "$cmd" $args -obj="$target" < "$addresses" 2>&1 >/dev/null
+ else
+ /usr/bin/time -f '%e\t%M' "$cmd" $args -e "$target" < "$addresses" 2>&1 >/dev/null
+ fi
+ }
+
+ # run without functions
+ log1=$(mktemp tmp.XXXXXXXXXX)
+ echo "==> Benchmarking"
+ run nofunc binutils addr2line >> "$log1"
+ #run nofunc elfutils eu-addr2line >> "$log1"
+ run nofunc llvm-sym llvm-symbolizer -functions=none >> "$log1"
+ for ref in "$@"; do
+ run nofunc "$ref" "$dirname/target/release/addr2line-$ref" >> "$log1"
+ done
+ cat "$log1" | column -t
+
+ # run with functions
+ log2=$(mktemp tmp.XXXXXXXXXX)
+ echo "==> Benchmarking with -f"
+ run func binutils addr2line "-f -i" >> "$log2"
+ #run func elfutils eu-addr2line "-f -i" >> "$log2"
+ run func llvm-sym llvm-symbolizer "-functions=linkage -demangle=0" >> "$log2"
+ for ref in "$@"; do
+ run func "$ref" "$dirname/target/release/addr2line-$ref" "-f -i" >> "$log2"
+ done
+ cat "$log2" | column -t
+ cat "$log2" >> "$log1"; rm "$log2"
+
+ echo "==> Plotting"
+ Rscript --no-readline --no-restore --no-save "$dirname/bench.plot.r" < "$log1"
+
+ echo "==> Cleaning up"
+ rm "$log1"
+ exit 0
+}
diff --git a/vendor/addr2line/coverage.sh b/vendor/addr2line/coverage.sh
new file mode 100644
index 000000000..892c0b7fa
--- /dev/null
+++ b/vendor/addr2line/coverage.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+# Run tarpaulin and pycobertura to generate coverage.html.
+
+cargo tarpaulin --skip-clean --out Xml
+pycobertura show --format html --output coverage.html cobertura.xml
diff --git a/vendor/addr2line/examples/addr2line.rs b/vendor/addr2line/examples/addr2line.rs
new file mode 100644
index 000000000..4b228a706
--- /dev/null
+++ b/vendor/addr2line/examples/addr2line.rs
@@ -0,0 +1,299 @@
+extern crate addr2line;
+extern crate clap;
+extern crate fallible_iterator;
+extern crate gimli;
+extern crate memmap;
+extern crate object;
+extern crate typed_arena;
+
+use std::borrow::Cow;
+use std::fs::File;
+use std::io::{BufRead, Lines, StdinLock, Write};
+use std::path::Path;
+
+use clap::{App, Arg, Values};
+use fallible_iterator::FallibleIterator;
+use object::{Object, ObjectSection};
+use typed_arena::Arena;
+
+use addr2line::{Context, Location};
+
+fn parse_uint_from_hex_string(string: &str) -> u64 {
+ if string.len() > 2 && string.starts_with("0x") {
+ u64::from_str_radix(&string[2..], 16).expect("Failed to parse address")
+ } else {
+ u64::from_str_radix(string, 16).expect("Failed to parse address")
+ }
+}
+
+enum Addrs<'a> {
+ Args(Values<'a>),
+ Stdin(Lines<StdinLock<'a>>),
+}
+
+impl<'a> Iterator for Addrs<'a> {
+ type Item = u64;
+
+ fn next(&mut self) -> Option<u64> {
+ let text = match *self {
+ Addrs::Args(ref mut vals) => vals.next().map(Cow::from),
+ Addrs::Stdin(ref mut lines) => lines.next().map(Result::unwrap).map(Cow::from),
+ };
+ text.as_ref()
+ .map(Cow::as_ref)
+ .map(parse_uint_from_hex_string)
+ }
+}
+
+fn print_loc(loc: &Option<Location>, basenames: bool, llvm: bool) {
+ if let Some(ref loc) = *loc {
+ let file = loc.file.as_ref().unwrap();
+ let path = if basenames {
+ Path::new(Path::new(file).file_name().unwrap())
+ } else {
+ Path::new(file)
+ };
+ print!("{}:", path.display());
+ if llvm {
+ print!("{}:{}", loc.line.unwrap_or(0), loc.column.unwrap_or(0));
+ } else if let Some(line) = loc.line {
+ print!("{}", line);
+ } else {
+ print!("?");
+ }
+ println!();
+ } else if llvm {
+ println!("??:0:0");
+ } else {
+ println!("??:?");
+ }
+}
+
+fn print_function(name: &str, language: Option<gimli::DwLang>, demangle: bool) {
+ if demangle {
+ print!("{}", addr2line::demangle_auto(Cow::from(name), language));
+ } else {
+ print!("{}", name);
+ }
+}
+
+fn load_file_section<'input, 'arena, Endian: gimli::Endianity>(
+ id: gimli::SectionId,
+ file: &object::File<'input>,
+ endian: Endian,
+ arena_data: &'arena Arena<Cow<'input, [u8]>>,
+) -> Result<gimli::EndianSlice<'arena, Endian>, ()> {
+ // TODO: Unify with dwarfdump.rs in gimli.
+ let name = id.name();
+ match file.section_by_name(name) {
+ Some(section) => match section.uncompressed_data().unwrap() {
+ Cow::Borrowed(b) => Ok(gimli::EndianSlice::new(b, endian)),
+ Cow::Owned(b) => Ok(gimli::EndianSlice::new(arena_data.alloc(b.into()), endian)),
+ },
+ None => Ok(gimli::EndianSlice::new(&[][..], endian)),
+ }
+}
+
+fn main() {
+ let matches = App::new("hardliner")
+ .version("0.1")
+ .about("A fast addr2line clone")
+ .arg(
+ Arg::with_name("exe")
+ .short("e")
+ .long("exe")
+ .value_name("filename")
+ .help(
+ "Specify the name of the executable for which addresses should be translated.",
+ )
+ .required(true),
+ )
+ .arg(
+ Arg::with_name("sup")
+ .long("sup")
+ .value_name("filename")
+ .help("Path to supplementary object file."),
+ )
+ .arg(
+ Arg::with_name("functions")
+ .short("f")
+ .long("functions")
+ .help("Display function names as well as file and line number information."),
+ )
+ .arg(
+ Arg::with_name("pretty")
+ .short("p")
+ .long("pretty-print")
+ .help(
+ "Make the output more human friendly: each location are printed on \
+ one line.",
+ ),
+ )
+ .arg(Arg::with_name("inlines").short("i").long("inlines").help(
+ "If the address belongs to a function that was inlined, the source \
+ information for all enclosing scopes back to the first non-inlined \
+ function will also be printed.",
+ ))
+ .arg(
+ Arg::with_name("addresses")
+ .short("a")
+ .long("addresses")
+ .help(
+ "Display the address before the function name, file and line \
+ number information.",
+ ),
+ )
+ .arg(
+ Arg::with_name("basenames")
+ .short("s")
+ .long("basenames")
+ .help("Display only the base of each file name."),
+ )
+ .arg(Arg::with_name("demangle").short("C").long("demangle").help(
+ "Demangle function names. \
+ Specifying a specific demangling style (like GNU addr2line) \
+ is not supported. (TODO)",
+ ))
+ .arg(
+ Arg::with_name("llvm")
+ .long("llvm")
+ .help("Display output in the same format as llvm-symbolizer."),
+ )
+ .arg(
+ Arg::with_name("addrs")
+ .takes_value(true)
+ .multiple(true)
+ .help("Addresses to use instead of reading from stdin."),
+ )
+ .get_matches();
+
+ let arena_data = Arena::new();
+
+ let do_functions = matches.is_present("functions");
+ let do_inlines = matches.is_present("inlines");
+ let pretty = matches.is_present("pretty");
+ let print_addrs = matches.is_present("addresses");
+ let basenames = matches.is_present("basenames");
+ let demangle = matches.is_present("demangle");
+ let llvm = matches.is_present("llvm");
+ let path = matches.value_of("exe").unwrap();
+
+ let file = File::open(path).unwrap();
+ let map = unsafe { memmap::Mmap::map(&file).unwrap() };
+ let object = &object::File::parse(&*map).unwrap();
+
+ let endian = if object.is_little_endian() {
+ gimli::RunTimeEndian::Little
+ } else {
+ gimli::RunTimeEndian::Big
+ };
+
+ let mut load_section = |id: gimli::SectionId| -> Result<_, _> {
+ load_file_section(id, object, endian, &arena_data)
+ };
+
+ let sup_map;
+ let sup_object = if let Some(sup_path) = matches.value_of("sup") {
+ let sup_file = File::open(sup_path).unwrap();
+ sup_map = unsafe { memmap::Mmap::map(&sup_file).unwrap() };
+ Some(object::File::parse(&*sup_map).unwrap())
+ } else {
+ None
+ };
+
+ let symbols = object.symbol_map();
+ let mut dwarf = gimli::Dwarf::load(&mut load_section).unwrap();
+ if let Some(ref sup_object) = sup_object {
+ let mut load_sup_section = |id: gimli::SectionId| -> Result<_, _> {
+ load_file_section(id, sup_object, endian, &arena_data)
+ };
+ dwarf.load_sup(&mut load_sup_section).unwrap();
+ }
+
+ let ctx = Context::from_dwarf(dwarf).unwrap();
+
+ let stdin = std::io::stdin();
+ let addrs = matches
+ .values_of("addrs")
+ .map(Addrs::Args)
+ .unwrap_or_else(|| Addrs::Stdin(stdin.lock().lines()));
+
+ for probe in addrs {
+ if print_addrs {
+ if llvm {
+ print!("0x{:x}", probe);
+ } else {
+ print!("0x{:016x}", probe);
+ }
+ if pretty {
+ print!(": ");
+ } else {
+ println!();
+ }
+ }
+
+ if do_functions || do_inlines {
+ let mut printed_anything = false;
+ let mut frames = ctx.find_frames(probe).unwrap().enumerate();
+ while let Some((i, frame)) = frames.next().unwrap() {
+ if pretty && i != 0 {
+ print!(" (inlined by) ");
+ }
+
+ if do_functions {
+ if let Some(func) = frame.function {
+ print_function(&func.raw_name().unwrap(), func.language, demangle);
+ } else if let Some(name) = symbols.get(probe).map(|x| x.name()) {
+ print_function(name, None, demangle);
+ } else {
+ print!("??");
+ }
+
+ if pretty {
+ print!(" at ");
+ } else {
+ println!();
+ }
+ }
+
+ print_loc(&frame.location, basenames, llvm);
+
+ printed_anything = true;
+
+ if !do_inlines {
+ break;
+ }
+ }
+
+ if !printed_anything {
+ if do_functions {
+ if let Some(name) = symbols.get(probe).map(|x| x.name()) {
+ print_function(name, None, demangle);
+ } else {
+ print!("??");
+ }
+
+ if pretty {
+ print!(" at ");
+ } else {
+ println!();
+ }
+ }
+
+ if llvm {
+ println!("??:0:0");
+ } else {
+ println!("??:?");
+ }
+ }
+ } else {
+ let loc = ctx.find_location(probe).unwrap();
+ print_loc(&loc, basenames, llvm);
+ }
+
+ if llvm {
+ println!();
+ }
+ std::io::stdout().flush().unwrap();
+ }
+}
diff --git a/vendor/addr2line/rustfmt.toml b/vendor/addr2line/rustfmt.toml
new file mode 100644
index 000000000..8b1378917
--- /dev/null
+++ b/vendor/addr2line/rustfmt.toml
@@ -0,0 +1 @@
+
diff --git a/vendor/addr2line/src/function.rs b/vendor/addr2line/src/function.rs
new file mode 100644
index 000000000..1589acdbe
--- /dev/null
+++ b/vendor/addr2line/src/function.rs
@@ -0,0 +1,520 @@
+use alloc::boxed::Box;
+use alloc::vec::Vec;
+use core::cmp::Ordering;
+use core::iter;
+
+use crate::lazy::LazyCell;
+use crate::maybe_small;
+use crate::{Error, RangeAttributes, ResDwarf};
+
+pub(crate) struct Functions<R: gimli::Reader> {
+ /// List of all `DW_TAG_subprogram` details in the unit.
+ pub(crate) functions: Box<
+ [(
+ gimli::UnitOffset<R::Offset>,
+ LazyCell<Result<Function<R>, Error>>,
+ )],
+ >,
+ /// List of `DW_TAG_subprogram` address ranges in the unit.
+ pub(crate) addresses: Box<[FunctionAddress]>,
+}
+
+/// A single address range for a function.
+///
+/// It is possible for a function to have multiple address ranges; this
+/// is handled by having multiple `FunctionAddress` entries with the same
+/// `function` field.
+pub(crate) struct FunctionAddress {
+ range: gimli::Range,
+ /// An index into `Functions::functions`.
+ pub(crate) function: usize,
+}
+
+pub(crate) struct Function<R: gimli::Reader> {
+ pub(crate) dw_die_offset: gimli::UnitOffset<R::Offset>,
+ pub(crate) name: Option<R>,
+ /// List of all `DW_TAG_inlined_subroutine` details in this function.
+ inlined_functions: Box<[InlinedFunction<R>]>,
+ /// List of `DW_TAG_inlined_subroutine` address ranges in this function.
+ inlined_addresses: Box<[InlinedFunctionAddress]>,
+}
+
+pub(crate) struct InlinedFunctionAddress {
+ range: gimli::Range,
+ call_depth: usize,
+ /// An index into `Function::inlined_functions`.
+ function: usize,
+}
+
+pub(crate) struct InlinedFunction<R: gimli::Reader> {
+ pub(crate) dw_die_offset: gimli::UnitOffset<R::Offset>,
+ pub(crate) name: Option<R>,
+ pub(crate) call_file: u64,
+ pub(crate) call_line: u32,
+ pub(crate) call_column: u32,
+}
+
+impl<R: gimli::Reader> Functions<R> {
+ pub(crate) fn parse(unit: &gimli::Unit<R>, dwarf: &ResDwarf<R>) -> Result<Functions<R>, Error> {
+ let mut functions = Vec::new();
+ let mut addresses = Vec::new();
+ let mut entries = unit.entries_raw(None)?;
+ while !entries.is_empty() {
+ let dw_die_offset = entries.next_offset();
+ if let Some(abbrev) = entries.read_abbreviation()? {
+ if abbrev.tag() == gimli::DW_TAG_subprogram {
+ let mut ranges = RangeAttributes::default();
+ for spec in abbrev.attributes() {
+ match entries.read_attribute(*spec) {
+ Ok(ref attr) => {
+ match attr.name() {
+ gimli::DW_AT_low_pc => {
+ if let gimli::AttributeValue::Addr(val) = attr.value() {
+ ranges.low_pc = Some(val);
+ }
+ }
+ gimli::DW_AT_high_pc => match attr.value() {
+ gimli::AttributeValue::Addr(val) => {
+ ranges.high_pc = Some(val)
+ }
+ gimli::AttributeValue::Udata(val) => {
+ ranges.size = Some(val)
+ }
+ _ => {}
+ },
+ gimli::DW_AT_ranges => {
+ ranges.ranges_offset = dwarf
+ .sections
+ .attr_ranges_offset(unit, attr.value())?;
+ }
+ _ => {}
+ };
+ }
+ Err(e) => return Err(e),
+ }
+ }
+
+ let function_index = functions.len();
+ if ranges.for_each_range(&dwarf.sections, unit, |range| {
+ addresses.push(FunctionAddress {
+ range,
+ function: function_index,
+ });
+ })? {
+ functions.push((dw_die_offset, LazyCell::new()));
+ }
+ } else {
+ entries.skip_attributes(abbrev.attributes())?;
+ }
+ }
+ }
+
+ // The binary search requires the addresses to be sorted.
+ //
+ // It also requires them to be non-overlapping. In practice, overlapping
+ // function ranges are unlikely, so we don't try to handle that yet.
+ //
+ // It's possible for multiple functions to have the same address range if the
+ // compiler can detect and remove functions with identical code. In that case
+ // we'll nondeterministically return one of them.
+ addresses.sort_by_key(|x| x.range.begin);
+
+ Ok(Functions {
+ functions: functions.into_boxed_slice(),
+ addresses: addresses.into_boxed_slice(),
+ })
+ }
+
+ pub(crate) fn find_address(&self, probe: u64) -> Option<usize> {
+ self.addresses
+ .binary_search_by(|address| {
+ if probe < address.range.begin {
+ Ordering::Greater
+ } else if probe >= address.range.end {
+ Ordering::Less
+ } else {
+ Ordering::Equal
+ }
+ })
+ .ok()
+ }
+
+ pub(crate) fn parse_inlined_functions(
+ &self,
+ unit: &gimli::Unit<R>,
+ dwarf: &ResDwarf<R>,
+ ) -> Result<(), Error> {
+ for function in &*self.functions {
+ function
+ .1
+ .borrow_with(|| Function::parse(function.0, unit, dwarf))
+ .as_ref()
+ .map_err(Error::clone)?;
+ }
+ Ok(())
+ }
+}
+
+impl<R: gimli::Reader> Function<R> {
+ pub(crate) fn parse(
+ dw_die_offset: gimli::UnitOffset<R::Offset>,
+ unit: &gimli::Unit<R>,
+ dwarf: &ResDwarf<R>,
+ ) -> Result<Self, Error> {
+ let mut entries = unit.entries_raw(Some(dw_die_offset))?;
+ let depth = entries.next_depth();
+ let abbrev = entries.read_abbreviation()?.unwrap();
+ debug_assert_eq!(abbrev.tag(), gimli::DW_TAG_subprogram);
+
+ let mut name = None;
+ for spec in abbrev.attributes() {
+ match entries.read_attribute(*spec) {
+ Ok(ref attr) => {
+ match attr.name() {
+ gimli::DW_AT_linkage_name | gimli::DW_AT_MIPS_linkage_name => {
+ if let Ok(val) = dwarf.sections.attr_string(unit, attr.value()) {
+ name = Some(val);
+ }
+ }
+ gimli::DW_AT_name => {
+ if name.is_none() {
+ name = dwarf.sections.attr_string(unit, attr.value()).ok();
+ }
+ }
+ gimli::DW_AT_abstract_origin | gimli::DW_AT_specification => {
+ if name.is_none() {
+ name = name_attr(attr.value(), unit, dwarf, 16)?;
+ }
+ }
+ _ => {}
+ };
+ }
+ Err(e) => return Err(e),
+ }
+ }
+
+ let mut inlined_functions = Vec::new();
+ let mut inlined_addresses = Vec::new();
+ Function::parse_children(
+ &mut entries,
+ depth,
+ unit,
+ dwarf,
+ &mut inlined_functions,
+ &mut inlined_addresses,
+ 0,
+ )?;
+
+ // Sort ranges in "breadth-first traversal order", i.e. first by call_depth
+ // and then by range.begin. This allows finding the range containing an
+ // address at a certain depth using binary search.
+ // Note: Using DFS order, i.e. ordering by range.begin first and then by
+ // call_depth, would not work! Consider the two examples
+ // "[0..10 at depth 0], [0..2 at depth 1], [6..8 at depth 1]" and
+ // "[0..5 at depth 0], [0..2 at depth 1], [5..10 at depth 0], [6..8 at depth 1]".
+ // In this example, if you want to look up address 7 at depth 0, and you
+ // encounter [0..2 at depth 1], are you before or after the target range?
+ // You don't know.
+ inlined_addresses.sort_by(|r1, r2| {
+ if r1.call_depth < r2.call_depth {
+ Ordering::Less
+ } else if r1.call_depth > r2.call_depth {
+ Ordering::Greater
+ } else if r1.range.begin < r2.range.begin {
+ Ordering::Less
+ } else if r1.range.begin > r2.range.begin {
+ Ordering::Greater
+ } else {
+ Ordering::Equal
+ }
+ });
+
+ Ok(Function {
+ dw_die_offset,
+ name,
+ inlined_functions: inlined_functions.into_boxed_slice(),
+ inlined_addresses: inlined_addresses.into_boxed_slice(),
+ })
+ }
+
+ fn parse_children(
+ entries: &mut gimli::EntriesRaw<R>,
+ depth: isize,
+ unit: &gimli::Unit<R>,
+ dwarf: &ResDwarf<R>,
+ inlined_functions: &mut Vec<InlinedFunction<R>>,
+ inlined_addresses: &mut Vec<InlinedFunctionAddress>,
+ inlined_depth: usize,
+ ) -> Result<(), Error> {
+ loop {
+ let dw_die_offset = entries.next_offset();
+ let next_depth = entries.next_depth();
+ if next_depth <= depth {
+ return Ok(());
+ }
+ if let Some(abbrev) = entries.read_abbreviation()? {
+ match abbrev.tag() {
+ gimli::DW_TAG_subprogram => {
+ Function::skip(entries, abbrev, next_depth)?;
+ }
+ gimli::DW_TAG_inlined_subroutine => {
+ InlinedFunction::parse(
+ dw_die_offset,
+ entries,
+ abbrev,
+ next_depth,
+ unit,
+ dwarf,
+ inlined_functions,
+ inlined_addresses,
+ inlined_depth,
+ )?;
+ }
+ _ => {
+ entries.skip_attributes(abbrev.attributes())?;
+ }
+ }
+ }
+ }
+ }
+
+ fn skip(
+ entries: &mut gimli::EntriesRaw<R>,
+ abbrev: &gimli::Abbreviation,
+ depth: isize,
+ ) -> Result<(), Error> {
+ // TODO: use DW_AT_sibling
+ entries.skip_attributes(abbrev.attributes())?;
+ while entries.next_depth() > depth {
+ if let Some(abbrev) = entries.read_abbreviation()? {
+ entries.skip_attributes(abbrev.attributes())?;
+ }
+ }
+ Ok(())
+ }
+
+ /// Build the list of inlined functions that contain `probe`.
+ pub(crate) fn find_inlined_functions(
+ &self,
+ probe: u64,
+ ) -> iter::Rev<maybe_small::IntoIter<&InlinedFunction<R>>> {
+ // `inlined_functions` is ordered from outside to inside.
+ let mut inlined_functions = maybe_small::Vec::new();
+ let mut inlined_addresses = &self.inlined_addresses[..];
+ loop {
+ let current_depth = inlined_functions.len();
+ // Look up (probe, current_depth) in inline_ranges.
+ // `inlined_addresses` is sorted in "breadth-first traversal order", i.e.
+ // by `call_depth` first, and then by `range.begin`. See the comment at
+ // the sort call for more information about why.
+ let search = inlined_addresses.binary_search_by(|range| {
+ if range.call_depth > current_depth {
+ Ordering::Greater
+ } else if range.call_depth < current_depth {
+ Ordering::Less
+ } else if range.range.begin > probe {
+ Ordering::Greater
+ } else if range.range.end <= probe {
+ Ordering::Less
+ } else {
+ Ordering::Equal
+ }
+ });
+ if let Ok(index) = search {
+ let function_index = inlined_addresses[index].function;
+ inlined_functions.push(&self.inlined_functions[function_index]);
+ inlined_addresses = &inlined_addresses[index + 1..];
+ } else {
+ break;
+ }
+ }
+ inlined_functions.into_iter().rev()
+ }
+}
+
+impl<R: gimli::Reader> InlinedFunction<R> {
+ fn parse(
+ dw_die_offset: gimli::UnitOffset<R::Offset>,
+ entries: &mut gimli::EntriesRaw<R>,
+ abbrev: &gimli::Abbreviation,
+ depth: isize,
+ unit: &gimli::Unit<R>,
+ dwarf: &ResDwarf<R>,
+ inlined_functions: &mut Vec<InlinedFunction<R>>,
+ inlined_addresses: &mut Vec<InlinedFunctionAddress>,
+ inlined_depth: usize,
+ ) -> Result<(), Error> {
+ let mut ranges = RangeAttributes::default();
+ let mut name = None;
+ let mut call_file = 0;
+ let mut call_line = 0;
+ let mut call_column = 0;
+ for spec in abbrev.attributes() {
+ match entries.read_attribute(*spec) {
+ Ok(ref attr) => match attr.name() {
+ gimli::DW_AT_low_pc => {
+ if let gimli::AttributeValue::Addr(val) = attr.value() {
+ ranges.low_pc = Some(val);
+ }
+ }
+ gimli::DW_AT_high_pc => match attr.value() {
+ gimli::AttributeValue::Addr(val) => ranges.high_pc = Some(val),
+ gimli::AttributeValue::Udata(val) => ranges.size = Some(val),
+ _ => {}
+ },
+ gimli::DW_AT_ranges => {
+ ranges.ranges_offset =
+ dwarf.sections.attr_ranges_offset(unit, attr.value())?;
+ }
+ gimli::DW_AT_linkage_name | gimli::DW_AT_MIPS_linkage_name => {
+ if let Ok(val) = dwarf.sections.attr_string(unit, attr.value()) {
+ name = Some(val);
+ }
+ }
+ gimli::DW_AT_name => {
+ if name.is_none() {
+ name = dwarf.sections.attr_string(unit, attr.value()).ok();
+ }
+ }
+ gimli::DW_AT_abstract_origin | gimli::DW_AT_specification => {
+ if name.is_none() {
+ name = name_attr(attr.value(), unit, dwarf, 16)?;
+ }
+ }
+ gimli::DW_AT_call_file => {
+ if let gimli::AttributeValue::FileIndex(fi) = attr.value() {
+ call_file = fi;
+ }
+ }
+ gimli::DW_AT_call_line => {
+ call_line = attr.udata_value().unwrap_or(0) as u32;
+ }
+ gimli::DW_AT_call_column => {
+ call_column = attr.udata_value().unwrap_or(0) as u32;
+ }
+ _ => {}
+ },
+ Err(e) => return Err(e),
+ }
+ }
+
+ let function_index = inlined_functions.len();
+ inlined_functions.push(InlinedFunction {
+ dw_die_offset,
+ name,
+ call_file,
+ call_line,
+ call_column,
+ });
+
+ ranges.for_each_range(&dwarf.sections, unit, |range| {
+ inlined_addresses.push(InlinedFunctionAddress {
+ range,
+ call_depth: inlined_depth,
+ function: function_index,
+ });
+ })?;
+
+ Function::parse_children(
+ entries,
+ depth,
+ unit,
+ dwarf,
+ inlined_functions,
+ inlined_addresses,
+ inlined_depth + 1,
+ )
+ }
+}
+
+fn name_attr<R>(
+ attr: gimli::AttributeValue<R>,
+ unit: &gimli::Unit<R>,
+ dwarf: &ResDwarf<R>,
+ recursion_limit: usize,
+) -> Result<Option<R>, Error>
+where
+ R: gimli::Reader,
+{
+ if recursion_limit == 0 {
+ return Ok(None);
+ }
+
+ match attr {
+ gimli::AttributeValue::UnitRef(offset) => name_entry(unit, offset, dwarf, recursion_limit),
+ gimli::AttributeValue::DebugInfoRef(dr) => {
+ let res_unit = dwarf.find_unit(dr)?;
+ name_entry(
+ &res_unit.dw_unit,
+ gimli::UnitOffset(dr.0 - res_unit.offset.0),
+ dwarf,
+ recursion_limit,
+ )
+ }
+ gimli::AttributeValue::DebugInfoRefSup(dr) => {
+ if let Some(sup_dwarf) = dwarf.sup.as_ref() {
+ let res_unit = sup_dwarf.find_unit(dr)?;
+ name_entry(
+ &res_unit.dw_unit,
+ gimli::UnitOffset(dr.0 - res_unit.offset.0),
+ sup_dwarf,
+ recursion_limit,
+ )
+ } else {
+ Ok(None)
+ }
+ }
+ _ => Ok(None),
+ }
+}
+
+fn name_entry<R>(
+ unit: &gimli::Unit<R>,
+ offset: gimli::UnitOffset<R::Offset>,
+ dwarf: &ResDwarf<R>,
+ recursion_limit: usize,
+) -> Result<Option<R>, Error>
+where
+ R: gimli::Reader,
+{
+ let mut entries = unit.entries_raw(Some(offset))?;
+ let abbrev = if let Some(abbrev) = entries.read_abbreviation()? {
+ abbrev
+ } else {
+ return Err(gimli::Error::NoEntryAtGivenOffset);
+ };
+
+ let mut name = None;
+ let mut next = None;
+ for spec in abbrev.attributes() {
+ match entries.read_attribute(*spec) {
+ Ok(ref attr) => match attr.name() {
+ gimli::DW_AT_linkage_name | gimli::DW_AT_MIPS_linkage_name => {
+ if let Ok(val) = dwarf.sections.attr_string(unit, attr.value()) {
+ return Ok(Some(val));
+ }
+ }
+ gimli::DW_AT_name => {
+ if let Ok(val) = dwarf.sections.attr_string(unit, attr.value()) {
+ name = Some(val);
+ }
+ }
+ gimli::DW_AT_abstract_origin | gimli::DW_AT_specification => {
+ next = Some(attr.value());
+ }
+ _ => {}
+ },
+ Err(e) => return Err(e),
+ }
+ }
+
+ if name.is_some() {
+ return Ok(name);
+ }
+
+ if let Some(next) = next {
+ return name_attr(next, unit, dwarf, recursion_limit - 1);
+ }
+
+ Ok(None)
+}
diff --git a/vendor/addr2line/src/lazy.rs b/vendor/addr2line/src/lazy.rs
new file mode 100644
index 000000000..280c76b46
--- /dev/null
+++ b/vendor/addr2line/src/lazy.rs
@@ -0,0 +1,29 @@
+use core::cell::UnsafeCell;
+
+pub struct LazyCell<T> {
+ contents: UnsafeCell<Option<T>>,
+}
+impl<T> LazyCell<T> {
+ pub fn new() -> LazyCell<T> {
+ LazyCell {
+ contents: UnsafeCell::new(None),
+ }
+ }
+
+ pub fn borrow_with(&self, closure: impl FnOnce() -> T) -> &T {
+ unsafe {
+ // First check if we're already initialized...
+ let ptr = self.contents.get();
+ if let Some(val) = &*ptr {
+ return val;
+ }
+ // Note that while we're executing `closure` our `borrow_with` may
+ // be called recursively. This means we need to check again after
+ // the closure has executed. For that we use the `get_or_insert`
+ // method which will only perform mutation if we aren't already
+ // `Some`.
+ let val = closure();
+ (*ptr).get_or_insert(val)
+ }
+ }
+}
diff --git a/vendor/addr2line/src/lib.rs b/vendor/addr2line/src/lib.rs
new file mode 100644
index 000000000..b46a98393
--- /dev/null
+++ b/vendor/addr2line/src/lib.rs
@@ -0,0 +1,1192 @@
+//! This crate provides a cross-platform library and binary for translating addresses into
+//! function names, file names and line numbers. Given an address in an executable or an
+//! offset in a section of a relocatable object, it uses the debugging information to
+//! figure out which file name and line number are associated with it.
+//!
+//! When used as a library, files must first be loaded using the
+//! [`object`](https://github.com/gimli-rs/object) crate.
+//! A context can then be created with [`Context::new`](./struct.Context.html#method.new).
+//! The context caches some of the parsed information so that multiple lookups are
+//! efficient.
+//! Location information is obtained with
+//! [`Context::find_location`](./struct.Context.html#method.find_location) or
+//! [`Context::find_location_range`](./struct.Context.html#method.find_location_range).
+//! Function information is obtained with
+//! [`Context::find_frames`](./struct.Context.html#method.find_frames), which returns
+//! a frame for each inline function. Each frame contains both name and location.
+//!
+//! The crate has an example CLI wrapper around the library which provides some of
+//! the functionality of the `addr2line` command line tool distributed with [GNU
+//! binutils](https://www.gnu.org/software/binutils/).
+//!
+//! Currently this library only provides information from the DWARF debugging information,
+//! which is parsed using [`gimli`](https://github.com/gimli-rs/gimli). The example CLI
+//! wrapper also uses symbol table information provided by the `object` crate.
+#![deny(missing_docs)]
+#![no_std]
+
+#[allow(unused_imports)]
+#[macro_use]
+extern crate alloc;
+
+#[cfg(feature = "cpp_demangle")]
+extern crate cpp_demangle;
+#[cfg(feature = "fallible-iterator")]
+pub extern crate fallible_iterator;
+pub extern crate gimli;
+#[cfg(feature = "object")]
+pub extern crate object;
+#[cfg(feature = "rustc-demangle")]
+extern crate rustc_demangle;
+
+use alloc::borrow::Cow;
+use alloc::boxed::Box;
+#[cfg(feature = "object")]
+use alloc::rc::Rc;
+use alloc::string::{String, ToString};
+use alloc::sync::Arc;
+use alloc::vec::Vec;
+
+use core::cmp::{self, Ordering};
+use core::iter;
+use core::mem;
+use core::num::NonZeroU64;
+use core::u64;
+
+use crate::function::{Function, Functions, InlinedFunction};
+use crate::lazy::LazyCell;
+
+#[cfg(feature = "smallvec")]
+mod maybe_small {
+ pub type Vec<T> = smallvec::SmallVec<[T; 16]>;
+ pub type IntoIter<T> = smallvec::IntoIter<[T; 16]>;
+}
+#[cfg(not(feature = "smallvec"))]
+mod maybe_small {
+ pub type Vec<T> = alloc::vec::Vec<T>;
+ pub type IntoIter<T> = alloc::vec::IntoIter<T>;
+}
+
+mod function;
+mod lazy;
+
+type Error = gimli::Error;
+
+/// The state necessary to perform address to line translation.
+///
+/// Constructing a `Context` is somewhat costly, so users should aim to reuse `Context`s
+/// when performing lookups for many addresses in the same executable.
+pub struct Context<R: gimli::Reader> {
+ dwarf: ResDwarf<R>,
+}
+
+/// The type of `Context` that supports the `new` method.
+#[cfg(feature = "std-object")]
+pub type ObjectContext = Context<gimli::EndianRcSlice<gimli::RunTimeEndian>>;
+
+#[cfg(feature = "std-object")]
+impl Context<gimli::EndianRcSlice<gimli::RunTimeEndian>> {
+ /// Construct a new `Context`.
+ ///
+ /// The resulting `Context` uses `gimli::EndianRcSlice<gimli::RunTimeEndian>`.
+ /// This means it is not thread safe, has no lifetime constraints (since it copies
+ /// the input data), and works for any endianity.
+ ///
+ /// Performance sensitive applications may want to use `Context::from_dwarf`
+ /// with a more specialised `gimli::Reader` implementation.
+ #[inline]
+ pub fn new<'data: 'file, 'file, O: object::Object<'data, 'file>>(
+ file: &'file O,
+ ) -> Result<Self, Error> {
+ Self::new_with_sup(file, None)
+ }
+
+ /// Construct a new `Context`.
+ ///
+ /// Optionally also use a supplementary object file.
+ ///
+ /// The resulting `Context` uses `gimli::EndianRcSlice<gimli::RunTimeEndian>`.
+ /// This means it is not thread safe, has no lifetime constraints (since it copies
+ /// the input data), and works for any endianity.
+ ///
+ /// Performance sensitive applications may want to use `Context::from_dwarf_with_sup`
+ /// with a more specialised `gimli::Reader` implementation.
+ pub fn new_with_sup<'data: 'file, 'file, O: object::Object<'data, 'file>>(
+ file: &'file O,
+ sup_file: Option<&'file O>,
+ ) -> Result<Self, Error> {
+ 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::EndianRcSlice<Endian>, 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::EndianRcSlice::new(Rc::from(&*data), endian))
+ }
+
+ let mut dwarf = gimli::Dwarf::load(|id| load_section(id, file, endian))?;
+ if let Some(sup_file) = sup_file {
+ dwarf.load_sup(|id| load_section(id, sup_file, endian))?;
+ }
+ Context::from_dwarf(dwarf)
+ }
+}
+
+impl<R: gimli::Reader> Context<R> {
+ /// Construct a new `Context` from DWARF sections.
+ ///
+ /// This method does not support using a supplementary object file.
+ pub fn from_sections(
+ debug_abbrev: gimli::DebugAbbrev<R>,
+ debug_addr: gimli::DebugAddr<R>,
+ debug_aranges: gimli::DebugAranges<R>,
+ debug_info: gimli::DebugInfo<R>,
+ debug_line: gimli::DebugLine<R>,
+ debug_line_str: gimli::DebugLineStr<R>,
+ debug_ranges: gimli::DebugRanges<R>,
+ debug_rnglists: gimli::DebugRngLists<R>,
+ debug_str: gimli::DebugStr<R>,
+ debug_str_offsets: gimli::DebugStrOffsets<R>,
+ default_section: R,
+ ) -> Result<Self, Error> {
+ Self::from_dwarf(gimli::Dwarf {
+ debug_abbrev,
+ debug_addr,
+ debug_aranges,
+ debug_info,
+ debug_line,
+ debug_line_str,
+ debug_str,
+ debug_str_offsets,
+ debug_types: default_section.clone().into(),
+ locations: gimli::LocationLists::new(
+ default_section.clone().into(),
+ default_section.clone().into(),
+ ),
+ ranges: gimli::RangeLists::new(debug_ranges, debug_rnglists),
+ file_type: gimli::DwarfFileType::Main,
+ sup: None,
+ })
+ }
+
+ /// Construct a new `Context` from an existing [`gimli::Dwarf`] object.
+ #[inline]
+ pub fn from_dwarf(sections: gimli::Dwarf<R>) -> Result<Self, Error> {
+ let mut dwarf = ResDwarf::parse(Arc::new(sections))?;
+ dwarf.sup = match dwarf.sections.sup.clone() {
+ Some(sup_sections) => Some(Box::new(ResDwarf::parse(sup_sections)?)),
+ None => None,
+ };
+ Ok(Context { dwarf })
+ }
+
+ /// The dwarf sections associated with this `Context`.
+ pub fn dwarf(&self) -> &gimli::Dwarf<R> {
+ &self.dwarf.sections
+ }
+
+ /// Finds the CUs for the function address given.
+ ///
+ /// There might be multiple CUs whose range contains this address.
+ /// Weak symbols have shown up in the wild which cause this to happen
+ /// but otherwise this can happen if the CU has non-contiguous functions
+ /// but only reports a single range.
+ ///
+ /// Consequently we return an iterator for all CUs which may contain the
+ /// address, and the caller must check if there is actually a function or
+ /// location in the CU for that address.
+ fn find_units(&self, probe: u64) -> impl Iterator<Item = &ResUnit<R>> {
+ self.find_units_range(probe, probe + 1)
+ .map(|(unit, _range)| unit)
+ }
+
+ /// Finds the CUs covering the range of addresses given.
+ ///
+ /// The range is [low, high) (ie, the upper bound is exclusive). This can return multiple
+ /// ranges for the same unit.
+ #[inline]
+ fn find_units_range(
+ &self,
+ probe_low: u64,
+ probe_high: u64,
+ ) -> impl Iterator<Item = (&ResUnit<R>, &gimli::Range)> {
+ // First up find the position in the array which could have our function
+ // address.
+ let pos = match self
+ .dwarf
+ .unit_ranges
+ .binary_search_by_key(&probe_high, |i| i.range.begin)
+ {
+ // Although unlikely, we could find an exact match.
+ Ok(i) => i + 1,
+ // No exact match was found, but this probe would fit at slot `i`.
+ // This means that slot `i` is bigger than `probe`, along with all
+ // indices greater than `i`, so we need to search all previous
+ // entries.
+ Err(i) => i,
+ };
+
+ // Once we have our index we iterate backwards from that position
+ // looking for a matching CU.
+ self.dwarf.unit_ranges[..pos]
+ .iter()
+ .rev()
+ .take_while(move |i| {
+ // We know that this CU's start is beneath the probe already because
+ // of our sorted array.
+ debug_assert!(i.range.begin <= probe_high);
+
+ // Each entry keeps track of the maximum end address seen so far,
+ // starting from the beginning of the array of unit ranges. We're
+ // iterating in reverse so if our probe is beyond the maximum range
+ // of this entry, then it's guaranteed to not fit in any prior
+ // entries, so we break out.
+ probe_low < i.max_end
+ })
+ .filter_map(move |i| {
+ // If this CU doesn't actually contain this address, move to the
+ // next CU.
+ if probe_low >= i.range.end || probe_high <= i.range.begin {
+ return None;
+ }
+ Some((&self.dwarf.units[i.unit_id], &i.range))
+ })
+ }
+
+ /// Find the DWARF unit corresponding to the given virtual memory address.
+ pub fn find_dwarf_unit(&self, probe: u64) -> Option<&gimli::Unit<R>> {
+ for unit in self.find_units(probe) {
+ match unit.find_function_or_location(probe, &self.dwarf) {
+ Ok((Some(_), _)) | Ok((_, Some(_))) => return Some(&unit.dw_unit),
+ _ => {}
+ }
+ }
+ None
+ }
+
+ /// Find the source file and line corresponding to the given virtual memory address.
+ pub fn find_location(&self, probe: u64) -> Result<Option<Location<'_>>, Error> {
+ for unit in self.find_units(probe) {
+ if let Some(location) = unit.find_location(probe, &self.dwarf.sections)? {
+ return Ok(Some(location));
+ }
+ }
+ Ok(None)
+ }
+
+ /// Return source file and lines for a range of addresses. For each location it also
+ /// returns the address and size of the range of the underlying instructions.
+ pub fn find_location_range(
+ &self,
+ probe_low: u64,
+ probe_high: u64,
+ ) -> Result<LocationRangeIter<'_, R>, Error> {
+ LocationRangeIter::new(self, probe_low, probe_high)
+ }
+
+ /// Return an iterator for the function frames corresponding to the given virtual
+ /// memory address.
+ ///
+ /// If the probe address is not for an inline function then only one frame is
+ /// returned.
+ ///
+ /// If the probe address is for an inline function then the first frame corresponds
+ /// to the innermost inline function. Subsequent frames contain the caller and call
+ /// location, until an non-inline caller is reached.
+ pub fn find_frames(&self, probe: u64) -> Result<FrameIter<R>, Error> {
+ for unit in self.find_units(probe) {
+ match unit.find_function_or_location(probe, &self.dwarf)? {
+ (Some(function), location) => {
+ let inlined_functions = function.find_inlined_functions(probe);
+ return Ok(FrameIter(FrameIterState::Frames(FrameIterFrames {
+ unit,
+ sections: &self.dwarf.sections,
+ function,
+ inlined_functions,
+ next: location,
+ })));
+ }
+ (None, Some(location)) => {
+ return Ok(FrameIter(FrameIterState::Location(Some(location))));
+ }
+ _ => {}
+ }
+ }
+ Ok(FrameIter(FrameIterState::Empty))
+ }
+
+ /// Initialize all line data structures. This is used for benchmarks.
+ #[doc(hidden)]
+ pub fn parse_lines(&self) -> Result<(), Error> {
+ for unit in &self.dwarf.units {
+ unit.parse_lines(&self.dwarf.sections)?;
+ }
+ Ok(())
+ }
+
+ /// Initialize all function data structures. This is used for benchmarks.
+ #[doc(hidden)]
+ pub fn parse_functions(&self) -> Result<(), Error> {
+ for unit in &self.dwarf.units {
+ unit.parse_functions(&self.dwarf)?;
+ }
+ Ok(())
+ }
+
+ /// Initialize all inlined function data structures. This is used for benchmarks.
+ #[doc(hidden)]
+ pub fn parse_inlined_functions(&self) -> Result<(), Error> {
+ for unit in &self.dwarf.units {
+ unit.parse_inlined_functions(&self.dwarf)?;
+ }
+ Ok(())
+ }
+}
+
+struct UnitRange {
+ unit_id: usize,
+ max_end: u64,
+ range: gimli::Range,
+}
+
+struct ResDwarf<R: gimli::Reader> {
+ unit_ranges: Vec<UnitRange>,
+ units: Vec<ResUnit<R>>,
+ sections: Arc<gimli::Dwarf<R>>,
+ sup: Option<Box<ResDwarf<R>>>,
+}
+
+impl<R: gimli::Reader> ResDwarf<R> {
+ fn parse(sections: Arc<gimli::Dwarf<R>>) -> Result<Self, Error> {
+ // Find all the references to compilation units in .debug_aranges.
+ // Note that we always also iterate through all of .debug_info to
+ // find compilation units, because .debug_aranges may be missing some.
+ let mut aranges = Vec::new();
+ let mut headers = sections.debug_aranges.headers();
+ while let Some(header) = headers.next()? {
+ aranges.push((header.debug_info_offset(), header.offset()));
+ }
+ aranges.sort_by_key(|i| i.0);
+
+ let mut unit_ranges = Vec::new();
+ let mut res_units = Vec::new();
+ let mut units = sections.units();
+ while let Some(header) = units.next()? {
+ let unit_id = res_units.len();
+ let offset = match header.offset().as_debug_info_offset() {
+ Some(offset) => offset,
+ None => continue,
+ };
+ // We mainly want compile units, but we may need to follow references to entries
+ // within other units for function names. We don't need anything from type units.
+ match header.type_() {
+ gimli::UnitType::Type { .. } | gimli::UnitType::SplitType { .. } => continue,
+ _ => {}
+ }
+ let dw_unit = match sections.unit(header) {
+ Ok(dw_unit) => dw_unit,
+ Err(_) => continue,
+ };
+
+ let mut lang = None;
+ {
+ let mut entries = dw_unit.entries_raw(None)?;
+
+ let abbrev = match entries.read_abbreviation()? {
+ Some(abbrev) => abbrev,
+ None => continue,
+ };
+
+ let mut ranges = RangeAttributes::default();
+ for spec in abbrev.attributes() {
+ let attr = entries.read_attribute(*spec)?;
+ match attr.name() {
+ gimli::DW_AT_low_pc => {
+ if let gimli::AttributeValue::Addr(val) = attr.value() {
+ ranges.low_pc = Some(val);
+ }
+ }
+ gimli::DW_AT_high_pc => match attr.value() {
+ gimli::AttributeValue::Addr(val) => ranges.high_pc = Some(val),
+ gimli::AttributeValue::Udata(val) => ranges.size = Some(val),
+ _ => {}
+ },
+ gimli::DW_AT_ranges => {
+ ranges.ranges_offset =
+ sections.attr_ranges_offset(&dw_unit, attr.value())?;
+ }
+ gimli::DW_AT_language => {
+ if let gimli::AttributeValue::Language(val) = attr.value() {
+ lang = Some(val);
+ }
+ }
+ _ => {}
+ }
+ }
+
+ // Find the address ranges for the CU, using in order of preference:
+ // - DW_AT_ranges
+ // - .debug_aranges
+ // - DW_AT_low_pc/DW_AT_high_pc
+ //
+ // Using DW_AT_ranges before .debug_aranges is possibly an arbitrary choice,
+ // but the feeling is that DW_AT_ranges is more likely to be reliable or complete
+ // if it is present.
+ //
+ // .debug_aranges must be used before DW_AT_low_pc/DW_AT_high_pc because
+ // it has been observed on macOS that DW_AT_ranges was not emitted even for
+ // discontiguous CUs.
+ let i = match ranges.ranges_offset {
+ Some(_) => None,
+ None => aranges.binary_search_by_key(&offset, |x| x.0).ok(),
+ };
+ if let Some(mut i) = i {
+ // There should be only one set per CU, but in practice multiple
+ // sets have been observed. This is probably a compiler bug, but
+ // either way we need to handle it.
+ while i > 0 && aranges[i - 1].0 == offset {
+ i -= 1;
+ }
+ for (_, aranges_offset) in aranges[i..].iter().take_while(|x| x.0 == offset) {
+ let aranges_header = sections.debug_aranges.header(*aranges_offset)?;
+ let mut aranges = aranges_header.entries();
+ while let Some(arange) = aranges.next()? {
+ if arange.length() != 0 {
+ unit_ranges.push(UnitRange {
+ range: arange.range(),
+ unit_id,
+ max_end: 0,
+ });
+ }
+ }
+ }
+ } else {
+ ranges.for_each_range(&sections, &dw_unit, |range| {
+ unit_ranges.push(UnitRange {
+ range,
+ unit_id,
+ max_end: 0,
+ });
+ })?;
+ }
+ }
+
+ res_units.push(ResUnit {
+ offset,
+ dw_unit,
+ lang,
+ lines: LazyCell::new(),
+ funcs: LazyCell::new(),
+ });
+ }
+
+ // Sort this for faster lookup in `find_unit_and_address` below.
+ unit_ranges.sort_by_key(|i| i.range.begin);
+
+ // Calculate the `max_end` field now that we've determined the order of
+ // CUs.
+ let mut max = 0;
+ for i in unit_ranges.iter_mut() {
+ max = max.max(i.range.end);
+ i.max_end = max;
+ }
+
+ Ok(ResDwarf {
+ units: res_units,
+ unit_ranges,
+ sections,
+ sup: None,
+ })
+ }
+
+ fn find_unit(&self, offset: gimli::DebugInfoOffset<R::Offset>) -> Result<&ResUnit<R>, Error> {
+ match self
+ .units
+ .binary_search_by_key(&offset.0, |unit| unit.offset.0)
+ {
+ // There is never a DIE at the unit offset or before the first unit.
+ Ok(_) | Err(0) => Err(gimli::Error::NoEntryAtGivenOffset),
+ Err(i) => Ok(&self.units[i - 1]),
+ }
+ }
+}
+
+struct Lines {
+ files: Box<[String]>,
+ sequences: Box<[LineSequence]>,
+}
+
+struct LineSequence {
+ start: u64,
+ end: u64,
+ rows: Box<[LineRow]>,
+}
+
+struct LineRow {
+ address: u64,
+ file_index: u64,
+ line: u32,
+ column: u32,
+}
+
+struct ResUnit<R: gimli::Reader> {
+ offset: gimli::DebugInfoOffset<R::Offset>,
+ dw_unit: gimli::Unit<R>,
+ lang: Option<gimli::DwLang>,
+ lines: LazyCell<Result<Lines, Error>>,
+ funcs: LazyCell<Result<Functions<R>, Error>>,
+}
+
+impl<R: gimli::Reader> ResUnit<R> {
+ fn parse_lines(&self, sections: &gimli::Dwarf<R>) -> Result<Option<&Lines>, Error> {
+ let ilnp = match self.dw_unit.line_program {
+ Some(ref ilnp) => ilnp,
+ None => return Ok(None),
+ };
+ self.lines
+ .borrow_with(|| {
+ let mut sequences = Vec::new();
+ let mut sequence_rows = Vec::<LineRow>::new();
+ let mut rows = ilnp.clone().rows();
+ while let Some((_, row)) = rows.next_row()? {
+ if row.end_sequence() {
+ if let Some(start) = sequence_rows.first().map(|x| x.address) {
+ let end = row.address();
+ let mut rows = Vec::new();
+ mem::swap(&mut rows, &mut sequence_rows);
+ sequences.push(LineSequence {
+ start,
+ end,
+ rows: rows.into_boxed_slice(),
+ });
+ }
+ continue;
+ }
+
+ let address = row.address();
+ let file_index = row.file_index();
+ let line = row.line().map(NonZeroU64::get).unwrap_or(0) as u32;
+ let column = match row.column() {
+ gimli::ColumnType::LeftEdge => 0,
+ gimli::ColumnType::Column(x) => x.get() as u32,
+ };
+
+ if let Some(last_row) = sequence_rows.last_mut() {
+ if last_row.address == address {
+ last_row.file_index = file_index;
+ last_row.line = line;
+ last_row.column = column;
+ continue;
+ }
+ }
+
+ sequence_rows.push(LineRow {
+ address,
+ file_index,
+ line,
+ column,
+ });
+ }
+ sequences.sort_by_key(|x| x.start);
+
+ let mut files = Vec::new();
+ let header = ilnp.header();
+ match header.file(0) {
+ Some(file) => files.push(self.render_file(file, header, sections)?),
+ None => files.push(String::from("")), // DWARF version <= 4 may not have 0th index
+ }
+ let mut index = 1;
+ while let Some(file) = header.file(index) {
+ files.push(self.render_file(file, header, sections)?);
+ index += 1;
+ }
+
+ Ok(Lines {
+ files: files.into_boxed_slice(),
+ sequences: sequences.into_boxed_slice(),
+ })
+ })
+ .as_ref()
+ .map(Some)
+ .map_err(Error::clone)
+ }
+
+ fn parse_functions(&self, dwarf: &ResDwarf<R>) -> Result<&Functions<R>, Error> {
+ self.funcs
+ .borrow_with(|| Functions::parse(&self.dw_unit, dwarf))
+ .as_ref()
+ .map_err(Error::clone)
+ }
+
+ fn parse_inlined_functions(&self, dwarf: &ResDwarf<R>) -> Result<(), Error> {
+ self.funcs
+ .borrow_with(|| Functions::parse(&self.dw_unit, dwarf))
+ .as_ref()
+ .map_err(Error::clone)?
+ .parse_inlined_functions(&self.dw_unit, dwarf)
+ }
+
+ fn find_location(
+ &self,
+ probe: u64,
+ sections: &gimli::Dwarf<R>,
+ ) -> Result<Option<Location<'_>>, Error> {
+ if let Some(mut iter) = LocationRangeUnitIter::new(self, sections, probe, probe + 1)? {
+ match iter.next() {
+ None => Ok(None),
+ Some((_addr, _len, loc)) => Ok(Some(loc)),
+ }
+ } else {
+ Ok(None)
+ }
+ }
+
+ #[inline]
+ fn find_location_range(
+ &self,
+ probe_low: u64,
+ probe_high: u64,
+ sections: &gimli::Dwarf<R>,
+ ) -> Result<Option<LocationRangeUnitIter<'_>>, Error> {
+ LocationRangeUnitIter::new(self, sections, probe_low, probe_high)
+ }
+
+ fn find_function_or_location(
+ &self,
+ probe: u64,
+ dwarf: &ResDwarf<R>,
+ ) -> Result<(Option<&Function<R>>, Option<Location<'_>>), Error> {
+ let functions = self.parse_functions(dwarf)?;
+ let function = match functions.find_address(probe) {
+ Some(address) => {
+ let function_index = functions.addresses[address].function;
+ let (offset, ref function) = functions.functions[function_index];
+ Some(
+ function
+ .borrow_with(|| Function::parse(offset, &self.dw_unit, dwarf))
+ .as_ref()
+ .map_err(Error::clone)?,
+ )
+ }
+ None => None,
+ };
+ let location = self.find_location(probe, &dwarf.sections)?;
+ Ok((function, location))
+ }
+
+ fn render_file(
+ &self,
+ file: &gimli::FileEntry<R, R::Offset>,
+ header: &gimli::LineProgramHeader<R, R::Offset>,
+ sections: &gimli::Dwarf<R>,
+ ) -> Result<String, gimli::Error> {
+ let mut path = if let Some(ref comp_dir) = self.dw_unit.comp_dir {
+ comp_dir.to_string_lossy()?.into_owned()
+ } else {
+ String::new()
+ };
+
+ if let Some(directory) = file.directory(header) {
+ path_push(
+ &mut path,
+ sections
+ .attr_string(&self.dw_unit, directory)?
+ .to_string_lossy()?
+ .as_ref(),
+ );
+ }
+
+ path_push(
+ &mut path,
+ sections
+ .attr_string(&self.dw_unit, file.path_name())?
+ .to_string_lossy()?
+ .as_ref(),
+ );
+
+ Ok(path)
+ }
+}
+
+/// Iterator over `Location`s in a range of addresses, returned by `Context::find_location_range`.
+pub struct LocationRangeIter<'ctx, R: gimli::Reader> {
+ unit_iter: Box<dyn Iterator<Item = (&'ctx ResUnit<R>, &'ctx gimli::Range)> + 'ctx>,
+ iter: Option<LocationRangeUnitIter<'ctx>>,
+
+ probe_low: u64,
+ probe_high: u64,
+ sections: &'ctx gimli::Dwarf<R>,
+}
+
+impl<'ctx, R: gimli::Reader> LocationRangeIter<'ctx, R> {
+ #[inline]
+ fn new(ctx: &'ctx Context<R>, probe_low: u64, probe_high: u64) -> Result<Self, Error> {
+ let sections = &ctx.dwarf.sections;
+ let unit_iter = ctx.find_units_range(probe_low, probe_high);
+ Ok(Self {
+ unit_iter: Box::new(unit_iter),
+ iter: None,
+ probe_low,
+ probe_high,
+ sections,
+ })
+ }
+
+ fn next_loc(&mut self) -> Result<Option<(u64, u64, Location<'ctx>)>, Error> {
+ loop {
+ let iter = self.iter.take();
+ match iter {
+ None => match self.unit_iter.next() {
+ Some((unit, range)) => {
+ self.iter = unit.find_location_range(
+ cmp::max(self.probe_low, range.begin),
+ cmp::min(self.probe_high, range.end),
+ self.sections,
+ )?;
+ }
+ None => return Ok(None),
+ },
+ Some(mut iter) => {
+ if let item @ Some(_) = iter.next() {
+ self.iter = Some(iter);
+ return Ok(item);
+ }
+ }
+ }
+ }
+ }
+}
+
+impl<'ctx, R> Iterator for LocationRangeIter<'ctx, R>
+where
+ R: gimli::Reader + 'ctx,
+{
+ type Item = (u64, u64, Location<'ctx>);
+
+ #[inline]
+ fn next(&mut self) -> Option<Self::Item> {
+ match self.next_loc() {
+ Err(_) => None,
+ Ok(loc) => loc,
+ }
+ }
+}
+
+#[cfg(feature = "fallible-iterator")]
+impl<'ctx, R> fallible_iterator::FallibleIterator for LocationRangeIter<'ctx, R>
+where
+ R: gimli::Reader + 'ctx,
+{
+ type Item = (u64, u64, Location<'ctx>);
+ type Error = Error;
+
+ #[inline]
+ fn next(&mut self) -> Result<Option<Self::Item>, Self::Error> {
+ self.next_loc()
+ }
+}
+
+struct LocationRangeUnitIter<'ctx> {
+ lines: &'ctx Lines,
+ seqs: &'ctx [LineSequence],
+ seq_idx: usize,
+ row_idx: usize,
+ probe_high: u64,
+}
+
+impl<'ctx> LocationRangeUnitIter<'ctx> {
+ fn new<R: gimli::Reader>(
+ resunit: &'ctx ResUnit<R>,
+ sections: &gimli::Dwarf<R>,
+ probe_low: u64,
+ probe_high: u64,
+ ) -> Result<Option<Self>, Error> {
+ let lines = resunit.parse_lines(sections)?;
+
+ if let Some(lines) = lines {
+ // Find index for probe_low.
+ let seq_idx = lines.sequences.binary_search_by(|sequence| {
+ if probe_low < sequence.start {
+ Ordering::Greater
+ } else if probe_low >= sequence.end {
+ Ordering::Less
+ } else {
+ Ordering::Equal
+ }
+ });
+ let seq_idx = match seq_idx {
+ Ok(x) => x,
+ Err(0) => 0, // probe below sequence, but range could overlap
+ Err(_) => lines.sequences.len(),
+ };
+
+ let row_idx = if let Some(seq) = lines.sequences.get(seq_idx) {
+ let idx = seq.rows.binary_search_by(|row| row.address.cmp(&probe_low));
+ let idx = match idx {
+ Ok(x) => x,
+ Err(0) => 0, // probe below sequence, but range could overlap
+ Err(x) => x - 1,
+ };
+ idx
+ } else {
+ 0
+ };
+
+ Ok(Some(Self {
+ lines,
+ seqs: &*lines.sequences,
+ seq_idx,
+ row_idx,
+ probe_high,
+ }))
+ } else {
+ Ok(None)
+ }
+ }
+}
+
+impl<'ctx> Iterator for LocationRangeUnitIter<'ctx> {
+ type Item = (u64, u64, Location<'ctx>);
+
+ fn next(&mut self) -> Option<(u64, u64, Location<'ctx>)> {
+ loop {
+ let seq = match self.seqs.get(self.seq_idx) {
+ Some(seq) => seq,
+ None => break,
+ };
+
+ if seq.start >= self.probe_high {
+ break;
+ }
+
+ match seq.rows.get(self.row_idx) {
+ Some(row) => {
+ if row.address >= self.probe_high {
+ break;
+ }
+
+ let file = self
+ .lines
+ .files
+ .get(row.file_index as usize)
+ .map(String::as_str);
+ let nextaddr = seq
+ .rows
+ .get(self.row_idx + 1)
+ .map(|row| row.address)
+ .unwrap_or(seq.end);
+
+ let item = (
+ row.address,
+ nextaddr - row.address,
+ Location {
+ file,
+ line: if row.line != 0 { Some(row.line) } else { None },
+ column: if row.column != 0 {
+ Some(row.column)
+ } else {
+ None
+ },
+ },
+ );
+ self.row_idx += 1;
+
+ return Some(item);
+ }
+ None => {
+ self.seq_idx += 1;
+ self.row_idx = 0;
+ }
+ }
+ }
+ None
+ }
+}
+
+fn path_push(path: &mut String, p: &str) {
+ if has_unix_root(p) || has_windows_root(p) {
+ *path = p.to_string();
+ } else {
+ let dir_separator = if has_windows_root(path.as_str()) {
+ '\\'
+ } else {
+ '/'
+ };
+
+ if !path.ends_with(dir_separator) {
+ path.push(dir_separator);
+ }
+ *path += p;
+ }
+}
+
+/// Check if the path in the given string has a unix style root
+fn has_unix_root(p: &str) -> bool {
+ p.starts_with('/')
+}
+
+/// Check if the path in the given string has a windows style root
+fn has_windows_root(p: &str) -> bool {
+ p.starts_with('\\') || p.get(1..3) == Some(":\\")
+}
+struct RangeAttributes<R: gimli::Reader> {
+ low_pc: Option<u64>,
+ high_pc: Option<u64>,
+ size: Option<u64>,
+ ranges_offset: Option<gimli::RangeListsOffset<<R as gimli::Reader>::Offset>>,
+}
+
+impl<R: gimli::Reader> Default for RangeAttributes<R> {
+ fn default() -> Self {
+ RangeAttributes {
+ low_pc: None,
+ high_pc: None,
+ size: None,
+ ranges_offset: None,
+ }
+ }
+}
+
+impl<R: gimli::Reader> RangeAttributes<R> {
+ fn for_each_range<F: FnMut(gimli::Range)>(
+ &self,
+ sections: &gimli::Dwarf<R>,
+ unit: &gimli::Unit<R>,
+ mut f: F,
+ ) -> Result<bool, Error> {
+ let mut added_any = false;
+ let mut add_range = |range: gimli::Range| {
+ if range.begin < range.end {
+ f(range);
+ added_any = true
+ }
+ };
+ if let Some(ranges_offset) = self.ranges_offset {
+ let mut range_list = sections.ranges(unit, ranges_offset)?;
+ while let Some(range) = range_list.next()? {
+ add_range(range);
+ }
+ } 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,
+ });
+ }
+ Ok(added_any)
+ }
+}
+
+/// An iterator over function frames.
+pub struct FrameIter<'ctx, R>(FrameIterState<'ctx, R>)
+where
+ R: gimli::Reader + 'ctx;
+
+enum FrameIterState<'ctx, R>
+where
+ R: gimli::Reader + 'ctx,
+{
+ Empty,
+ Location(Option<Location<'ctx>>),
+ Frames(FrameIterFrames<'ctx, R>),
+}
+
+struct FrameIterFrames<'ctx, R>
+where
+ R: gimli::Reader + 'ctx,
+{
+ unit: &'ctx ResUnit<R>,
+ sections: &'ctx gimli::Dwarf<R>,
+ function: &'ctx Function<R>,
+ inlined_functions: iter::Rev<maybe_small::IntoIter<&'ctx InlinedFunction<R>>>,
+ next: Option<Location<'ctx>>,
+}
+
+impl<'ctx, R> FrameIter<'ctx, R>
+where
+ R: gimli::Reader + 'ctx,
+{
+ /// Advances the iterator and returns the next frame.
+ pub fn next(&mut self) -> Result<Option<Frame<'ctx, R>>, Error> {
+ let frames = match &mut self.0 {
+ FrameIterState::Empty => return Ok(None),
+ FrameIterState::Location(location) => {
+ // We can't move out of a mutable reference, so use `take` instead.
+ let location = location.take();
+ self.0 = FrameIterState::Empty;
+ return Ok(Some(Frame {
+ dw_die_offset: None,
+ function: None,
+ location,
+ }));
+ }
+ FrameIterState::Frames(frames) => frames,
+ };
+
+ let loc = frames.next.take();
+ let func = match frames.inlined_functions.next() {
+ Some(func) => func,
+ None => {
+ let frame = Frame {
+ dw_die_offset: Some(frames.function.dw_die_offset),
+ function: frames.function.name.clone().map(|name| FunctionName {
+ name,
+ language: frames.unit.lang,
+ }),
+ location: loc,
+ };
+ self.0 = FrameIterState::Empty;
+ return Ok(Some(frame));
+ }
+ };
+
+ let mut next = Location {
+ file: None,
+ line: if func.call_line != 0 {
+ Some(func.call_line)
+ } else {
+ None
+ },
+ column: if func.call_column != 0 {
+ Some(func.call_column)
+ } else {
+ None
+ },
+ };
+ if func.call_file != 0 {
+ if let Some(lines) = frames.unit.parse_lines(frames.sections)? {
+ next.file = lines.files.get(func.call_file as usize).map(String::as_str);
+ }
+ }
+ frames.next = Some(next);
+
+ Ok(Some(Frame {
+ dw_die_offset: Some(func.dw_die_offset),
+ function: func.name.clone().map(|name| FunctionName {
+ name,
+ language: frames.unit.lang,
+ }),
+ location: loc,
+ }))
+ }
+}
+
+#[cfg(feature = "fallible-iterator")]
+impl<'ctx, R> fallible_iterator::FallibleIterator for FrameIter<'ctx, R>
+where
+ R: gimli::Reader + 'ctx,
+{
+ type Item = Frame<'ctx, R>;
+ type Error = Error;
+
+ #[inline]
+ fn next(&mut self) -> Result<Option<Frame<'ctx, R>>, Error> {
+ self.next()
+ }
+}
+
+/// A function frame.
+pub struct Frame<'ctx, R: gimli::Reader> {
+ /// The DWARF unit offset corresponding to the DIE of the function.
+ pub dw_die_offset: Option<gimli::UnitOffset<R::Offset>>,
+ /// The name of the function.
+ pub function: Option<FunctionName<R>>,
+ /// The source location corresponding to this frame.
+ pub location: Option<Location<'ctx>>,
+}
+
+/// A function name.
+pub struct FunctionName<R: gimli::Reader> {
+ /// The name of the function.
+ pub name: R,
+ /// The language of the compilation unit containing this function.
+ pub language: Option<gimli::DwLang>,
+}
+
+impl<R: gimli::Reader> FunctionName<R> {
+ /// The raw name of this function before demangling.
+ pub fn raw_name(&self) -> Result<Cow<str>, Error> {
+ self.name.to_string_lossy()
+ }
+
+ /// The name of this function after demangling (if applicable).
+ pub fn demangle(&self) -> Result<Cow<str>, Error> {
+ self.raw_name().map(|x| demangle_auto(x, self.language))
+ }
+}
+
+/// Demangle a symbol name using the demangling scheme for the given language.
+///
+/// Returns `None` if demangling failed or is not required.
+#[allow(unused_variables)]
+pub fn demangle(name: &str, language: gimli::DwLang) -> Option<String> {
+ match language {
+ #[cfg(feature = "rustc-demangle")]
+ gimli::DW_LANG_Rust => rustc_demangle::try_demangle(name)
+ .ok()
+ .as_ref()
+ .map(|x| format!("{:#}", x)),
+ #[cfg(feature = "cpp_demangle")]
+ gimli::DW_LANG_C_plus_plus
+ | gimli::DW_LANG_C_plus_plus_03
+ | gimli::DW_LANG_C_plus_plus_11
+ | gimli::DW_LANG_C_plus_plus_14 => cpp_demangle::Symbol::new(name)
+ .ok()
+ .and_then(|x| x.demangle(&Default::default()).ok()),
+ _ => None,
+ }
+}
+
+/// Apply 'best effort' demangling of a symbol name.
+///
+/// If `language` is given, then only the demangling scheme for that language
+/// is used.
+///
+/// If `language` is `None`, then heuristics are used to determine how to
+/// demangle the name. Currently, these heuristics are very basic.
+///
+/// If demangling fails or is not required, then `name` is returned unchanged.
+pub fn demangle_auto(name: Cow<str>, language: Option<gimli::DwLang>) -> Cow<str> {
+ match language {
+ Some(language) => demangle(name.as_ref(), language),
+ None => demangle(name.as_ref(), gimli::DW_LANG_Rust)
+ .or_else(|| demangle(name.as_ref(), gimli::DW_LANG_C_plus_plus)),
+ }
+ .map(Cow::from)
+ .unwrap_or(name)
+}
+
+/// A source location.
+pub struct Location<'a> {
+ /// The file name.
+ pub file: Option<&'a str>,
+ /// The line number.
+ pub line: Option<u32>,
+ /// The column number.
+ pub column: Option<u32>,
+}
+
+#[cfg(test)]
+mod tests {
+ #[test]
+ fn context_is_send() {
+ fn assert_is_send<T: Send>() {}
+ assert_is_send::<crate::Context<gimli::read::EndianSlice<gimli::LittleEndian>>>();
+ }
+}
diff --git a/vendor/addr2line/tests/correctness.rs b/vendor/addr2line/tests/correctness.rs
new file mode 100644
index 000000000..3f7b43373
--- /dev/null
+++ b/vendor/addr2line/tests/correctness.rs
@@ -0,0 +1,91 @@
+extern crate addr2line;
+extern crate fallible_iterator;
+extern crate findshlibs;
+extern crate gimli;
+extern crate memmap;
+extern crate object;
+
+use addr2line::Context;
+use fallible_iterator::FallibleIterator;
+use findshlibs::{IterationControl, SharedLibrary, TargetSharedLibrary};
+use object::Object;
+use std::fs::File;
+
+fn find_debuginfo() -> memmap::Mmap {
+ let path = std::env::current_exe().unwrap();
+ let file = File::open(&path).unwrap();
+ let map = unsafe { memmap::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 { memmap::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 ctx = Context::new(file).unwrap();
+
+ let mut bias = None;
+ TargetSharedLibrary::each(|lib| {
+ bias = Some(lib.virtual_memory_bias().0 as u64);
+ IterationControl::Break
+ });
+
+ let test = |sym: u64, expected_prefix: &str| {
+ let ip = sym.wrapping_sub(bias.unwrap());
+
+ let frames = ctx.find_frames(ip).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).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 000000000..9dc366672
--- /dev/null
+++ b/vendor/addr2line/tests/output_equivalence.rs
@@ -0,0 +1,145 @@
+extern crate backtrace;
+extern crate findshlibs;
+extern crate rustc_test as test;
+
+use std::env;
+use std::ffi::OsStr;
+use std::path::Path;
+use std::process::Command;
+
+use backtrace::Backtrace;
+use findshlibs::{IterationControl, SharedLibrary, TargetSharedLibrary};
+use test::{ShouldPanic, TestDesc, TestDescAndFn, TestFn, TestName};
+
+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>) {
+ 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
+ );
+ }
+}
+
+static FLAGS: &'static str = "aipsf";
+
+fn make_tests() -> Vec<TestDescAndFn> {
+ (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| TestDescAndFn {
+ desc: TestDesc {
+ name: TestName::DynTestName(format!(
+ "addr2line {}",
+ param.as_ref().map_or("", String::as_str)
+ )),
+ ignore: false,
+ should_panic: ShouldPanic::No,
+ allow_fail: false,
+ },
+ testfn: TestFn::DynTestFn(Box::new(move || {
+ run_test(param.as_ref().map(String::as_str))
+ })),
+ })
+ .collect()
+}
+
+fn main() {
+ if !cfg!(target_os = "linux") {
+ return;
+ }
+ let args: Vec<_> = env::args().collect();
+ test::test_main(&args, make_tests());
+}
diff --git a/vendor/addr2line/tests/parse.rs b/vendor/addr2line/tests/parse.rs
new file mode 100644
index 000000000..91d66e382
--- /dev/null
+++ b/vendor/addr2line/tests/parse.rs
@@ -0,0 +1,118 @@
+extern crate addr2line;
+extern crate memmap;
+extern crate object;
+
+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 { memmap::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();
+ });
+}