summaryrefslogtreecommitdiff
path: root/vendor/addr2line
diff options
context:
space:
mode:
authorValentin Popov <valentin@popov.link>2024-01-08 00:21:28 +0300
committerValentin Popov <valentin@popov.link>2024-01-08 00:21:28 +0300
commit1b6a04ca5504955c571d1c97504fb45ea0befee4 (patch)
tree7579f518b23313e8a9748a88ab6173d5e030b227 /vendor/addr2line
parent5ecd8cf2cba827454317368b68571df0d13d7842 (diff)
downloadfparkan-1b6a04ca5504955c571d1c97504fb45ea0befee4.tar.xz
fparkan-1b6a04ca5504955c571d1c97504fb45ea0befee4.zip
Initial vendor packages
Signed-off-by: Valentin Popov <valentin@popov.link>
Diffstat (limited to 'vendor/addr2line')
-rw-r--r--vendor/addr2line/.cargo-checksum.json1
-rw-r--r--vendor/addr2line/CHANGELOG.md336
-rw-r--r--vendor/addr2line/Cargo.lock704
-rw-r--r--vendor/addr2line/Cargo.toml147
-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.rs317
-rw-r--r--vendor/addr2line/rustfmt.toml1
-rw-r--r--vendor/addr2line/src/builtin_split_dwarf_loader.rs164
-rw-r--r--vendor/addr2line/src/function.rs555
-rw-r--r--vendor/addr2line/src/lazy.rs31
-rw-r--r--vendor/addr2line/src/lib.rs1729
-rw-r--r--vendor/addr2line/tests/correctness.rs126
-rw-r--r--vendor/addr2line/tests/output_equivalence.rs135
-rw-r--r--vendor/addr2line/tests/parse.rs114
19 files changed, 4774 insertions, 0 deletions
diff --git a/vendor/addr2line/.cargo-checksum.json b/vendor/addr2line/.cargo-checksum.json
new file mode 100644
index 0000000..5b12782
--- /dev/null
+++ b/vendor/addr2line/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"CHANGELOG.md":"ef9fa958318e442f1da7d204494cefec75c144aa6d5d5c93b0a5d6fcdf4ef6c6","Cargo.lock":"20b23c454fc3127f08a1bcd2864bbf029793759e6411fba24d44d8f4b7831ad0","Cargo.toml":"d0f15fde73d42bdf00e93f960dff908447225bede9364cb1659e44740a536c04","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"e99d88d232bf57d70f0fb87f6b496d44b6653f99f8a63d250a54c61ea4bcde40","README.md":"76d28502bd2e83f6a9e3576bd45e9a7fe5308448c4b5384b0d249515b5f67a5c","bench.plot.r":"6a5d7a4d36ed6b3d9919be703a479bef47698bf947818b483ff03951df2d4e01","benchmark.sh":"b35f89b1ca2c1dc0476cdd07f0284b72d41920d1c7b6054072f50ffba296d78d","coverage.sh":"4677e81922d08a82e83068a911717a247c66af12e559f37b78b6be3337ac9f07","examples/addr2line.rs":"3c5eb5a6726634df6cf53e4d67ee9f90c9ac09838303947f45c3bea1e84548b5","rustfmt.toml":"01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b","src/builtin_split_dwarf_loader.rs":"dc6979de81b35f82e97275e6be27ec61f3c4225ea10574a9e031813e00185174","src/function.rs":"68f047e0c78afe18ad165db255c8254ee74c35cd6df0cc07e400252981f661ed","src/lazy.rs":"0bf23f7098f1902f181e43c2ffa82a3f86df2c0dbcb9bc0ebce6a0168dd8b060","src/lib.rs":"9d6531f71fd138d31cc7596db9ab234198d0895a21ea9cb116434c19ec78b660","tests/correctness.rs":"4081f8019535305e3aa254c6a4e1436272dd873f9717c687ca0e66ea8d5871ed","tests/output_equivalence.rs":"b2cd7c59fa55808a2e66e9fe7f160d846867e3ecefe22c22a818f822c3c41f23","tests/parse.rs":"c2f7362e4679c1b4803b12ec6e8dca6da96aed7273fd210a857524a4182c30e7"},"package":"8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"} \ No newline at end of file
diff --git a/vendor/addr2line/CHANGELOG.md b/vendor/addr2line/CHANGELOG.md
new file mode 100644
index 0000000..8754c71
--- /dev/null
+++ b/vendor/addr2line/CHANGELOG.md
@@ -0,0 +1,336 @@
+# `addr2line` Change Log
+
+--------------------------------------------------------------------------------
+
+## 0.21.0 (2023/08/12)
+
+### Breaking changes
+
+* Updated `gimli`, `object`, and `fallible-iterator` dependencies.
+
+### Changed
+
+* The minimum supported rust version is 1.65.0.
+
+* Store boxed slices instead of `Vec` objects in `Context`.
+ [#278](https://github.com/gimli-rs/addr2line/pull/278)
+
+--------------------------------------------------------------------------------
+
+## 0.20.0 (2023/04/15)
+
+### Breaking changes
+
+* The minimum supported rust version is 1.58.0.
+
+* Changed `Context::find_frames` to return `LookupResult`.
+ Use `LookupResult::skip_all_loads` to obtain the result without loading split DWARF.
+ [#260](https://github.com/gimli-rs/addr2line/pull/260)
+
+* Replaced `Context::find_dwarf_unit` with `Context::find_dwarf_and_unit`.
+ [#260](https://github.com/gimli-rs/addr2line/pull/260)
+
+* Updated `object` dependency.
+
+### Changed
+
+* Fix handling of file index 0 for DWARF 5.
+ [#264](https://github.com/gimli-rs/addr2line/pull/264)
+
+### Added
+
+* Added types and methods to support loading split DWARF:
+ `LookupResult`, `SplitDwarfLoad`, `SplitDwarfLoader`, `Context::preload_units`.
+ [#260](https://github.com/gimli-rs/addr2line/pull/260)
+ [#262](https://github.com/gimli-rs/addr2line/pull/262)
+ [#263](https://github.com/gimli-rs/addr2line/pull/263)
+
+--------------------------------------------------------------------------------
+
+## 0.19.0 (2022/11/24)
+
+### Breaking changes
+
+* Updated `gimli` and `object` dependencies.
+
+--------------------------------------------------------------------------------
+
+## 0.18.0 (2022/07/16)
+
+### Breaking changes
+
+* Updated `object` dependency.
+
+### Changed
+
+* Fixed handling of relative path for `DW_AT_comp_dir`.
+ [#239](https://github.com/gimli-rs/addr2line/pull/239)
+
+* Fixed handling of `DW_FORM_addrx` for DWARF 5 support.
+ [#243](https://github.com/gimli-rs/addr2line/pull/243)
+
+* Fixed handling of units that are missing range information.
+ [#249](https://github.com/gimli-rs/addr2line/pull/249)
+
+--------------------------------------------------------------------------------
+
+## 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 outputs 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 0000000..3c23002
--- /dev/null
+++ b/vendor/addr2line/Cargo.lock
@@ -0,0 +1,704 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "addr2line"
+version = "0.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97"
+dependencies = [
+ "gimli 0.27.2",
+]
+
+[[package]]
+name = "addr2line"
+version = "0.21.0"
+dependencies = [
+ "backtrace",
+ "clap",
+ "compiler_builtins",
+ "cpp_demangle",
+ "fallible-iterator",
+ "findshlibs",
+ "gimli 0.28.0",
+ "libtest-mimic",
+ "memmap2",
+ "object 0.32.0",
+ "rustc-demangle",
+ "rustc-std-workspace-alloc",
+ "rustc-std-workspace-core",
+ "smallvec",
+ "typed-arena",
+]
+
+[[package]]
+name = "adler"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
+
+[[package]]
+name = "anstream"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163"
+dependencies = [
+ "anstyle",
+ "anstyle-parse",
+ "anstyle-query",
+ "anstyle-wincon",
+ "colorchoice",
+ "is-terminal",
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd"
+
+[[package]]
+name = "anstyle-parse"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333"
+dependencies = [
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle-query"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
+name = "anstyle-wincon"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c677ab05e09154296dd37acecd46420c17b9713e8366facafa8fc0885167cf4c"
+dependencies = [
+ "anstyle",
+ "windows-sys",
+]
+
+[[package]]
+name = "backtrace"
+version = "0.3.67"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca"
+dependencies = [
+ "addr2line 0.19.0",
+ "cc",
+ "cfg-if",
+ "libc",
+ "miniz_oxide",
+ "object 0.30.3",
+ "rustc-demangle",
+]
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "bitflags"
+version = "2.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
+
+[[package]]
+name = "byteorder"
+version = "1.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
+
+[[package]]
+name = "cc"
+version = "1.0.79"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "clap"
+version = "4.3.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c27cdf28c0f604ba3f512b0c9a409f8de8513e4816705deb0498b627e7c3a3fd"
+dependencies = [
+ "clap_builder",
+ "clap_derive",
+ "once_cell",
+]
+
+[[package]]
+name = "clap_builder"
+version = "4.3.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08a9f1ab5e9f01a9b81f202e8562eb9a10de70abf9eaeac1be465c28b75aa4aa"
+dependencies = [
+ "anstream",
+ "anstyle",
+ "clap_lex",
+ "strsim",
+ "terminal_size",
+]
+
+[[package]]
+name = "clap_derive"
+version = "4.3.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "54a9bb5758fc5dfe728d1019941681eccaf0cf8a4189b692a0ee2f2ecf90a050"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.15",
+]
+
+[[package]]
+name = "clap_lex"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b"
+
+[[package]]
+name = "colorchoice"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
+
+[[package]]
+name = "compiler_builtins"
+version = "0.1.91"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "571298a3cce7e2afbd3d61abb91a18667d5ab25993ec577a88ee8ac45f00cc3a"
+
+[[package]]
+name = "cpp_demangle"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2c76f98bdfc7f66172e6c7065f981ebb576ffc903fe4c0561d9f0c2509226dc6"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "crc32fast"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "errno"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f"
+dependencies = [
+ "errno-dragonfly",
+ "libc",
+ "windows-sys",
+]
+
+[[package]]
+name = "errno-dragonfly"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
+dependencies = [
+ "cc",
+ "libc",
+]
+
+[[package]]
+name = "fallible-iterator"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
+
+[[package]]
+name = "findshlibs"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "40b9e59cd0f7e0806cca4be089683ecb6434e602038df21fe6bf6711b2f07f64"
+dependencies = [
+ "cc",
+ "lazy_static",
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "flate2"
+version = "1.0.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841"
+dependencies = [
+ "crc32fast",
+ "miniz_oxide",
+]
+
+[[package]]
+name = "gimli"
+version = "0.27.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4"
+
+[[package]]
+name = "gimli"
+version = "0.28.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
+dependencies = [
+ "compiler_builtins",
+ "fallible-iterator",
+ "rustc-std-workspace-alloc",
+ "rustc-std-workspace-core",
+ "stable_deref_trait",
+]
+
+[[package]]
+name = "heck"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
+
+[[package]]
+name = "hermit-abi"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "hermit-abi"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
+
+[[package]]
+name = "io-lifetimes"
+version = "1.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
+dependencies = [
+ "hermit-abi 0.3.2",
+ "libc",
+ "windows-sys",
+]
+
+[[package]]
+name = "is-terminal"
+version = "0.4.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
+dependencies = [
+ "hermit-abi 0.3.2",
+ "rustix 0.38.8",
+ "windows-sys",
+]
+
+[[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.147"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
+
+[[package]]
+name = "libtest-mimic"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d8de370f98a6cb8a4606618e53e802f93b094ddec0f96988eaec2c27e6e9ce7"
+dependencies = [
+ "clap",
+ "termcolor",
+ "threadpool",
+]
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503"
+
+[[package]]
+name = "memchr"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
+
+[[package]]
+name = "memmap2"
+version = "0.5.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "miniz_oxide"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa"
+dependencies = [
+ "adler",
+]
+
+[[package]]
+name = "num_cpus"
+version = "1.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
+dependencies = [
+ "hermit-abi 0.2.6",
+ "libc",
+]
+
+[[package]]
+name = "object"
+version = "0.30.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "object"
+version = "0.32.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77ac5bbd07aea88c60a577a1ce218075ffd59208b2d7ca97adf9bfc5aeb21ebe"
+dependencies = [
+ "flate2",
+ "memchr",
+ "ruzstd",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.17.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.56"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "rustc-demangle"
+version = "0.1.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d4a36c42d1873f9a77c53bde094f9664d9891bc604a45b4798fd2c389ed12e5b"
+
+[[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 = "rustix"
+version = "0.37.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06"
+dependencies = [
+ "bitflags 1.3.2",
+ "errno",
+ "io-lifetimes",
+ "libc",
+ "linux-raw-sys 0.3.8",
+ "windows-sys",
+]
+
+[[package]]
+name = "rustix"
+version = "0.38.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19ed4fa021d81c8392ce04db050a3da9a60299050b7ae1cf482d862b54a7218f"
+dependencies = [
+ "bitflags 2.4.0",
+ "errno",
+ "libc",
+ "linux-raw-sys 0.4.5",
+ "windows-sys",
+]
+
+[[package]]
+name = "ruzstd"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3ffab8f9715a0d455df4bbb9d21e91135aab3cd3ca187af0cd0c3c3f868fdc"
+dependencies = [
+ "byteorder",
+ "thiserror-core",
+ "twox-hash",
+]
+
+[[package]]
+name = "smallvec"
+version = "1.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
+
+[[package]]
+name = "stable_deref_trait"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
+
+[[package]]
+name = "static_assertions"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
+
+[[package]]
+name = "strsim"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
+
+[[package]]
+name = "syn"
+version = "1.0.109"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "termcolor"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "terminal_size"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237"
+dependencies = [
+ "rustix 0.37.23",
+ "windows-sys",
+]
+
+[[package]]
+name = "thiserror-core"
+version = "1.0.38"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d97345f6437bb2004cd58819d8a9ef8e36cdd7661c2abc4bbde0a7c40d9f497"
+dependencies = [
+ "thiserror-core-impl",
+]
+
+[[package]]
+name = "thiserror-core-impl"
+version = "1.0.38"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "10ac1c5050e43014d16b2f94d0d2ce79e65ffdd8b38d8048f9c8f6a8a6da62ac"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "threadpool"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa"
+dependencies = [
+ "num_cpus",
+]
+
+[[package]]
+name = "twox-hash"
+version = "1.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675"
+dependencies = [
+ "cfg-if",
+ "static_assertions",
+]
+
+[[package]]
+name = "typed-arena"
+version = "2.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
+
+[[package]]
+name = "utf8parse"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
+
+[[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-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "windows-sys"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.48.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
diff --git a/vendor/addr2line/Cargo.toml b/vendor/addr2line/Cargo.toml
new file mode 100644
index 0000000..b6b6b83
--- /dev/null
+++ b/vendor/addr2line/Cargo.toml
@@ -0,0 +1,147 @@
+# 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 are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2018"
+rust-version = "1.65"
+name = "addr2line"
+version = "0.21.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
+
+[profile.release]
+debug = true
+
+[[example]]
+name = "addr2line"
+required-features = ["default"]
+
+[[test]]
+name = "output_equivalence"
+harness = false
+required-features = ["default"]
+
+[[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.4"
+features = ["alloc"]
+optional = true
+default-features = false
+
+[dependencies.fallible-iterator]
+version = "0.3.0"
+optional = true
+default-features = false
+
+[dependencies.gimli]
+version = "0.28.0"
+features = ["read"]
+default-features = false
+
+[dependencies.memmap2]
+version = "0.5.5"
+optional = true
+
+[dependencies.object]
+version = "0.32.0"
+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 = "4.3.21"
+features = ["wrap_help"]
+
+[dev-dependencies.findshlibs]
+version = "0.10"
+
+[dev-dependencies.libtest-mimic]
+version = "0.6.1"
+
+[dev-dependencies.typed-arena]
+version = "2"
+
+[features]
+default = [
+ "rustc-demangle",
+ "cpp_demangle",
+ "std-object",
+ "fallible-iterator",
+ "smallvec",
+ "memmap2",
+]
+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 0000000..16fe87b
--- /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 0000000..3a03f1f
--- /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 0000000..dc6cb93
--- /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 0000000..ecbf248
--- /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 0000000..ca4c4f6
--- /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 0000000..892c0b7
--- /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 0000000..97fc802
--- /dev/null
+++ b/vendor/addr2line/examples/addr2line.rs
@@ -0,0 +1,317 @@
+use std::borrow::Cow;
+use std::fs::File;
+use std::io::{BufRead, Lines, StdinLock, Write};
+use std::path::{Path, PathBuf};
+
+use clap::{Arg, ArgAction, Command};
+use fallible_iterator::FallibleIterator;
+use object::{Object, ObjectSection, SymbolMap, SymbolMapName};
+use typed_arena::Arena;
+
+use addr2line::{Context, Location};
+
+fn parse_uint_from_hex_string(string: &str) -> Option<u64> {
+ if string.len() > 2 && string.starts_with("0x") {
+ u64::from_str_radix(&string[2..], 16).ok()
+ } else {
+ u64::from_str_radix(string, 16).ok()
+ }
+}
+
+enum Addrs<'a> {
+ Args(clap::parser::ValuesRef<'a, String>),
+ Stdin(Lines<StdinLock<'a>>),
+}
+
+impl<'a> Iterator for Addrs<'a> {
+ type Item = Option<u64>;
+
+ fn next(&mut self) -> Option<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(loc) = loc {
+ if let Some(ref file) = loc.file.as_ref() {
+ let path = if basenames {
+ Path::new(Path::new(file).file_name().unwrap())
+ } else {
+ Path::new(file)
+ };
+ print!("{}:", path.display());
+ } else {
+ print!("??:");
+ }
+ 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!("??:0");
+ }
+}
+
+fn print_function(name: Option<&str>, language: Option<gimli::DwLang>, demangle: bool) {
+ if let Some(name) = name {
+ if demangle {
+ print!("{}", addr2line::demangle_auto(Cow::from(name), language));
+ } else {
+ print!("{}", name);
+ }
+ } else {
+ print!("??");
+ }
+}
+
+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 find_name_from_symbols<'a>(
+ symbols: &'a SymbolMap<SymbolMapName<'_>>,
+ probe: u64,
+) -> Option<&'a str> {
+ symbols.get(probe).map(|x| x.name())
+}
+
+struct Options<'a> {
+ do_functions: bool,
+ do_inlines: bool,
+ pretty: bool,
+ print_addrs: bool,
+ basenames: bool,
+ demangle: bool,
+ llvm: bool,
+ exe: &'a PathBuf,
+ sup: Option<&'a PathBuf>,
+}
+
+fn main() {
+ let matches = Command::new("addr2line")
+ .version(env!("CARGO_PKG_VERSION"))
+ .about("A fast addr2line Rust port")
+ .max_term_width(100)
+ .args(&[
+ Arg::new("exe")
+ .short('e')
+ .long("exe")
+ .value_name("filename")
+ .value_parser(clap::value_parser!(PathBuf))
+ .help(
+ "Specify the name of the executable for which addresses should be translated.",
+ )
+ .required(true),
+ Arg::new("sup")
+ .long("sup")
+ .value_name("filename")
+ .value_parser(clap::value_parser!(PathBuf))
+ .help("Path to supplementary object file."),
+ Arg::new("functions")
+ .short('f')
+ .long("functions")
+ .action(ArgAction::SetTrue)
+ .help("Display function names as well as file and line number information."),
+ Arg::new("pretty").short('p').long("pretty-print")
+ .action(ArgAction::SetTrue)
+ .help(
+ "Make the output more human friendly: each location are printed on one line.",
+ ),
+ Arg::new("inlines").short('i').long("inlines")
+ .action(ArgAction::SetTrue)
+ .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::new("addresses").short('a').long("addresses")
+ .action(ArgAction::SetTrue)
+ .help(
+ "Display the address before the function name, file and line number information.",
+ ),
+ Arg::new("basenames")
+ .short('s')
+ .long("basenames")
+ .action(ArgAction::SetTrue)
+ .help("Display only the base of each file name."),
+ Arg::new("demangle").short('C').long("demangle")
+ .action(ArgAction::SetTrue)
+ .help(
+ "Demangle function names. \
+ Specifying a specific demangling style (like GNU addr2line) is not supported. \
+ (TODO)"
+ ),
+ Arg::new("llvm")
+ .long("llvm")
+ .action(ArgAction::SetTrue)
+ .help("Display output in the same format as llvm-symbolizer."),
+ Arg::new("addrs")
+ .action(ArgAction::Append)
+ .help("Addresses to use instead of reading from stdin."),
+ ])
+ .get_matches();
+
+ let arena_data = Arena::new();
+
+ let opts = Options {
+ do_functions: matches.get_flag("functions"),
+ do_inlines: matches.get_flag("inlines"),
+ pretty: matches.get_flag("pretty"),
+ print_addrs: matches.get_flag("addresses"),
+ basenames: matches.get_flag("basenames"),
+ demangle: matches.get_flag("demangle"),
+ llvm: matches.get_flag("llvm"),
+ exe: matches.get_one::<PathBuf>("exe").unwrap(),
+ sup: matches.get_one::<PathBuf>("sup"),
+ };
+
+ let file = File::open(opts.exe).unwrap();
+ let map = unsafe { memmap2::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) = opts.sup {
+ let sup_file = File::open(sup_path).unwrap();
+ sup_map = unsafe { memmap2::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 mut split_dwarf_loader = addr2line::builtin_split_dwarf_loader::SplitDwarfLoader::new(
+ |data, endian| {
+ gimli::EndianSlice::new(arena_data.alloc(Cow::Owned(data.into_owned())), endian)
+ },
+ Some(opts.exe.clone()),
+ );
+ let ctx = Context::from_dwarf(dwarf).unwrap();
+
+ let stdin = std::io::stdin();
+ let addrs = matches
+ .get_many::<String>("addrs")
+ .map(Addrs::Args)
+ .unwrap_or_else(|| Addrs::Stdin(stdin.lock().lines()));
+
+ for probe in addrs {
+ if opts.print_addrs {
+ let addr = probe.unwrap_or(0);
+ if opts.llvm {
+ print!("0x{:x}", addr);
+ } else {
+ print!("0x{:016x}", addr);
+ }
+ if opts.pretty {
+ print!(": ");
+ } else {
+ println!();
+ }
+ }
+
+ if opts.do_functions || opts.do_inlines {
+ let mut printed_anything = false;
+ if let Some(probe) = probe {
+ let frames = ctx.find_frames(probe);
+ let frames = split_dwarf_loader.run(frames).unwrap();
+ let mut frames = frames.enumerate();
+ while let Some((i, frame)) = frames.next().unwrap() {
+ if opts.pretty && i != 0 {
+ print!(" (inlined by) ");
+ }
+
+ if opts.do_functions {
+ if let Some(func) = frame.function {
+ print_function(
+ func.raw_name().ok().as_ref().map(AsRef::as_ref),
+ func.language,
+ opts.demangle,
+ );
+ } else {
+ let name = find_name_from_symbols(&symbols, probe);
+ print_function(name, None, opts.demangle);
+ }
+
+ if opts.pretty {
+ print!(" at ");
+ } else {
+ println!();
+ }
+ }
+
+ print_loc(frame.location.as_ref(), opts.basenames, opts.llvm);
+
+ printed_anything = true;
+
+ if !opts.do_inlines {
+ break;
+ }
+ }
+ }
+
+ if !printed_anything {
+ if opts.do_functions {
+ let name = probe.and_then(|probe| find_name_from_symbols(&symbols, probe));
+ print_function(name, None, opts.demangle);
+
+ if opts.pretty {
+ print!(" at ");
+ } else {
+ println!();
+ }
+ }
+
+ print_loc(None, opts.basenames, opts.llvm);
+ }
+ } else {
+ let loc = probe.and_then(|probe| ctx.find_location(probe).unwrap());
+ print_loc(loc.as_ref(), opts.basenames, opts.llvm);
+ }
+
+ if opts.llvm {
+ println!();
+ }
+ std::io::stdout().flush().unwrap();
+ }
+}
diff --git a/vendor/addr2line/rustfmt.toml b/vendor/addr2line/rustfmt.toml
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/vendor/addr2line/rustfmt.toml
@@ -0,0 +1 @@
+
diff --git a/vendor/addr2line/src/builtin_split_dwarf_loader.rs b/vendor/addr2line/src/builtin_split_dwarf_loader.rs
new file mode 100644
index 0000000..4711931
--- /dev/null
+++ b/vendor/addr2line/src/builtin_split_dwarf_loader.rs
@@ -0,0 +1,164 @@
+use alloc::borrow::Cow;
+use alloc::sync::Arc;
+use std::fs::File;
+use std::path::PathBuf;
+
+use object::Object;
+
+use crate::{LookupContinuation, LookupResult};
+
+#[cfg(unix)]
+fn convert_path<R: gimli::Reader<Endian = gimli::RunTimeEndian>>(
+ r: &R,
+) -> Result<PathBuf, gimli::Error> {
+ use std::ffi::OsStr;
+ use std::os::unix::ffi::OsStrExt;
+ let bytes = r.to_slice()?;
+ let s = OsStr::from_bytes(&bytes);
+ Ok(PathBuf::from(s))
+}
+
+#[cfg(not(unix))]
+fn convert_path<R: gimli::Reader<Endian = gimli::RunTimeEndian>>(
+ r: &R,
+) -> Result<PathBuf, gimli::Error> {
+ let bytes = r.to_slice()?;
+ let s = std::str::from_utf8(&bytes).map_err(|_| gimli::Error::BadUtf8)?;
+ Ok(PathBuf::from(s))
+}
+
+fn load_section<'data: 'file, 'file, O, R, F>(
+ id: gimli::SectionId,
+ file: &'file O,
+ endian: R::Endian,
+ loader: &mut F,
+) -> Result<R, gimli::Error>
+where
+ O: object::Object<'data, 'file>,
+ R: gimli::Reader<Endian = gimli::RunTimeEndian>,
+ F: FnMut(Cow<'data, [u8]>, R::Endian) -> R,
+{
+ use object::ObjectSection;
+
+ let data = id
+ .dwo_name()
+ .and_then(|dwo_name| {
+ file.section_by_name(dwo_name)
+ .and_then(|section| section.uncompressed_data().ok())
+ })
+ .unwrap_or(Cow::Borrowed(&[]));
+ Ok(loader(data, endian))
+}
+
+/// A simple builtin split DWARF loader.
+pub struct SplitDwarfLoader<R, F>
+where
+ R: gimli::Reader<Endian = gimli::RunTimeEndian>,
+ F: FnMut(Cow<'_, [u8]>, R::Endian) -> R,
+{
+ loader: F,
+ dwarf_package: Option<gimli::DwarfPackage<R>>,
+}
+
+impl<R, F> SplitDwarfLoader<R, F>
+where
+ R: gimli::Reader<Endian = gimli::RunTimeEndian>,
+ F: FnMut(Cow<'_, [u8]>, R::Endian) -> R,
+{
+ fn load_dwarf_package(loader: &mut F, path: Option<PathBuf>) -> Option<gimli::DwarfPackage<R>> {
+ let mut path = path.map(Ok).unwrap_or_else(std::env::current_exe).ok()?;
+ let dwp_extension = path
+ .extension()
+ .map(|previous_extension| {
+ let mut previous_extension = previous_extension.to_os_string();
+ previous_extension.push(".dwp");
+ previous_extension
+ })
+ .unwrap_or_else(|| "dwp".into());
+ path.set_extension(dwp_extension);
+ let file = File::open(&path).ok()?;
+ let map = unsafe { memmap2::Mmap::map(&file).ok()? };
+ let dwp = object::File::parse(&*map).ok()?;
+
+ let endian = if dwp.is_little_endian() {
+ gimli::RunTimeEndian::Little
+ } else {
+ gimli::RunTimeEndian::Big
+ };
+
+ let empty = loader(Cow::Borrowed(&[]), endian);
+ gimli::DwarfPackage::load(
+ |section_id| load_section(section_id, &dwp, endian, loader),
+ empty,
+ )
+ .ok()
+ }
+
+ /// Create a new split DWARF loader.
+ pub fn new(mut loader: F, path: Option<PathBuf>) -> SplitDwarfLoader<R, F> {
+ let dwarf_package = SplitDwarfLoader::load_dwarf_package(&mut loader, path);
+ SplitDwarfLoader {
+ loader,
+ dwarf_package,
+ }
+ }
+
+ /// Run the provided `LookupResult` to completion, loading any necessary
+ /// split DWARF along the way.
+ pub fn run<L>(&mut self, mut l: LookupResult<L>) -> L::Output
+ where
+ L: LookupContinuation<Buf = R>,
+ {
+ loop {
+ let (load, continuation) = match l {
+ LookupResult::Output(output) => break output,
+ LookupResult::Load { load, continuation } => (load, continuation),
+ };
+
+ let mut r: Option<Arc<gimli::Dwarf<_>>> = None;
+ if let Some(dwp) = self.dwarf_package.as_ref() {
+ if let Ok(Some(cu)) = dwp.find_cu(load.dwo_id, &load.parent) {
+ r = Some(Arc::new(cu));
+ }
+ }
+
+ if r.is_none() {
+ let mut path = PathBuf::new();
+ if let Some(p) = load.comp_dir.as_ref() {
+ if let Ok(p) = convert_path(p) {
+ path.push(p);
+ }
+ }
+
+ if let Some(p) = load.path.as_ref() {
+ if let Ok(p) = convert_path(p) {
+ path.push(p);
+ }
+ }
+
+ if let Ok(file) = File::open(&path) {
+ if let Ok(map) = unsafe { memmap2::Mmap::map(&file) } {
+ if let Ok(file) = object::File::parse(&*map) {
+ let endian = if file.is_little_endian() {
+ gimli::RunTimeEndian::Little
+ } else {
+ gimli::RunTimeEndian::Big
+ };
+
+ r = gimli::Dwarf::load(|id| {
+ load_section(id, &file, endian, &mut self.loader)
+ })
+ .ok()
+ .map(|mut dwo_dwarf| {
+ dwo_dwarf.make_dwo(&load.parent);
+ Arc::new(dwo_dwarf)
+ });
+ }
+ }
+ }
+ }
+
+ l = continuation.resume(r);
+ }
+ }
+}
diff --git a/vendor/addr2line/src/function.rs b/vendor/addr2line/src/function.rs
new file mode 100644
index 0000000..09c19e0
--- /dev/null
+++ b/vendor/addr2line/src/function.rs
@@ -0,0 +1,555 @@
+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::{Context, DebugFile, Error, RangeAttributes};
+
+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: Option<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>,
+ sections: &gimli::Dwarf<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 => match attr.value() {
+ gimli::AttributeValue::Addr(val) => {
+ ranges.low_pc = Some(val)
+ }
+ gimli::AttributeValue::DebugAddrIndex(index) => {
+ ranges.low_pc = Some(sections.address(unit, index)?);
+ }
+ _ => {}
+ },
+ gimli::DW_AT_high_pc => match attr.value() {
+ gimli::AttributeValue::Addr(val) => {
+ ranges.high_pc = Some(val)
+ }
+ gimli::AttributeValue::DebugAddrIndex(index) => {
+ ranges.high_pc = Some(sections.address(unit, index)?);
+ }
+ gimli::AttributeValue::Udata(val) => {
+ ranges.size = Some(val)
+ }
+ _ => {}
+ },
+ gimli::DW_AT_ranges => {
+ ranges.ranges_offset =
+ sections.attr_ranges_offset(unit, attr.value())?;
+ }
+ _ => {}
+ };
+ }
+ Err(e) => return Err(e),
+ }
+ }
+
+ let function_index = functions.len();
+ if ranges.for_each_range(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,
+ file: DebugFile,
+ unit: &gimli::Unit<R>,
+ ctx: &Context<R>,
+ sections: &gimli::Dwarf<R>,
+ ) -> Result<(), Error> {
+ for function in &*self.functions {
+ function
+ .1
+ .borrow_with(|| Function::parse(function.0, file, unit, ctx, sections))
+ .as_ref()
+ .map_err(Error::clone)?;
+ }
+ Ok(())
+ }
+}
+
+impl<R: gimli::Reader> Function<R> {
+ pub(crate) fn parse(
+ dw_die_offset: gimli::UnitOffset<R::Offset>,
+ file: DebugFile,
+ unit: &gimli::Unit<R>,
+ ctx: &Context<R>,
+ sections: &gimli::Dwarf<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) = sections.attr_string(unit, attr.value()) {
+ name = Some(val);
+ }
+ }
+ gimli::DW_AT_name => {
+ if name.is_none() {
+ name = 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(), file, unit, ctx, sections, 16)?;
+ }
+ }
+ _ => {}
+ };
+ }
+ Err(e) => return Err(e),
+ }
+ }
+
+ let mut inlined_functions = Vec::new();
+ let mut inlined_addresses = Vec::new();
+ Function::parse_children(
+ &mut entries,
+ depth,
+ file,
+ unit,
+ ctx,
+ sections,
+ &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,
+ file: DebugFile,
+ unit: &gimli::Unit<R>,
+ ctx: &Context<R>,
+ sections: &gimli::Dwarf<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,
+ file,
+ unit,
+ ctx,
+ sections,
+ 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,
+ file: DebugFile,
+ unit: &gimli::Unit<R>,
+ ctx: &Context<R>,
+ sections: &gimli::Dwarf<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 = None;
+ 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 => match attr.value() {
+ gimli::AttributeValue::Addr(val) => ranges.low_pc = Some(val),
+ gimli::AttributeValue::DebugAddrIndex(index) => {
+ ranges.low_pc = Some(sections.address(unit, index)?);
+ }
+ _ => {}
+ },
+ gimli::DW_AT_high_pc => match attr.value() {
+ gimli::AttributeValue::Addr(val) => ranges.high_pc = Some(val),
+ gimli::AttributeValue::DebugAddrIndex(index) => {
+ ranges.high_pc = Some(sections.address(unit, index)?);
+ }
+ gimli::AttributeValue::Udata(val) => ranges.size = Some(val),
+ _ => {}
+ },
+ gimli::DW_AT_ranges => {
+ ranges.ranges_offset = sections.attr_ranges_offset(unit, attr.value())?;
+ }
+ gimli::DW_AT_linkage_name | gimli::DW_AT_MIPS_linkage_name => {
+ if let Ok(val) = sections.attr_string(unit, attr.value()) {
+ name = Some(val);
+ }
+ }
+ gimli::DW_AT_name => {
+ if name.is_none() {
+ name = 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(), file, unit, ctx, sections, 16)?;
+ }
+ }
+ gimli::DW_AT_call_file => {
+ // There is a spec issue [1] with how DW_AT_call_file is specified in DWARF 5.
+ // Before, a file index of 0 would indicate no source file, however in
+ // DWARF 5 this could be a valid index into the file table.
+ //
+ // Implementations such as LLVM generates a file index of 0 when DWARF 5 is
+ // used.
+ //
+ // Thus, if we see a version of 5 or later, treat a file index of 0 as such.
+ // [1]: http://wiki.dwarfstd.org/index.php?title=DWARF5_Line_Table_File_Numbers
+ if let gimli::AttributeValue::FileIndex(fi) = attr.value() {
+ if fi > 0 || unit.header.version() >= 5 {
+ call_file = Some(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(sections, unit, |range| {
+ inlined_addresses.push(InlinedFunctionAddress {
+ range,
+ call_depth: inlined_depth,
+ function: function_index,
+ });
+ })?;
+
+ Function::parse_children(
+ entries,
+ depth,
+ file,
+ unit,
+ ctx,
+ sections,
+ inlined_functions,
+ inlined_addresses,
+ inlined_depth + 1,
+ )
+ }
+}
+
+fn name_attr<R>(
+ attr: gimli::AttributeValue<R>,
+ mut file: DebugFile,
+ unit: &gimli::Unit<R>,
+ ctx: &Context<R>,
+ sections: &gimli::Dwarf<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(file, unit, offset, ctx, sections, recursion_limit)
+ }
+ gimli::AttributeValue::DebugInfoRef(dr) => {
+ let (unit, offset) = ctx.find_unit(dr, file)?;
+ name_entry(file, unit, offset, ctx, sections, recursion_limit)
+ }
+ gimli::AttributeValue::DebugInfoRefSup(dr) => {
+ if let Some(sup_sections) = sections.sup.as_ref() {
+ file = DebugFile::Supplementary;
+ let (unit, offset) = ctx.find_unit(dr, file)?;
+ name_entry(file, unit, offset, ctx, sup_sections, recursion_limit)
+ } else {
+ Ok(None)
+ }
+ }
+ _ => Ok(None),
+ }
+}
+
+fn name_entry<R>(
+ file: DebugFile,
+ unit: &gimli::Unit<R>,
+ offset: gimli::UnitOffset<R::Offset>,
+ ctx: &Context<R>,
+ sections: &gimli::Dwarf<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) = sections.attr_string(unit, attr.value()) {
+ return Ok(Some(val));
+ }
+ }
+ gimli::DW_AT_name => {
+ if let Ok(val) = 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, file, unit, ctx, sections, recursion_limit - 1);
+ }
+
+ Ok(None)
+}
diff --git a/vendor/addr2line/src/lazy.rs b/vendor/addr2line/src/lazy.rs
new file mode 100644
index 0000000..2df2ed6
--- /dev/null
+++ b/vendor/addr2line/src/lazy.rs
@@ -0,0 +1,31 @@
+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(&self) -> Option<&T> {
+ unsafe { &*self.contents.get() }.as_ref()
+ }
+
+ pub fn borrow_with(&self, closure: impl FnOnce() -> T) -> &T {
+ // First check if we're already initialized...
+ let ptr = self.contents.get();
+ if let Some(val) = unsafe { &*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();
+ unsafe { (*ptr).get_or_insert(val) }
+ }
+}
diff --git a/vendor/addr2line/src/lib.rs b/vendor/addr2line/src/lib.rs
new file mode 100644
index 0000000..3270aad
--- /dev/null
+++ b/vendor/addr2line/src/lib.rs
@@ -0,0 +1,1729 @@
+//! 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]
+
+#[cfg(feature = "std")]
+extern crate std;
+
+#[allow(unused_imports)]
+#[macro_use]
+extern crate alloc;
+
+#[cfg(feature = "fallible-iterator")]
+pub extern crate fallible_iterator;
+pub extern crate gimli;
+#[cfg(feature = "object")]
+pub extern crate object;
+
+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::marker::PhantomData;
+use core::mem;
+use core::num::NonZeroU64;
+use core::ops::ControlFlow;
+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>;
+}
+
+#[cfg(all(feature = "std", feature = "object", feature = "memmap2"))]
+/// A simple builtin split DWARF loader.
+pub mod builtin_split_dwarf_loader;
+mod function;
+mod lazy;
+
+type Error = gimli::Error;
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+enum DebugFile {
+ Primary,
+ Supplementary,
+ Dwo,
+}
+
+/// Operations that consult debug information may require additional files
+/// to be loaded if split DWARF is being used. This enum returns the result
+/// of the operation in the `Break` variant, or information about the split
+/// DWARF that is required and a continuation to invoke once it is available
+/// in the `Continue` variant.
+///
+/// This enum is intended to be used in a loop like so:
+/// ```no_run
+/// # use addr2line::*;
+/// # use std::sync::Arc;
+/// # let ctx: Context<gimli::EndianRcSlice<gimli::RunTimeEndian>> = todo!();
+/// # let do_split_dwarf_load = |load: SplitDwarfLoad<gimli::EndianRcSlice<gimli::RunTimeEndian>>| -> Option<Arc<gimli::Dwarf<gimli::EndianRcSlice<gimli::RunTimeEndian>>>> { None };
+/// const ADDRESS: u64 = 0xdeadbeef;
+/// let mut r = ctx.find_frames(ADDRESS);
+/// let result = loop {
+/// match r {
+/// LookupResult::Output(result) => break result,
+/// LookupResult::Load { load, continuation } => {
+/// let dwo = do_split_dwarf_load(load);
+/// r = continuation.resume(dwo);
+/// }
+/// }
+/// };
+/// ```
+pub enum LookupResult<L: LookupContinuation> {
+ /// The lookup requires split DWARF data to be loaded.
+ Load {
+ /// The information needed to find the split DWARF data.
+ load: SplitDwarfLoad<<L as LookupContinuation>::Buf>,
+ /// The continuation to resume with the loaded split DWARF data.
+ continuation: L,
+ },
+ /// The lookup has completed and produced an output.
+ Output(<L as LookupContinuation>::Output),
+}
+
+/// This trait represents a partially complete operation that can be resumed
+/// once a load of needed split DWARF data is completed or abandoned by the
+/// API consumer.
+pub trait LookupContinuation: Sized {
+ /// The final output of this operation.
+ type Output;
+ /// The type of reader used.
+ type Buf: gimli::Reader;
+
+ /// Resumes the operation with the provided data.
+ ///
+ /// After the caller loads the split DWARF data required, call this
+ /// method to resume the operation. The return value of this method
+ /// indicates if the computation has completed or if further data is
+ /// required.
+ ///
+ /// If the additional data cannot be located, or the caller does not
+ /// support split DWARF, `resume(None)` can be used to continue the
+ /// operation with the data that is available.
+ fn resume(self, input: Option<Arc<gimli::Dwarf<Self::Buf>>>) -> LookupResult<Self>;
+}
+
+impl<L: LookupContinuation> LookupResult<L> {
+ /// Callers that do not handle split DWARF can call `skip_all_loads`
+ /// to fast-forward to the end result. This result is produced with
+ /// the data that is available and may be less accurate than the
+ /// the results that would be produced if the caller did properly
+ /// support split DWARF.
+ pub fn skip_all_loads(mut self) -> L::Output {
+ loop {
+ self = match self {
+ LookupResult::Output(t) => return t,
+ LookupResult::Load { continuation, .. } => continuation.resume(None),
+ };
+ }
+ }
+
+ fn map<T, F: FnOnce(L::Output) -> T>(self, f: F) -> LookupResult<MappedLookup<T, L, F>> {
+ match self {
+ LookupResult::Output(t) => LookupResult::Output(f(t)),
+ LookupResult::Load { load, continuation } => LookupResult::Load {
+ load,
+ continuation: MappedLookup {
+ original: continuation,
+ mutator: f,
+ },
+ },
+ }
+ }
+
+ fn unwrap(self) -> L::Output {
+ match self {
+ LookupResult::Output(t) => t,
+ LookupResult::Load { .. } => unreachable!("Internal API misuse"),
+ }
+ }
+}
+
+/// 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> {
+ sections: Arc<gimli::Dwarf<R>>,
+ unit_ranges: Box<[UnitRange]>,
+ units: Box<[ResUnit<R>]>,
+ sup_units: Box<[SupUnit<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 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.into(),
+ ),
+ ranges: gimli::RangeLists::new(debug_ranges, debug_rnglists),
+ file_type: gimli::DwarfFileType::Main,
+ sup: None,
+ abbreviations_cache: gimli::AbbreviationsCache::new(),
+ })
+ }
+
+ /// Construct a new `Context` from an existing [`gimli::Dwarf`] object.
+ #[inline]
+ pub fn from_dwarf(sections: gimli::Dwarf<R>) -> Result<Context<R>, Error> {
+ let sections = Arc::new(sections);
+ let (unit_ranges, units) = Context::parse_units(&sections)?;
+ let sup_units = if let Some(sup) = sections.sup.as_ref() {
+ Context::parse_sup(sup)?
+ } else {
+ Vec::new()
+ };
+ Ok(Context {
+ sections,
+ unit_ranges: unit_ranges.into_boxed_slice(),
+ units: units.into_boxed_slice(),
+ sup_units: sup_units.into_boxed_slice(),
+ })
+ }
+
+ /// 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
+ .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.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.units[i.unit_id], &i.range))
+ })
+ }
+
+ /// Find the DWARF unit corresponding to the given virtual memory address.
+ pub fn find_dwarf_and_unit(
+ &self,
+ probe: u64,
+ ) -> LookupResult<
+ impl LookupContinuation<Output = Option<(&gimli::Dwarf<R>, &gimli::Unit<R>)>, Buf = R>,
+ > {
+ let mut units_iter = self.find_units(probe);
+ if let Some(unit) = units_iter.next() {
+ return LoopingLookup::new_lookup(
+ unit.find_function_or_location(probe, self),
+ move |r| {
+ ControlFlow::Break(match r {
+ Ok((Some(_), _)) | Ok((_, Some(_))) => {
+ let (_file, sections, unit) = unit
+ .dwarf_and_unit_dwo(self)
+ // We've already been through both error cases here to get to this point.
+ .unwrap()
+ .unwrap();
+ Some((sections, unit))
+ }
+ _ => match units_iter.next() {
+ Some(next_unit) => {
+ return ControlFlow::Continue(
+ next_unit.find_function_or_location(probe, self),
+ );
+ }
+ None => None,
+ },
+ })
+ },
+ );
+ }
+
+ LoopingLookup::new_complete(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.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,
+ ) -> LookupResult<impl LookupContinuation<Output = Result<FrameIter<'_, R>, Error>, Buf = R>>
+ {
+ let mut units_iter = self.find_units(probe);
+ if let Some(unit) = units_iter.next() {
+ LoopingLookup::new_lookup(unit.find_function_or_location(probe, self), move |r| {
+ ControlFlow::Break(match r {
+ Err(e) => Err(e),
+ Ok((Some(function), location)) => {
+ let inlined_functions = function.find_inlined_functions(probe);
+ Ok(FrameIter(FrameIterState::Frames(FrameIterFrames {
+ unit,
+ sections: &self.sections,
+ function,
+ inlined_functions,
+ next: location,
+ })))
+ }
+ Ok((None, Some(location))) => {
+ Ok(FrameIter(FrameIterState::Location(Some(location))))
+ }
+ Ok((None, None)) => match units_iter.next() {
+ Some(next_unit) => {
+ return ControlFlow::Continue(
+ next_unit.find_function_or_location(probe, self),
+ );
+ }
+ None => Ok(FrameIter(FrameIterState::Empty)),
+ },
+ })
+ })
+ } else {
+ LoopingLookup::new_complete(Ok(FrameIter(FrameIterState::Empty)))
+ }
+ }
+
+ /// Preload units for `probe`.
+ ///
+ /// The iterator returns pairs of `SplitDwarfLoad`s containing the
+ /// information needed to locate and load split DWARF for `probe` and
+ /// a matching callback to invoke once that data is available.
+ ///
+ /// If this method is called, and all of the returned closures are invoked,
+ /// addr2line guarantees that any future API call for the address `probe`
+ /// will not require the loading of any split DWARF.
+ ///
+ /// ```no_run
+ /// # use addr2line::*;
+ /// # use std::sync::Arc;
+ /// # let ctx: Context<gimli::EndianRcSlice<gimli::RunTimeEndian>> = todo!();
+ /// # let do_split_dwarf_load = |load: SplitDwarfLoad<gimli::EndianRcSlice<gimli::RunTimeEndian>>| -> Option<Arc<gimli::Dwarf<gimli::EndianRcSlice<gimli::RunTimeEndian>>>> { None };
+ /// const ADDRESS: u64 = 0xdeadbeef;
+ /// ctx.preload_units(ADDRESS).for_each(|(load, callback)| {
+ /// let dwo = do_split_dwarf_load(load);
+ /// callback(dwo);
+ /// });
+ ///
+ /// let frames_iter = match ctx.find_frames(ADDRESS) {
+ /// LookupResult::Output(result) => result,
+ /// LookupResult::Load { .. } => unreachable!("addr2line promised we wouldn't get here"),
+ /// };
+ ///
+ /// // ...
+ /// ```
+ pub fn preload_units(
+ &'_ self,
+ probe: u64,
+ ) -> impl Iterator<
+ Item = (
+ SplitDwarfLoad<R>,
+ impl FnOnce(Option<Arc<gimli::Dwarf<R>>>) -> Result<(), gimli::Error> + '_,
+ ),
+ > {
+ self.find_units(probe)
+ .filter_map(move |unit| match unit.dwarf_and_unit_dwo(self) {
+ LookupResult::Output(_) => None,
+ LookupResult::Load { load, continuation } => Some((load, |result| {
+ continuation.resume(result).unwrap().map(|_| ())
+ })),
+ })
+ }
+
+ /// Initialize all line data structures. This is used for benchmarks.
+ #[doc(hidden)]
+ pub fn parse_lines(&self) -> Result<(), Error> {
+ for unit in self.units.iter() {
+ unit.parse_lines(&self.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.units.iter() {
+ unit.parse_functions(self).skip_all_loads()?;
+ }
+ 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.units.iter() {
+ unit.parse_inlined_functions(self).skip_all_loads()?;
+ }
+ Ok(())
+ }
+}
+
+struct UnitRange {
+ unit_id: usize,
+ max_end: u64,
+ range: gimli::Range,
+}
+
+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>>,
+ dwo: LazyCell<Result<Option<Box<(Arc<gimli::Dwarf<R>>, gimli::Unit<R>)>>, Error>>,
+}
+
+struct SupUnit<R: gimli::Reader> {
+ offset: gimli::DebugInfoOffset<R::Offset>,
+ dw_unit: gimli::Unit<R>,
+}
+
+impl<R: gimli::Reader> Context<R> {
+ fn parse_units(sections: &gimli::Dwarf<R>) -> Result<(Vec<UnitRange>, Vec<ResUnit<R>>), 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 have_unit_range = false;
+ {
+ 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 => match attr.value() {
+ gimli::AttributeValue::Addr(val) => ranges.low_pc = Some(val),
+ gimli::AttributeValue::DebugAddrIndex(index) => {
+ ranges.low_pc = Some(sections.address(&dw_unit, index)?);
+ }
+ _ => {}
+ },
+ gimli::DW_AT_high_pc => match attr.value() {
+ gimli::AttributeValue::Addr(val) => ranges.high_pc = Some(val),
+ gimli::AttributeValue::DebugAddrIndex(index) => {
+ ranges.high_pc = Some(sections.address(&dw_unit, index)?);
+ }
+ 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,
+ });
+ have_unit_range = true;
+ }
+ }
+ }
+ } else {
+ have_unit_range |= ranges.for_each_range(sections, &dw_unit, |range| {
+ unit_ranges.push(UnitRange {
+ range,
+ unit_id,
+ max_end: 0,
+ });
+ })?;
+ }
+ }
+
+ let lines = LazyCell::new();
+ if !have_unit_range {
+ // The unit did not declare any ranges.
+ // Try to get some ranges from the line program sequences.
+ if let Some(ref ilnp) = dw_unit.line_program {
+ if let Ok(lines) = lines
+ .borrow_with(|| Lines::parse(&dw_unit, ilnp.clone(), sections))
+ .as_ref()
+ {
+ for sequence in lines.sequences.iter() {
+ unit_ranges.push(UnitRange {
+ range: gimli::Range {
+ begin: sequence.start,
+ end: sequence.end,
+ },
+ unit_id,
+ max_end: 0,
+ })
+ }
+ }
+ }
+ }
+
+ res_units.push(ResUnit {
+ offset,
+ dw_unit,
+ lang,
+ lines,
+ funcs: LazyCell::new(),
+ dwo: 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((unit_ranges, res_units))
+ }
+
+ fn parse_sup(sections: &gimli::Dwarf<R>) -> Result<Vec<SupUnit<R>>, Error> {
+ let mut sup_units = Vec::new();
+ let mut units = sections.units();
+ while let Some(header) = units.next()? {
+ let offset = match header.offset().as_debug_info_offset() {
+ Some(offset) => offset,
+ None => continue,
+ };
+ let dw_unit = match sections.unit(header) {
+ Ok(dw_unit) => dw_unit,
+ Err(_) => continue,
+ };
+ sup_units.push(SupUnit { dw_unit, offset });
+ }
+ Ok(sup_units)
+ }
+
+ // Find the unit containing the given offset, and convert the offset into a unit offset.
+ fn find_unit(
+ &self,
+ offset: gimli::DebugInfoOffset<R::Offset>,
+ file: DebugFile,
+ ) -> Result<(&gimli::Unit<R>, gimli::UnitOffset<R::Offset>), Error> {
+ let unit = match file {
+ DebugFile::Primary => {
+ 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) => return Err(gimli::Error::NoEntryAtGivenOffset),
+ Err(i) => &self.units[i - 1].dw_unit,
+ }
+ }
+ DebugFile::Supplementary => {
+ match self
+ .sup_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) => return Err(gimli::Error::NoEntryAtGivenOffset),
+ Err(i) => &self.sup_units[i - 1].dw_unit,
+ }
+ }
+ DebugFile::Dwo => return Err(gimli::Error::NoEntryAtGivenOffset),
+ };
+
+ let unit_offset = offset
+ .to_unit_offset(&unit.header)
+ .ok_or(gimli::Error::NoEntryAtGivenOffset)?;
+ Ok((unit, unit_offset))
+ }
+}
+
+struct Lines {
+ files: Box<[String]>,
+ sequences: Box<[LineSequence]>,
+}
+
+impl Lines {
+ fn parse<R: gimli::Reader>(
+ dw_unit: &gimli::Unit<R>,
+ ilnp: gimli::IncompleteLineProgram<R, R::Offset>,
+ sections: &gimli::Dwarf<R>,
+ ) -> Result<Self, Error> {
+ let mut sequences = Vec::new();
+ let mut sequence_rows = Vec::<LineRow>::new();
+ let mut rows = ilnp.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 = rows.header();
+ match header.file(0) {
+ Some(file) => files.push(render_file(dw_unit, 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(render_file(dw_unit, file, header, sections)?);
+ index += 1;
+ }
+
+ Ok(Self {
+ files: files.into_boxed_slice(),
+ sequences: sequences.into_boxed_slice(),
+ })
+ }
+}
+
+fn render_file<R: gimli::Reader>(
+ dw_unit: &gimli::Unit<R>,
+ 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) = dw_unit.comp_dir {
+ comp_dir.to_string_lossy()?.into_owned()
+ } else {
+ String::new()
+ };
+
+ // The directory index 0 is defined to correspond to the compilation unit directory.
+ if file.directory_index() != 0 {
+ if let Some(directory) = file.directory(header) {
+ path_push(
+ &mut path,
+ sections
+ .attr_string(dw_unit, directory)?
+ .to_string_lossy()?
+ .as_ref(),
+ );
+ }
+ }
+
+ path_push(
+ &mut path,
+ sections
+ .attr_string(dw_unit, file.path_name())?
+ .to_string_lossy()?
+ .as_ref(),
+ );
+
+ Ok(path)
+}
+
+struct LineSequence {
+ start: u64,
+ end: u64,
+ rows: Box<[LineRow]>,
+}
+
+struct LineRow {
+ address: u64,
+ file_index: u64,
+ line: u32,
+ column: u32,
+}
+
+/// This struct contains the information needed to find split DWARF data
+/// and to produce a `gimli::Dwarf<R>` for it.
+pub struct SplitDwarfLoad<R> {
+ /// The dwo id, for looking up in a DWARF package, or for
+ /// verifying an unpacked dwo found on the file system
+ pub dwo_id: gimli::DwoId,
+ /// The compilation directory `path` is relative to.
+ pub comp_dir: Option<R>,
+ /// A path on the filesystem, relative to `comp_dir` to find this dwo.
+ pub path: Option<R>,
+ /// Once the split DWARF data is loaded, the loader is expected
+ /// to call [make_dwo(parent)](gimli::read::Dwarf::make_dwo) before
+ /// returning the data.
+ pub parent: Arc<gimli::Dwarf<R>>,
+}
+
+struct SimpleLookup<T, R, F>
+where
+ F: FnOnce(Option<Arc<gimli::Dwarf<R>>>) -> T,
+ R: gimli::Reader,
+{
+ f: F,
+ phantom: PhantomData<(T, R)>,
+}
+
+impl<T, R, F> SimpleLookup<T, R, F>
+where
+ F: FnOnce(Option<Arc<gimli::Dwarf<R>>>) -> T,
+ R: gimli::Reader,
+{
+ fn new_complete(t: F::Output) -> LookupResult<SimpleLookup<T, R, F>> {
+ LookupResult::Output(t)
+ }
+
+ fn new_needs_load(load: SplitDwarfLoad<R>, f: F) -> LookupResult<SimpleLookup<T, R, F>> {
+ LookupResult::Load {
+ load,
+ continuation: SimpleLookup {
+ f,
+ phantom: PhantomData,
+ },
+ }
+ }
+}
+
+impl<T, R, F> LookupContinuation for SimpleLookup<T, R, F>
+where
+ F: FnOnce(Option<Arc<gimli::Dwarf<R>>>) -> T,
+ R: gimli::Reader,
+{
+ type Output = T;
+ type Buf = R;
+
+ fn resume(self, v: Option<Arc<gimli::Dwarf<Self::Buf>>>) -> LookupResult<Self> {
+ LookupResult::Output((self.f)(v))
+ }
+}
+
+struct MappedLookup<T, L, F>
+where
+ L: LookupContinuation,
+ F: FnOnce(L::Output) -> T,
+{
+ original: L,
+ mutator: F,
+}
+
+impl<T, L, F> LookupContinuation for MappedLookup<T, L, F>
+where
+ L: LookupContinuation,
+ F: FnOnce(L::Output) -> T,
+{
+ type Output = T;
+ type Buf = L::Buf;
+
+ fn resume(self, v: Option<Arc<gimli::Dwarf<Self::Buf>>>) -> LookupResult<Self> {
+ match self.original.resume(v) {
+ LookupResult::Output(t) => LookupResult::Output((self.mutator)(t)),
+ LookupResult::Load { load, continuation } => LookupResult::Load {
+ load,
+ continuation: MappedLookup {
+ original: continuation,
+ mutator: self.mutator,
+ },
+ },
+ }
+ }
+}
+
+/// Some functions (e.g. `find_frames`) require considering multiple
+/// compilation units, each of which might require their own split DWARF
+/// lookup (and thus produce a continuation).
+///
+/// We store the underlying continuation here as well as a mutator function
+/// that will either a) decide that the result of this continuation is
+/// what is needed and mutate it to the final result or b) produce another
+/// `LookupResult`. `new_lookup` will in turn eagerly drive any non-continuation
+/// `LookupResult` with successive invocations of the mutator, until a new
+/// continuation or a final result is produced. And finally, the impl of
+/// `LookupContinuation::resume` will call `new_lookup` each time the
+/// computation is resumed.
+struct LoopingLookup<T, L, F>
+where
+ L: LookupContinuation,
+ F: FnMut(L::Output) -> ControlFlow<T, LookupResult<L>>,
+{
+ continuation: L,
+ mutator: F,
+}
+
+impl<T, L, F> LoopingLookup<T, L, F>
+where
+ L: LookupContinuation,
+ F: FnMut(L::Output) -> ControlFlow<T, LookupResult<L>>,
+{
+ fn new_complete(t: T) -> LookupResult<Self> {
+ LookupResult::Output(t)
+ }
+
+ fn new_lookup(mut r: LookupResult<L>, mut mutator: F) -> LookupResult<Self> {
+ // Drive the loop eagerly so that we only ever have to represent one state
+ // (the r == ControlFlow::Continue state) in LoopingLookup.
+ loop {
+ match r {
+ LookupResult::Output(l) => match mutator(l) {
+ ControlFlow::Break(t) => return LookupResult::Output(t),
+ ControlFlow::Continue(r2) => {
+ r = r2;
+ }
+ },
+ LookupResult::Load { load, continuation } => {
+ return LookupResult::Load {
+ load,
+ continuation: LoopingLookup {
+ continuation,
+ mutator,
+ },
+ };
+ }
+ }
+ }
+ }
+}
+
+impl<T, L, F> LookupContinuation for LoopingLookup<T, L, F>
+where
+ L: LookupContinuation,
+ F: FnMut(L::Output) -> ControlFlow<T, LookupResult<L>>,
+{
+ type Output = T;
+ type Buf = L::Buf;
+
+ fn resume(self, v: Option<Arc<gimli::Dwarf<Self::Buf>>>) -> LookupResult<Self> {
+ let r = self.continuation.resume(v);
+ LoopingLookup::new_lookup(r, self.mutator)
+ }
+}
+
+impl<R: gimli::Reader> ResUnit<R> {
+ fn dwarf_and_unit_dwo<'unit, 'ctx: 'unit>(
+ &'unit self,
+ ctx: &'ctx Context<R>,
+ ) -> LookupResult<
+ SimpleLookup<
+ Result<(DebugFile, &'unit gimli::Dwarf<R>, &'unit gimli::Unit<R>), Error>,
+ R,
+ impl FnOnce(
+ Option<Arc<gimli::Dwarf<R>>>,
+ )
+ -> Result<(DebugFile, &'unit gimli::Dwarf<R>, &'unit gimli::Unit<R>), Error>,
+ >,
+ > {
+ loop {
+ break SimpleLookup::new_complete(match self.dwo.borrow() {
+ Some(Ok(Some(v))) => Ok((DebugFile::Dwo, &*v.0, &v.1)),
+ Some(Ok(None)) => Ok((DebugFile::Primary, &*ctx.sections, &self.dw_unit)),
+ Some(Err(e)) => Err(*e),
+ None => {
+ let dwo_id = match self.dw_unit.dwo_id {
+ None => {
+ self.dwo.borrow_with(|| Ok(None));
+ continue;
+ }
+ Some(dwo_id) => dwo_id,
+ };
+
+ let comp_dir = self.dw_unit.comp_dir.clone();
+
+ let dwo_name = self.dw_unit.dwo_name().and_then(|s| {
+ if let Some(s) = s {
+ Ok(Some(ctx.sections.attr_string(&self.dw_unit, s)?))
+ } else {
+ Ok(None)
+ }
+ });
+
+ let path = match dwo_name {
+ Ok(v) => v,
+ Err(e) => {
+ self.dwo.borrow_with(|| Err(e));
+ continue;
+ }
+ };
+
+ let process_dwo = move |dwo_dwarf: Option<Arc<gimli::Dwarf<R>>>| {
+ let dwo_dwarf = match dwo_dwarf {
+ None => return Ok(None),
+ Some(dwo_dwarf) => dwo_dwarf,
+ };
+ let mut dwo_units = dwo_dwarf.units();
+ let dwo_header = match dwo_units.next()? {
+ Some(dwo_header) => dwo_header,
+ None => return Ok(None),
+ };
+
+ let mut dwo_unit = dwo_dwarf.unit(dwo_header)?;
+ dwo_unit.copy_relocated_attributes(&self.dw_unit);
+ Ok(Some(Box::new((dwo_dwarf, dwo_unit))))
+ };
+
+ return SimpleLookup::new_needs_load(
+ SplitDwarfLoad {
+ dwo_id,
+ comp_dir,
+ path,
+ parent: ctx.sections.clone(),
+ },
+ move |dwo_dwarf| match self.dwo.borrow_with(|| process_dwo(dwo_dwarf)) {
+ Ok(Some(v)) => Ok((DebugFile::Dwo, &*v.0, &v.1)),
+ Ok(None) => Ok((DebugFile::Primary, &*ctx.sections, &self.dw_unit)),
+ Err(e) => Err(*e),
+ },
+ );
+ }
+ });
+ }
+ }
+
+ fn parse_lines(&self, sections: &gimli::Dwarf<R>) -> Result<Option<&Lines>, Error> {
+ // NB: line information is always stored in the main debug file so this does not need
+ // to handle DWOs.
+ let ilnp = match self.dw_unit.line_program {
+ Some(ref ilnp) => ilnp,
+ None => return Ok(None),
+ };
+ self.lines
+ .borrow_with(|| Lines::parse(&self.dw_unit, ilnp.clone(), sections))
+ .as_ref()
+ .map(Some)
+ .map_err(Error::clone)
+ }
+
+ fn parse_functions_dwarf_and_unit(
+ &self,
+ unit: &gimli::Unit<R>,
+ sections: &gimli::Dwarf<R>,
+ ) -> Result<&Functions<R>, Error> {
+ self.funcs
+ .borrow_with(|| Functions::parse(unit, sections))
+ .as_ref()
+ .map_err(Error::clone)
+ }
+
+ fn parse_functions<'unit, 'ctx: 'unit>(
+ &'unit self,
+ ctx: &'ctx Context<R>,
+ ) -> LookupResult<impl LookupContinuation<Output = Result<&'unit Functions<R>, Error>, Buf = R>>
+ {
+ self.dwarf_and_unit_dwo(ctx).map(move |r| {
+ let (_file, sections, unit) = r?;
+ self.parse_functions_dwarf_and_unit(unit, sections)
+ })
+ }
+ fn parse_inlined_functions<'unit, 'ctx: 'unit>(
+ &'unit self,
+ ctx: &'ctx Context<R>,
+ ) -> LookupResult<impl LookupContinuation<Output = Result<(), Error>, Buf = R> + 'unit> {
+ self.dwarf_and_unit_dwo(ctx).map(move |r| {
+ let (file, sections, unit) = r?;
+ self.funcs
+ .borrow_with(|| Functions::parse(unit, sections))
+ .as_ref()
+ .map_err(Error::clone)?
+ .parse_inlined_functions(file, unit, ctx, sections)
+ })
+ }
+
+ 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<'unit, 'ctx: 'unit>(
+ &'unit self,
+ probe: u64,
+ ctx: &'ctx Context<R>,
+ ) -> LookupResult<
+ impl LookupContinuation<
+ Output = Result<(Option<&'unit Function<R>>, Option<Location<'unit>>), Error>,
+ Buf = R,
+ >,
+ > {
+ self.dwarf_and_unit_dwo(ctx).map(move |r| {
+ let (file, sections, unit) = r?;
+ let functions = self.parse_functions_dwarf_and_unit(unit, sections)?;
+ 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, file, unit, ctx, sections))
+ .as_ref()
+ .map_err(Error::clone)?,
+ )
+ }
+ None => None,
+ };
+ let location = self.find_location(probe, sections)?;
+ Ok((function, location))
+ })
+ }
+}
+
+/// 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.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));
+ match idx {
+ Ok(x) => x,
+ Err(0) => 0, // probe below sequence, but range could overlap
+ Err(x) => x - 1,
+ }
+ } 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>)> {
+ while let Some(seq) = self.seqs.get(self.seq_idx) {
+ 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.is_empty() && !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;
+
+enum FrameIterState<'ctx, R>
+where
+ R: gimli::Reader,
+{
+ Empty,
+ Location(Option<Location<'ctx>>),
+ Frames(FrameIterFrames<'ctx, R>),
+}
+
+struct FrameIterFrames<'ctx, R>
+where
+ R: gimli::Reader,
+{
+ 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 let Some(call_file) = func.call_file {
+ if let Some(lines) = frames.unit.parse_lines(frames.sections)? {
+ next.file = lines.files.get(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 0000000..73ee462
--- /dev/null
+++ b/vendor/addr2line/tests/correctness.rs
@@ -0,0 +1,126 @@
+use addr2line::Context;
+use fallible_iterator::FallibleIterator;
+use findshlibs::{IterationControl, SharedLibrary, TargetSharedLibrary};
+use object::Object;
+use std::borrow::Cow;
+use std::fs::File;
+use std::sync::Arc;
+
+fn find_debuginfo() -> memmap2::Mmap {
+ let path = std::env::current_exe().unwrap();
+ let file = File::open(&path).unwrap();
+ let map = unsafe { memmap2::Mmap::map(&file).unwrap() };
+ let file = &object::File::parse(&*map).unwrap();
+ if let Ok(uuid) = file.mach_uuid() {
+ for candidate in path.parent().unwrap().read_dir().unwrap() {
+ let path = candidate.unwrap().path();
+ if !path.to_str().unwrap().ends_with(".dSYM") {
+ continue;
+ }
+ for candidate in path.join("Contents/Resources/DWARF").read_dir().unwrap() {
+ let path = candidate.unwrap().path();
+ let file = File::open(&path).unwrap();
+ let map = unsafe { memmap2::Mmap::map(&file).unwrap() };
+ let file = &object::File::parse(&*map).unwrap();
+ if file.mach_uuid().unwrap() == uuid {
+ return map;
+ }
+ }
+ }
+ }
+
+ return map;
+}
+
+#[test]
+fn correctness() {
+ let map = find_debuginfo();
+ let file = &object::File::parse(&*map).unwrap();
+ let module_base = file.relative_address_base();
+
+ let endian = if file.is_little_endian() {
+ gimli::RunTimeEndian::Little
+ } else {
+ gimli::RunTimeEndian::Big
+ };
+
+ fn load_section<'data: 'file, 'file, O, Endian>(
+ id: gimli::SectionId,
+ file: &'file O,
+ endian: Endian,
+ ) -> Result<gimli::EndianArcSlice<Endian>, gimli::Error>
+ where
+ O: object::Object<'data, 'file>,
+ Endian: gimli::Endianity,
+ {
+ use object::ObjectSection;
+
+ let data = file
+ .section_by_name(id.name())
+ .and_then(|section| section.uncompressed_data().ok())
+ .unwrap_or(Cow::Borrowed(&[]));
+ Ok(gimli::EndianArcSlice::new(Arc::from(&*data), endian))
+ }
+
+ let dwarf = gimli::Dwarf::load(|id| load_section(id, file, endian)).unwrap();
+ let ctx = Context::from_dwarf(dwarf).unwrap();
+ let mut split_dwarf_loader = addr2line::builtin_split_dwarf_loader::SplitDwarfLoader::new(
+ |data, endian| gimli::EndianArcSlice::new(Arc::from(&*data), endian),
+ None,
+ );
+
+ let mut bias = None;
+ TargetSharedLibrary::each(|lib| {
+ bias = Some((lib.virtual_memory_bias().0 as u64).wrapping_sub(module_base));
+ IterationControl::Break
+ });
+
+ #[allow(unused_mut)]
+ let mut test = |sym: u64, expected_prefix: &str| {
+ let ip = sym.wrapping_sub(bias.unwrap());
+
+ let frames = ctx.find_frames(ip);
+ let frames = split_dwarf_loader.run(frames).unwrap();
+ let frame = frames.last().unwrap().unwrap();
+ let name = frame.function.as_ref().unwrap().demangle().unwrap();
+ // Old rust versions generate DWARF with wrong linkage name,
+ // so only check the start.
+ if !name.starts_with(expected_prefix) {
+ panic!("incorrect name '{}', expected {:?}", name, expected_prefix);
+ }
+ };
+
+ test(test_function as u64, "correctness::test_function");
+ test(
+ small::test_function as u64,
+ "correctness::small::test_function",
+ );
+ test(auxiliary::foo as u64, "auxiliary::foo");
+}
+
+mod small {
+ pub fn test_function() {
+ println!("y");
+ }
+}
+
+fn test_function() {
+ println!("x");
+}
+
+#[test]
+fn zero_function() {
+ let map = find_debuginfo();
+ let file = &object::File::parse(&*map).unwrap();
+ let ctx = Context::new(file).unwrap();
+ for probe in 0..10 {
+ assert!(
+ ctx.find_frames(probe)
+ .skip_all_loads()
+ .unwrap()
+ .count()
+ .unwrap()
+ < 10
+ );
+ }
+}
diff --git a/vendor/addr2line/tests/output_equivalence.rs b/vendor/addr2line/tests/output_equivalence.rs
new file mode 100644
index 0000000..ef026e3
--- /dev/null
+++ b/vendor/addr2line/tests/output_equivalence.rs
@@ -0,0 +1,135 @@
+use std::env;
+use std::ffi::OsStr;
+use std::path::Path;
+use std::process::Command;
+
+use backtrace::Backtrace;
+use findshlibs::{IterationControl, SharedLibrary, TargetSharedLibrary};
+use libtest_mimic::{Arguments, Failed, Trial};
+
+#[inline(never)]
+fn make_trace() -> Vec<String> {
+ fn foo() -> Backtrace {
+ bar()
+ }
+ #[inline(never)]
+ fn bar() -> Backtrace {
+ baz()
+ }
+ #[inline(always)]
+ fn baz() -> Backtrace {
+ Backtrace::new_unresolved()
+ }
+
+ let mut base_addr = None;
+ TargetSharedLibrary::each(|lib| {
+ base_addr = Some(lib.virtual_memory_bias().0 as isize);
+ IterationControl::Break
+ });
+ let addrfix = -base_addr.unwrap();
+
+ let trace = foo();
+ trace
+ .frames()
+ .iter()
+ .take(5)
+ .map(|x| format!("{:p}", (x.ip() as *const u8).wrapping_offset(addrfix)))
+ .collect()
+}
+
+fn run_cmd<P: AsRef<OsStr>>(exe: P, me: &Path, flags: Option<&str>, trace: &str) -> String {
+ let mut cmd = Command::new(exe);
+ cmd.env("LC_ALL", "C"); // GNU addr2line is localized, we aren't
+ cmd.env("RUST_BACKTRACE", "1"); // if a child crashes, we want to know why
+
+ if let Some(flags) = flags {
+ cmd.arg(flags);
+ }
+ cmd.arg("--exe").arg(me).arg(trace);
+
+ let output = cmd.output().unwrap();
+
+ assert!(output.status.success());
+ String::from_utf8(output.stdout).unwrap()
+}
+
+fn run_test(flags: Option<&str>) -> Result<(), Failed> {
+ let me = env::current_exe().unwrap();
+ let mut exe = me.clone();
+ assert!(exe.pop());
+ if exe.file_name().unwrap().to_str().unwrap() == "deps" {
+ assert!(exe.pop());
+ }
+ exe.push("examples");
+ exe.push("addr2line");
+
+ assert!(exe.is_file());
+
+ let trace = make_trace();
+
+ // HACK: GNU addr2line has a bug where looking up multiple addresses can cause the second
+ // lookup to fail. Workaround by doing one address at a time.
+ for addr in &trace {
+ let theirs = run_cmd("addr2line", &me, flags, addr);
+ let ours = run_cmd(&exe, &me, flags, addr);
+
+ // HACK: GNU addr2line does not tidy up paths properly, causing double slashes to be printed.
+ // We consider our behavior to be correct, so we fix their output to match ours.
+ let theirs = theirs.replace("//", "/");
+
+ assert!(
+ theirs == ours,
+ "Output not equivalent:
+
+$ addr2line {0} --exe {1} {2}
+{4}
+$ {3} {0} --exe {1} {2}
+{5}
+
+
+",
+ flags.unwrap_or(""),
+ me.display(),
+ trace.join(" "),
+ exe.display(),
+ theirs,
+ ours
+ );
+ }
+ Ok(())
+}
+
+static FLAGS: &str = "aipsf";
+
+fn make_tests() -> Vec<Trial> {
+ (0..(1 << FLAGS.len()))
+ .map(|bits| {
+ if bits == 0 {
+ None
+ } else {
+ let mut param = String::new();
+ param.push('-');
+ for (i, flag) in FLAGS.chars().enumerate() {
+ if (bits & (1 << i)) != 0 {
+ param.push(flag);
+ }
+ }
+ Some(param)
+ }
+ })
+ .map(|param| {
+ Trial::test(
+ format!("addr2line {}", param.as_ref().map_or("", String::as_str)),
+ move || run_test(param.as_ref().map(String::as_str)),
+ )
+ })
+ .collect()
+}
+
+fn main() {
+ if !cfg!(target_os = "linux") {
+ return;
+ }
+ let args = Arguments::from_args();
+ libtest_mimic::run(&args, make_tests()).exit();
+}
diff --git a/vendor/addr2line/tests/parse.rs b/vendor/addr2line/tests/parse.rs
new file mode 100644
index 0000000..4dafe38
--- /dev/null
+++ b/vendor/addr2line/tests/parse.rs
@@ -0,0 +1,114 @@
+use std::borrow::Cow;
+use std::env;
+use std::fs::File;
+use std::path::{self, PathBuf};
+
+use object::Object;
+
+fn release_fixture_path() -> PathBuf {
+ if let Ok(p) = env::var("ADDR2LINE_FIXTURE_PATH") {
+ return p.into();
+ }
+
+ let mut path = PathBuf::new();
+ if let Ok(dir) = env::var("CARGO_MANIFEST_DIR") {
+ path.push(dir);
+ }
+ path.push("fixtures");
+ path.push("addr2line-release");
+ path
+}
+
+fn with_file<F: FnOnce(&object::File<'_>)>(target: &path::Path, f: F) {
+ let file = File::open(target).unwrap();
+ let map = unsafe { memmap2::Mmap::map(&file).unwrap() };
+ let file = object::File::parse(&*map).unwrap();
+ f(&file)
+}
+
+fn dwarf_load<'a>(object: &object::File<'a>) -> gimli::Dwarf<Cow<'a, [u8]>> {
+ let load_section = |id: gimli::SectionId| -> Result<Cow<'a, [u8]>, gimli::Error> {
+ use object::ObjectSection;
+
+ let data = object
+ .section_by_name(id.name())
+ .and_then(|section| section.data().ok())
+ .unwrap_or(&[][..]);
+ Ok(Cow::Borrowed(data))
+ };
+ gimli::Dwarf::load(&load_section).unwrap()
+}
+
+fn dwarf_borrow<'a>(
+ dwarf: &'a gimli::Dwarf<Cow<'_, [u8]>>,
+) -> gimli::Dwarf<gimli::EndianSlice<'a, gimli::LittleEndian>> {
+ let borrow_section: &dyn for<'b> Fn(
+ &'b Cow<'_, [u8]>,
+ ) -> gimli::EndianSlice<'b, gimli::LittleEndian> =
+ &|section| gimli::EndianSlice::new(section, gimli::LittleEndian);
+ dwarf.borrow(&borrow_section)
+}
+
+#[test]
+fn parse_base_rc() {
+ let target = release_fixture_path();
+
+ with_file(&target, |file| {
+ addr2line::ObjectContext::new(file).unwrap();
+ });
+}
+
+#[test]
+fn parse_base_slice() {
+ let target = release_fixture_path();
+
+ with_file(&target, |file| {
+ let dwarf = dwarf_load(file);
+ let dwarf = dwarf_borrow(&dwarf);
+ addr2line::Context::from_dwarf(dwarf).unwrap();
+ });
+}
+
+#[test]
+fn parse_lines_rc() {
+ let target = release_fixture_path();
+
+ with_file(&target, |file| {
+ let context = addr2line::ObjectContext::new(file).unwrap();
+ context.parse_lines().unwrap();
+ });
+}
+
+#[test]
+fn parse_lines_slice() {
+ let target = release_fixture_path();
+
+ with_file(&target, |file| {
+ let dwarf = dwarf_load(file);
+ let dwarf = dwarf_borrow(&dwarf);
+ let context = addr2line::Context::from_dwarf(dwarf).unwrap();
+ context.parse_lines().unwrap();
+ });
+}
+
+#[test]
+fn parse_functions_rc() {
+ let target = release_fixture_path();
+
+ with_file(&target, |file| {
+ let context = addr2line::ObjectContext::new(file).unwrap();
+ context.parse_functions().unwrap();
+ });
+}
+
+#[test]
+fn parse_functions_slice() {
+ let target = release_fixture_path();
+
+ with_file(&target, |file| {
+ let dwarf = dwarf_load(file);
+ let dwarf = dwarf_borrow(&dwarf);
+ let context = addr2line::Context::from_dwarf(dwarf).unwrap();
+ context.parse_functions().unwrap();
+ });
+}