update vendored cargo modules in zeroidc dir with cargo vendor for 1.12.2 (see predownloaded-development in .gear/rules)
This commit is contained in:
parent
d4faaa12f3
commit
aa9ee28b3b
6536 changed files with 3346116 additions and 798089 deletions
1
.gear/predownloaded-development/vendor/addr2line/.cargo-checksum.json
vendored
Normal file
1
.gear/predownloaded-development/vendor/addr2line/.cargo-checksum.json
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"files":{"CHANGELOG.md":"b278b1b797ac494c3653c85ede8a0f423a866300137117d2e914e4a52a87c08d","Cargo.lock":"ded666c16c5232c89b807781768ee73a4f8ed51d3b05a86850856d1a482dd5e6","Cargo.toml":"af4c88d2c7e685f9adf0f473fc9a0c33a2c8f54e3497f8eb92c8ec5d1dcfb1b5","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"e99d88d232bf57d70f0fb87f6b496d44b6653f99f8a63d250a54c61ea4bcde40","README.md":"76d28502bd2e83f6a9e3576bd45e9a7fe5308448c4b5384b0d249515b5f67a5c","bench.plot.r":"6a5d7a4d36ed6b3d9919be703a479bef47698bf947818b483ff03951df2d4e01","benchmark.sh":"b35f89b1ca2c1dc0476cdd07f0284b72d41920d1c7b6054072f50ffba296d78d","coverage.sh":"4677e81922d08a82e83068a911717a247c66af12e559f37b78b6be3337ac9f07","examples/addr2line.rs":"0ffdd45eeac7a2a5ddb71895009ea5e41306e22404bce375600b8371728e36ed","rustfmt.toml":"01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b","src/builtin_split_dwarf_loader.rs":"dc6979de81b35f82e97275e6be27ec61f3c4225ea10574a9e031813e00185174","src/function.rs":"68f047e0c78afe18ad165db255c8254ee74c35cd6df0cc07e400252981f661ed","src/lazy.rs":"0bf23f7098f1902f181e43c2ffa82a3f86df2c0dbcb9bc0ebce6a0168dd8b060","src/lib.rs":"ebfdd66a4b553e6dcbb937903c4f30bfe3f4a0b6ae9fec810ec9eb9e6bf0ec2f","tests/correctness.rs":"4081f8019535305e3aa254c6a4e1436272dd873f9717c687ca0e66ea8d5871ed","tests/output_equivalence.rs":"b2cd7c59fa55808a2e66e9fe7f160d846867e3ecefe22c22a818f822c3c41f23","tests/parse.rs":"c2f7362e4679c1b4803b12ec6e8dca6da96aed7273fd210a857524a4182c30e7"},"package":"f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3"}
|
||||
321
.gear/predownloaded-development/vendor/addr2line/CHANGELOG.md
vendored
Normal file
321
.gear/predownloaded-development/vendor/addr2line/CHANGELOG.md
vendored
Normal file
|
|
@ -0,0 +1,321 @@
|
|||
# `addr2line` Change Log
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 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>`.
|
||||
548
.gear/predownloaded-development/vendor/addr2line/Cargo.lock
generated
vendored
Normal file
548
.gear/predownloaded-development/vendor/addr2line/Cargo.lock
generated
vendored
Normal file
|
|
@ -0,0 +1,548 @@
|
|||
# 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",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.20.0"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"clap",
|
||||
"compiler_builtins",
|
||||
"cpp_demangle",
|
||||
"fallible-iterator",
|
||||
"findshlibs",
|
||||
"gimli",
|
||||
"libtest-mimic",
|
||||
"memmap2",
|
||||
"object 0.31.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 = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
dependencies = [
|
||||
"hermit-abi 0.1.19",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[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 = "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 = "3.2.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"bitflags",
|
||||
"clap_derive",
|
||||
"clap_lex",
|
||||
"indexmap",
|
||||
"once_cell",
|
||||
"strsim",
|
||||
"termcolor",
|
||||
"textwrap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "3.2.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
|
||||
dependencies = [
|
||||
"os_str_bytes",
|
||||
]
|
||||
|
||||
[[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 = "fallible-iterator"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
|
||||
|
||||
[[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"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"fallible-iterator",
|
||||
"rustc-std-workspace-alloc",
|
||||
"rustc-std-workspace-core",
|
||||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
|
||||
[[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.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[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.141"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5"
|
||||
|
||||
[[package]]
|
||||
name = "libtest-mimic"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79529479c298f5af41375b0c1a77ef670d450b4c9cd7949d2b43af08121b20ec"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"termcolor",
|
||||
"threadpool",
|
||||
]
|
||||
|
||||
[[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.31.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d08090140cfee2e09897d6be320b47a45b79eb68b414de87130f9532966e2f1d"
|
||||
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 = "os_str_bytes"
|
||||
version = "6.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||
dependencies = [
|
||||
"proc-macro-error-attr",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error-attr"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[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 = "ruzstd"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a15e661f0f9dac21f3494fe5d23a6338c0ac116a2d22c2b63010acd89467ffe"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"thiserror",
|
||||
"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 = "textwrap"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d"
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.15",
|
||||
]
|
||||
|
||||
[[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 = "version_check"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[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"
|
||||
145
.gear/predownloaded-development/vendor/addr2line/Cargo.toml
vendored
Normal file
145
.gear/predownloaded-development/vendor/addr2line/Cargo.toml
vendored
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
# 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"
|
||||
name = "addr2line"
|
||||
version = "0.20.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.2"
|
||||
optional = true
|
||||
default-features = false
|
||||
|
||||
[dependencies.gimli]
|
||||
version = "0.27.2"
|
||||
features = ["read"]
|
||||
default-features = false
|
||||
|
||||
[dependencies.memmap2]
|
||||
version = "0.5.5"
|
||||
optional = true
|
||||
|
||||
[dependencies.object]
|
||||
version = "0.31.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 = "3.1.6"
|
||||
|
||||
[dev-dependencies.findshlibs]
|
||||
version = "0.10"
|
||||
|
||||
[dev-dependencies.libtest-mimic]
|
||||
version = "0.5.2"
|
||||
|
||||
[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",
|
||||
]
|
||||
25
.gear/predownloaded-development/vendor/addr2line/LICENSE-MIT
vendored
Normal file
25
.gear/predownloaded-development/vendor/addr2line/LICENSE-MIT
vendored
Normal file
|
|
@ -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.
|
||||
48
.gear/predownloaded-development/vendor/addr2line/README.md
vendored
Normal file
48
.gear/predownloaded-development/vendor/addr2line/README.md
vendored
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
# addr2line
|
||||
|
||||
[](https://crates.io/crates/addr2line)
|
||||
[](https://docs.rs/addr2line)
|
||||
[](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.
|
||||
23
.gear/predownloaded-development/vendor/addr2line/bench.plot.r
vendored
Normal file
23
.gear/predownloaded-development/vendor/addr2line/bench.plot.r
vendored
Normal file
|
|
@ -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)
|
||||
112
.gear/predownloaded-development/vendor/addr2line/benchmark.sh
vendored
Executable file
112
.gear/predownloaded-development/vendor/addr2line/benchmark.sh
vendored
Executable file
|
|
@ -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
|
||||
}
|
||||
5
.gear/predownloaded-development/vendor/addr2line/coverage.sh
vendored
Normal file
5
.gear/predownloaded-development/vendor/addr2line/coverage.sh
vendored
Normal file
|
|
@ -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
|
||||
306
.gear/predownloaded-development/vendor/addr2line/examples/addr2line.rs
vendored
Normal file
306
.gear/predownloaded-development/vendor/addr2line/examples/addr2line.rs
vendored
Normal file
|
|
@ -0,0 +1,306 @@
|
|||
use std::borrow::Cow;
|
||||
use std::fs::File;
|
||||
use std::io::{BufRead, Lines, StdinLock, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use clap::{Arg, Command, Values};
|
||||
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(Values<'a>),
|
||||
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")
|
||||
.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")
|
||||
.help("Display function names as well as file and line number information."),
|
||||
Arg::new("pretty").short('p').long("pretty-print").help(
|
||||
"Make the output more human friendly: each location are printed on one line.",
|
||||
),
|
||||
Arg::new("inlines").short('i').long("inlines").help(
|
||||
"If the address belongs to a function that was inlined, the source information for \
|
||||
all enclosing scopes back to the first non-inlined function will also be printed.",
|
||||
),
|
||||
Arg::new("addresses").short('a').long("addresses").help(
|
||||
"Display the address before the function name, file and line number information.",
|
||||
),
|
||||
Arg::new("basenames")
|
||||
.short('s')
|
||||
.long("basenames")
|
||||
.help("Display only the base of each file name."),
|
||||
Arg::new("demangle").short('C').long("demangle").help(
|
||||
"Demangle function names. \
|
||||
Specifying a specific demangling style (like GNU addr2line) is not supported. \
|
||||
(TODO)"
|
||||
),
|
||||
Arg::new("llvm")
|
||||
.long("llvm")
|
||||
.help("Display output in the same format as llvm-symbolizer."),
|
||||
Arg::new("addrs")
|
||||
.takes_value(true)
|
||||
.multiple_occurrences(true)
|
||||
.help("Addresses to use instead of reading from stdin."),
|
||||
])
|
||||
.get_matches();
|
||||
|
||||
let arena_data = Arena::new();
|
||||
|
||||
let opts = Options {
|
||||
do_functions: matches.is_present("functions"),
|
||||
do_inlines: matches.is_present("inlines"),
|
||||
pretty: matches.is_present("pretty"),
|
||||
print_addrs: matches.is_present("addresses"),
|
||||
basenames: matches.is_present("basenames"),
|
||||
demangle: matches.is_present("demangle"),
|
||||
llvm: matches.is_present("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
|
||||
.values_of("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();
|
||||
}
|
||||
}
|
||||
1
.gear/predownloaded-development/vendor/addr2line/rustfmt.toml
vendored
Normal file
1
.gear/predownloaded-development/vendor/addr2line/rustfmt.toml
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
|
||||
164
.gear/predownloaded-development/vendor/addr2line/src/builtin_split_dwarf_loader.rs
vendored
Normal file
164
.gear/predownloaded-development/vendor/addr2line/src/builtin_split_dwarf_loader.rs
vendored
Normal file
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
555
.gear/predownloaded-development/vendor/addr2line/src/function.rs
vendored
Normal file
555
.gear/predownloaded-development/vendor/addr2line/src/function.rs
vendored
Normal file
|
|
@ -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)
|
||||
}
|
||||
31
.gear/predownloaded-development/vendor/addr2line/src/lazy.rs
vendored
Normal file
31
.gear/predownloaded-development/vendor/addr2line/src/lazy.rs
vendored
Normal file
|
|
@ -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) }
|
||||
}
|
||||
}
|
||||
1729
.gear/predownloaded-development/vendor/addr2line/src/lib.rs
vendored
Normal file
1729
.gear/predownloaded-development/vendor/addr2line/src/lib.rs
vendored
Normal file
File diff suppressed because it is too large
Load diff
126
.gear/predownloaded-development/vendor/addr2line/tests/correctness.rs
vendored
Normal file
126
.gear/predownloaded-development/vendor/addr2line/tests/correctness.rs
vendored
Normal file
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
135
.gear/predownloaded-development/vendor/addr2line/tests/output_equivalence.rs
vendored
Normal file
135
.gear/predownloaded-development/vendor/addr2line/tests/output_equivalence.rs
vendored
Normal file
|
|
@ -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();
|
||||
}
|
||||
114
.gear/predownloaded-development/vendor/addr2line/tests/parse.rs
vendored
Normal file
114
.gear/predownloaded-development/vendor/addr2line/tests/parse.rs
vendored
Normal file
|
|
@ -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();
|
||||
});
|
||||
}
|
||||
1
.gear/predownloaded-development/vendor/adler/.cargo-checksum.json
vendored
Normal file
1
.gear/predownloaded-development/vendor/adler/.cargo-checksum.json
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"files":{"CHANGELOG.md":"737088e45fdf27fe2cfedce163332d8ce08c58fd86ca287de2de34c0fbaf63e7","Cargo.toml":"f410869f0f1a5697f65a8a77be03da7aeecc0be26e7cf3a1feb1acaa4f518770","LICENSE-0BSD":"861399f8c21c042b110517e76dc6b63a2b334276c8cf17412fc3c8908ca8dc17","LICENSE-APACHE":"8ada45cd9f843acf64e4722ae262c622a2b3b3007c7310ef36ac1061a30f6adb","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"308c50cdb42b9573743068158339570b45ca3f895015ca3b87ba983edb0a21e6","RELEASE_PROCESS.md":"a86cd10fc70f167f8d00e9e4ce0c6b4ebdfa1865058390dffd1e0ad4d3e68d9d","benches/bench.rs":"c07ce370e3680c602e415f8d1ec4e543ea2163ab22a09b6b82d93e8a30adca82","src/algo.rs":"b664b131f724a809591394a10b9023f40ab5963e32a83fa3163c2668e59c8b66","src/lib.rs":"b55ba9c629b30360d08168b2ca0c96275432856a539737a105a6d6ae6bf7e88f"},"package":"f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"}
|
||||
63
.gear/predownloaded-development/vendor/adler/CHANGELOG.md
vendored
Normal file
63
.gear/predownloaded-development/vendor/adler/CHANGELOG.md
vendored
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
# Changelog
|
||||
|
||||
## Unreleased
|
||||
|
||||
No changes.
|
||||
|
||||
## [1.0.2 - 2021-02-26](https://github.com/jonas-schievink/adler/releases/tag/v1.0.2)
|
||||
|
||||
- Fix doctest on big-endian systems ([#9]).
|
||||
|
||||
[#9]: https://github.com/jonas-schievink/adler/pull/9
|
||||
|
||||
## [1.0.1 - 2020-11-08](https://github.com/jonas-schievink/adler/releases/tag/v1.0.1)
|
||||
|
||||
### Fixes
|
||||
|
||||
- Fix documentation on docs.rs.
|
||||
|
||||
## [1.0.0 - 2020-11-08](https://github.com/jonas-schievink/adler/releases/tag/v1.0.0)
|
||||
|
||||
### Fixes
|
||||
|
||||
- Fix `cargo test --no-default-features` ([#5]).
|
||||
|
||||
### Improvements
|
||||
|
||||
- Extended and clarified documentation.
|
||||
- Added more rustdoc examples.
|
||||
- Extended CI to test the crate with `--no-default-features`.
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
- `adler32_reader` now takes its generic argument by value instead of as a `&mut`.
|
||||
- Renamed `adler32_reader` to `adler32`.
|
||||
|
||||
## [0.2.3 - 2020-07-11](https://github.com/jonas-schievink/adler/releases/tag/v0.2.3)
|
||||
|
||||
- Process 4 Bytes at a time, improving performance by up to 50% ([#2]).
|
||||
|
||||
## [0.2.2 - 2020-06-27](https://github.com/jonas-schievink/adler/releases/tag/v0.2.2)
|
||||
|
||||
- Bump MSRV to 1.31.0.
|
||||
|
||||
## [0.2.1 - 2020-06-27](https://github.com/jonas-schievink/adler/releases/tag/v0.2.1)
|
||||
|
||||
- Add a few `#[inline]` annotations to small functions.
|
||||
- Fix CI badge.
|
||||
- Allow integration into libstd.
|
||||
|
||||
## [0.2.0 - 2020-06-27](https://github.com/jonas-schievink/adler/releases/tag/v0.2.0)
|
||||
|
||||
- Support `#![no_std]` when using `default-features = false`.
|
||||
- Improve performance by around 7x.
|
||||
- Support Rust 1.8.0.
|
||||
- Improve API naming.
|
||||
|
||||
## [0.1.0 - 2020-06-26](https://github.com/jonas-schievink/adler/releases/tag/v0.1.0)
|
||||
|
||||
Initial release.
|
||||
|
||||
|
||||
[#2]: https://github.com/jonas-schievink/adler/pull/2
|
||||
[#5]: https://github.com/jonas-schievink/adler/pull/5
|
||||
64
.gear/predownloaded-development/vendor/adler/Cargo.toml
vendored
Normal file
64
.gear/predownloaded-development/vendor/adler/Cargo.toml
vendored
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies
|
||||
#
|
||||
# If you believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
|
||||
[package]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
authors = ["Jonas Schievink <jonasschievink@gmail.com>"]
|
||||
description = "A simple clean-room implementation of the Adler-32 checksum"
|
||||
documentation = "https://docs.rs/adler/"
|
||||
readme = "README.md"
|
||||
keywords = ["checksum", "integrity", "hash", "adler32", "zlib"]
|
||||
categories = ["algorithms"]
|
||||
license = "0BSD OR MIT OR Apache-2.0"
|
||||
repository = "https://github.com/jonas-schievink/adler.git"
|
||||
[package.metadata.docs.rs]
|
||||
rustdoc-args = ["--cfg=docsrs"]
|
||||
|
||||
[package.metadata.release]
|
||||
no-dev-version = true
|
||||
pre-release-commit-message = "Release {{version}}"
|
||||
tag-message = "{{version}}"
|
||||
|
||||
[[package.metadata.release.pre-release-replacements]]
|
||||
file = "CHANGELOG.md"
|
||||
replace = "## Unreleased\n\nNo changes.\n\n## [{{version}} - {{date}}](https://github.com/jonas-schievink/adler/releases/tag/v{{version}})\n"
|
||||
search = "## Unreleased\n"
|
||||
|
||||
[[package.metadata.release.pre-release-replacements]]
|
||||
file = "README.md"
|
||||
replace = "adler = \"{{version}}\""
|
||||
search = "adler = \"[a-z0-9\\\\.-]+\""
|
||||
|
||||
[[package.metadata.release.pre-release-replacements]]
|
||||
file = "src/lib.rs"
|
||||
replace = "https://docs.rs/adler/{{version}}"
|
||||
search = "https://docs.rs/adler/[a-z0-9\\.-]+"
|
||||
|
||||
[[bench]]
|
||||
name = "bench"
|
||||
harness = false
|
||||
[dependencies.compiler_builtins]
|
||||
version = "0.1.2"
|
||||
optional = true
|
||||
|
||||
[dependencies.core]
|
||||
version = "1.0.0"
|
||||
optional = true
|
||||
package = "rustc-std-workspace-core"
|
||||
[dev-dependencies.criterion]
|
||||
version = "0.3.2"
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
rustc-dep-of-std = ["core", "compiler_builtins"]
|
||||
std = []
|
||||
12
.gear/predownloaded-development/vendor/adler/LICENSE-0BSD
vendored
Normal file
12
.gear/predownloaded-development/vendor/adler/LICENSE-0BSD
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
Copyright (C) Jonas Schievink <jonasschievink@gmail.com>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for
|
||||
any purpose with or without fee is hereby granted.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
|
||||
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
201
.gear/predownloaded-development/vendor/adler/LICENSE-APACHE
vendored
Normal file
201
.gear/predownloaded-development/vendor/adler/LICENSE-APACHE
vendored
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
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
|
||||
|
||||
https://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.
|
||||
39
.gear/predownloaded-development/vendor/adler/README.md
vendored
Normal file
39
.gear/predownloaded-development/vendor/adler/README.md
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
# Adler-32 checksums for Rust
|
||||
|
||||
[](https://crates.io/crates/adler)
|
||||
[](https://docs.rs/adler/)
|
||||

|
||||
|
||||
This crate provides a simple implementation of the Adler-32 checksum, used in
|
||||
the zlib compression format.
|
||||
|
||||
Please refer to the [changelog](CHANGELOG.md) to see what changed in the last
|
||||
releases.
|
||||
|
||||
## Features
|
||||
|
||||
- Permissively licensed (0BSD) clean-room implementation.
|
||||
- Zero dependencies.
|
||||
- Zero `unsafe`.
|
||||
- Decent performance (3-4 GB/s).
|
||||
- Supports `#![no_std]` (with `default-features = false`).
|
||||
|
||||
## Usage
|
||||
|
||||
Add an entry to your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
adler = "1.0.2"
|
||||
```
|
||||
|
||||
Check the [API Documentation](https://docs.rs/adler/) for how to use the
|
||||
crate's functionality.
|
||||
|
||||
## Rust version support
|
||||
|
||||
Currently, this crate supports all Rust versions starting at Rust 1.31.0.
|
||||
|
||||
Bumping the Minimum Supported Rust Version (MSRV) is *not* considered a breaking
|
||||
change, but will not be done without good reasons. The latest 3 stable Rust
|
||||
versions will always be supported no matter what.
|
||||
13
.gear/predownloaded-development/vendor/adler/RELEASE_PROCESS.md
vendored
Normal file
13
.gear/predownloaded-development/vendor/adler/RELEASE_PROCESS.md
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
# What to do to publish a new release
|
||||
|
||||
1. Ensure all notable changes are in the changelog under "Unreleased".
|
||||
|
||||
2. Execute `cargo release <level>` to bump version(s), tag and publish
|
||||
everything. External subcommand, must be installed with `cargo install
|
||||
cargo-release`.
|
||||
|
||||
`<level>` can be one of `major|minor|patch`. If this is the first release
|
||||
(`0.1.0`), use `minor`, since the version starts out as `0.0.0`.
|
||||
|
||||
3. Go to the GitHub releases, edit the just-pushed tag. Copy the release notes
|
||||
from the changelog.
|
||||
109
.gear/predownloaded-development/vendor/adler/benches/bench.rs
vendored
Normal file
109
.gear/predownloaded-development/vendor/adler/benches/bench.rs
vendored
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
extern crate adler;
|
||||
extern crate criterion;
|
||||
|
||||
use adler::{adler32_slice, Adler32};
|
||||
use criterion::{criterion_group, criterion_main, Criterion, Throughput};
|
||||
|
||||
fn simple(c: &mut Criterion) {
|
||||
{
|
||||
const SIZE: usize = 100;
|
||||
|
||||
let mut group = c.benchmark_group("simple-100b");
|
||||
group.throughput(Throughput::Bytes(SIZE as u64));
|
||||
group.bench_function("zeroes-100", |bencher| {
|
||||
bencher.iter(|| {
|
||||
adler32_slice(&[0; SIZE]);
|
||||
});
|
||||
});
|
||||
group.bench_function("ones-100", |bencher| {
|
||||
bencher.iter(|| {
|
||||
adler32_slice(&[0xff; SIZE]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
const SIZE: usize = 1024;
|
||||
|
||||
let mut group = c.benchmark_group("simple-1k");
|
||||
group.throughput(Throughput::Bytes(SIZE as u64));
|
||||
|
||||
group.bench_function("zeroes-1k", |bencher| {
|
||||
bencher.iter(|| {
|
||||
adler32_slice(&[0; SIZE]);
|
||||
});
|
||||
});
|
||||
|
||||
group.bench_function("ones-1k", |bencher| {
|
||||
bencher.iter(|| {
|
||||
adler32_slice(&[0xff; SIZE]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
const SIZE: usize = 1024 * 1024;
|
||||
|
||||
let mut group = c.benchmark_group("simple-1m");
|
||||
group.throughput(Throughput::Bytes(SIZE as u64));
|
||||
group.bench_function("zeroes-1m", |bencher| {
|
||||
bencher.iter(|| {
|
||||
adler32_slice(&[0; SIZE]);
|
||||
});
|
||||
});
|
||||
|
||||
group.bench_function("ones-1m", |bencher| {
|
||||
bencher.iter(|| {
|
||||
adler32_slice(&[0xff; SIZE]);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn chunked(c: &mut Criterion) {
|
||||
const SIZE: usize = 16 * 1024 * 1024;
|
||||
|
||||
let data = vec![0xAB; SIZE];
|
||||
|
||||
let mut group = c.benchmark_group("chunked-16m");
|
||||
group.throughput(Throughput::Bytes(SIZE as u64));
|
||||
group.bench_function("5552", |bencher| {
|
||||
bencher.iter(|| {
|
||||
let mut h = Adler32::new();
|
||||
for chunk in data.chunks(5552) {
|
||||
h.write_slice(chunk);
|
||||
}
|
||||
h.checksum()
|
||||
});
|
||||
});
|
||||
group.bench_function("8k", |bencher| {
|
||||
bencher.iter(|| {
|
||||
let mut h = Adler32::new();
|
||||
for chunk in data.chunks(8 * 1024) {
|
||||
h.write_slice(chunk);
|
||||
}
|
||||
h.checksum()
|
||||
});
|
||||
});
|
||||
group.bench_function("64k", |bencher| {
|
||||
bencher.iter(|| {
|
||||
let mut h = Adler32::new();
|
||||
for chunk in data.chunks(64 * 1024) {
|
||||
h.write_slice(chunk);
|
||||
}
|
||||
h.checksum()
|
||||
});
|
||||
});
|
||||
group.bench_function("1m", |bencher| {
|
||||
bencher.iter(|| {
|
||||
let mut h = Adler32::new();
|
||||
for chunk in data.chunks(1024 * 1024) {
|
||||
h.write_slice(chunk);
|
||||
}
|
||||
h.checksum()
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
criterion_group!(benches, simple, chunked);
|
||||
criterion_main!(benches);
|
||||
146
.gear/predownloaded-development/vendor/adler/src/algo.rs
vendored
Normal file
146
.gear/predownloaded-development/vendor/adler/src/algo.rs
vendored
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
use crate::Adler32;
|
||||
use std::ops::{AddAssign, MulAssign, RemAssign};
|
||||
|
||||
impl Adler32 {
|
||||
pub(crate) fn compute(&mut self, bytes: &[u8]) {
|
||||
// The basic algorithm is, for every byte:
|
||||
// a = (a + byte) % MOD
|
||||
// b = (b + a) % MOD
|
||||
// where MOD = 65521.
|
||||
//
|
||||
// For efficiency, we can defer the `% MOD` operations as long as neither a nor b overflows:
|
||||
// - Between calls to `write`, we ensure that a and b are always in range 0..MOD.
|
||||
// - We use 32-bit arithmetic in this function.
|
||||
// - Therefore, a and b must not increase by more than 2^32-MOD without performing a `% MOD`
|
||||
// operation.
|
||||
//
|
||||
// According to Wikipedia, b is calculated as follows for non-incremental checksumming:
|
||||
// b = n×D1 + (n−1)×D2 + (n−2)×D3 + ... + Dn + n*1 (mod 65521)
|
||||
// Where n is the number of bytes and Di is the i-th Byte. We need to change this to account
|
||||
// for the previous values of a and b, as well as treat every input Byte as being 255:
|
||||
// b_inc = n×255 + (n-1)×255 + ... + 255 + n*65520
|
||||
// Or in other words:
|
||||
// b_inc = n*65520 + n(n+1)/2*255
|
||||
// The max chunk size is thus the largest value of n so that b_inc <= 2^32-65521.
|
||||
// 2^32-65521 = n*65520 + n(n+1)/2*255
|
||||
// Plugging this into an equation solver since I can't math gives n = 5552.18..., so 5552.
|
||||
//
|
||||
// On top of the optimization outlined above, the algorithm can also be parallelized with a
|
||||
// bit more work:
|
||||
//
|
||||
// Note that b is a linear combination of a vector of input bytes (D1, ..., Dn).
|
||||
//
|
||||
// If we fix some value k<N and rewrite indices 1, ..., N as
|
||||
//
|
||||
// 1_1, 1_2, ..., 1_k, 2_1, ..., 2_k, ..., (N/k)_k,
|
||||
//
|
||||
// then we can express a and b in terms of sums of smaller sequences kb and ka:
|
||||
//
|
||||
// ka(j) := D1_j + D2_j + ... + D(N/k)_j where j <= k
|
||||
// kb(j) := (N/k)*D1_j + (N/k-1)*D2_j + ... + D(N/k)_j where j <= k
|
||||
//
|
||||
// a = ka(1) + ka(2) + ... + ka(k) + 1
|
||||
// b = k*(kb(1) + kb(2) + ... + kb(k)) - 1*ka(2) - ... - (k-1)*ka(k) + N
|
||||
//
|
||||
// We use this insight to unroll the main loop and process k=4 bytes at a time.
|
||||
// The resulting code is highly amenable to SIMD acceleration, although the immediate speedups
|
||||
// stem from increased pipeline parallelism rather than auto-vectorization.
|
||||
//
|
||||
// This technique is described in-depth (here:)[https://software.intel.com/content/www/us/\
|
||||
// en/develop/articles/fast-computation-of-fletcher-checksums.html]
|
||||
|
||||
const MOD: u32 = 65521;
|
||||
const CHUNK_SIZE: usize = 5552 * 4;
|
||||
|
||||
let mut a = u32::from(self.a);
|
||||
let mut b = u32::from(self.b);
|
||||
let mut a_vec = U32X4([0; 4]);
|
||||
let mut b_vec = a_vec;
|
||||
|
||||
let (bytes, remainder) = bytes.split_at(bytes.len() - bytes.len() % 4);
|
||||
|
||||
// iterate over 4 bytes at a time
|
||||
let chunk_iter = bytes.chunks_exact(CHUNK_SIZE);
|
||||
let remainder_chunk = chunk_iter.remainder();
|
||||
for chunk in chunk_iter {
|
||||
for byte_vec in chunk.chunks_exact(4) {
|
||||
let val = U32X4::from(byte_vec);
|
||||
a_vec += val;
|
||||
b_vec += a_vec;
|
||||
}
|
||||
b += CHUNK_SIZE as u32 * a;
|
||||
a_vec %= MOD;
|
||||
b_vec %= MOD;
|
||||
b %= MOD;
|
||||
}
|
||||
// special-case the final chunk because it may be shorter than the rest
|
||||
for byte_vec in remainder_chunk.chunks_exact(4) {
|
||||
let val = U32X4::from(byte_vec);
|
||||
a_vec += val;
|
||||
b_vec += a_vec;
|
||||
}
|
||||
b += remainder_chunk.len() as u32 * a;
|
||||
a_vec %= MOD;
|
||||
b_vec %= MOD;
|
||||
b %= MOD;
|
||||
|
||||
// combine the sub-sum results into the main sum
|
||||
b_vec *= 4;
|
||||
b_vec.0[1] += MOD - a_vec.0[1];
|
||||
b_vec.0[2] += (MOD - a_vec.0[2]) * 2;
|
||||
b_vec.0[3] += (MOD - a_vec.0[3]) * 3;
|
||||
for &av in a_vec.0.iter() {
|
||||
a += av;
|
||||
}
|
||||
for &bv in b_vec.0.iter() {
|
||||
b += bv;
|
||||
}
|
||||
|
||||
// iterate over the remaining few bytes in serial
|
||||
for &byte in remainder.iter() {
|
||||
a += u32::from(byte);
|
||||
b += a;
|
||||
}
|
||||
|
||||
self.a = (a % MOD) as u16;
|
||||
self.b = (b % MOD) as u16;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct U32X4([u32; 4]);
|
||||
|
||||
impl U32X4 {
|
||||
fn from(bytes: &[u8]) -> Self {
|
||||
U32X4([
|
||||
u32::from(bytes[0]),
|
||||
u32::from(bytes[1]),
|
||||
u32::from(bytes[2]),
|
||||
u32::from(bytes[3]),
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign<Self> for U32X4 {
|
||||
fn add_assign(&mut self, other: Self) {
|
||||
for (s, o) in self.0.iter_mut().zip(other.0.iter()) {
|
||||
*s += o;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RemAssign<u32> for U32X4 {
|
||||
fn rem_assign(&mut self, quotient: u32) {
|
||||
for s in self.0.iter_mut() {
|
||||
*s %= quotient;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MulAssign<u32> for U32X4 {
|
||||
fn mul_assign(&mut self, rhs: u32) {
|
||||
for s in self.0.iter_mut() {
|
||||
*s *= rhs;
|
||||
}
|
||||
}
|
||||
}
|
||||
287
.gear/predownloaded-development/vendor/adler/src/lib.rs
vendored
Normal file
287
.gear/predownloaded-development/vendor/adler/src/lib.rs
vendored
Normal file
|
|
@ -0,0 +1,287 @@
|
|||
//! Adler-32 checksum implementation.
|
||||
//!
|
||||
//! This implementation features:
|
||||
//!
|
||||
//! - Permissively licensed (0BSD) clean-room implementation.
|
||||
//! - Zero dependencies.
|
||||
//! - Zero `unsafe`.
|
||||
//! - Decent performance (3-4 GB/s).
|
||||
//! - `#![no_std]` support (with `default-features = false`).
|
||||
|
||||
#![doc(html_root_url = "https://docs.rs/adler/1.0.2")]
|
||||
// Deny a few warnings in doctests, since rustdoc `allow`s many warnings by default
|
||||
#![doc(test(attr(deny(unused_imports, unused_must_use))))]
|
||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||
#![warn(missing_debug_implementations)]
|
||||
#![forbid(unsafe_code)]
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
extern crate core as std;
|
||||
|
||||
mod algo;
|
||||
|
||||
use std::hash::Hasher;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use std::io::{self, BufRead};
|
||||
|
||||
/// Adler-32 checksum calculator.
|
||||
///
|
||||
/// An instance of this type is equivalent to an Adler-32 checksum: It can be created in the default
|
||||
/// state via [`new`] (or the provided `Default` impl), or from a precalculated checksum via
|
||||
/// [`from_checksum`], and the currently stored checksum can be fetched via [`checksum`].
|
||||
///
|
||||
/// This type also implements `Hasher`, which makes it easy to calculate Adler-32 checksums of any
|
||||
/// type that implements or derives `Hash`. This also allows using Adler-32 in a `HashMap`, although
|
||||
/// that is not recommended (while every checksum is a hash function, they are not necessarily a
|
||||
/// good one).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic, piecewise checksum calculation:
|
||||
///
|
||||
/// ```
|
||||
/// use adler::Adler32;
|
||||
///
|
||||
/// let mut adler = Adler32::new();
|
||||
///
|
||||
/// adler.write_slice(&[0, 1, 2]);
|
||||
/// adler.write_slice(&[3, 4, 5]);
|
||||
///
|
||||
/// assert_eq!(adler.checksum(), 0x00290010);
|
||||
/// ```
|
||||
///
|
||||
/// Using `Hash` to process structures:
|
||||
///
|
||||
/// ```
|
||||
/// use std::hash::Hash;
|
||||
/// use adler::Adler32;
|
||||
///
|
||||
/// #[derive(Hash)]
|
||||
/// struct Data {
|
||||
/// byte: u8,
|
||||
/// word: u16,
|
||||
/// big: u64,
|
||||
/// }
|
||||
///
|
||||
/// let mut adler = Adler32::new();
|
||||
///
|
||||
/// let data = Data { byte: 0x1F, word: 0xABCD, big: !0 };
|
||||
/// data.hash(&mut adler);
|
||||
///
|
||||
/// // hash value depends on architecture endianness
|
||||
/// if cfg!(target_endian = "little") {
|
||||
/// assert_eq!(adler.checksum(), 0x33410990);
|
||||
/// }
|
||||
/// if cfg!(target_endian = "big") {
|
||||
/// assert_eq!(adler.checksum(), 0x331F0990);
|
||||
/// }
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// [`new`]: #method.new
|
||||
/// [`from_checksum`]: #method.from_checksum
|
||||
/// [`checksum`]: #method.checksum
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Adler32 {
|
||||
a: u16,
|
||||
b: u16,
|
||||
}
|
||||
|
||||
impl Adler32 {
|
||||
/// Creates a new Adler-32 instance with default state.
|
||||
#[inline]
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
/// Creates an `Adler32` instance from a precomputed Adler-32 checksum.
|
||||
///
|
||||
/// This allows resuming checksum calculation without having to keep the `Adler32` instance
|
||||
/// around.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use adler::Adler32;
|
||||
/// let parts = [
|
||||
/// "rust",
|
||||
/// "acean",
|
||||
/// ];
|
||||
/// let whole = adler::adler32_slice(b"rustacean");
|
||||
///
|
||||
/// let mut sum = Adler32::new();
|
||||
/// sum.write_slice(parts[0].as_bytes());
|
||||
/// let partial = sum.checksum();
|
||||
///
|
||||
/// // ...later
|
||||
///
|
||||
/// let mut sum = Adler32::from_checksum(partial);
|
||||
/// sum.write_slice(parts[1].as_bytes());
|
||||
/// assert_eq!(sum.checksum(), whole);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn from_checksum(sum: u32) -> Self {
|
||||
Adler32 {
|
||||
a: sum as u16,
|
||||
b: (sum >> 16) as u16,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the calculated checksum at this point in time.
|
||||
#[inline]
|
||||
pub fn checksum(&self) -> u32 {
|
||||
(u32::from(self.b) << 16) | u32::from(self.a)
|
||||
}
|
||||
|
||||
/// Adds `bytes` to the checksum calculation.
|
||||
///
|
||||
/// If efficiency matters, this should be called with Byte slices that contain at least a few
|
||||
/// thousand Bytes.
|
||||
pub fn write_slice(&mut self, bytes: &[u8]) {
|
||||
self.compute(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Adler32 {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Adler32 { a: 1, b: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
impl Hasher for Adler32 {
|
||||
#[inline]
|
||||
fn finish(&self) -> u64 {
|
||||
u64::from(self.checksum())
|
||||
}
|
||||
|
||||
fn write(&mut self, bytes: &[u8]) {
|
||||
self.write_slice(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculates the Adler-32 checksum of a byte slice.
|
||||
///
|
||||
/// This is a convenience function around the [`Adler32`] type.
|
||||
///
|
||||
/// [`Adler32`]: struct.Adler32.html
|
||||
pub fn adler32_slice(data: &[u8]) -> u32 {
|
||||
let mut h = Adler32::new();
|
||||
h.write_slice(data);
|
||||
h.checksum()
|
||||
}
|
||||
|
||||
/// Calculates the Adler-32 checksum of a `BufRead`'s contents.
|
||||
///
|
||||
/// The passed `BufRead` implementor will be read until it reaches EOF (or until it reports an
|
||||
/// error).
|
||||
///
|
||||
/// If you only have a `Read` implementor, you can wrap it in `std::io::BufReader` before calling
|
||||
/// this function.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Any error returned by the reader are bubbled up by this function.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # fn run() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// use adler::adler32;
|
||||
///
|
||||
/// use std::fs::File;
|
||||
/// use std::io::BufReader;
|
||||
///
|
||||
/// let file = File::open("input.txt")?;
|
||||
/// let mut file = BufReader::new(file);
|
||||
///
|
||||
/// adler32(&mut file)?;
|
||||
/// # Ok(()) }
|
||||
/// # fn main() { run().unwrap() }
|
||||
/// ```
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||
pub fn adler32<R: BufRead>(mut reader: R) -> io::Result<u32> {
|
||||
let mut h = Adler32::new();
|
||||
loop {
|
||||
let len = {
|
||||
let buf = reader.fill_buf()?;
|
||||
if buf.is_empty() {
|
||||
return Ok(h.checksum());
|
||||
}
|
||||
|
||||
h.write_slice(buf);
|
||||
buf.len()
|
||||
};
|
||||
reader.consume(len);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn zeroes() {
|
||||
assert_eq!(adler32_slice(&[]), 1);
|
||||
assert_eq!(adler32_slice(&[0]), 1 | 1 << 16);
|
||||
assert_eq!(adler32_slice(&[0, 0]), 1 | 2 << 16);
|
||||
assert_eq!(adler32_slice(&[0; 100]), 0x00640001);
|
||||
assert_eq!(adler32_slice(&[0; 1024]), 0x04000001);
|
||||
assert_eq!(adler32_slice(&[0; 1024 * 1024]), 0x00f00001);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ones() {
|
||||
assert_eq!(adler32_slice(&[0xff; 1024]), 0x79a6fc2e);
|
||||
assert_eq!(adler32_slice(&[0xff; 1024 * 1024]), 0x8e88ef11);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mixed() {
|
||||
assert_eq!(adler32_slice(&[1]), 2 | 2 << 16);
|
||||
assert_eq!(adler32_slice(&[40]), 41 | 41 << 16);
|
||||
|
||||
assert_eq!(adler32_slice(&[0xA5; 1024 * 1024]), 0xd5009ab1);
|
||||
}
|
||||
|
||||
/// Example calculation from https://en.wikipedia.org/wiki/Adler-32.
|
||||
#[test]
|
||||
fn wiki() {
|
||||
assert_eq!(adler32_slice(b"Wikipedia"), 0x11E60398);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resume() {
|
||||
let mut adler = Adler32::new();
|
||||
adler.write_slice(&[0xff; 1024]);
|
||||
let partial = adler.checksum();
|
||||
assert_eq!(partial, 0x79a6fc2e); // from above
|
||||
adler.write_slice(&[0xff; 1024 * 1024 - 1024]);
|
||||
assert_eq!(adler.checksum(), 0x8e88ef11); // from above
|
||||
|
||||
// Make sure that we can resume computing from the partial checksum via `from_checksum`.
|
||||
let mut adler = Adler32::from_checksum(partial);
|
||||
adler.write_slice(&[0xff; 1024 * 1024 - 1024]);
|
||||
assert_eq!(adler.checksum(), 0x8e88ef11); // from above
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[test]
|
||||
fn bufread() {
|
||||
use std::io::BufReader;
|
||||
fn test(data: &[u8], checksum: u32) {
|
||||
// `BufReader` uses an 8 KB buffer, so this will test buffer refilling.
|
||||
let mut buf = BufReader::new(data);
|
||||
let real_sum = adler32(&mut buf).unwrap();
|
||||
assert_eq!(checksum, real_sum);
|
||||
}
|
||||
|
||||
test(&[], 1);
|
||||
test(&[0; 1024], 0x04000001);
|
||||
test(&[0; 1024 * 1024], 0x00f00001);
|
||||
test(&[0xA5; 1024 * 1024], 0xd5009ab1);
|
||||
}
|
||||
}
|
||||
1
.gear/predownloaded-development/vendor/android-tzdata/.cargo-checksum.json
vendored
Normal file
1
.gear/predownloaded-development/vendor/android-tzdata/.cargo-checksum.json
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"files":{"Cargo.toml":"a87d9acc9827a50c7a96a88720c5dd055cbc08b1144dff95bd572ff977d4a79a","LICENSE-APACHE":"4458503dd48e88c4e0b945fb252a08b93c40ec757309b8ffa7c594dfa1e35104","LICENSE-MIT":"002c2696d92b5c8cf956c11072baa58eaf9f6ade995c031ea635c6a1ee342ad1","README.md":"6dfe0c602dc61eebe118900ed66a2c1f7887b9fe95b36e1c2974c4e8fa7ebd4b","src/lib.rs":"8f421233df83f82e737930ca8a2ad254966334183148bcc170f9c405df230de2","src/tzdata.rs":"78920925b04219910511e9a1f036f468cd2925c0054f280d6a00b106529046e7"},"package":"e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"}
|
||||
34
.gear/predownloaded-development/vendor/android-tzdata/Cargo.toml
vendored
Normal file
34
.gear/predownloaded-development/vendor/android-tzdata/Cargo.toml
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
# 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"
|
||||
name = "android-tzdata"
|
||||
version = "0.1.1"
|
||||
authors = ["RumovZ"]
|
||||
include = [
|
||||
"src/**/*",
|
||||
"LICENSE-*",
|
||||
"README.md",
|
||||
]
|
||||
description = "Parser for the Android-specific tzdata file"
|
||||
readme = "README.md"
|
||||
keywords = [
|
||||
"parser",
|
||||
"android",
|
||||
"timezone",
|
||||
]
|
||||
categories = ["date-and-time"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/RumovZ/android-tzdata"
|
||||
|
||||
[dev-dependencies.zip]
|
||||
version = "0.6.4"
|
||||
201
.gear/predownloaded-development/vendor/android-tzdata/LICENSE-APACHE
vendored
Normal file
201
.gear/predownloaded-development/vendor/android-tzdata/LICENSE-APACHE
vendored
Normal file
|
|
@ -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.
|
||||
21
.gear/predownloaded-development/vendor/android-tzdata/LICENSE-MIT
vendored
Normal file
21
.gear/predownloaded-development/vendor/android-tzdata/LICENSE-MIT
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) [year] [fullname]
|
||||
|
||||
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.
|
||||
20
.gear/predownloaded-development/vendor/android-tzdata/README.md
vendored
Normal file
20
.gear/predownloaded-development/vendor/android-tzdata/README.md
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# android-tzdata
|
||||
|
||||
Parser for the Android-specific tzdata file.
|
||||
|
||||
## License
|
||||
|
||||
Licensed under either of
|
||||
|
||||
- Apache License, Version 2.0
|
||||
([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
|
||||
- MIT license
|
||||
([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
||||
|
||||
at your option.
|
||||
|
||||
## Contribution
|
||||
|
||||
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.
|
||||
29
.gear/predownloaded-development/vendor/android-tzdata/src/lib.rs
vendored
Normal file
29
.gear/predownloaded-development/vendor/android-tzdata/src/lib.rs
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
//! Parser for the Android-specific tzdata file.
|
||||
|
||||
mod tzdata;
|
||||
|
||||
/// Tries to locate the `tzdata` file, parse it, and return the entry for the
|
||||
/// requested time zone.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an [std::io::Error] if the `tzdata` file cannot be found and parsed, or
|
||||
/// if it does not contain the requested timezone entry.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # use std::error::Error;
|
||||
/// # use android_tzdata::find_tz_data;
|
||||
/// #
|
||||
/// # fn main() -> Result<(), Box<dyn Error>> {
|
||||
/// let tz_data = find_tz_data("Europe/Kiev")?;
|
||||
/// // Check it's version 2 of the [Time Zone Information Format](https://www.ietf.org/archive/id/draft-murchison-rfc8536bis-02.html).
|
||||
/// assert!(tz_data.starts_with(b"TZif2"));
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn find_tz_data(tz_name: impl AsRef<str>) -> Result<Vec<u8>, std::io::Error> {
|
||||
let mut file = tzdata::find_file()?;
|
||||
tzdata::find_tz_data_in_file(&mut file, tz_name.as_ref())
|
||||
}
|
||||
166
.gear/predownloaded-development/vendor/android-tzdata/src/tzdata.rs
vendored
Normal file
166
.gear/predownloaded-development/vendor/android-tzdata/src/tzdata.rs
vendored
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
//! Logic was mainly ported from https://android.googlesource.com/platform/libcore/+/jb-mr2-release/luni/src/main/java/libcore/util/ZoneInfoDB.java
|
||||
|
||||
use core::{cmp::Ordering, convert::TryInto};
|
||||
use std::{
|
||||
fs::File,
|
||||
io::{self, ErrorKind, Read, Seek, SeekFrom},
|
||||
};
|
||||
|
||||
// The database uses 32-bit (4 byte) integers.
|
||||
const TZ_INT_SIZE: usize = 4;
|
||||
// The first 12 bytes contain a special version string.
|
||||
const MAGIC_SIZE: usize = 12;
|
||||
const HEADER_SIZE: usize = MAGIC_SIZE + 3 * TZ_INT_SIZE;
|
||||
// The database reserves 40 bytes for each id.
|
||||
const TZ_NAME_SIZE: usize = 40;
|
||||
const INDEX_ENTRY_SIZE: usize = TZ_NAME_SIZE + 3 * TZ_INT_SIZE;
|
||||
const TZDATA_LOCATIONS: [TzdataLocation; 2] = [
|
||||
TzdataLocation {
|
||||
env_var: "ANDROID_DATA",
|
||||
path: "/misc/zoneinfo/",
|
||||
},
|
||||
TzdataLocation {
|
||||
env_var: "ANDROID_ROOT",
|
||||
path: "/usr/share/zoneinfo/",
|
||||
},
|
||||
];
|
||||
|
||||
#[derive(Debug)]
|
||||
struct TzdataLocation {
|
||||
env_var: &'static str,
|
||||
path: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
struct Header {
|
||||
index_offset: usize,
|
||||
data_offset: usize,
|
||||
_zonetab_offset: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Index(Vec<u8>);
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
struct IndexEntry<'a> {
|
||||
_name: &'a [u8],
|
||||
offset: usize,
|
||||
length: usize,
|
||||
_raw_utc_offset: usize,
|
||||
}
|
||||
|
||||
pub(super) fn find_file() -> Result<File, io::Error> {
|
||||
for location in &TZDATA_LOCATIONS {
|
||||
if let Ok(env_value) = std::env::var(location.env_var) {
|
||||
if let Ok(file) = File::open(format!("{}{}tzdata", env_value, location.path)) {
|
||||
return Ok(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(io::Error::from(io::ErrorKind::NotFound))
|
||||
}
|
||||
|
||||
pub(super) fn find_tz_data_in_file(
|
||||
mut file: impl Read + Seek,
|
||||
tz_name: &str,
|
||||
) -> Result<Vec<u8>, io::Error> {
|
||||
let header = Header::new(&mut file)?;
|
||||
let index = Index::new(&mut file, header)?;
|
||||
if let Some(entry) = index.find_entry(tz_name) {
|
||||
file.seek(SeekFrom::Start((entry.offset + header.data_offset) as u64))?;
|
||||
let mut tz_data = vec![0u8; entry.length];
|
||||
file.read_exact(&mut tz_data)?;
|
||||
Ok(tz_data)
|
||||
} else {
|
||||
Err(io::Error::from(ErrorKind::NotFound))
|
||||
}
|
||||
}
|
||||
|
||||
impl Header {
|
||||
fn new(mut file: impl Read + Seek) -> Result<Self, io::Error> {
|
||||
let mut buf = [0; HEADER_SIZE];
|
||||
file.read_exact(&mut buf)?;
|
||||
if !buf.starts_with(b"tzdata") || buf[MAGIC_SIZE - 1] != 0u8 {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"invalid magic number",
|
||||
));
|
||||
}
|
||||
Ok(Self {
|
||||
index_offset: parse_tz_int(&buf, MAGIC_SIZE) as usize,
|
||||
data_offset: parse_tz_int(&buf, MAGIC_SIZE + TZ_INT_SIZE) as usize,
|
||||
_zonetab_offset: parse_tz_int(&buf, MAGIC_SIZE + 2 * TZ_INT_SIZE) as usize,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Index {
|
||||
fn new(mut file: impl Read + Seek, header: Header) -> Result<Self, io::Error> {
|
||||
file.seek(SeekFrom::Start(header.index_offset as u64))?;
|
||||
let size = header.data_offset - header.index_offset;
|
||||
let mut bytes = vec![0; size];
|
||||
file.read_exact(&mut bytes)?;
|
||||
Ok(Self(bytes))
|
||||
}
|
||||
|
||||
fn find_entry(&self, name: &str) -> Option<IndexEntry> {
|
||||
let name_bytes = name.as_bytes();
|
||||
let name_len = name_bytes.len();
|
||||
if name_len > TZ_NAME_SIZE {
|
||||
return None;
|
||||
}
|
||||
|
||||
let zeros = [0u8; TZ_NAME_SIZE];
|
||||
let cmp = |chunk: &&[u8]| -> Ordering {
|
||||
// tz names always have TZ_NAME_SIZE bytes and are right-padded with 0s
|
||||
// so we check that a chunk starts with `name` and the remaining bytes are 0
|
||||
chunk[..name_len]
|
||||
.cmp(name_bytes)
|
||||
.then_with(|| chunk[name_len..TZ_NAME_SIZE].cmp(&zeros[name_len..]))
|
||||
};
|
||||
|
||||
let chunks: Vec<_> = self.0.chunks_exact(INDEX_ENTRY_SIZE).collect();
|
||||
chunks
|
||||
.binary_search_by(cmp)
|
||||
.map(|idx| IndexEntry::new(chunks[idx]))
|
||||
.ok()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IndexEntry<'a> {
|
||||
fn new(bytes: &'a [u8]) -> Self {
|
||||
Self {
|
||||
_name: bytes[..TZ_NAME_SIZE]
|
||||
.splitn(2, |&b| b == 0u8)
|
||||
.next()
|
||||
.unwrap(),
|
||||
offset: parse_tz_int(bytes, TZ_NAME_SIZE) as usize,
|
||||
length: parse_tz_int(bytes, TZ_NAME_SIZE + TZ_INT_SIZE) as usize,
|
||||
_raw_utc_offset: parse_tz_int(bytes, TZ_NAME_SIZE + 2 * TZ_INT_SIZE) as usize,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Panics if slice does not contain [TZ_INT_SIZE] bytes beginning at start.
|
||||
fn parse_tz_int(slice: &[u8], start: usize) -> u32 {
|
||||
u32::from_be_bytes(slice[start..start + TZ_INT_SIZE].try_into().unwrap())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use std::fs::File;
|
||||
use std::io::Cursor;
|
||||
|
||||
#[test]
|
||||
fn parse() {
|
||||
let mut archive = File::open("tests/resources/tzdata.zip").unwrap();
|
||||
let mut zip = zip::ZipArchive::new(&mut archive).unwrap();
|
||||
let mut file = zip.by_index(0).unwrap();
|
||||
let mut data = Vec::new();
|
||||
file.read_to_end(&mut data).unwrap();
|
||||
let cursor = Cursor::new(data);
|
||||
let tz = find_tz_data_in_file(cursor, "Europe/Kiev").unwrap();
|
||||
assert!(tz.starts_with(b"TZif2"));
|
||||
}
|
||||
}
|
||||
1
.gear/predownloaded-development/vendor/backtrace/.cargo-checksum.json
vendored
Normal file
1
.gear/predownloaded-development/vendor/backtrace/.cargo-checksum.json
vendored
Normal file
File diff suppressed because one or more lines are too long
192
.gear/predownloaded-development/vendor/backtrace/Cargo.lock
generated
vendored
Normal file
192
.gear/predownloaded-development/vendor/backtrace/Cargo.lock
generated
vendored
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.68"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"cpp_demangle",
|
||||
"libc",
|
||||
"libloading",
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
"rustc-demangle",
|
||||
"rustc-serialize",
|
||||
"serde",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[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 = "cpp_demangle"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c76f98bdfc7f66172e6c7065f981ebb576ffc903fe4c0561d9f0c2509226dc6"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.27.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.146"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
|
||||
dependencies = [
|
||||
"adler",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.31.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-serialize"
|
||||
version = "0.3.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.164"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.164"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
|
||||
|
||||
[[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-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
144
.gear/predownloaded-development/vendor/backtrace/Cargo.toml
vendored
Normal file
144
.gear/predownloaded-development/vendor/backtrace/Cargo.toml
vendored
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
# 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"
|
||||
name = "backtrace"
|
||||
version = "0.3.68"
|
||||
authors = ["The Rust Project Developers"]
|
||||
build = "build.rs"
|
||||
autoexamples = true
|
||||
autotests = true
|
||||
description = """
|
||||
A library to acquire a stack trace (backtrace) at runtime in a Rust program.
|
||||
"""
|
||||
homepage = "https://github.com/rust-lang/backtrace-rs"
|
||||
documentation = "https://docs.rs/backtrace"
|
||||
readme = "README.md"
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/rust-lang/backtrace-rs"
|
||||
|
||||
[[example]]
|
||||
name = "backtrace"
|
||||
required-features = ["std"]
|
||||
|
||||
[[example]]
|
||||
name = "raw"
|
||||
required-features = ["std"]
|
||||
|
||||
[[test]]
|
||||
name = "skip_inner_frames"
|
||||
required-features = ["std"]
|
||||
|
||||
[[test]]
|
||||
name = "long_fn_name"
|
||||
required-features = ["std"]
|
||||
|
||||
[[test]]
|
||||
name = "smoke"
|
||||
required-features = ["std"]
|
||||
edition = "2018"
|
||||
|
||||
[[test]]
|
||||
name = "accuracy"
|
||||
required-features = ["std"]
|
||||
edition = "2018"
|
||||
|
||||
[[test]]
|
||||
name = "concurrent-panics"
|
||||
harness = false
|
||||
required-features = ["std"]
|
||||
|
||||
[[test]]
|
||||
name = "current-exe-mismatch"
|
||||
harness = false
|
||||
required-features = ["std"]
|
||||
|
||||
[dependencies.addr2line]
|
||||
version = "0.20.0"
|
||||
default-features = false
|
||||
|
||||
[dependencies.cfg-if]
|
||||
version = "1.0"
|
||||
|
||||
[dependencies.cpp_demangle]
|
||||
version = "0.4.0"
|
||||
features = ["alloc"]
|
||||
optional = true
|
||||
default-features = false
|
||||
|
||||
[dependencies.libc]
|
||||
version = "0.2.146"
|
||||
default-features = false
|
||||
|
||||
[dependencies.miniz_oxide]
|
||||
version = "0.7.0"
|
||||
default-features = false
|
||||
|
||||
[dependencies.object]
|
||||
version = "0.31.1"
|
||||
features = [
|
||||
"read_core",
|
||||
"elf",
|
||||
"macho",
|
||||
"pe",
|
||||
"unaligned",
|
||||
"archive",
|
||||
]
|
||||
default-features = false
|
||||
|
||||
[dependencies.rustc-demangle]
|
||||
version = "0.1.4"
|
||||
|
||||
[dependencies.rustc-serialize]
|
||||
version = "0.3"
|
||||
optional = true
|
||||
|
||||
[dependencies.serde]
|
||||
version = "1.0"
|
||||
features = ["derive"]
|
||||
optional = true
|
||||
|
||||
[dev-dependencies.libloading]
|
||||
version = "0.7"
|
||||
|
||||
[build-dependencies.cc]
|
||||
version = "1.0.67"
|
||||
|
||||
[features]
|
||||
coresymbolication = []
|
||||
dbghelp = []
|
||||
default = ["std"]
|
||||
dladdr = []
|
||||
gimli-symbolize = []
|
||||
kernel32 = []
|
||||
libbacktrace = []
|
||||
libunwind = []
|
||||
serialize-rustc = ["rustc-serialize"]
|
||||
serialize-serde = ["serde"]
|
||||
std = []
|
||||
unix-backtrace = []
|
||||
verify-winapi = [
|
||||
"winapi/dbghelp",
|
||||
"winapi/handleapi",
|
||||
"winapi/libloaderapi",
|
||||
"winapi/memoryapi",
|
||||
"winapi/minwindef",
|
||||
"winapi/processthreadsapi",
|
||||
"winapi/synchapi",
|
||||
"winapi/tlhelp32",
|
||||
"winapi/winbase",
|
||||
"winapi/winnt",
|
||||
]
|
||||
|
||||
[target."cfg(windows)".dependencies.winapi]
|
||||
version = "0.3.9"
|
||||
optional = true
|
||||
25
.gear/predownloaded-development/vendor/backtrace/LICENSE-MIT
vendored
Normal file
25
.gear/predownloaded-development/vendor/backtrace/LICENSE-MIT
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
Copyright (c) 2014 Alex Crichton
|
||||
|
||||
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.
|
||||
73
.gear/predownloaded-development/vendor/backtrace/README.md
vendored
Normal file
73
.gear/predownloaded-development/vendor/backtrace/README.md
vendored
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
# backtrace-rs
|
||||
|
||||
[Documentation](https://docs.rs/backtrace)
|
||||
|
||||
A library for acquiring backtraces at runtime for Rust. This library aims to
|
||||
enhance the support of the standard library by providing a programmatic
|
||||
interface to work with, but it also supports simply easily printing the current
|
||||
backtrace like libstd's panics.
|
||||
|
||||
## Install
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
backtrace = "0.3"
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
To simply capture a backtrace and defer dealing with it until a later time,
|
||||
you can use the top-level `Backtrace` type.
|
||||
|
||||
```rust
|
||||
use backtrace::Backtrace;
|
||||
|
||||
fn main() {
|
||||
let bt = Backtrace::new();
|
||||
|
||||
// do_some_work();
|
||||
|
||||
println!("{:?}", bt);
|
||||
}
|
||||
```
|
||||
|
||||
If, however, you'd like more raw access to the actual tracing functionality, you
|
||||
can use the `trace` and `resolve` functions directly.
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
backtrace::trace(|frame| {
|
||||
let ip = frame.ip();
|
||||
let symbol_address = frame.symbol_address();
|
||||
|
||||
// Resolve this instruction pointer to a symbol name
|
||||
backtrace::resolve_frame(frame, |symbol| {
|
||||
if let Some(name) = symbol.name() {
|
||||
// ...
|
||||
}
|
||||
if let Some(filename) = symbol.filename() {
|
||||
// ...
|
||||
}
|
||||
});
|
||||
|
||||
true // keep going to the next frame
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
# License
|
||||
|
||||
This project is 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.
|
||||
|
||||
### Contribution
|
||||
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted
|
||||
for inclusion in backtrace-rs by you, as defined in the Apache-2.0 license, shall be
|
||||
dual licensed as above, without any additional terms or conditions.
|
||||
92
.gear/predownloaded-development/vendor/backtrace/benches/benchmarks.rs
vendored
Normal file
92
.gear/predownloaded-development/vendor/backtrace/benches/benchmarks.rs
vendored
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
#![feature(test)]
|
||||
|
||||
extern crate test;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use backtrace::Backtrace;
|
||||
|
||||
#[bench]
|
||||
#[cfg(feature = "std")]
|
||||
fn trace(b: &mut test::Bencher) {
|
||||
#[inline(never)]
|
||||
fn the_function() {
|
||||
backtrace::trace(|frame| {
|
||||
let ip = frame.ip();
|
||||
test::black_box(ip);
|
||||
true
|
||||
});
|
||||
}
|
||||
b.iter(the_function);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
#[cfg(feature = "std")]
|
||||
fn trace_and_resolve_callback(b: &mut test::Bencher) {
|
||||
#[inline(never)]
|
||||
fn the_function() {
|
||||
backtrace::trace(|frame| {
|
||||
backtrace::resolve(frame.ip(), |symbol| {
|
||||
let addr = symbol.addr();
|
||||
test::black_box(addr);
|
||||
});
|
||||
true
|
||||
});
|
||||
}
|
||||
b.iter(the_function);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
#[cfg(feature = "std")]
|
||||
fn trace_and_resolve_separate(b: &mut test::Bencher) {
|
||||
#[inline(never)]
|
||||
fn the_function(frames: &mut Vec<*mut std::ffi::c_void>) {
|
||||
backtrace::trace(|frame| {
|
||||
frames.push(frame.ip());
|
||||
true
|
||||
});
|
||||
frames.iter().for_each(|frame_ip| {
|
||||
backtrace::resolve(*frame_ip, |symbol| {
|
||||
test::black_box(symbol);
|
||||
});
|
||||
});
|
||||
}
|
||||
let mut frames = Vec::with_capacity(1024);
|
||||
b.iter(|| {
|
||||
the_function(&mut frames);
|
||||
frames.clear();
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
#[cfg(feature = "std")]
|
||||
fn new_unresolved(b: &mut test::Bencher) {
|
||||
#[inline(never)]
|
||||
fn the_function() {
|
||||
let bt = Backtrace::new_unresolved();
|
||||
test::black_box(bt);
|
||||
}
|
||||
b.iter(the_function);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
#[cfg(feature = "std")]
|
||||
fn new(b: &mut test::Bencher) {
|
||||
#[inline(never)]
|
||||
fn the_function() {
|
||||
let bt = Backtrace::new();
|
||||
test::black_box(bt);
|
||||
}
|
||||
b.iter(the_function);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
#[cfg(feature = "std")]
|
||||
fn new_unresolved_and_resolve_separate(b: &mut test::Bencher) {
|
||||
#[inline(never)]
|
||||
fn the_function() {
|
||||
let mut bt = Backtrace::new_unresolved();
|
||||
bt.resolve();
|
||||
test::black_box(bt);
|
||||
}
|
||||
b.iter(the_function);
|
||||
}
|
||||
41
.gear/predownloaded-development/vendor/backtrace/build.rs
vendored
Normal file
41
.gear/predownloaded-development/vendor/backtrace/build.rs
vendored
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
extern crate cc;
|
||||
|
||||
use std::env;
|
||||
|
||||
fn main() {
|
||||
match env::var("CARGO_CFG_TARGET_OS").unwrap_or_default().as_str() {
|
||||
"android" => build_android(),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn build_android() {
|
||||
let expansion = match cc::Build::new().file("src/android-api.c").try_expand() {
|
||||
Ok(result) => result,
|
||||
Err(e) => {
|
||||
println!("failed to run C compiler: {}", e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
let expansion = match std::str::from_utf8(&expansion) {
|
||||
Ok(s) => s,
|
||||
Err(_) => return,
|
||||
};
|
||||
println!("expanded android version detection:\n{}", expansion);
|
||||
let marker = "APIVERSION";
|
||||
let i = match expansion.find(marker) {
|
||||
Some(i) => i,
|
||||
None => return,
|
||||
};
|
||||
let version = match expansion[i + marker.len() + 1..].split_whitespace().next() {
|
||||
Some(s) => s,
|
||||
None => return,
|
||||
};
|
||||
let version = match version.parse::<u32>() {
|
||||
Ok(n) => n,
|
||||
Err(_) => return,
|
||||
};
|
||||
if version >= 21 {
|
||||
println!("cargo:rustc-cfg=feature=\"dl_iterate_phdr\"");
|
||||
}
|
||||
}
|
||||
14
.gear/predownloaded-development/vendor/backtrace/ci/android-ndk.sh
vendored
Executable file
14
.gear/predownloaded-development/vendor/backtrace/ci/android-ndk.sh
vendored
Executable file
|
|
@ -0,0 +1,14 @@
|
|||
set -ex
|
||||
|
||||
ANDROID_NDK_URL=https://dl.google.com/android/repository
|
||||
ANDROID_NDK_ARCHIVE=android-ndk-r25b-linux.zip
|
||||
|
||||
mkdir /android-toolchain
|
||||
cd /android-toolchain
|
||||
curl -fO $ANDROID_NDK_URL/$ANDROID_NDK_ARCHIVE
|
||||
unzip -q $ANDROID_NDK_ARCHIVE
|
||||
rm $ANDROID_NDK_ARCHIVE
|
||||
mv android-ndk-* ndk
|
||||
|
||||
cd /tmp
|
||||
rm -rf android
|
||||
65
.gear/predownloaded-development/vendor/backtrace/ci/android-sdk.sh
vendored
Executable file
65
.gear/predownloaded-development/vendor/backtrace/ci/android-sdk.sh
vendored
Executable file
|
|
@ -0,0 +1,65 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
set -ex
|
||||
|
||||
# Prep the SDK and emulator
|
||||
#
|
||||
# Note that the update process requires that we accept a bunch of licenses, and
|
||||
# we can't just pipe `yes` into it for some reason, so we take the same strategy
|
||||
# located in https://github.com/appunite/docker by just wrapping it in a script
|
||||
# which apparently magically accepts the licenses.
|
||||
|
||||
SDK=4333796
|
||||
mkdir sdk
|
||||
curl --retry 20 https://dl.google.com/android/repository/sdk-tools-linux-${SDK}.zip -O
|
||||
unzip -q -d sdk sdk-tools-linux-${SDK}.zip
|
||||
|
||||
case "$1" in
|
||||
arm | armv7)
|
||||
api=24
|
||||
image="system-images;android-${api};google_apis;armeabi-v7a"
|
||||
;;
|
||||
aarch64)
|
||||
api=24
|
||||
image="system-images;android-${api};google_apis;arm64-v8a"
|
||||
;;
|
||||
i686)
|
||||
api=28
|
||||
image="system-images;android-${api};default;x86"
|
||||
;;
|
||||
x86_64)
|
||||
api=28
|
||||
image="system-images;android-${api};default;x86_64"
|
||||
;;
|
||||
*)
|
||||
echo "invalid arch: $1"
|
||||
exit 1
|
||||
;;
|
||||
esac;
|
||||
|
||||
# Try to fix warning about missing file.
|
||||
# See https://askubuntu.com/a/1078784
|
||||
mkdir -p /root/.android/
|
||||
echo '### User Sources for Android SDK Manager' >> /root/.android/repositories.cfg
|
||||
echo '#Fri Nov 03 10:11:27 CET 2017 count=0' >> /root/.android/repositories.cfg
|
||||
|
||||
# Print all available packages
|
||||
# yes | ./sdk/tools/bin/sdkmanager --list --verbose
|
||||
|
||||
# --no_https avoids
|
||||
# javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: No trusted certificate found
|
||||
#
|
||||
# | grep -v = || true removes the progress bar output from the sdkmanager
|
||||
# which produces an insane amount of output.
|
||||
yes | ./sdk/tools/bin/sdkmanager --licenses --no_https | grep -v = || true
|
||||
yes | ./sdk/tools/bin/sdkmanager --no_https \
|
||||
"emulator" \
|
||||
"platform-tools" \
|
||||
"platforms;android-${api}" \
|
||||
"${image}" | grep -v = || true
|
||||
|
||||
echo "no" |
|
||||
./sdk/tools/bin/avdmanager create avd \
|
||||
--name "${1}" \
|
||||
--package "${image}" | grep -v = || true
|
||||
|
||||
29
.gear/predownloaded-development/vendor/backtrace/ci/debuglink-docker.sh
vendored
Executable file
29
.gear/predownloaded-development/vendor/backtrace/ci/debuglink-docker.sh
vendored
Executable file
|
|
@ -0,0 +1,29 @@
|
|||
# Small script to run debuglink tests inside a docker image.
|
||||
# Creates a writable mount on /usr/lib/debug.
|
||||
|
||||
set -ex
|
||||
|
||||
run() {
|
||||
cargo generate-lockfile --manifest-path crates/debuglink/Cargo.toml
|
||||
mkdir -p target crates/debuglink/target debug
|
||||
docker build -t backtrace -f ci/docker/$1/Dockerfile ci
|
||||
docker run \
|
||||
--user `id -u`:`id -g` \
|
||||
--rm \
|
||||
--init \
|
||||
--volume $(dirname $(dirname `which cargo`)):/cargo \
|
||||
--env CARGO_HOME=/cargo \
|
||||
--volume `rustc --print sysroot`:/rust:ro \
|
||||
--env TARGET=$1 \
|
||||
--volume `pwd`:/checkout:ro \
|
||||
--volume `pwd`/target:/checkout/crates/debuglink/target \
|
||||
--workdir /checkout \
|
||||
--volume `pwd`/debug:/usr/lib/debug \
|
||||
--privileged \
|
||||
--env RUSTFLAGS \
|
||||
backtrace \
|
||||
bash \
|
||||
-c 'PATH=$PATH:/rust/bin exec ci/debuglink.sh'
|
||||
}
|
||||
|
||||
run x86_64-unknown-linux-gnu
|
||||
75
.gear/predownloaded-development/vendor/backtrace/ci/debuglink.sh
vendored
Executable file
75
.gear/predownloaded-development/vendor/backtrace/ci/debuglink.sh
vendored
Executable file
|
|
@ -0,0 +1,75 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Debuglink tests.
|
||||
# We build crates/debuglink and then move its debuginfo around
|
||||
# and test that it can still find the debuginfo.
|
||||
|
||||
set -ex
|
||||
|
||||
cratedir=`pwd`/crates/debuglink
|
||||
exefile=crates/debuglink/target/debug/debuglink
|
||||
|
||||
# Baseline; no separate debug
|
||||
cargo build --manifest-path crates/debuglink/Cargo.toml
|
||||
$exefile $cratedir
|
||||
|
||||
# Separate debug in same dir
|
||||
debugfile1=`dirname $exefile`/debuglink.debug
|
||||
objcopy --only-keep-debug $exefile $debugfile1
|
||||
strip -g $exefile
|
||||
(cd `dirname $exefile` && objcopy --add-gnu-debuglink=debuglink.debug debuglink)
|
||||
$exefile $cratedir
|
||||
|
||||
# Separate debug in .debug subdir
|
||||
debugfile2=`dirname $exefile`/.debug/debuglink.debug
|
||||
mkdir -p `dirname $debugfile2`
|
||||
mv $debugfile1 $debugfile2
|
||||
$exefile $cratedir
|
||||
|
||||
# Separate debug in /usr/lib/debug subdir
|
||||
debugfile3="/usr/lib/debug/$cratedir/target/debug/debuglink.debug"
|
||||
mkdir -p `dirname $debugfile3`
|
||||
mv $debugfile2 $debugfile3
|
||||
$exefile $cratedir
|
||||
|
||||
# Separate debug in /usr/lib/debug/.build-id subdir
|
||||
id=`readelf -n $exefile | grep '^ Build ID: [0-9a-f]' | cut -b 15-`
|
||||
idfile="/usr/lib/debug/.build-id/${id:0:2}/${id:2}.debug"
|
||||
mkdir -p `dirname $idfile`
|
||||
mv $debugfile3 $idfile
|
||||
$exefile $cratedir
|
||||
|
||||
# Replace idfile with a symlink (this is the usual arrangement)
|
||||
mv $idfile $debugfile3
|
||||
ln -s $debugfile3 $idfile
|
||||
$exefile $cratedir
|
||||
|
||||
# Supplementary object file using relative path
|
||||
dwzfile="/usr/lib/debug/.dwz/debuglink.debug"
|
||||
mkdir -p `dirname $dwzfile`
|
||||
cp $debugfile3 $debugfile3.copy
|
||||
dwz -m $dwzfile -rh $debugfile3 $debugfile3.copy
|
||||
rm $debugfile3.copy
|
||||
$exefile $cratedir
|
||||
|
||||
# Supplementary object file using build ID
|
||||
dwzid=`readelf -n $dwzfile | grep '^ Build ID: [0-9a-f]' | cut -b 15-`
|
||||
dwzidfile="/usr/lib/debug/.build-id/${dwzid:0:2}/${dwzid:2}.debug"
|
||||
mkdir -p `dirname $dwzidfile`
|
||||
mv $dwzfile $dwzidfile
|
||||
$exefile $cratedir
|
||||
mv $dwzidfile $dwzfile
|
||||
|
||||
# Missing debug should fail
|
||||
mv $debugfile3 $debugfile3.tmp
|
||||
! $exefile $cratedir
|
||||
mv $debugfile3.tmp $debugfile3
|
||||
|
||||
# Missing dwz should fail
|
||||
mv $dwzfile $dwzfile.tmp
|
||||
! $exefile $cratedir
|
||||
mv $dwzfile.tmp $dwzfile
|
||||
|
||||
# Cleanup
|
||||
rm $idfile $debugfile3 $dwzfile
|
||||
echo Success
|
||||
18
.gear/predownloaded-development/vendor/backtrace/ci/docker/aarch64-linux-android/Dockerfile
vendored
Normal file
18
.gear/predownloaded-development/vendor/backtrace/ci/docker/aarch64-linux-android/Dockerfile
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
FROM ubuntu:20.04
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
curl \
|
||||
ca-certificates \
|
||||
unzip \
|
||||
openjdk-8-jre \
|
||||
python \
|
||||
gcc \
|
||||
libc6-dev
|
||||
|
||||
COPY android-ndk.sh /
|
||||
RUN /android-ndk.sh
|
||||
ENV PATH=$PATH:/android-toolchain/ndk/toolchains/llvm/prebuilt/linux-x86_64/bin
|
||||
|
||||
# TODO: run tests in an emulator eventually
|
||||
ENV CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER=aarch64-linux-android21-clang \
|
||||
CARGO_TARGET_AARCH64_LINUX_ANDROID_RUNNER=echo
|
||||
11
.gear/predownloaded-development/vendor/backtrace/ci/docker/aarch64-unknown-linux-gnu/Dockerfile
vendored
Normal file
11
.gear/predownloaded-development/vendor/backtrace/ci/docker/aarch64-unknown-linux-gnu/Dockerfile
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
FROM ubuntu:20.04
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
gcc \
|
||||
ca-certificates \
|
||||
libc6-dev \
|
||||
gcc-aarch64-linux-gnu \
|
||||
libc6-dev-arm64-cross \
|
||||
qemu-user
|
||||
|
||||
ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc \
|
||||
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUNNER="qemu-aarch64 -L /usr/aarch64-linux-gnu"
|
||||
18
.gear/predownloaded-development/vendor/backtrace/ci/docker/arm-linux-androideabi/Dockerfile
vendored
Normal file
18
.gear/predownloaded-development/vendor/backtrace/ci/docker/arm-linux-androideabi/Dockerfile
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
FROM ubuntu:20.04
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
curl \
|
||||
ca-certificates \
|
||||
unzip \
|
||||
openjdk-8-jre \
|
||||
python \
|
||||
gcc \
|
||||
libc6-dev
|
||||
|
||||
COPY android-ndk.sh /
|
||||
RUN /android-ndk.sh
|
||||
ENV PATH=$PATH:/android-toolchain/ndk/toolchains/llvm/prebuilt/linux-x86_64/bin
|
||||
|
||||
# TODO: run tests in an emulator eventually
|
||||
ENV CARGO_TARGET_ARM_LINUX_ANDROIDEABI_LINKER=armv7a-linux-androideabi19-clang \
|
||||
CARGO_TARGET_ARM_LINUX_ANDROIDEABI_RUNNER=echo
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
FROM ubuntu:20.04
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
gcc \
|
||||
ca-certificates \
|
||||
libc6-dev \
|
||||
gcc-arm-linux-gnueabihf \
|
||||
libc6-dev-armhf-cross \
|
||||
qemu-user
|
||||
ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \
|
||||
CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_RUNNER="qemu-arm -L /usr/arm-linux-gnueabihf"
|
||||
18
.gear/predownloaded-development/vendor/backtrace/ci/docker/armv7-linux-androideabi/Dockerfile
vendored
Normal file
18
.gear/predownloaded-development/vendor/backtrace/ci/docker/armv7-linux-androideabi/Dockerfile
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
FROM ubuntu:20.04
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
curl \
|
||||
ca-certificates \
|
||||
unzip \
|
||||
openjdk-8-jre \
|
||||
python \
|
||||
gcc \
|
||||
libc6-dev
|
||||
|
||||
COPY android-ndk.sh /
|
||||
RUN /android-ndk.sh
|
||||
ENV PATH=$PATH:/android-toolchain/ndk/toolchains/llvm/prebuilt/linux-x86_64/bin
|
||||
|
||||
# TODO: run tests in an emulator eventually
|
||||
ENV CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_LINKER=armv7a-linux-androideabi19-clang \
|
||||
CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_RUNNER=echo
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
FROM ubuntu:20.04
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
gcc \
|
||||
ca-certificates \
|
||||
libc6-dev \
|
||||
gcc-arm-linux-gnueabihf \
|
||||
libc6-dev-armhf-cross \
|
||||
qemu-user
|
||||
ENV CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \
|
||||
CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_RUNNER="qemu-arm -L /usr/arm-linux-gnueabihf"
|
||||
5
.gear/predownloaded-development/vendor/backtrace/ci/docker/i586-unknown-linux-gnu/Dockerfile
vendored
Normal file
5
.gear/predownloaded-development/vendor/backtrace/ci/docker/i586-unknown-linux-gnu/Dockerfile
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
FROM ubuntu:20.04
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
gcc-multilib \
|
||||
libc6-dev \
|
||||
ca-certificates
|
||||
18
.gear/predownloaded-development/vendor/backtrace/ci/docker/i686-linux-android/Dockerfile
vendored
Normal file
18
.gear/predownloaded-development/vendor/backtrace/ci/docker/i686-linux-android/Dockerfile
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
FROM ubuntu:20.04
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
curl \
|
||||
ca-certificates \
|
||||
unzip \
|
||||
openjdk-8-jre \
|
||||
python \
|
||||
gcc \
|
||||
libc6-dev
|
||||
|
||||
COPY android-ndk.sh /
|
||||
RUN /android-ndk.sh
|
||||
ENV PATH=$PATH:/android-toolchain/ndk/toolchains/llvm/prebuilt/linux-x86_64/bin
|
||||
|
||||
# TODO: run tests in an emulator eventually
|
||||
ENV CARGO_TARGET_I686_LINUX_ANDROID_LINKER=i686-linux-android19-clang \
|
||||
CARGO_TARGET_I686_LINUX_ANDROID_RUNNER=echo
|
||||
5
.gear/predownloaded-development/vendor/backtrace/ci/docker/i686-unknown-linux-gnu/Dockerfile
vendored
Normal file
5
.gear/predownloaded-development/vendor/backtrace/ci/docker/i686-unknown-linux-gnu/Dockerfile
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
FROM ubuntu:20.04
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
gcc-multilib \
|
||||
libc6-dev \
|
||||
ca-certificates
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
FROM ubuntu:20.04
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
gcc \
|
||||
ca-certificates \
|
||||
libc6-dev \
|
||||
gcc-powerpc64-linux-gnu \
|
||||
libc6-dev-ppc64-cross \
|
||||
qemu-user \
|
||||
qemu-system-ppc
|
||||
|
||||
ENV CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_LINKER=powerpc64-linux-gnu-gcc \
|
||||
# TODO: should actually run these tests
|
||||
#CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_RUNNER="qemu-ppc64 -L /usr/powerpc64-linux-gnu" \
|
||||
CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_RUNNER=echo \
|
||||
CC=powerpc64-linux-gnu-gcc
|
||||
17
.gear/predownloaded-development/vendor/backtrace/ci/docker/s390x-unknown-linux-gnu/Dockerfile
vendored
Normal file
17
.gear/predownloaded-development/vendor/backtrace/ci/docker/s390x-unknown-linux-gnu/Dockerfile
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
FROM ubuntu:20.04
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
gcc \
|
||||
ca-certificates \
|
||||
libc6-dev \
|
||||
gcc-s390x-linux-gnu \
|
||||
libc6-dev-s390x-cross \
|
||||
qemu-user \
|
||||
# There seems to be a bug in processing mixed-architecture
|
||||
# ld.so.cache files that causes crashes in some cases. Work
|
||||
# around this by simply deleting the cache for now.
|
||||
&& rm /etc/ld.so.cache
|
||||
|
||||
ENV CARGO_TARGET_S390X_UNKNOWN_LINUX_GNU_LINKER=s390x-linux-gnu-gcc \
|
||||
CARGO_TARGET_S390X_UNKNOWN_LINUX_GNU_RUNNER="qemu-s390x -L /usr/s390x-linux-gnu" \
|
||||
CC=s390x-linux-gnu-gcc
|
||||
18
.gear/predownloaded-development/vendor/backtrace/ci/docker/x86_64-linux-android/Dockerfile
vendored
Normal file
18
.gear/predownloaded-development/vendor/backtrace/ci/docker/x86_64-linux-android/Dockerfile
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
FROM ubuntu:20.04
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
curl \
|
||||
ca-certificates \
|
||||
unzip \
|
||||
openjdk-8-jre \
|
||||
python \
|
||||
gcc \
|
||||
libc6-dev
|
||||
|
||||
COPY android-ndk.sh /
|
||||
RUN /android-ndk.sh
|
||||
ENV PATH=$PATH:/android-toolchain/ndk/toolchains/llvm/prebuilt/linux-x86_64/bin
|
||||
|
||||
# TODO: run tests in an emulator eventually
|
||||
ENV CARGO_TARGET_X86_64_LINUX_ANDROID_LINKER=x86_64-linux-android21-clang \
|
||||
CARGO_TARGET_X86_64_LINUX_ANDROID_RUNNER=echo
|
||||
10
.gear/predownloaded-development/vendor/backtrace/ci/docker/x86_64-pc-windows-gnu/Dockerfile
vendored
Normal file
10
.gear/predownloaded-development/vendor/backtrace/ci/docker/x86_64-pc-windows-gnu/Dockerfile
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
FROM ubuntu:20.04
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
gcc \
|
||||
libc6-dev \
|
||||
ca-certificates \
|
||||
gcc-mingw-w64-x86-64
|
||||
|
||||
# No need to run tests, we're just testing that it compiles
|
||||
ENV CARGO_TARGET_X86_64_PC_WINDOWS_GNU_RUNNER=echo \
|
||||
CARGO_TARGET_X86_64_PC_WINDOWS_GNU_LINKER=x86_64-w64-mingw32-gcc
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
FROM ubuntu:20.04
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
gcc \
|
||||
libc6-dev \
|
||||
ca-certificates \
|
||||
dwz
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
FROM ubuntu:20.04
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
gcc \
|
||||
libc6-dev \
|
||||
ca-certificates \
|
||||
musl-tools
|
||||
33
.gear/predownloaded-development/vendor/backtrace/ci/run-docker.sh
vendored
Executable file
33
.gear/predownloaded-development/vendor/backtrace/ci/run-docker.sh
vendored
Executable file
|
|
@ -0,0 +1,33 @@
|
|||
# Small script to run tests for a target (or all targets) inside all the
|
||||
# respective docker images.
|
||||
|
||||
set -ex
|
||||
|
||||
run() {
|
||||
docker build -t backtrace -f ci/docker/$1/Dockerfile ci
|
||||
mkdir -p target
|
||||
docker run \
|
||||
--user `id -u`:`id -g` \
|
||||
--rm \
|
||||
--init \
|
||||
--volume $(dirname $(dirname `which cargo`)):/cargo \
|
||||
--env CARGO_HOME=/cargo \
|
||||
--volume `rustc --print sysroot`:/rust:ro \
|
||||
--env TARGET=$1 \
|
||||
--volume `pwd`:/checkout:ro \
|
||||
--volume `pwd`/target:/checkout/target \
|
||||
--workdir /checkout \
|
||||
--privileged \
|
||||
--env RUSTFLAGS \
|
||||
backtrace \
|
||||
bash \
|
||||
-c 'PATH=$PATH:/rust/bin exec ci/run.sh'
|
||||
}
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
for d in `ls ci/docker/`; do
|
||||
run $d
|
||||
done
|
||||
else
|
||||
run $1
|
||||
fi
|
||||
6
.gear/predownloaded-development/vendor/backtrace/ci/run.sh
vendored
Executable file
6
.gear/predownloaded-development/vendor/backtrace/ci/run.sh
vendored
Executable file
|
|
@ -0,0 +1,6 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -ex
|
||||
|
||||
cargo test --target $TARGET
|
||||
cargo build --target $TARGET --manifest-path crates/as-if-std/Cargo.toml
|
||||
50
.gear/predownloaded-development/vendor/backtrace/ci/runtest-android.rs
vendored
Normal file
50
.gear/predownloaded-development/vendor/backtrace/ci/runtest-android.rs
vendored
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
use std::env;
|
||||
use std::process::Command;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
fn main() {
|
||||
let args = env::args_os()
|
||||
.skip(1)
|
||||
.filter(|arg| arg != "--quiet")
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(args.len(), 1);
|
||||
let test = PathBuf::from(&args[0]);
|
||||
let dst = Path::new("/data/local/tmp").join(test.file_name().unwrap());
|
||||
|
||||
println!("waiting for device to come online...");
|
||||
let status = Command::new("adb")
|
||||
.arg("wait-for-device")
|
||||
.status()
|
||||
.expect("failed to run: adb wait-for-device");
|
||||
assert!(status.success());
|
||||
|
||||
println!("pushing executable...");
|
||||
let status = Command::new("adb")
|
||||
.arg("push")
|
||||
.arg(&test)
|
||||
.arg(&dst)
|
||||
.status()
|
||||
.expect("failed to run: adb pushr");
|
||||
assert!(status.success());
|
||||
|
||||
println!("executing tests...");
|
||||
let output = Command::new("adb")
|
||||
.arg("shell")
|
||||
.arg(&dst)
|
||||
.output()
|
||||
.expect("failed to run: adb shell");
|
||||
assert!(status.success());
|
||||
|
||||
println!("status: {}\nstdout ---\n{}\nstderr ---\n{}",
|
||||
output.status,
|
||||
String::from_utf8_lossy(&output.stdout),
|
||||
String::from_utf8_lossy(&output.stderr));
|
||||
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
stdout.lines().find(|l|
|
||||
(l.starts_with("PASSED ") && l.contains(" tests")) ||
|
||||
l.starts_with("test result: ok")
|
||||
).unwrap_or_else(|| {
|
||||
panic!("failed to find successful test run");
|
||||
});
|
||||
}
|
||||
5
.gear/predownloaded-development/vendor/backtrace/examples/backtrace.rs
vendored
Normal file
5
.gear/predownloaded-development/vendor/backtrace/examples/backtrace.rs
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
use backtrace::Backtrace;
|
||||
|
||||
fn main() {
|
||||
println!("{:?}", Backtrace::new());
|
||||
}
|
||||
52
.gear/predownloaded-development/vendor/backtrace/examples/raw.rs
vendored
Normal file
52
.gear/predownloaded-development/vendor/backtrace/examples/raw.rs
vendored
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
fn main() {
|
||||
foo();
|
||||
}
|
||||
|
||||
fn foo() {
|
||||
bar()
|
||||
}
|
||||
fn bar() {
|
||||
baz()
|
||||
}
|
||||
fn baz() {
|
||||
print()
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
const HEX_WIDTH: usize = 10;
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
const HEX_WIDTH: usize = 20;
|
||||
|
||||
fn print() {
|
||||
let mut cnt = 0;
|
||||
backtrace::trace(|frame| {
|
||||
let ip = frame.ip();
|
||||
print!("frame #{:<2} - {:#02$x}", cnt, ip as usize, HEX_WIDTH);
|
||||
cnt += 1;
|
||||
|
||||
let mut resolved = false;
|
||||
backtrace::resolve(frame.ip(), |symbol| {
|
||||
if !resolved {
|
||||
resolved = true;
|
||||
} else {
|
||||
print!("{}", vec![" "; 7 + 2 + 3 + HEX_WIDTH].join(""));
|
||||
}
|
||||
|
||||
if let Some(name) = symbol.name() {
|
||||
print!(" - {}", name);
|
||||
} else {
|
||||
print!(" - <unknown>");
|
||||
}
|
||||
if let Some(file) = symbol.filename() {
|
||||
if let Some(l) = symbol.lineno() {
|
||||
print!("\n{:13}{:4$}@ {}:{}", "", "", file.display(), l, HEX_WIDTH);
|
||||
}
|
||||
}
|
||||
println!("");
|
||||
});
|
||||
if !resolved {
|
||||
println!(" - <no info>");
|
||||
}
|
||||
true // keep going
|
||||
});
|
||||
}
|
||||
4
.gear/predownloaded-development/vendor/backtrace/src/android-api.c
vendored
Normal file
4
.gear/predownloaded-development/vendor/backtrace/src/android-api.c
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
// Used from the build script to detect the value of the `__ANDROID_API__`
|
||||
// builtin #define
|
||||
|
||||
APIVERSION __ANDROID_API__
|
||||
257
.gear/predownloaded-development/vendor/backtrace/src/backtrace/dbghelp.rs
vendored
Normal file
257
.gear/predownloaded-development/vendor/backtrace/src/backtrace/dbghelp.rs
vendored
Normal file
|
|
@ -0,0 +1,257 @@
|
|||
//! Backtrace strategy for MSVC platforms.
|
||||
//!
|
||||
//! This module contains the ability to generate a backtrace on MSVC using one
|
||||
//! of two possible methods. The `StackWalkEx` function is primarily used if
|
||||
//! possible, but not all systems have that. Failing that the `StackWalk64`
|
||||
//! function is used instead. Note that `StackWalkEx` is favored because it
|
||||
//! handles debuginfo internally and returns inline frame information.
|
||||
//!
|
||||
//! Note that all dbghelp support is loaded dynamically, see `src/dbghelp.rs`
|
||||
//! for more information about that.
|
||||
|
||||
#![allow(bad_style)]
|
||||
|
||||
use super::super::{dbghelp, windows::*};
|
||||
use core::ffi::c_void;
|
||||
use core::mem;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum StackFrame {
|
||||
New(STACKFRAME_EX),
|
||||
Old(STACKFRAME64),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Frame {
|
||||
pub(crate) stack_frame: StackFrame,
|
||||
base_address: *mut c_void,
|
||||
}
|
||||
|
||||
// we're just sending around raw pointers and reading them, never interpreting
|
||||
// them so this should be safe to both send and share across threads.
|
||||
unsafe impl Send for Frame {}
|
||||
unsafe impl Sync for Frame {}
|
||||
|
||||
impl Frame {
|
||||
pub fn ip(&self) -> *mut c_void {
|
||||
self.addr_pc().Offset as *mut _
|
||||
}
|
||||
|
||||
pub fn sp(&self) -> *mut c_void {
|
||||
self.addr_stack().Offset as *mut _
|
||||
}
|
||||
|
||||
pub fn symbol_address(&self) -> *mut c_void {
|
||||
self.ip()
|
||||
}
|
||||
|
||||
pub fn module_base_address(&self) -> Option<*mut c_void> {
|
||||
Some(self.base_address)
|
||||
}
|
||||
|
||||
fn addr_pc(&self) -> &ADDRESS64 {
|
||||
match self.stack_frame {
|
||||
StackFrame::New(ref new) => &new.AddrPC,
|
||||
StackFrame::Old(ref old) => &old.AddrPC,
|
||||
}
|
||||
}
|
||||
|
||||
fn addr_pc_mut(&mut self) -> &mut ADDRESS64 {
|
||||
match self.stack_frame {
|
||||
StackFrame::New(ref mut new) => &mut new.AddrPC,
|
||||
StackFrame::Old(ref mut old) => &mut old.AddrPC,
|
||||
}
|
||||
}
|
||||
|
||||
fn addr_frame_mut(&mut self) -> &mut ADDRESS64 {
|
||||
match self.stack_frame {
|
||||
StackFrame::New(ref mut new) => &mut new.AddrFrame,
|
||||
StackFrame::Old(ref mut old) => &mut old.AddrFrame,
|
||||
}
|
||||
}
|
||||
|
||||
fn addr_stack(&self) -> &ADDRESS64 {
|
||||
match self.stack_frame {
|
||||
StackFrame::New(ref new) => &new.AddrStack,
|
||||
StackFrame::Old(ref old) => &old.AddrStack,
|
||||
}
|
||||
}
|
||||
|
||||
fn addr_stack_mut(&mut self) -> &mut ADDRESS64 {
|
||||
match self.stack_frame {
|
||||
StackFrame::New(ref mut new) => &mut new.AddrStack,
|
||||
StackFrame::Old(ref mut old) => &mut old.AddrStack,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C, align(16))] // required by `CONTEXT`, is a FIXME in winapi right now
|
||||
struct MyContext(CONTEXT);
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn trace(cb: &mut dyn FnMut(&super::Frame) -> bool) {
|
||||
// Allocate necessary structures for doing the stack walk
|
||||
let process = GetCurrentProcess();
|
||||
let thread = GetCurrentThread();
|
||||
|
||||
let mut context = mem::zeroed::<MyContext>();
|
||||
RtlCaptureContext(&mut context.0);
|
||||
|
||||
// Ensure this process's symbols are initialized
|
||||
let dbghelp = match dbghelp::init() {
|
||||
Ok(dbghelp) => dbghelp,
|
||||
Err(()) => return, // oh well...
|
||||
};
|
||||
|
||||
// On x86_64 and ARM64 we opt to not use the default `Sym*` functions from
|
||||
// dbghelp for getting the function table and module base. Instead we use
|
||||
// the `RtlLookupFunctionEntry` function in kernel32 which will account for
|
||||
// JIT compiler frames as well. These should be equivalent, but using
|
||||
// `Rtl*` allows us to backtrace through JIT frames.
|
||||
//
|
||||
// Note that `RtlLookupFunctionEntry` only works for in-process backtraces,
|
||||
// but that's all we support anyway, so it all lines up well.
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(target_pointer_width = "64")] {
|
||||
use core::ptr;
|
||||
|
||||
unsafe extern "system" fn function_table_access(_process: HANDLE, addr: DWORD64) -> PVOID {
|
||||
let mut base = 0;
|
||||
RtlLookupFunctionEntry(addr, &mut base, ptr::null_mut()).cast()
|
||||
}
|
||||
|
||||
unsafe extern "system" fn get_module_base(_process: HANDLE, addr: DWORD64) -> DWORD64 {
|
||||
let mut base = 0;
|
||||
RtlLookupFunctionEntry(addr, &mut base, ptr::null_mut());
|
||||
base
|
||||
}
|
||||
} else {
|
||||
let function_table_access = dbghelp.SymFunctionTableAccess64();
|
||||
let get_module_base = dbghelp.SymGetModuleBase64();
|
||||
}
|
||||
}
|
||||
|
||||
let process_handle = GetCurrentProcess();
|
||||
|
||||
// Attempt to use `StackWalkEx` if we can, but fall back to `StackWalk64`
|
||||
// since it's in theory supported on more systems.
|
||||
match (*dbghelp.dbghelp()).StackWalkEx() {
|
||||
Some(StackWalkEx) => {
|
||||
let mut inner: STACKFRAME_EX = mem::zeroed();
|
||||
inner.StackFrameSize = mem::size_of::<STACKFRAME_EX>() as DWORD;
|
||||
let mut frame = super::Frame {
|
||||
inner: Frame {
|
||||
stack_frame: StackFrame::New(inner),
|
||||
base_address: 0 as _,
|
||||
},
|
||||
};
|
||||
let image = init_frame(&mut frame.inner, &context.0);
|
||||
let frame_ptr = match &mut frame.inner.stack_frame {
|
||||
StackFrame::New(ptr) => ptr as *mut STACKFRAME_EX,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
while StackWalkEx(
|
||||
image as DWORD,
|
||||
process,
|
||||
thread,
|
||||
frame_ptr,
|
||||
&mut context.0 as *mut CONTEXT as *mut _,
|
||||
None,
|
||||
Some(function_table_access),
|
||||
Some(get_module_base),
|
||||
None,
|
||||
0,
|
||||
) == TRUE
|
||||
{
|
||||
frame.inner.base_address = get_module_base(process_handle, frame.ip() as _) as _;
|
||||
|
||||
if !cb(&frame) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
let mut frame = super::Frame {
|
||||
inner: Frame {
|
||||
stack_frame: StackFrame::Old(mem::zeroed()),
|
||||
base_address: 0 as _,
|
||||
},
|
||||
};
|
||||
let image = init_frame(&mut frame.inner, &context.0);
|
||||
let frame_ptr = match &mut frame.inner.stack_frame {
|
||||
StackFrame::Old(ptr) => ptr as *mut STACKFRAME64,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
while dbghelp.StackWalk64()(
|
||||
image as DWORD,
|
||||
process,
|
||||
thread,
|
||||
frame_ptr,
|
||||
&mut context.0 as *mut CONTEXT as *mut _,
|
||||
None,
|
||||
Some(function_table_access),
|
||||
Some(get_module_base),
|
||||
None,
|
||||
) == TRUE
|
||||
{
|
||||
frame.inner.base_address = get_module_base(process_handle, frame.ip() as _) as _;
|
||||
|
||||
if !cb(&frame) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn init_frame(frame: &mut Frame, ctx: &CONTEXT) -> WORD {
|
||||
frame.addr_pc_mut().Offset = ctx.Rip as u64;
|
||||
frame.addr_pc_mut().Mode = AddrModeFlat;
|
||||
frame.addr_stack_mut().Offset = ctx.Rsp as u64;
|
||||
frame.addr_stack_mut().Mode = AddrModeFlat;
|
||||
frame.addr_frame_mut().Offset = ctx.Rbp as u64;
|
||||
frame.addr_frame_mut().Mode = AddrModeFlat;
|
||||
|
||||
IMAGE_FILE_MACHINE_AMD64
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86")]
|
||||
fn init_frame(frame: &mut Frame, ctx: &CONTEXT) -> WORD {
|
||||
frame.addr_pc_mut().Offset = ctx.Eip as u64;
|
||||
frame.addr_pc_mut().Mode = AddrModeFlat;
|
||||
frame.addr_stack_mut().Offset = ctx.Esp as u64;
|
||||
frame.addr_stack_mut().Mode = AddrModeFlat;
|
||||
frame.addr_frame_mut().Offset = ctx.Ebp as u64;
|
||||
frame.addr_frame_mut().Mode = AddrModeFlat;
|
||||
|
||||
IMAGE_FILE_MACHINE_I386
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
fn init_frame(frame: &mut Frame, ctx: &CONTEXT) -> WORD {
|
||||
frame.addr_pc_mut().Offset = ctx.Pc as u64;
|
||||
frame.addr_pc_mut().Mode = AddrModeFlat;
|
||||
frame.addr_stack_mut().Offset = ctx.Sp as u64;
|
||||
frame.addr_stack_mut().Mode = AddrModeFlat;
|
||||
unsafe {
|
||||
frame.addr_frame_mut().Offset = ctx.u.s().Fp as u64;
|
||||
}
|
||||
frame.addr_frame_mut().Mode = AddrModeFlat;
|
||||
IMAGE_FILE_MACHINE_ARM64
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "arm")]
|
||||
fn init_frame(frame: &mut Frame, ctx: &CONTEXT) -> WORD {
|
||||
frame.addr_pc_mut().Offset = ctx.Pc as u64;
|
||||
frame.addr_pc_mut().Mode = AddrModeFlat;
|
||||
frame.addr_stack_mut().Offset = ctx.Sp as u64;
|
||||
frame.addr_stack_mut().Mode = AddrModeFlat;
|
||||
unsafe {
|
||||
frame.addr_frame_mut().Offset = ctx.R11 as u64;
|
||||
}
|
||||
frame.addr_frame_mut().Mode = AddrModeFlat;
|
||||
IMAGE_FILE_MACHINE_ARMNT
|
||||
}
|
||||
268
.gear/predownloaded-development/vendor/backtrace/src/backtrace/libunwind.rs
vendored
Normal file
268
.gear/predownloaded-development/vendor/backtrace/src/backtrace/libunwind.rs
vendored
Normal file
|
|
@ -0,0 +1,268 @@
|
|||
//! Backtrace support using libunwind/gcc_s/etc APIs.
|
||||
//!
|
||||
//! This module contains the ability to unwind the stack using libunwind-style
|
||||
//! APIs. Note that there's a whole bunch of implementations of the
|
||||
//! libunwind-like API, and this is just trying to be compatible with most of
|
||||
//! them all at once instead of being picky.
|
||||
//!
|
||||
//! The libunwind API is powered by `_Unwind_Backtrace` and is in practice very
|
||||
//! reliable at generating a backtrace. It's not entirely clear how it does it
|
||||
//! (frame pointers? eh_frame info? both?) but it seems to work!
|
||||
//!
|
||||
//! Most of the complexity of this module is handling the various platform
|
||||
//! differences across libunwind implementations. Otherwise this is a pretty
|
||||
//! straightforward Rust binding to the libunwind APIs.
|
||||
//!
|
||||
//! This is the default unwinding API for all non-Windows platforms currently.
|
||||
|
||||
use super::super::Bomb;
|
||||
use core::ffi::c_void;
|
||||
|
||||
pub enum Frame {
|
||||
Raw(*mut uw::_Unwind_Context),
|
||||
Cloned {
|
||||
ip: *mut c_void,
|
||||
sp: *mut c_void,
|
||||
symbol_address: *mut c_void,
|
||||
},
|
||||
}
|
||||
|
||||
// With a raw libunwind pointer it should only ever be access in a readonly
|
||||
// threadsafe fashion, so it's `Sync`. When sending to other threads via `Clone`
|
||||
// we always switch to a version which doesn't retain interior pointers, so we
|
||||
// should be `Send` as well.
|
||||
unsafe impl Send for Frame {}
|
||||
unsafe impl Sync for Frame {}
|
||||
|
||||
impl Frame {
|
||||
pub fn ip(&self) -> *mut c_void {
|
||||
let ctx = match *self {
|
||||
Frame::Raw(ctx) => ctx,
|
||||
Frame::Cloned { ip, .. } => return ip,
|
||||
};
|
||||
unsafe { uw::_Unwind_GetIP(ctx) as *mut c_void }
|
||||
}
|
||||
|
||||
pub fn sp(&self) -> *mut c_void {
|
||||
match *self {
|
||||
Frame::Raw(ctx) => unsafe { uw::get_sp(ctx) as *mut c_void },
|
||||
Frame::Cloned { sp, .. } => sp,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn symbol_address(&self) -> *mut c_void {
|
||||
if let Frame::Cloned { symbol_address, .. } = *self {
|
||||
return symbol_address;
|
||||
}
|
||||
|
||||
// The macOS linker emits a "compact" unwind table that only includes an
|
||||
// entry for a function if that function either has an LSDA or its
|
||||
// encoding differs from that of the previous entry. Consequently, on
|
||||
// macOS, `_Unwind_FindEnclosingFunction` is unreliable (it can return a
|
||||
// pointer to some totally unrelated function). Instead, we just always
|
||||
// return the ip.
|
||||
//
|
||||
// https://github.com/rust-lang/rust/issues/74771#issuecomment-664056788
|
||||
//
|
||||
// Note the `skip_inner_frames.rs` test is skipped on macOS due to this
|
||||
// clause, and if this is fixed that test in theory can be run on macOS!
|
||||
if cfg!(target_vendor = "apple") {
|
||||
self.ip()
|
||||
} else {
|
||||
unsafe { uw::_Unwind_FindEnclosingFunction(self.ip()) }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn module_base_address(&self) -> Option<*mut c_void> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Frame {
|
||||
fn clone(&self) -> Frame {
|
||||
Frame::Cloned {
|
||||
ip: self.ip(),
|
||||
sp: self.sp(),
|
||||
symbol_address: self.symbol_address(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn trace(mut cb: &mut dyn FnMut(&super::Frame) -> bool) {
|
||||
uw::_Unwind_Backtrace(trace_fn, &mut cb as *mut _ as *mut _);
|
||||
|
||||
extern "C" fn trace_fn(
|
||||
ctx: *mut uw::_Unwind_Context,
|
||||
arg: *mut c_void,
|
||||
) -> uw::_Unwind_Reason_Code {
|
||||
let cb = unsafe { &mut *(arg as *mut &mut dyn FnMut(&super::Frame) -> bool) };
|
||||
let cx = super::Frame {
|
||||
inner: Frame::Raw(ctx),
|
||||
};
|
||||
|
||||
let mut bomb = Bomb { enabled: true };
|
||||
let keep_going = cb(&cx);
|
||||
bomb.enabled = false;
|
||||
|
||||
if keep_going {
|
||||
uw::_URC_NO_REASON
|
||||
} else {
|
||||
uw::_URC_FAILURE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Unwind library interface used for backtraces
|
||||
///
|
||||
/// Note that dead code is allowed as here are just bindings
|
||||
/// iOS doesn't use all of them it but adding more
|
||||
/// platform-specific configs pollutes the code too much
|
||||
#[allow(non_camel_case_types)]
|
||||
#[allow(non_snake_case)]
|
||||
#[allow(dead_code)]
|
||||
mod uw {
|
||||
pub use self::_Unwind_Reason_Code::*;
|
||||
|
||||
use core::ffi::c_void;
|
||||
|
||||
#[repr(C)]
|
||||
pub enum _Unwind_Reason_Code {
|
||||
_URC_NO_REASON = 0,
|
||||
_URC_FOREIGN_EXCEPTION_CAUGHT = 1,
|
||||
_URC_FATAL_PHASE2_ERROR = 2,
|
||||
_URC_FATAL_PHASE1_ERROR = 3,
|
||||
_URC_NORMAL_STOP = 4,
|
||||
_URC_END_OF_STACK = 5,
|
||||
_URC_HANDLER_FOUND = 6,
|
||||
_URC_INSTALL_CONTEXT = 7,
|
||||
_URC_CONTINUE_UNWIND = 8,
|
||||
_URC_FAILURE = 9, // used only by ARM EABI
|
||||
}
|
||||
|
||||
pub enum _Unwind_Context {}
|
||||
|
||||
pub type _Unwind_Trace_Fn =
|
||||
extern "C" fn(ctx: *mut _Unwind_Context, arg: *mut c_void) -> _Unwind_Reason_Code;
|
||||
|
||||
extern "C" {
|
||||
pub fn _Unwind_Backtrace(
|
||||
trace: _Unwind_Trace_Fn,
|
||||
trace_argument: *mut c_void,
|
||||
) -> _Unwind_Reason_Code;
|
||||
}
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
// available since GCC 4.2.0, should be fine for our purpose
|
||||
if #[cfg(all(
|
||||
not(all(target_os = "android", target_arch = "arm")),
|
||||
not(all(target_os = "freebsd", target_arch = "arm")),
|
||||
not(all(target_os = "linux", target_arch = "arm")),
|
||||
not(all(target_os = "horizon", target_arch = "arm")),
|
||||
not(all(target_os = "vita", target_arch = "arm")),
|
||||
))] {
|
||||
extern "C" {
|
||||
pub fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> libc::uintptr_t;
|
||||
pub fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void;
|
||||
|
||||
#[cfg(not(all(target_os = "linux", target_arch = "s390x")))]
|
||||
// This function is a misnomer: rather than getting this frame's
|
||||
// Canonical Frame Address (aka the caller frame's SP) it
|
||||
// returns this frame's SP.
|
||||
//
|
||||
// https://github.com/libunwind/libunwind/blob/d32956507cf29d9b1a98a8bce53c78623908f4fe/src/unwind/GetCFA.c#L28-L35
|
||||
#[link_name = "_Unwind_GetCFA"]
|
||||
pub fn get_sp(ctx: *mut _Unwind_Context) -> libc::uintptr_t;
|
||||
|
||||
}
|
||||
|
||||
// s390x uses a biased CFA value, therefore we need to use
|
||||
// _Unwind_GetGR to get the stack pointer register (%r15)
|
||||
// instead of relying on _Unwind_GetCFA.
|
||||
#[cfg(all(target_os = "linux", target_arch = "s390x"))]
|
||||
pub unsafe fn get_sp(ctx: *mut _Unwind_Context) -> libc::uintptr_t {
|
||||
extern "C" {
|
||||
pub fn _Unwind_GetGR(ctx: *mut _Unwind_Context, index: libc::c_int) -> libc::uintptr_t;
|
||||
}
|
||||
_Unwind_GetGR(ctx, 15)
|
||||
}
|
||||
} else {
|
||||
// On android and arm, the function `_Unwind_GetIP` and a bunch of
|
||||
// others are macros, so we define functions containing the
|
||||
// expansion of the macros.
|
||||
//
|
||||
// TODO: link to the header file that defines these macros, if you
|
||||
// can find it. (I, fitzgen, cannot find the header file that some
|
||||
// of these macro expansions were originally borrowed from.)
|
||||
#[repr(C)]
|
||||
enum _Unwind_VRS_Result {
|
||||
_UVRSR_OK = 0,
|
||||
_UVRSR_NOT_IMPLEMENTED = 1,
|
||||
_UVRSR_FAILED = 2,
|
||||
}
|
||||
#[repr(C)]
|
||||
enum _Unwind_VRS_RegClass {
|
||||
_UVRSC_CORE = 0,
|
||||
_UVRSC_VFP = 1,
|
||||
_UVRSC_FPA = 2,
|
||||
_UVRSC_WMMXD = 3,
|
||||
_UVRSC_WMMXC = 4,
|
||||
}
|
||||
#[repr(C)]
|
||||
enum _Unwind_VRS_DataRepresentation {
|
||||
_UVRSD_UINT32 = 0,
|
||||
_UVRSD_VFPX = 1,
|
||||
_UVRSD_FPAX = 2,
|
||||
_UVRSD_UINT64 = 3,
|
||||
_UVRSD_FLOAT = 4,
|
||||
_UVRSD_DOUBLE = 5,
|
||||
}
|
||||
|
||||
type _Unwind_Word = libc::c_uint;
|
||||
extern "C" {
|
||||
fn _Unwind_VRS_Get(
|
||||
ctx: *mut _Unwind_Context,
|
||||
klass: _Unwind_VRS_RegClass,
|
||||
word: _Unwind_Word,
|
||||
repr: _Unwind_VRS_DataRepresentation,
|
||||
data: *mut c_void,
|
||||
) -> _Unwind_VRS_Result;
|
||||
}
|
||||
|
||||
pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> libc::uintptr_t {
|
||||
let mut val: _Unwind_Word = 0;
|
||||
let ptr = &mut val as *mut _Unwind_Word;
|
||||
let _ = _Unwind_VRS_Get(
|
||||
ctx,
|
||||
_Unwind_VRS_RegClass::_UVRSC_CORE,
|
||||
15,
|
||||
_Unwind_VRS_DataRepresentation::_UVRSD_UINT32,
|
||||
ptr as *mut c_void,
|
||||
);
|
||||
(val & !1) as libc::uintptr_t
|
||||
}
|
||||
|
||||
// R13 is the stack pointer on arm.
|
||||
const SP: _Unwind_Word = 13;
|
||||
|
||||
pub unsafe fn get_sp(ctx: *mut _Unwind_Context) -> libc::uintptr_t {
|
||||
let mut val: _Unwind_Word = 0;
|
||||
let ptr = &mut val as *mut _Unwind_Word;
|
||||
let _ = _Unwind_VRS_Get(
|
||||
ctx,
|
||||
_Unwind_VRS_RegClass::_UVRSC_CORE,
|
||||
SP,
|
||||
_Unwind_VRS_DataRepresentation::_UVRSD_UINT32,
|
||||
ptr as *mut c_void,
|
||||
);
|
||||
val as libc::uintptr_t
|
||||
}
|
||||
|
||||
// This function also doesn't exist on Android or ARM/Linux, so make it
|
||||
// a no-op.
|
||||
pub unsafe fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void {
|
||||
pc
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
109
.gear/predownloaded-development/vendor/backtrace/src/backtrace/miri.rs
vendored
Normal file
109
.gear/predownloaded-development/vendor/backtrace/src/backtrace/miri.rs
vendored
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
use alloc::boxed::Box;
|
||||
use alloc::vec::Vec;
|
||||
use core::ffi::c_void;
|
||||
|
||||
extern "Rust" {
|
||||
fn miri_backtrace_size(flags: u64) -> usize;
|
||||
fn miri_get_backtrace(flags: u64, buf: *mut *mut ());
|
||||
fn miri_resolve_frame(ptr: *mut (), flags: u64) -> MiriFrame;
|
||||
fn miri_resolve_frame_names(ptr: *mut (), flags: u64, name_buf: *mut u8, filename_buf: *mut u8);
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct MiriFrame {
|
||||
pub name_len: usize,
|
||||
pub filename_len: usize,
|
||||
pub lineno: u32,
|
||||
pub colno: u32,
|
||||
pub fn_ptr: *mut c_void,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct FullMiriFrame {
|
||||
pub name: Box<[u8]>,
|
||||
pub filename: Box<[u8]>,
|
||||
pub lineno: u32,
|
||||
pub colno: u32,
|
||||
pub fn_ptr: *mut c_void,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Frame {
|
||||
pub addr: *mut c_void,
|
||||
pub inner: FullMiriFrame,
|
||||
}
|
||||
|
||||
// SAFETY: Miri guarantees that the returned pointer
|
||||
// can be used from any thread.
|
||||
unsafe impl Send for Frame {}
|
||||
unsafe impl Sync for Frame {}
|
||||
|
||||
impl Frame {
|
||||
pub fn ip(&self) -> *mut c_void {
|
||||
self.addr
|
||||
}
|
||||
|
||||
pub fn sp(&self) -> *mut c_void {
|
||||
core::ptr::null_mut()
|
||||
}
|
||||
|
||||
pub fn symbol_address(&self) -> *mut c_void {
|
||||
self.inner.fn_ptr
|
||||
}
|
||||
|
||||
pub fn module_base_address(&self) -> Option<*mut c_void> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn trace<F: FnMut(&super::Frame) -> bool>(cb: F) {
|
||||
// SAFETY: Miri guarantees that the backtrace API functions
|
||||
// can be called from any thread.
|
||||
unsafe { trace_unsynchronized(cb) };
|
||||
}
|
||||
|
||||
pub fn resolve_addr(ptr: *mut c_void) -> Frame {
|
||||
// SAFETY: Miri will stop execution with an error if this pointer
|
||||
// is invalid.
|
||||
let frame = unsafe { miri_resolve_frame(ptr as *mut (), 1) };
|
||||
|
||||
let mut name = Vec::with_capacity(frame.name_len);
|
||||
let mut filename = Vec::with_capacity(frame.filename_len);
|
||||
|
||||
// SAFETY: name and filename have been allocated with the amount
|
||||
// of memory miri has asked for, and miri guarantees it will initialize it
|
||||
unsafe {
|
||||
miri_resolve_frame_names(ptr as *mut (), 0, name.as_mut_ptr(), filename.as_mut_ptr());
|
||||
|
||||
name.set_len(frame.name_len);
|
||||
filename.set_len(frame.filename_len);
|
||||
}
|
||||
|
||||
Frame {
|
||||
addr: ptr,
|
||||
inner: FullMiriFrame {
|
||||
name: name.into(),
|
||||
filename: filename.into(),
|
||||
lineno: frame.lineno,
|
||||
colno: frame.colno,
|
||||
fn_ptr: frame.fn_ptr,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn trace_unsynchronized<F: FnMut(&super::Frame) -> bool>(mut cb: F) {
|
||||
let len = miri_backtrace_size(0);
|
||||
|
||||
let mut frames = Vec::with_capacity(len);
|
||||
|
||||
miri_get_backtrace(1, frames.as_mut_ptr());
|
||||
|
||||
frames.set_len(len);
|
||||
|
||||
for ptr in frames.iter() {
|
||||
let frame = resolve_addr(*ptr as *mut c_void);
|
||||
if !cb(&super::Frame { inner: frame }) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
163
.gear/predownloaded-development/vendor/backtrace/src/backtrace/mod.rs
vendored
Normal file
163
.gear/predownloaded-development/vendor/backtrace/src/backtrace/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
use core::ffi::c_void;
|
||||
use core::fmt;
|
||||
|
||||
/// Inspects the current call-stack, passing all active frames into the closure
|
||||
/// provided to calculate a stack trace.
|
||||
///
|
||||
/// This function is the workhorse of this library in calculating the stack
|
||||
/// traces for a program. The given closure `cb` is yielded instances of a
|
||||
/// `Frame` which represent information about that call frame on the stack. The
|
||||
/// closure is yielded frames in a top-down fashion (most recently called
|
||||
/// functions first).
|
||||
///
|
||||
/// The closure's return value is an indication of whether the backtrace should
|
||||
/// continue. A return value of `false` will terminate the backtrace and return
|
||||
/// immediately.
|
||||
///
|
||||
/// Once a `Frame` is acquired you will likely want to call `backtrace::resolve`
|
||||
/// to convert the `ip` (instruction pointer) or symbol address to a `Symbol`
|
||||
/// through which the name and/or filename/line number can be learned.
|
||||
///
|
||||
/// Note that this is a relatively low-level function and if you'd like to, for
|
||||
/// example, capture a backtrace to be inspected later, then the `Backtrace`
|
||||
/// type may be more appropriate.
|
||||
///
|
||||
/// # Required features
|
||||
///
|
||||
/// This function requires the `std` feature of the `backtrace` crate to be
|
||||
/// enabled, and the `std` feature is enabled by default.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function strives to never panic, but if the `cb` provided panics then
|
||||
/// some platforms will force a double panic to abort the process. Some
|
||||
/// platforms use a C library which internally uses callbacks which cannot be
|
||||
/// unwound through, so panicking from `cb` may trigger a process abort.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// extern crate backtrace;
|
||||
///
|
||||
/// fn main() {
|
||||
/// backtrace::trace(|frame| {
|
||||
/// // ...
|
||||
///
|
||||
/// true // continue the backtrace
|
||||
/// });
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg(feature = "std")]
|
||||
pub fn trace<F: FnMut(&Frame) -> bool>(cb: F) {
|
||||
let _guard = crate::lock::lock();
|
||||
unsafe { trace_unsynchronized(cb) }
|
||||
}
|
||||
|
||||
/// Same as `trace`, only unsafe as it's unsynchronized.
|
||||
///
|
||||
/// This function does not have synchronization guarantees but is available
|
||||
/// when the `std` feature of this crate isn't compiled in. See the `trace`
|
||||
/// function for more documentation and examples.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// See information on `trace` for caveats on `cb` panicking.
|
||||
pub unsafe fn trace_unsynchronized<F: FnMut(&Frame) -> bool>(mut cb: F) {
|
||||
trace_imp(&mut cb)
|
||||
}
|
||||
|
||||
/// A trait representing one frame of a backtrace, yielded to the `trace`
|
||||
/// function of this crate.
|
||||
///
|
||||
/// The tracing function's closure will be yielded frames, and the frame is
|
||||
/// virtually dispatched as the underlying implementation is not always known
|
||||
/// until runtime.
|
||||
#[derive(Clone)]
|
||||
pub struct Frame {
|
||||
pub(crate) inner: FrameImp,
|
||||
}
|
||||
|
||||
impl Frame {
|
||||
/// Returns the current instruction pointer of this frame.
|
||||
///
|
||||
/// This is normally the next instruction to execute in the frame, but not
|
||||
/// all implementations list this with 100% accuracy (but it's generally
|
||||
/// pretty close).
|
||||
///
|
||||
/// It is recommended to pass this value to `backtrace::resolve` to turn it
|
||||
/// into a symbol name.
|
||||
pub fn ip(&self) -> *mut c_void {
|
||||
self.inner.ip()
|
||||
}
|
||||
|
||||
/// Returns the current stack pointer of this frame.
|
||||
///
|
||||
/// In the case that a backend cannot recover the stack pointer for this
|
||||
/// frame, a null pointer is returned.
|
||||
pub fn sp(&self) -> *mut c_void {
|
||||
self.inner.sp()
|
||||
}
|
||||
|
||||
/// Returns the starting symbol address of the frame of this function.
|
||||
///
|
||||
/// This will attempt to rewind the instruction pointer returned by `ip` to
|
||||
/// the start of the function, returning that value. In some cases, however,
|
||||
/// backends will just return `ip` from this function.
|
||||
///
|
||||
/// The returned value can sometimes be used if `backtrace::resolve` failed
|
||||
/// on the `ip` given above.
|
||||
pub fn symbol_address(&self) -> *mut c_void {
|
||||
self.inner.symbol_address()
|
||||
}
|
||||
|
||||
/// Returns the base address of the module to which the frame belongs.
|
||||
pub fn module_base_address(&self) -> Option<*mut c_void> {
|
||||
self.inner.module_base_address()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Frame {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("Frame")
|
||||
.field("ip", &self.ip())
|
||||
.field("symbol_address", &self.symbol_address())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
// This needs to come first, to ensure that
|
||||
// Miri takes priority over the host platform
|
||||
if #[cfg(miri)] {
|
||||
pub(crate) mod miri;
|
||||
use self::miri::trace as trace_imp;
|
||||
pub(crate) use self::miri::Frame as FrameImp;
|
||||
} else if #[cfg(
|
||||
any(
|
||||
all(
|
||||
unix,
|
||||
not(target_os = "emscripten"),
|
||||
not(all(target_os = "ios", target_arch = "arm")),
|
||||
not(all(target_os = "nto", target_env = "nto70")),
|
||||
),
|
||||
all(
|
||||
target_env = "sgx",
|
||||
target_vendor = "fortanix",
|
||||
),
|
||||
)
|
||||
)] {
|
||||
mod libunwind;
|
||||
use self::libunwind::trace as trace_imp;
|
||||
pub(crate) use self::libunwind::Frame as FrameImp;
|
||||
} else if #[cfg(all(windows, not(target_vendor = "uwp")))] {
|
||||
mod dbghelp;
|
||||
use self::dbghelp::trace as trace_imp;
|
||||
pub(crate) use self::dbghelp::Frame as FrameImp;
|
||||
#[cfg(target_env = "msvc")] // only used in dbghelp symbolize
|
||||
pub(crate) use self::dbghelp::StackFrame;
|
||||
} else {
|
||||
mod noop;
|
||||
use self::noop::trace as trace_imp;
|
||||
pub(crate) use self::noop::Frame as FrameImp;
|
||||
}
|
||||
}
|
||||
28
.gear/predownloaded-development/vendor/backtrace/src/backtrace/noop.rs
vendored
Normal file
28
.gear/predownloaded-development/vendor/backtrace/src/backtrace/noop.rs
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
//! Empty implementation of unwinding used when no other implementation is
|
||||
//! appropriate.
|
||||
|
||||
use core::ffi::c_void;
|
||||
|
||||
#[inline(always)]
|
||||
pub fn trace(_cb: &mut dyn FnMut(&super::Frame) -> bool) {}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Frame;
|
||||
|
||||
impl Frame {
|
||||
pub fn ip(&self) -> *mut c_void {
|
||||
0 as *mut _
|
||||
}
|
||||
|
||||
pub fn sp(&self) -> *mut c_void {
|
||||
0 as *mut _
|
||||
}
|
||||
|
||||
pub fn symbol_address(&self) -> *mut c_void {
|
||||
0 as *mut _
|
||||
}
|
||||
|
||||
pub fn module_base_address(&self) -> Option<*mut c_void> {
|
||||
None
|
||||
}
|
||||
}
|
||||
555
.gear/predownloaded-development/vendor/backtrace/src/capture.rs
vendored
Normal file
555
.gear/predownloaded-development/vendor/backtrace/src/capture.rs
vendored
Normal file
|
|
@ -0,0 +1,555 @@
|
|||
use crate::PrintFmt;
|
||||
use crate::{resolve, resolve_frame, trace, BacktraceFmt, Symbol, SymbolName};
|
||||
use std::ffi::c_void;
|
||||
use std::fmt;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::prelude::v1::*;
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Representation of an owned and self-contained backtrace.
|
||||
///
|
||||
/// This structure can be used to capture a backtrace at various points in a
|
||||
/// program and later used to inspect what the backtrace was at that time.
|
||||
///
|
||||
/// `Backtrace` supports pretty-printing of backtraces through its `Debug`
|
||||
/// implementation.
|
||||
///
|
||||
/// # Required features
|
||||
///
|
||||
/// This function requires the `std` feature of the `backtrace` crate to be
|
||||
/// enabled, and the `std` feature is enabled by default.
|
||||
#[derive(Clone)]
|
||||
#[cfg_attr(feature = "serialize-rustc", derive(RustcDecodable, RustcEncodable))]
|
||||
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
|
||||
pub struct Backtrace {
|
||||
// Frames here are listed from top-to-bottom of the stack
|
||||
frames: Vec<BacktraceFrame>,
|
||||
// The index we believe is the actual start of the backtrace, omitting
|
||||
// frames like `Backtrace::new` and `backtrace::trace`.
|
||||
actual_start_index: usize,
|
||||
}
|
||||
|
||||
fn _assert_send_sync() {
|
||||
fn _assert<T: Send + Sync>() {}
|
||||
_assert::<Backtrace>();
|
||||
}
|
||||
|
||||
/// Captured version of a frame in a backtrace.
|
||||
///
|
||||
/// This type is returned as a list from `Backtrace::frames` and represents one
|
||||
/// stack frame in a captured backtrace.
|
||||
///
|
||||
/// # Required features
|
||||
///
|
||||
/// This function requires the `std` feature of the `backtrace` crate to be
|
||||
/// enabled, and the `std` feature is enabled by default.
|
||||
#[derive(Clone)]
|
||||
pub struct BacktraceFrame {
|
||||
frame: Frame,
|
||||
symbols: Option<Vec<BacktraceSymbol>>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
enum Frame {
|
||||
Raw(crate::Frame),
|
||||
#[allow(dead_code)]
|
||||
Deserialized {
|
||||
ip: usize,
|
||||
symbol_address: usize,
|
||||
module_base_address: Option<usize>,
|
||||
},
|
||||
}
|
||||
|
||||
impl Frame {
|
||||
fn ip(&self) -> *mut c_void {
|
||||
match *self {
|
||||
Frame::Raw(ref f) => f.ip(),
|
||||
Frame::Deserialized { ip, .. } => ip as *mut c_void,
|
||||
}
|
||||
}
|
||||
|
||||
fn symbol_address(&self) -> *mut c_void {
|
||||
match *self {
|
||||
Frame::Raw(ref f) => f.symbol_address(),
|
||||
Frame::Deserialized { symbol_address, .. } => symbol_address as *mut c_void,
|
||||
}
|
||||
}
|
||||
|
||||
fn module_base_address(&self) -> Option<*mut c_void> {
|
||||
match *self {
|
||||
Frame::Raw(ref f) => f.module_base_address(),
|
||||
Frame::Deserialized {
|
||||
module_base_address,
|
||||
..
|
||||
} => module_base_address.map(|addr| addr as *mut c_void),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Captured version of a symbol in a backtrace.
|
||||
///
|
||||
/// This type is returned as a list from `BacktraceFrame::symbols` and
|
||||
/// represents the metadata for a symbol in a backtrace.
|
||||
///
|
||||
/// # Required features
|
||||
///
|
||||
/// This function requires the `std` feature of the `backtrace` crate to be
|
||||
/// enabled, and the `std` feature is enabled by default.
|
||||
#[derive(Clone)]
|
||||
#[cfg_attr(feature = "serialize-rustc", derive(RustcDecodable, RustcEncodable))]
|
||||
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
|
||||
pub struct BacktraceSymbol {
|
||||
name: Option<Vec<u8>>,
|
||||
addr: Option<usize>,
|
||||
filename: Option<PathBuf>,
|
||||
lineno: Option<u32>,
|
||||
colno: Option<u32>,
|
||||
}
|
||||
|
||||
impl Backtrace {
|
||||
/// Captures a backtrace at the callsite of this function, returning an
|
||||
/// owned representation.
|
||||
///
|
||||
/// This function is useful for representing a backtrace as an object in
|
||||
/// Rust. This returned value can be sent across threads and printed
|
||||
/// elsewhere, and the purpose of this value is to be entirely self
|
||||
/// contained.
|
||||
///
|
||||
/// Note that on some platforms acquiring a full backtrace and resolving it
|
||||
/// can be extremely expensive. If the cost is too much for your application
|
||||
/// it's recommended to instead use `Backtrace::new_unresolved()` which
|
||||
/// avoids the symbol resolution step (which typically takes the longest)
|
||||
/// and allows deferring that to a later date.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use backtrace::Backtrace;
|
||||
///
|
||||
/// let current_backtrace = Backtrace::new();
|
||||
/// ```
|
||||
///
|
||||
/// # Required features
|
||||
///
|
||||
/// This function requires the `std` feature of the `backtrace` crate to be
|
||||
/// enabled, and the `std` feature is enabled by default.
|
||||
#[inline(never)] // want to make sure there's a frame here to remove
|
||||
pub fn new() -> Backtrace {
|
||||
let mut bt = Self::create(Self::new as usize);
|
||||
bt.resolve();
|
||||
bt
|
||||
}
|
||||
|
||||
/// Similar to `new` except that this does not resolve any symbols, this
|
||||
/// simply captures the backtrace as a list of addresses.
|
||||
///
|
||||
/// At a later time the `resolve` function can be called to resolve this
|
||||
/// backtrace's symbols into readable names. This function exists because
|
||||
/// the resolution process can sometimes take a significant amount of time
|
||||
/// whereas any one backtrace may only be rarely printed.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use backtrace::Backtrace;
|
||||
///
|
||||
/// let mut current_backtrace = Backtrace::new_unresolved();
|
||||
/// println!("{:?}", current_backtrace); // no symbol names
|
||||
/// current_backtrace.resolve();
|
||||
/// println!("{:?}", current_backtrace); // symbol names now present
|
||||
/// ```
|
||||
///
|
||||
/// # Required features
|
||||
///
|
||||
/// This function requires the `std` feature of the `backtrace` crate to be
|
||||
/// enabled, and the `std` feature is enabled by default.
|
||||
#[inline(never)] // want to make sure there's a frame here to remove
|
||||
pub fn new_unresolved() -> Backtrace {
|
||||
Self::create(Self::new_unresolved as usize)
|
||||
}
|
||||
|
||||
fn create(ip: usize) -> Backtrace {
|
||||
let mut frames = Vec::new();
|
||||
let mut actual_start_index = None;
|
||||
trace(|frame| {
|
||||
frames.push(BacktraceFrame {
|
||||
frame: Frame::Raw(frame.clone()),
|
||||
symbols: None,
|
||||
});
|
||||
|
||||
if frame.symbol_address() as usize == ip && actual_start_index.is_none() {
|
||||
actual_start_index = Some(frames.len());
|
||||
}
|
||||
true
|
||||
});
|
||||
|
||||
Backtrace {
|
||||
frames,
|
||||
actual_start_index: actual_start_index.unwrap_or(0),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the frames from when this backtrace was captured.
|
||||
///
|
||||
/// The first entry of this slice is likely the function `Backtrace::new`,
|
||||
/// and the last frame is likely something about how this thread or the main
|
||||
/// function started.
|
||||
///
|
||||
/// # Required features
|
||||
///
|
||||
/// This function requires the `std` feature of the `backtrace` crate to be
|
||||
/// enabled, and the `std` feature is enabled by default.
|
||||
pub fn frames(&self) -> &[BacktraceFrame] {
|
||||
&self.frames[self.actual_start_index..]
|
||||
}
|
||||
|
||||
/// If this backtrace was created from `new_unresolved` then this function
|
||||
/// will resolve all addresses in the backtrace to their symbolic names.
|
||||
///
|
||||
/// If this backtrace has been previously resolved or was created through
|
||||
/// `new`, this function does nothing.
|
||||
///
|
||||
/// # Required features
|
||||
///
|
||||
/// This function requires the `std` feature of the `backtrace` crate to be
|
||||
/// enabled, and the `std` feature is enabled by default.
|
||||
pub fn resolve(&mut self) {
|
||||
for frame in self.frames.iter_mut().filter(|f| f.symbols.is_none()) {
|
||||
let mut symbols = Vec::new();
|
||||
{
|
||||
let sym = |symbol: &Symbol| {
|
||||
symbols.push(BacktraceSymbol {
|
||||
name: symbol.name().map(|m| m.as_bytes().to_vec()),
|
||||
addr: symbol.addr().map(|a| a as usize),
|
||||
filename: symbol.filename().map(|m| m.to_owned()),
|
||||
lineno: symbol.lineno(),
|
||||
colno: symbol.colno(),
|
||||
});
|
||||
};
|
||||
match frame.frame {
|
||||
Frame::Raw(ref f) => resolve_frame(f, sym),
|
||||
Frame::Deserialized { ip, .. } => {
|
||||
resolve(ip as *mut c_void, sym);
|
||||
}
|
||||
}
|
||||
}
|
||||
frame.symbols = Some(symbols);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<BacktraceFrame>> for Backtrace {
|
||||
fn from(frames: Vec<BacktraceFrame>) -> Self {
|
||||
Backtrace {
|
||||
frames,
|
||||
actual_start_index: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crate::Frame> for BacktraceFrame {
|
||||
fn from(frame: crate::Frame) -> BacktraceFrame {
|
||||
BacktraceFrame {
|
||||
frame: Frame::Raw(frame),
|
||||
symbols: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<Vec<BacktraceFrame>> for Backtrace {
|
||||
fn into(self) -> Vec<BacktraceFrame> {
|
||||
self.frames
|
||||
}
|
||||
}
|
||||
|
||||
impl BacktraceFrame {
|
||||
/// Same as `Frame::ip`
|
||||
///
|
||||
/// # Required features
|
||||
///
|
||||
/// This function requires the `std` feature of the `backtrace` crate to be
|
||||
/// enabled, and the `std` feature is enabled by default.
|
||||
pub fn ip(&self) -> *mut c_void {
|
||||
self.frame.ip() as *mut c_void
|
||||
}
|
||||
|
||||
/// Same as `Frame::symbol_address`
|
||||
///
|
||||
/// # Required features
|
||||
///
|
||||
/// This function requires the `std` feature of the `backtrace` crate to be
|
||||
/// enabled, and the `std` feature is enabled by default.
|
||||
pub fn symbol_address(&self) -> *mut c_void {
|
||||
self.frame.symbol_address() as *mut c_void
|
||||
}
|
||||
|
||||
/// Same as `Frame::module_base_address`
|
||||
///
|
||||
/// # Required features
|
||||
///
|
||||
/// This function requires the `std` feature of the `backtrace` crate to be
|
||||
/// enabled, and the `std` feature is enabled by default.
|
||||
pub fn module_base_address(&self) -> Option<*mut c_void> {
|
||||
self.frame
|
||||
.module_base_address()
|
||||
.map(|addr| addr as *mut c_void)
|
||||
}
|
||||
|
||||
/// Returns the list of symbols that this frame corresponds to.
|
||||
///
|
||||
/// Normally there is only one symbol per frame, but sometimes if a number
|
||||
/// of functions are inlined into one frame then multiple symbols will be
|
||||
/// returned. The first symbol listed is the "innermost function", whereas
|
||||
/// the last symbol is the outermost (last caller).
|
||||
///
|
||||
/// Note that if this frame came from an unresolved backtrace then this will
|
||||
/// return an empty list.
|
||||
///
|
||||
/// # Required features
|
||||
///
|
||||
/// This function requires the `std` feature of the `backtrace` crate to be
|
||||
/// enabled, and the `std` feature is enabled by default.
|
||||
pub fn symbols(&self) -> &[BacktraceSymbol] {
|
||||
self.symbols.as_ref().map(|s| &s[..]).unwrap_or(&[])
|
||||
}
|
||||
}
|
||||
|
||||
impl BacktraceSymbol {
|
||||
/// Same as `Symbol::name`
|
||||
///
|
||||
/// # Required features
|
||||
///
|
||||
/// This function requires the `std` feature of the `backtrace` crate to be
|
||||
/// enabled, and the `std` feature is enabled by default.
|
||||
pub fn name(&self) -> Option<SymbolName<'_>> {
|
||||
self.name.as_ref().map(|s| SymbolName::new(s))
|
||||
}
|
||||
|
||||
/// Same as `Symbol::addr`
|
||||
///
|
||||
/// # Required features
|
||||
///
|
||||
/// This function requires the `std` feature of the `backtrace` crate to be
|
||||
/// enabled, and the `std` feature is enabled by default.
|
||||
pub fn addr(&self) -> Option<*mut c_void> {
|
||||
self.addr.map(|s| s as *mut c_void)
|
||||
}
|
||||
|
||||
/// Same as `Symbol::filename`
|
||||
///
|
||||
/// # Required features
|
||||
///
|
||||
/// This function requires the `std` feature of the `backtrace` crate to be
|
||||
/// enabled, and the `std` feature is enabled by default.
|
||||
pub fn filename(&self) -> Option<&Path> {
|
||||
self.filename.as_ref().map(|p| &**p)
|
||||
}
|
||||
|
||||
/// Same as `Symbol::lineno`
|
||||
///
|
||||
/// # Required features
|
||||
///
|
||||
/// This function requires the `std` feature of the `backtrace` crate to be
|
||||
/// enabled, and the `std` feature is enabled by default.
|
||||
pub fn lineno(&self) -> Option<u32> {
|
||||
self.lineno
|
||||
}
|
||||
|
||||
/// Same as `Symbol::colno`
|
||||
///
|
||||
/// # Required features
|
||||
///
|
||||
/// This function requires the `std` feature of the `backtrace` crate to be
|
||||
/// enabled, and the `std` feature is enabled by default.
|
||||
pub fn colno(&self) -> Option<u32> {
|
||||
self.colno
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Backtrace {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let full = fmt.alternate();
|
||||
let (frames, style) = if full {
|
||||
(&self.frames[..], PrintFmt::Full)
|
||||
} else {
|
||||
(&self.frames[self.actual_start_index..], PrintFmt::Short)
|
||||
};
|
||||
|
||||
// When printing paths we try to strip the cwd if it exists, otherwise
|
||||
// we just print the path as-is. Note that we also only do this for the
|
||||
// short format, because if it's full we presumably want to print
|
||||
// everything.
|
||||
let cwd = std::env::current_dir();
|
||||
let mut print_path =
|
||||
move |fmt: &mut fmt::Formatter<'_>, path: crate::BytesOrWideString<'_>| {
|
||||
let path = path.into_path_buf();
|
||||
if !full {
|
||||
if let Ok(cwd) = &cwd {
|
||||
if let Ok(suffix) = path.strip_prefix(cwd) {
|
||||
return fmt::Display::fmt(&suffix.display(), fmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt::Display::fmt(&path.display(), fmt)
|
||||
};
|
||||
|
||||
let mut f = BacktraceFmt::new(fmt, style, &mut print_path);
|
||||
f.add_context()?;
|
||||
for frame in frames {
|
||||
f.frame().backtrace_frame(frame)?;
|
||||
}
|
||||
f.finish()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Backtrace {
|
||||
fn default() -> Backtrace {
|
||||
Backtrace::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for BacktraceFrame {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt.debug_struct("BacktraceFrame")
|
||||
.field("ip", &self.ip())
|
||||
.field("symbol_address", &self.symbol_address())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for BacktraceSymbol {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt.debug_struct("BacktraceSymbol")
|
||||
.field("name", &self.name())
|
||||
.field("addr", &self.addr())
|
||||
.field("filename", &self.filename())
|
||||
.field("lineno", &self.lineno())
|
||||
.field("colno", &self.colno())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serialize-rustc")]
|
||||
mod rustc_serialize_impls {
|
||||
use super::*;
|
||||
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
|
||||
|
||||
#[derive(RustcEncodable, RustcDecodable)]
|
||||
struct SerializedFrame {
|
||||
ip: usize,
|
||||
symbol_address: usize,
|
||||
module_base_address: Option<usize>,
|
||||
symbols: Option<Vec<BacktraceSymbol>>,
|
||||
}
|
||||
|
||||
impl Decodable for BacktraceFrame {
|
||||
fn decode<D>(d: &mut D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Decoder,
|
||||
{
|
||||
let frame: SerializedFrame = SerializedFrame::decode(d)?;
|
||||
Ok(BacktraceFrame {
|
||||
frame: Frame::Deserialized {
|
||||
ip: frame.ip,
|
||||
symbol_address: frame.symbol_address,
|
||||
module_base_address: frame.module_base_address,
|
||||
},
|
||||
symbols: frame.symbols,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Encodable for BacktraceFrame {
|
||||
fn encode<E>(&self, e: &mut E) -> Result<(), E::Error>
|
||||
where
|
||||
E: Encoder,
|
||||
{
|
||||
let BacktraceFrame { frame, symbols } = self;
|
||||
SerializedFrame {
|
||||
ip: frame.ip() as usize,
|
||||
symbol_address: frame.symbol_address() as usize,
|
||||
module_base_address: frame.module_base_address().map(|addr| addr as usize),
|
||||
symbols: symbols.clone(),
|
||||
}
|
||||
.encode(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
mod serde_impls {
|
||||
use super::*;
|
||||
use serde::de::Deserializer;
|
||||
use serde::ser::Serializer;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct SerializedFrame {
|
||||
ip: usize,
|
||||
symbol_address: usize,
|
||||
module_base_address: Option<usize>,
|
||||
symbols: Option<Vec<BacktraceSymbol>>,
|
||||
}
|
||||
|
||||
impl Serialize for BacktraceFrame {
|
||||
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let BacktraceFrame { frame, symbols } = self;
|
||||
SerializedFrame {
|
||||
ip: frame.ip() as usize,
|
||||
symbol_address: frame.symbol_address() as usize,
|
||||
module_base_address: frame.module_base_address().map(|addr| addr as usize),
|
||||
symbols: symbols.clone(),
|
||||
}
|
||||
.serialize(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Deserialize<'a> for BacktraceFrame {
|
||||
fn deserialize<D>(d: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'a>,
|
||||
{
|
||||
let frame: SerializedFrame = SerializedFrame::deserialize(d)?;
|
||||
Ok(BacktraceFrame {
|
||||
frame: Frame::Deserialized {
|
||||
ip: frame.ip,
|
||||
symbol_address: frame.symbol_address,
|
||||
module_base_address: frame.module_base_address,
|
||||
},
|
||||
symbols: frame.symbols,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_frame_conversion() {
|
||||
let mut frames = vec![];
|
||||
crate::trace(|frame| {
|
||||
let converted = BacktraceFrame::from(frame.clone());
|
||||
frames.push(converted);
|
||||
true
|
||||
});
|
||||
|
||||
let mut manual = Backtrace::from(frames);
|
||||
manual.resolve();
|
||||
let frames = manual.frames();
|
||||
|
||||
for frame in frames {
|
||||
println!("{:?}", frame.ip());
|
||||
println!("{:?}", frame.symbol_address());
|
||||
println!("{:?}", frame.module_base_address());
|
||||
println!("{:?}", frame.symbols());
|
||||
}
|
||||
}
|
||||
}
|
||||
365
.gear/predownloaded-development/vendor/backtrace/src/dbghelp.rs
vendored
Normal file
365
.gear/predownloaded-development/vendor/backtrace/src/dbghelp.rs
vendored
Normal file
|
|
@ -0,0 +1,365 @@
|
|||
//! A module to assist in managing dbghelp bindings on Windows
|
||||
//!
|
||||
//! Backtraces on Windows (at least for MSVC) are largely powered through
|
||||
//! `dbghelp.dll` and the various functions that it contains. These functions
|
||||
//! are currently loaded *dynamically* rather than linking to `dbghelp.dll`
|
||||
//! statically. This is currently done by the standard library (and is in theory
|
||||
//! required there), but is an effort to help reduce the static dll dependencies
|
||||
//! of a library since backtraces are typically pretty optional. That being
|
||||
//! said, `dbghelp.dll` almost always successfully loads on Windows.
|
||||
//!
|
||||
//! Note though that since we're loading all this support dynamically we can't
|
||||
//! actually use the raw definitions in `winapi`, but rather we need to define
|
||||
//! the function pointer types ourselves and use that. We don't really want to
|
||||
//! be in the business of duplicating winapi, so we have a Cargo feature
|
||||
//! `verify-winapi` which asserts that all bindings match those in winapi and
|
||||
//! this feature is enabled on CI.
|
||||
//!
|
||||
//! Finally, you'll note here that the dll for `dbghelp.dll` is never unloaded,
|
||||
//! and that's currently intentional. The thinking is that we can globally cache
|
||||
//! it and use it between calls to the API, avoiding expensive loads/unloads. If
|
||||
//! this is a problem for leak detectors or something like that we can cross the
|
||||
//! bridge when we get there.
|
||||
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use super::windows::*;
|
||||
use core::mem;
|
||||
use core::ptr;
|
||||
|
||||
// Work around `SymGetOptions` and `SymSetOptions` not being present in winapi
|
||||
// itself. Otherwise this is only used when we're double-checking types against
|
||||
// winapi.
|
||||
#[cfg(feature = "verify-winapi")]
|
||||
mod dbghelp {
|
||||
use crate::windows::*;
|
||||
pub use winapi::um::dbghelp::{
|
||||
StackWalk64, StackWalkEx, SymCleanup, SymFromAddrW, SymFunctionTableAccess64,
|
||||
SymGetLineFromAddrW64, SymGetModuleBase64, SymGetOptions, SymInitializeW, SymSetOptions,
|
||||
};
|
||||
|
||||
extern "system" {
|
||||
// Not defined in winapi yet
|
||||
pub fn SymFromInlineContextW(
|
||||
hProcess: HANDLE,
|
||||
Address: DWORD64,
|
||||
InlineContext: ULONG,
|
||||
Displacement: PDWORD64,
|
||||
Symbol: PSYMBOL_INFOW,
|
||||
) -> BOOL;
|
||||
pub fn SymGetLineFromInlineContextW(
|
||||
hProcess: HANDLE,
|
||||
dwAddr: DWORD64,
|
||||
InlineContext: ULONG,
|
||||
qwModuleBaseAddress: DWORD64,
|
||||
pdwDisplacement: PDWORD,
|
||||
Line: PIMAGEHLP_LINEW64,
|
||||
) -> BOOL;
|
||||
}
|
||||
|
||||
pub fn assert_equal_types<T>(a: T, _b: T) -> T {
|
||||
a
|
||||
}
|
||||
}
|
||||
|
||||
// This macro is used to define a `Dbghelp` structure which internally contains
|
||||
// all the function pointers that we might load.
|
||||
macro_rules! dbghelp {
|
||||
(extern "system" {
|
||||
$(fn $name:ident($($arg:ident: $argty:ty),*) -> $ret: ty;)*
|
||||
}) => (
|
||||
pub struct Dbghelp {
|
||||
/// The loaded DLL for `dbghelp.dll`
|
||||
dll: HMODULE,
|
||||
|
||||
// Each function pointer for each function we might use
|
||||
$($name: usize,)*
|
||||
}
|
||||
|
||||
static mut DBGHELP: Dbghelp = Dbghelp {
|
||||
// Initially we haven't loaded the DLL
|
||||
dll: 0 as *mut _,
|
||||
// Initially all functions are set to zero to say they need to be
|
||||
// dynamically loaded.
|
||||
$($name: 0,)*
|
||||
};
|
||||
|
||||
// Convenience typedef for each function type.
|
||||
$(pub type $name = unsafe extern "system" fn($($argty),*) -> $ret;)*
|
||||
|
||||
impl Dbghelp {
|
||||
/// Attempts to open `dbghelp.dll`. Returns success if it works or
|
||||
/// error if `LoadLibraryW` fails.
|
||||
///
|
||||
/// Panics if library is already loaded.
|
||||
fn ensure_open(&mut self) -> Result<(), ()> {
|
||||
if !self.dll.is_null() {
|
||||
return Ok(())
|
||||
}
|
||||
let lib = b"dbghelp.dll\0";
|
||||
unsafe {
|
||||
self.dll = LoadLibraryA(lib.as_ptr() as *const i8);
|
||||
if self.dll.is_null() {
|
||||
Err(())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Function for each method we'd like to use. When called it will
|
||||
// either read the cached function pointer or load it and return the
|
||||
// loaded value. Loads are asserted to succeed.
|
||||
$(pub fn $name(&mut self) -> Option<$name> {
|
||||
unsafe {
|
||||
if self.$name == 0 {
|
||||
let name = concat!(stringify!($name), "\0");
|
||||
self.$name = self.symbol(name.as_bytes())?;
|
||||
}
|
||||
let ret = mem::transmute::<usize, $name>(self.$name);
|
||||
#[cfg(feature = "verify-winapi")]
|
||||
dbghelp::assert_equal_types(ret, dbghelp::$name);
|
||||
Some(ret)
|
||||
}
|
||||
})*
|
||||
|
||||
fn symbol(&self, symbol: &[u8]) -> Option<usize> {
|
||||
unsafe {
|
||||
match GetProcAddress(self.dll, symbol.as_ptr() as *const _) as usize {
|
||||
0 => None,
|
||||
n => Some(n),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convenience proxy to use the cleanup locks to reference dbghelp
|
||||
// functions.
|
||||
#[allow(dead_code)]
|
||||
impl Init {
|
||||
$(pub fn $name(&self) -> $name {
|
||||
unsafe {
|
||||
DBGHELP.$name().unwrap()
|
||||
}
|
||||
})*
|
||||
|
||||
pub fn dbghelp(&self) -> *mut Dbghelp {
|
||||
unsafe {
|
||||
&mut DBGHELP
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
const SYMOPT_DEFERRED_LOADS: DWORD = 0x00000004;
|
||||
|
||||
dbghelp! {
|
||||
extern "system" {
|
||||
fn SymGetOptions() -> DWORD;
|
||||
fn SymSetOptions(options: DWORD) -> DWORD;
|
||||
fn SymInitializeW(
|
||||
handle: HANDLE,
|
||||
path: PCWSTR,
|
||||
invade: BOOL
|
||||
) -> BOOL;
|
||||
fn SymCleanup(handle: HANDLE) -> BOOL;
|
||||
fn StackWalk64(
|
||||
MachineType: DWORD,
|
||||
hProcess: HANDLE,
|
||||
hThread: HANDLE,
|
||||
StackFrame: LPSTACKFRAME64,
|
||||
ContextRecord: PVOID,
|
||||
ReadMemoryRoutine: PREAD_PROCESS_MEMORY_ROUTINE64,
|
||||
FunctionTableAccessRoutine: PFUNCTION_TABLE_ACCESS_ROUTINE64,
|
||||
GetModuleBaseRoutine: PGET_MODULE_BASE_ROUTINE64,
|
||||
TranslateAddress: PTRANSLATE_ADDRESS_ROUTINE64
|
||||
) -> BOOL;
|
||||
fn SymFunctionTableAccess64(
|
||||
hProcess: HANDLE,
|
||||
AddrBase: DWORD64
|
||||
) -> PVOID;
|
||||
fn SymGetModuleBase64(
|
||||
hProcess: HANDLE,
|
||||
AddrBase: DWORD64
|
||||
) -> DWORD64;
|
||||
fn SymFromAddrW(
|
||||
hProcess: HANDLE,
|
||||
Address: DWORD64,
|
||||
Displacement: PDWORD64,
|
||||
Symbol: PSYMBOL_INFOW
|
||||
) -> BOOL;
|
||||
fn SymGetLineFromAddrW64(
|
||||
hProcess: HANDLE,
|
||||
dwAddr: DWORD64,
|
||||
pdwDisplacement: PDWORD,
|
||||
Line: PIMAGEHLP_LINEW64
|
||||
) -> BOOL;
|
||||
fn StackWalkEx(
|
||||
MachineType: DWORD,
|
||||
hProcess: HANDLE,
|
||||
hThread: HANDLE,
|
||||
StackFrame: LPSTACKFRAME_EX,
|
||||
ContextRecord: PVOID,
|
||||
ReadMemoryRoutine: PREAD_PROCESS_MEMORY_ROUTINE64,
|
||||
FunctionTableAccessRoutine: PFUNCTION_TABLE_ACCESS_ROUTINE64,
|
||||
GetModuleBaseRoutine: PGET_MODULE_BASE_ROUTINE64,
|
||||
TranslateAddress: PTRANSLATE_ADDRESS_ROUTINE64,
|
||||
Flags: DWORD
|
||||
) -> BOOL;
|
||||
fn SymFromInlineContextW(
|
||||
hProcess: HANDLE,
|
||||
Address: DWORD64,
|
||||
InlineContext: ULONG,
|
||||
Displacement: PDWORD64,
|
||||
Symbol: PSYMBOL_INFOW
|
||||
) -> BOOL;
|
||||
fn SymGetLineFromInlineContextW(
|
||||
hProcess: HANDLE,
|
||||
dwAddr: DWORD64,
|
||||
InlineContext: ULONG,
|
||||
qwModuleBaseAddress: DWORD64,
|
||||
pdwDisplacement: PDWORD,
|
||||
Line: PIMAGEHLP_LINEW64
|
||||
) -> BOOL;
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Init {
|
||||
lock: HANDLE,
|
||||
}
|
||||
|
||||
/// Initialize all support necessary to access `dbghelp` API functions from this
|
||||
/// crate.
|
||||
///
|
||||
/// Note that this function is **safe**, it internally has its own
|
||||
/// synchronization. Also note that it is safe to call this function multiple
|
||||
/// times recursively.
|
||||
pub fn init() -> Result<Init, ()> {
|
||||
use core::sync::atomic::{AtomicUsize, Ordering::SeqCst};
|
||||
|
||||
// Helper function for generating a name that's unique to the process.
|
||||
fn mutex_name() -> [u8; 33] {
|
||||
let mut name: [u8; 33] = *b"Local\\RustBacktraceMutex00000000\0";
|
||||
let mut id = unsafe { GetCurrentProcessId() };
|
||||
// Quick and dirty no alloc u32 to hex.
|
||||
let mut index = name.len() - 1;
|
||||
while id > 0 {
|
||||
name[index - 1] = match (id & 0xF) as u8 {
|
||||
h @ 0..=9 => b'0' + h,
|
||||
h => b'A' + (h - 10),
|
||||
};
|
||||
id >>= 4;
|
||||
index -= 1;
|
||||
}
|
||||
name
|
||||
}
|
||||
|
||||
unsafe {
|
||||
// First thing we need to do is to synchronize this function. This can
|
||||
// be called concurrently from other threads or recursively within one
|
||||
// thread. Note that it's trickier than that though because what we're
|
||||
// using here, `dbghelp`, *also* needs to be synchronized with all other
|
||||
// callers to `dbghelp` in this process.
|
||||
//
|
||||
// Typically there aren't really that many calls to `dbghelp` within the
|
||||
// same process and we can probably safely assume that we're the only
|
||||
// ones accessing it. There is, however, one primary other user we have
|
||||
// to worry about which is ironically ourselves, but in the standard
|
||||
// library. The Rust standard library depends on this crate for
|
||||
// backtrace support, and this crate also exists on crates.io. This
|
||||
// means that if the standard library is printing a panic backtrace it
|
||||
// may race with this crate coming from crates.io, causing segfaults.
|
||||
//
|
||||
// To help solve this synchronization problem we employ a
|
||||
// Windows-specific trick here (it is, after all, a Windows-specific
|
||||
// restriction about synchronization). We create a *session-local* named
|
||||
// mutex to protect this call. The intention here is that the standard
|
||||
// library and this crate don't have to share Rust-level APIs to
|
||||
// synchronize here but can instead work behind the scenes to make sure
|
||||
// they're synchronizing with one another. That way when this function
|
||||
// is called through the standard library or through crates.io we can be
|
||||
// sure that the same mutex is being acquired.
|
||||
//
|
||||
// So all of that is to say that the first thing we do here is we
|
||||
// atomically create a `HANDLE` which is a named mutex on Windows. We
|
||||
// synchronize a bit with other threads sharing this function
|
||||
// specifically and ensure that only one handle is created per instance
|
||||
// of this function. Note that the handle is never closed once it's
|
||||
// stored in the global.
|
||||
//
|
||||
// After we've actually go the lock we simply acquire it, and our `Init`
|
||||
// handle we hand out will be responsible for dropping it eventually.
|
||||
static LOCK: AtomicUsize = AtomicUsize::new(0);
|
||||
let mut lock = LOCK.load(SeqCst);
|
||||
if lock == 0 {
|
||||
let name = mutex_name();
|
||||
lock = CreateMutexA(ptr::null_mut(), 0, name.as_ptr().cast::<i8>()) as usize;
|
||||
if lock == 0 {
|
||||
return Err(());
|
||||
}
|
||||
if let Err(other) = LOCK.compare_exchange(0, lock, SeqCst, SeqCst) {
|
||||
debug_assert!(other != 0);
|
||||
CloseHandle(lock as HANDLE);
|
||||
lock = other;
|
||||
}
|
||||
}
|
||||
debug_assert!(lock != 0);
|
||||
let lock = lock as HANDLE;
|
||||
let r = WaitForSingleObjectEx(lock, INFINITE, FALSE);
|
||||
debug_assert_eq!(r, 0);
|
||||
let ret = Init { lock };
|
||||
|
||||
// Ok, phew! Now that we're all safely synchronized, let's actually
|
||||
// start processing everything. First up we need to ensure that
|
||||
// `dbghelp.dll` is actually loaded in this process. We do this
|
||||
// dynamically to avoid a static dependency. This has historically been
|
||||
// done to work around weird linking issues and is intended at making
|
||||
// binaries a bit more portable since this is largely just a debugging
|
||||
// utility.
|
||||
//
|
||||
// Once we've opened `dbghelp.dll` we need to call some initialization
|
||||
// functions in it, and that's detailed more below. We only do this
|
||||
// once, though, so we've got a global boolean indicating whether we're
|
||||
// done yet or not.
|
||||
DBGHELP.ensure_open()?;
|
||||
|
||||
static mut INITIALIZED: bool = false;
|
||||
if INITIALIZED {
|
||||
return Ok(ret);
|
||||
}
|
||||
|
||||
let orig = DBGHELP.SymGetOptions().unwrap()();
|
||||
|
||||
// Ensure that the `SYMOPT_DEFERRED_LOADS` flag is set, because
|
||||
// according to MSVC's own docs about this: "This is the fastest, most
|
||||
// efficient way to use the symbol handler.", so let's do that!
|
||||
DBGHELP.SymSetOptions().unwrap()(orig | SYMOPT_DEFERRED_LOADS);
|
||||
|
||||
// Actually initialize symbols with MSVC. Note that this can fail, but we
|
||||
// ignore it. There's not a ton of prior art for this per se, but LLVM
|
||||
// internally seems to ignore the return value here and one of the
|
||||
// sanitizer libraries in LLVM prints a scary warning if this fails but
|
||||
// basically ignores it in the long run.
|
||||
//
|
||||
// One case this comes up a lot for Rust is that the standard library and
|
||||
// this crate on crates.io both want to compete for `SymInitializeW`. The
|
||||
// standard library historically wanted to initialize then cleanup most of
|
||||
// the time, but now that it's using this crate it means that someone will
|
||||
// get to initialization first and the other will pick up that
|
||||
// initialization.
|
||||
DBGHELP.SymInitializeW().unwrap()(GetCurrentProcess(), ptr::null_mut(), TRUE);
|
||||
INITIALIZED = true;
|
||||
Ok(ret)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Init {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
let r = ReleaseMutex(self.lock);
|
||||
debug_assert!(r != 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
192
.gear/predownloaded-development/vendor/backtrace/src/lib.rs
vendored
Normal file
192
.gear/predownloaded-development/vendor/backtrace/src/lib.rs
vendored
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
//! A library for acquiring a backtrace at runtime
|
||||
//!
|
||||
//! This library is meant to supplement the `RUST_BACKTRACE=1` support of the
|
||||
//! standard library by allowing an acquisition of a backtrace at runtime
|
||||
//! programmatically. The backtraces generated by this library do not need to be
|
||||
//! parsed, for example, and expose the functionality of multiple backend
|
||||
//! implementations.
|
||||
//!
|
||||
//! # Usage
|
||||
//!
|
||||
//! First, add this to your Cargo.toml
|
||||
//!
|
||||
//! ```toml
|
||||
//! [dependencies]
|
||||
//! backtrace = "0.3"
|
||||
//! ```
|
||||
//!
|
||||
//! Next:
|
||||
//!
|
||||
//! ```
|
||||
//! fn main() {
|
||||
//! # // Unsafe here so test passes on no_std.
|
||||
//! # #[cfg(feature = "std")] {
|
||||
//! backtrace::trace(|frame| {
|
||||
//! let ip = frame.ip();
|
||||
//! let symbol_address = frame.symbol_address();
|
||||
//!
|
||||
//! // Resolve this instruction pointer to a symbol name
|
||||
//! backtrace::resolve_frame(frame, |symbol| {
|
||||
//! if let Some(name) = symbol.name() {
|
||||
//! // ...
|
||||
//! }
|
||||
//! if let Some(filename) = symbol.filename() {
|
||||
//! // ...
|
||||
//! }
|
||||
//! });
|
||||
//!
|
||||
//! true // keep going to the next frame
|
||||
//! });
|
||||
//! }
|
||||
//! # }
|
||||
//! ```
|
||||
//!
|
||||
//! # Backtrace accuracy
|
||||
//!
|
||||
//! This crate implements best-effort attempts to get the native backtrace. This
|
||||
//! is not always guaranteed to work, and some platforms don't return any
|
||||
//! backtrace at all. If your application requires accurate backtraces then it's
|
||||
//! recommended to closely evaluate this crate to see whether it's suitable
|
||||
//! for your use case on your target platforms.
|
||||
//!
|
||||
//! Even on supported platforms, there's a number of reasons that backtraces may
|
||||
//! be less-than-accurate, including but not limited to:
|
||||
//!
|
||||
//! * Unwind information may not be available. This crate primarily implements
|
||||
//! backtraces by unwinding the stack, but not all functions may have
|
||||
//! unwinding information (e.g. DWARF unwinding information).
|
||||
//!
|
||||
//! * Rust code may be compiled without unwinding information for some
|
||||
//! functions. This can also happen for Rust code compiled with
|
||||
//! `-Cpanic=abort`. You can remedy this, however, with
|
||||
//! `-Cforce-unwind-tables` as a compiler option.
|
||||
//!
|
||||
//! * Unwind information may be inaccurate or corrupt. In the worst case
|
||||
//! inaccurate unwind information can lead this library to segfault. In the
|
||||
//! best case inaccurate information will result in a truncated stack trace.
|
||||
//!
|
||||
//! * Backtraces may not report filenames/line numbers correctly due to missing
|
||||
//! or corrupt debug information. This won't lead to segfaults unlike corrupt
|
||||
//! unwinding information, but missing or malformed debug information will
|
||||
//! mean that filenames and line numbers will not be available. This may be
|
||||
//! because debug information wasn't generated by the compiler, or it's just
|
||||
//! missing on the filesystem.
|
||||
//!
|
||||
//! * Not all platforms are supported. For example there's no way to get a
|
||||
//! backtrace on WebAssembly at the moment.
|
||||
//!
|
||||
//! * Crate features may be disabled. Currently this crate supports using Gimli
|
||||
//! libbacktrace on non-Windows platforms for reading debuginfo for
|
||||
//! backtraces. If both crate features are disabled, however, then these
|
||||
//! platforms will generate a backtrace but be unable to generate symbols for
|
||||
//! it.
|
||||
//!
|
||||
//! In most standard workflows for most standard platforms you generally don't
|
||||
//! need to worry about these caveats. We'll try to fix ones where we can over
|
||||
//! time, but otherwise it's important to be aware of the limitations of
|
||||
//! unwinding-based backtraces!
|
||||
|
||||
#![deny(missing_docs)]
|
||||
#![no_std]
|
||||
#![cfg_attr(
|
||||
all(feature = "std", target_env = "sgx", target_vendor = "fortanix"),
|
||||
feature(sgx_platform)
|
||||
)]
|
||||
#![warn(rust_2018_idioms)]
|
||||
// When we're building as part of libstd, silence all warnings since they're
|
||||
// irrelevant as this crate is developed out-of-tree.
|
||||
#![cfg_attr(backtrace_in_libstd, allow(warnings))]
|
||||
#![cfg_attr(not(feature = "std"), allow(dead_code))]
|
||||
// We know this is deprecated, it's only here for back-compat reasons.
|
||||
#![cfg_attr(feature = "rustc-serialize", allow(deprecated))]
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[macro_use]
|
||||
extern crate std;
|
||||
|
||||
// This is only used for gimli right now, which is only used on some platforms, and miri
|
||||
// so don't worry if it's unused in other configurations.
|
||||
#[allow(unused_extern_crates)]
|
||||
extern crate alloc;
|
||||
|
||||
pub use self::backtrace::{trace_unsynchronized, Frame};
|
||||
mod backtrace;
|
||||
|
||||
pub use self::symbolize::resolve_frame_unsynchronized;
|
||||
pub use self::symbolize::{resolve_unsynchronized, Symbol, SymbolName};
|
||||
mod symbolize;
|
||||
|
||||
pub use self::types::BytesOrWideString;
|
||||
mod types;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub use self::symbolize::clear_symbol_cache;
|
||||
|
||||
mod print;
|
||||
pub use print::{BacktraceFmt, BacktraceFrameFmt, PrintFmt};
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "std")] {
|
||||
pub use self::backtrace::trace;
|
||||
pub use self::symbolize::{resolve, resolve_frame};
|
||||
pub use self::capture::{Backtrace, BacktraceFrame, BacktraceSymbol};
|
||||
mod capture;
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
struct Bomb {
|
||||
enabled: bool,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl Drop for Bomb {
|
||||
fn drop(&mut self) {
|
||||
if self.enabled {
|
||||
panic!("cannot panic during the backtrace function");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[cfg(feature = "std")]
|
||||
mod lock {
|
||||
use std::boxed::Box;
|
||||
use std::cell::Cell;
|
||||
use std::sync::{Mutex, MutexGuard, Once};
|
||||
|
||||
pub struct LockGuard(Option<MutexGuard<'static, ()>>);
|
||||
|
||||
static mut LOCK: *mut Mutex<()> = 0 as *mut _;
|
||||
static INIT: Once = Once::new();
|
||||
thread_local!(static LOCK_HELD: Cell<bool> = Cell::new(false));
|
||||
|
||||
impl Drop for LockGuard {
|
||||
fn drop(&mut self) {
|
||||
if self.0.is_some() {
|
||||
LOCK_HELD.with(|slot| {
|
||||
assert!(slot.get());
|
||||
slot.set(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lock() -> LockGuard {
|
||||
if LOCK_HELD.with(|l| l.get()) {
|
||||
return LockGuard(None);
|
||||
}
|
||||
LOCK_HELD.with(|s| s.set(true));
|
||||
unsafe {
|
||||
INIT.call_once(|| {
|
||||
LOCK = Box::into_raw(Box::new(Mutex::new(())));
|
||||
});
|
||||
LockGuard(Some((*LOCK).lock().unwrap()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(windows, not(target_vendor = "uwp")))]
|
||||
mod dbghelp;
|
||||
#[cfg(windows)]
|
||||
mod windows;
|
||||
319
.gear/predownloaded-development/vendor/backtrace/src/print.rs
vendored
Normal file
319
.gear/predownloaded-development/vendor/backtrace/src/print.rs
vendored
Normal file
|
|
@ -0,0 +1,319 @@
|
|||
#[cfg(feature = "std")]
|
||||
use super::{BacktraceFrame, BacktraceSymbol};
|
||||
use super::{BytesOrWideString, Frame, SymbolName};
|
||||
use core::ffi::c_void;
|
||||
use core::fmt;
|
||||
|
||||
const HEX_WIDTH: usize = 2 + 2 * core::mem::size_of::<usize>();
|
||||
|
||||
#[cfg(target_os = "fuchsia")]
|
||||
mod fuchsia;
|
||||
|
||||
/// A formatter for backtraces.
|
||||
///
|
||||
/// This type can be used to print a backtrace regardless of where the backtrace
|
||||
/// itself comes from. If you have a `Backtrace` type then its `Debug`
|
||||
/// implementation already uses this printing format.
|
||||
pub struct BacktraceFmt<'a, 'b> {
|
||||
fmt: &'a mut fmt::Formatter<'b>,
|
||||
frame_index: usize,
|
||||
format: PrintFmt,
|
||||
print_path:
|
||||
&'a mut (dyn FnMut(&mut fmt::Formatter<'_>, BytesOrWideString<'_>) -> fmt::Result + 'b),
|
||||
}
|
||||
|
||||
/// The styles of printing that we can print
|
||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
pub enum PrintFmt {
|
||||
/// Prints a terser backtrace which ideally only contains relevant information
|
||||
Short,
|
||||
/// Prints a backtrace that contains all possible information
|
||||
Full,
|
||||
#[doc(hidden)]
|
||||
__Nonexhaustive,
|
||||
}
|
||||
|
||||
impl<'a, 'b> BacktraceFmt<'a, 'b> {
|
||||
/// Create a new `BacktraceFmt` which will write output to the provided
|
||||
/// `fmt`.
|
||||
///
|
||||
/// The `format` argument will control the style in which the backtrace is
|
||||
/// printed, and the `print_path` argument will be used to print the
|
||||
/// `BytesOrWideString` instances of filenames. This type itself doesn't do
|
||||
/// any printing of filenames, but this callback is required to do so.
|
||||
pub fn new(
|
||||
fmt: &'a mut fmt::Formatter<'b>,
|
||||
format: PrintFmt,
|
||||
print_path: &'a mut (dyn FnMut(&mut fmt::Formatter<'_>, BytesOrWideString<'_>) -> fmt::Result
|
||||
+ 'b),
|
||||
) -> Self {
|
||||
BacktraceFmt {
|
||||
fmt,
|
||||
frame_index: 0,
|
||||
format,
|
||||
print_path,
|
||||
}
|
||||
}
|
||||
|
||||
/// Prints a preamble for the backtrace about to be printed.
|
||||
///
|
||||
/// This is required on some platforms for backtraces to be fully
|
||||
/// symbolicated later, and otherwise this should just be the first method
|
||||
/// you call after creating a `BacktraceFmt`.
|
||||
pub fn add_context(&mut self) -> fmt::Result {
|
||||
#[cfg(target_os = "fuchsia")]
|
||||
fuchsia::print_dso_context(self.fmt)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Adds a frame to the backtrace output.
|
||||
///
|
||||
/// This commit returns an RAII instance of a `BacktraceFrameFmt` which can be used
|
||||
/// to actually print a frame, and on destruction it will increment the
|
||||
/// frame counter.
|
||||
pub fn frame(&mut self) -> BacktraceFrameFmt<'_, 'a, 'b> {
|
||||
BacktraceFrameFmt {
|
||||
fmt: self,
|
||||
symbol_index: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Completes the backtrace output.
|
||||
///
|
||||
/// This is currently a no-op but is added for future compatibility with
|
||||
/// backtrace formats.
|
||||
pub fn finish(&mut self) -> fmt::Result {
|
||||
// Currently a no-op-- including this hook to allow for future additions.
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Inserts a message in the backtrace output.
|
||||
///
|
||||
/// This allows information to be inserted between frames,
|
||||
/// and won't increment the `frame_index` unlike the `frame`
|
||||
/// method.
|
||||
pub fn message(&mut self, msg: &str) -> fmt::Result {
|
||||
self.fmt.write_str(msg)
|
||||
}
|
||||
|
||||
/// Return the inner formatter.
|
||||
///
|
||||
/// This is used for writing custom information between frames with `write!` and `writeln!`,
|
||||
/// and won't increment the `frame_index` unlike the `frame` method.
|
||||
pub fn formatter(&mut self) -> &mut fmt::Formatter<'b> {
|
||||
self.fmt
|
||||
}
|
||||
}
|
||||
|
||||
/// A formatter for just one frame of a backtrace.
|
||||
///
|
||||
/// This type is created by the `BacktraceFmt::frame` function.
|
||||
pub struct BacktraceFrameFmt<'fmt, 'a, 'b> {
|
||||
fmt: &'fmt mut BacktraceFmt<'a, 'b>,
|
||||
symbol_index: usize,
|
||||
}
|
||||
|
||||
impl BacktraceFrameFmt<'_, '_, '_> {
|
||||
/// Prints a `BacktraceFrame` with this frame formatter.
|
||||
///
|
||||
/// This will recursively print all `BacktraceSymbol` instances within the
|
||||
/// `BacktraceFrame`.
|
||||
///
|
||||
/// # Required features
|
||||
///
|
||||
/// This function requires the `std` feature of the `backtrace` crate to be
|
||||
/// enabled, and the `std` feature is enabled by default.
|
||||
#[cfg(feature = "std")]
|
||||
pub fn backtrace_frame(&mut self, frame: &BacktraceFrame) -> fmt::Result {
|
||||
let symbols = frame.symbols();
|
||||
for symbol in symbols {
|
||||
self.backtrace_symbol(frame, symbol)?;
|
||||
}
|
||||
if symbols.is_empty() {
|
||||
self.print_raw(frame.ip(), None, None, None)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Prints a `BacktraceSymbol` within a `BacktraceFrame`.
|
||||
///
|
||||
/// # Required features
|
||||
///
|
||||
/// This function requires the `std` feature of the `backtrace` crate to be
|
||||
/// enabled, and the `std` feature is enabled by default.
|
||||
#[cfg(feature = "std")]
|
||||
pub fn backtrace_symbol(
|
||||
&mut self,
|
||||
frame: &BacktraceFrame,
|
||||
symbol: &BacktraceSymbol,
|
||||
) -> fmt::Result {
|
||||
self.print_raw_with_column(
|
||||
frame.ip(),
|
||||
symbol.name(),
|
||||
// TODO: this isn't great that we don't end up printing anything
|
||||
// with non-utf8 filenames. Thankfully almost everything is utf8 so
|
||||
// this shouldn't be too bad.
|
||||
symbol
|
||||
.filename()
|
||||
.and_then(|p| Some(BytesOrWideString::Bytes(p.to_str()?.as_bytes()))),
|
||||
symbol.lineno(),
|
||||
symbol.colno(),
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Prints a raw traced `Frame` and `Symbol`, typically from within the raw
|
||||
/// callbacks of this crate.
|
||||
pub fn symbol(&mut self, frame: &Frame, symbol: &super::Symbol) -> fmt::Result {
|
||||
self.print_raw_with_column(
|
||||
frame.ip(),
|
||||
symbol.name(),
|
||||
symbol.filename_raw(),
|
||||
symbol.lineno(),
|
||||
symbol.colno(),
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Adds a raw frame to the backtrace output.
|
||||
///
|
||||
/// This method, unlike the previous, takes the raw arguments in case
|
||||
/// they're being source from different locations. Note that this may be
|
||||
/// called multiple times for one frame.
|
||||
pub fn print_raw(
|
||||
&mut self,
|
||||
frame_ip: *mut c_void,
|
||||
symbol_name: Option<SymbolName<'_>>,
|
||||
filename: Option<BytesOrWideString<'_>>,
|
||||
lineno: Option<u32>,
|
||||
) -> fmt::Result {
|
||||
self.print_raw_with_column(frame_ip, symbol_name, filename, lineno, None)
|
||||
}
|
||||
|
||||
/// Adds a raw frame to the backtrace output, including column information.
|
||||
///
|
||||
/// This method, like the previous, takes the raw arguments in case
|
||||
/// they're being source from different locations. Note that this may be
|
||||
/// called multiple times for one frame.
|
||||
pub fn print_raw_with_column(
|
||||
&mut self,
|
||||
frame_ip: *mut c_void,
|
||||
symbol_name: Option<SymbolName<'_>>,
|
||||
filename: Option<BytesOrWideString<'_>>,
|
||||
lineno: Option<u32>,
|
||||
colno: Option<u32>,
|
||||
) -> fmt::Result {
|
||||
// Fuchsia is unable to symbolize within a process so it has a special
|
||||
// format which can be used to symbolize later. Print that instead of
|
||||
// printing addresses in our own format here.
|
||||
if cfg!(target_os = "fuchsia") {
|
||||
self.print_raw_fuchsia(frame_ip)?;
|
||||
} else {
|
||||
self.print_raw_generic(frame_ip, symbol_name, filename, lineno, colno)?;
|
||||
}
|
||||
self.symbol_index += 1;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(unused_mut)]
|
||||
fn print_raw_generic(
|
||||
&mut self,
|
||||
mut frame_ip: *mut c_void,
|
||||
symbol_name: Option<SymbolName<'_>>,
|
||||
filename: Option<BytesOrWideString<'_>>,
|
||||
lineno: Option<u32>,
|
||||
colno: Option<u32>,
|
||||
) -> fmt::Result {
|
||||
// No need to print "null" frames, it basically just means that the
|
||||
// system backtrace was a bit eager to trace back super far.
|
||||
if let PrintFmt::Short = self.fmt.format {
|
||||
if frame_ip.is_null() {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
// To reduce TCB size in Sgx enclave, we do not want to implement symbol
|
||||
// resolution functionality. Rather, we can print the offset of the
|
||||
// address here, which could be later mapped to correct function.
|
||||
#[cfg(all(feature = "std", target_env = "sgx", target_vendor = "fortanix"))]
|
||||
{
|
||||
let image_base = std::os::fortanix_sgx::mem::image_base();
|
||||
frame_ip = usize::wrapping_sub(frame_ip as usize, image_base as _) as _;
|
||||
}
|
||||
|
||||
// Print the index of the frame as well as the optional instruction
|
||||
// pointer of the frame. If we're beyond the first symbol of this frame
|
||||
// though we just print appropriate whitespace.
|
||||
if self.symbol_index == 0 {
|
||||
write!(self.fmt.fmt, "{:4}: ", self.fmt.frame_index)?;
|
||||
if let PrintFmt::Full = self.fmt.format {
|
||||
write!(self.fmt.fmt, "{:1$?} - ", frame_ip, HEX_WIDTH)?;
|
||||
}
|
||||
} else {
|
||||
write!(self.fmt.fmt, " ")?;
|
||||
if let PrintFmt::Full = self.fmt.format {
|
||||
write!(self.fmt.fmt, "{:1$}", "", HEX_WIDTH + 3)?;
|
||||
}
|
||||
}
|
||||
|
||||
// Next up write out the symbol name, using the alternate formatting for
|
||||
// more information if we're a full backtrace. Here we also handle
|
||||
// symbols which don't have a name,
|
||||
match (symbol_name, &self.fmt.format) {
|
||||
(Some(name), PrintFmt::Short) => write!(self.fmt.fmt, "{:#}", name)?,
|
||||
(Some(name), PrintFmt::Full) => write!(self.fmt.fmt, "{}", name)?,
|
||||
(None, _) | (_, PrintFmt::__Nonexhaustive) => write!(self.fmt.fmt, "<unknown>")?,
|
||||
}
|
||||
self.fmt.fmt.write_str("\n")?;
|
||||
|
||||
// And last up, print out the filename/line number if they're available.
|
||||
if let (Some(file), Some(line)) = (filename, lineno) {
|
||||
self.print_fileline(file, line, colno)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_fileline(
|
||||
&mut self,
|
||||
file: BytesOrWideString<'_>,
|
||||
line: u32,
|
||||
colno: Option<u32>,
|
||||
) -> fmt::Result {
|
||||
// Filename/line are printed on lines under the symbol name, so print
|
||||
// some appropriate whitespace to sort of right-align ourselves.
|
||||
if let PrintFmt::Full = self.fmt.format {
|
||||
write!(self.fmt.fmt, "{:1$}", "", HEX_WIDTH)?;
|
||||
}
|
||||
write!(self.fmt.fmt, " at ")?;
|
||||
|
||||
// Delegate to our internal callback to print the filename and then
|
||||
// print out the line number.
|
||||
(self.fmt.print_path)(self.fmt.fmt, file)?;
|
||||
write!(self.fmt.fmt, ":{}", line)?;
|
||||
|
||||
// Add column number, if available.
|
||||
if let Some(colno) = colno {
|
||||
write!(self.fmt.fmt, ":{}", colno)?;
|
||||
}
|
||||
|
||||
write!(self.fmt.fmt, "\n")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_raw_fuchsia(&mut self, frame_ip: *mut c_void) -> fmt::Result {
|
||||
// We only care about the first symbol of a frame
|
||||
if self.symbol_index == 0 {
|
||||
self.fmt.fmt.write_str("{{{bt:")?;
|
||||
write!(self.fmt.fmt, "{}:{:?}", self.fmt.frame_index, frame_ip)?;
|
||||
self.fmt.fmt.write_str("}}}\n")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for BacktraceFrameFmt<'_, '_, '_> {
|
||||
fn drop(&mut self) {
|
||||
self.fmt.frame_index += 1;
|
||||
}
|
||||
}
|
||||
436
.gear/predownloaded-development/vendor/backtrace/src/print/fuchsia.rs
vendored
Normal file
436
.gear/predownloaded-development/vendor/backtrace/src/print/fuchsia.rs
vendored
Normal file
|
|
@ -0,0 +1,436 @@
|
|||
use core::fmt::{self, Write};
|
||||
use core::mem::{size_of, transmute};
|
||||
use core::slice::from_raw_parts;
|
||||
use libc::c_char;
|
||||
|
||||
extern "C" {
|
||||
// dl_iterate_phdr takes a callback that will receive a dl_phdr_info pointer
|
||||
// for every DSO that has been linked into the process. dl_iterate_phdr also
|
||||
// ensures that the dynamic linker is locked from start to finish of the
|
||||
// iteration. If the callback returns a non-zero value the iteration is
|
||||
// terminated early. 'data' will be passed as the third argument to the
|
||||
// callback on each call. 'size' gives the size of the dl_phdr_info.
|
||||
#[allow(improper_ctypes)]
|
||||
fn dl_iterate_phdr(
|
||||
f: extern "C" fn(info: &dl_phdr_info, size: usize, data: &mut DsoPrinter<'_, '_>) -> i32,
|
||||
data: &mut DsoPrinter<'_, '_>,
|
||||
) -> i32;
|
||||
}
|
||||
|
||||
// We need to parse out the build ID and some basic program header data
|
||||
// which means that we need a bit of stuff from the ELF spec as well.
|
||||
|
||||
const PT_LOAD: u32 = 1;
|
||||
const PT_NOTE: u32 = 4;
|
||||
|
||||
// Now we have to replicate, bit for bit, the structure of the dl_phdr_info
|
||||
// type used by fuchsia's current dynamic linker. Chromium also has this ABI
|
||||
// boundary as well as crashpad. Eventually we'd like to move these cases to
|
||||
// use elf-search but we'd need to provide that in the SDK and that has not
|
||||
// yet been done. Thus we (and they) are stuck having to use this method
|
||||
// which incurs a tight coupling with the fuchsia libc.
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
#[repr(C)]
|
||||
struct dl_phdr_info {
|
||||
addr: *const u8,
|
||||
name: *const c_char,
|
||||
phdr: *const Elf_Phdr,
|
||||
phnum: u16,
|
||||
adds: u64,
|
||||
subs: u64,
|
||||
tls_modid: usize,
|
||||
tls_data: *const u8,
|
||||
}
|
||||
|
||||
impl dl_phdr_info {
|
||||
fn program_headers(&self) -> PhdrIter<'_> {
|
||||
PhdrIter {
|
||||
phdrs: self.phdr_slice(),
|
||||
base: self.addr,
|
||||
}
|
||||
}
|
||||
// We have no way of knowing of checking if e_phoff and e_phnum are valid.
|
||||
// libc should ensure this for us however so it's safe to form a slice here.
|
||||
fn phdr_slice(&self) -> &[Elf_Phdr] {
|
||||
unsafe { from_raw_parts(self.phdr, self.phnum as usize) }
|
||||
}
|
||||
}
|
||||
|
||||
struct PhdrIter<'a> {
|
||||
phdrs: &'a [Elf_Phdr],
|
||||
base: *const u8,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for PhdrIter<'a> {
|
||||
type Item = Phdr<'a>;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.phdrs.split_first().map(|(phdr, new_phdrs)| {
|
||||
self.phdrs = new_phdrs;
|
||||
Phdr {
|
||||
phdr,
|
||||
base: self.base,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Elf_Phdr represents a 64-bit ELF program header in the endianness of the target
|
||||
// architecture.
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Clone, Debug)]
|
||||
#[repr(C)]
|
||||
struct Elf_Phdr {
|
||||
p_type: u32,
|
||||
p_flags: u32,
|
||||
p_offset: u64,
|
||||
p_vaddr: u64,
|
||||
p_paddr: u64,
|
||||
p_filesz: u64,
|
||||
p_memsz: u64,
|
||||
p_align: u64,
|
||||
}
|
||||
|
||||
// Phdr represents a valid ELF program header and its contents.
|
||||
struct Phdr<'a> {
|
||||
phdr: &'a Elf_Phdr,
|
||||
base: *const u8,
|
||||
}
|
||||
|
||||
impl<'a> Phdr<'a> {
|
||||
// We have no way of checking if p_addr or p_memsz are valid. Fuchsia's libc
|
||||
// parses the notes first however so by virtue of being here these headers
|
||||
// must be valid. NoteIter does not require the underlying data to be valid
|
||||
// but it does require the bounds to be valid. We trust that libc has ensured
|
||||
// that this is the case for us here.
|
||||
fn notes(&self) -> NoteIter<'a> {
|
||||
unsafe {
|
||||
NoteIter::new(
|
||||
self.base.add(self.phdr.p_offset as usize),
|
||||
self.phdr.p_memsz as usize,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The note type for build IDs.
|
||||
const NT_GNU_BUILD_ID: u32 = 3;
|
||||
|
||||
// Elf_Nhdr represents an ELF note header in the endianness of the target.
|
||||
#[allow(non_camel_case_types)]
|
||||
#[repr(C)]
|
||||
struct Elf_Nhdr {
|
||||
n_namesz: u32,
|
||||
n_descsz: u32,
|
||||
n_type: u32,
|
||||
}
|
||||
|
||||
// Note represents an ELF note (header + contents). The name is left as a u8
|
||||
// slice because it is not always null terminated and rust makes it easy enough
|
||||
// to check that the bytes match eitherway.
|
||||
struct Note<'a> {
|
||||
name: &'a [u8],
|
||||
desc: &'a [u8],
|
||||
tipe: u32,
|
||||
}
|
||||
|
||||
// NoteIter lets you safely iterate over a note segment. It terminates as soon
|
||||
// as an error occurs or there are no more notes. If you iterate over invalid
|
||||
// data it will function as though no notes were found.
|
||||
struct NoteIter<'a> {
|
||||
base: &'a [u8],
|
||||
error: bool,
|
||||
}
|
||||
|
||||
impl<'a> NoteIter<'a> {
|
||||
// It is an invariant of function that the pointer and size given denote a
|
||||
// valid range of bytes that can all be read. The contents of these bytes
|
||||
// can be anything but the range must be valid for this to be safe.
|
||||
unsafe fn new(base: *const u8, size: usize) -> Self {
|
||||
NoteIter {
|
||||
base: from_raw_parts(base, size),
|
||||
error: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// align_to aligns 'x' to 'to'-byte alignment assuming 'to' is a power of 2.
|
||||
// This follows a standard pattern in C/C++ ELF parsing code where
|
||||
// (x + to - 1) & -to is used. Rust does not let you negate usize so I use
|
||||
// 2's-complement conversion to recreate that.
|
||||
fn align_to(x: usize, to: usize) -> usize {
|
||||
(x + to - 1) & (!to + 1)
|
||||
}
|
||||
|
||||
// take_bytes_align4 consumes num bytes from the slice (if present) and
|
||||
// additionally ensures that the final slice is properlly aligned. If an
|
||||
// either the number of bytes requested is too large or the slice can't be
|
||||
// realigned afterwards due to not enough remaining bytes existing, None is
|
||||
// returned and the slice is not modified.
|
||||
fn take_bytes_align4<'a>(num: usize, bytes: &mut &'a [u8]) -> Option<&'a [u8]> {
|
||||
if bytes.len() < align_to(num, 4) {
|
||||
return None;
|
||||
}
|
||||
let (out, bytes_new) = bytes.split_at(num);
|
||||
*bytes = &bytes_new[align_to(num, 4) - num..];
|
||||
Some(out)
|
||||
}
|
||||
|
||||
// This function has no real invariants the caller must uphold other than
|
||||
// perhaps that 'bytes' should be aligned for performance (and on some
|
||||
// architectures correctness). The values in the Elf_Nhdr fields might
|
||||
// be nonsense but this function ensures no such thing.
|
||||
fn take_nhdr<'a>(bytes: &mut &'a [u8]) -> Option<&'a Elf_Nhdr> {
|
||||
if size_of::<Elf_Nhdr>() > bytes.len() {
|
||||
return None;
|
||||
}
|
||||
// This is safe as long as there is enough space and we just confirmed that
|
||||
// in the if statement above so this should not be unsafe.
|
||||
let out = unsafe { transmute::<*const u8, &'a Elf_Nhdr>(bytes.as_ptr()) };
|
||||
// Note that sice_of::<Elf_Nhdr>() is always 4-byte aligned.
|
||||
*bytes = &bytes[size_of::<Elf_Nhdr>()..];
|
||||
Some(out)
|
||||
}
|
||||
|
||||
impl<'a> Iterator for NoteIter<'a> {
|
||||
type Item = Note<'a>;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
// Check if we've reached the end.
|
||||
if self.base.len() == 0 || self.error {
|
||||
return None;
|
||||
}
|
||||
// We transmute out an nhdr but we carefully consider the resulting
|
||||
// struct. We don't trust the namesz or descsz and we make no unsafe
|
||||
// decisions based on the type. So even if we get out complete garbage
|
||||
// we should still be safe.
|
||||
let nhdr = take_nhdr(&mut self.base)?;
|
||||
let name = take_bytes_align4(nhdr.n_namesz as usize, &mut self.base)?;
|
||||
let desc = take_bytes_align4(nhdr.n_descsz as usize, &mut self.base)?;
|
||||
Some(Note {
|
||||
name: name,
|
||||
desc: desc,
|
||||
tipe: nhdr.n_type,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
struct Perm(u32);
|
||||
|
||||
/// Indicates that a segment is executable.
|
||||
const PERM_X: u32 = 0b00000001;
|
||||
/// Indicates that a segment is writable.
|
||||
const PERM_W: u32 = 0b00000010;
|
||||
/// Indicates that a segment is readable.
|
||||
const PERM_R: u32 = 0b00000100;
|
||||
|
||||
impl core::fmt::Display for Perm {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let v = self.0;
|
||||
if v & PERM_R != 0 {
|
||||
f.write_char('r')?
|
||||
}
|
||||
if v & PERM_W != 0 {
|
||||
f.write_char('w')?
|
||||
}
|
||||
if v & PERM_X != 0 {
|
||||
f.write_char('x')?
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents an ELF segment at runtime.
|
||||
struct Segment {
|
||||
/// Gives the runtime virtual address of this segment's contents.
|
||||
addr: usize,
|
||||
/// Gives the memory size of this segment's contents.
|
||||
size: usize,
|
||||
/// Gives the module virtual address of this segment with the ELF file.
|
||||
mod_rel_addr: usize,
|
||||
/// Gives the permissions found in the ELF file. These permissions are not
|
||||
/// necessarily the permissions present at runtime however.
|
||||
flags: Perm,
|
||||
}
|
||||
|
||||
/// Lets one iterate over Segments from a DSO.
|
||||
struct SegmentIter<'a> {
|
||||
phdrs: &'a [Elf_Phdr],
|
||||
base: usize,
|
||||
}
|
||||
|
||||
impl Iterator for SegmentIter<'_> {
|
||||
type Item = Segment;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.phdrs.split_first().and_then(|(phdr, new_phdrs)| {
|
||||
self.phdrs = new_phdrs;
|
||||
if phdr.p_type != PT_LOAD {
|
||||
self.next()
|
||||
} else {
|
||||
Some(Segment {
|
||||
addr: phdr.p_vaddr as usize + self.base,
|
||||
size: phdr.p_memsz as usize,
|
||||
mod_rel_addr: phdr.p_vaddr as usize,
|
||||
flags: Perm(phdr.p_flags),
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents an ELF DSO (Dynamic Shared Object). This type references
|
||||
/// the data stored in the actual DSO rather than making its own copy.
|
||||
struct Dso<'a> {
|
||||
/// The dynamic linker always gives us a name, even if the name is empty.
|
||||
/// In the case of the main executable this name will be empty. In the case
|
||||
/// of a shared object it will be the soname (see DT_SONAME).
|
||||
name: &'a str,
|
||||
/// On Fuchsia virtually all binaries have build IDs but this is not a strict
|
||||
/// requirement. There's no way to match up DSO information with a real ELF
|
||||
/// file afterwards if there is no build_id so we require that every DSO
|
||||
/// have one here. DSO's without a build_id are ignored.
|
||||
build_id: &'a [u8],
|
||||
|
||||
base: usize,
|
||||
phdrs: &'a [Elf_Phdr],
|
||||
}
|
||||
|
||||
impl Dso<'_> {
|
||||
/// Returns an iterator over Segments in this DSO.
|
||||
fn segments(&self) -> SegmentIter<'_> {
|
||||
SegmentIter {
|
||||
phdrs: self.phdrs.as_ref(),
|
||||
base: self.base,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct HexSlice<'a> {
|
||||
bytes: &'a [u8],
|
||||
}
|
||||
|
||||
impl fmt::Display for HexSlice<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
for byte in self.bytes {
|
||||
write!(f, "{:02x}", byte)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn get_build_id<'a>(info: &'a dl_phdr_info) -> Option<&'a [u8]> {
|
||||
for phdr in info.program_headers() {
|
||||
if phdr.phdr.p_type == PT_NOTE {
|
||||
for note in phdr.notes() {
|
||||
if note.tipe == NT_GNU_BUILD_ID && (note.name == b"GNU\0" || note.name == b"GNU") {
|
||||
return Some(note.desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// These errors encode issues that arise while parsing information about
|
||||
/// each DSO.
|
||||
enum Error {
|
||||
/// NameError means that an error occurred while converting a C style string
|
||||
/// into a rust string.
|
||||
NameError(core::str::Utf8Error),
|
||||
/// BuildIDError means that we didn't find a build ID. This could either be
|
||||
/// because the DSO had no build ID or because the segment containing the
|
||||
/// build ID was malformed.
|
||||
BuildIDError,
|
||||
}
|
||||
|
||||
/// Calls either 'dso' or 'error' for each DSO linked into the process by the
|
||||
/// dynamic linker.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `visitor` - A DsoPrinter that will have one of eats methods called foreach DSO.
|
||||
fn for_each_dso(mut visitor: &mut DsoPrinter<'_, '_>) {
|
||||
extern "C" fn callback(
|
||||
info: &dl_phdr_info,
|
||||
_size: usize,
|
||||
visitor: &mut DsoPrinter<'_, '_>,
|
||||
) -> i32 {
|
||||
// dl_iterate_phdr ensures that info.name will point to a valid
|
||||
// location.
|
||||
let name_len = unsafe { libc::strlen(info.name) };
|
||||
let name_slice: &[u8] =
|
||||
unsafe { core::slice::from_raw_parts(info.name as *const u8, name_len) };
|
||||
let name = match core::str::from_utf8(name_slice) {
|
||||
Ok(name) => name,
|
||||
Err(err) => {
|
||||
return visitor.error(Error::NameError(err)) as i32;
|
||||
}
|
||||
};
|
||||
let build_id = match get_build_id(info) {
|
||||
Some(build_id) => build_id,
|
||||
None => {
|
||||
return visitor.error(Error::BuildIDError) as i32;
|
||||
}
|
||||
};
|
||||
visitor.dso(Dso {
|
||||
name: name,
|
||||
build_id: build_id,
|
||||
phdrs: info.phdr_slice(),
|
||||
base: info.addr as usize,
|
||||
}) as i32
|
||||
}
|
||||
unsafe { dl_iterate_phdr(callback, &mut visitor) };
|
||||
}
|
||||
|
||||
struct DsoPrinter<'a, 'b> {
|
||||
writer: &'a mut core::fmt::Formatter<'b>,
|
||||
module_count: usize,
|
||||
error: core::fmt::Result,
|
||||
}
|
||||
|
||||
impl DsoPrinter<'_, '_> {
|
||||
fn dso(&mut self, dso: Dso<'_>) -> bool {
|
||||
let mut write = || {
|
||||
write!(
|
||||
self.writer,
|
||||
"{{{{{{module:{:#x}:{}:elf:{}}}}}}}\n",
|
||||
self.module_count,
|
||||
dso.name,
|
||||
HexSlice {
|
||||
bytes: dso.build_id.as_ref()
|
||||
}
|
||||
)?;
|
||||
for seg in dso.segments() {
|
||||
write!(
|
||||
self.writer,
|
||||
"{{{{{{mmap:{:#x}:{:#x}:load:{:#x}:{}:{:#x}}}}}}}\n",
|
||||
seg.addr, seg.size, self.module_count, seg.flags, seg.mod_rel_addr
|
||||
)?;
|
||||
}
|
||||
self.module_count += 1;
|
||||
Ok(())
|
||||
};
|
||||
match write() {
|
||||
Ok(()) => false,
|
||||
Err(err) => {
|
||||
self.error = Err(err);
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
fn error(&mut self, _error: Error) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// This function prints the Fuchsia symbolizer markup for all information contained in a DSO.
|
||||
pub fn print_dso_context(out: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
out.write_str("{{{reset}}}\n")?;
|
||||
let mut visitor = DsoPrinter {
|
||||
writer: out,
|
||||
module_count: 0,
|
||||
error: Ok(()),
|
||||
};
|
||||
for_each_dso(&mut visitor);
|
||||
visitor.error
|
||||
}
|
||||
218
.gear/predownloaded-development/vendor/backtrace/src/symbolize/dbghelp.rs
vendored
Normal file
218
.gear/predownloaded-development/vendor/backtrace/src/symbolize/dbghelp.rs
vendored
Normal file
|
|
@ -0,0 +1,218 @@
|
|||
//! Symbolication strategy using `dbghelp.dll` on Windows, only used for MSVC
|
||||
//!
|
||||
//! This symbolication strategy, like with backtraces, uses dynamically loaded
|
||||
//! information from `dbghelp.dll`. (see `src/dbghelp.rs` for info about why
|
||||
//! it's dynamically loaded).
|
||||
//!
|
||||
//! This API selects its resolution strategy based on the frame provided or the
|
||||
//! information we have at hand. If a frame from `StackWalkEx` is given to us
|
||||
//! then we use similar APIs to generate correct information about inlined
|
||||
//! functions. Otherwise if all we have is an address or an older stack frame
|
||||
//! from `StackWalk64` we use the older APIs for symbolication.
|
||||
//!
|
||||
//! There's a good deal of support in this module, but a good chunk of it is
|
||||
//! converting back and forth between Windows types and Rust types. For example
|
||||
//! symbols come to us as wide strings which we then convert to utf-8 strings if
|
||||
//! we can.
|
||||
|
||||
#![allow(bad_style)]
|
||||
|
||||
use super::super::{backtrace::StackFrame, dbghelp, windows::*};
|
||||
use super::{BytesOrWideString, ResolveWhat, SymbolName};
|
||||
use core::char;
|
||||
use core::ffi::c_void;
|
||||
use core::marker;
|
||||
use core::mem;
|
||||
use core::slice;
|
||||
|
||||
// Store an OsString on std so we can provide the symbol name and filename.
|
||||
pub struct Symbol<'a> {
|
||||
name: *const [u8],
|
||||
addr: *mut c_void,
|
||||
line: Option<u32>,
|
||||
filename: Option<*const [u16]>,
|
||||
#[cfg(feature = "std")]
|
||||
_filename_cache: Option<::std::ffi::OsString>,
|
||||
#[cfg(not(feature = "std"))]
|
||||
_filename_cache: (),
|
||||
_marker: marker::PhantomData<&'a i32>,
|
||||
}
|
||||
|
||||
impl Symbol<'_> {
|
||||
pub fn name(&self) -> Option<SymbolName<'_>> {
|
||||
Some(SymbolName::new(unsafe { &*self.name }))
|
||||
}
|
||||
|
||||
pub fn addr(&self) -> Option<*mut c_void> {
|
||||
Some(self.addr as *mut _)
|
||||
}
|
||||
|
||||
pub fn filename_raw(&self) -> Option<BytesOrWideString<'_>> {
|
||||
self.filename
|
||||
.map(|slice| unsafe { BytesOrWideString::Wide(&*slice) })
|
||||
}
|
||||
|
||||
pub fn colno(&self) -> Option<u32> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn lineno(&self) -> Option<u32> {
|
||||
self.line
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub fn filename(&self) -> Option<&::std::path::Path> {
|
||||
use std::path::Path;
|
||||
|
||||
self._filename_cache.as_ref().map(Path::new)
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C, align(8))]
|
||||
struct Aligned8<T>(T);
|
||||
|
||||
pub unsafe fn resolve(what: ResolveWhat<'_>, cb: &mut dyn FnMut(&super::Symbol)) {
|
||||
// Ensure this process's symbols are initialized
|
||||
let dbghelp = match dbghelp::init() {
|
||||
Ok(dbghelp) => dbghelp,
|
||||
Err(()) => return, // oh well...
|
||||
};
|
||||
|
||||
match what {
|
||||
ResolveWhat::Address(_) => resolve_without_inline(&dbghelp, what.address_or_ip(), cb),
|
||||
ResolveWhat::Frame(frame) => match &frame.inner.stack_frame {
|
||||
StackFrame::New(frame) => resolve_with_inline(&dbghelp, frame, cb),
|
||||
StackFrame::Old(_) => resolve_without_inline(&dbghelp, frame.ip(), cb),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn resolve_with_inline(
|
||||
dbghelp: &dbghelp::Init,
|
||||
frame: &STACKFRAME_EX,
|
||||
cb: &mut dyn FnMut(&super::Symbol),
|
||||
) {
|
||||
do_resolve(
|
||||
|info| {
|
||||
dbghelp.SymFromInlineContextW()(
|
||||
GetCurrentProcess(),
|
||||
super::adjust_ip(frame.AddrPC.Offset as *mut _) as u64,
|
||||
frame.InlineFrameContext,
|
||||
&mut 0,
|
||||
info,
|
||||
)
|
||||
},
|
||||
|line| {
|
||||
dbghelp.SymGetLineFromInlineContextW()(
|
||||
GetCurrentProcess(),
|
||||
super::adjust_ip(frame.AddrPC.Offset as *mut _) as u64,
|
||||
frame.InlineFrameContext,
|
||||
0,
|
||||
&mut 0,
|
||||
line,
|
||||
)
|
||||
},
|
||||
cb,
|
||||
)
|
||||
}
|
||||
|
||||
unsafe fn resolve_without_inline(
|
||||
dbghelp: &dbghelp::Init,
|
||||
addr: *mut c_void,
|
||||
cb: &mut dyn FnMut(&super::Symbol),
|
||||
) {
|
||||
do_resolve(
|
||||
|info| dbghelp.SymFromAddrW()(GetCurrentProcess(), addr as DWORD64, &mut 0, info),
|
||||
|line| dbghelp.SymGetLineFromAddrW64()(GetCurrentProcess(), addr as DWORD64, &mut 0, line),
|
||||
cb,
|
||||
)
|
||||
}
|
||||
|
||||
unsafe fn do_resolve(
|
||||
sym_from_addr: impl FnOnce(*mut SYMBOL_INFOW) -> BOOL,
|
||||
get_line_from_addr: impl FnOnce(&mut IMAGEHLP_LINEW64) -> BOOL,
|
||||
cb: &mut dyn FnMut(&super::Symbol),
|
||||
) {
|
||||
const SIZE: usize = 2 * MAX_SYM_NAME + mem::size_of::<SYMBOL_INFOW>();
|
||||
let mut data = Aligned8([0u8; SIZE]);
|
||||
let data = &mut data.0;
|
||||
let info = &mut *(data.as_mut_ptr() as *mut SYMBOL_INFOW);
|
||||
info.MaxNameLen = MAX_SYM_NAME as ULONG;
|
||||
// the struct size in C. the value is different to
|
||||
// `size_of::<SYMBOL_INFOW>() - MAX_SYM_NAME + 1` (== 81)
|
||||
// due to struct alignment.
|
||||
info.SizeOfStruct = 88;
|
||||
|
||||
if sym_from_addr(info) != TRUE {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the symbol name is greater than MaxNameLen, SymFromAddrW will
|
||||
// give a buffer of (MaxNameLen - 1) characters and set NameLen to
|
||||
// the real value.
|
||||
let name_len = ::core::cmp::min(info.NameLen as usize, info.MaxNameLen as usize - 1);
|
||||
let name_ptr = info.Name.as_ptr() as *const u16;
|
||||
let name = slice::from_raw_parts(name_ptr, name_len);
|
||||
|
||||
// Reencode the utf-16 symbol to utf-8 so we can use `SymbolName::new` like
|
||||
// all other platforms
|
||||
let mut name_len = 0;
|
||||
let mut name_buffer = [0; 256];
|
||||
{
|
||||
let mut remaining = &mut name_buffer[..];
|
||||
for c in char::decode_utf16(name.iter().cloned()) {
|
||||
let c = c.unwrap_or(char::REPLACEMENT_CHARACTER);
|
||||
let len = c.len_utf8();
|
||||
if len < remaining.len() {
|
||||
c.encode_utf8(remaining);
|
||||
let tmp = remaining;
|
||||
remaining = &mut tmp[len..];
|
||||
name_len += len;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
let name = &name_buffer[..name_len] as *const [u8];
|
||||
|
||||
let mut line = mem::zeroed::<IMAGEHLP_LINEW64>();
|
||||
line.SizeOfStruct = mem::size_of::<IMAGEHLP_LINEW64>() as DWORD;
|
||||
|
||||
let mut filename = None;
|
||||
let mut lineno = None;
|
||||
if get_line_from_addr(&mut line) == TRUE {
|
||||
lineno = Some(line.LineNumber as u32);
|
||||
|
||||
let base = line.FileName;
|
||||
let mut len = 0;
|
||||
while *base.offset(len) != 0 {
|
||||
len += 1;
|
||||
}
|
||||
|
||||
let len = len as usize;
|
||||
|
||||
filename = Some(slice::from_raw_parts(base, len) as *const [u16]);
|
||||
}
|
||||
|
||||
cb(&super::Symbol {
|
||||
inner: Symbol {
|
||||
name,
|
||||
addr: info.Address as *mut _,
|
||||
line: lineno,
|
||||
filename,
|
||||
_filename_cache: cache(filename),
|
||||
_marker: marker::PhantomData,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
unsafe fn cache(filename: Option<*const [u16]>) -> Option<::std::ffi::OsString> {
|
||||
use std::os::windows::ffi::OsStringExt;
|
||||
filename.map(|f| ::std::ffi::OsString::from_wide(&*f))
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
unsafe fn cache(_filename: Option<*const [u16]>) {}
|
||||
|
||||
pub unsafe fn clear_symbol_cache() {}
|
||||
511
.gear/predownloaded-development/vendor/backtrace/src/symbolize/gimli.rs
vendored
Normal file
511
.gear/predownloaded-development/vendor/backtrace/src/symbolize/gimli.rs
vendored
Normal file
|
|
@ -0,0 +1,511 @@
|
|||
//! Support for symbolication using the `gimli` crate on crates.io
|
||||
//!
|
||||
//! This is the default symbolication implementation for Rust.
|
||||
|
||||
use self::gimli::read::EndianSlice;
|
||||
use self::gimli::NativeEndian as Endian;
|
||||
use self::mmap::Mmap;
|
||||
use self::stash::Stash;
|
||||
use super::BytesOrWideString;
|
||||
use super::ResolveWhat;
|
||||
use super::SymbolName;
|
||||
use addr2line::gimli;
|
||||
use core::convert::TryInto;
|
||||
use core::mem;
|
||||
use core::u32;
|
||||
use libc::c_void;
|
||||
use mystd::ffi::OsString;
|
||||
use mystd::fs::File;
|
||||
use mystd::path::Path;
|
||||
use mystd::prelude::v1::*;
|
||||
|
||||
#[cfg(backtrace_in_libstd)]
|
||||
mod mystd {
|
||||
pub use crate::*;
|
||||
}
|
||||
#[cfg(not(backtrace_in_libstd))]
|
||||
extern crate std as mystd;
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(windows)] {
|
||||
#[path = "gimli/mmap_windows.rs"]
|
||||
mod mmap;
|
||||
} else if #[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "freebsd",
|
||||
target_os = "fuchsia",
|
||||
target_os = "haiku",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos",
|
||||
target_os = "openbsd",
|
||||
target_os = "solaris",
|
||||
target_os = "illumos",
|
||||
))] {
|
||||
#[path = "gimli/mmap_unix.rs"]
|
||||
mod mmap;
|
||||
} else {
|
||||
#[path = "gimli/mmap_fake.rs"]
|
||||
mod mmap;
|
||||
}
|
||||
}
|
||||
|
||||
mod stash;
|
||||
|
||||
const MAPPINGS_CACHE_SIZE: usize = 4;
|
||||
|
||||
struct Mapping {
|
||||
// 'static lifetime is a lie to hack around lack of support for self-referential structs.
|
||||
cx: Context<'static>,
|
||||
_map: Mmap,
|
||||
stash: Stash,
|
||||
}
|
||||
|
||||
enum Either<A, B> {
|
||||
#[allow(dead_code)]
|
||||
A(A),
|
||||
B(B),
|
||||
}
|
||||
|
||||
impl Mapping {
|
||||
/// Creates a `Mapping` by ensuring that the `data` specified is used to
|
||||
/// create a `Context` and it can only borrow from that or the `Stash` of
|
||||
/// decompressed sections or auxiliary data.
|
||||
fn mk<F>(data: Mmap, mk: F) -> Option<Mapping>
|
||||
where
|
||||
F: for<'a> FnOnce(&'a [u8], &'a Stash) -> Option<Context<'a>>,
|
||||
{
|
||||
Mapping::mk_or_other(data, move |data, stash| {
|
||||
let cx = mk(data, stash)?;
|
||||
Some(Either::B(cx))
|
||||
})
|
||||
}
|
||||
|
||||
/// Creates a `Mapping` from `data`, or if the closure decides to, returns a
|
||||
/// different mapping.
|
||||
fn mk_or_other<F>(data: Mmap, mk: F) -> Option<Mapping>
|
||||
where
|
||||
F: for<'a> FnOnce(&'a [u8], &'a Stash) -> Option<Either<Mapping, Context<'a>>>,
|
||||
{
|
||||
let stash = Stash::new();
|
||||
let cx = match mk(&data, &stash)? {
|
||||
Either::A(mapping) => return Some(mapping),
|
||||
Either::B(cx) => cx,
|
||||
};
|
||||
Some(Mapping {
|
||||
// Convert to 'static lifetimes since the symbols should
|
||||
// only borrow `map` and `stash` and we're preserving them below.
|
||||
cx: unsafe { core::mem::transmute::<Context<'_>, Context<'static>>(cx) },
|
||||
_map: data,
|
||||
stash: stash,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
struct Context<'a> {
|
||||
dwarf: addr2line::Context<EndianSlice<'a, Endian>>,
|
||||
object: Object<'a>,
|
||||
package: Option<gimli::DwarfPackage<EndianSlice<'a, Endian>>>,
|
||||
}
|
||||
|
||||
impl<'data> Context<'data> {
|
||||
fn new(
|
||||
stash: &'data Stash,
|
||||
object: Object<'data>,
|
||||
sup: Option<Object<'data>>,
|
||||
dwp: Option<Object<'data>>,
|
||||
) -> Option<Context<'data>> {
|
||||
let mut sections = gimli::Dwarf::load(|id| -> Result<_, ()> {
|
||||
let data = object.section(stash, id.name()).unwrap_or(&[]);
|
||||
Ok(EndianSlice::new(data, Endian))
|
||||
})
|
||||
.ok()?;
|
||||
|
||||
if let Some(sup) = sup {
|
||||
sections
|
||||
.load_sup(|id| -> Result<_, ()> {
|
||||
let data = sup.section(stash, id.name()).unwrap_or(&[]);
|
||||
Ok(EndianSlice::new(data, Endian))
|
||||
})
|
||||
.ok()?;
|
||||
}
|
||||
let dwarf = addr2line::Context::from_dwarf(sections).ok()?;
|
||||
|
||||
let mut package = None;
|
||||
if let Some(dwp) = dwp {
|
||||
package = Some(
|
||||
gimli::DwarfPackage::load(
|
||||
|id| -> Result<_, gimli::Error> {
|
||||
let data = id
|
||||
.dwo_name()
|
||||
.and_then(|name| dwp.section(stash, name))
|
||||
.unwrap_or(&[]);
|
||||
Ok(EndianSlice::new(data, Endian))
|
||||
},
|
||||
EndianSlice::new(&[], Endian),
|
||||
)
|
||||
.ok()?,
|
||||
);
|
||||
}
|
||||
|
||||
Some(Context {
|
||||
dwarf,
|
||||
object,
|
||||
package,
|
||||
})
|
||||
}
|
||||
|
||||
fn find_frames(
|
||||
&'_ self,
|
||||
stash: &'data Stash,
|
||||
probe: u64,
|
||||
) -> gimli::Result<addr2line::FrameIter<'_, EndianSlice<'data, Endian>>> {
|
||||
use addr2line::{LookupContinuation, LookupResult};
|
||||
|
||||
let mut l = self.dwarf.find_frames(probe);
|
||||
loop {
|
||||
let (load, continuation) = match l {
|
||||
LookupResult::Output(output) => break output,
|
||||
LookupResult::Load { load, continuation } => (load, continuation),
|
||||
};
|
||||
|
||||
l = continuation.resume(handle_split_dwarf(self.package.as_ref(), stash, load));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn mmap(path: &Path) -> Option<Mmap> {
|
||||
let file = File::open(path).ok()?;
|
||||
let len = file.metadata().ok()?.len().try_into().ok()?;
|
||||
unsafe { Mmap::map(&file, len) }
|
||||
}
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(windows)] {
|
||||
mod coff;
|
||||
use self::coff::{handle_split_dwarf, Object};
|
||||
} else if #[cfg(any(
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "tvos",
|
||||
target_os = "watchos",
|
||||
))] {
|
||||
mod macho;
|
||||
use self::macho::{handle_split_dwarf, Object};
|
||||
} else {
|
||||
mod elf;
|
||||
use self::elf::{handle_split_dwarf, Object};
|
||||
}
|
||||
}
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(windows)] {
|
||||
mod libs_windows;
|
||||
use libs_windows::native_libraries;
|
||||
} else if #[cfg(any(
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "tvos",
|
||||
target_os = "watchos",
|
||||
))] {
|
||||
mod libs_macos;
|
||||
use libs_macos::native_libraries;
|
||||
} else if #[cfg(target_os = "illumos")] {
|
||||
mod libs_illumos;
|
||||
use libs_illumos::native_libraries;
|
||||
} else if #[cfg(all(
|
||||
any(
|
||||
target_os = "linux",
|
||||
target_os = "fuchsia",
|
||||
target_os = "freebsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "netbsd",
|
||||
all(target_os = "android", feature = "dl_iterate_phdr"),
|
||||
),
|
||||
not(target_env = "uclibc"),
|
||||
))] {
|
||||
mod libs_dl_iterate_phdr;
|
||||
use libs_dl_iterate_phdr::native_libraries;
|
||||
#[path = "gimli/parse_running_mmaps_unix.rs"]
|
||||
mod parse_running_mmaps;
|
||||
} else if #[cfg(target_env = "libnx")] {
|
||||
mod libs_libnx;
|
||||
use libs_libnx::native_libraries;
|
||||
} else if #[cfg(target_os = "haiku")] {
|
||||
mod libs_haiku;
|
||||
use libs_haiku::native_libraries;
|
||||
} else {
|
||||
// Everything else should doesn't know how to load native libraries.
|
||||
fn native_libraries() -> Vec<Library> {
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct Cache {
|
||||
/// All known shared libraries that have been loaded.
|
||||
libraries: Vec<Library>,
|
||||
|
||||
/// Mappings cache where we retain parsed dwarf information.
|
||||
///
|
||||
/// This list has a fixed capacity for its entire lifetime which never
|
||||
/// increases. The `usize` element of each pair is an index into `libraries`
|
||||
/// above where `usize::max_value()` represents the current executable. The
|
||||
/// `Mapping` is corresponding parsed dwarf information.
|
||||
///
|
||||
/// Note that this is basically an LRU cache and we'll be shifting things
|
||||
/// around in here as we symbolize addresses.
|
||||
mappings: Vec<(usize, Mapping)>,
|
||||
}
|
||||
|
||||
struct Library {
|
||||
name: OsString,
|
||||
/// Segments of this library loaded into memory, and where they're loaded.
|
||||
segments: Vec<LibrarySegment>,
|
||||
/// The "bias" of this library, typically where it's loaded into memory.
|
||||
/// This value is added to each segment's stated address to get the actual
|
||||
/// virtual memory address that the segment is loaded into. Additionally
|
||||
/// this bias is subtracted from real virtual memory addresses to index into
|
||||
/// debuginfo and the symbol table.
|
||||
bias: usize,
|
||||
}
|
||||
|
||||
struct LibrarySegment {
|
||||
/// The stated address of this segment in the object file. This is not
|
||||
/// actually where the segment is loaded, but rather this address plus the
|
||||
/// containing library's `bias` is where to find it.
|
||||
stated_virtual_memory_address: usize,
|
||||
/// The size of this segment in memory.
|
||||
len: usize,
|
||||
}
|
||||
|
||||
// unsafe because this is required to be externally synchronized
|
||||
pub unsafe fn clear_symbol_cache() {
|
||||
Cache::with_global(|cache| cache.mappings.clear());
|
||||
}
|
||||
|
||||
impl Cache {
|
||||
fn new() -> Cache {
|
||||
Cache {
|
||||
mappings: Vec::with_capacity(MAPPINGS_CACHE_SIZE),
|
||||
libraries: native_libraries(),
|
||||
}
|
||||
}
|
||||
|
||||
// unsafe because this is required to be externally synchronized
|
||||
unsafe fn with_global(f: impl FnOnce(&mut Self)) {
|
||||
// A very small, very simple LRU cache for debug info mappings.
|
||||
//
|
||||
// The hit rate should be very high, since the typical stack doesn't cross
|
||||
// between many shared libraries.
|
||||
//
|
||||
// The `addr2line::Context` structures are pretty expensive to create. Its
|
||||
// cost is expected to be amortized by subsequent `locate` queries, which
|
||||
// leverage the structures built when constructing `addr2line::Context`s to
|
||||
// get nice speedups. If we didn't have this cache, that amortization would
|
||||
// never happen, and symbolicating backtraces would be ssssllllooooowwww.
|
||||
static mut MAPPINGS_CACHE: Option<Cache> = None;
|
||||
|
||||
f(MAPPINGS_CACHE.get_or_insert_with(|| Cache::new()))
|
||||
}
|
||||
|
||||
fn avma_to_svma(&self, addr: *const u8) -> Option<(usize, *const u8)> {
|
||||
self.libraries
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(i, lib)| {
|
||||
// First up, test if this `lib` has any segment containing the
|
||||
// `addr` (handling relocation). If this check passes then we
|
||||
// can continue below and actually translate the address.
|
||||
//
|
||||
// Note that we're using `wrapping_add` here to avoid overflow
|
||||
// checks. It's been seen in the wild that the SVMA + bias
|
||||
// computation overflows. It seems a bit odd that would happen
|
||||
// but there's not a huge amount we can do about it other than
|
||||
// probably just ignore those segments since they're likely
|
||||
// pointing off into space. This originally came up in
|
||||
// rust-lang/backtrace-rs#329.
|
||||
if !lib.segments.iter().any(|s| {
|
||||
let svma = s.stated_virtual_memory_address;
|
||||
let start = svma.wrapping_add(lib.bias);
|
||||
let end = start.wrapping_add(s.len);
|
||||
let address = addr as usize;
|
||||
start <= address && address < end
|
||||
}) {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Now that we know `lib` contains `addr`, we can offset with
|
||||
// the bias to find the stated virtual memory address.
|
||||
let svma = (addr as usize).wrapping_sub(lib.bias);
|
||||
Some((i, svma as *const u8))
|
||||
})
|
||||
.next()
|
||||
}
|
||||
|
||||
fn mapping_for_lib<'a>(&'a mut self, lib: usize) -> Option<(&'a mut Context<'a>, &'a Stash)> {
|
||||
let idx = self.mappings.iter().position(|(idx, _)| *idx == lib);
|
||||
|
||||
// Invariant: after this conditional completes without early returning
|
||||
// from an error, the cache entry for this path is at index 0.
|
||||
|
||||
if let Some(idx) = idx {
|
||||
// When the mapping is already in the cache, move it to the front.
|
||||
if idx != 0 {
|
||||
let entry = self.mappings.remove(idx);
|
||||
self.mappings.insert(0, entry);
|
||||
}
|
||||
} else {
|
||||
// When the mapping is not in the cache, create a new mapping,
|
||||
// insert it into the front of the cache, and evict the oldest cache
|
||||
// entry if necessary.
|
||||
let name = &self.libraries[lib].name;
|
||||
let mapping = Mapping::new(name.as_ref())?;
|
||||
|
||||
if self.mappings.len() == MAPPINGS_CACHE_SIZE {
|
||||
self.mappings.pop();
|
||||
}
|
||||
|
||||
self.mappings.insert(0, (lib, mapping));
|
||||
}
|
||||
|
||||
let mapping = &mut self.mappings[0].1;
|
||||
let cx: &'a mut Context<'static> = &mut mapping.cx;
|
||||
let stash: &'a Stash = &mapping.stash;
|
||||
// don't leak the `'static` lifetime, make sure it's scoped to just
|
||||
// ourselves
|
||||
Some((
|
||||
unsafe { mem::transmute::<&'a mut Context<'static>, &'a mut Context<'a>>(cx) },
|
||||
stash,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn resolve(what: ResolveWhat<'_>, cb: &mut dyn FnMut(&super::Symbol)) {
|
||||
let addr = what.address_or_ip();
|
||||
let mut call = |sym: Symbol<'_>| {
|
||||
// Extend the lifetime of `sym` to `'static` since we are unfortunately
|
||||
// required to here, but it's only ever going out as a reference so no
|
||||
// reference to it should be persisted beyond this frame anyway.
|
||||
let sym = mem::transmute::<Symbol<'_>, Symbol<'static>>(sym);
|
||||
(cb)(&super::Symbol { inner: sym });
|
||||
};
|
||||
|
||||
Cache::with_global(|cache| {
|
||||
let (lib, addr) = match cache.avma_to_svma(addr as *const u8) {
|
||||
Some(pair) => pair,
|
||||
None => return,
|
||||
};
|
||||
|
||||
// Finally, get a cached mapping or create a new mapping for this file, and
|
||||
// evaluate the DWARF info to find the file/line/name for this address.
|
||||
let (cx, stash) = match cache.mapping_for_lib(lib) {
|
||||
Some((cx, stash)) => (cx, stash),
|
||||
None => return,
|
||||
};
|
||||
let mut any_frames = false;
|
||||
if let Ok(mut frames) = cx.find_frames(stash, addr as u64) {
|
||||
while let Ok(Some(frame)) = frames.next() {
|
||||
any_frames = true;
|
||||
let name = match frame.function {
|
||||
Some(f) => Some(f.name.slice()),
|
||||
None => cx.object.search_symtab(addr as u64),
|
||||
};
|
||||
call(Symbol::Frame {
|
||||
addr: addr as *mut c_void,
|
||||
location: frame.location,
|
||||
name,
|
||||
});
|
||||
}
|
||||
}
|
||||
if !any_frames {
|
||||
if let Some((object_cx, object_addr)) = cx.object.search_object_map(addr as u64) {
|
||||
if let Ok(mut frames) = object_cx.find_frames(stash, object_addr) {
|
||||
while let Ok(Some(frame)) = frames.next() {
|
||||
any_frames = true;
|
||||
call(Symbol::Frame {
|
||||
addr: addr as *mut c_void,
|
||||
location: frame.location,
|
||||
name: frame.function.map(|f| f.name.slice()),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if !any_frames {
|
||||
if let Some(name) = cx.object.search_symtab(addr as u64) {
|
||||
call(Symbol::Symtab {
|
||||
addr: addr as *mut c_void,
|
||||
name,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub enum Symbol<'a> {
|
||||
/// We were able to locate frame information for this symbol, and
|
||||
/// `addr2line`'s frame internally has all the nitty gritty details.
|
||||
Frame {
|
||||
addr: *mut c_void,
|
||||
location: Option<addr2line::Location<'a>>,
|
||||
name: Option<&'a [u8]>,
|
||||
},
|
||||
/// Couldn't find debug information, but we found it in the symbol table of
|
||||
/// the elf executable.
|
||||
Symtab { addr: *mut c_void, name: &'a [u8] },
|
||||
}
|
||||
|
||||
impl Symbol<'_> {
|
||||
pub fn name(&self) -> Option<SymbolName<'_>> {
|
||||
match self {
|
||||
Symbol::Frame { name, .. } => {
|
||||
let name = name.as_ref()?;
|
||||
Some(SymbolName::new(name))
|
||||
}
|
||||
Symbol::Symtab { name, .. } => Some(SymbolName::new(name)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn addr(&self) -> Option<*mut c_void> {
|
||||
match self {
|
||||
Symbol::Frame { addr, .. } => Some(*addr),
|
||||
Symbol::Symtab { .. } => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn filename_raw(&self) -> Option<BytesOrWideString<'_>> {
|
||||
match self {
|
||||
Symbol::Frame { location, .. } => {
|
||||
let file = location.as_ref()?.file?;
|
||||
Some(BytesOrWideString::Bytes(file.as_bytes()))
|
||||
}
|
||||
Symbol::Symtab { .. } => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn filename(&self) -> Option<&Path> {
|
||||
match self {
|
||||
Symbol::Frame { location, .. } => {
|
||||
let file = location.as_ref()?.file?;
|
||||
Some(Path::new(file))
|
||||
}
|
||||
Symbol::Symtab { .. } => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lineno(&self) -> Option<u32> {
|
||||
match self {
|
||||
Symbol::Frame { location, .. } => location.as_ref()?.line,
|
||||
Symbol::Symtab { .. } => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn colno(&self) -> Option<u32> {
|
||||
match self {
|
||||
Symbol::Frame { location, .. } => location.as_ref()?.column,
|
||||
Symbol::Symtab { .. } => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
118
.gear/predownloaded-development/vendor/backtrace/src/symbolize/gimli/coff.rs
vendored
Normal file
118
.gear/predownloaded-development/vendor/backtrace/src/symbolize/gimli/coff.rs
vendored
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
use super::{gimli, Context, Endian, EndianSlice, Mapping, Path, Stash, Vec};
|
||||
use alloc::sync::Arc;
|
||||
use core::convert::TryFrom;
|
||||
use object::pe::{ImageDosHeader, ImageSymbol};
|
||||
use object::read::coff::ImageSymbol as _;
|
||||
use object::read::pe::{ImageNtHeaders, ImageOptionalHeader, SectionTable};
|
||||
use object::read::StringTable;
|
||||
use object::LittleEndian as LE;
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
type Pe = object::pe::ImageNtHeaders32;
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
type Pe = object::pe::ImageNtHeaders64;
|
||||
|
||||
impl Mapping {
|
||||
pub fn new(path: &Path) -> Option<Mapping> {
|
||||
let map = super::mmap(path)?;
|
||||
Mapping::mk(map, |data, stash| {
|
||||
Context::new(stash, Object::parse(data)?, None, None)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Object<'a> {
|
||||
data: &'a [u8],
|
||||
sections: SectionTable<'a>,
|
||||
symbols: Vec<(usize, &'a ImageSymbol)>,
|
||||
strings: StringTable<'a>,
|
||||
}
|
||||
|
||||
pub fn get_image_base(data: &[u8]) -> Option<usize> {
|
||||
let dos_header = ImageDosHeader::parse(data).ok()?;
|
||||
let mut offset = dos_header.nt_headers_offset().into();
|
||||
let (nt_headers, _) = Pe::parse(data, &mut offset).ok()?;
|
||||
usize::try_from(nt_headers.optional_header().image_base()).ok()
|
||||
}
|
||||
|
||||
impl<'a> Object<'a> {
|
||||
fn parse(data: &'a [u8]) -> Option<Object<'a>> {
|
||||
let dos_header = ImageDosHeader::parse(data).ok()?;
|
||||
let mut offset = dos_header.nt_headers_offset().into();
|
||||
let (nt_headers, _) = Pe::parse(data, &mut offset).ok()?;
|
||||
let sections = nt_headers.sections(data, offset).ok()?;
|
||||
let symtab = nt_headers.symbols(data).ok()?;
|
||||
let strings = symtab.strings();
|
||||
let image_base = usize::try_from(nt_headers.optional_header().image_base()).ok()?;
|
||||
|
||||
// Collect all the symbols into a local vector which is sorted
|
||||
// by address and contains enough data to learn about the symbol
|
||||
// name. Note that we only look at function symbols and also
|
||||
// note that the sections are 1-indexed because the zero section
|
||||
// is special (apparently).
|
||||
let mut symbols = Vec::new();
|
||||
let mut i = 0;
|
||||
let len = symtab.len();
|
||||
while i < len {
|
||||
let sym = symtab.symbol(i).ok()?;
|
||||
i += 1 + sym.number_of_aux_symbols as usize;
|
||||
let section_number = sym.section_number.get(LE);
|
||||
if sym.derived_type() != object::pe::IMAGE_SYM_DTYPE_FUNCTION || section_number == 0 {
|
||||
continue;
|
||||
}
|
||||
let addr = usize::try_from(sym.value.get(LE)).ok()?;
|
||||
let section = sections
|
||||
.section(usize::try_from(section_number).ok()?)
|
||||
.ok()?;
|
||||
let va = usize::try_from(section.virtual_address.get(LE)).ok()?;
|
||||
symbols.push((addr + va + image_base, sym));
|
||||
}
|
||||
symbols.sort_unstable_by_key(|x| x.0);
|
||||
Some(Object {
|
||||
data,
|
||||
sections,
|
||||
strings,
|
||||
symbols,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn section(&self, _: &Stash, name: &str) -> Option<&'a [u8]> {
|
||||
Some(
|
||||
self.sections
|
||||
.section_by_name(self.strings, name.as_bytes())?
|
||||
.1
|
||||
.pe_data(self.data)
|
||||
.ok()?,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn search_symtab<'b>(&'b self, addr: u64) -> Option<&'b [u8]> {
|
||||
// Note that unlike other formats COFF doesn't embed the size of
|
||||
// each symbol. As a last ditch effort search for the *closest*
|
||||
// symbol to a particular address and return that one. This gets
|
||||
// really wonky once symbols start getting removed because the
|
||||
// symbols returned here can be totally incorrect, but we have
|
||||
// no idea of knowing how to detect that.
|
||||
let addr = usize::try_from(addr).ok()?;
|
||||
let i = match self.symbols.binary_search_by_key(&addr, |p| p.0) {
|
||||
Ok(i) => i,
|
||||
// typically `addr` isn't in the array, but `i` is where
|
||||
// we'd insert it, so the previous position must be the
|
||||
// greatest less than `addr`
|
||||
Err(i) => i.checked_sub(1)?,
|
||||
};
|
||||
self.symbols[i].1.name(self.strings).ok()
|
||||
}
|
||||
|
||||
pub(super) fn search_object_map(&self, _addr: u64) -> Option<(&Context<'_>, u64)> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn handle_split_dwarf<'data>(
|
||||
_package: Option<&gimli::DwarfPackage<EndianSlice<'data, Endian>>>,
|
||||
_stash: &'data Stash,
|
||||
_load: addr2line::SplitDwarfLoad<EndianSlice<'data, Endian>>,
|
||||
) -> Option<Arc<gimli::Dwarf<EndianSlice<'data, Endian>>>> {
|
||||
None
|
||||
}
|
||||
495
.gear/predownloaded-development/vendor/backtrace/src/symbolize/gimli/elf.rs
vendored
Normal file
495
.gear/predownloaded-development/vendor/backtrace/src/symbolize/gimli/elf.rs
vendored
Normal file
|
|
@ -0,0 +1,495 @@
|
|||
use super::mystd::ffi::{OsStr, OsString};
|
||||
use super::mystd::fs;
|
||||
use super::mystd::os::unix::ffi::{OsStrExt, OsStringExt};
|
||||
use super::mystd::path::{Path, PathBuf};
|
||||
use super::Either;
|
||||
use super::{gimli, Context, Endian, EndianSlice, Mapping, Stash, Vec};
|
||||
use alloc::sync::Arc;
|
||||
use core::convert::{TryFrom, TryInto};
|
||||
use core::str;
|
||||
use object::elf::{ELFCOMPRESS_ZLIB, ELF_NOTE_GNU, NT_GNU_BUILD_ID, SHF_COMPRESSED};
|
||||
use object::read::elf::{CompressionHeader, FileHeader, SectionHeader, SectionTable, Sym};
|
||||
use object::read::StringTable;
|
||||
use object::{BigEndian, Bytes, NativeEndian};
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
type Elf = object::elf::FileHeader32<NativeEndian>;
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
type Elf = object::elf::FileHeader64<NativeEndian>;
|
||||
|
||||
impl Mapping {
|
||||
pub fn new(path: &Path) -> Option<Mapping> {
|
||||
let map = super::mmap(path)?;
|
||||
Mapping::mk_or_other(map, |map, stash| {
|
||||
let object = Object::parse(&map)?;
|
||||
|
||||
// Try to locate an external debug file using the build ID.
|
||||
if let Some(path_debug) = object.build_id().and_then(locate_build_id) {
|
||||
if let Some(mapping) = Mapping::new_debug(path, path_debug, None) {
|
||||
return Some(Either::A(mapping));
|
||||
}
|
||||
}
|
||||
|
||||
// Try to locate an external debug file using the GNU debug link section.
|
||||
if let Some((path_debug, crc)) = object.gnu_debuglink_path(path) {
|
||||
if let Some(mapping) = Mapping::new_debug(path, path_debug, Some(crc)) {
|
||||
return Some(Either::A(mapping));
|
||||
}
|
||||
}
|
||||
|
||||
let dwp = Mapping::load_dwarf_package(path, stash);
|
||||
|
||||
Context::new(stash, object, None, dwp).map(Either::B)
|
||||
})
|
||||
}
|
||||
|
||||
/// Load debuginfo from an external debug file.
|
||||
fn new_debug(original_path: &Path, path: PathBuf, crc: Option<u32>) -> Option<Mapping> {
|
||||
let map = super::mmap(&path)?;
|
||||
Mapping::mk(map, |map, stash| {
|
||||
let object = Object::parse(&map)?;
|
||||
|
||||
if let Some(_crc) = crc {
|
||||
// TODO: check crc
|
||||
}
|
||||
|
||||
// Try to locate a supplementary object file.
|
||||
let mut sup = None;
|
||||
if let Some((path_sup, build_id_sup)) = object.gnu_debugaltlink_path(&path) {
|
||||
if let Some(map_sup) = super::mmap(&path_sup) {
|
||||
let map_sup = stash.cache_mmap(map_sup);
|
||||
if let Some(sup_) = Object::parse(map_sup) {
|
||||
if sup_.build_id() == Some(build_id_sup) {
|
||||
sup = Some(sup_);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let dwp = Mapping::load_dwarf_package(original_path, stash);
|
||||
|
||||
Context::new(stash, object, sup, dwp)
|
||||
})
|
||||
}
|
||||
|
||||
/// Try to locate a DWARF package file.
|
||||
fn load_dwarf_package<'data>(path: &Path, stash: &'data Stash) -> Option<Object<'data>> {
|
||||
let mut path_dwp = path.to_path_buf();
|
||||
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_dwp.set_extension(dwp_extension);
|
||||
if let Some(map_dwp) = super::mmap(&path_dwp) {
|
||||
let map_dwp = stash.cache_mmap(map_dwp);
|
||||
if let Some(dwp_) = Object::parse(map_dwp) {
|
||||
return Some(dwp_);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
struct ParsedSym {
|
||||
address: u64,
|
||||
size: u64,
|
||||
name: u32,
|
||||
}
|
||||
|
||||
pub struct Object<'a> {
|
||||
/// Zero-sized type representing the native endianness.
|
||||
///
|
||||
/// We could use a literal instead, but this helps ensure correctness.
|
||||
endian: NativeEndian,
|
||||
/// The entire file data.
|
||||
data: &'a [u8],
|
||||
sections: SectionTable<'a, Elf>,
|
||||
strings: StringTable<'a>,
|
||||
/// List of pre-parsed and sorted symbols by base address.
|
||||
syms: Vec<ParsedSym>,
|
||||
}
|
||||
|
||||
impl<'a> Object<'a> {
|
||||
fn parse(data: &'a [u8]) -> Option<Object<'a>> {
|
||||
let elf = Elf::parse(data).ok()?;
|
||||
let endian = elf.endian().ok()?;
|
||||
let sections = elf.sections(endian, data).ok()?;
|
||||
let mut syms = sections
|
||||
.symbols(endian, data, object::elf::SHT_SYMTAB)
|
||||
.ok()?;
|
||||
if syms.is_empty() {
|
||||
syms = sections
|
||||
.symbols(endian, data, object::elf::SHT_DYNSYM)
|
||||
.ok()?;
|
||||
}
|
||||
let strings = syms.strings();
|
||||
|
||||
let mut syms = syms
|
||||
.iter()
|
||||
// Only look at function/object symbols. This mirrors what
|
||||
// libbacktrace does and in general we're only symbolicating
|
||||
// function addresses in theory. Object symbols correspond
|
||||
// to data, and maybe someone's crazy enough to have a
|
||||
// function go into static data?
|
||||
.filter(|sym| {
|
||||
let st_type = sym.st_type();
|
||||
st_type == object::elf::STT_FUNC || st_type == object::elf::STT_OBJECT
|
||||
})
|
||||
// skip anything that's in an undefined section header,
|
||||
// since it means it's an imported function and we're only
|
||||
// symbolicating with locally defined functions.
|
||||
.filter(|sym| sym.st_shndx(endian) != object::elf::SHN_UNDEF)
|
||||
.map(|sym| {
|
||||
let address = sym.st_value(endian).into();
|
||||
let size = sym.st_size(endian).into();
|
||||
let name = sym.st_name(endian);
|
||||
ParsedSym {
|
||||
address,
|
||||
size,
|
||||
name,
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
syms.sort_unstable_by_key(|s| s.address);
|
||||
Some(Object {
|
||||
endian,
|
||||
data,
|
||||
sections,
|
||||
strings,
|
||||
syms,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn section(&self, stash: &'a Stash, name: &str) -> Option<&'a [u8]> {
|
||||
if let Some(section) = self.section_header(name) {
|
||||
let mut data = Bytes(section.data(self.endian, self.data).ok()?);
|
||||
|
||||
// Check for DWARF-standard (gABI) compression, i.e., as generated
|
||||
// by ld's `--compress-debug-sections=zlib-gabi` flag.
|
||||
let flags: u64 = section.sh_flags(self.endian).into();
|
||||
if (flags & u64::from(SHF_COMPRESSED)) == 0 {
|
||||
// Not compressed.
|
||||
return Some(data.0);
|
||||
}
|
||||
|
||||
let header = data.read::<<Elf as FileHeader>::CompressionHeader>().ok()?;
|
||||
if header.ch_type(self.endian) != ELFCOMPRESS_ZLIB {
|
||||
// Zlib compression is the only known type.
|
||||
return None;
|
||||
}
|
||||
let size = usize::try_from(header.ch_size(self.endian)).ok()?;
|
||||
let buf = stash.allocate(size);
|
||||
decompress_zlib(data.0, buf)?;
|
||||
return Some(buf);
|
||||
}
|
||||
|
||||
// Check for the nonstandard GNU compression format, i.e., as generated
|
||||
// by ld's `--compress-debug-sections=zlib-gnu` flag. This means that if
|
||||
// we're actually asking for `.debug_info` then we need to look up a
|
||||
// section named `.zdebug_info`.
|
||||
if !name.starts_with(".debug_") {
|
||||
return None;
|
||||
}
|
||||
let debug_name = name[7..].as_bytes();
|
||||
let compressed_section = self
|
||||
.sections
|
||||
.iter()
|
||||
.filter_map(|header| {
|
||||
let name = self.sections.section_name(self.endian, header).ok()?;
|
||||
if name.starts_with(b".zdebug_") && &name[8..] == debug_name {
|
||||
Some(header)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.next()?;
|
||||
let mut data = Bytes(compressed_section.data(self.endian, self.data).ok()?);
|
||||
if data.read_bytes(8).ok()?.0 != b"ZLIB\0\0\0\0" {
|
||||
return None;
|
||||
}
|
||||
let size = usize::try_from(data.read::<object::U32Bytes<_>>().ok()?.get(BigEndian)).ok()?;
|
||||
let buf = stash.allocate(size);
|
||||
decompress_zlib(data.0, buf)?;
|
||||
Some(buf)
|
||||
}
|
||||
|
||||
fn section_header(&self, name: &str) -> Option<&<Elf as FileHeader>::SectionHeader> {
|
||||
self.sections
|
||||
.section_by_name(self.endian, name.as_bytes())
|
||||
.map(|(_index, section)| section)
|
||||
}
|
||||
|
||||
pub fn search_symtab<'b>(&'b self, addr: u64) -> Option<&'b [u8]> {
|
||||
// Same sort of binary search as Windows above
|
||||
let i = match self.syms.binary_search_by_key(&addr, |sym| sym.address) {
|
||||
Ok(i) => i,
|
||||
Err(i) => i.checked_sub(1)?,
|
||||
};
|
||||
let sym = self.syms.get(i)?;
|
||||
if sym.address <= addr && addr <= sym.address + sym.size {
|
||||
self.strings.get(sym.name).ok()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn search_object_map(&self, _addr: u64) -> Option<(&Context<'_>, u64)> {
|
||||
None
|
||||
}
|
||||
|
||||
fn build_id(&self) -> Option<&'a [u8]> {
|
||||
for section in self.sections.iter() {
|
||||
if let Ok(Some(mut notes)) = section.notes(self.endian, self.data) {
|
||||
while let Ok(Some(note)) = notes.next() {
|
||||
if note.name() == ELF_NOTE_GNU && note.n_type(self.endian) == NT_GNU_BUILD_ID {
|
||||
return Some(note.desc());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
// The contents of the ".gnu_debuglink" section is documented at:
|
||||
// https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html
|
||||
fn gnu_debuglink_path(&self, path: &Path) -> Option<(PathBuf, u32)> {
|
||||
let section = self.section_header(".gnu_debuglink")?;
|
||||
let data = section.data(self.endian, self.data).ok()?;
|
||||
let len = data.iter().position(|x| *x == 0)?;
|
||||
let filename = &data[..len];
|
||||
let offset = (len + 1 + 3) & !3;
|
||||
let crc_bytes = data
|
||||
.get(offset..offset + 4)
|
||||
.and_then(|bytes| bytes.try_into().ok())?;
|
||||
let crc = u32::from_ne_bytes(crc_bytes);
|
||||
let path_debug = locate_debuglink(path, filename)?;
|
||||
Some((path_debug, crc))
|
||||
}
|
||||
|
||||
// The format of the ".gnu_debugaltlink" section is based on gdb.
|
||||
fn gnu_debugaltlink_path(&self, path: &Path) -> Option<(PathBuf, &'a [u8])> {
|
||||
let section = self.section_header(".gnu_debugaltlink")?;
|
||||
let data = section.data(self.endian, self.data).ok()?;
|
||||
let len = data.iter().position(|x| *x == 0)?;
|
||||
let filename = &data[..len];
|
||||
let build_id = &data[len + 1..];
|
||||
let path_sup = locate_debugaltlink(path, filename, build_id)?;
|
||||
Some((path_sup, build_id))
|
||||
}
|
||||
}
|
||||
|
||||
fn decompress_zlib(input: &[u8], output: &mut [u8]) -> Option<()> {
|
||||
use miniz_oxide::inflate::core::inflate_flags::{
|
||||
TINFL_FLAG_PARSE_ZLIB_HEADER, TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF,
|
||||
};
|
||||
use miniz_oxide::inflate::core::{decompress, DecompressorOxide};
|
||||
use miniz_oxide::inflate::TINFLStatus;
|
||||
|
||||
let (status, in_read, out_read) = decompress(
|
||||
&mut DecompressorOxide::new(),
|
||||
input,
|
||||
output,
|
||||
0,
|
||||
TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | TINFL_FLAG_PARSE_ZLIB_HEADER,
|
||||
);
|
||||
if status == TINFLStatus::Done && in_read == input.len() && out_read == output.len() {
|
||||
Some(())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
const DEBUG_PATH: &[u8] = b"/usr/lib/debug";
|
||||
|
||||
fn debug_path_exists() -> bool {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(any(target_os = "freebsd", target_os = "linux"))] {
|
||||
use core::sync::atomic::{AtomicU8, Ordering};
|
||||
static DEBUG_PATH_EXISTS: AtomicU8 = AtomicU8::new(0);
|
||||
|
||||
let mut exists = DEBUG_PATH_EXISTS.load(Ordering::Relaxed);
|
||||
if exists == 0 {
|
||||
exists = if Path::new(OsStr::from_bytes(DEBUG_PATH)).is_dir() {
|
||||
1
|
||||
} else {
|
||||
2
|
||||
};
|
||||
DEBUG_PATH_EXISTS.store(exists, Ordering::Relaxed);
|
||||
}
|
||||
exists == 1
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Locate a debug file based on its build ID.
|
||||
///
|
||||
/// The format of build id paths is documented at:
|
||||
/// https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html
|
||||
fn locate_build_id(build_id: &[u8]) -> Option<PathBuf> {
|
||||
const BUILD_ID_PATH: &[u8] = b"/usr/lib/debug/.build-id/";
|
||||
const BUILD_ID_SUFFIX: &[u8] = b".debug";
|
||||
|
||||
if build_id.len() < 2 {
|
||||
return None;
|
||||
}
|
||||
|
||||
if !debug_path_exists() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut path =
|
||||
Vec::with_capacity(BUILD_ID_PATH.len() + BUILD_ID_SUFFIX.len() + build_id.len() * 2 + 1);
|
||||
path.extend(BUILD_ID_PATH);
|
||||
path.push(hex(build_id[0] >> 4));
|
||||
path.push(hex(build_id[0] & 0xf));
|
||||
path.push(b'/');
|
||||
for byte in &build_id[1..] {
|
||||
path.push(hex(byte >> 4));
|
||||
path.push(hex(byte & 0xf));
|
||||
}
|
||||
path.extend(BUILD_ID_SUFFIX);
|
||||
Some(PathBuf::from(OsString::from_vec(path)))
|
||||
}
|
||||
|
||||
fn hex(byte: u8) -> u8 {
|
||||
if byte < 10 {
|
||||
b'0' + byte
|
||||
} else {
|
||||
b'a' + byte - 10
|
||||
}
|
||||
}
|
||||
|
||||
/// Locate a file specified in a `.gnu_debuglink` section.
|
||||
///
|
||||
/// `path` is the file containing the section.
|
||||
/// `filename` is from the contents of the section.
|
||||
///
|
||||
/// Search order is based on gdb, documented at:
|
||||
/// https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html
|
||||
///
|
||||
/// gdb also allows the user to customize the debug search path, but we don't.
|
||||
///
|
||||
/// gdb also supports debuginfod, but we don't yet.
|
||||
fn locate_debuglink(path: &Path, filename: &[u8]) -> Option<PathBuf> {
|
||||
let path = fs::canonicalize(path).ok()?;
|
||||
let parent = path.parent()?;
|
||||
let mut f = PathBuf::from(OsString::with_capacity(
|
||||
DEBUG_PATH.len() + parent.as_os_str().len() + filename.len() + 2,
|
||||
));
|
||||
let filename = Path::new(OsStr::from_bytes(filename));
|
||||
|
||||
// Try "/parent/filename" if it differs from "path"
|
||||
f.push(parent);
|
||||
f.push(filename);
|
||||
if f != path && f.is_file() {
|
||||
return Some(f);
|
||||
}
|
||||
|
||||
// Try "/parent/.debug/filename"
|
||||
let mut s = OsString::from(f);
|
||||
s.clear();
|
||||
f = PathBuf::from(s);
|
||||
f.push(parent);
|
||||
f.push(".debug");
|
||||
f.push(filename);
|
||||
if f.is_file() {
|
||||
return Some(f);
|
||||
}
|
||||
|
||||
if debug_path_exists() {
|
||||
// Try "/usr/lib/debug/parent/filename"
|
||||
let mut s = OsString::from(f);
|
||||
s.clear();
|
||||
f = PathBuf::from(s);
|
||||
f.push(OsStr::from_bytes(DEBUG_PATH));
|
||||
f.push(parent.strip_prefix("/").unwrap());
|
||||
f.push(filename);
|
||||
if f.is_file() {
|
||||
return Some(f);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// Locate a file specified in a `.gnu_debugaltlink` section.
|
||||
///
|
||||
/// `path` is the file containing the section.
|
||||
/// `filename` and `build_id` are the contents of the section.
|
||||
///
|
||||
/// Search order is based on gdb:
|
||||
/// - filename, which is either absolute or relative to `path`
|
||||
/// - the build ID path under `BUILD_ID_PATH`
|
||||
///
|
||||
/// gdb also allows the user to customize the debug search path, but we don't.
|
||||
///
|
||||
/// gdb also supports debuginfod, but we don't yet.
|
||||
fn locate_debugaltlink(path: &Path, filename: &[u8], build_id: &[u8]) -> Option<PathBuf> {
|
||||
let filename = Path::new(OsStr::from_bytes(filename));
|
||||
if filename.is_absolute() {
|
||||
if filename.is_file() {
|
||||
return Some(filename.into());
|
||||
}
|
||||
} else {
|
||||
let path = fs::canonicalize(path).ok()?;
|
||||
let parent = path.parent()?;
|
||||
let mut f = PathBuf::from(parent);
|
||||
f.push(filename);
|
||||
if f.is_file() {
|
||||
return Some(f);
|
||||
}
|
||||
}
|
||||
|
||||
locate_build_id(build_id)
|
||||
}
|
||||
|
||||
fn convert_path<R: gimli::Reader>(r: &R) -> Result<PathBuf, gimli::Error> {
|
||||
let bytes = r.to_slice()?;
|
||||
Ok(PathBuf::from(OsStr::from_bytes(&bytes)))
|
||||
}
|
||||
|
||||
pub(super) fn handle_split_dwarf<'data>(
|
||||
package: Option<&gimli::DwarfPackage<EndianSlice<'data, Endian>>>,
|
||||
stash: &'data Stash,
|
||||
load: addr2line::SplitDwarfLoad<EndianSlice<'data, Endian>>,
|
||||
) -> Option<Arc<gimli::Dwarf<EndianSlice<'data, Endian>>>> {
|
||||
if let Some(dwp) = package.as_ref() {
|
||||
if let Ok(Some(cu)) = dwp.find_cu(load.dwo_id, &load.parent) {
|
||||
return Some(Arc::new(cu));
|
||||
}
|
||||
}
|
||||
|
||||
let mut path = PathBuf::new();
|
||||
if let Some(p) = load.comp_dir.as_ref() {
|
||||
path.push(convert_path(p).ok()?);
|
||||
}
|
||||
|
||||
path.push(convert_path(load.path.as_ref()?).ok()?);
|
||||
|
||||
if let Some(map_dwo) = super::mmap(&path) {
|
||||
let map_dwo = stash.cache_mmap(map_dwo);
|
||||
if let Some(dwo) = Object::parse(map_dwo) {
|
||||
return gimli::Dwarf::load(|id| -> Result<_, ()> {
|
||||
let data = id
|
||||
.dwo_name()
|
||||
.and_then(|name| dwo.section(stash, name))
|
||||
.unwrap_or(&[]);
|
||||
Ok(EndianSlice::new(data, Endian))
|
||||
})
|
||||
.ok()
|
||||
.map(|mut dwo_dwarf| {
|
||||
dwo_dwarf.make_dwo(&load.parent);
|
||||
Arc::new(dwo_dwarf)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
71
.gear/predownloaded-development/vendor/backtrace/src/symbolize/gimli/libs_dl_iterate_phdr.rs
vendored
Normal file
71
.gear/predownloaded-development/vendor/backtrace/src/symbolize/gimli/libs_dl_iterate_phdr.rs
vendored
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
// Other Unix (e.g. Linux) platforms use ELF as an object file format
|
||||
// and typically implement an API called `dl_iterate_phdr` to load
|
||||
// native libraries.
|
||||
|
||||
use super::mystd::borrow::ToOwned;
|
||||
use super::mystd::env;
|
||||
use super::mystd::ffi::{CStr, OsStr};
|
||||
use super::mystd::os::unix::prelude::*;
|
||||
use super::{Library, LibrarySegment, OsString, Vec};
|
||||
use core::slice;
|
||||
|
||||
pub(super) fn native_libraries() -> Vec<Library> {
|
||||
let mut ret = Vec::new();
|
||||
unsafe {
|
||||
libc::dl_iterate_phdr(Some(callback), &mut ret as *mut Vec<_> as *mut _);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
fn infer_current_exe(base_addr: usize) -> OsString {
|
||||
if let Ok(entries) = super::parse_running_mmaps::parse_maps() {
|
||||
let opt_path = entries
|
||||
.iter()
|
||||
.find(|e| e.ip_matches(base_addr) && e.pathname().len() > 0)
|
||||
.map(|e| e.pathname())
|
||||
.cloned();
|
||||
if let Some(path) = opt_path {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
env::current_exe().map(|e| e.into()).unwrap_or_default()
|
||||
}
|
||||
|
||||
// `info` should be a valid pointers.
|
||||
// `vec` should be a valid pointer to a `std::Vec`.
|
||||
unsafe extern "C" fn callback(
|
||||
info: *mut libc::dl_phdr_info,
|
||||
_size: libc::size_t,
|
||||
vec: *mut libc::c_void,
|
||||
) -> libc::c_int {
|
||||
let info = &*info;
|
||||
let libs = &mut *(vec as *mut Vec<Library>);
|
||||
let is_main_prog = info.dlpi_name.is_null() || *info.dlpi_name == 0;
|
||||
let name = if is_main_prog {
|
||||
// The man page for dl_iterate_phdr says that the first object visited by
|
||||
// callback is the main program; so the first time we encounter a
|
||||
// nameless entry, we can assume its the main program and try to infer its path.
|
||||
// After that, we cannot continue that assumption, and we use an empty string.
|
||||
if libs.is_empty() {
|
||||
infer_current_exe(info.dlpi_addr as usize)
|
||||
} else {
|
||||
OsString::new()
|
||||
}
|
||||
} else {
|
||||
let bytes = CStr::from_ptr(info.dlpi_name).to_bytes();
|
||||
OsStr::from_bytes(bytes).to_owned()
|
||||
};
|
||||
let headers = slice::from_raw_parts(info.dlpi_phdr, info.dlpi_phnum as usize);
|
||||
libs.push(Library {
|
||||
name,
|
||||
segments: headers
|
||||
.iter()
|
||||
.map(|header| LibrarySegment {
|
||||
len: (*header).p_memsz as usize,
|
||||
stated_virtual_memory_address: (*header).p_vaddr as usize,
|
||||
})
|
||||
.collect(),
|
||||
bias: info.dlpi_addr as usize,
|
||||
});
|
||||
0
|
||||
}
|
||||
48
.gear/predownloaded-development/vendor/backtrace/src/symbolize/gimli/libs_haiku.rs
vendored
Normal file
48
.gear/predownloaded-development/vendor/backtrace/src/symbolize/gimli/libs_haiku.rs
vendored
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
// Haiku implements the image_info struct and the get_next_image_info()
|
||||
// functions to iterate through the loaded executable images. The
|
||||
// image_info struct contains a pointer to the start of the .text
|
||||
// section within the virtual address space, as well as the size of
|
||||
// that section. All the read-only segments of the ELF-binary are in
|
||||
// that part of the address space.
|
||||
|
||||
use super::mystd::borrow::ToOwned;
|
||||
use super::mystd::ffi::{CStr, OsStr};
|
||||
use super::mystd::mem::MaybeUninit;
|
||||
use super::mystd::os::unix::prelude::*;
|
||||
use super::{Library, LibrarySegment, Vec};
|
||||
|
||||
pub(super) fn native_libraries() -> Vec<Library> {
|
||||
let mut libraries: Vec<Library> = Vec::new();
|
||||
|
||||
unsafe {
|
||||
let mut info = MaybeUninit::<libc::image_info>::zeroed();
|
||||
let mut cookie: i32 = 0;
|
||||
// Load the first image to get a valid info struct
|
||||
let mut status =
|
||||
libc::get_next_image_info(libc::B_CURRENT_TEAM, &mut cookie, info.as_mut_ptr());
|
||||
if status != libc::B_OK {
|
||||
return libraries;
|
||||
}
|
||||
let mut info = info.assume_init();
|
||||
|
||||
while status == libc::B_OK {
|
||||
let mut segments = Vec::new();
|
||||
segments.push(LibrarySegment {
|
||||
stated_virtual_memory_address: 0,
|
||||
len: info.text_size as usize,
|
||||
});
|
||||
|
||||
let bytes = CStr::from_ptr(info.name.as_ptr()).to_bytes();
|
||||
let name = OsStr::from_bytes(bytes).to_owned();
|
||||
libraries.push(Library {
|
||||
name: name,
|
||||
segments: segments,
|
||||
bias: info.text as usize,
|
||||
});
|
||||
|
||||
status = libc::get_next_image_info(libc::B_CURRENT_TEAM, &mut cookie, &mut info);
|
||||
}
|
||||
}
|
||||
|
||||
libraries
|
||||
}
|
||||
99
.gear/predownloaded-development/vendor/backtrace/src/symbolize/gimli/libs_illumos.rs
vendored
Normal file
99
.gear/predownloaded-development/vendor/backtrace/src/symbolize/gimli/libs_illumos.rs
vendored
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
use super::mystd::borrow::ToOwned;
|
||||
use super::mystd::ffi::{CStr, OsStr};
|
||||
use super::mystd::os::unix::prelude::*;
|
||||
use super::{Library, LibrarySegment, Vec};
|
||||
use core::mem;
|
||||
use object::NativeEndian;
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
use object::elf::{FileHeader64 as FileHeader, ProgramHeader64 as ProgramHeader};
|
||||
|
||||
type EHdr = FileHeader<NativeEndian>;
|
||||
type PHdr = ProgramHeader<NativeEndian>;
|
||||
|
||||
#[repr(C)]
|
||||
struct LinkMap {
|
||||
l_addr: libc::c_ulong,
|
||||
l_name: *const libc::c_char,
|
||||
l_ld: *const libc::c_void,
|
||||
l_next: *const LinkMap,
|
||||
l_prev: *const LinkMap,
|
||||
l_refname: *const libc::c_char,
|
||||
}
|
||||
|
||||
const RTLD_SELF: *const libc::c_void = -3isize as *const libc::c_void;
|
||||
const RTLD_DI_LINKMAP: libc::c_int = 2;
|
||||
|
||||
extern "C" {
|
||||
fn dlinfo(
|
||||
handle: *const libc::c_void,
|
||||
request: libc::c_int,
|
||||
p: *mut libc::c_void,
|
||||
) -> libc::c_int;
|
||||
}
|
||||
|
||||
pub(super) fn native_libraries() -> Vec<Library> {
|
||||
let mut libs = Vec::new();
|
||||
|
||||
// Request the current link map from the runtime linker:
|
||||
let map = unsafe {
|
||||
let mut map: *const LinkMap = mem::zeroed();
|
||||
if dlinfo(
|
||||
RTLD_SELF,
|
||||
RTLD_DI_LINKMAP,
|
||||
(&mut map) as *mut *const LinkMap as *mut libc::c_void,
|
||||
) != 0
|
||||
{
|
||||
return libs;
|
||||
}
|
||||
map
|
||||
};
|
||||
|
||||
// Each entry in the link map represents a loaded object:
|
||||
let mut l = map;
|
||||
while !l.is_null() {
|
||||
// Fetch the fully qualified path of the loaded object:
|
||||
let bytes = unsafe { CStr::from_ptr((*l).l_name) }.to_bytes();
|
||||
let name = OsStr::from_bytes(bytes).to_owned();
|
||||
|
||||
// The base address of the object loaded into memory:
|
||||
let addr = unsafe { (*l).l_addr };
|
||||
|
||||
// Use the ELF header for this object to locate the program
|
||||
// header:
|
||||
let e: *const EHdr = unsafe { (*l).l_addr as *const EHdr };
|
||||
let phoff = unsafe { (*e).e_phoff }.get(NativeEndian);
|
||||
let phnum = unsafe { (*e).e_phnum }.get(NativeEndian);
|
||||
let etype = unsafe { (*e).e_type }.get(NativeEndian);
|
||||
|
||||
let phdr: *const PHdr = (addr + phoff) as *const PHdr;
|
||||
let phdr = unsafe { core::slice::from_raw_parts(phdr, phnum as usize) };
|
||||
|
||||
libs.push(Library {
|
||||
name,
|
||||
segments: phdr
|
||||
.iter()
|
||||
.map(|p| {
|
||||
let memsz = p.p_memsz.get(NativeEndian);
|
||||
let vaddr = p.p_vaddr.get(NativeEndian);
|
||||
LibrarySegment {
|
||||
len: memsz as usize,
|
||||
stated_virtual_memory_address: vaddr as usize,
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
bias: if etype == object::elf::ET_EXEC {
|
||||
// Program header addresses for the base executable are
|
||||
// already absolute.
|
||||
0
|
||||
} else {
|
||||
// Other addresses are relative to the object base.
|
||||
addr as usize
|
||||
},
|
||||
});
|
||||
|
||||
l = unsafe { (*l).l_next };
|
||||
}
|
||||
|
||||
libs
|
||||
}
|
||||
27
.gear/predownloaded-development/vendor/backtrace/src/symbolize/gimli/libs_libnx.rs
vendored
Normal file
27
.gear/predownloaded-development/vendor/backtrace/src/symbolize/gimli/libs_libnx.rs
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
use super::{Library, LibrarySegment, Vec};
|
||||
|
||||
// DevkitA64 doesn't natively support debug info, but the build system will
|
||||
// place debug info at the path `romfs:/debug_info.elf`.
|
||||
pub(super) fn native_libraries() -> Vec<Library> {
|
||||
extern "C" {
|
||||
static __start__: u8;
|
||||
}
|
||||
|
||||
let bias = unsafe { &__start__ } as *const u8 as usize;
|
||||
|
||||
let mut ret = Vec::new();
|
||||
let mut segments = Vec::new();
|
||||
segments.push(LibrarySegment {
|
||||
stated_virtual_memory_address: 0,
|
||||
len: usize::max_value() - bias,
|
||||
});
|
||||
|
||||
let path = "romfs:/debug_info.elf";
|
||||
ret.push(Library {
|
||||
name: path.into(),
|
||||
segments,
|
||||
bias,
|
||||
});
|
||||
|
||||
ret
|
||||
}
|
||||
146
.gear/predownloaded-development/vendor/backtrace/src/symbolize/gimli/libs_macos.rs
vendored
Normal file
146
.gear/predownloaded-development/vendor/backtrace/src/symbolize/gimli/libs_macos.rs
vendored
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
#![allow(deprecated)]
|
||||
|
||||
use super::mystd::ffi::{CStr, OsStr};
|
||||
use super::mystd::os::unix::prelude::*;
|
||||
use super::mystd::prelude::v1::*;
|
||||
use super::{Library, LibrarySegment};
|
||||
use core::convert::TryInto;
|
||||
use core::mem;
|
||||
|
||||
pub(super) fn native_libraries() -> Vec<Library> {
|
||||
let mut ret = Vec::new();
|
||||
let images = unsafe { libc::_dyld_image_count() };
|
||||
for i in 0..images {
|
||||
ret.extend(native_library(i));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
fn native_library(i: u32) -> Option<Library> {
|
||||
use object::macho;
|
||||
use object::read::macho::{MachHeader, Segment};
|
||||
use object::NativeEndian;
|
||||
|
||||
// Fetch the name of this library which corresponds to the path of
|
||||
// where to load it as well.
|
||||
let name = unsafe {
|
||||
let name = libc::_dyld_get_image_name(i);
|
||||
if name.is_null() {
|
||||
return None;
|
||||
}
|
||||
CStr::from_ptr(name)
|
||||
};
|
||||
|
||||
// Load the image header of this library and delegate to `object` to
|
||||
// parse all the load commands so we can figure out all the segments
|
||||
// involved here.
|
||||
let (mut load_commands, endian) = unsafe {
|
||||
let header = libc::_dyld_get_image_header(i);
|
||||
if header.is_null() {
|
||||
return None;
|
||||
}
|
||||
match (*header).magic {
|
||||
macho::MH_MAGIC => {
|
||||
let endian = NativeEndian;
|
||||
let header = &*(header as *const macho::MachHeader32<NativeEndian>);
|
||||
let data = core::slice::from_raw_parts(
|
||||
header as *const _ as *const u8,
|
||||
mem::size_of_val(header) + header.sizeofcmds.get(endian) as usize,
|
||||
);
|
||||
(header.load_commands(endian, data, 0).ok()?, endian)
|
||||
}
|
||||
macho::MH_MAGIC_64 => {
|
||||
let endian = NativeEndian;
|
||||
let header = &*(header as *const macho::MachHeader64<NativeEndian>);
|
||||
let data = core::slice::from_raw_parts(
|
||||
header as *const _ as *const u8,
|
||||
mem::size_of_val(header) + header.sizeofcmds.get(endian) as usize,
|
||||
);
|
||||
(header.load_commands(endian, data, 0).ok()?, endian)
|
||||
}
|
||||
_ => return None,
|
||||
}
|
||||
};
|
||||
|
||||
// Iterate over the segments and register known regions for segments
|
||||
// that we find. Additionally record information bout text segments
|
||||
// for processing later, see comments below.
|
||||
let mut segments = Vec::new();
|
||||
let mut first_text = 0;
|
||||
let mut text_fileoff_zero = false;
|
||||
while let Some(cmd) = load_commands.next().ok()? {
|
||||
if let Some((seg, _)) = cmd.segment_32().ok()? {
|
||||
if seg.name() == b"__TEXT" {
|
||||
first_text = segments.len();
|
||||
if seg.fileoff(endian) == 0 && seg.filesize(endian) > 0 {
|
||||
text_fileoff_zero = true;
|
||||
}
|
||||
}
|
||||
segments.push(LibrarySegment {
|
||||
len: seg.vmsize(endian).try_into().ok()?,
|
||||
stated_virtual_memory_address: seg.vmaddr(endian).try_into().ok()?,
|
||||
});
|
||||
}
|
||||
if let Some((seg, _)) = cmd.segment_64().ok()? {
|
||||
if seg.name() == b"__TEXT" {
|
||||
first_text = segments.len();
|
||||
if seg.fileoff(endian) == 0 && seg.filesize(endian) > 0 {
|
||||
text_fileoff_zero = true;
|
||||
}
|
||||
}
|
||||
segments.push(LibrarySegment {
|
||||
len: seg.vmsize(endian).try_into().ok()?,
|
||||
stated_virtual_memory_address: seg.vmaddr(endian).try_into().ok()?,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Determine the "slide" for this library which ends up being the
|
||||
// bias we use to figure out where in memory objects are loaded.
|
||||
// This is a bit of a weird computation though and is the result of
|
||||
// trying a few things in the wild and seeing what sticks.
|
||||
//
|
||||
// The general idea is that the `bias` plus a segment's
|
||||
// `stated_virtual_memory_address` is going to be where in the
|
||||
// actual address space the segment resides. The other thing we rely
|
||||
// on though is that a real address minus the `bias` is the index to
|
||||
// look up in the symbol table and debuginfo.
|
||||
//
|
||||
// It turns out, though, that for system loaded libraries these
|
||||
// calculations are incorrect. For native executables, however, it
|
||||
// appears correct. Lifting some logic from LLDB's source it has
|
||||
// some special-casing for the first `__TEXT` section loaded from
|
||||
// file offset 0 with a nonzero size. For whatever reason when this
|
||||
// is present it appears to mean that the symbol table is relative
|
||||
// to just the vmaddr slide for the library. If it's *not* present
|
||||
// then the symbol table is relative to the vmaddr slide plus the
|
||||
// segment's stated address.
|
||||
//
|
||||
// To handle this situation if we *don't* find a text section at
|
||||
// file offset zero then we increase the bias by the first text
|
||||
// sections's stated address and decrease all stated addresses by
|
||||
// that amount as well. That way the symbol table is always appears
|
||||
// relative to the library's bias amount. This appears to have the
|
||||
// right results for symbolizing via the symbol table.
|
||||
//
|
||||
// Honestly I'm not entirely sure whether this is right or if
|
||||
// there's something else that should indicate how to do this. For
|
||||
// now though this seems to work well enough (?) and we should
|
||||
// always be able to tweak this over time if necessary.
|
||||
//
|
||||
// For some more information see #318
|
||||
let mut slide = unsafe { libc::_dyld_get_image_vmaddr_slide(i) as usize };
|
||||
if !text_fileoff_zero {
|
||||
let adjust = segments[first_text].stated_virtual_memory_address;
|
||||
for segment in segments.iter_mut() {
|
||||
segment.stated_virtual_memory_address -= adjust;
|
||||
}
|
||||
slide += adjust;
|
||||
}
|
||||
|
||||
Some(Library {
|
||||
name: OsStr::from_bytes(name.to_bytes()).to_owned(),
|
||||
segments,
|
||||
bias: slide,
|
||||
})
|
||||
}
|
||||
89
.gear/predownloaded-development/vendor/backtrace/src/symbolize/gimli/libs_windows.rs
vendored
Normal file
89
.gear/predownloaded-development/vendor/backtrace/src/symbolize/gimli/libs_windows.rs
vendored
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
use super::super::super::windows::*;
|
||||
use super::mystd::os::windows::prelude::*;
|
||||
use super::{coff, mmap, Library, LibrarySegment, OsString};
|
||||
use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
use core::mem;
|
||||
use core::mem::MaybeUninit;
|
||||
|
||||
// For loading native libraries on Windows, see some discussion on
|
||||
// rust-lang/rust#71060 for the various strategies here.
|
||||
pub(super) fn native_libraries() -> Vec<Library> {
|
||||
let mut ret = Vec::new();
|
||||
unsafe {
|
||||
add_loaded_images(&mut ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
unsafe fn add_loaded_images(ret: &mut Vec<Library>) {
|
||||
let snap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, 0);
|
||||
if snap == INVALID_HANDLE_VALUE {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut me = MaybeUninit::<MODULEENTRY32W>::zeroed().assume_init();
|
||||
me.dwSize = mem::size_of_val(&me) as DWORD;
|
||||
if Module32FirstW(snap, &mut me) == TRUE {
|
||||
loop {
|
||||
if let Some(lib) = load_library(&me) {
|
||||
ret.push(lib);
|
||||
}
|
||||
|
||||
if Module32NextW(snap, &mut me) != TRUE {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CloseHandle(snap);
|
||||
}
|
||||
|
||||
unsafe fn load_library(me: &MODULEENTRY32W) -> Option<Library> {
|
||||
let pos = me
|
||||
.szExePath
|
||||
.iter()
|
||||
.position(|i| *i == 0)
|
||||
.unwrap_or(me.szExePath.len());
|
||||
let name = OsString::from_wide(&me.szExePath[..pos]);
|
||||
|
||||
// MinGW libraries currently don't support ASLR
|
||||
// (rust-lang/rust#16514), but DLLs can still be relocated around in
|
||||
// the address space. It appears that addresses in debug info are
|
||||
// all as-if this library was loaded at its "image base", which is a
|
||||
// field in its COFF file headers. Since this is what debuginfo
|
||||
// seems to list we parse the symbol table and store addresses as if
|
||||
// the library was loaded at "image base" as well.
|
||||
//
|
||||
// The library may not be loaded at "image base", however.
|
||||
// (presumably something else may be loaded there?) This is where
|
||||
// the `bias` field comes into play, and we need to figure out the
|
||||
// value of `bias` here. Unfortunately though it's not clear how to
|
||||
// acquire this from a loaded module. What we do have, however, is
|
||||
// the actual load address (`modBaseAddr`).
|
||||
//
|
||||
// As a bit of a cop-out for now we mmap the file, read the file
|
||||
// header information, then drop the mmap. This is wasteful because
|
||||
// we'll probably reopen the mmap later, but this should work well
|
||||
// enough for now.
|
||||
//
|
||||
// Once we have the `image_base` (desired load location) and the
|
||||
// `base_addr` (actual load location) we can fill in the `bias`
|
||||
// (difference between the actual and desired) and then the stated
|
||||
// address of each segment is the `image_base` since that's what the
|
||||
// file says.
|
||||
//
|
||||
// For now it appears that unlike ELF/MachO we can make do with one
|
||||
// segment per library, using `modBaseSize` as the whole size.
|
||||
let mmap = mmap(name.as_ref())?;
|
||||
let image_base = coff::get_image_base(&mmap)?;
|
||||
let base_addr = me.modBaseAddr as usize;
|
||||
Some(Library {
|
||||
name,
|
||||
bias: base_addr.wrapping_sub(image_base),
|
||||
segments: vec![LibrarySegment {
|
||||
stated_virtual_memory_address: image_base,
|
||||
len: me.modBaseSize as usize,
|
||||
}],
|
||||
})
|
||||
}
|
||||
333
.gear/predownloaded-development/vendor/backtrace/src/symbolize/gimli/macho.rs
vendored
Normal file
333
.gear/predownloaded-development/vendor/backtrace/src/symbolize/gimli/macho.rs
vendored
Normal file
|
|
@ -0,0 +1,333 @@
|
|||
use super::{gimli, Box, Context, Endian, EndianSlice, Mapping, Path, Stash, Vec};
|
||||
use alloc::sync::Arc;
|
||||
use core::convert::TryInto;
|
||||
use object::macho;
|
||||
use object::read::macho::{MachHeader, Nlist, Section, Segment as _};
|
||||
use object::{Bytes, NativeEndian};
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
type Mach = object::macho::MachHeader32<NativeEndian>;
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
type Mach = object::macho::MachHeader64<NativeEndian>;
|
||||
type MachSegment = <Mach as MachHeader>::Segment;
|
||||
type MachSection = <Mach as MachHeader>::Section;
|
||||
type MachNlist = <Mach as MachHeader>::Nlist;
|
||||
|
||||
impl Mapping {
|
||||
// The loading path for macOS is so different we just have a completely
|
||||
// different implementation of the function here. On macOS we need to go
|
||||
// probing the filesystem for a bunch of files.
|
||||
pub fn new(path: &Path) -> Option<Mapping> {
|
||||
// First up we need to load the unique UUID which is stored in the macho
|
||||
// header of the file we're reading, specified at `path`.
|
||||
let map = super::mmap(path)?;
|
||||
let (macho, data) = find_header(&map)?;
|
||||
let endian = macho.endian().ok()?;
|
||||
let uuid = macho.uuid(endian, data, 0).ok()?;
|
||||
|
||||
// Next we need to look for a `*.dSYM` file. For now we just probe the
|
||||
// containing directory and look around for something that matches
|
||||
// `*.dSYM`. Once it's found we root through the dwarf resources that it
|
||||
// contains and try to find a macho file which has a matching UUID as
|
||||
// the one of our own file. If we find a match that's the dwarf file we
|
||||
// want to return.
|
||||
if let Some(uuid) = uuid {
|
||||
if let Some(parent) = path.parent() {
|
||||
if let Some(mapping) = Mapping::load_dsym(parent, uuid) {
|
||||
return Some(mapping);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Looks like nothing matched our UUID, so let's at least return our own
|
||||
// file. This should have the symbol table for at least some
|
||||
// symbolication purposes.
|
||||
Mapping::mk(map, |data, stash| {
|
||||
let (macho, data) = find_header(data)?;
|
||||
let endian = macho.endian().ok()?;
|
||||
let obj = Object::parse(macho, endian, data)?;
|
||||
Context::new(stash, obj, None, None)
|
||||
})
|
||||
}
|
||||
|
||||
fn load_dsym(dir: &Path, uuid: [u8; 16]) -> Option<Mapping> {
|
||||
for entry in dir.read_dir().ok()? {
|
||||
let entry = entry.ok()?;
|
||||
let filename = match entry.file_name().into_string() {
|
||||
Ok(name) => name,
|
||||
Err(_) => continue,
|
||||
};
|
||||
if !filename.ends_with(".dSYM") {
|
||||
continue;
|
||||
}
|
||||
let candidates = entry.path().join("Contents/Resources/DWARF");
|
||||
if let Some(mapping) = Mapping::try_dsym_candidate(&candidates, uuid) {
|
||||
return Some(mapping);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn try_dsym_candidate(dir: &Path, uuid: [u8; 16]) -> Option<Mapping> {
|
||||
// Look for files in the `DWARF` directory which have a matching uuid to
|
||||
// the original object file. If we find one then we found the debug
|
||||
// information.
|
||||
for entry in dir.read_dir().ok()? {
|
||||
let entry = entry.ok()?;
|
||||
let map = super::mmap(&entry.path())?;
|
||||
let candidate = Mapping::mk(map, |data, stash| {
|
||||
let (macho, data) = find_header(data)?;
|
||||
let endian = macho.endian().ok()?;
|
||||
let entry_uuid = macho.uuid(endian, data, 0).ok()??;
|
||||
if entry_uuid != uuid {
|
||||
return None;
|
||||
}
|
||||
let obj = Object::parse(macho, endian, data)?;
|
||||
Context::new(stash, obj, None, None)
|
||||
});
|
||||
if let Some(candidate) = candidate {
|
||||
return Some(candidate);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn find_header(data: &'_ [u8]) -> Option<(&'_ Mach, &'_ [u8])> {
|
||||
use object::endian::BigEndian;
|
||||
|
||||
let desired_cpu = || {
|
||||
if cfg!(target_arch = "x86") {
|
||||
Some(macho::CPU_TYPE_X86)
|
||||
} else if cfg!(target_arch = "x86_64") {
|
||||
Some(macho::CPU_TYPE_X86_64)
|
||||
} else if cfg!(target_arch = "arm") {
|
||||
Some(macho::CPU_TYPE_ARM)
|
||||
} else if cfg!(target_arch = "aarch64") {
|
||||
Some(macho::CPU_TYPE_ARM64)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
let mut data = Bytes(data);
|
||||
match data
|
||||
.clone()
|
||||
.read::<object::endian::U32<NativeEndian>>()
|
||||
.ok()?
|
||||
.get(NativeEndian)
|
||||
{
|
||||
macho::MH_MAGIC_64 | macho::MH_CIGAM_64 | macho::MH_MAGIC | macho::MH_CIGAM => {}
|
||||
|
||||
macho::FAT_MAGIC | macho::FAT_CIGAM => {
|
||||
let mut header_data = data;
|
||||
let endian = BigEndian;
|
||||
let header = header_data.read::<macho::FatHeader>().ok()?;
|
||||
let nfat = header.nfat_arch.get(endian);
|
||||
let arch = (0..nfat)
|
||||
.filter_map(|_| header_data.read::<macho::FatArch32>().ok())
|
||||
.find(|arch| desired_cpu() == Some(arch.cputype.get(endian)))?;
|
||||
let offset = arch.offset.get(endian);
|
||||
let size = arch.size.get(endian);
|
||||
data = data
|
||||
.read_bytes_at(offset.try_into().ok()?, size.try_into().ok()?)
|
||||
.ok()?;
|
||||
}
|
||||
|
||||
macho::FAT_MAGIC_64 | macho::FAT_CIGAM_64 => {
|
||||
let mut header_data = data;
|
||||
let endian = BigEndian;
|
||||
let header = header_data.read::<macho::FatHeader>().ok()?;
|
||||
let nfat = header.nfat_arch.get(endian);
|
||||
let arch = (0..nfat)
|
||||
.filter_map(|_| header_data.read::<macho::FatArch64>().ok())
|
||||
.find(|arch| desired_cpu() == Some(arch.cputype.get(endian)))?;
|
||||
let offset = arch.offset.get(endian);
|
||||
let size = arch.size.get(endian);
|
||||
data = data
|
||||
.read_bytes_at(offset.try_into().ok()?, size.try_into().ok()?)
|
||||
.ok()?;
|
||||
}
|
||||
|
||||
_ => return None,
|
||||
}
|
||||
|
||||
Mach::parse(data.0, 0).ok().map(|h| (h, data.0))
|
||||
}
|
||||
|
||||
// This is used both for executables/libraries and source object files.
|
||||
pub struct Object<'a> {
|
||||
endian: NativeEndian,
|
||||
data: &'a [u8],
|
||||
dwarf: Option<&'a [MachSection]>,
|
||||
syms: Vec<(&'a [u8], u64)>,
|
||||
syms_sort_by_name: bool,
|
||||
// Only set for executables/libraries, and not the source object files.
|
||||
object_map: Option<object::ObjectMap<'a>>,
|
||||
// The outer Option is for lazy loading, and the inner Option allows load errors to be cached.
|
||||
object_mappings: Box<[Option<Option<Mapping>>]>,
|
||||
}
|
||||
|
||||
impl<'a> Object<'a> {
|
||||
fn parse(mach: &'a Mach, endian: NativeEndian, data: &'a [u8]) -> Option<Object<'a>> {
|
||||
let is_object = mach.filetype(endian) == object::macho::MH_OBJECT;
|
||||
let mut dwarf = None;
|
||||
let mut syms = Vec::new();
|
||||
let mut syms_sort_by_name = false;
|
||||
let mut commands = mach.load_commands(endian, data, 0).ok()?;
|
||||
let mut object_map = None;
|
||||
let mut object_mappings = Vec::new();
|
||||
while let Ok(Some(command)) = commands.next() {
|
||||
if let Some((segment, section_data)) = MachSegment::from_command(command).ok()? {
|
||||
// Object files should have all sections in a single unnamed segment load command.
|
||||
if segment.name() == b"__DWARF" || (is_object && segment.name() == b"") {
|
||||
dwarf = segment.sections(endian, section_data).ok();
|
||||
}
|
||||
} else if let Some(symtab) = command.symtab().ok()? {
|
||||
let symbols = symtab.symbols::<Mach, _>(endian, data).ok()?;
|
||||
syms = symbols
|
||||
.iter()
|
||||
.filter_map(|nlist: &MachNlist| {
|
||||
let name = nlist.name(endian, symbols.strings()).ok()?;
|
||||
if name.len() > 0 && nlist.is_definition() {
|
||||
Some((name, u64::from(nlist.n_value(endian))))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
if is_object {
|
||||
// We never search object file symbols by address.
|
||||
// Instead, we already know the symbol name from the executable, and we
|
||||
// need to search by name to find the matching symbol in the object file.
|
||||
syms.sort_unstable_by_key(|(name, _)| *name);
|
||||
syms_sort_by_name = true;
|
||||
} else {
|
||||
syms.sort_unstable_by_key(|(_, addr)| *addr);
|
||||
let map = symbols.object_map(endian);
|
||||
object_mappings.resize_with(map.objects().len(), || None);
|
||||
object_map = Some(map);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some(Object {
|
||||
endian,
|
||||
data,
|
||||
dwarf,
|
||||
syms,
|
||||
syms_sort_by_name,
|
||||
object_map,
|
||||
object_mappings: object_mappings.into_boxed_slice(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn section(&self, _: &Stash, name: &str) -> Option<&'a [u8]> {
|
||||
let name = name.as_bytes();
|
||||
let dwarf = self.dwarf?;
|
||||
let section = dwarf.into_iter().find(|section| {
|
||||
let section_name = section.name();
|
||||
section_name == name || {
|
||||
section_name.starts_with(b"__")
|
||||
&& name.starts_with(b".")
|
||||
&& §ion_name[2..] == &name[1..]
|
||||
}
|
||||
})?;
|
||||
Some(section.data(self.endian, self.data).ok()?)
|
||||
}
|
||||
|
||||
pub fn search_symtab<'b>(&'b self, addr: u64) -> Option<&'b [u8]> {
|
||||
debug_assert!(!self.syms_sort_by_name);
|
||||
let i = match self.syms.binary_search_by_key(&addr, |(_, addr)| *addr) {
|
||||
Ok(i) => i,
|
||||
Err(i) => i.checked_sub(1)?,
|
||||
};
|
||||
let (sym, _addr) = self.syms.get(i)?;
|
||||
Some(sym)
|
||||
}
|
||||
|
||||
/// Try to load a context for an object file.
|
||||
///
|
||||
/// If dsymutil was not run, then the DWARF may be found in the source object files.
|
||||
pub(super) fn search_object_map<'b>(&'b mut self, addr: u64) -> Option<(&Context<'b>, u64)> {
|
||||
// `object_map` contains a map from addresses to symbols and object paths.
|
||||
// Look up the address and get a mapping for the object.
|
||||
let object_map = self.object_map.as_ref()?;
|
||||
let symbol = object_map.get(addr)?;
|
||||
let object_index = symbol.object_index();
|
||||
let mapping = self.object_mappings.get_mut(object_index)?;
|
||||
if mapping.is_none() {
|
||||
// No cached mapping, so create it.
|
||||
*mapping = Some(object_mapping(object_map.objects().get(object_index)?));
|
||||
}
|
||||
let cx: &'b Context<'static> = &mapping.as_ref()?.as_ref()?.cx;
|
||||
// Don't leak the `'static` lifetime, make sure it's scoped to just ourselves.
|
||||
let cx = unsafe { core::mem::transmute::<&'b Context<'static>, &'b Context<'b>>(cx) };
|
||||
|
||||
// We must translate the address in order to be able to look it up
|
||||
// in the DWARF in the object file.
|
||||
debug_assert!(cx.object.syms.is_empty() || cx.object.syms_sort_by_name);
|
||||
let i = cx
|
||||
.object
|
||||
.syms
|
||||
.binary_search_by_key(&symbol.name(), |(name, _)| *name)
|
||||
.ok()?;
|
||||
let object_symbol = cx.object.syms.get(i)?;
|
||||
let object_addr = addr
|
||||
.wrapping_sub(symbol.address())
|
||||
.wrapping_add(object_symbol.1);
|
||||
Some((cx, object_addr))
|
||||
}
|
||||
}
|
||||
|
||||
fn object_mapping(path: &[u8]) -> Option<Mapping> {
|
||||
use super::mystd::ffi::OsStr;
|
||||
use super::mystd::os::unix::prelude::*;
|
||||
|
||||
let map;
|
||||
|
||||
// `N_OSO` symbol names can be either `/path/to/object.o` or `/path/to/archive.a(object.o)`.
|
||||
let member_name = if let Some((archive_path, member_name)) = split_archive_path(path) {
|
||||
map = super::mmap(Path::new(OsStr::from_bytes(archive_path)))?;
|
||||
Some(member_name)
|
||||
} else {
|
||||
map = super::mmap(Path::new(OsStr::from_bytes(path)))?;
|
||||
None
|
||||
};
|
||||
Mapping::mk(map, |data, stash| {
|
||||
let data = match member_name {
|
||||
Some(member_name) => {
|
||||
let archive = object::read::archive::ArchiveFile::parse(data).ok()?;
|
||||
let member = archive
|
||||
.members()
|
||||
.filter_map(Result::ok)
|
||||
.find(|m| m.name() == member_name)?;
|
||||
member.data(data).ok()?
|
||||
}
|
||||
None => data,
|
||||
};
|
||||
let (macho, data) = find_header(data)?;
|
||||
let endian = macho.endian().ok()?;
|
||||
let obj = Object::parse(macho, endian, data)?;
|
||||
Context::new(stash, obj, None, None)
|
||||
})
|
||||
}
|
||||
|
||||
fn split_archive_path(path: &[u8]) -> Option<(&[u8], &[u8])> {
|
||||
let (last, path) = path.split_last()?;
|
||||
if *last != b')' {
|
||||
return None;
|
||||
}
|
||||
let index = path.iter().position(|&x| x == b'(')?;
|
||||
let (archive, rest) = path.split_at(index);
|
||||
Some((archive, &rest[1..]))
|
||||
}
|
||||
|
||||
pub(super) fn handle_split_dwarf<'data>(
|
||||
_package: Option<&gimli::DwarfPackage<EndianSlice<'data, Endian>>>,
|
||||
_stash: &'data Stash,
|
||||
_load: addr2line::SplitDwarfLoad<EndianSlice<'data, Endian>>,
|
||||
) -> Option<Arc<gimli::Dwarf<EndianSlice<'data, Endian>>>> {
|
||||
None
|
||||
}
|
||||
25
.gear/predownloaded-development/vendor/backtrace/src/symbolize/gimli/mmap_fake.rs
vendored
Normal file
25
.gear/predownloaded-development/vendor/backtrace/src/symbolize/gimli/mmap_fake.rs
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
use super::{mystd::io::Read, File};
|
||||
use alloc::vec::Vec;
|
||||
use core::ops::Deref;
|
||||
|
||||
pub struct Mmap {
|
||||
vec: Vec<u8>,
|
||||
}
|
||||
|
||||
impl Mmap {
|
||||
pub unsafe fn map(mut file: &File, len: usize) -> Option<Mmap> {
|
||||
let mut mmap = Mmap {
|
||||
vec: Vec::with_capacity(len),
|
||||
};
|
||||
file.read_to_end(&mut mmap.vec).ok()?;
|
||||
Some(mmap)
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Mmap {
|
||||
type Target = [u8];
|
||||
|
||||
fn deref(&self) -> &[u8] {
|
||||
&self.vec[..]
|
||||
}
|
||||
}
|
||||
49
.gear/predownloaded-development/vendor/backtrace/src/symbolize/gimli/mmap_unix.rs
vendored
Normal file
49
.gear/predownloaded-development/vendor/backtrace/src/symbolize/gimli/mmap_unix.rs
vendored
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
use super::mystd::fs::File;
|
||||
use super::mystd::os::unix::prelude::*;
|
||||
use core::ops::Deref;
|
||||
use core::ptr;
|
||||
use core::slice;
|
||||
|
||||
#[cfg(not(all(target_os = "linux", target_env = "gnu")))]
|
||||
use libc::mmap as mmap64;
|
||||
#[cfg(all(target_os = "linux", target_env = "gnu"))]
|
||||
use libc::mmap64;
|
||||
|
||||
pub struct Mmap {
|
||||
ptr: *mut libc::c_void,
|
||||
len: usize,
|
||||
}
|
||||
|
||||
impl Mmap {
|
||||
pub unsafe fn map(file: &File, len: usize) -> Option<Mmap> {
|
||||
let ptr = mmap64(
|
||||
ptr::null_mut(),
|
||||
len,
|
||||
libc::PROT_READ,
|
||||
libc::MAP_PRIVATE,
|
||||
file.as_raw_fd(),
|
||||
0,
|
||||
);
|
||||
if ptr == libc::MAP_FAILED {
|
||||
return None;
|
||||
}
|
||||
Some(Mmap { ptr, len })
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Mmap {
|
||||
type Target = [u8];
|
||||
|
||||
fn deref(&self) -> &[u8] {
|
||||
unsafe { slice::from_raw_parts(self.ptr as *const u8, self.len) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Mmap {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
let r = libc::munmap(self.ptr, self.len);
|
||||
debug_assert_eq!(r, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
57
.gear/predownloaded-development/vendor/backtrace/src/symbolize/gimli/mmap_windows.rs
vendored
Normal file
57
.gear/predownloaded-development/vendor/backtrace/src/symbolize/gimli/mmap_windows.rs
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
use super::super::super::windows::*;
|
||||
use super::mystd::fs::File;
|
||||
use super::mystd::os::windows::prelude::*;
|
||||
use core::ops::Deref;
|
||||
use core::ptr;
|
||||
use core::slice;
|
||||
|
||||
pub struct Mmap {
|
||||
// keep the file alive to prevent it from being deleted which would cause
|
||||
// us to read bad data.
|
||||
_file: File,
|
||||
ptr: *mut c_void,
|
||||
len: usize,
|
||||
}
|
||||
|
||||
impl Mmap {
|
||||
pub unsafe fn map(file: &File, len: usize) -> Option<Mmap> {
|
||||
let file = file.try_clone().ok()?;
|
||||
let mapping = CreateFileMappingA(
|
||||
file.as_raw_handle() as *mut _,
|
||||
ptr::null_mut(),
|
||||
PAGE_READONLY,
|
||||
0,
|
||||
0,
|
||||
ptr::null(),
|
||||
);
|
||||
if mapping.is_null() {
|
||||
return None;
|
||||
}
|
||||
let ptr = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, len);
|
||||
CloseHandle(mapping);
|
||||
if ptr.is_null() {
|
||||
return None;
|
||||
}
|
||||
Some(Mmap {
|
||||
_file: file,
|
||||
ptr,
|
||||
len,
|
||||
})
|
||||
}
|
||||
}
|
||||
impl Deref for Mmap {
|
||||
type Target = [u8];
|
||||
|
||||
fn deref(&self) -> &[u8] {
|
||||
unsafe { slice::from_raw_parts(self.ptr as *const u8, self.len) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Mmap {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
let r = UnmapViewOfFile(self.ptr);
|
||||
debug_assert!(r != 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
232
.gear/predownloaded-development/vendor/backtrace/src/symbolize/gimli/parse_running_mmaps_unix.rs
vendored
Normal file
232
.gear/predownloaded-development/vendor/backtrace/src/symbolize/gimli/parse_running_mmaps_unix.rs
vendored
Normal file
|
|
@ -0,0 +1,232 @@
|
|||
// Note: This file is only currently used on targets that call out to the code
|
||||
// in `mod libs_dl_iterate_phdr` (e.g. linux, freebsd, ...); it may be more
|
||||
// general purpose, but it hasn't been tested elsewhere.
|
||||
|
||||
use super::mystd::fs::File;
|
||||
use super::mystd::io::Read;
|
||||
use super::mystd::str::FromStr;
|
||||
use super::{OsString, String, Vec};
|
||||
|
||||
#[derive(PartialEq, Eq, Debug)]
|
||||
pub(super) struct MapsEntry {
|
||||
/// start (inclusive) and limit (exclusive) of address range.
|
||||
address: (usize, usize),
|
||||
/// The perms field are the permissions for the entry
|
||||
///
|
||||
/// r = read
|
||||
/// w = write
|
||||
/// x = execute
|
||||
/// s = shared
|
||||
/// p = private (copy on write)
|
||||
perms: [char; 4],
|
||||
/// Offset into the file (or "whatever").
|
||||
offset: usize,
|
||||
/// device (major, minor)
|
||||
dev: (usize, usize),
|
||||
/// inode on the device. 0 indicates that no inode is associated with the memory region (e.g. uninitalized data aka BSS).
|
||||
inode: usize,
|
||||
/// Usually the file backing the mapping.
|
||||
///
|
||||
/// Note: The man page for proc includes a note about "coordination" by
|
||||
/// using readelf to see the Offset field in ELF program headers. pnkfelix
|
||||
/// is not yet sure if that is intended to be a comment on pathname, or what
|
||||
/// form/purpose such coordination is meant to have.
|
||||
///
|
||||
/// There are also some pseudo-paths:
|
||||
/// "[stack]": The initial process's (aka main thread's) stack.
|
||||
/// "[stack:<tid>]": a specific thread's stack. (This was only present for a limited range of Linux verisons; it was determined to be too expensive to provide.)
|
||||
/// "[vdso]": Virtual dynamically linked shared object
|
||||
/// "[heap]": The process's heap
|
||||
///
|
||||
/// The pathname can be blank, which means it is an anonymous mapping
|
||||
/// obtained via mmap.
|
||||
///
|
||||
/// Newlines in pathname are replaced with an octal escape sequence.
|
||||
///
|
||||
/// The pathname may have "(deleted)" appended onto it if the file-backed
|
||||
/// path has been deleted.
|
||||
///
|
||||
/// Note that modifications like the latter two indicated above imply that
|
||||
/// in general the pathname may be ambiguous. (I.e. you cannot tell if the
|
||||
/// denoted filename actually ended with the text "(deleted)", or if that
|
||||
/// was added by the maps rendering.
|
||||
pathname: OsString,
|
||||
}
|
||||
|
||||
pub(super) fn parse_maps() -> Result<Vec<MapsEntry>, &'static str> {
|
||||
let mut v = Vec::new();
|
||||
let mut proc_self_maps =
|
||||
File::open("/proc/self/maps").map_err(|_| "Couldn't open /proc/self/maps")?;
|
||||
let mut buf = String::new();
|
||||
let _bytes_read = proc_self_maps
|
||||
.read_to_string(&mut buf)
|
||||
.map_err(|_| "Couldn't read /proc/self/maps")?;
|
||||
for line in buf.lines() {
|
||||
v.push(line.parse()?);
|
||||
}
|
||||
|
||||
Ok(v)
|
||||
}
|
||||
|
||||
impl MapsEntry {
|
||||
pub(super) fn pathname(&self) -> &OsString {
|
||||
&self.pathname
|
||||
}
|
||||
|
||||
pub(super) fn ip_matches(&self, ip: usize) -> bool {
|
||||
self.address.0 <= ip && ip < self.address.1
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for MapsEntry {
|
||||
type Err = &'static str;
|
||||
|
||||
// Format: address perms offset dev inode pathname
|
||||
// e.g.: "ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]"
|
||||
// e.g.: "7f5985f46000-7f5985f48000 rw-p 00039000 103:06 76021795 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2"
|
||||
// e.g.: "35b1a21000-35b1a22000 rw-p 00000000 00:00 0"
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let mut parts = s
|
||||
.split(' ') // space-separated fields
|
||||
.filter(|s| s.len() > 0); // multiple spaces implies empty strings that need to be skipped.
|
||||
let range_str = parts.next().ok_or("Couldn't find address")?;
|
||||
let perms_str = parts.next().ok_or("Couldn't find permissions")?;
|
||||
let offset_str = parts.next().ok_or("Couldn't find offset")?;
|
||||
let dev_str = parts.next().ok_or("Couldn't find dev")?;
|
||||
let inode_str = parts.next().ok_or("Couldn't find inode")?;
|
||||
let pathname_str = parts.next().unwrap_or(""); // pathname may be omitted.
|
||||
|
||||
let hex = |s| usize::from_str_radix(s, 16).map_err(|_| "Couldn't parse hex number");
|
||||
let address = if let Some((start, limit)) = range_str.split_once('-') {
|
||||
(hex(start)?, hex(limit)?)
|
||||
} else {
|
||||
return Err("Couldn't parse address range");
|
||||
};
|
||||
let perms: [char; 4] = {
|
||||
let mut chars = perms_str.chars();
|
||||
let mut c = || chars.next().ok_or("insufficient perms");
|
||||
let perms = [c()?, c()?, c()?, c()?];
|
||||
if chars.next().is_some() {
|
||||
return Err("too many perms");
|
||||
}
|
||||
perms
|
||||
};
|
||||
let offset = hex(offset_str)?;
|
||||
let dev = if let Some((major, minor)) = dev_str.split_once(':') {
|
||||
(hex(major)?, hex(minor)?)
|
||||
} else {
|
||||
return Err("Couldn't parse dev");
|
||||
};
|
||||
let inode = hex(inode_str)?;
|
||||
let pathname = pathname_str.into();
|
||||
|
||||
Ok(MapsEntry {
|
||||
address,
|
||||
perms,
|
||||
offset,
|
||||
dev,
|
||||
inode,
|
||||
pathname,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure we can parse 64-bit sample output if we're on a 64-bit target.
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
#[test]
|
||||
fn check_maps_entry_parsing_64bit() {
|
||||
assert_eq!(
|
||||
"ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 \
|
||||
[vsyscall]"
|
||||
.parse::<MapsEntry>()
|
||||
.unwrap(),
|
||||
MapsEntry {
|
||||
address: (0xffffffffff600000, 0xffffffffff601000),
|
||||
perms: ['-', '-', 'x', 'p'],
|
||||
offset: 0x00000000,
|
||||
dev: (0x00, 0x00),
|
||||
inode: 0x0,
|
||||
pathname: "[vsyscall]".into(),
|
||||
}
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
"7f5985f46000-7f5985f48000 rw-p 00039000 103:06 76021795 \
|
||||
/usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2"
|
||||
.parse::<MapsEntry>()
|
||||
.unwrap(),
|
||||
MapsEntry {
|
||||
address: (0x7f5985f46000, 0x7f5985f48000),
|
||||
perms: ['r', 'w', '-', 'p'],
|
||||
offset: 0x00039000,
|
||||
dev: (0x103, 0x06),
|
||||
inode: 0x76021795,
|
||||
pathname: "/usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2".into(),
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
"35b1a21000-35b1a22000 rw-p 00000000 00:00 0"
|
||||
.parse::<MapsEntry>()
|
||||
.unwrap(),
|
||||
MapsEntry {
|
||||
address: (0x35b1a21000, 0x35b1a22000),
|
||||
perms: ['r', 'w', '-', 'p'],
|
||||
offset: 0x00000000,
|
||||
dev: (0x00, 0x00),
|
||||
inode: 0x0,
|
||||
pathname: Default::default(),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// (This output was taken from a 32-bit machine, but will work on any target)
|
||||
#[test]
|
||||
fn check_maps_entry_parsing_32bit() {
|
||||
/* Example snippet of output:
|
||||
08056000-08077000 rw-p 00000000 00:00 0 [heap]
|
||||
b7c79000-b7e02000 r--p 00000000 08:01 60662705 /usr/lib/locale/locale-archive
|
||||
b7e02000-b7e03000 rw-p 00000000 00:00 0
|
||||
*/
|
||||
assert_eq!(
|
||||
"08056000-08077000 rw-p 00000000 00:00 0 \
|
||||
[heap]"
|
||||
.parse::<MapsEntry>()
|
||||
.unwrap(),
|
||||
MapsEntry {
|
||||
address: (0x08056000, 0x08077000),
|
||||
perms: ['r', 'w', '-', 'p'],
|
||||
offset: 0x00000000,
|
||||
dev: (0x00, 0x00),
|
||||
inode: 0x0,
|
||||
pathname: "[heap]".into(),
|
||||
}
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
"b7c79000-b7e02000 r--p 00000000 08:01 60662705 \
|
||||
/usr/lib/locale/locale-archive"
|
||||
.parse::<MapsEntry>()
|
||||
.unwrap(),
|
||||
MapsEntry {
|
||||
address: (0xb7c79000, 0xb7e02000),
|
||||
perms: ['r', '-', '-', 'p'],
|
||||
offset: 0x00000000,
|
||||
dev: (0x08, 0x01),
|
||||
inode: 0x60662705,
|
||||
pathname: "/usr/lib/locale/locale-archive".into(),
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
"b7e02000-b7e03000 rw-p 00000000 00:00 0"
|
||||
.parse::<MapsEntry>()
|
||||
.unwrap(),
|
||||
MapsEntry {
|
||||
address: (0xb7e02000, 0xb7e03000),
|
||||
perms: ['r', 'w', '-', 'p'],
|
||||
offset: 0x00000000,
|
||||
dev: (0x00, 0x00),
|
||||
inode: 0x0,
|
||||
pathname: Default::default(),
|
||||
}
|
||||
);
|
||||
}
|
||||
50
.gear/predownloaded-development/vendor/backtrace/src/symbolize/gimli/stash.rs
vendored
Normal file
50
.gear/predownloaded-development/vendor/backtrace/src/symbolize/gimli/stash.rs
vendored
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
// only used on Linux right now, so allow dead code elsewhere
|
||||
#![cfg_attr(not(target_os = "linux"), allow(dead_code))]
|
||||
|
||||
use super::Mmap;
|
||||
use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
use core::cell::UnsafeCell;
|
||||
|
||||
/// A simple arena allocator for byte buffers.
|
||||
pub struct Stash {
|
||||
buffers: UnsafeCell<Vec<Vec<u8>>>,
|
||||
mmaps: UnsafeCell<Vec<Mmap>>,
|
||||
}
|
||||
|
||||
impl Stash {
|
||||
pub fn new() -> Stash {
|
||||
Stash {
|
||||
buffers: UnsafeCell::new(Vec::new()),
|
||||
mmaps: UnsafeCell::new(Vec::new()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Allocates a buffer of the specified size and returns a mutable reference
|
||||
/// to it.
|
||||
pub fn allocate(&self, size: usize) -> &mut [u8] {
|
||||
// SAFETY: this is the only function that ever constructs a mutable
|
||||
// reference to `self.buffers`.
|
||||
let buffers = unsafe { &mut *self.buffers.get() };
|
||||
let i = buffers.len();
|
||||
buffers.push(vec![0; size]);
|
||||
// SAFETY: we never remove elements from `self.buffers`, so a reference
|
||||
// to the data inside any buffer will live as long as `self` does.
|
||||
&mut buffers[i]
|
||||
}
|
||||
|
||||
/// Stores a `Mmap` for the lifetime of this `Stash`, returning a pointer
|
||||
/// which is scoped to just this lifetime.
|
||||
pub fn cache_mmap(&self, map: Mmap) -> &[u8] {
|
||||
// SAFETY: this is the only location for a mutable pointer to
|
||||
// `mmaps`, and this structure isn't threadsafe to shared across
|
||||
// threads either. We also never remove elements from `self.mmaps`,
|
||||
// so a reference to the data inside the map will live as long as
|
||||
// `self` does.
|
||||
unsafe {
|
||||
let mmaps = &mut *self.mmaps.get();
|
||||
mmaps.push(map);
|
||||
mmaps.last().unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
56
.gear/predownloaded-development/vendor/backtrace/src/symbolize/miri.rs
vendored
Normal file
56
.gear/predownloaded-development/vendor/backtrace/src/symbolize/miri.rs
vendored
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
use core::ffi::c_void;
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use super::super::backtrace::miri::{resolve_addr, Frame};
|
||||
use super::BytesOrWideString;
|
||||
use super::{ResolveWhat, SymbolName};
|
||||
|
||||
pub unsafe fn resolve(what: ResolveWhat<'_>, cb: &mut dyn FnMut(&super::Symbol)) {
|
||||
let sym = match what {
|
||||
ResolveWhat::Address(addr) => Symbol {
|
||||
inner: resolve_addr(addr),
|
||||
_unused: PhantomData,
|
||||
},
|
||||
ResolveWhat::Frame(frame) => Symbol {
|
||||
inner: frame.inner.clone(),
|
||||
_unused: PhantomData,
|
||||
},
|
||||
};
|
||||
cb(&super::Symbol { inner: sym })
|
||||
}
|
||||
|
||||
pub struct Symbol<'a> {
|
||||
inner: Frame,
|
||||
_unused: PhantomData<&'a ()>,
|
||||
}
|
||||
|
||||
impl<'a> Symbol<'a> {
|
||||
pub fn name(&self) -> Option<SymbolName<'_>> {
|
||||
Some(SymbolName::new(&self.inner.inner.name))
|
||||
}
|
||||
|
||||
pub fn addr(&self) -> Option<*mut c_void> {
|
||||
Some(self.inner.addr)
|
||||
}
|
||||
|
||||
pub fn filename_raw(&self) -> Option<BytesOrWideString<'_>> {
|
||||
Some(BytesOrWideString::Bytes(&self.inner.inner.filename))
|
||||
}
|
||||
|
||||
pub fn lineno(&self) -> Option<u32> {
|
||||
Some(self.inner.inner.lineno)
|
||||
}
|
||||
|
||||
pub fn colno(&self) -> Option<u32> {
|
||||
Some(self.inner.inner.colno)
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub fn filename(&self) -> Option<&std::path::Path> {
|
||||
Some(std::path::Path::new(
|
||||
core::str::from_utf8(&self.inner.inner.filename).unwrap(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn clear_symbol_cache() {}
|
||||
485
.gear/predownloaded-development/vendor/backtrace/src/symbolize/mod.rs
vendored
Normal file
485
.gear/predownloaded-development/vendor/backtrace/src/symbolize/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,485 @@
|
|||
use core::{fmt, str};
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "std")] {
|
||||
use std::path::Path;
|
||||
use std::prelude::v1::*;
|
||||
}
|
||||
}
|
||||
|
||||
use super::backtrace::Frame;
|
||||
use super::types::BytesOrWideString;
|
||||
use core::ffi::c_void;
|
||||
use rustc_demangle::{try_demangle, Demangle};
|
||||
|
||||
/// Resolve an address to a symbol, passing the symbol to the specified
|
||||
/// closure.
|
||||
///
|
||||
/// This function will look up the given address in areas such as the local
|
||||
/// symbol table, dynamic symbol table, or DWARF debug info (depending on the
|
||||
/// activated implementation) to find symbols to yield.
|
||||
///
|
||||
/// The closure may not be called if resolution could not be performed, and it
|
||||
/// also may be called more than once in the case of inlined functions.
|
||||
///
|
||||
/// Symbols yielded represent the execution at the specified `addr`, returning
|
||||
/// file/line pairs for that address (if available).
|
||||
///
|
||||
/// Note that if you have a `Frame` then it's recommended to use the
|
||||
/// `resolve_frame` function instead of this one.
|
||||
///
|
||||
/// # Required features
|
||||
///
|
||||
/// This function requires the `std` feature of the `backtrace` crate to be
|
||||
/// enabled, and the `std` feature is enabled by default.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function strives to never panic, but if the `cb` provided panics then
|
||||
/// some platforms will force a double panic to abort the process. Some
|
||||
/// platforms use a C library which internally uses callbacks which cannot be
|
||||
/// unwound through, so panicking from `cb` may trigger a process abort.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// extern crate backtrace;
|
||||
///
|
||||
/// fn main() {
|
||||
/// backtrace::trace(|frame| {
|
||||
/// let ip = frame.ip();
|
||||
///
|
||||
/// backtrace::resolve(ip, |symbol| {
|
||||
/// // ...
|
||||
/// });
|
||||
///
|
||||
/// false // only look at the top frame
|
||||
/// });
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg(feature = "std")]
|
||||
pub fn resolve<F: FnMut(&Symbol)>(addr: *mut c_void, cb: F) {
|
||||
let _guard = crate::lock::lock();
|
||||
unsafe { resolve_unsynchronized(addr, cb) }
|
||||
}
|
||||
|
||||
/// Resolve a previously capture frame to a symbol, passing the symbol to the
|
||||
/// specified closure.
|
||||
///
|
||||
/// This function performs the same function as `resolve` except that it takes a
|
||||
/// `Frame` as an argument instead of an address. This can allow some platform
|
||||
/// implementations of backtracing to provide more accurate symbol information
|
||||
/// or information about inline frames for example. It's recommended to use this
|
||||
/// if you can.
|
||||
///
|
||||
/// # Required features
|
||||
///
|
||||
/// This function requires the `std` feature of the `backtrace` crate to be
|
||||
/// enabled, and the `std` feature is enabled by default.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function strives to never panic, but if the `cb` provided panics then
|
||||
/// some platforms will force a double panic to abort the process. Some
|
||||
/// platforms use a C library which internally uses callbacks which cannot be
|
||||
/// unwound through, so panicking from `cb` may trigger a process abort.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// extern crate backtrace;
|
||||
///
|
||||
/// fn main() {
|
||||
/// backtrace::trace(|frame| {
|
||||
/// backtrace::resolve_frame(frame, |symbol| {
|
||||
/// // ...
|
||||
/// });
|
||||
///
|
||||
/// false // only look at the top frame
|
||||
/// });
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg(feature = "std")]
|
||||
pub fn resolve_frame<F: FnMut(&Symbol)>(frame: &Frame, cb: F) {
|
||||
let _guard = crate::lock::lock();
|
||||
unsafe { resolve_frame_unsynchronized(frame, cb) }
|
||||
}
|
||||
|
||||
pub enum ResolveWhat<'a> {
|
||||
Address(*mut c_void),
|
||||
Frame(&'a Frame),
|
||||
}
|
||||
|
||||
impl<'a> ResolveWhat<'a> {
|
||||
#[allow(dead_code)]
|
||||
fn address_or_ip(&self) -> *mut c_void {
|
||||
match self {
|
||||
ResolveWhat::Address(a) => adjust_ip(*a),
|
||||
ResolveWhat::Frame(f) => adjust_ip(f.ip()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// IP values from stack frames are typically (always?) the instruction
|
||||
// *after* the call that's the actual stack trace. Symbolizing this on
|
||||
// causes the filename/line number to be one ahead and perhaps into
|
||||
// the void if it's near the end of the function.
|
||||
//
|
||||
// This appears to basically always be the case on all platforms, so we always
|
||||
// subtract one from a resolved ip to resolve it to the previous call
|
||||
// instruction instead of the instruction being returned to.
|
||||
//
|
||||
// Ideally we would not do this. Ideally we would require callers of the
|
||||
// `resolve` APIs here to manually do the -1 and account that they want location
|
||||
// information for the *previous* instruction, not the current. Ideally we'd
|
||||
// also expose on `Frame` if we are indeed the address of the next instruction
|
||||
// or the current.
|
||||
//
|
||||
// For now though this is a pretty niche concern so we just internally always
|
||||
// subtract one. Consumers should keep working and getting pretty good results,
|
||||
// so we should be good enough.
|
||||
fn adjust_ip(a: *mut c_void) -> *mut c_void {
|
||||
if a.is_null() {
|
||||
a
|
||||
} else {
|
||||
(a as usize - 1) as *mut c_void
|
||||
}
|
||||
}
|
||||
|
||||
/// Same as `resolve`, only unsafe as it's unsynchronized.
|
||||
///
|
||||
/// This function does not have synchronization guarantees but is available when
|
||||
/// the `std` feature of this crate isn't compiled in. See the `resolve`
|
||||
/// function for more documentation and examples.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// See information on `resolve` for caveats on `cb` panicking.
|
||||
pub unsafe fn resolve_unsynchronized<F>(addr: *mut c_void, mut cb: F)
|
||||
where
|
||||
F: FnMut(&Symbol),
|
||||
{
|
||||
imp::resolve(ResolveWhat::Address(addr), &mut cb)
|
||||
}
|
||||
|
||||
/// Same as `resolve_frame`, only unsafe as it's unsynchronized.
|
||||
///
|
||||
/// This function does not have synchronization guarantees but is available
|
||||
/// when the `std` feature of this crate isn't compiled in. See the
|
||||
/// `resolve_frame` function for more documentation and examples.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// See information on `resolve_frame` for caveats on `cb` panicking.
|
||||
pub unsafe fn resolve_frame_unsynchronized<F>(frame: &Frame, mut cb: F)
|
||||
where
|
||||
F: FnMut(&Symbol),
|
||||
{
|
||||
imp::resolve(ResolveWhat::Frame(frame), &mut cb)
|
||||
}
|
||||
|
||||
/// A trait representing the resolution of a symbol in a file.
|
||||
///
|
||||
/// This trait is yielded as a trait object to the closure given to the
|
||||
/// `backtrace::resolve` function, and it is virtually dispatched as it's
|
||||
/// unknown which implementation is behind it.
|
||||
///
|
||||
/// A symbol can give contextual information about a function, for example the
|
||||
/// name, filename, line number, precise address, etc. Not all information is
|
||||
/// always available in a symbol, however, so all methods return an `Option`.
|
||||
pub struct Symbol {
|
||||
// TODO: this lifetime bound needs to be persisted eventually to `Symbol`,
|
||||
// but that's currently a breaking change. For now this is safe since
|
||||
// `Symbol` is only ever handed out by reference and can't be cloned.
|
||||
inner: imp::Symbol<'static>,
|
||||
}
|
||||
|
||||
impl Symbol {
|
||||
/// Returns the name of this function.
|
||||
///
|
||||
/// The returned structure can be used to query various properties about the
|
||||
/// symbol name:
|
||||
///
|
||||
/// * The `Display` implementation will print out the demangled symbol.
|
||||
/// * The raw `str` value of the symbol can be accessed (if it's valid
|
||||
/// utf-8).
|
||||
/// * The raw bytes for the symbol name can be accessed.
|
||||
pub fn name(&self) -> Option<SymbolName<'_>> {
|
||||
self.inner.name()
|
||||
}
|
||||
|
||||
/// Returns the starting address of this function.
|
||||
pub fn addr(&self) -> Option<*mut c_void> {
|
||||
self.inner.addr().map(|p| p as *mut _)
|
||||
}
|
||||
|
||||
/// Returns the raw filename as a slice. This is mainly useful for `no_std`
|
||||
/// environments.
|
||||
pub fn filename_raw(&self) -> Option<BytesOrWideString<'_>> {
|
||||
self.inner.filename_raw()
|
||||
}
|
||||
|
||||
/// Returns the column number for where this symbol is currently executing.
|
||||
///
|
||||
/// Only gimli currently provides a value here and even then only if `filename`
|
||||
/// returns `Some`, and so it is then consequently subject to similar caveats.
|
||||
pub fn colno(&self) -> Option<u32> {
|
||||
self.inner.colno()
|
||||
}
|
||||
|
||||
/// Returns the line number for where this symbol is currently executing.
|
||||
///
|
||||
/// This return value is typically `Some` if `filename` returns `Some`, and
|
||||
/// is consequently subject to similar caveats.
|
||||
pub fn lineno(&self) -> Option<u32> {
|
||||
self.inner.lineno()
|
||||
}
|
||||
|
||||
/// Returns the file name where this function was defined.
|
||||
///
|
||||
/// This is currently only available when libbacktrace or gimli is being
|
||||
/// used (e.g. unix platforms other) and when a binary is compiled with
|
||||
/// debuginfo. If neither of these conditions is met then this will likely
|
||||
/// return `None`.
|
||||
///
|
||||
/// # Required features
|
||||
///
|
||||
/// This function requires the `std` feature of the `backtrace` crate to be
|
||||
/// enabled, and the `std` feature is enabled by default.
|
||||
#[cfg(feature = "std")]
|
||||
#[allow(unreachable_code)]
|
||||
pub fn filename(&self) -> Option<&Path> {
|
||||
self.inner.filename()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Symbol {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let mut d = f.debug_struct("Symbol");
|
||||
if let Some(name) = self.name() {
|
||||
d.field("name", &name);
|
||||
}
|
||||
if let Some(addr) = self.addr() {
|
||||
d.field("addr", &addr);
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
{
|
||||
if let Some(filename) = self.filename() {
|
||||
d.field("filename", &filename);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(lineno) = self.lineno() {
|
||||
d.field("lineno", &lineno);
|
||||
}
|
||||
d.finish()
|
||||
}
|
||||
}
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "cpp_demangle")] {
|
||||
// Maybe a parsed C++ symbol, if parsing the mangled symbol as Rust
|
||||
// failed.
|
||||
struct OptionCppSymbol<'a>(Option<::cpp_demangle::BorrowedSymbol<'a>>);
|
||||
|
||||
impl<'a> OptionCppSymbol<'a> {
|
||||
fn parse(input: &'a [u8]) -> OptionCppSymbol<'a> {
|
||||
OptionCppSymbol(::cpp_demangle::BorrowedSymbol::new(input).ok())
|
||||
}
|
||||
|
||||
fn none() -> OptionCppSymbol<'a> {
|
||||
OptionCppSymbol(None)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
use core::marker::PhantomData;
|
||||
|
||||
// Make sure to keep this zero-sized, so that the `cpp_demangle` feature
|
||||
// has no cost when disabled.
|
||||
struct OptionCppSymbol<'a>(PhantomData<&'a ()>);
|
||||
|
||||
impl<'a> OptionCppSymbol<'a> {
|
||||
fn parse(_: &'a [u8]) -> OptionCppSymbol<'a> {
|
||||
OptionCppSymbol(PhantomData)
|
||||
}
|
||||
|
||||
fn none() -> OptionCppSymbol<'a> {
|
||||
OptionCppSymbol(PhantomData)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A wrapper around a symbol name to provide ergonomic accessors to the
|
||||
/// demangled name, the raw bytes, the raw string, etc.
|
||||
// Allow dead code for when the `cpp_demangle` feature is not enabled.
|
||||
#[allow(dead_code)]
|
||||
pub struct SymbolName<'a> {
|
||||
bytes: &'a [u8],
|
||||
demangled: Option<Demangle<'a>>,
|
||||
cpp_demangled: OptionCppSymbol<'a>,
|
||||
}
|
||||
|
||||
impl<'a> SymbolName<'a> {
|
||||
/// Creates a new symbol name from the raw underlying bytes.
|
||||
pub fn new(bytes: &'a [u8]) -> SymbolName<'a> {
|
||||
let str_bytes = str::from_utf8(bytes).ok();
|
||||
let demangled = str_bytes.and_then(|s| try_demangle(s).ok());
|
||||
|
||||
let cpp = if demangled.is_none() {
|
||||
OptionCppSymbol::parse(bytes)
|
||||
} else {
|
||||
OptionCppSymbol::none()
|
||||
};
|
||||
|
||||
SymbolName {
|
||||
bytes: bytes,
|
||||
demangled: demangled,
|
||||
cpp_demangled: cpp,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the raw (mangled) symbol name as a `str` if the symbol is valid utf-8.
|
||||
///
|
||||
/// Use the `Display` implementation if you want the demangled version.
|
||||
pub fn as_str(&self) -> Option<&'a str> {
|
||||
self.demangled
|
||||
.as_ref()
|
||||
.map(|s| s.as_str())
|
||||
.or_else(|| str::from_utf8(self.bytes).ok())
|
||||
}
|
||||
|
||||
/// Returns the raw symbol name as a list of bytes
|
||||
pub fn as_bytes(&self) -> &'a [u8] {
|
||||
self.bytes
|
||||
}
|
||||
}
|
||||
|
||||
fn format_symbol_name(
|
||||
fmt: fn(&str, &mut fmt::Formatter<'_>) -> fmt::Result,
|
||||
mut bytes: &[u8],
|
||||
f: &mut fmt::Formatter<'_>,
|
||||
) -> fmt::Result {
|
||||
while bytes.len() > 0 {
|
||||
match str::from_utf8(bytes) {
|
||||
Ok(name) => {
|
||||
fmt(name, f)?;
|
||||
break;
|
||||
}
|
||||
Err(err) => {
|
||||
fmt("\u{FFFD}", f)?;
|
||||
|
||||
match err.error_len() {
|
||||
Some(len) => bytes = &bytes[err.valid_up_to() + len..],
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "cpp_demangle")] {
|
||||
impl<'a> fmt::Display for SymbolName<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
if let Some(ref s) = self.demangled {
|
||||
s.fmt(f)
|
||||
} else if let Some(ref cpp) = self.cpp_demangled.0 {
|
||||
cpp.fmt(f)
|
||||
} else {
|
||||
format_symbol_name(fmt::Display::fmt, self.bytes, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
impl<'a> fmt::Display for SymbolName<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
if let Some(ref s) = self.demangled {
|
||||
s.fmt(f)
|
||||
} else {
|
||||
format_symbol_name(fmt::Display::fmt, self.bytes, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(all(feature = "std", feature = "cpp_demangle"))] {
|
||||
impl<'a> fmt::Debug for SymbolName<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
use std::fmt::Write;
|
||||
|
||||
if let Some(ref s) = self.demangled {
|
||||
return s.fmt(f)
|
||||
}
|
||||
|
||||
// This may to print if the demangled symbol isn't actually
|
||||
// valid, so handle the error here gracefully by not propagating
|
||||
// it outwards.
|
||||
if let Some(ref cpp) = self.cpp_demangled.0 {
|
||||
let mut s = String::new();
|
||||
if write!(s, "{}", cpp).is_ok() {
|
||||
return s.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
format_symbol_name(fmt::Debug::fmt, self.bytes, f)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
impl<'a> fmt::Debug for SymbolName<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
if let Some(ref s) = self.demangled {
|
||||
s.fmt(f)
|
||||
} else {
|
||||
format_symbol_name(fmt::Debug::fmt, self.bytes, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempt to reclaim that cached memory used to symbolicate addresses.
|
||||
///
|
||||
/// This method will attempt to release any global data structures that have
|
||||
/// otherwise been cached globally or in the thread which typically represent
|
||||
/// parsed DWARF information or similar.
|
||||
///
|
||||
/// # Caveats
|
||||
///
|
||||
/// While this function is always available it doesn't actually do anything on
|
||||
/// most implementations. Libraries like dbghelp or libbacktrace do not provide
|
||||
/// facilities to deallocate state and manage the allocated memory. For now the
|
||||
/// `gimli-symbolize` feature of this crate is the only feature where this
|
||||
/// function has any effect.
|
||||
#[cfg(feature = "std")]
|
||||
pub fn clear_symbol_cache() {
|
||||
let _guard = crate::lock::lock();
|
||||
unsafe {
|
||||
imp::clear_symbol_cache();
|
||||
}
|
||||
}
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(miri)] {
|
||||
mod miri;
|
||||
use miri as imp;
|
||||
} else if #[cfg(all(windows, target_env = "msvc", not(target_vendor = "uwp")))] {
|
||||
mod dbghelp;
|
||||
use dbghelp as imp;
|
||||
} else if #[cfg(all(
|
||||
any(unix, windows),
|
||||
not(target_vendor = "uwp"),
|
||||
not(target_os = "emscripten"),
|
||||
any(not(backtrace_in_libstd), feature = "backtrace"),
|
||||
))] {
|
||||
mod gimli;
|
||||
use gimli as imp;
|
||||
} else {
|
||||
mod noop;
|
||||
use noop as imp;
|
||||
}
|
||||
}
|
||||
41
.gear/predownloaded-development/vendor/backtrace/src/symbolize/noop.rs
vendored
Normal file
41
.gear/predownloaded-development/vendor/backtrace/src/symbolize/noop.rs
vendored
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
//! Empty symbolication strategy used to compile for platforms that have no
|
||||
//! support.
|
||||
|
||||
use super::{BytesOrWideString, ResolveWhat, SymbolName};
|
||||
use core::ffi::c_void;
|
||||
use core::marker;
|
||||
|
||||
pub unsafe fn resolve(_addr: ResolveWhat<'_>, _cb: &mut dyn FnMut(&super::Symbol)) {}
|
||||
|
||||
pub struct Symbol<'a> {
|
||||
_marker: marker::PhantomData<&'a i32>,
|
||||
}
|
||||
|
||||
impl Symbol<'_> {
|
||||
pub fn name(&self) -> Option<SymbolName<'_>> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn addr(&self) -> Option<*mut c_void> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn filename_raw(&self) -> Option<BytesOrWideString<'_>> {
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub fn filename(&self) -> Option<&::std::path::Path> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn lineno(&self) -> Option<u32> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn colno(&self) -> Option<u32> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn clear_symbol_cache() {}
|
||||
83
.gear/predownloaded-development/vendor/backtrace/src/types.rs
vendored
Normal file
83
.gear/predownloaded-development/vendor/backtrace/src/types.rs
vendored
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
//! Platform dependent types.
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "std")] {
|
||||
use std::borrow::Cow;
|
||||
use std::fmt;
|
||||
use std::path::PathBuf;
|
||||
use std::prelude::v1::*;
|
||||
use std::str;
|
||||
}
|
||||
}
|
||||
|
||||
/// A platform independent representation of a string. When working with `std`
|
||||
/// enabled it is recommended to the convenience methods for providing
|
||||
/// conversions to `std` types.
|
||||
#[derive(Debug)]
|
||||
pub enum BytesOrWideString<'a> {
|
||||
/// A slice, typically provided on Unix platforms.
|
||||
Bytes(&'a [u8]),
|
||||
/// Wide strings typically from Windows.
|
||||
Wide(&'a [u16]),
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<'a> BytesOrWideString<'a> {
|
||||
/// Lossy converts to a `Cow<str>`, will allocate if `Bytes` is not valid
|
||||
/// UTF-8 or if `BytesOrWideString` is `Wide`.
|
||||
///
|
||||
/// # Required features
|
||||
///
|
||||
/// This function requires the `std` feature of the `backtrace` crate to be
|
||||
/// enabled, and the `std` feature is enabled by default.
|
||||
pub fn to_str_lossy(&self) -> Cow<'a, str> {
|
||||
use self::BytesOrWideString::*;
|
||||
|
||||
match self {
|
||||
&Bytes(slice) => String::from_utf8_lossy(slice),
|
||||
&Wide(wide) => Cow::Owned(String::from_utf16_lossy(wide)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Provides a `Path` representation of `BytesOrWideString`.
|
||||
///
|
||||
/// # Required features
|
||||
///
|
||||
/// This function requires the `std` feature of the `backtrace` crate to be
|
||||
/// enabled, and the `std` feature is enabled by default.
|
||||
pub fn into_path_buf(self) -> PathBuf {
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use std::ffi::OsStr;
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
|
||||
if let BytesOrWideString::Bytes(slice) = self {
|
||||
return PathBuf::from(OsStr::from_bytes(slice));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
{
|
||||
use std::ffi::OsString;
|
||||
use std::os::windows::ffi::OsStringExt;
|
||||
|
||||
if let BytesOrWideString::Wide(slice) = self {
|
||||
return PathBuf::from(OsString::from_wide(slice));
|
||||
}
|
||||
}
|
||||
|
||||
if let BytesOrWideString::Bytes(b) = self {
|
||||
if let Ok(s) = str::from_utf8(b) {
|
||||
return PathBuf::from(s);
|
||||
}
|
||||
}
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<'a> fmt::Display for BytesOrWideString<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.to_str_lossy().fmt(f)
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue