cargo vendor

This commit is contained in:
Andrew A. Vasilyev 2024-02-29 18:27:23 +03:00
parent e8b153031a
commit a6268455b9
2684 changed files with 934867 additions and 670613 deletions

292
Cargo.lock generated
View File

@ -3,10 +3,25 @@
version = 3
[[package]]
name = "anyhow"
version = "1.0.65"
name = "addr2line"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602"
checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
dependencies = [
"gimli",
]
[[package]]
name = "adler"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "anyhow"
version = "1.0.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1"
[[package]]
name = "autocfg"
@ -14,6 +29,21 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "backtrace"
version = "0.3.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
dependencies = [
"addr2line",
"cc",
"cfg-if",
"libc",
"miniz_oxide",
"object",
"rustc-demangle",
]
[[package]]
name = "bitflags"
version = "1.3.2"
@ -22,9 +52,15 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bytes"
version = "1.2.1"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db"
checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
[[package]]
name = "cc"
version = "1.0.88"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02f341c093d19155a6e41631ce5971aac4e9a868262212153124c15fa22d1cdc"
[[package]]
name = "cfg-if"
@ -33,13 +69,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "hermit-abi"
version = "0.1.19"
name = "gimli"
version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
[[package]]
name = "hermit-abi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
[[package]]
name = "lazy_static"
@ -49,77 +88,92 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.134"
version = "0.2.153"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "329c933548736bc49fd575ee68c89e8be4d260064184389a5b77517cddd99ffb"
[[package]]
name = "log"
version = "0.4.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
dependencies = [
"cfg-if",
]
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
[[package]]
name = "memchr"
version = "2.5.0"
version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
[[package]]
name = "memoffset"
version = "0.6.5"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4"
dependencies = [
"autocfg",
]
[[package]]
name = "mio"
version = "0.8.4"
name = "miniz_oxide"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf"
checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
dependencies = [
"adler",
]
[[package]]
name = "mio"
version = "0.8.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09"
dependencies = [
"libc",
"log",
"wasi",
"windows-sys",
"windows-sys 0.48.0",
]
[[package]]
name = "nix"
version = "0.24.2"
version = "0.26.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "195cdbc1741b8134346d515b3a56a1c94b0912758009cfd53f99ea0f57b065fc"
checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b"
dependencies = [
"bitflags",
"cfg-if",
"libc",
"memoffset",
"pin-utils",
]
[[package]]
name = "num_cpus"
version = "1.13.1"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
dependencies = [
"hermit-abi",
"libc",
]
[[package]]
name = "pin-project-lite"
version = "0.2.9"
name = "object"
version = "0.32.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
dependencies = [
"memchr",
]
[[package]]
name = "pin-project-lite"
version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
[[package]]
name = "pin-utils"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "pve-lxc-syscalld"
version = "1.2.2"
version = "1.3.0"
dependencies = [
"anyhow",
"bitflags",
@ -131,30 +185,35 @@ dependencies = [
]
[[package]]
name = "socket2"
version = "0.4.7"
name = "rustc-demangle"
version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd"
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
[[package]]
name = "socket2"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871"
dependencies = [
"libc",
"winapi",
"windows-sys 0.52.0",
]
[[package]]
name = "tokio"
version = "1.21.2"
version = "1.36.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9e03c497dc955702ba729190dc4aac6f2a0ce97f913e5b1b5912fc5039d9099"
checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931"
dependencies = [
"autocfg",
"backtrace",
"bytes",
"libc",
"memchr",
"mio",
"num_cpus",
"pin-project-lite",
"socket2",
"winapi",
"windows-sys 0.48.0",
]
[[package]]
@ -164,66 +223,133 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "winapi"
version = "0.3.9"
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
"windows-targets 0.48.5",
]
[[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"
[[package]]
name = "windows-sys"
version = "0.36.1"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_msvc",
"windows-targets 0.52.4",
]
[[package]]
name = "windows_aarch64_msvc"
version = "0.36.1"
name = "windows-targets"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm 0.48.5",
"windows_aarch64_msvc 0.48.5",
"windows_i686_gnu 0.48.5",
"windows_i686_msvc 0.48.5",
"windows_x86_64_gnu 0.48.5",
"windows_x86_64_gnullvm 0.48.5",
"windows_x86_64_msvc 0.48.5",
]
[[package]]
name = "windows-targets"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b"
dependencies = [
"windows_aarch64_gnullvm 0.52.4",
"windows_aarch64_msvc 0.52.4",
"windows_i686_gnu 0.52.4",
"windows_i686_msvc 0.52.4",
"windows_x86_64_gnu 0.52.4",
"windows_x86_64_gnullvm 0.52.4",
"windows_x86_64_msvc 0.52.4",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675"
[[package]]
name = "windows_i686_gnu"
version = "0.36.1"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_gnu"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3"
[[package]]
name = "windows_i686_msvc"
version = "0.36.1"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_i686_msvc"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02"
[[package]]
name = "windows_x86_64_gnu"
version = "0.36.1"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177"
[[package]]
name = "windows_x86_64_msvc"
version = "0.36.1"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8"

1
vendor/addr2line/.cargo-checksum.json vendored Normal file
View File

@ -0,0 +1 @@
{"files":{"CHANGELOG.md":"ef9fa958318e442f1da7d204494cefec75c144aa6d5d5c93b0a5d6fcdf4ef6c6","Cargo.lock":"20b23c454fc3127f08a1bcd2864bbf029793759e6411fba24d44d8f4b7831ad0","Cargo.toml":"d0f15fde73d42bdf00e93f960dff908447225bede9364cb1659e44740a536c04","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"e99d88d232bf57d70f0fb87f6b496d44b6653f99f8a63d250a54c61ea4bcde40","README.md":"76d28502bd2e83f6a9e3576bd45e9a7fe5308448c4b5384b0d249515b5f67a5c","bench.plot.r":"6a5d7a4d36ed6b3d9919be703a479bef47698bf947818b483ff03951df2d4e01","benchmark.sh":"b35f89b1ca2c1dc0476cdd07f0284b72d41920d1c7b6054072f50ffba296d78d","coverage.sh":"4677e81922d08a82e83068a911717a247c66af12e559f37b78b6be3337ac9f07","examples/addr2line.rs":"3c5eb5a6726634df6cf53e4d67ee9f90c9ac09838303947f45c3bea1e84548b5","rustfmt.toml":"01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b","src/builtin_split_dwarf_loader.rs":"dc6979de81b35f82e97275e6be27ec61f3c4225ea10574a9e031813e00185174","src/function.rs":"68f047e0c78afe18ad165db255c8254ee74c35cd6df0cc07e400252981f661ed","src/lazy.rs":"0bf23f7098f1902f181e43c2ffa82a3f86df2c0dbcb9bc0ebce6a0168dd8b060","src/lib.rs":"9d6531f71fd138d31cc7596db9ab234198d0895a21ea9cb116434c19ec78b660","tests/correctness.rs":"4081f8019535305e3aa254c6a4e1436272dd873f9717c687ca0e66ea8d5871ed","tests/output_equivalence.rs":"b2cd7c59fa55808a2e66e9fe7f160d846867e3ecefe22c22a818f822c3c41f23","tests/parse.rs":"c2f7362e4679c1b4803b12ec6e8dca6da96aed7273fd210a857524a4182c30e7"},"package":"8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"}

336
vendor/addr2line/CHANGELOG.md vendored Normal file
View File

@ -0,0 +1,336 @@
# `addr2line` Change Log
--------------------------------------------------------------------------------
## 0.21.0 (2023/08/12)
### Breaking changes
* Updated `gimli`, `object`, and `fallible-iterator` dependencies.
### Changed
* The minimum supported rust version is 1.65.0.
* Store boxed slices instead of `Vec` objects in `Context`.
[#278](https://github.com/gimli-rs/addr2line/pull/278)
--------------------------------------------------------------------------------
## 0.20.0 (2023/04/15)
### Breaking changes
* The minimum supported rust version is 1.58.0.
* Changed `Context::find_frames` to return `LookupResult`.
Use `LookupResult::skip_all_loads` to obtain the result without loading split DWARF.
[#260](https://github.com/gimli-rs/addr2line/pull/260)
* Replaced `Context::find_dwarf_unit` with `Context::find_dwarf_and_unit`.
[#260](https://github.com/gimli-rs/addr2line/pull/260)
* Updated `object` dependency.
### Changed
* Fix handling of file index 0 for DWARF 5.
[#264](https://github.com/gimli-rs/addr2line/pull/264)
### Added
* Added types and methods to support loading split DWARF:
`LookupResult`, `SplitDwarfLoad`, `SplitDwarfLoader`, `Context::preload_units`.
[#260](https://github.com/gimli-rs/addr2line/pull/260)
[#262](https://github.com/gimli-rs/addr2line/pull/262)
[#263](https://github.com/gimli-rs/addr2line/pull/263)
--------------------------------------------------------------------------------
## 0.19.0 (2022/11/24)
### Breaking changes
* Updated `gimli` and `object` dependencies.
--------------------------------------------------------------------------------
## 0.18.0 (2022/07/16)
### Breaking changes
* Updated `object` dependency.
### Changed
* Fixed handling of relative path for `DW_AT_comp_dir`.
[#239](https://github.com/gimli-rs/addr2line/pull/239)
* Fixed handling of `DW_FORM_addrx` for DWARF 5 support.
[#243](https://github.com/gimli-rs/addr2line/pull/243)
* Fixed handling of units that are missing range information.
[#249](https://github.com/gimli-rs/addr2line/pull/249)
--------------------------------------------------------------------------------
## 0.17.0 (2021/10/24)
### Breaking changes
* Updated `gimli` and `object` dependencies.
### Changed
* Use `skip_attributes` to improve performance.
[#236](https://github.com/gimli-rs/addr2line/pull/236)
--------------------------------------------------------------------------------
## 0.16.0 (2021/07/26)
### Breaking changes
* Updated `gimli` and `object` dependencies.
--------------------------------------------------------------------------------
## 0.15.2 (2021/06/04)
### Fixed
* Allow `Context` to be `Send`.
[#219](https://github.com/gimli-rs/addr2line/pull/219)
--------------------------------------------------------------------------------
## 0.15.1 (2021/05/02)
### Fixed
* Don't ignore aranges with address 0.
[#217](https://github.com/gimli-rs/addr2line/pull/217)
--------------------------------------------------------------------------------
## 0.15.0 (2021/05/02)
### Breaking changes
* Updated `gimli` and `object` dependencies.
[#215](https://github.com/gimli-rs/addr2line/pull/215)
* Added `debug_aranges` parameter to `Context::from_sections`.
[#200](https://github.com/gimli-rs/addr2line/pull/200)
### Added
* Added `.debug_aranges` support.
[#200](https://github.com/gimli-rs/addr2line/pull/200)
* Added supplementary object file support.
[#208](https://github.com/gimli-rs/addr2line/pull/208)
### Fixed
* Fixed handling of Windows paths in locations.
[#209](https://github.com/gimli-rs/addr2line/pull/209)
* examples/addr2line: Flush stdout after each response.
[#210](https://github.com/gimli-rs/addr2line/pull/210)
* examples/addr2line: Avoid copying every section.
[#213](https://github.com/gimli-rs/addr2line/pull/213)
--------------------------------------------------------------------------------
## 0.14.1 (2020/12/31)
### Fixed
* Fix location lookup for skeleton units.
[#201](https://github.com/gimli-rs/addr2line/pull/201)
### Added
* Added `Context::find_location_range`.
[#196](https://github.com/gimli-rs/addr2line/pull/196)
[#199](https://github.com/gimli-rs/addr2line/pull/199)
--------------------------------------------------------------------------------
## 0.14.0 (2020/10/27)
### Breaking changes
* Updated `gimli` and `object` dependencies.
### Fixed
* Handle units that only have line information.
[#188](https://github.com/gimli-rs/addr2line/pull/188)
* Handle DWARF units with version <= 4 and no `DW_AT_name`.
[#191](https://github.com/gimli-rs/addr2line/pull/191)
* Fix handling of `DW_FORM_ref_addr`.
[#193](https://github.com/gimli-rs/addr2line/pull/193)
--------------------------------------------------------------------------------
## 0.13.0 (2020/07/07)
### Breaking changes
* Updated `gimli` and `object` dependencies.
* Added `rustc-dep-of-std` feature.
[#166](https://github.com/gimli-rs/addr2line/pull/166)
### Changed
* Improve performance by parsing function contents lazily.
[#178](https://github.com/gimli-rs/addr2line/pull/178)
* Don't skip `.debug_info` and `.debug_line` entries with a zero address.
[#182](https://github.com/gimli-rs/addr2line/pull/182)
--------------------------------------------------------------------------------
## 0.12.2 (2020/06/21)
### Fixed
* Avoid linear search for `DW_FORM_ref_addr`.
[#175](https://github.com/gimli-rs/addr2line/pull/175)
--------------------------------------------------------------------------------
## 0.12.1 (2020/05/19)
### Fixed
* Handle units with overlapping address ranges.
[#163](https://github.com/gimli-rs/addr2line/pull/163)
* Don't assert for functions with overlapping address ranges.
[#168](https://github.com/gimli-rs/addr2line/pull/168)
--------------------------------------------------------------------------------
## 0.12.0 (2020/05/12)
### Breaking changes
* Updated `gimli` and `object` dependencies.
* Added more optional features: `smallvec` and `fallible-iterator`.
[#160](https://github.com/gimli-rs/addr2line/pull/160)
### Added
* Added `Context::dwarf` and `Context::find_dwarf_unit`.
[#159](https://github.com/gimli-rs/addr2line/pull/159)
### Changed
* Removed `lazycell` dependency.
[#160](https://github.com/gimli-rs/addr2line/pull/160)
--------------------------------------------------------------------------------
## 0.11.0 (2020/01/11)
### Breaking changes
* Updated `gimli` and `object` dependencies.
* [#130](https://github.com/gimli-rs/addr2line/pull/130)
Changed `Location::file` from `Option<String>` to `Option<&str>`.
This required adding lifetime parameters to `Location` and other structs that
contain it.
* [#152](https://github.com/gimli-rs/addr2line/pull/152)
Changed `Location::line` and `Location::column` from `Option<u64>`to `Option<u32>`.
* [#156](https://github.com/gimli-rs/addr2line/pull/156)
Deleted `alloc` feature, and fixed `no-std` builds with stable rust.
Removed default `Reader` parameter for `Context`, and added `ObjectContext` instead.
### Added
* [#134](https://github.com/gimli-rs/addr2line/pull/134)
Added `Context::from_dwarf`.
### Changed
* [#133](https://github.com/gimli-rs/addr2line/pull/133)
Fixed handling of units that can't be parsed.
* [#155](https://github.com/gimli-rs/addr2line/pull/155)
Fixed `addr2line` output to match binutils.
* [#130](https://github.com/gimli-rs/addr2line/pull/130)
Improved `.debug_line` parsing performance.
* [#148](https://github.com/gimli-rs/addr2line/pull/148)
[#150](https://github.com/gimli-rs/addr2line/pull/150)
[#151](https://github.com/gimli-rs/addr2line/pull/151)
[#152](https://github.com/gimli-rs/addr2line/pull/152)
Improved `.debug_info` parsing performance.
* [#137](https://github.com/gimli-rs/addr2line/pull/137)
[#138](https://github.com/gimli-rs/addr2line/pull/138)
[#139](https://github.com/gimli-rs/addr2line/pull/139)
[#140](https://github.com/gimli-rs/addr2line/pull/140)
[#146](https://github.com/gimli-rs/addr2line/pull/146)
Improved benchmarks.
--------------------------------------------------------------------------------
## 0.10.0 (2019/07/07)
### Breaking changes
* [#127](https://github.com/gimli-rs/addr2line/pull/127)
Update `gimli`.
--------------------------------------------------------------------------------
## 0.9.0 (2019/05/02)
### Breaking changes
* [#121](https://github.com/gimli-rs/addr2line/pull/121)
Update `gimli`, `object`, and `fallible-iterator` dependencies.
### Added
* [#121](https://github.com/gimli-rs/addr2line/pull/121)
Reexport `gimli`, `object`, and `fallible-iterator`.
--------------------------------------------------------------------------------
## 0.8.0 (2019/02/06)
### Breaking changes
* [#107](https://github.com/gimli-rs/addr2line/pull/107)
Update `object` dependency to 0.11. This is part of the public API.
### Added
* [#101](https://github.com/gimli-rs/addr2line/pull/101)
Add `object` feature (enabled by default). Disable this feature to remove
the `object` dependency and `Context::new` API.
* [#102](https://github.com/gimli-rs/addr2line/pull/102)
Add `std` (enabled by default) and `alloc` features.
### Changed
* [#108](https://github.com/gimli-rs/addr2line/issues/108)
`demangle` no longer outputs the hash for rust symbols.
* [#109](https://github.com/gimli-rs/addr2line/issues/109)
Set default `R` for `Context<R>`.

704
vendor/addr2line/Cargo.lock generated vendored Normal file
View File

@ -0,0 +1,704 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "addr2line"
version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97"
dependencies = [
"gimli 0.27.2",
]
[[package]]
name = "addr2line"
version = "0.21.0"
dependencies = [
"backtrace",
"clap",
"compiler_builtins",
"cpp_demangle",
"fallible-iterator",
"findshlibs",
"gimli 0.28.0",
"libtest-mimic",
"memmap2",
"object 0.32.0",
"rustc-demangle",
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
"smallvec",
"typed-arena",
]
[[package]]
name = "adler"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "anstream"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is-terminal",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd"
[[package]]
name = "anstyle-parse"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
dependencies = [
"windows-sys",
]
[[package]]
name = "anstyle-wincon"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c677ab05e09154296dd37acecd46420c17b9713e8366facafa8fc0885167cf4c"
dependencies = [
"anstyle",
"windows-sys",
]
[[package]]
name = "backtrace"
version = "0.3.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca"
dependencies = [
"addr2line 0.19.0",
"cc",
"cfg-if",
"libc",
"miniz_oxide",
"object 0.30.3",
"rustc-demangle",
]
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cc"
version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "4.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c27cdf28c0f604ba3f512b0c9a409f8de8513e4816705deb0498b627e7c3a3fd"
dependencies = [
"clap_builder",
"clap_derive",
"once_cell",
]
[[package]]
name = "clap_builder"
version = "4.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08a9f1ab5e9f01a9b81f202e8562eb9a10de70abf9eaeac1be465c28b75aa4aa"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
"terminal_size",
]
[[package]]
name = "clap_derive"
version = "4.3.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54a9bb5758fc5dfe728d1019941681eccaf0cf8a4189b692a0ee2f2ecf90a050"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn 2.0.15",
]
[[package]]
name = "clap_lex"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b"
[[package]]
name = "colorchoice"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
name = "compiler_builtins"
version = "0.1.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "571298a3cce7e2afbd3d61abb91a18667d5ab25993ec577a88ee8ac45f00cc3a"
[[package]]
name = "cpp_demangle"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c76f98bdfc7f66172e6c7065f981ebb576ffc903fe4c0561d9f0c2509226dc6"
dependencies = [
"cfg-if",
]
[[package]]
name = "crc32fast"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
dependencies = [
"cfg-if",
]
[[package]]
name = "errno"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f"
dependencies = [
"errno-dragonfly",
"libc",
"windows-sys",
]
[[package]]
name = "errno-dragonfly"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
dependencies = [
"cc",
"libc",
]
[[package]]
name = "fallible-iterator"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
[[package]]
name = "findshlibs"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40b9e59cd0f7e0806cca4be089683ecb6434e602038df21fe6bf6711b2f07f64"
dependencies = [
"cc",
"lazy_static",
"libc",
"winapi",
]
[[package]]
name = "flate2"
version = "1.0.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841"
dependencies = [
"crc32fast",
"miniz_oxide",
]
[[package]]
name = "gimli"
version = "0.27.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4"
[[package]]
name = "gimli"
version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
dependencies = [
"compiler_builtins",
"fallible-iterator",
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
"stable_deref_trait",
]
[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "hermit-abi"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
dependencies = [
"libc",
]
[[package]]
name = "hermit-abi"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
[[package]]
name = "io-lifetimes"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
dependencies = [
"hermit-abi 0.3.2",
"libc",
"windows-sys",
]
[[package]]
name = "is-terminal"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
dependencies = [
"hermit-abi 0.3.2",
"rustix 0.38.8",
"windows-sys",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.147"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
[[package]]
name = "libtest-mimic"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d8de370f98a6cb8a4606618e53e802f93b094ddec0f96988eaec2c27e6e9ce7"
dependencies = [
"clap",
"termcolor",
"threadpool",
]
[[package]]
name = "linux-raw-sys"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
[[package]]
name = "linux-raw-sys"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503"
[[package]]
name = "memchr"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "memmap2"
version = "0.5.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327"
dependencies = [
"libc",
]
[[package]]
name = "miniz_oxide"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa"
dependencies = [
"adler",
]
[[package]]
name = "num_cpus"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
dependencies = [
"hermit-abi 0.2.6",
"libc",
]
[[package]]
name = "object"
version = "0.30.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439"
dependencies = [
"memchr",
]
[[package]]
name = "object"
version = "0.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77ac5bbd07aea88c60a577a1ce218075ffd59208b2d7ca97adf9bfc5aeb21ebe"
dependencies = [
"flate2",
"memchr",
"ruzstd",
]
[[package]]
name = "once_cell"
version = "1.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
[[package]]
name = "proc-macro2"
version = "1.0.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rustc-demangle"
version = "0.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4a36c42d1873f9a77c53bde094f9664d9891bc604a45b4798fd2c389ed12e5b"
[[package]]
name = "rustc-std-workspace-alloc"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff66d57013a5686e1917ed6a025d54dd591fcda71a41fe07edf4d16726aefa86"
[[package]]
name = "rustc-std-workspace-core"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1956f5517128a2b6f23ab2dadf1a976f4f5b27962e7724c2bf3d45e539ec098c"
[[package]]
name = "rustix"
version = "0.37.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06"
dependencies = [
"bitflags 1.3.2",
"errno",
"io-lifetimes",
"libc",
"linux-raw-sys 0.3.8",
"windows-sys",
]
[[package]]
name = "rustix"
version = "0.38.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19ed4fa021d81c8392ce04db050a3da9a60299050b7ae1cf482d862b54a7218f"
dependencies = [
"bitflags 2.4.0",
"errno",
"libc",
"linux-raw-sys 0.4.5",
"windows-sys",
]
[[package]]
name = "ruzstd"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3ffab8f9715a0d455df4bbb9d21e91135aab3cd3ca187af0cd0c3c3f868fdc"
dependencies = [
"byteorder",
"thiserror-core",
"twox-hash",
]
[[package]]
name = "smallvec"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
[[package]]
name = "stable_deref_trait"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "syn"
version = "2.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "termcolor"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
dependencies = [
"winapi-util",
]
[[package]]
name = "terminal_size"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237"
dependencies = [
"rustix 0.37.23",
"windows-sys",
]
[[package]]
name = "thiserror-core"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d97345f6437bb2004cd58819d8a9ef8e36cdd7661c2abc4bbde0a7c40d9f497"
dependencies = [
"thiserror-core-impl",
]
[[package]]
name = "thiserror-core-impl"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10ac1c5050e43014d16b2f94d0d2ce79e65ffdd8b38d8048f9c8f6a8a6da62ac"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "threadpool"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa"
dependencies = [
"num_cpus",
]
[[package]]
name = "twox-hash"
version = "1.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675"
dependencies = [
"cfg-if",
"static_assertions",
]
[[package]]
name = "typed-arena"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a"
[[package]]
name = "unicode-ident"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
[[package]]
name = "utf8parse"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.48.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
[[package]]
name = "windows_i686_gnu"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
[[package]]
name = "windows_i686_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"

147
vendor/addr2line/Cargo.toml vendored Normal file
View File

@ -0,0 +1,147 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies.
#
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.
[package]
edition = "2018"
rust-version = "1.65"
name = "addr2line"
version = "0.21.0"
exclude = [
"/benches/*",
"/fixtures/*",
".github",
]
description = "A cross-platform symbolication library written in Rust, using `gimli`"
documentation = "https://docs.rs/addr2line"
readme = "./README.md"
keywords = [
"DWARF",
"debug",
"elf",
"symbolicate",
"atos",
]
categories = ["development-tools::debugging"]
license = "Apache-2.0 OR MIT"
repository = "https://github.com/gimli-rs/addr2line"
[profile.bench]
codegen-units = 1
debug = true
[profile.release]
debug = true
[[example]]
name = "addr2line"
required-features = ["default"]
[[test]]
name = "output_equivalence"
harness = false
required-features = ["default"]
[[test]]
name = "correctness"
required-features = ["default"]
[[test]]
name = "parse"
required-features = ["std-object"]
[dependencies.alloc]
version = "1.0.0"
optional = true
package = "rustc-std-workspace-alloc"
[dependencies.compiler_builtins]
version = "0.1.2"
optional = true
[dependencies.core]
version = "1.0.0"
optional = true
package = "rustc-std-workspace-core"
[dependencies.cpp_demangle]
version = "0.4"
features = ["alloc"]
optional = true
default-features = false
[dependencies.fallible-iterator]
version = "0.3.0"
optional = true
default-features = false
[dependencies.gimli]
version = "0.28.0"
features = ["read"]
default-features = false
[dependencies.memmap2]
version = "0.5.5"
optional = true
[dependencies.object]
version = "0.32.0"
features = ["read"]
optional = true
default-features = false
[dependencies.rustc-demangle]
version = "0.1"
optional = true
[dependencies.smallvec]
version = "1"
optional = true
default-features = false
[dev-dependencies.backtrace]
version = "0.3.13"
[dev-dependencies.clap]
version = "4.3.21"
features = ["wrap_help"]
[dev-dependencies.findshlibs]
version = "0.10"
[dev-dependencies.libtest-mimic]
version = "0.6.1"
[dev-dependencies.typed-arena]
version = "2"
[features]
default = [
"rustc-demangle",
"cpp_demangle",
"std-object",
"fallible-iterator",
"smallvec",
"memmap2",
]
rustc-dep-of-std = [
"core",
"alloc",
"compiler_builtins",
"gimli/rustc-dep-of-std",
]
std = ["gimli/std"]
std-object = [
"std",
"object",
"object/std",
"object/compression",
"gimli/endian-reader",
]

View File

@ -1,201 +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.
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.

View File

@ -1,25 +1,25 @@
Copyright (c) 2014 The Rust Project 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.
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
vendor/addr2line/README.md vendored Normal file
View File

@ -0,0 +1,48 @@
# addr2line
[![](https://img.shields.io/crates/v/addr2line.svg)](https://crates.io/crates/addr2line)
[![](https://img.shields.io/docsrs/addr2line.svg)](https://docs.rs/addr2line)
[![Coverage Status](https://coveralls.io/repos/github/gimli-rs/addr2line/badge.svg?branch=master)](https://coveralls.io/github/gimli-rs/addr2line?branch=master)
A cross-platform library for retrieving per-address debug information
from files with DWARF debug information.
`addr2line` uses [`gimli`](https://github.com/gimli-rs/gimli) to parse
the debug information, and exposes an interface for finding
the source file, line number, and wrapping function for instruction
addresses within the target program. These lookups can either be
performed programmatically through `Context::find_location` and
`Context::find_frames`, or via the included example binary,
`addr2line` (named and modelled after the equivalent utility from
[GNU binutils](https://sourceware.org/binutils/docs/binutils/addr2line.html)).
# Quickstart
- Add the [`addr2line` crate](https://crates.io/crates/addr2line) to your `Cargo.toml`
- Load the file and parse it with [`addr2line::object::read::File::parse`](https://docs.rs/object/*/object/read/struct.File.html#method.parse)
- Pass the parsed file to [`addr2line::Context::new` ](https://docs.rs/addr2line/*/addr2line/struct.Context.html#method.new)
- Use [`addr2line::Context::find_location`](https://docs.rs/addr2line/*/addr2line/struct.Context.html#method.find_location)
or [`addr2line::Context::find_frames`](https://docs.rs/addr2line/*/addr2line/struct.Context.html#method.find_frames)
to look up debug information for an address
# Performance
`addr2line` optimizes for speed over memory by caching parsed information.
The DWARF information is parsed lazily where possible.
The library aims to perform similarly to equivalent existing tools such
as `addr2line` from binutils, `eu-addr2line` from elfutils, and
`llvm-symbolize` from the llvm project, and in the past some benchmarking
was done that indicates a comparable performance.
## License
Licensed under either of
* Apache License, Version 2.0 ([`LICENSE-APACHE`](./LICENSE-APACHE) or https://www.apache.org/licenses/LICENSE-2.0)
* MIT license ([`LICENSE-MIT`](./LICENSE-MIT) or https://opensource.org/licenses/MIT)
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
dual licensed as above, without any additional terms or conditions.

23
vendor/addr2line/bench.plot.r vendored Normal file
View 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
vendor/addr2line/benchmark.sh vendored Executable file
View 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
vendor/addr2line/coverage.sh vendored Normal file
View 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

317
vendor/addr2line/examples/addr2line.rs vendored Normal file
View File

@ -0,0 +1,317 @@
use std::borrow::Cow;
use std::fs::File;
use std::io::{BufRead, Lines, StdinLock, Write};
use std::path::{Path, PathBuf};
use clap::{Arg, ArgAction, Command};
use fallible_iterator::FallibleIterator;
use object::{Object, ObjectSection, SymbolMap, SymbolMapName};
use typed_arena::Arena;
use addr2line::{Context, Location};
fn parse_uint_from_hex_string(string: &str) -> Option<u64> {
if string.len() > 2 && string.starts_with("0x") {
u64::from_str_radix(&string[2..], 16).ok()
} else {
u64::from_str_radix(string, 16).ok()
}
}
enum Addrs<'a> {
Args(clap::parser::ValuesRef<'a, String>),
Stdin(Lines<StdinLock<'a>>),
}
impl<'a> Iterator for Addrs<'a> {
type Item = Option<u64>;
fn next(&mut self) -> Option<Option<u64>> {
let text = match *self {
Addrs::Args(ref mut vals) => vals.next().map(Cow::from),
Addrs::Stdin(ref mut lines) => lines.next().map(Result::unwrap).map(Cow::from),
};
text.as_ref()
.map(Cow::as_ref)
.map(parse_uint_from_hex_string)
}
}
fn print_loc(loc: Option<&Location<'_>>, basenames: bool, llvm: bool) {
if let Some(loc) = loc {
if let Some(ref file) = loc.file.as_ref() {
let path = if basenames {
Path::new(Path::new(file).file_name().unwrap())
} else {
Path::new(file)
};
print!("{}:", path.display());
} else {
print!("??:");
}
if llvm {
print!("{}:{}", loc.line.unwrap_or(0), loc.column.unwrap_or(0));
} else if let Some(line) = loc.line {
print!("{}", line);
} else {
print!("?");
}
println!();
} else if llvm {
println!("??:0:0");
} else {
println!("??:0");
}
}
fn print_function(name: Option<&str>, language: Option<gimli::DwLang>, demangle: bool) {
if let Some(name) = name {
if demangle {
print!("{}", addr2line::demangle_auto(Cow::from(name), language));
} else {
print!("{}", name);
}
} else {
print!("??");
}
}
fn load_file_section<'input, 'arena, Endian: gimli::Endianity>(
id: gimli::SectionId,
file: &object::File<'input>,
endian: Endian,
arena_data: &'arena Arena<Cow<'input, [u8]>>,
) -> Result<gimli::EndianSlice<'arena, Endian>, ()> {
// TODO: Unify with dwarfdump.rs in gimli.
let name = id.name();
match file.section_by_name(name) {
Some(section) => match section.uncompressed_data().unwrap() {
Cow::Borrowed(b) => Ok(gimli::EndianSlice::new(b, endian)),
Cow::Owned(b) => Ok(gimli::EndianSlice::new(arena_data.alloc(b.into()), endian)),
},
None => Ok(gimli::EndianSlice::new(&[][..], endian)),
}
}
fn find_name_from_symbols<'a>(
symbols: &'a SymbolMap<SymbolMapName<'_>>,
probe: u64,
) -> Option<&'a str> {
symbols.get(probe).map(|x| x.name())
}
struct Options<'a> {
do_functions: bool,
do_inlines: bool,
pretty: bool,
print_addrs: bool,
basenames: bool,
demangle: bool,
llvm: bool,
exe: &'a PathBuf,
sup: Option<&'a PathBuf>,
}
fn main() {
let matches = Command::new("addr2line")
.version(env!("CARGO_PKG_VERSION"))
.about("A fast addr2line Rust port")
.max_term_width(100)
.args(&[
Arg::new("exe")
.short('e')
.long("exe")
.value_name("filename")
.value_parser(clap::value_parser!(PathBuf))
.help(
"Specify the name of the executable for which addresses should be translated.",
)
.required(true),
Arg::new("sup")
.long("sup")
.value_name("filename")
.value_parser(clap::value_parser!(PathBuf))
.help("Path to supplementary object file."),
Arg::new("functions")
.short('f')
.long("functions")
.action(ArgAction::SetTrue)
.help("Display function names as well as file and line number information."),
Arg::new("pretty").short('p').long("pretty-print")
.action(ArgAction::SetTrue)
.help(
"Make the output more human friendly: each location are printed on one line.",
),
Arg::new("inlines").short('i').long("inlines")
.action(ArgAction::SetTrue)
.help(
"If the address belongs to a function that was inlined, the source information for \
all enclosing scopes back to the first non-inlined function will also be printed.",
),
Arg::new("addresses").short('a').long("addresses")
.action(ArgAction::SetTrue)
.help(
"Display the address before the function name, file and line number information.",
),
Arg::new("basenames")
.short('s')
.long("basenames")
.action(ArgAction::SetTrue)
.help("Display only the base of each file name."),
Arg::new("demangle").short('C').long("demangle")
.action(ArgAction::SetTrue)
.help(
"Demangle function names. \
Specifying a specific demangling style (like GNU addr2line) is not supported. \
(TODO)"
),
Arg::new("llvm")
.long("llvm")
.action(ArgAction::SetTrue)
.help("Display output in the same format as llvm-symbolizer."),
Arg::new("addrs")
.action(ArgAction::Append)
.help("Addresses to use instead of reading from stdin."),
])
.get_matches();
let arena_data = Arena::new();
let opts = Options {
do_functions: matches.get_flag("functions"),
do_inlines: matches.get_flag("inlines"),
pretty: matches.get_flag("pretty"),
print_addrs: matches.get_flag("addresses"),
basenames: matches.get_flag("basenames"),
demangle: matches.get_flag("demangle"),
llvm: matches.get_flag("llvm"),
exe: matches.get_one::<PathBuf>("exe").unwrap(),
sup: matches.get_one::<PathBuf>("sup"),
};
let file = File::open(opts.exe).unwrap();
let map = unsafe { memmap2::Mmap::map(&file).unwrap() };
let object = &object::File::parse(&*map).unwrap();
let endian = if object.is_little_endian() {
gimli::RunTimeEndian::Little
} else {
gimli::RunTimeEndian::Big
};
let mut load_section = |id: gimli::SectionId| -> Result<_, _> {
load_file_section(id, object, endian, &arena_data)
};
let sup_map;
let sup_object = if let Some(sup_path) = opts.sup {
let sup_file = File::open(sup_path).unwrap();
sup_map = unsafe { memmap2::Mmap::map(&sup_file).unwrap() };
Some(object::File::parse(&*sup_map).unwrap())
} else {
None
};
let symbols = object.symbol_map();
let mut dwarf = gimli::Dwarf::load(&mut load_section).unwrap();
if let Some(ref sup_object) = sup_object {
let mut load_sup_section = |id: gimli::SectionId| -> Result<_, _> {
load_file_section(id, sup_object, endian, &arena_data)
};
dwarf.load_sup(&mut load_sup_section).unwrap();
}
let mut split_dwarf_loader = addr2line::builtin_split_dwarf_loader::SplitDwarfLoader::new(
|data, endian| {
gimli::EndianSlice::new(arena_data.alloc(Cow::Owned(data.into_owned())), endian)
},
Some(opts.exe.clone()),
);
let ctx = Context::from_dwarf(dwarf).unwrap();
let stdin = std::io::stdin();
let addrs = matches
.get_many::<String>("addrs")
.map(Addrs::Args)
.unwrap_or_else(|| Addrs::Stdin(stdin.lock().lines()));
for probe in addrs {
if opts.print_addrs {
let addr = probe.unwrap_or(0);
if opts.llvm {
print!("0x{:x}", addr);
} else {
print!("0x{:016x}", addr);
}
if opts.pretty {
print!(": ");
} else {
println!();
}
}
if opts.do_functions || opts.do_inlines {
let mut printed_anything = false;
if let Some(probe) = probe {
let frames = ctx.find_frames(probe);
let frames = split_dwarf_loader.run(frames).unwrap();
let mut frames = frames.enumerate();
while let Some((i, frame)) = frames.next().unwrap() {
if opts.pretty && i != 0 {
print!(" (inlined by) ");
}
if opts.do_functions {
if let Some(func) = frame.function {
print_function(
func.raw_name().ok().as_ref().map(AsRef::as_ref),
func.language,
opts.demangle,
);
} else {
let name = find_name_from_symbols(&symbols, probe);
print_function(name, None, opts.demangle);
}
if opts.pretty {
print!(" at ");
} else {
println!();
}
}
print_loc(frame.location.as_ref(), opts.basenames, opts.llvm);
printed_anything = true;
if !opts.do_inlines {
break;
}
}
}
if !printed_anything {
if opts.do_functions {
let name = probe.and_then(|probe| find_name_from_symbols(&symbols, probe));
print_function(name, None, opts.demangle);
if opts.pretty {
print!(" at ");
} else {
println!();
}
}
print_loc(None, opts.basenames, opts.llvm);
}
} else {
let loc = probe.and_then(|probe| ctx.find_location(probe).unwrap());
print_loc(loc.as_ref(), opts.basenames, opts.llvm);
}
if opts.llvm {
println!();
}
std::io::stdout().flush().unwrap();
}
}

View 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
vendor/addr2line/src/function.rs vendored Normal file
View 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
vendor/addr2line/src/lazy.rs vendored Normal file
View 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
vendor/addr2line/src/lib.rs vendored Normal file

File diff suppressed because it is too large Load Diff

126
vendor/addr2line/tests/correctness.rs vendored Normal file
View 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
);
}
}

View 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
vendor/addr2line/tests/parse.rs vendored Normal file
View 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
vendor/adler/.cargo-checksum.json vendored Normal file
View 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
vendor/adler/CHANGELOG.md vendored Normal file
View 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
vendor/adler/Cargo.toml vendored Normal file
View 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
vendor/adler/LICENSE-0BSD vendored Normal file
View 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
vendor/adler/LICENSE-APACHE vendored Normal file
View 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.

23
vendor/adler/LICENSE-MIT vendored Normal file
View File

@ -0,0 +1,23 @@
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.

39
vendor/adler/README.md vendored Normal file
View File

@ -0,0 +1,39 @@
# Adler-32 checksums for Rust
[![crates.io](https://img.shields.io/crates/v/adler.svg)](https://crates.io/crates/adler)
[![docs.rs](https://docs.rs/adler/badge.svg)](https://docs.rs/adler/)
![CI](https://github.com/jonas-schievink/adler/workflows/CI/badge.svg)
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
vendor/adler/RELEASE_PROCESS.md vendored Normal file
View 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
vendor/adler/benches/bench.rs vendored Normal file
View 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
vendor/adler/src/algo.rs vendored Normal file
View 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 + (n1)×D2 + (n2)×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
vendor/adler/src/lib.rs vendored Normal file
View 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);
}
}

View File

@ -1 +1 @@
{"files":{"Cargo.toml":"5779c6bea2555cdabd4560de187ac5e3c88ff2df8172077397643edc51c6fcc3","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"4bd4d352368ac0f5447031d82454490f6ac0c80d2fa4cb64ba0c23c614670d49","build.rs":"88bf7100143c79c0af683da7f28deaac031c9b9b213a6426560dc089b0ba45aa","rust-toolchain.toml":"6bbb61302978c736b2da03e4fb40e3beab908f85d533ab46fd541e637b5f3e0f","src/backtrace.rs":"5b4103a7d24d6f438a64b8cc0fafe28d55fc0ca090368174ce44d64e3940badd","src/chain.rs":"6edefc5f3c7d69683095862e54e3bb56faba5b3387bf2eeaed429da090007a0a","src/context.rs":"0bb1566aae147d393796dd6ede6ba329916e0a373b7cbc38335c3eeeb3d48b57","src/ensure.rs":"498bc9c7fb8b93168ed12f532cb97df6ccdda9ce25371586d7f5b1b1c98a14bf","src/error.rs":"e45d4dcfe64b1823b42fbf9bb260e6437987e8c2d51f92434db9d808b36e700a","src/fmt.rs":"c2d4aad6ce20625a70a7c091e3087b6a2c19a4a87c7a12edb4c98978307245ea","src/kind.rs":"332854c5eb07d44447c356a2e7dc585634b0da1ffbbfa81269c369deaefbc247","src/lib.rs":"82011e86fb9b41fe10ab2fde2b797b4858e697e7ead3a5f0d30b018357f1721d","src/macros.rs":"dd35f2ec2a0a25e4504fb04bcd42f6d0963bc0035aaaefc412f5ee1d78945fe1","src/ptr.rs":"f4e28bc9feba1e84160ca9d185008a51b5d72e168e6546f3e942f4258c361e19","src/wrapper.rs":"ff3ad72065a30cc32e9acb0614a30703c49c57b941a335c348b6439af684316b","tests/common/mod.rs":"f9088c2d7afafa64ff730b629272045b776bfafc2f5957508242da630635f2e1","tests/compiletest.rs":"022a8e400ef813d7ea1875b944549cee5125f6a995dc33e93b48cba3e1b57bd1","tests/drop/mod.rs":"08c3e553c1cc0d2dbd936fc45f4b5b1105057186affd6865e8d261e05f0f0646","tests/test_autotrait.rs":"981e792db353be2f14c7a1cabe43b5f1329c168cb7679077cc2be786a0920d48","tests/test_backtrace.rs":"0e50edbb33b6bd07ba89ff3db72fb7c688ba2a4371fccdbbb20309ab02948b6a","tests/test_boxed.rs":"6b26db0e2eb72afe9af7352ea820837aab90f8d486294616dd5dc34c1b94038c","tests/test_chain.rs":"d5e90e3eba58abc60d241d3aade39e0b8d4006d9a14f3cf015d3d925160b5812","tests/test_context.rs":"8409c53b328562c11e822bd6c3cd17e0d4d50b9bbb8fc3617333fd77303a6a33","tests/test_convert.rs":"7e7a8b4772a427a911014ac4d1083f9519000e786177f898808980dd9bdfde61","tests/test_downcast.rs":"797e69a72d125758c4c4897e5dc776d549d52cc9a6a633e0a33193f588a62b88","tests/test_ensure.rs":"c8137a9565685aedf02b365008b27c707f4c3d81cd2b986b3b7105b426c723b1","tests/test_ffi.rs":"d0cb4c1d6d9154090982dee72ae3ebe05a5981f976058c3250f1c9da5a45edef","tests/test_fmt.rs":"17572596f257aac9aa2ec4620e292ca6a954128b94772bb948399fab53832e70","tests/test_macros.rs":"11f05010bc9b16319884c1286444100e30cddc2ecd1ffe5e0fd3fee5ffb32683","tests/test_repr.rs":"dbb9b04ddbe1ab31eb5331ea69f05bb3a147299da2275a3d4dcc92947b5591b9","tests/test_source.rs":"b80723cf635a4f8c4df21891b34bfab9ed2b2aa407e7a2f826d24e334cd5f88e","tests/ui/chained-comparison.rs":"6504b03d95b5acc232a7f4defc9f343b2be6733bf475fa0992e8e6545b912bd4","tests/ui/chained-comparison.stderr":"7f1d0a8c251b0ede2d30b3087ec157fc660945c97a642c4a5acf5a14ec58de34","tests/ui/empty-ensure.rs":"ab5bf37c846a0d689f26ce9257a27228411ed64154f9c950f1602d88a355d94b","tests/ui/empty-ensure.stderr":"345102cbef47310f2f4066a669199873a627ca4f1fcb885505c6e17d1fc95e88","tests/ui/must-use.rs":"fb59860b43f673bf4a430a6036ba463e95028844d8dd4243cfe5ebc7f2be582f","tests/ui/must-use.stderr":"c2848c5f254b4c061eea6714d9baf709924aba06619eaf2a8b3aee1266b75f9e","tests/ui/no-impl.rs":"fab6cbf2f6ea510b86f567dfb3b7c31250a9fd71ae5d110dbb9188be569ec593","tests/ui/no-impl.stderr":"9d36a96220f0b5a81db027bcba411a61a72cc2e370c38058ab556442e8bb8a8b","tests/ui/temporary-value.rs":"4dcc96271b2403e6372cf4cfc813445e5ce4365fc6e156b6bc38274098499a70","tests/ui/temporary-value.stderr":"64e448b6759cf51d41b1360307a638452bbe53ffa706f93e4a503b712d7b89a8","tests/ui/wrong-interpolation.rs":"9c44d4674c2dccd27b9dedd03341346ec02d993b41793ee89b5755202e7e367e","tests/ui/wrong-interpolation.stderr":"301e60e2eb9401782c7dc0b3580613a4cb2aafd4cc8065734a630a62e1161aa5"},"package":"98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602"}
{"files":{"Cargo.toml":"57c31a9c69df69ad3038d1319cf3e6282e0543b9863a5509a0e7d47625bb97f5","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"0999fd320cdb3300dd22ff03b97cd41945cc9833a02a5b7c53ed36ab6d6f66e7","build.rs":"a5ac61a8922f6b9bf319e2f8c0c20bdafb362b9c1f7805fc6d878660708e5ac2","build/probe.rs":"b8b792036f13c9c1fbc6b1244198ea2305e61ddfcda3856563b581dcb1e1fe6e","rust-toolchain.toml":"6bbb61302978c736b2da03e4fb40e3beab908f85d533ab46fd541e637b5f3e0f","src/backtrace.rs":"f3bcaddc8665442611ae0f31ce7e9c19ede55d4a3022ffeb16f4c982bca7f018","src/chain.rs":"e83ee788dc5bb6bebba64356b35abbd5b624f2449d47e3716d02b2473fb8e5c5","src/context.rs":"04e4b80b9f6d8163edc53455b98ab0c40cb9ad104bcf0c74f8075f22024471ab","src/ensure.rs":"d4c2588608e529275bfee1c1afc8860d7def868ab01e95a692a995ee06b2936e","src/error.rs":"a274234af662770340b237c9016beea2f94e7906f3fe69d0d78057929889f25b","src/fmt.rs":"adf4be906b29900153bfb4b767a6049d58697dc3bcce7dfbb85ca773f5de5b33","src/kind.rs":"febaac378b8bfca7b95a76c9bf9fbd8ccdfd0cc1a6277cdc109a2cda5763f16e","src/lib.rs":"fa8d1209787ebf54242c9ea048a0b243dfafa6418939814a3ee12a4268d556e1","src/macros.rs":"dd35f2ec2a0a25e4504fb04bcd42f6d0963bc0035aaaefc412f5ee1d78945fe1","src/ptr.rs":"4cb31d2f815b178daf951bfb94a1930383e056c0ca68d494603f45d8eea35d50","src/wrapper.rs":"4ffdf284d45fee90f11a48e59c493ed1114e1243903ceb265fa89cd4c8c0d338","tests/common/mod.rs":"f9088c2d7afafa64ff730b629272045b776bfafc2f5957508242da630635f2e1","tests/compiletest.rs":"022a8e400ef813d7ea1875b944549cee5125f6a995dc33e93b48cba3e1b57bd1","tests/drop/mod.rs":"08c3e553c1cc0d2dbd936fc45f4b5b1105057186affd6865e8d261e05f0f0646","tests/test_autotrait.rs":"ecccf9202a33611f64b76598806aa82abec2560ae058e32f63fb2fb3ef225be9","tests/test_backtrace.rs":"ed144f90bf62cc441de067f6cee09ece94bca9da8f9b492d11d3dc652ba83e26","tests/test_boxed.rs":"6b26db0e2eb72afe9af7352ea820837aab90f8d486294616dd5dc34c1b94038c","tests/test_chain.rs":"3a8a8d7569913bd98c0e27c69d0bda35101e7fde7c056ed57cdd8ed018e4cbcb","tests/test_context.rs":"8409c53b328562c11e822bd6c3cd17e0d4d50b9bbb8fc3617333fd77303a6a33","tests/test_convert.rs":"7e7a8b4772a427a911014ac4d1083f9519000e786177f898808980dd9bdfde61","tests/test_downcast.rs":"797e69a72d125758c4c4897e5dc776d549d52cc9a6a633e0a33193f588a62b88","tests/test_ensure.rs":"89bb15f2a6288037bcf6ad976705038d9bea714da4244dee8314c720f88393c8","tests/test_ffi.rs":"d0cb4c1d6d9154090982dee72ae3ebe05a5981f976058c3250f1c9da5a45edef","tests/test_fmt.rs":"81b14dd207ba5fbf02aaed031646810906c9c9c2fc5cabffc8e88f82462be499","tests/test_macros.rs":"5172f82a6ad25b75f668f6419d161de3d12b8666d54701739fe33e86e4ddf148","tests/test_repr.rs":"034dee888abd08741e11ac2e95ef4fcb2ab3943d0a76e8e976db404658e1a252","tests/test_source.rs":"b80723cf635a4f8c4df21891b34bfab9ed2b2aa407e7a2f826d24e334cd5f88e","tests/ui/chained-comparison.rs":"6504b03d95b5acc232a7f4defc9f343b2be6733bf475fa0992e8e6545b912bd4","tests/ui/chained-comparison.stderr":"7f1d0a8c251b0ede2d30b3087ec157fc660945c97a642c4a5acf5a14ec58de34","tests/ui/empty-ensure.rs":"ab5bf37c846a0d689f26ce9257a27228411ed64154f9c950f1602d88a355d94b","tests/ui/empty-ensure.stderr":"315782f5f4246290fe190e3767b22c3dcaffaabc19c5ace0373537d53e765278","tests/ui/must-use.rs":"fb59860b43f673bf4a430a6036ba463e95028844d8dd4243cfe5ebc7f2be582f","tests/ui/must-use.stderr":"c2848c5f254b4c061eea6714d9baf709924aba06619eaf2a8b3aee1266b75f9e","tests/ui/no-impl.rs":"fab6cbf2f6ea510b86f567dfb3b7c31250a9fd71ae5d110dbb9188be569ec593","tests/ui/no-impl.stderr":"6f1fd1c620a1319e98b261e4a42b9346c28154310c5bb3dc6d6ded72fbdf638d","tests/ui/temporary-value.rs":"4dcc96271b2403e6372cf4cfc813445e5ce4365fc6e156b6bc38274098499a70","tests/ui/temporary-value.stderr":"171f6c1c962503855480696e5d39e68946ec2a027b61a6f36ca1ad1b40265c5d","tests/ui/wrong-interpolation.rs":"9c44d4674c2dccd27b9dedd03341346ec02d993b41793ee89b5755202e7e367e","tests/ui/wrong-interpolation.stderr":"301e60e2eb9401782c7dc0b3580613a4cb2aafd4cc8065734a630a62e1161aa5"},"package":"5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1"}

View File

@ -11,9 +11,9 @@
[package]
edition = "2018"
rust-version = "1.38"
rust-version = "1.39"
name = "anyhow"
version = "1.0.65"
version = "1.0.80"
authors = ["David Tolnay <dtolnay@gmail.com>"]
description = "Flexible concrete Error type built on std::error::Error"
documentation = "https://docs.rs/anyhow"
@ -30,11 +30,15 @@ license = "MIT OR Apache-2.0"
repository = "https://github.com/dtolnay/anyhow"
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
rustdoc-args = [
"--cfg",
"doc_cfg",
"--generate-link-to-definition",
]
targets = ["x86_64-unknown-linux-gnu"]
[lib]
doc-scrape-examples = false
[dependencies.backtrace]
version = "0.3.51"
@ -48,14 +52,14 @@ default-features = false
version = "1.0.6"
[dev-dependencies.syn]
version = "1.0"
version = "2.0"
features = ["full"]
[dev-dependencies.thiserror]
version = "1.0"
version = "1.0.45"
[dev-dependencies.trybuild]
version = "1.0.49"
version = "1.0.66"
features = ["diff"]
[features]

View File

@ -174,28 +174,3 @@ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
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.

View File

@ -4,7 +4,7 @@ Anyhow&ensp;¯\\\_(°ペ)\_/¯
[<img alt="github" src="https://img.shields.io/badge/github-dtolnay/anyhow-8da0cb?style=for-the-badge&labelColor=555555&logo=github" height="20">](https://github.com/dtolnay/anyhow)
[<img alt="crates.io" src="https://img.shields.io/crates/v/anyhow.svg?style=for-the-badge&color=fc8d62&logo=rust" height="20">](https://crates.io/crates/anyhow)
[<img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-anyhow-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs" height="20">](https://docs.rs/anyhow)
[<img alt="build status" src="https://img.shields.io/github/workflow/status/dtolnay/anyhow/CI/master?style=for-the-badge" height="20">](https://github.com/dtolnay/anyhow/actions?query=branch%3Amaster)
[<img alt="build status" src="https://img.shields.io/github/actions/workflow/status/dtolnay/anyhow/ci.yml?branch=master&style=for-the-badge" height="20">](https://github.com/dtolnay/anyhow/actions?query=branch%3Amaster)
This library provides [`anyhow::Error`][Error], a trait object based error type
for easy idiomatic error handling in Rust applications.
@ -16,7 +16,7 @@ for easy idiomatic error handling in Rust applications.
anyhow = "1.0"
```
*Compiler support: requires rustc 1.38+*
*Compiler support: requires rustc 1.39+*
<br>
@ -75,10 +75,10 @@ anyhow = "1.0"
}
```
- If using the nightly channel, or stable with `features = ["backtrace"]`, a
backtrace is captured and printed with the error if the underlying error type
does not already provide its own. In order to see backtraces, they must be
enabled through the environment variables described in [`std::backtrace`]:
- If using Rust &ge; 1.65, a backtrace is captured and printed with the error if
the underlying error type does not already provide its own. In order to see
backtraces, they must be enabled through the environment variables described
in [`std::backtrace`]:
- If you want panics and errors to both have backtraces, set
`RUST_BACKTRACE=1`;
@ -86,10 +86,7 @@ anyhow = "1.0"
- If you want only panics to have backtraces, set `RUST_BACKTRACE=1` and
`RUST_LIB_BACKTRACE=0`.
The tracking issue for this feature is [rust-lang/rust#53487].
[`std::backtrace`]: https://doc.rust-lang.org/std/backtrace/index.html#environment-variables
[rust-lang/rust#53487]: https://github.com/rust-lang/rust/issues/53487
- Anyhow works with any error type that has an impl of `std::error::Error`,
including ones defined in your crate. We do not bundle a `derive(Error)` macro

158
vendor/anyhow/build.rs vendored
View File

@ -1,9 +1,7 @@
#![allow(clippy::option_if_let_else)]
use std::env;
use std::fs;
use std::ffi::OsString;
use std::path::Path;
use std::process::{Command, ExitStatus, Stdio};
use std::process::{self, Command, Stdio};
use std::str;
#[cfg(all(feature = "backtrace", not(feature = "std")))]
@ -11,56 +9,53 @@ compile_error! {
"`backtrace` feature without `std` feature is not supported"
}
// This code exercises the surface area that we expect of the std Backtrace
// type. If the current toolchain is able to compile it, we go ahead and use
// backtrace in anyhow.
const PROBE: &str = r#"
#![feature(error_generic_member_access, provide_any)]
use std::any::{Demand, Provider};
use std::backtrace::{Backtrace, BacktraceStatus};
use std::error::Error;
use std::fmt::{self, Display};
#[derive(Debug)]
struct E {
backtrace: Backtrace,
}
impl Display for E {
fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result {
unimplemented!()
}
}
impl Error for E {
fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
demand.provide_ref(&self.backtrace);
}
}
struct P;
impl Provider for P {
fn provide<'a>(&'a self, _demand: &mut Demand<'a>) {}
}
const _: fn() = || {
let backtrace: Backtrace = Backtrace::capture();
let status: BacktraceStatus = backtrace.status();
match status {
BacktraceStatus::Captured | BacktraceStatus::Disabled | _ => {}
}
};
const _: fn(&dyn Error) -> Option<&Backtrace> = |err| err.request_ref::<Backtrace>();
"#;
fn main() {
let mut error_generic_member_access = false;
if cfg!(feature = "std") {
match compile_probe() {
Some(status) if status.success() => println!("cargo:rustc-cfg=backtrace"),
_ => {}
println!("cargo:rerun-if-changed=build/probe.rs");
let consider_rustc_bootstrap;
if compile_probe(false) {
// This is a nightly or dev compiler, so it supports unstable
// features regardless of RUSTC_BOOTSTRAP. No need to rerun build
// script if RUSTC_BOOTSTRAP is changed.
error_generic_member_access = true;
consider_rustc_bootstrap = false;
} else if let Some(rustc_bootstrap) = env::var_os("RUSTC_BOOTSTRAP") {
if compile_probe(true) {
// This is a stable or beta compiler for which the user has set
// RUSTC_BOOTSTRAP to turn on unstable features. Rerun build
// script if they change it.
error_generic_member_access = true;
consider_rustc_bootstrap = true;
} else if rustc_bootstrap == "1" {
// This compiler does not support the generic member access API
// in the form that anyhow expects. No need to pay attention to
// RUSTC_BOOTSTRAP.
error_generic_member_access = false;
consider_rustc_bootstrap = false;
} else {
// This is a stable or beta compiler for which RUSTC_BOOTSTRAP
// is set to restrict the use of unstable features by this
// crate.
error_generic_member_access = false;
consider_rustc_bootstrap = true;
}
} else {
// Without RUSTC_BOOTSTRAP, this compiler does not support the
// generic member access API in the form that anyhow expects, but
// try again if the user turns on unstable features.
error_generic_member_access = false;
consider_rustc_bootstrap = true;
}
if error_generic_member_access {
println!("cargo:rustc-cfg=std_backtrace");
println!("cargo:rustc-cfg=error_generic_member_access");
}
if consider_rustc_bootstrap {
println!("cargo:rerun-if-env-changed=RUSTC_BOOTSTRAP");
}
}
@ -70,19 +65,43 @@ fn main() {
};
if rustc < 51 {
// core::ptr::addr_of
// https://blog.rust-lang.org/2021/03/25/Rust-1.51.0.html#stabilized-apis
println!("cargo:rustc-cfg=anyhow_no_ptr_addr_of");
}
if rustc < 52 {
// core::fmt::Arguments::as_str
// https://blog.rust-lang.org/2021/05/06/Rust-1.52.0.html#stabilized-apis
println!("cargo:rustc-cfg=anyhow_no_fmt_arguments_as_str");
// #![deny(unsafe_op_in_unsafe_fn)]
// https://github.com/rust-lang/rust/issues/71668
println!("cargo:rustc-cfg=anyhow_no_unsafe_op_in_unsafe_fn_lint");
}
if !error_generic_member_access && cfg!(feature = "std") && rustc >= 65 {
// std::backtrace::Backtrace
// https://blog.rust-lang.org/2022/11/03/Rust-1.65.0.html#stabilized-apis
println!("cargo:rustc-cfg=std_backtrace");
}
}
fn compile_probe() -> Option<ExitStatus> {
let rustc = env::var_os("RUSTC")?;
let out_dir = env::var_os("OUT_DIR")?;
let probefile = Path::new(&out_dir).join("probe.rs");
fs::write(&probefile, PROBE).ok()?;
fn compile_probe(rustc_bootstrap: bool) -> bool {
if env::var_os("RUSTC_STAGE").is_some() {
// We are running inside rustc bootstrap. This is a highly non-standard
// environment with issues such as:
//
// https://github.com/rust-lang/cargo/issues/11138
// https://github.com/rust-lang/rust/issues/114839
//
// Let's just not use nightly features here.
return false;
}
let rustc = cargo_env_var("RUSTC");
let out_dir = cargo_env_var("OUT_DIR");
let probefile = Path::new("build").join("probe.rs");
// Make sure to pick up Cargo rustc configuration.
let mut cmd = if let Some(wrapper) = env::var_os("RUSTC_WRAPPER") {
@ -94,11 +113,15 @@ fn compile_probe() -> Option<ExitStatus> {
Command::new(rustc)
};
if !rustc_bootstrap {
cmd.env_remove("RUSTC_BOOTSTRAP");
}
cmd.stderr(Stdio::null())
.arg("--edition=2018")
.arg("--crate-name=anyhow_build")
.arg("--crate-name=anyhow")
.arg("--crate-type=lib")
.arg("--emit=metadata")
.arg("--emit=dep-info,metadata")
.arg("--out-dir")
.arg(out_dir)
.arg(probefile);
@ -116,11 +139,14 @@ fn compile_probe() -> Option<ExitStatus> {
}
}
cmd.status().ok()
match cmd.status() {
Ok(status) => status.success(),
Err(_) => false,
}
}
fn rustc_minor_version() -> Option<u32> {
let rustc = env::var_os("RUSTC")?;
let rustc = cargo_env_var("RUSTC");
let output = Command::new(rustc).arg("--version").output().ok()?;
let version = str::from_utf8(&output.stdout).ok()?;
let mut pieces = version.split('.');
@ -129,3 +155,13 @@ fn rustc_minor_version() -> Option<u32> {
}
pieces.next()?.parse().ok()
}
fn cargo_env_var(key: &str) -> OsString {
env::var_os(key).unwrap_or_else(|| {
eprintln!(
"Environment variable ${} is not set during execution of build script",
key,
);
process::exit(1);
})
}

35
vendor/anyhow/build/probe.rs vendored Normal file
View File

@ -0,0 +1,35 @@
// This code exercises the surface area that we expect of the Error generic
// member access API. If the current toolchain is able to compile it, then
// anyhow is able to provide backtrace support.
#![feature(error_generic_member_access)]
use std::backtrace::Backtrace;
use std::error::{self, Error, Request};
use std::fmt::{self, Debug, Display};
struct MyError(Thing);
struct Thing;
impl Debug for MyError {
fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result {
unimplemented!()
}
}
impl Display for MyError {
fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result {
unimplemented!()
}
}
impl Error for MyError {
fn provide<'a>(&'a self, request: &mut Request<'a>) {
request.provide_ref(&self.0);
}
}
const _: fn(&dyn Error) -> Option<&Backtrace> = |err| error::request_ref::<Backtrace>(err);
// Include in sccache cache key.
const _: Option<&str> = option_env!("RUSTC_BOOTSTRAP");

View File

@ -1,71 +1,75 @@
#[cfg(backtrace)]
#[cfg(std_backtrace)]
pub(crate) use std::backtrace::{Backtrace, BacktraceStatus};
#[cfg(all(not(backtrace), feature = "backtrace"))]
#[cfg(all(not(std_backtrace), feature = "backtrace"))]
pub(crate) use self::capture::{Backtrace, BacktraceStatus};
#[cfg(not(any(backtrace, feature = "backtrace")))]
#[cfg(not(any(std_backtrace, feature = "backtrace")))]
pub(crate) enum Backtrace {}
#[cfg(backtrace)]
#[cfg(std_backtrace)]
macro_rules! impl_backtrace {
() => {
std::backtrace::Backtrace
};
}
#[cfg(all(not(backtrace), feature = "backtrace"))]
#[cfg(all(not(std_backtrace), feature = "backtrace"))]
macro_rules! impl_backtrace {
() => {
impl core::fmt::Debug + core::fmt::Display
};
}
#[cfg(any(backtrace, feature = "backtrace"))]
#[cfg(any(std_backtrace, feature = "backtrace"))]
macro_rules! backtrace {
() => {
Some(crate::backtrace::Backtrace::capture())
};
}
#[cfg(not(any(backtrace, feature = "backtrace")))]
#[cfg(not(any(std_backtrace, feature = "backtrace")))]
macro_rules! backtrace {
() => {
None
};
}
#[cfg(backtrace)]
#[cfg(error_generic_member_access)]
macro_rules! backtrace_if_absent {
($err:expr) => {
match ($err as &dyn std::error::Error).request_ref::<std::backtrace::Backtrace>() {
match std::error::request_ref::<std::backtrace::Backtrace>($err as &dyn std::error::Error) {
Some(_) => None,
None => backtrace!(),
}
};
}
#[cfg(all(feature = "std", not(backtrace), feature = "backtrace"))]
#[cfg(all(
feature = "std",
not(error_generic_member_access),
any(std_backtrace, feature = "backtrace")
))]
macro_rules! backtrace_if_absent {
($err:expr) => {
backtrace!()
};
}
#[cfg(all(feature = "std", not(backtrace), not(feature = "backtrace")))]
#[cfg(all(feature = "std", not(std_backtrace), not(feature = "backtrace")))]
macro_rules! backtrace_if_absent {
($err:expr) => {
None
};
}
#[cfg(all(not(backtrace), feature = "backtrace"))]
#[cfg(all(not(std_backtrace), feature = "backtrace"))]
mod capture {
use alloc::borrow::Cow;
use backtrace::{BacktraceFmt, BytesOrWideString, Frame, PrintFmt, SymbolName};
use core::cell::UnsafeCell;
use core::fmt::{self, Debug, Display};
use core::sync::atomic::{AtomicUsize, Ordering};
use std::borrow::Cow;
use std::env;
use std::path::{self, Path, PathBuf};
use std::sync::Once;

View File

@ -2,7 +2,7 @@ use self::ChainState::*;
use crate::StdError;
#[cfg(feature = "std")]
use std::vec;
use alloc::vec::{self, Vec};
#[cfg(feature = "std")]
pub(crate) use crate::Chain;

View File

@ -3,8 +3,8 @@ use crate::{Context, Error, StdError};
use core::convert::Infallible;
use core::fmt::{self, Debug, Display, Write};
#[cfg(backtrace)]
use std::any::Demand;
#[cfg(error_generic_member_access)]
use std::error::Request;
mod ext {
use super::*;
@ -47,7 +47,12 @@ where
where
C: Display + Send + Sync + 'static,
{
self.map_err(|error| error.ext_context(context))
// Not using map_err to save 2 useless frames off the captured backtrace
// in ext_context.
match self {
Ok(ok) => Ok(ok),
Err(error) => Err(error.ext_context(context)),
}
}
fn with_context<C, F>(self, context: F) -> Result<T, Error>
@ -55,7 +60,10 @@ where
C: Display + Send + Sync + 'static,
F: FnOnce() -> C,
{
self.map_err(|error| error.ext_context(context()))
match self {
Ok(ok) => Ok(ok),
Err(error) => Err(error.ext_context(context())),
}
}
}
@ -84,7 +92,12 @@ impl<T> Context<T, Infallible> for Option<T> {
where
C: Display + Send + Sync + 'static,
{
self.ok_or_else(|| Error::from_display(context, backtrace!()))
// Not using ok_or_else to save 2 useless frames off the captured
// backtrace.
match self {
Some(ok) => Ok(ok),
None => Err(Error::from_display(context, backtrace!())),
}
}
fn with_context<C, F>(self, context: F) -> Result<T, Error>
@ -92,7 +105,10 @@ impl<T> Context<T, Infallible> for Option<T> {
C: Display + Send + Sync + 'static,
F: FnOnce() -> C,
{
self.ok_or_else(|| Error::from_display(context(), backtrace!()))
match self {
Some(ok) => Ok(ok),
None => Err(Error::from_display(context(), backtrace!())),
}
}
}
@ -127,9 +143,9 @@ where
Some(&self.error)
}
#[cfg(backtrace)]
fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
self.error.provide(demand);
#[cfg(error_generic_member_access)]
fn provide<'a>(&'a self, request: &mut Request<'a>) {
StdError::provide(&self.error, request);
}
}
@ -141,10 +157,9 @@ where
Some(unsafe { crate::ErrorImpl::error(self.error.inner.by_ref()) })
}
#[cfg(backtrace)]
fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
demand.provide_ref(self.error.backtrace());
self.error.provide(demand);
#[cfg(error_generic_member_access)]
fn provide<'a>(&'a self, request: &mut Request<'a>) {
Error::provide(&self.error, request);
}
}

View File

@ -231,6 +231,11 @@ macro_rules! __parse_ensure {
$crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* $unsafe $block) $($parse)*} ($($rest)*) $($rest)*)
};
(0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($const:tt $block:tt $($dup:tt)*) const {$($body:tt)*} $($rest:tt)*) => {
// TODO: this is mostly useless due to https://github.com/rust-lang/rust/issues/86730
$crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* $const $block) $($parse)*} ($($rest)*) $($rest)*)
};
(0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $dup:tt $lit:literal $($rest:tt)*) => {
$crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* $lit) $($parse)*} ($($rest)*) $($rest)*)
};

View File

@ -5,14 +5,14 @@ use crate::ptr::Mut;
use crate::ptr::{Own, Ref};
use crate::{Error, StdError};
use alloc::boxed::Box;
#[cfg(backtrace)]
use core::any::Demand;
use core::any::TypeId;
use core::fmt::{self, Debug, Display};
use core::mem::ManuallyDrop;
#[cfg(not(anyhow_no_ptr_addr_of))]
use core::ptr;
use core::ptr::NonNull;
#[cfg(error_generic_member_access)]
use std::error::{self, Request};
#[cfg(feature = "std")]
use core::ops::{Deref, DerefMut};
@ -99,7 +99,10 @@ impl Error {
#[cfg(anyhow_no_ptr_addr_of)]
object_downcast_mut: object_downcast_mut::<E>,
object_drop_rest: object_drop_front::<E>,
#[cfg(all(not(backtrace), feature = "backtrace"))]
#[cfg(all(
not(error_generic_member_access),
any(std_backtrace, feature = "backtrace")
))]
object_backtrace: no_backtrace,
};
@ -124,7 +127,10 @@ impl Error {
#[cfg(anyhow_no_ptr_addr_of)]
object_downcast_mut: object_downcast_mut::<M>,
object_drop_rest: object_drop_front::<M>,
#[cfg(all(not(backtrace), feature = "backtrace"))]
#[cfg(all(
not(error_generic_member_access),
any(std_backtrace, feature = "backtrace")
))]
object_backtrace: no_backtrace,
};
@ -150,7 +156,10 @@ impl Error {
#[cfg(anyhow_no_ptr_addr_of)]
object_downcast_mut: object_downcast_mut::<M>,
object_drop_rest: object_drop_front::<M>,
#[cfg(all(not(backtrace), feature = "backtrace"))]
#[cfg(all(
not(error_generic_member_access),
any(std_backtrace, feature = "backtrace")
))]
object_backtrace: no_backtrace,
};
@ -178,7 +187,10 @@ impl Error {
#[cfg(anyhow_no_ptr_addr_of)]
object_downcast_mut: context_downcast_mut::<C, E>,
object_drop_rest: context_drop_rest::<C, E>,
#[cfg(all(not(backtrace), feature = "backtrace"))]
#[cfg(all(
not(error_generic_member_access),
any(std_backtrace, feature = "backtrace")
))]
object_backtrace: no_backtrace,
};
@ -204,7 +216,10 @@ impl Error {
#[cfg(anyhow_no_ptr_addr_of)]
object_downcast_mut: object_downcast_mut::<Box<dyn StdError + Send + Sync>>,
object_drop_rest: object_drop_front::<Box<dyn StdError + Send + Sync>>,
#[cfg(all(not(backtrace), feature = "backtrace"))]
#[cfg(all(
not(error_generic_member_access),
any(std_backtrace, feature = "backtrace")
))]
object_backtrace: no_backtrace,
};
@ -317,7 +332,10 @@ impl Error {
#[cfg(anyhow_no_ptr_addr_of)]
object_downcast_mut: context_chain_downcast_mut::<C>,
object_drop_rest: context_chain_drop_rest::<C>,
#[cfg(all(not(backtrace), feature = "backtrace"))]
#[cfg(all(
not(error_generic_member_access),
any(std_backtrace, feature = "backtrace")
))]
object_backtrace: context_backtrace::<C>,
};
@ -345,21 +363,17 @@ impl Error {
///
/// # Stability
///
/// Standard library backtraces are only available on the nightly channel.
/// Tracking issue: [rust-lang/rust#53487][tracking].
///
/// On stable compilers, this function is only available if the crate's
/// Standard library backtraces are only available when using Rust &ge;
/// 1.65. On older compilers, this function is only available if the crate's
/// "backtrace" feature is enabled, and will use the `backtrace` crate as
/// the underlying backtrace implementation.
/// the underlying backtrace implementation. The return type of this
/// function on old compilers is `&(impl Debug + Display)`.
///
/// ```toml
/// [dependencies]
/// anyhow = { version = "1.0", features = ["backtrace"] }
/// ```
///
/// [tracking]: https://github.com/rust-lang/rust/issues/53487
#[cfg(any(backtrace, feature = "backtrace"))]
#[cfg_attr(doc_cfg, doc(cfg(any(nightly, feature = "backtrace"))))]
#[cfg(any(std_backtrace, feature = "backtrace"))]
pub fn backtrace(&self) -> &impl_backtrace!() {
unsafe { ErrorImpl::backtrace(self.inner.by_ref()) }
}
@ -522,17 +536,21 @@ impl Error {
Some(addr.cast::<E>().deref_mut())
}
}
}
#[cfg(backtrace)]
impl std::any::Provider for Error {
#[cfg(error_generic_member_access)]
pub(crate) fn provide<'a>(&'a self, request: &mut Request<'a>) {
unsafe { ErrorImpl::provide(self.inner.by_ref(), request) }
}
// Called by thiserror when you have `#[source] anyhow::Error`. This provide
// implementation includes the anyhow::Error's Backtrace if any, unlike
// deref'ing to dyn Error where the provide implementation would include
// only the original error's Backtrace from before it got wrapped into an
// anyhow::Error.
fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
unsafe { ErrorImpl::provide(self.inner.by_ref(), demand) }
#[cfg(error_generic_member_access)]
#[doc(hidden)]
pub fn thiserror_provide<'a>(&'a self, request: &mut Request<'a>) {
Self::provide(self, request);
}
}
@ -598,7 +616,10 @@ struct ErrorVTable {
#[cfg(anyhow_no_ptr_addr_of)]
object_downcast_mut: unsafe fn(Mut<ErrorImpl>, TypeId) -> Option<Mut<()>>,
object_drop_rest: unsafe fn(Own<ErrorImpl>, TypeId),
#[cfg(all(not(backtrace), feature = "backtrace"))]
#[cfg(all(
not(error_generic_member_access),
any(std_backtrace, feature = "backtrace")
))]
object_backtrace: unsafe fn(Ref<ErrorImpl>) -> Option<&Backtrace>,
}
@ -606,8 +627,8 @@ struct ErrorVTable {
unsafe fn object_drop<E>(e: Own<ErrorImpl>) {
// Cast back to ErrorImpl<E> so that the allocator receives the correct
// Layout to deallocate the Box's memory.
let unerased = e.cast::<ErrorImpl<E>>().boxed();
drop(unerased);
let unerased_own = e.cast::<ErrorImpl<E>>();
drop(unsafe { unerased_own.boxed() });
}
// Safety: requires layout of *e to match ErrorImpl<E>.
@ -616,8 +637,8 @@ unsafe fn object_drop_front<E>(e: Own<ErrorImpl>, target: TypeId) {
// without dropping E itself. This is used by downcast after doing a
// ptr::read to take ownership of the E.
let _ = target;
let unerased = e.cast::<ErrorImpl<ManuallyDrop<E>>>().boxed();
drop(unerased);
let unerased_own = e.cast::<ErrorImpl<ManuallyDrop<E>>>();
drop(unsafe { unerased_own.boxed() });
}
// Safety: requires layout of *e to match ErrorImpl<E>.
@ -627,15 +648,15 @@ where
{
// Attach E's native StdError vtable onto a pointer to self._object.
let unerased = e.cast::<ErrorImpl<E>>();
let unerased_ref = e.cast::<ErrorImpl<E>>();
#[cfg(not(anyhow_no_ptr_addr_of))]
return Ref::from_raw(NonNull::new_unchecked(
ptr::addr_of!((*unerased.as_ptr())._object) as *mut E,
));
return Ref::from_raw(unsafe {
NonNull::new_unchecked(ptr::addr_of!((*unerased_ref.as_ptr())._object) as *mut E)
});
#[cfg(anyhow_no_ptr_addr_of)]
return Ref::new(&unerased.deref()._object);
return Ref::new(unsafe { &unerased_ref.deref()._object });
}
// Safety: requires layout of *e to match ErrorImpl<E>, and for `e` to be derived
@ -646,7 +667,8 @@ where
E: StdError + Send + Sync + 'static,
{
// Attach E's native StdError vtable onto a pointer to self._object.
&mut e.cast::<ErrorImpl<E>>().deref_mut()._object
let unerased_mut = e.cast::<ErrorImpl<E>>();
unsafe { &mut unerased_mut.deref_mut()._object }
}
// Safety: requires layout of *e to match ErrorImpl<E>.
@ -655,7 +677,8 @@ where
E: StdError + Send + Sync + 'static,
{
// Attach ErrorImpl<E>'s native StdError vtable. The StdError impl is below.
e.cast::<ErrorImpl<E>>().boxed()
let unerased_own = e.cast::<ErrorImpl<E>>();
unsafe { unerased_own.boxed() }
}
// Safety: requires layout of *e to match ErrorImpl<E>.
@ -667,18 +690,18 @@ where
// Caller is looking for an E pointer and e is ErrorImpl<E>, take a
// pointer to its E field.
let unerased = e.cast::<ErrorImpl<E>>();
let unerased_ref = e.cast::<ErrorImpl<E>>();
#[cfg(not(anyhow_no_ptr_addr_of))]
return Some(
Ref::from_raw(NonNull::new_unchecked(
ptr::addr_of!((*unerased.as_ptr())._object) as *mut E,
))
Ref::from_raw(unsafe {
NonNull::new_unchecked(ptr::addr_of!((*unerased_ref.as_ptr())._object) as *mut E)
})
.cast::<()>(),
);
#[cfg(anyhow_no_ptr_addr_of)]
return Some(Ref::new(&unerased.deref()._object).cast::<()>());
return Some(Ref::new(unsafe { &unerased_ref.deref()._object }).cast::<()>());
} else {
None
}
@ -693,14 +716,18 @@ where
if TypeId::of::<E>() == target {
// Caller is looking for an E pointer and e is ErrorImpl<E>, take a
// pointer to its E field.
let unerased = e.cast::<ErrorImpl<E>>().deref_mut();
let unerased_mut = e.cast::<ErrorImpl<E>>();
let unerased = unsafe { unerased_mut.deref_mut() };
Some(Mut::new(&mut unerased._object).cast::<()>())
} else {
None
}
}
#[cfg(all(not(backtrace), feature = "backtrace"))]
#[cfg(all(
not(error_generic_member_access),
any(std_backtrace, feature = "backtrace")
))]
fn no_backtrace(e: Ref<ErrorImpl>) -> Option<&Backtrace> {
let _ = e;
None
@ -714,10 +741,12 @@ where
E: 'static,
{
if TypeId::of::<C>() == target {
let unerased = e.cast::<ErrorImpl<ContextError<C, E>>>().deref();
let unerased_ref = e.cast::<ErrorImpl<ContextError<C, E>>>();
let unerased = unsafe { unerased_ref.deref() };
Some(Ref::new(&unerased._object.context).cast::<()>())
} else if TypeId::of::<E>() == target {
let unerased = e.cast::<ErrorImpl<ContextError<C, E>>>().deref();
let unerased_ref = e.cast::<ErrorImpl<ContextError<C, E>>>();
let unerased = unsafe { unerased_ref.deref() };
Some(Ref::new(&unerased._object.error).cast::<()>())
} else {
None
@ -732,10 +761,12 @@ where
E: 'static,
{
if TypeId::of::<C>() == target {
let unerased = e.cast::<ErrorImpl<ContextError<C, E>>>().deref_mut();
let unerased_mut = e.cast::<ErrorImpl<ContextError<C, E>>>();
let unerased = unsafe { unerased_mut.deref_mut() };
Some(Mut::new(&mut unerased._object.context).cast::<()>())
} else if TypeId::of::<E>() == target {
let unerased = e.cast::<ErrorImpl<ContextError<C, E>>>().deref_mut();
let unerased_mut = e.cast::<ErrorImpl<ContextError<C, E>>>();
let unerased = unsafe { unerased_mut.deref_mut() };
Some(Mut::new(&mut unerased._object.error).cast::<()>())
} else {
None
@ -752,15 +783,11 @@ where
// Called after downcasting by value to either the C or the E and doing a
// ptr::read to take ownership of that value.
if TypeId::of::<C>() == target {
let unerased = e
.cast::<ErrorImpl<ContextError<ManuallyDrop<C>, E>>>()
.boxed();
drop(unerased);
let unerased_own = e.cast::<ErrorImpl<ContextError<ManuallyDrop<C>, E>>>();
drop(unsafe { unerased_own.boxed() });
} else {
let unerased = e
.cast::<ErrorImpl<ContextError<C, ManuallyDrop<E>>>>()
.boxed();
drop(unerased);
let unerased_own = e.cast::<ErrorImpl<ContextError<C, ManuallyDrop<E>>>>();
drop(unsafe { unerased_own.boxed() });
}
}
@ -769,13 +796,14 @@ unsafe fn context_chain_downcast<C>(e: Ref<ErrorImpl>, target: TypeId) -> Option
where
C: 'static,
{
let unerased = e.cast::<ErrorImpl<ContextError<C, Error>>>().deref();
let unerased_ref = e.cast::<ErrorImpl<ContextError<C, Error>>>();
let unerased = unsafe { unerased_ref.deref() };
if TypeId::of::<C>() == target {
Some(Ref::new(&unerased._object.context).cast::<()>())
} else {
// Recurse down the context chain per the inner error's vtable.
let source = &unerased._object.error;
(vtable(source.inner.ptr).object_downcast)(source.inner.by_ref(), target)
unsafe { (vtable(source.inner.ptr).object_downcast)(source.inner.by_ref(), target) }
}
}
@ -785,13 +813,14 @@ unsafe fn context_chain_downcast_mut<C>(e: Mut<ErrorImpl>, target: TypeId) -> Op
where
C: 'static,
{
let unerased = e.cast::<ErrorImpl<ContextError<C, Error>>>().deref_mut();
let unerased_mut = e.cast::<ErrorImpl<ContextError<C, Error>>>();
let unerased = unsafe { unerased_mut.deref_mut() };
if TypeId::of::<C>() == target {
Some(Mut::new(&mut unerased._object.context).cast::<()>())
} else {
// Recurse down the context chain per the inner error's vtable.
let source = &mut unerased._object.error;
(vtable(source.inner.ptr).object_downcast_mut)(source.inner.by_mut(), target)
unsafe { (vtable(source.inner.ptr).object_downcast_mut)(source.inner.by_mut(), target) }
}
}
@ -803,33 +832,34 @@ where
// Called after downcasting by value to either the C or one of the causes
// and doing a ptr::read to take ownership of that value.
if TypeId::of::<C>() == target {
let unerased = e
.cast::<ErrorImpl<ContextError<ManuallyDrop<C>, Error>>>()
.boxed();
let unerased_own = e.cast::<ErrorImpl<ContextError<ManuallyDrop<C>, Error>>>();
// Drop the entire rest of the data structure rooted in the next Error.
drop(unerased);
drop(unsafe { unerased_own.boxed() });
} else {
let unerased = e
.cast::<ErrorImpl<ContextError<C, ManuallyDrop<Error>>>>()
.boxed();
let unerased_own = e.cast::<ErrorImpl<ContextError<C, ManuallyDrop<Error>>>>();
let unerased = unsafe { unerased_own.boxed() };
// Read the Own<ErrorImpl> from the next error.
let inner = unerased._object.error.inner;
drop(unerased);
let vtable = vtable(inner.ptr);
let vtable = unsafe { vtable(inner.ptr) };
// Recursively drop the next error using the same target typeid.
(vtable.object_drop_rest)(inner, target);
unsafe { (vtable.object_drop_rest)(inner, target) };
}
}
// Safety: requires layout of *e to match ErrorImpl<ContextError<C, Error>>.
#[cfg(all(not(backtrace), feature = "backtrace"))]
#[cfg(all(
not(error_generic_member_access),
any(std_backtrace, feature = "backtrace")
))]
#[allow(clippy::unnecessary_wraps)]
unsafe fn context_backtrace<C>(e: Ref<ErrorImpl>) -> Option<&Backtrace>
where
C: 'static,
{
let unerased = e.cast::<ErrorImpl<ContextError<C, Error>>>().deref();
let backtrace = ErrorImpl::backtrace(unerased._object.error.inner.by_ref());
let unerased_ref = e.cast::<ErrorImpl<ContextError<C, Error>>>();
let unerased = unsafe { unerased_ref.deref() };
let backtrace = unsafe { ErrorImpl::backtrace(unerased._object.error.inner.by_ref()) };
Some(backtrace)
}
@ -849,7 +879,7 @@ pub(crate) struct ErrorImpl<E = ()> {
// avoids converting `p` into a reference.
unsafe fn vtable(p: NonNull<ErrorImpl>) -> &'static ErrorVTable {
// NOTE: This assumes that `ErrorVTable` is the first field of ErrorImpl.
*(p.as_ptr() as *const &'static ErrorVTable)
unsafe { *(p.as_ptr() as *const &'static ErrorVTable) }
}
// repr C to ensure that ContextError<C, E> has the same layout as
@ -873,7 +903,7 @@ impl ErrorImpl {
pub(crate) unsafe fn error(this: Ref<Self>) -> &(dyn StdError + Send + Sync + 'static) {
// Use vtable to attach E's native StdError vtable for the right
// original type E.
(vtable(this.ptr).object_ref)(this).deref()
unsafe { (vtable(this.ptr).object_ref)(this).deref() }
}
#[cfg(feature = "std")]
@ -882,42 +912,44 @@ impl ErrorImpl {
// original type E.
#[cfg(not(anyhow_no_ptr_addr_of))]
return (vtable(this.ptr).object_ref)(this.by_ref())
.by_mut()
.deref_mut();
return unsafe {
(vtable(this.ptr).object_ref)(this.by_ref())
.by_mut()
.deref_mut()
};
#[cfg(anyhow_no_ptr_addr_of)]
return (vtable(this.ptr).object_mut)(this);
return unsafe { (vtable(this.ptr).object_mut)(this) };
}
#[cfg(any(backtrace, feature = "backtrace"))]
#[cfg(any(std_backtrace, feature = "backtrace"))]
pub(crate) unsafe fn backtrace(this: Ref<Self>) -> &Backtrace {
// This unwrap can only panic if the underlying error's backtrace method
// is nondeterministic, which would only happen in maliciously
// constructed code.
this.deref()
unsafe { this.deref() }
.backtrace
.as_ref()
.or_else(|| {
#[cfg(backtrace)]
return Self::error(this).request_ref::<Backtrace>();
#[cfg(not(backtrace))]
return (vtable(this.ptr).object_backtrace)(this);
#[cfg(error_generic_member_access)]
return error::request_ref::<Backtrace>(unsafe { Self::error(this) });
#[cfg(not(error_generic_member_access))]
return unsafe { (vtable(this.ptr).object_backtrace)(this) };
})
.expect("backtrace capture failed")
}
#[cfg(backtrace)]
unsafe fn provide<'a>(this: Ref<'a, Self>, demand: &mut Demand<'a>) {
if let Some(backtrace) = &this.deref().backtrace {
demand.provide_ref(backtrace);
#[cfg(error_generic_member_access)]
unsafe fn provide<'a>(this: Ref<'a, Self>, request: &mut Request<'a>) {
if let Some(backtrace) = unsafe { &this.deref().backtrace } {
request.provide_ref(backtrace);
}
Self::error(this).provide(demand);
unsafe { Self::error(this) }.provide(request);
}
#[cold]
pub(crate) unsafe fn chain(this: Ref<Self>) -> Chain {
Chain::new(Self::error(this))
Chain::new(unsafe { Self::error(this) })
}
}
@ -929,9 +961,9 @@ where
unsafe { ErrorImpl::error(self.erase()).source() }
}
#[cfg(backtrace)]
fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
unsafe { ErrorImpl::provide(self.erase(), demand) }
#[cfg(error_generic_member_access)]
fn provide<'a>(&'a self, request: &mut Request<'a>) {
unsafe { ErrorImpl::provide(self.erase(), request) }
}
}

View File

@ -5,10 +5,11 @@ use core::fmt::{self, Debug, Write};
impl ErrorImpl {
pub(crate) unsafe fn display(this: Ref<Self>, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", Self::error(this))?;
write!(f, "{}", unsafe { Self::error(this) })?;
if f.alternate() {
for cause in Self::chain(this).skip(1) {
let chain = unsafe { Self::chain(this) };
for cause in chain.skip(1) {
write!(f, ": {}", cause)?;
}
}
@ -17,7 +18,7 @@ impl ErrorImpl {
}
pub(crate) unsafe fn debug(this: Ref<Self>, f: &mut fmt::Formatter) -> fmt::Result {
let error = Self::error(this);
let error = unsafe { Self::error(this) };
if f.alternate() {
return Debug::fmt(error, f);
@ -39,11 +40,12 @@ impl ErrorImpl {
}
}
#[cfg(any(backtrace, feature = "backtrace"))]
#[cfg(any(std_backtrace, feature = "backtrace"))]
{
use crate::backtrace::BacktraceStatus;
use alloc::string::ToString;
let backtrace = Self::backtrace(this);
let backtrace = unsafe { Self::backtrace(this) };
if let BacktraceStatus::Captured = backtrace.status() {
let mut backtrace = backtrace.to_string();
write!(f, "\n\n")?;
@ -101,6 +103,7 @@ where
#[cfg(test)]
mod tests {
use super::*;
use alloc::string::String;
#[test]
fn one_digit() {

View File

@ -49,9 +49,12 @@ use core::fmt::{Debug, Display};
#[cfg(feature = "std")]
use crate::StdError;
#[cfg(feature = "std")]
use alloc::boxed::Box;
pub struct Adhoc;
#[doc(hidden)]
pub trait AdhocKind: Sized {
#[inline]
fn anyhow_kind(&self) -> Adhoc {
@ -73,6 +76,7 @@ impl Adhoc {
pub struct Trait;
#[doc(hidden)]
pub trait TraitKind: Sized {
#[inline]
fn anyhow_kind(&self) -> Trait {
@ -96,6 +100,7 @@ impl Trait {
pub struct Boxed;
#[cfg(feature = "std")]
#[doc(hidden)]
pub trait BoxedKind: Sized {
#[inline]
fn anyhow_kind(&self) -> Boxed {

View File

@ -128,11 +128,10 @@
//! # ;
//! ```
//!
//! - If using the nightly channel, or stable with `features = ["backtrace"]`, a
//! backtrace is captured and printed with the error if the underlying error
//! type does not already provide its own. In order to see backtraces, they
//! must be enabled through the environment variables described in
//! [`std::backtrace`]:
//! - If using Rust &ge; 1.65, a backtrace is captured and printed with the
//! error if the underlying error type does not already provide its own. In
//! order to see backtraces, they must be enabled through the environment
//! variables described in [`std::backtrace`]:
//!
//! - If you want panics and errors to both have backtraces, set
//! `RUST_BACKTRACE=1`;
@ -140,10 +139,7 @@
//! - If you want only panics to have backtraces, set `RUST_BACKTRACE=1` and
//! `RUST_LIB_BACKTRACE=0`.
//!
//! The tracking issue for this feature is [rust-lang/rust#53487].
//!
//! [`std::backtrace`]: https://doc.rust-lang.org/std/backtrace/index.html#environment-variables
//! [rust-lang/rust#53487]: https://github.com/rust-lang/rust/issues/53487
//!
//! - Anyhow works with any error type that has an impl of `std::error::Error`,
//! including ones defined in your crate. We do not bundle a `derive(Error)`
@ -210,15 +206,23 @@
//! will require an explicit `.map_err(Error::msg)` when working with a
//! non-Anyhow error type inside a function that returns Anyhow's error type.
#![doc(html_root_url = "https://docs.rs/anyhow/1.0.65")]
#![cfg_attr(backtrace, feature(error_generic_member_access, provide_any))]
#![doc(html_root_url = "https://docs.rs/anyhow/1.0.80")]
#![cfg_attr(error_generic_member_access, feature(error_generic_member_access))]
#![cfg_attr(doc_cfg, feature(doc_cfg))]
#![cfg_attr(not(feature = "std"), no_std)]
#![no_std]
#![deny(dead_code, unused_imports, unused_mut)]
#![cfg_attr(
not(anyhow_no_unsafe_op_in_unsafe_fn_lint),
deny(unsafe_op_in_unsafe_fn)
)]
#![cfg_attr(anyhow_no_unsafe_op_in_unsafe_fn_lint, allow(unused_unsafe))]
#![allow(
clippy::doc_markdown,
clippy::enum_glob_use,
clippy::explicit_auto_deref,
clippy::extra_unused_type_parameters,
clippy::incompatible_msrv,
clippy::let_underscore_untyped,
clippy::missing_errors_doc,
clippy::missing_panics_doc,
clippy::module_name_repetitions,
@ -227,14 +231,25 @@
clippy::new_ret_no_self,
clippy::redundant_else,
clippy::return_self_not_must_use,
clippy::struct_field_names,
clippy::unused_self,
clippy::used_underscore_binding,
clippy::wildcard_imports,
clippy::wrong_self_convention
)]
#[cfg(all(
anyhow_nightly_testing,
feature = "std",
not(error_generic_member_access)
))]
compile_error!("Build script probe failed to compile.");
extern crate alloc;
#[cfg(feature = "std")]
extern crate std;
#[macro_use]
mod backtrace;
mod chain;
@ -264,6 +279,7 @@ trait StdError: Debug + Display {
}
}
#[doc(no_inline)]
pub use anyhow as format_err;
/// The `Error` type, a wrapper around a dynamic error type.
@ -367,7 +383,7 @@ pub use anyhow as format_err;
/// # Ok(())
/// }
/// ```
#[repr(transparent)]
#[cfg_attr(not(doc), repr(transparent))]
pub struct Error {
inner: Own<ErrorImpl>,
}
@ -639,16 +655,22 @@ pub mod __private {
use alloc::fmt;
use core::fmt::Arguments;
#[doc(hidden)]
pub use crate::ensure::{BothDebug, NotBothDebug};
#[doc(hidden)]
pub use alloc::format;
#[doc(hidden)]
pub use core::result::Result::Err;
#[doc(hidden)]
pub use core::{concat, format_args, stringify};
#[doc(hidden)]
pub mod kind {
#[doc(hidden)]
pub use crate::kind::{AdhocKind, TraitKind};
#[cfg(feature = "std")]
#[doc(hidden)]
pub use crate::kind::BoxedKind;
}

View File

@ -42,7 +42,7 @@ where
}
pub unsafe fn boxed(self) -> Box<T> {
Box::from_raw(self.ptr.as_ptr())
unsafe { Box::from_raw(self.ptr.as_ptr()) }
}
pub fn by_ref(&self) -> Ref<T> {
@ -120,7 +120,7 @@ where
}
pub unsafe fn deref(self) -> &'a T {
&*self.ptr.as_ptr()
unsafe { &*self.ptr.as_ptr() }
}
}
@ -179,13 +179,13 @@ where
}
pub unsafe fn deref_mut(self) -> &'a mut T {
&mut *self.ptr.as_ptr()
unsafe { &mut *self.ptr.as_ptr() }
}
}
impl<'a, T> Mut<'a, T> {
pub unsafe fn read(self) -> T {
self.ptr.as_ptr().read()
unsafe { self.ptr.as_ptr().read() }
}
}

View File

@ -1,8 +1,11 @@
use crate::StdError;
use core::fmt::{self, Debug, Display};
#[cfg(backtrace)]
use std::any::Demand;
#[cfg(feature = "std")]
use alloc::boxed::Box;
#[cfg(error_generic_member_access)]
use std::error::Request;
#[repr(transparent)]
pub struct MessageError<M>(pub M);
@ -74,8 +77,8 @@ impl StdError for BoxedError {
self.0.source()
}
#[cfg(backtrace)]
fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
self.0.provide(demand);
#[cfg(error_generic_member_access)]
fn provide<'a>(&'a self, request: &mut Request<'a>) {
self.0.provide(request);
}
}

View File

@ -1,3 +1,5 @@
#![allow(clippy::extra_unused_type_parameters)]
use anyhow::Error;
#[test]

View File

@ -1,3 +1,5 @@
#![allow(clippy::let_underscore_untyped)]
#[rustversion::not(nightly)]
#[ignore]
#[test]

View File

@ -56,6 +56,7 @@ fn test_default() {
}
#[test]
#[allow(clippy::redundant_clone)]
fn test_clone() {
let e = error();
let mut chain = e.chain().clone();

View File

@ -1,11 +1,15 @@
#![allow(
clippy::bool_to_int_with_if,
clippy::diverging_sub_expression,
clippy::extra_unused_type_parameters,
clippy::if_same_then_else,
clippy::ifs_same_cond,
clippy::ignored_unit_patterns,
clippy::items_after_statements,
clippy::let_and_return,
clippy::let_underscore_drop,
clippy::let_underscore_untyped,
clippy::match_bool,
clippy::needless_else,
clippy::never_loop,
clippy::overly_complex_bool_expr,
clippy::redundant_closure_call,
@ -17,10 +21,12 @@
irrefutable_let_patterns
)]
use self::Enum::Generic;
use anyhow::{anyhow, ensure, Chain, Error, Result};
use std::fmt::Debug;
use std::fmt::{self, Debug};
use std::iter;
use std::marker::{PhantomData, PhantomData as P};
use std::mem;
use std::ops::Add;
use std::ptr;
@ -43,6 +49,24 @@ trait Trait: Sized {
impl<T> Trait for T {}
enum Enum<T: ?Sized> {
#[allow(dead_code)]
Thing(PhantomData<T>),
Generic,
}
impl<T: ?Sized> PartialEq for Enum<T> {
fn eq(&self, rhs: &Self) -> bool {
mem::discriminant(self) == mem::discriminant(rhs)
}
}
impl<T: ?Sized> Debug for Enum<T> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("Generic")
}
}
#[track_caller]
fn assert_err<T: Debug>(result: impl FnOnce() -> Result<T>, expected: &'static str) {
let actual = result().unwrap_err().to_string();
@ -355,27 +379,27 @@ fn test_path() {
let test = || Ok(ensure!(E::U::<u8,>>E::U));
assert_err(test, "Condition failed: `E::U::<u8> > E::U` (U vs U)");
let test = || Ok(ensure!(PhantomData::<dyn Debug + Sync> != PhantomData));
let test = || Ok(ensure!(Generic::<dyn Debug + Sync> != Generic));
assert_err(
test,
"Condition failed: `PhantomData::<dyn Debug + Sync> != PhantomData` (PhantomData vs PhantomData)",
"Condition failed: `Generic::<dyn Debug + Sync> != Generic` (Generic vs Generic)",
);
let test = || Ok(ensure!(PhantomData::<dyn Fn() + Sync> != PhantomData));
let test = || Ok(ensure!(Generic::<dyn Fn() + Sync> != Generic));
assert_err(
test,
"Condition failed: `PhantomData::<dyn Fn() + Sync> != PhantomData` (PhantomData vs PhantomData)",
"Condition failed: `Generic::<dyn Fn() + Sync> != Generic` (Generic vs Generic)",
);
#[rustfmt::skip]
let test = || {
Ok(ensure!(
PhantomData::<dyn Fn::() + ::std::marker::Sync> != PhantomData
Generic::<dyn Fn::() + ::std::marker::Sync> != Generic
))
};
assert_err(
test,
"Condition failed: `PhantomData::<dyn Fn() + ::std::marker::Sync> != PhantomData` (PhantomData vs PhantomData)",
"Condition failed: `Generic::<dyn Fn() + ::std::marker::Sync> != Generic` (Generic vs Generic)",
);
}
@ -408,7 +432,7 @@ fn test_trailer() {
let test = || Ok(ensure!(PhantomData::<u8> {} != PhantomData));
assert_err(
test,
"Condition failed: `PhantomData::<u8> {} != PhantomData` (PhantomData vs PhantomData)",
"Condition failed: `PhantomData::<u8> {} != PhantomData` (PhantomData<u8> vs PhantomData<u8>)",
);
let result = Ok::<_, Error>(1);
@ -596,7 +620,7 @@ fn test_as() {
};
assert_err(
test,
"Condition failed: `PhantomData as PhantomData<<i32 as ToOwned>::Owned> != PhantomData` (PhantomData vs PhantomData)",
"Condition failed: `PhantomData as PhantomData<<i32 as ToOwned>::Owned> != PhantomData` (PhantomData<i32> vs PhantomData<i32>)",
);
macro_rules! int {

View File

@ -79,7 +79,7 @@ fn test_altdisplay() {
}
#[test]
#[cfg_attr(not(backtrace), ignore)]
#[cfg_attr(not(std_backtrace), ignore)]
fn test_debug() {
assert_eq!(EXPECTED_DEBUG_F, format!("{:?}", f().unwrap_err()));
assert_eq!(EXPECTED_DEBUG_G, format!("{:?}", g().unwrap_err()));

View File

@ -1,6 +1,7 @@
#![allow(
clippy::assertions_on_result_states,
clippy::eq_op,
clippy::incompatible_msrv, // https://github.com/rust-lang/rust-clippy/issues/12257
clippy::items_after_statements,
clippy::needless_pass_by_value,
clippy::shadow_unrelated,

View File

@ -1,8 +1,9 @@
#![allow(clippy::extra_unused_type_parameters)]
mod drop;
use self::drop::{DetectDrop, Flag};
use anyhow::Error;
use std::marker::Unpin;
use std::mem;
#[test]

View File

@ -4,4 +4,9 @@ error: unexpected end of macro invocation
4 | ensure!();
| ^^^^^^^^^ missing tokens in macro arguments
|
note: while trying to match meta-variable `$cond:expr`
--> src/ensure.rs
|
| ($cond:expr $(,)?) => {
| ^^^^^^^^^^
= note: this error originates in the macro `$crate::__parse_ensure` which comes from the expansion of the macro `ensure` (in Nightly builds, run with -Z macro-backtrace for more info)

View File

@ -1,31 +1,32 @@
error[E0599]: the method `anyhow_kind` exists for reference `&Error`, but its trait bounds were not satisfied
--> tests/ui/no-impl.rs:7:13
|
4 | struct Error;
| ------------
| |
| doesn't satisfy `Error: Into<anyhow::Error>`
| doesn't satisfy `Error: anyhow::kind::TraitKind`
| doesn't satisfy `Error: std::fmt::Display`
--> tests/ui/no-impl.rs:7:13
|
4 | struct Error;
| ------------ doesn't satisfy `Error: Into<anyhow::Error>`, `Error: anyhow::kind::TraitKind` or `Error: std::fmt::Display`
...
7 | let _ = anyhow!(Error);
| ^^^^^^^^^^^^^^ method cannot be called on `&Error` due to unsatisfied trait bounds
|
= note: the following trait bounds were not satisfied:
`Error: Into<anyhow::Error>`
which is required by `Error: anyhow::kind::TraitKind`
`Error: std::fmt::Display`
which is required by `&Error: anyhow::kind::AdhocKind`
`&Error: Into<anyhow::Error>`
which is required by `&Error: anyhow::kind::TraitKind`
note: the following traits must be implemented
--> $RUST/core/src/fmt/mod.rs
|
| pub trait Display {
| ^^^^^^^^^^^^^^^^^
|
::: $RUST/core/src/convert/mod.rs
|
| pub trait Into<T>: Sized {
| ^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `anyhow` (in Nightly builds, run with -Z macro-backtrace for more info)
7 | let _ = anyhow!(Error);
| ^^^^^^^^^^^^^^ method cannot be called on `&Error` due to unsatisfied trait bounds
|
= note: the following trait bounds were not satisfied:
`Error: Into<anyhow::Error>`
which is required by `Error: anyhow::kind::TraitKind`
`Error: std::fmt::Display`
which is required by `&Error: anyhow::kind::AdhocKind`
`&Error: Into<anyhow::Error>`
which is required by `&Error: anyhow::kind::TraitKind`
note: the traits `Into` and `std::fmt::Display` must be implemented
--> $RUST/core/src/fmt/mod.rs
|
| pub trait Display {
| ^^^^^^^^^^^^^^^^^
|
::: $RUST/core/src/convert/mod.rs
|
| pub trait Into<T>: Sized {
| ^^^^^^^^^^^^^^^^^^^^^^^^
= help: items from traits can only be used if the trait is implemented and in scope
= note: the following traits define an item `anyhow_kind`, perhaps you need to implement one of them:
candidate #1: `anyhow::kind::AdhocKind`
candidate #2: `anyhow::kind::TraitKind`
candidate #3: `anyhow::kind::BoxedKind`
= note: this error originates in the macro `anyhow` (in Nightly builds, run with -Z macro-backtrace for more info)

View File

@ -4,6 +4,6 @@ error[E0716]: temporary value dropped while borrowed
4 | let _ = anyhow!(&String::new());
| ---------^^^^^^^^^^^^^-
| | |
| | creates a temporary which is freed while still in use
| | creates a temporary value which is freed while still in use
| temporary value is freed at the end of this statement
| argument requires that borrow lasts for `'static`

1
vendor/backtrace/.cargo-checksum.json vendored Normal file
View File

@ -0,0 +1 @@
{"files":{"Cargo.lock":"d2dfb97c75e40290ddadf7f5f11eb154d0398088acdb893afeef0ce8f9be5929","Cargo.toml":"b509b390f54dbe9df8e5572dcc27a2f828686b35aab1c83a2dd88640c515bd9c","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"6007ea91612793f8c77d499d2065acd2255fc5f3c3268fd8bd1ae5f7bb40d6de","benches/benchmarks.rs":"029b78bb79052ec940eecfd18067b743925189202fc16015d3c4c25b05eb6d67","build.rs":"0e30892bba823f9a1143d6d15995951b65a25f917af5443ba96cc8323bddb67f","examples/backtrace.rs":"5da0c95ccebfaffbbe7b5a92b0e488017dc375cbb5b8fb2b7712dd65b2dfb2ba","examples/raw.rs":"575ec6037f597ba7ab0eaf9dd699fadfabef918ba2affea7dc20cdbde55de5ec","src/android-api.c":"b75f16de578451464f49b83dc817b76aa9a0be0d86ea71d1659cc78f99e94fbd","src/backtrace/dbghelp.rs":"ea2f175d6c62259d86e7e9bb04328e03657d7259d4459aab70734f1cf1cd9d72","src/backtrace/libunwind.rs":"0034180e37da7b155cfe87136f07aecf6e67d51848a2db9689b19cf757bd30ee","src/backtrace/miri.rs":"c0dcb1e430eea92fcbad3e293124010f39c1f8ff1bbbf1a0275c53b05880cd5f","src/backtrace/mod.rs":"c782a02a0f9abd1eab79b1271cb6b793102a3c5b516b5dac2977ec634e158bfc","src/backtrace/noop.rs":"a8550b70b3c83f6852a1dba83cf97b1325238b5aa3ce7b35437e9382cdafd924","src/capture.rs":"8701657803f04ea9e0b9dd6a4ca619761edb8a42cfd2f7c9c9e4ee31d9357159","src/dbghelp.rs":"eae2d15fdf7a894ff4c0641f801b687337c07640a80b3a60f2b66013195ca7b4","src/lib.rs":"897d98f5db9ba97802b853b2aaab79645808c0570e840e22c661bae43ba7f111","src/print.rs":"a550d6c11e70ff8e5d0ff6d6034db0e33567f29d8ac7596459af67abef9e6300","src/print/fuchsia.rs":"2c04b3125edf93b47c07489646f5fffa3f7614f7925d0a95886ac0c81368a945","src/symbolize/dbghelp.rs":"58aeda764a27702e0abb3af62bae8a162d8b6cb8c80ffd141ee794d81a8ace15","src/symbolize/gimli.rs":"4f93f6d6652a518ca4c4866fdefb928aa8cf7f547cbdffe0eec081760d1a2507","src/symbolize/gimli/coff.rs":"1a6d69aeb9c79d1acdeb054c1af050251c774d1328ef1a964d08f01c27f2bd2f","src/symbolize/gimli/elf.rs":"0b11415c75302bd4f70abf5147e83595fba38fcd54344170aedce1cb70049807","src/symbolize/gimli/libs_dl_iterate_phdr.rs":"bc64242857dd82288d6e7d6b183e651d05ab7bc4f037f19b9e42719f04fc2c83","src/symbolize/gimli/libs_haiku.rs":"0a0d4b37145e898f7068cadacccf362d8216e463e7026af2ce38d75ebfd74bea","src/symbolize/gimli/libs_illumos.rs":"523e96272b46bdaab2abb0dd0201cb8032bf86558cbed986a20d7e2cc02fa8be","src/symbolize/gimli/libs_libnx.rs":"4116eceadb2d9916d4f5602712eacec647f185d4c53c723aced8de5fc471b14d","src/symbolize/gimli/libs_macos.rs":"c24cb480ae029b350325873ac4358104e5943ad61b62eb22bb6b65b2f05bbd29","src/symbolize/gimli/libs_windows.rs":"6459f8610ca1a0fd7456539ec604f5276c94b3d0d7331357eaed338e49220a02","src/symbolize/gimli/macho.rs":"3cb44a7ff72d0b8c619463c2346f2cfdc378996bb523ceb0c5ab22b1443035b6","src/symbolize/gimli/mmap_fake.rs":"9564fcf47000e70d521b31518e205c8e6ee09b7410fb1eb1e452721757ff54ba","src/symbolize/gimli/mmap_unix.rs":"7d3d7bc6e5d34e3ecb1fe8b30d36bed404b4b9cd79d3b771c91215abfabb9ad1","src/symbolize/gimli/mmap_windows.rs":"a80bada1cef7e2ba1cff7b211eaa53b816248a7c89713c8cc6a70996f727efe4","src/symbolize/gimli/parse_running_mmaps_unix.rs":"b0bffbe15bc55920ecbeb6afe547f81a19a6e428e1a5038d33b8a5a837fe8c3b","src/symbolize/gimli/stash.rs":"69153136df5cb9bf955430c0a2f43c6131834cb7846631f39b58c074496a6ef0","src/symbolize/miri.rs":"f5201cc8a7de24ad3424d2472cb0af59cd28563d09cc0c21e998f4cee4367ade","src/symbolize/mod.rs":"b8248e5210a3a6ddd32c09dbb46c67efaceba7638a6688a5c27f30af7b991534","src/symbolize/noop.rs":"5d4432079b8ae2b9382945a57ae43df57bb4b7ed2e5956d4167e051a44567388","src/types.rs":"f43c94b99d57ca66a5cfe939a46016c95b2d69d82695fb52480f7a3e5b344fd9","src/windows.rs":"c45d95310d787f0be05f1a297b8a954defcd7bdfa48bab38c7196f5875b89852","tests/accuracy/auxiliary.rs":"71d2238da401042e007ef5ee20336d6834724bae96d93c8c52d11a5a332d7d34","tests/accuracy/main.rs":"f8e42aeeb50b35fca380db2e9fe52820cc0bc3133167289c5710e3290701e78e","tests/common/mod.rs":"733101288a48cf94d5a87a1957724deaf2650c3e4e8aa0190a4a7db62aa90d01","tests/concurrent-panics.rs":"b60279ad5c4fb9b2754807f35179cbc8fbd7acbe6e92ac6d0f416ae75db38705","tests/current-exe-mismatch.rs":"540523069f005a9a0822497c6e1c5b7f0df442f0cef6b6e411d6f600bcd0be15","tests/long_fn_name.rs":"ebef58e34543ed4d47048faa9b6525f68fc71e12255af734523a513c5d4baa6f","tests/skip_inner_frames.rs":"6c03cd0ad9facf0aa81e59cf970504785b6ada9993a2dfc2aea0b18b79419aeb","tests/smoke.rs":"33014495f9158aea2d0ee2ee3335ffe82105c7ed894f96eaf7d23845a60f7439"},"package":"2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"}

192
vendor/backtrace/Cargo.lock generated vendored Normal file
View 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.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
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.69"
dependencies = [
"addr2line",
"cc",
"cfg-if",
"cpp_demangle",
"libc",
"libloading",
"miniz_oxide",
"object",
"rustc-demangle",
"rustc-serialize",
"serde",
"winapi",
]
[[package]]
name = "cc"
version = "1.0.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee"
[[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.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e8227005286ec39567949b33df9896bcadfa6051bccca2488129f108ca23119"
dependencies = [
"cfg-if",
]
[[package]]
name = "gimli"
version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
[[package]]
name = "libc"
version = "0.2.147"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
[[package]]
name = "libloading"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd"
dependencies = [
"cfg-if",
"winapi",
]
[[package]]
name = "memchr"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
[[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.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77ac5bbd07aea88c60a577a1ce218075ffd59208b2d7ca97adf9bfc5aeb21ebe"
dependencies = [
"memchr",
]
[[package]]
name = "proc-macro2"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rustc-demangle"
version = "0.1.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
[[package]]
name = "rustc-serialize"
version = "0.3.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
[[package]]
name = "serde"
version = "1.0.136"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.136"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "syn"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[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"

145
vendor/backtrace/Cargo.toml vendored Normal file
View 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 = "backtrace"
version = "0.3.69"
authors = ["The Rust Project Developers"]
build = "build.rs"
exclude = ["/ci/"]
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.cfg-if]
version = "1.0"
[dependencies.cpp_demangle]
version = "0.4.0"
features = ["alloc"]
optional = true
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(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))".dependencies.addr2line]
version = "0.21.0"
default-features = false
[target."cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))".dependencies.libc]
version = "0.2.146"
default-features = false
[target."cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))".dependencies.miniz_oxide]
version = "0.7.0"
default-features = false
[target."cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))".dependencies.object]
version = "0.32.0"
features = [
"read_core",
"elf",
"macho",
"pe",
"unaligned",
"archive",
]
default-features = false
[target."cfg(windows)".dependencies.winapi]
version = "0.3.9"
optional = true

201
vendor/backtrace/LICENSE-APACHE vendored Normal file
View 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.

25
vendor/backtrace/LICENSE-MIT vendored Normal file
View 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
vendor/backtrace/README.md vendored Normal file
View 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
vendor/backtrace/benches/benchmarks.rs vendored Normal file
View 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);
}

49
vendor/backtrace/build.rs vendored Normal file
View File

@ -0,0 +1,49 @@
extern crate cc;
use std::env;
use std::path::Path;
// Must be public so the build script of `std` can call it.
pub fn main() {
match env::var("CARGO_CFG_TARGET_OS").unwrap_or_default().as_str() {
"android" => build_android(),
_ => {}
}
}
fn build_android() {
// Resolve `src/android-api.c` relative to this file.
// Required to support calling this from the `std` build script.
let android_api_c = Path::new(file!())
.parent()
.unwrap()
.join("src/android-api.c");
let expansion = match cc::Build::new().file(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\"");
}
}

View File

@ -0,0 +1,5 @@
use backtrace::Backtrace;
fn main() {
println!("{:?}", Backtrace::new());
}

52
vendor/backtrace/examples/raw.rs vendored Normal file
View 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
vendor/backtrace/src/android-api.c vendored Normal file
View File

@ -0,0 +1,4 @@
// Used from the build script to detect the value of the `__ANDROID_API__`
// builtin #define
APIVERSION __ANDROID_API__

View 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
}

View 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
vendor/backtrace/src/backtrace/miri.rs vendored Normal file
View 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
vendor/backtrace/src/backtrace/mod.rs vendored Normal file
View 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
vendor/backtrace/src/backtrace/noop.rs vendored Normal file
View 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
vendor/backtrace/src/capture.rs vendored Normal file
View 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
vendor/backtrace/src/dbghelp.rs vendored Normal file
View 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
vendor/backtrace/src/lib.rs vendored Normal file
View 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;

320
vendor/backtrace/src/print.rs vendored Normal file
View File

@ -0,0 +1,320 @@
#[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 {
#[cfg(target_os = "fuchsia")]
fuchsia::finish_context(self.fmt)?;
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;
}
}

441
vendor/backtrace/src/print/fuchsia.rs vendored Normal file
View File

@ -0,0 +1,441 @@
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:begin}}}\n")?;
let mut visitor = DsoPrinter {
writer: out,
module_count: 0,
error: Ok(()),
};
for_each_dso(&mut visitor);
visitor.error
}
/// This function prints the Fuchsia symbolizer markup to end the backtrace.
pub fn finish_context(out: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
out.write_str("{{{reset:end}}}\n")
}

View 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
vendor/backtrace/src/symbolize/gimli.rs vendored Normal file
View 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,
}
}
}

View 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
}

View 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
}

View 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
}

View 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
}

View 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
}

View 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
}

View 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,
})
}

View 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,
}],
})
}

View 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".")
&& &section_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
}

View 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[..]
}
}

View 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);
}
}
}

View 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);
}
}
}

View File

@ -0,0 +1,295 @@
// 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"
//
// Note that paths may contain spaces, so we can't use `str::split` for parsing (until
// Split::remainder is stabilized #77998).
fn from_str(s: &str) -> Result<Self, Self::Err> {
let (range_str, s) = s.trim_start().split_once(' ').unwrap_or((s, ""));
if range_str.is_empty() {
return Err("Couldn't find address");
}
let (perms_str, s) = s.trim_start().split_once(' ').unwrap_or((s, ""));
if perms_str.is_empty() {
return Err("Couldn't find permissions");
}
let (offset_str, s) = s.trim_start().split_once(' ').unwrap_or((s, ""));
if offset_str.is_empty() {
return Err("Couldn't find offset");
}
let (dev_str, s) = s.trim_start().split_once(' ').unwrap_or((s, ""));
if dev_str.is_empty() {
return Err("Couldn't find dev");
}
let (inode_str, s) = s.trim_start().split_once(' ').unwrap_or((s, ""));
if inode_str.is_empty() {
return Err("Couldn't find inode");
}
// Pathname may be omitted in which case it will be empty
let pathname_str = s.trim_start();
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(),
}
);
assert_eq!(
"b7c79000-b7e02000 r--p 00000000 08:01 60662705 \
/executable/path/with some spaces"
.parse::<MapsEntry>()
.unwrap(),
MapsEntry {
address: (0xb7c79000, 0xb7e02000),
perms: ['r', '-', '-', 'p'],
offset: 0x00000000,
dev: (0x08, 0x01),
inode: 0x60662705,
pathname: "/executable/path/with some spaces".into(),
}
);
assert_eq!(
"b7c79000-b7e02000 r--p 00000000 08:01 60662705 \
/executable/path/with multiple-continuous spaces "
.parse::<MapsEntry>()
.unwrap(),
MapsEntry {
address: (0xb7c79000, 0xb7e02000),
perms: ['r', '-', '-', 'p'],
offset: 0x00000000,
dev: (0x08, 0x01),
inode: 0x60662705,
pathname: "/executable/path/with multiple-continuous spaces ".into(),
}
);
assert_eq!(
" b7c79000-b7e02000 r--p 00000000 08:01 60662705 \
/executable/path/starts-with-spaces"
.parse::<MapsEntry>()
.unwrap(),
MapsEntry {
address: (0xb7c79000, 0xb7e02000),
perms: ['r', '-', '-', 'p'],
offset: 0x00000000,
dev: (0x08, 0x01),
inode: 0x60662705,
pathname: "/executable/path/starts-with-spaces".into(),
}
);
}

View 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
vendor/backtrace/src/symbolize/miri.rs vendored Normal file
View 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
vendor/backtrace/src/symbolize/mod.rs vendored Normal file
View 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, all(windows, target_env = "gnu")),
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
vendor/backtrace/src/symbolize/noop.rs vendored Normal file
View 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
vendor/backtrace/src/types.rs vendored Normal file
View 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)
}
}

693
vendor/backtrace/src/windows.rs vendored Normal file
View File

@ -0,0 +1,693 @@
//! A module to define the FFI definitions we use on Windows for `dbghelp.dll`
//!
//! This module uses a custom macro, `ffi!`, to wrap all definitions to
//! automatically generate tests to assert that our definitions here are the
//! same as `winapi`.
//!
//! This module largely exists to integrate into libstd itself where winapi is
//! not currently available.
#![allow(bad_style, dead_code)]
cfg_if::cfg_if! {
if #[cfg(feature = "verify-winapi")] {
pub use self::winapi::c_void;
pub use self::winapi::HINSTANCE;
pub use self::winapi::FARPROC;
pub use self::winapi::LPSECURITY_ATTRIBUTES;
#[cfg(target_pointer_width = "64")]
pub use self::winapi::PUNWIND_HISTORY_TABLE;
#[cfg(target_pointer_width = "64")]
pub use self::winapi::PRUNTIME_FUNCTION;
mod winapi {
pub use winapi::ctypes::*;
pub use winapi::shared::basetsd::*;
pub use winapi::shared::minwindef::*;
pub use winapi::um::dbghelp::*;
pub use winapi::um::fileapi::*;
pub use winapi::um::handleapi::*;
pub use winapi::um::libloaderapi::*;
pub use winapi::um::memoryapi::*;
pub use winapi::um::minwinbase::*;
pub use winapi::um::processthreadsapi::*;
pub use winapi::um::synchapi::*;
pub use winapi::um::tlhelp32::*;
pub use winapi::um::winbase::*;
pub use winapi::um::winnt::*;
}
} else {
pub use core::ffi::c_void;
pub type HINSTANCE = *mut c_void;
pub type FARPROC = *mut c_void;
pub type LPSECURITY_ATTRIBUTES = *mut c_void;
#[cfg(target_pointer_width = "64")]
pub type PRUNTIME_FUNCTION = *mut c_void;
#[cfg(target_pointer_width = "64")]
pub type PUNWIND_HISTORY_TABLE = *mut c_void;
}
}
macro_rules! ffi {
() => ();
(#[repr($($r:tt)*)] pub struct $name:ident { $(pub $field:ident: $ty:ty,)* } $($rest:tt)*) => (
#[repr($($r)*)]
#[cfg(not(feature = "verify-winapi"))]
#[derive(Copy, Clone)]
pub struct $name {
$(pub $field: $ty,)*
}
#[cfg(feature = "verify-winapi")]
pub use self::winapi::$name;
#[test]
#[cfg(feature = "verify-winapi")]
fn $name() {
use core::mem;
#[repr($($r)*)]
pub struct $name {
$(pub $field: $ty,)*
}
assert_eq!(
mem::size_of::<$name>(),
mem::size_of::<winapi::$name>(),
concat!("size of ", stringify!($name), " is wrong"),
);
assert_eq!(
mem::align_of::<$name>(),
mem::align_of::<winapi::$name>(),
concat!("align of ", stringify!($name), " is wrong"),
);
type Winapi = winapi::$name;
fn assert_same<T>(_: T, _: T) {}
unsafe {
let a = &*(mem::align_of::<$name>() as *const $name);
let b = &*(mem::align_of::<Winapi>() as *const Winapi);
$(
ffi!(@test_fields a b $field $ty);
)*
}
}
ffi!($($rest)*);
);
// Handling verification against unions in winapi requires some special care
(@test_fields $a:ident $b:ident FltSave $ty:ty) => (
// Skip this field on x86_64 `CONTEXT` since it's a union and a bit funny
);
(@test_fields $a:ident $b:ident D $ty:ty) => ({
let a = &$a.D;
let b = $b.D();
assert_same(a, b);
assert_eq!(a as *const $ty, b as *const $ty, "misplaced field D");
});
(@test_fields $a:ident $b:ident s $ty:ty) => ({
let a = &$a.s;
let b = $b.s();
assert_same(a, b);
assert_eq!(a as *const $ty, b as *const $ty, "misplaced field s");
});
// Otherwise test all fields normally.
(@test_fields $a:ident $b:ident $field:ident $ty:ty) => ({
let a = &$a.$field;
let b = &$b.$field;
assert_same(a, b);
assert_eq!(a as *const $ty, b as *const $ty,
concat!("misplaced field ", stringify!($field)));
});
(pub type $name:ident = $ty:ty; $($rest:tt)*) => (
pub type $name = $ty;
#[cfg(feature = "verify-winapi")]
#[allow(dead_code)]
const $name: () = {
fn _foo() {
trait SameType {}
impl<T> SameType for (T, T) {}
fn assert_same<T: SameType>() {}
assert_same::<($name, winapi::$name)>();
}
};
ffi!($($rest)*);
);
(pub const $name:ident: $ty:ty = $val:expr; $($rest:tt)*) => (
pub const $name: $ty = $val;
#[cfg(feature = "verify-winapi")]
#[allow(unused_imports)]
mod $name {
use super::*;
#[test]
fn assert_valid() {
let x: $ty = winapi::$name;
assert_eq!(x, $val);
}
}
ffi!($($rest)*);
);
($(#[$meta:meta])* extern "system" { $(pub fn $name:ident($($args:tt)*) -> $ret:ty;)* } $($rest:tt)*) => (
$(#[$meta])* extern "system" {
$(pub fn $name($($args)*) -> $ret;)*
}
$(
#[cfg(feature = "verify-winapi")]
mod $name {
#[test]
fn assert_same() {
use super::*;
assert_eq!($name as usize, winapi::$name as usize);
let mut x: unsafe extern "system" fn($($args)*) -> $ret;
x = $name;
let _ = x;
x = winapi::$name;
let _ = x;
}
}
)*
ffi!($($rest)*);
);
(impl $name:ident { $($i:tt)* } $($rest:tt)*) => (
#[cfg(not(feature = "verify-winapi"))]
impl $name {
$($i)*
}
ffi!($($rest)*);
);
}
ffi! {
#[repr(C)]
pub struct STACKFRAME64 {
pub AddrPC: ADDRESS64,
pub AddrReturn: ADDRESS64,
pub AddrFrame: ADDRESS64,
pub AddrStack: ADDRESS64,
pub AddrBStore: ADDRESS64,
pub FuncTableEntry: PVOID,
pub Params: [DWORD64; 4],
pub Far: BOOL,
pub Virtual: BOOL,
pub Reserved: [DWORD64; 3],
pub KdHelp: KDHELP64,
}
pub type LPSTACKFRAME64 = *mut STACKFRAME64;
#[repr(C)]
pub struct STACKFRAME_EX {
pub AddrPC: ADDRESS64,
pub AddrReturn: ADDRESS64,
pub AddrFrame: ADDRESS64,
pub AddrStack: ADDRESS64,
pub AddrBStore: ADDRESS64,
pub FuncTableEntry: PVOID,
pub Params: [DWORD64; 4],
pub Far: BOOL,
pub Virtual: BOOL,
pub Reserved: [DWORD64; 3],
pub KdHelp: KDHELP64,
pub StackFrameSize: DWORD,
pub InlineFrameContext: DWORD,
}
pub type LPSTACKFRAME_EX = *mut STACKFRAME_EX;
#[repr(C)]
pub struct IMAGEHLP_LINEW64 {
pub SizeOfStruct: DWORD,
pub Key: PVOID,
pub LineNumber: DWORD,
pub FileName: PWSTR,
pub Address: DWORD64,
}
pub type PIMAGEHLP_LINEW64 = *mut IMAGEHLP_LINEW64;
#[repr(C)]
pub struct SYMBOL_INFOW {
pub SizeOfStruct: ULONG,
pub TypeIndex: ULONG,
pub Reserved: [ULONG64; 2],
pub Index: ULONG,
pub Size: ULONG,
pub ModBase: ULONG64,
pub Flags: ULONG,
pub Value: ULONG64,
pub Address: ULONG64,
pub Register: ULONG,
pub Scope: ULONG,
pub Tag: ULONG,
pub NameLen: ULONG,
pub MaxNameLen: ULONG,
pub Name: [WCHAR; 1],
}
pub type PSYMBOL_INFOW = *mut SYMBOL_INFOW;
pub type PTRANSLATE_ADDRESS_ROUTINE64 = Option<
unsafe extern "system" fn(hProcess: HANDLE, hThread: HANDLE, lpaddr: LPADDRESS64) -> DWORD64,
>;
pub type PGET_MODULE_BASE_ROUTINE64 =
Option<unsafe extern "system" fn(hProcess: HANDLE, Address: DWORD64) -> DWORD64>;
pub type PFUNCTION_TABLE_ACCESS_ROUTINE64 =
Option<unsafe extern "system" fn(ahProcess: HANDLE, AddrBase: DWORD64) -> PVOID>;
pub type PREAD_PROCESS_MEMORY_ROUTINE64 = Option<
unsafe extern "system" fn(
hProcess: HANDLE,
qwBaseAddress: DWORD64,
lpBuffer: PVOID,
nSize: DWORD,
lpNumberOfBytesRead: LPDWORD,
) -> BOOL,
>;
#[repr(C)]
pub struct ADDRESS64 {
pub Offset: DWORD64,
pub Segment: WORD,
pub Mode: ADDRESS_MODE,
}
pub type LPADDRESS64 = *mut ADDRESS64;
pub type ADDRESS_MODE = u32;
#[repr(C)]
pub struct KDHELP64 {
pub Thread: DWORD64,
pub ThCallbackStack: DWORD,
pub ThCallbackBStore: DWORD,
pub NextCallback: DWORD,
pub FramePointer: DWORD,
pub KiCallUserMode: DWORD64,
pub KeUserCallbackDispatcher: DWORD64,
pub SystemRangeStart: DWORD64,
pub KiUserExceptionDispatcher: DWORD64,
pub StackBase: DWORD64,
pub StackLimit: DWORD64,
pub BuildVersion: DWORD,
pub Reserved0: DWORD,
pub Reserved1: [DWORD64; 4],
}
#[repr(C)]
pub struct MODULEENTRY32W {
pub dwSize: DWORD,
pub th32ModuleID: DWORD,
pub th32ProcessID: DWORD,
pub GlblcntUsage: DWORD,
pub ProccntUsage: DWORD,
pub modBaseAddr: *mut u8,
pub modBaseSize: DWORD,
pub hModule: HMODULE,
pub szModule: [WCHAR; MAX_MODULE_NAME32 + 1],
pub szExePath: [WCHAR; MAX_PATH],
}
pub const MAX_SYM_NAME: usize = 2000;
pub const AddrModeFlat: ADDRESS_MODE = 3;
pub const TRUE: BOOL = 1;
pub const FALSE: BOOL = 0;
pub const PROCESS_QUERY_INFORMATION: DWORD = 0x400;
pub const IMAGE_FILE_MACHINE_ARM64: u16 = 43620;
pub const IMAGE_FILE_MACHINE_AMD64: u16 = 34404;
pub const IMAGE_FILE_MACHINE_I386: u16 = 332;
pub const IMAGE_FILE_MACHINE_ARMNT: u16 = 452;
pub const FILE_SHARE_READ: DWORD = 0x1;
pub const FILE_SHARE_WRITE: DWORD = 0x2;
pub const OPEN_EXISTING: DWORD = 0x3;
pub const GENERIC_READ: DWORD = 0x80000000;
pub const INFINITE: DWORD = !0;
pub const PAGE_READONLY: DWORD = 2;
pub const FILE_MAP_READ: DWORD = 4;
pub const TH32CS_SNAPMODULE: DWORD = 0x00000008;
pub const INVALID_HANDLE_VALUE: HANDLE = -1isize as HANDLE;
pub const MAX_MODULE_NAME32: usize = 255;
pub const MAX_PATH: usize = 260;
pub type DWORD = u32;
pub type PDWORD = *mut u32;
pub type BOOL = i32;
pub type DWORD64 = u64;
pub type PDWORD64 = *mut u64;
pub type HANDLE = *mut c_void;
pub type PVOID = HANDLE;
pub type PCWSTR = *const u16;
pub type LPSTR = *mut i8;
pub type LPCSTR = *const i8;
pub type PWSTR = *mut u16;
pub type WORD = u16;
pub type ULONG = u32;
pub type ULONG64 = u64;
pub type WCHAR = u16;
pub type PCONTEXT = *mut CONTEXT;
pub type LPDWORD = *mut DWORD;
pub type DWORDLONG = u64;
pub type HMODULE = HINSTANCE;
pub type SIZE_T = usize;
pub type LPVOID = *mut c_void;
pub type LPCVOID = *const c_void;
pub type LPMODULEENTRY32W = *mut MODULEENTRY32W;
#[link(name = "kernel32")]
extern "system" {
pub fn GetCurrentProcess() -> HANDLE;
pub fn GetCurrentThread() -> HANDLE;
pub fn RtlCaptureContext(ContextRecord: PCONTEXT) -> ();
pub fn LoadLibraryA(a: *const i8) -> HMODULE;
pub fn GetProcAddress(h: HMODULE, name: *const i8) -> FARPROC;
pub fn GetModuleHandleA(name: *const i8) -> HMODULE;
pub fn OpenProcess(
dwDesiredAccess: DWORD,
bInheitHandle: BOOL,
dwProcessId: DWORD,
) -> HANDLE;
pub fn GetCurrentProcessId() -> DWORD;
pub fn CloseHandle(h: HANDLE) -> BOOL;
pub fn CreateFileA(
lpFileName: LPCSTR,
dwDesiredAccess: DWORD,
dwShareMode: DWORD,
lpSecurityAttributes: LPSECURITY_ATTRIBUTES,
dwCreationDisposition: DWORD,
dwFlagsAndAttributes: DWORD,
hTemplateFile: HANDLE,
) -> HANDLE;
pub fn CreateMutexA(
attrs: LPSECURITY_ATTRIBUTES,
initial: BOOL,
name: LPCSTR,
) -> HANDLE;
pub fn ReleaseMutex(hMutex: HANDLE) -> BOOL;
pub fn WaitForSingleObjectEx(
hHandle: HANDLE,
dwMilliseconds: DWORD,
bAlertable: BOOL,
) -> DWORD;
pub fn CreateFileMappingA(
hFile: HANDLE,
lpFileMappingAttributes: LPSECURITY_ATTRIBUTES,
flProtect: DWORD,
dwMaximumSizeHigh: DWORD,
dwMaximumSizeLow: DWORD,
lpName: LPCSTR,
) -> HANDLE;
pub fn MapViewOfFile(
hFileMappingObject: HANDLE,
dwDesiredAccess: DWORD,
dwFileOffsetHigh: DWORD,
dwFileOffsetLow: DWORD,
dwNumberOfBytesToMap: SIZE_T,
) -> LPVOID;
pub fn UnmapViewOfFile(lpBaseAddress: LPCVOID) -> BOOL;
pub fn CreateToolhelp32Snapshot(
dwFlags: DWORD,
th32ProcessID: DWORD,
) -> HANDLE;
pub fn Module32FirstW(
hSnapshot: HANDLE,
lpme: LPMODULEENTRY32W,
) -> BOOL;
pub fn Module32NextW(
hSnapshot: HANDLE,
lpme: LPMODULEENTRY32W,
) -> BOOL;
}
}
#[cfg(target_pointer_width = "64")]
ffi! {
#[link(name = "kernel32")]
extern "system" {
pub fn RtlLookupFunctionEntry(
ControlPc: DWORD64,
ImageBase: PDWORD64,
HistoryTable: PUNWIND_HISTORY_TABLE,
) -> PRUNTIME_FUNCTION;
}
}
#[cfg(target_arch = "aarch64")]
ffi! {
#[repr(C, align(16))]
pub struct CONTEXT {
pub ContextFlags: DWORD,
pub Cpsr: DWORD,
pub u: CONTEXT_u,
pub Sp: u64,
pub Pc: u64,
pub V: [ARM64_NT_NEON128; 32],
pub Fpcr: DWORD,
pub Fpsr: DWORD,
pub Bcr: [DWORD; ARM64_MAX_BREAKPOINTS],
pub Bvr: [DWORD64; ARM64_MAX_BREAKPOINTS],
pub Wcr: [DWORD; ARM64_MAX_WATCHPOINTS],
pub Wvr: [DWORD64; ARM64_MAX_WATCHPOINTS],
}
#[repr(C)]
pub struct CONTEXT_u {
pub s: CONTEXT_u_s,
}
impl CONTEXT_u {
pub unsafe fn s(&self) -> &CONTEXT_u_s {
&self.s
}
}
#[repr(C)]
pub struct CONTEXT_u_s {
pub X0: u64,
pub X1: u64,
pub X2: u64,
pub X3: u64,
pub X4: u64,
pub X5: u64,
pub X6: u64,
pub X7: u64,
pub X8: u64,
pub X9: u64,
pub X10: u64,
pub X11: u64,
pub X12: u64,
pub X13: u64,
pub X14: u64,
pub X15: u64,
pub X16: u64,
pub X17: u64,
pub X18: u64,
pub X19: u64,
pub X20: u64,
pub X21: u64,
pub X22: u64,
pub X23: u64,
pub X24: u64,
pub X25: u64,
pub X26: u64,
pub X27: u64,
pub X28: u64,
pub Fp: u64,
pub Lr: u64,
}
pub const ARM64_MAX_BREAKPOINTS: usize = 8;
pub const ARM64_MAX_WATCHPOINTS: usize = 2;
#[repr(C)]
pub struct ARM64_NT_NEON128 {
pub D: [f64; 2],
}
}
#[cfg(target_arch = "x86")]
ffi! {
#[repr(C)]
pub struct CONTEXT {
pub ContextFlags: DWORD,
pub Dr0: DWORD,
pub Dr1: DWORD,
pub Dr2: DWORD,
pub Dr3: DWORD,
pub Dr6: DWORD,
pub Dr7: DWORD,
pub FloatSave: FLOATING_SAVE_AREA,
pub SegGs: DWORD,
pub SegFs: DWORD,
pub SegEs: DWORD,
pub SegDs: DWORD,
pub Edi: DWORD,
pub Esi: DWORD,
pub Ebx: DWORD,
pub Edx: DWORD,
pub Ecx: DWORD,
pub Eax: DWORD,
pub Ebp: DWORD,
pub Eip: DWORD,
pub SegCs: DWORD,
pub EFlags: DWORD,
pub Esp: DWORD,
pub SegSs: DWORD,
pub ExtendedRegisters: [u8; 512],
}
#[repr(C)]
pub struct FLOATING_SAVE_AREA {
pub ControlWord: DWORD,
pub StatusWord: DWORD,
pub TagWord: DWORD,
pub ErrorOffset: DWORD,
pub ErrorSelector: DWORD,
pub DataOffset: DWORD,
pub DataSelector: DWORD,
pub RegisterArea: [u8; 80],
pub Spare0: DWORD,
}
}
#[cfg(target_arch = "x86_64")]
ffi! {
#[repr(C, align(8))]
pub struct CONTEXT {
pub P1Home: DWORDLONG,
pub P2Home: DWORDLONG,
pub P3Home: DWORDLONG,
pub P4Home: DWORDLONG,
pub P5Home: DWORDLONG,
pub P6Home: DWORDLONG,
pub ContextFlags: DWORD,
pub MxCsr: DWORD,
pub SegCs: WORD,
pub SegDs: WORD,
pub SegEs: WORD,
pub SegFs: WORD,
pub SegGs: WORD,
pub SegSs: WORD,
pub EFlags: DWORD,
pub Dr0: DWORDLONG,
pub Dr1: DWORDLONG,
pub Dr2: DWORDLONG,
pub Dr3: DWORDLONG,
pub Dr6: DWORDLONG,
pub Dr7: DWORDLONG,
pub Rax: DWORDLONG,
pub Rcx: DWORDLONG,
pub Rdx: DWORDLONG,
pub Rbx: DWORDLONG,
pub Rsp: DWORDLONG,
pub Rbp: DWORDLONG,
pub Rsi: DWORDLONG,
pub Rdi: DWORDLONG,
pub R8: DWORDLONG,
pub R9: DWORDLONG,
pub R10: DWORDLONG,
pub R11: DWORDLONG,
pub R12: DWORDLONG,
pub R13: DWORDLONG,
pub R14: DWORDLONG,
pub R15: DWORDLONG,
pub Rip: DWORDLONG,
pub FltSave: FLOATING_SAVE_AREA,
pub VectorRegister: [M128A; 26],
pub VectorControl: DWORDLONG,
pub DebugControl: DWORDLONG,
pub LastBranchToRip: DWORDLONG,
pub LastBranchFromRip: DWORDLONG,
pub LastExceptionToRip: DWORDLONG,
pub LastExceptionFromRip: DWORDLONG,
}
#[repr(C)]
pub struct M128A {
pub Low: u64,
pub High: i64,
}
}
#[repr(C)]
#[cfg(target_arch = "x86_64")]
#[derive(Copy, Clone)]
pub struct FLOATING_SAVE_AREA {
_Dummy: [u8; 512],
}
#[cfg(target_arch = "arm")]
ffi! {
// #[repr(C)]
// pub struct NEON128 {
// pub Low: ULONG64,
// pub High: LONG64,
// }
// pub type PNEON128 = *mut NEON128;
#[repr(C)]
pub struct CONTEXT_u {
// pub Q: [NEON128; 16],
pub D: [ULONG64; 32],
// pub S: [DWORD; 32],
}
pub const ARM_MAX_BREAKPOINTS: usize = 8;
pub const ARM_MAX_WATCHPOINTS: usize = 1;
#[repr(C)]
pub struct CONTEXT {
pub ContextFlags: DWORD,
pub R0: DWORD,
pub R1: DWORD,
pub R2: DWORD,
pub R3: DWORD,
pub R4: DWORD,
pub R5: DWORD,
pub R6: DWORD,
pub R7: DWORD,
pub R8: DWORD,
pub R9: DWORD,
pub R10: DWORD,
pub R11: DWORD,
pub R12: DWORD,
pub Sp: DWORD,
pub Lr: DWORD,
pub Pc: DWORD,
pub Cpsr: DWORD,
pub Fpsrc: DWORD,
pub Padding: DWORD,
pub u: CONTEXT_u,
pub Bvr: [DWORD; ARM_MAX_BREAKPOINTS],
pub Bcr: [DWORD; ARM_MAX_BREAKPOINTS],
pub Wvr: [DWORD; ARM_MAX_WATCHPOINTS],
pub Wcr: [DWORD; ARM_MAX_WATCHPOINTS],
pub Padding2: [DWORD; 2],
}
} // IFDEF(arm)

View File

@ -0,0 +1,15 @@
#[inline(never)]
pub fn callback<F>(f: F)
where
F: FnOnce((&'static str, u32)),
{
f((file!(), line!()))
}
#[inline(always)]
pub fn callback_inlined<F>(f: F)
where
F: FnOnce((&'static str, u32)),
{
f((file!(), line!()))
}

Some files were not shown because too many files have changed in this diff Show More