summaryrefslogtreecommitdiffstats
path: root/vendor/backtrace
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/backtrace')
-rw-r--r--vendor/backtrace/.cargo-checksum.json1
-rw-r--r--vendor/backtrace/Cargo.lock192
-rw-r--r--vendor/backtrace/Cargo.toml138
-rw-r--r--vendor/backtrace/LICENSE-APACHE201
-rw-r--r--vendor/backtrace/LICENSE-MIT25
-rw-r--r--vendor/backtrace/README.md73
-rw-r--r--vendor/backtrace/benches/benchmarks.rs92
-rw-r--r--vendor/backtrace/build.rs41
-rwxr-xr-xvendor/backtrace/ci/android-ndk.sh23
-rwxr-xr-xvendor/backtrace/ci/android-sdk.sh65
-rwxr-xr-xvendor/backtrace/ci/debuglink-docker.sh29
-rwxr-xr-xvendor/backtrace/ci/debuglink.sh75
-rw-r--r--vendor/backtrace/ci/docker/aarch64-linux-android/Dockerfile18
-rw-r--r--vendor/backtrace/ci/docker/aarch64-unknown-linux-gnu/Dockerfile11
-rw-r--r--vendor/backtrace/ci/docker/arm-linux-androideabi/Dockerfile18
-rw-r--r--vendor/backtrace/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile10
-rw-r--r--vendor/backtrace/ci/docker/armv7-linux-androideabi/Dockerfile18
-rw-r--r--vendor/backtrace/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile10
-rw-r--r--vendor/backtrace/ci/docker/i586-unknown-linux-gnu/Dockerfile5
-rw-r--r--vendor/backtrace/ci/docker/i686-linux-android/Dockerfile18
-rw-r--r--vendor/backtrace/ci/docker/i686-unknown-linux-gnu/Dockerfile5
-rw-r--r--vendor/backtrace/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile16
-rw-r--r--vendor/backtrace/ci/docker/s390x-unknown-linux-gnu/Dockerfile17
-rw-r--r--vendor/backtrace/ci/docker/x86_64-linux-android/Dockerfile18
-rw-r--r--vendor/backtrace/ci/docker/x86_64-pc-windows-gnu/Dockerfile10
-rw-r--r--vendor/backtrace/ci/docker/x86_64-unknown-linux-gnu/Dockerfile6
-rw-r--r--vendor/backtrace/ci/docker/x86_64-unknown-linux-musl/Dockerfile6
-rwxr-xr-xvendor/backtrace/ci/run-docker.sh33
-rwxr-xr-xvendor/backtrace/ci/run.sh6
-rw-r--r--vendor/backtrace/ci/runtest-android.rs50
-rw-r--r--vendor/backtrace/examples/backtrace.rs5
-rw-r--r--vendor/backtrace/examples/raw.rs52
-rw-r--r--vendor/backtrace/src/android-api.c4
-rw-r--r--vendor/backtrace/src/backtrace/dbghelp.rs257
-rw-r--r--vendor/backtrace/src/backtrace/libunwind.rs267
-rw-r--r--vendor/backtrace/src/backtrace/miri.rs107
-rw-r--r--vendor/backtrace/src/backtrace/mod.rs162
-rw-r--r--vendor/backtrace/src/backtrace/noop.rs28
-rw-r--r--vendor/backtrace/src/capture.rs555
-rw-r--r--vendor/backtrace/src/dbghelp.rs351
-rw-r--r--vendor/backtrace/src/lib.rs193
-rw-r--r--vendor/backtrace/src/print.rs302
-rw-r--r--vendor/backtrace/src/print/fuchsia.rs436
-rw-r--r--vendor/backtrace/src/symbolize/dbghelp.rs218
-rw-r--r--vendor/backtrace/src/symbolize/gimli.rs462
-rw-r--r--vendor/backtrace/src/symbolize/gimli/coff.rs108
-rw-r--r--vendor/backtrace/src/symbolize/gimli/elf.rs423
-rw-r--r--vendor/backtrace/src/symbolize/gimli/libs_dl_iterate_phdr.rs53
-rw-r--r--vendor/backtrace/src/symbolize/gimli/libs_haiku.rs48
-rw-r--r--vendor/backtrace/src/symbolize/gimli/libs_illumos.rs99
-rw-r--r--vendor/backtrace/src/symbolize/gimli/libs_libnx.rs27
-rw-r--r--vendor/backtrace/src/symbolize/gimli/libs_macos.rs146
-rw-r--r--vendor/backtrace/src/symbolize/gimli/libs_windows.rs89
-rw-r--r--vendor/backtrace/src/symbolize/gimli/macho.rs324
-rw-r--r--vendor/backtrace/src/symbolize/gimli/mmap_fake.rs25
-rw-r--r--vendor/backtrace/src/symbolize/gimli/mmap_unix.rs44
-rw-r--r--vendor/backtrace/src/symbolize/gimli/mmap_windows.rs57
-rw-r--r--vendor/backtrace/src/symbolize/gimli/stash.rs52
-rw-r--r--vendor/backtrace/src/symbolize/miri.rs56
-rw-r--r--vendor/backtrace/src/symbolize/mod.rs485
-rw-r--r--vendor/backtrace/src/symbolize/noop.rs41
-rw-r--r--vendor/backtrace/src/types.rs83
-rw-r--r--vendor/backtrace/src/windows.rs691
-rw-r--r--vendor/backtrace/tests/accuracy/auxiliary.rs15
-rw-r--r--vendor/backtrace/tests/accuracy/main.rs117
-rw-r--r--vendor/backtrace/tests/concurrent-panics.rs78
-rw-r--r--vendor/backtrace/tests/long_fn_name.rs48
-rw-r--r--vendor/backtrace/tests/skip_inner_frames.rs44
-rw-r--r--vendor/backtrace/tests/smoke.rs323
69 files changed, 8105 insertions, 0 deletions
diff --git a/vendor/backtrace/.cargo-checksum.json b/vendor/backtrace/.cargo-checksum.json
new file mode 100644
index 000000000..434618119
--- /dev/null
+++ b/vendor/backtrace/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"Cargo.lock":"b0096194daaeffd2e4c7577e0549b74f3d40183ef2abc83d29b9fe2faca882a7","Cargo.toml":"94e809a91c1cae05980cc022d6449db2e9029f18aa33c8151d7fb8a738f443a0","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"6007ea91612793f8c77d499d2065acd2255fc5f3c3268fd8bd1ae5f7bb40d6de","benches/benchmarks.rs":"029b78bb79052ec940eecfd18067b743925189202fc16015d3c4c25b05eb6d67","build.rs":"8d5e860da109f86c67596b10b5613ff6d19f9d24c2970f491a55261fb1973692","ci/android-ndk.sh":"89fafa41d08ff477f949bfc163d04d1eb34fdee370f7a695cfba4ef34c164a55","ci/android-sdk.sh":"69a953f70f32064d1d2a57c7082a50336b90a12d10c75e5416dbb1d6d718016c","ci/debuglink-docker.sh":"3a16131df8c69fef37331cb6f01a6623d169177474f475159d05bab61df077a9","ci/debuglink.sh":"164a961b930de8c9aedf45a11076c3d41081846a8e6a9566ba2b6ad615179e0b","ci/docker/aarch64-linux-android/Dockerfile":"1058f2ee9cf74b4c51a489e62544bea94c6cd537ad5c1b056f3e4b262f7e09f2","ci/docker/aarch64-unknown-linux-gnu/Dockerfile":"a7b7aae0d8e2f826cf1c6c7c3160f8e5e9a30478b83c394b6575ce15b0ff0802","ci/docker/arm-linux-androideabi/Dockerfile":"12f8c62f0750d3581292b23309f5aef15492c946a73e55df13bc345de5ca576e","ci/docker/arm-unknown-linux-gnueabihf/Dockerfile":"5156382ff639b11801c1bd7ddc6e03e8834505a74ecf7160e92182603cd5d96f","ci/docker/armv7-linux-androideabi/Dockerfile":"7c582c2a4b162b147deada3194a30185ccb7a01215f97990cd1a5a3460c30fb9","ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile":"4aaceef14ba700ea3719fe30fcb46f1bb154a47aa52cdb64fa6ed7eff96d6c85","ci/docker/i586-unknown-linux-gnu/Dockerfile":"0816c89b79a74be7ccfc34e95cd718ce29a8698a2ab56903b4b0712470f5c8bb","ci/docker/i686-linux-android/Dockerfile":"18957e8dad4c6d9c8ad561f846e20f6e2186ff7a8421f2a0089793b510f66fe2","ci/docker/i686-unknown-linux-gnu/Dockerfile":"0816c89b79a74be7ccfc34e95cd718ce29a8698a2ab56903b4b0712470f5c8bb","ci/docker/powerpc64-unknown-linux-gnu/Dockerfile":"270de99179c925e6284a8283fdb4e40a8c813a569b24930d6cfe79a4c470ab61","ci/docker/s390x-unknown-linux-gnu/Dockerfile":"4aa8ca641efd2f1937ef669eda2f3e357b2fb926911722b3afc6cf25ce4bcac2","ci/docker/x86_64-linux-android/Dockerfile":"e6d6fb37041a9d6fc6771be1ae8d1eaa506a1dc8796170c1ffcc3d6dd043bed2","ci/docker/x86_64-pc-windows-gnu/Dockerfile":"654988c5c008610f90d5159a8dd0ab6fd491e9c0d16ad65b03ef53f694a5400c","ci/docker/x86_64-unknown-linux-gnu/Dockerfile":"9f89f080551fff6678b1efcc0925fc8c16316f69cdd150e89f9e95cdab583510","ci/docker/x86_64-unknown-linux-musl/Dockerfile":"4db3cb7d315588f363eb9f377bf1c27d8e8886c07b6c0d0c5cf7ee91114a718b","ci/run-docker.sh":"70760696a608b0d89eb3dcc4b08f176d709dd9f98e50297f2b7e0bb9b0f3b458","ci/run.sh":"0bb5c8256019779f3e1db20fcc2c01416ffd4679428f3e395ef5f3e55d2d642c","ci/runtest-android.rs":"be2e49bb296b92a8e3643a6c0a70917fe7b130fa43b71a29c4e7514f45c00e7e","examples/backtrace.rs":"5da0c95ccebfaffbbe7b5a92b0e488017dc375cbb5b8fb2b7712dd65b2dfb2ba","examples/raw.rs":"575ec6037f597ba7ab0eaf9dd699fadfabef918ba2affea7dc20cdbde55de5ec","src/android-api.c":"b75f16de578451464f49b83dc817b76aa9a0be0d86ea71d1659cc78f99e94fbd","src/backtrace/dbghelp.rs":"ea2f175d6c62259d86e7e9bb04328e03657d7259d4459aab70734f1cf1cd9d72","src/backtrace/libunwind.rs":"65373ce7bd87abc411b4307bd41679f9176987170b3b627abe0f0bb1625ff685","src/backtrace/miri.rs":"630faf9919d3ced8d75095cea30fde6c1ed7f0ad135dee8c81a3d7614b55cc11","src/backtrace/mod.rs":"b301e6b7da4f3811c5255c2f1fdb83f4ab97acfa1647d998d8455614ae90ddaf","src/backtrace/noop.rs":"a8550b70b3c83f6852a1dba83cf97b1325238b5aa3ce7b35437e9382cdafd924","src/capture.rs":"8701657803f04ea9e0b9dd6a4ca619761edb8a42cfd2f7c9c9e4ee31d9357159","src/dbghelp.rs":"40891588891fe48c16263374a36092ac3e67ddf4f756b880839f31dfcb80b7c4","src/lib.rs":"03f2a0f2524cb2078e2f28959c3eb1625ff400d3e23eeb7d3b73d86c012979b2","src/print.rs":"766affbd9d2242a81d85067413dd95b807425a6df2fffb17a4eacc5f606d4200","src/print/fuchsia.rs":"de45f55032e05fdc1fd55224910158f8c64a705494103a29c7e2680536e76e40","src/symbolize/dbghelp.rs":"58aeda764a27702e0abb3af62bae8a162d8b6cb8c80ffd141ee794d81a8ace15","src/symbolize/gimli.rs":"062afb232fdd1550ae613de79385365b03aa50a721794666d7856401b7f44e5a","src/symbolize/gimli/coff.rs":"d3f4a274bd3b2ed81d114a9326630c019f682ca91aac6ec31e660f420c35b064","src/symbolize/gimli/elf.rs":"3445558fc1feed60165af55e07847c59c3eca5e4031f50b04329fc5be36eb057","src/symbolize/gimli/libs_dl_iterate_phdr.rs":"8f7dabbdff97e5a24f0d5b3670469840666a91e9971ac352abeb4e96d98a2a6c","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":"a0d6edf8f3af23523d1a63a12ef6a6dd9ad1057b2cb20cc405da0544daba5389","src/symbolize/gimli/libs_windows.rs":"6459f8610ca1a0fd7456539ec604f5276c94b3d0d7331357eaed338e49220a02","src/symbolize/gimli/macho.rs":"a725d85566438499ecfb0ac06193c3153a2fa1b533f360d55c63dea386d1920d","src/symbolize/gimli/mmap_fake.rs":"9564fcf47000e70d521b31518e205c8e6ee09b7410fb1eb1e452721757ff54ba","src/symbolize/gimli/mmap_unix.rs":"8159a4a807bd5692412ba1a280bb36ab942c06e904f37a92e2545f0b4211308a","src/symbolize/gimli/mmap_windows.rs":"1ca715317c1054968d92350438b293f800bae2174f395b20bc43a633d757fe8f","src/symbolize/gimli/stash.rs":"67d01016b17ca4c0adbb0827da9b83fde5f79ccc89db3e4fd769ab03c1248d8e","src/symbolize/miri.rs":"f5201cc8a7de24ad3424d2472cb0af59cd28563d09cc0c21e998f4cee4367ade","src/symbolize/mod.rs":"a7177603810aca1cd9cd4a59027a1dd2c792dc9d345435b5dc866eb7c8b66baf","src/symbolize/noop.rs":"5d4432079b8ae2b9382945a57ae43df57bb4b7ed2e5956d4167e051a44567388","src/types.rs":"f43c94b99d57ca66a5cfe939a46016c95b2d69d82695fb52480f7a3e5b344fd9","src/windows.rs":"46f02837a2e6b404a035993f2e1f03cdfc1a5a872c1feb92926566a31138d273","tests/accuracy/auxiliary.rs":"71d2238da401042e007ef5ee20336d6834724bae96d93c8c52d11a5a332d7d34","tests/accuracy/main.rs":"f8e42aeeb50b35fca380db2e9fe52820cc0bc3133167289c5710e3290701e78e","tests/concurrent-panics.rs":"7696676e46a1c50a3a88446fdc59c0dedfb81ded24d77ec725f7cc101a5d8fe6","tests/long_fn_name.rs":"ebef58e34543ed4d47048faa9b6525f68fc71e12255af734523a513c5d4baa6f","tests/skip_inner_frames.rs":"7560fe59e83e4b234789c448da5504d3dd9065f9ad1b2615f12606f9112df4e0","tests/smoke.rs":"33014495f9158aea2d0ee2ee3335ffe82105c7ed894f96eaf7d23845a60f7439"},"package":"cab84319d616cfb654d03394f38ab7e6f0919e181b1b57e1fd15e7fb4077d9a7"} \ No newline at end of file
diff --git a/vendor/backtrace/Cargo.lock b/vendor/backtrace/Cargo.lock
new file mode 100644
index 000000000..6eee92255
--- /dev/null
+++ b/vendor/backtrace/Cargo.lock
@@ -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.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b"
+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.66"
+dependencies = [
+ "addr2line",
+ "cc",
+ "cfg-if",
+ "cpp_demangle",
+ "libc",
+ "libloading",
+ "miniz_oxide",
+ "object",
+ "rustc-demangle",
+ "rustc-serialize",
+ "serde",
+ "winapi",
+]
+
+[[package]]
+name = "cc"
+version = "1.0.73"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
+
+[[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.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eeaa953eaad386a53111e47172c2fedba671e5684c8dd601a5f474f4f118710f"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "gimli"
+version = "0.26.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4"
+
+[[package]]
+name = "libc"
+version = "0.2.126"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
+
+[[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.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
+
+[[package]]
+name = "miniz_oxide"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc"
+dependencies = [
+ "adler",
+]
+
+[[package]]
+name = "object"
+version = "0.29.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804"
+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.138"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1578c6245786b9d168c5447eeacfb96856573ca56c9d68fdcf394be134882a47"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.138"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "023e9b1467aef8a10fb88f25611870ada9800ef7e22afce356bb0d2387b6f27c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "syn"
+version = "1.0.98"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c"
+
+[[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"
diff --git a/vendor/backtrace/Cargo.toml b/vendor/backtrace/Cargo.toml
new file mode 100644
index 000000000..641181528
--- /dev/null
+++ b/vendor/backtrace/Cargo.toml
@@ -0,0 +1,138 @@
+# 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.66"
+authors = ["The Rust Project Developers"]
+build = "build.rs"
+autoexamples = true
+autotests = true
+description = """
+A library to acquire a stack trace (backtrace) at runtime in a Rust program.
+"""
+homepage = "https://github.com/rust-lang/backtrace-rs"
+documentation = "https://docs.rs/backtrace"
+readme = "README.md"
+license = "MIT/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"]
+
+[dependencies.addr2line]
+version = "0.17.0"
+default-features = false
+
+[dependencies.cfg-if]
+version = "1.0"
+
+[dependencies.cpp_demangle]
+version = "0.3.0"
+optional = true
+default-features = false
+
+[dependencies.libc]
+version = "0.2.94"
+default-features = false
+
+[dependencies.miniz_oxide]
+version = "0.5.0"
+default-features = false
+
+[dependencies.object]
+version = "0.29.0"
+features = [
+ "read_core",
+ "elf",
+ "macho",
+ "pe",
+ "unaligned",
+ "archive",
+]
+default-features = false
+
+[dependencies.rustc-demangle]
+version = "0.1.4"
+
+[dependencies.rustc-serialize]
+version = "0.3"
+optional = true
+
+[dependencies.serde]
+version = "1.0"
+features = ["derive"]
+optional = true
+
+[dev-dependencies.libloading]
+version = "0.7"
+
+[build-dependencies.cc]
+version = "1.0.67"
+
+[features]
+coresymbolication = []
+dbghelp = []
+default = ["std"]
+dladdr = []
+gimli-symbolize = []
+kernel32 = []
+libbacktrace = []
+libunwind = []
+serialize-rustc = ["rustc-serialize"]
+serialize-serde = ["serde"]
+std = []
+unix-backtrace = []
+verify-winapi = [
+ "winapi/dbghelp",
+ "winapi/handleapi",
+ "winapi/libloaderapi",
+ "winapi/memoryapi",
+ "winapi/minwindef",
+ "winapi/processthreadsapi",
+ "winapi/synchapi",
+ "winapi/tlhelp32",
+ "winapi/winbase",
+ "winapi/winnt",
+]
+
+[target."cfg(windows)".dependencies.winapi]
+version = "0.3.9"
+optional = true
diff --git a/vendor/backtrace/LICENSE-APACHE b/vendor/backtrace/LICENSE-APACHE
new file mode 100644
index 000000000..16fe87b06
--- /dev/null
+++ b/vendor/backtrace/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/vendor/backtrace/LICENSE-MIT b/vendor/backtrace/LICENSE-MIT
new file mode 100644
index 000000000..39e0ed660
--- /dev/null
+++ b/vendor/backtrace/LICENSE-MIT
@@ -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.
diff --git a/vendor/backtrace/README.md b/vendor/backtrace/README.md
new file mode 100644
index 000000000..cd80a697c
--- /dev/null
+++ b/vendor/backtrace/README.md
@@ -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.
diff --git a/vendor/backtrace/benches/benchmarks.rs b/vendor/backtrace/benches/benchmarks.rs
new file mode 100644
index 000000000..e14e733b8
--- /dev/null
+++ b/vendor/backtrace/benches/benchmarks.rs
@@ -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);
+}
diff --git a/vendor/backtrace/build.rs b/vendor/backtrace/build.rs
new file mode 100644
index 000000000..812fbb1fe
--- /dev/null
+++ b/vendor/backtrace/build.rs
@@ -0,0 +1,41 @@
+extern crate cc;
+
+use std::env;
+
+fn main() {
+ match env::var("CARGO_CFG_TARGET_OS").unwrap_or_default().as_str() {
+ "android" => build_android(),
+ _ => {}
+ }
+}
+
+fn build_android() {
+ let expansion = match cc::Build::new().file("src/android-api.c").try_expand() {
+ Ok(result) => result,
+ Err(e) => {
+ println!("failed to run C compiler: {}", e);
+ return;
+ }
+ };
+ let expansion = match std::str::from_utf8(&expansion) {
+ Ok(s) => s,
+ Err(_) => return,
+ };
+ println!("expanded android version detection:\n{}", expansion);
+ let marker = "APIVERSION";
+ let i = match expansion.find(marker) {
+ Some(i) => i,
+ None => return,
+ };
+ let version = match expansion[i + marker.len() + 1..].split_whitespace().next() {
+ Some(s) => s,
+ None => return,
+ };
+ let version = match version.parse::<u32>() {
+ Ok(n) => n,
+ Err(_) => return,
+ };
+ if version >= 21 {
+ println!("cargo:rustc-cfg=feature=\"dl_iterate_phdr\"");
+ }
+}
diff --git a/vendor/backtrace/ci/android-ndk.sh b/vendor/backtrace/ci/android-ndk.sh
new file mode 100755
index 000000000..b5df62b6f
--- /dev/null
+++ b/vendor/backtrace/ci/android-ndk.sh
@@ -0,0 +1,23 @@
+set -ex
+
+ANDROID_ARCH=$1
+ANDROID_SDK_VERSION=4333796
+
+mkdir /tmp/android
+cd /tmp/android
+
+curl -o android-sdk.zip \
+ "https://dl.google.com/android/repository/sdk-tools-linux-${ANDROID_SDK_VERSION}.zip"
+unzip -q android-sdk.zip
+
+yes | ./tools/bin/sdkmanager --licenses > /dev/null
+./tools/bin/sdkmanager ndk-bundle > /dev/null
+
+./ndk-bundle/build/tools/make_standalone_toolchain.py \
+ --arch $ANDROID_ARCH \
+ --stl=libc++ \
+ --api 21 \
+ --install-dir /android-toolchain
+
+cd /tmp
+rm -rf android
diff --git a/vendor/backtrace/ci/android-sdk.sh b/vendor/backtrace/ci/android-sdk.sh
new file mode 100755
index 000000000..7fde9a97f
--- /dev/null
+++ b/vendor/backtrace/ci/android-sdk.sh
@@ -0,0 +1,65 @@
+#!/usr/bin/env sh
+
+set -ex
+
+# Prep the SDK and emulator
+#
+# Note that the update process requires that we accept a bunch of licenses, and
+# we can't just pipe `yes` into it for some reason, so we take the same strategy
+# located in https://github.com/appunite/docker by just wrapping it in a script
+# which apparently magically accepts the licenses.
+
+SDK=4333796
+mkdir sdk
+curl --retry 20 https://dl.google.com/android/repository/sdk-tools-linux-${SDK}.zip -O
+unzip -q -d sdk sdk-tools-linux-${SDK}.zip
+
+case "$1" in
+ arm | armv7)
+ api=24
+ image="system-images;android-${api};google_apis;armeabi-v7a"
+ ;;
+ aarch64)
+ api=24
+ image="system-images;android-${api};google_apis;arm64-v8a"
+ ;;
+ i686)
+ api=28
+ image="system-images;android-${api};default;x86"
+ ;;
+ x86_64)
+ api=28
+ image="system-images;android-${api};default;x86_64"
+ ;;
+ *)
+ echo "invalid arch: $1"
+ exit 1
+ ;;
+esac;
+
+# Try to fix warning about missing file.
+# See https://askubuntu.com/a/1078784
+mkdir -p /root/.android/
+echo '### User Sources for Android SDK Manager' >> /root/.android/repositories.cfg
+echo '#Fri Nov 03 10:11:27 CET 2017 count=0' >> /root/.android/repositories.cfg
+
+# Print all available packages
+# yes | ./sdk/tools/bin/sdkmanager --list --verbose
+
+# --no_https avoids
+# javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: No trusted certificate found
+#
+# | grep -v = || true removes the progress bar output from the sdkmanager
+# which produces an insane amount of output.
+yes | ./sdk/tools/bin/sdkmanager --licenses --no_https | grep -v = || true
+yes | ./sdk/tools/bin/sdkmanager --no_https \
+ "emulator" \
+ "platform-tools" \
+ "platforms;android-${api}" \
+ "${image}" | grep -v = || true
+
+echo "no" |
+ ./sdk/tools/bin/avdmanager create avd \
+ --name "${1}" \
+ --package "${image}" | grep -v = || true
+
diff --git a/vendor/backtrace/ci/debuglink-docker.sh b/vendor/backtrace/ci/debuglink-docker.sh
new file mode 100755
index 000000000..acb19e98b
--- /dev/null
+++ b/vendor/backtrace/ci/debuglink-docker.sh
@@ -0,0 +1,29 @@
+# Small script to run debuglink tests inside a docker image.
+# Creates a writable mount on /usr/lib/debug.
+
+set -ex
+
+run() {
+ cargo generate-lockfile --manifest-path crates/debuglink/Cargo.toml
+ mkdir -p target crates/debuglink/target debug
+ docker build -t backtrace -f ci/docker/$1/Dockerfile ci
+ docker run \
+ --user `id -u`:`id -g` \
+ --rm \
+ --init \
+ --volume $(dirname $(dirname `which cargo`)):/cargo \
+ --env CARGO_HOME=/cargo \
+ --volume `rustc --print sysroot`:/rust:ro \
+ --env TARGET=$1 \
+ --volume `pwd`:/checkout:ro \
+ --volume `pwd`/target:/checkout/crates/debuglink/target \
+ --workdir /checkout \
+ --volume `pwd`/debug:/usr/lib/debug \
+ --privileged \
+ --env RUSTFLAGS \
+ backtrace \
+ bash \
+ -c 'PATH=$PATH:/rust/bin exec ci/debuglink.sh'
+}
+
+run x86_64-unknown-linux-gnu
diff --git a/vendor/backtrace/ci/debuglink.sh b/vendor/backtrace/ci/debuglink.sh
new file mode 100755
index 000000000..b2da2013d
--- /dev/null
+++ b/vendor/backtrace/ci/debuglink.sh
@@ -0,0 +1,75 @@
+#!/bin/bash
+
+# Debuglink tests.
+# We build crates/debuglink and then move its debuginfo around
+# and test that it can still find the debuginfo.
+
+set -ex
+
+cratedir=`pwd`/crates/debuglink
+exefile=crates/debuglink/target/debug/debuglink
+
+# Baseline; no separate debug
+cargo build --manifest-path crates/debuglink/Cargo.toml
+$exefile $cratedir
+
+# Separate debug in same dir
+debugfile1=`dirname $exefile`/debuglink.debug
+objcopy --only-keep-debug $exefile $debugfile1
+strip -g $exefile
+(cd `dirname $exefile` && objcopy --add-gnu-debuglink=debuglink.debug debuglink)
+$exefile $cratedir
+
+# Separate debug in .debug subdir
+debugfile2=`dirname $exefile`/.debug/debuglink.debug
+mkdir -p `dirname $debugfile2`
+mv $debugfile1 $debugfile2
+$exefile $cratedir
+
+# Separate debug in /usr/lib/debug subdir
+debugfile3="/usr/lib/debug/$cratedir/target/debug/debuglink.debug"
+mkdir -p `dirname $debugfile3`
+mv $debugfile2 $debugfile3
+$exefile $cratedir
+
+# Separate debug in /usr/lib/debug/.build-id subdir
+id=`readelf -n $exefile | grep '^ Build ID: [0-9a-f]' | cut -b 15-`
+idfile="/usr/lib/debug/.build-id/${id:0:2}/${id:2}.debug"
+mkdir -p `dirname $idfile`
+mv $debugfile3 $idfile
+$exefile $cratedir
+
+# Replace idfile with a symlink (this is the usual arrangement)
+mv $idfile $debugfile3
+ln -s $debugfile3 $idfile
+$exefile $cratedir
+
+# Supplementary object file using relative path
+dwzfile="/usr/lib/debug/.dwz/debuglink.debug"
+mkdir -p `dirname $dwzfile`
+cp $debugfile3 $debugfile3.copy
+dwz -m $dwzfile -rh $debugfile3 $debugfile3.copy
+rm $debugfile3.copy
+$exefile $cratedir
+
+# Supplementary object file using build ID
+dwzid=`readelf -n $dwzfile | grep '^ Build ID: [0-9a-f]' | cut -b 15-`
+dwzidfile="/usr/lib/debug/.build-id/${dwzid:0:2}/${dwzid:2}.debug"
+mkdir -p `dirname $dwzidfile`
+mv $dwzfile $dwzidfile
+$exefile $cratedir
+mv $dwzidfile $dwzfile
+
+# Missing debug should fail
+mv $debugfile3 $debugfile3.tmp
+! $exefile $cratedir
+mv $debugfile3.tmp $debugfile3
+
+# Missing dwz should fail
+mv $dwzfile $dwzfile.tmp
+! $exefile $cratedir
+mv $dwzfile.tmp $dwzfile
+
+# Cleanup
+rm $idfile $debugfile3 $dwzfile
+echo Success
diff --git a/vendor/backtrace/ci/docker/aarch64-linux-android/Dockerfile b/vendor/backtrace/ci/docker/aarch64-linux-android/Dockerfile
new file mode 100644
index 000000000..c5655ed5e
--- /dev/null
+++ b/vendor/backtrace/ci/docker/aarch64-linux-android/Dockerfile
@@ -0,0 +1,18 @@
+FROM ubuntu:20.04
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+ curl \
+ ca-certificates \
+ unzip \
+ openjdk-8-jre \
+ python \
+ gcc \
+ libc6-dev
+
+COPY android-ndk.sh /
+RUN /android-ndk.sh arm64
+ENV PATH=$PATH:/android-toolchain/bin
+
+# TODO: run tests in an emulator eventually
+ENV CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER=aarch64-linux-android-gcc \
+ CARGO_TARGET_AARCH64_LINUX_ANDROID_RUNNER=echo
diff --git a/vendor/backtrace/ci/docker/aarch64-unknown-linux-gnu/Dockerfile b/vendor/backtrace/ci/docker/aarch64-unknown-linux-gnu/Dockerfile
new file mode 100644
index 000000000..871b353c0
--- /dev/null
+++ b/vendor/backtrace/ci/docker/aarch64-unknown-linux-gnu/Dockerfile
@@ -0,0 +1,11 @@
+FROM ubuntu:20.04
+RUN apt-get update && apt-get install -y --no-install-recommends \
+ gcc \
+ ca-certificates \
+ libc6-dev \
+ gcc-aarch64-linux-gnu \
+ libc6-dev-arm64-cross \
+ qemu-user
+
+ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc \
+ CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUNNER="qemu-aarch64 -L /usr/aarch64-linux-gnu"
diff --git a/vendor/backtrace/ci/docker/arm-linux-androideabi/Dockerfile b/vendor/backtrace/ci/docker/arm-linux-androideabi/Dockerfile
new file mode 100644
index 000000000..446a64cc0
--- /dev/null
+++ b/vendor/backtrace/ci/docker/arm-linux-androideabi/Dockerfile
@@ -0,0 +1,18 @@
+FROM ubuntu:20.04
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+ curl \
+ ca-certificates \
+ unzip \
+ openjdk-8-jre \
+ python \
+ gcc \
+ libc6-dev
+
+COPY android-ndk.sh /
+RUN /android-ndk.sh arm
+ENV PATH=$PATH:/android-toolchain/bin
+
+# TODO: run tests in an emulator eventually
+ENV CARGO_TARGET_ARM_LINUX_ANDROIDEABI_LINKER=arm-linux-androideabi-gcc \
+ CARGO_TARGET_ARM_LINUX_ANDROIDEABI_RUNNER=echo
diff --git a/vendor/backtrace/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile b/vendor/backtrace/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile
new file mode 100644
index 000000000..24665972c
--- /dev/null
+++ b/vendor/backtrace/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile
@@ -0,0 +1,10 @@
+FROM ubuntu:20.04
+RUN apt-get update && apt-get install -y --no-install-recommends \
+ gcc \
+ ca-certificates \
+ libc6-dev \
+ gcc-arm-linux-gnueabihf \
+ libc6-dev-armhf-cross \
+ qemu-user
+ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \
+ CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_RUNNER="qemu-arm -L /usr/arm-linux-gnueabihf"
diff --git a/vendor/backtrace/ci/docker/armv7-linux-androideabi/Dockerfile b/vendor/backtrace/ci/docker/armv7-linux-androideabi/Dockerfile
new file mode 100644
index 000000000..539bbc494
--- /dev/null
+++ b/vendor/backtrace/ci/docker/armv7-linux-androideabi/Dockerfile
@@ -0,0 +1,18 @@
+FROM ubuntu:20.04
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+ curl \
+ ca-certificates \
+ unzip \
+ openjdk-8-jre \
+ python \
+ gcc \
+ libc6-dev
+
+COPY android-ndk.sh /
+RUN /android-ndk.sh arm
+ENV PATH=$PATH:/android-toolchain/bin
+
+# TODO: run tests in an emulator eventually
+ENV CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_LINKER=arm-linux-androideabi-gcc \
+ CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_RUNNER=echo
diff --git a/vendor/backtrace/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile b/vendor/backtrace/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile
new file mode 100644
index 000000000..6f7d0fd36
--- /dev/null
+++ b/vendor/backtrace/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile
@@ -0,0 +1,10 @@
+FROM ubuntu:20.04
+RUN apt-get update && apt-get install -y --no-install-recommends \
+ gcc \
+ ca-certificates \
+ libc6-dev \
+ gcc-arm-linux-gnueabihf \
+ libc6-dev-armhf-cross \
+ qemu-user
+ENV CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \
+ CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_RUNNER="qemu-arm -L /usr/arm-linux-gnueabihf"
diff --git a/vendor/backtrace/ci/docker/i586-unknown-linux-gnu/Dockerfile b/vendor/backtrace/ci/docker/i586-unknown-linux-gnu/Dockerfile
new file mode 100644
index 000000000..316a233e3
--- /dev/null
+++ b/vendor/backtrace/ci/docker/i586-unknown-linux-gnu/Dockerfile
@@ -0,0 +1,5 @@
+FROM ubuntu:20.04
+RUN apt-get update && apt-get install -y --no-install-recommends \
+ gcc-multilib \
+ libc6-dev \
+ ca-certificates
diff --git a/vendor/backtrace/ci/docker/i686-linux-android/Dockerfile b/vendor/backtrace/ci/docker/i686-linux-android/Dockerfile
new file mode 100644
index 000000000..83ccb2948
--- /dev/null
+++ b/vendor/backtrace/ci/docker/i686-linux-android/Dockerfile
@@ -0,0 +1,18 @@
+FROM ubuntu:20.04
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+ curl \
+ ca-certificates \
+ unzip \
+ openjdk-8-jre \
+ python \
+ gcc \
+ libc6-dev
+
+COPY android-ndk.sh /
+RUN /android-ndk.sh x86
+ENV PATH=$PATH:/android-toolchain/bin
+
+# TODO: run tests in an emulator eventually
+ENV CARGO_TARGET_I686_LINUX_ANDROID_LINKER=i686-linux-android-gcc \
+ CARGO_TARGET_I686_LINUX_ANDROID_RUNNER=echo
diff --git a/vendor/backtrace/ci/docker/i686-unknown-linux-gnu/Dockerfile b/vendor/backtrace/ci/docker/i686-unknown-linux-gnu/Dockerfile
new file mode 100644
index 000000000..316a233e3
--- /dev/null
+++ b/vendor/backtrace/ci/docker/i686-unknown-linux-gnu/Dockerfile
@@ -0,0 +1,5 @@
+FROM ubuntu:20.04
+RUN apt-get update && apt-get install -y --no-install-recommends \
+ gcc-multilib \
+ libc6-dev \
+ ca-certificates
diff --git a/vendor/backtrace/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile b/vendor/backtrace/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile
new file mode 100644
index 000000000..7ca5a64bf
--- /dev/null
+++ b/vendor/backtrace/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile
@@ -0,0 +1,16 @@
+FROM ubuntu:20.04
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+ gcc \
+ ca-certificates \
+ libc6-dev \
+ gcc-powerpc64-linux-gnu \
+ libc6-dev-ppc64-cross \
+ qemu-user \
+ qemu-system-ppc
+
+ENV CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_LINKER=powerpc64-linux-gnu-gcc \
+ # TODO: should actually run these tests
+ #CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_RUNNER="qemu-ppc64 -L /usr/powerpc64-linux-gnu" \
+ CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_RUNNER=echo \
+ CC=powerpc64-linux-gnu-gcc
diff --git a/vendor/backtrace/ci/docker/s390x-unknown-linux-gnu/Dockerfile b/vendor/backtrace/ci/docker/s390x-unknown-linux-gnu/Dockerfile
new file mode 100644
index 000000000..7c19dcbb4
--- /dev/null
+++ b/vendor/backtrace/ci/docker/s390x-unknown-linux-gnu/Dockerfile
@@ -0,0 +1,17 @@
+FROM ubuntu:20.04
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+ gcc \
+ ca-certificates \
+ libc6-dev \
+ gcc-s390x-linux-gnu \
+ libc6-dev-s390x-cross \
+ qemu-user \
+ # There seems to be a bug in processing mixed-architecture
+ # ld.so.cache files that causes crashes in some cases. Work
+ # around this by simply deleting the cache for now.
+ && rm /etc/ld.so.cache
+
+ENV CARGO_TARGET_S390X_UNKNOWN_LINUX_GNU_LINKER=s390x-linux-gnu-gcc \
+ CARGO_TARGET_S390X_UNKNOWN_LINUX_GNU_RUNNER="qemu-s390x -L /usr/s390x-linux-gnu" \
+ CC=s390x-linux-gnu-gcc
diff --git a/vendor/backtrace/ci/docker/x86_64-linux-android/Dockerfile b/vendor/backtrace/ci/docker/x86_64-linux-android/Dockerfile
new file mode 100644
index 000000000..88a22ce6c
--- /dev/null
+++ b/vendor/backtrace/ci/docker/x86_64-linux-android/Dockerfile
@@ -0,0 +1,18 @@
+FROM ubuntu:20.04
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+ curl \
+ ca-certificates \
+ unzip \
+ openjdk-8-jre \
+ python \
+ gcc \
+ libc6-dev
+
+COPY android-ndk.sh /
+RUN /android-ndk.sh x86_64
+ENV PATH=$PATH:/android-toolchain/bin
+
+# TODO: run tests in an emulator eventually
+ENV CARGO_TARGET_X86_64_LINUX_ANDROID_LINKER=x86_64-linux-android-gcc \
+ CARGO_TARGET_X86_64_LINUX_ANDROID_RUNNER=echo
diff --git a/vendor/backtrace/ci/docker/x86_64-pc-windows-gnu/Dockerfile b/vendor/backtrace/ci/docker/x86_64-pc-windows-gnu/Dockerfile
new file mode 100644
index 000000000..a8e859e67
--- /dev/null
+++ b/vendor/backtrace/ci/docker/x86_64-pc-windows-gnu/Dockerfile
@@ -0,0 +1,10 @@
+FROM ubuntu:20.04
+RUN apt-get update && apt-get install -y --no-install-recommends \
+ gcc \
+ libc6-dev \
+ ca-certificates \
+ gcc-mingw-w64-x86-64
+
+# No need to run tests, we're just testing that it compiles
+ENV CARGO_TARGET_X86_64_PC_WINDOWS_GNU_RUNNER=echo \
+ CARGO_TARGET_X86_64_PC_WINDOWS_GNU_LINKER=x86_64-w64-mingw32-gcc
diff --git a/vendor/backtrace/ci/docker/x86_64-unknown-linux-gnu/Dockerfile b/vendor/backtrace/ci/docker/x86_64-unknown-linux-gnu/Dockerfile
new file mode 100644
index 000000000..551ab1378
--- /dev/null
+++ b/vendor/backtrace/ci/docker/x86_64-unknown-linux-gnu/Dockerfile
@@ -0,0 +1,6 @@
+FROM ubuntu:20.04
+RUN apt-get update && apt-get install -y --no-install-recommends \
+ gcc \
+ libc6-dev \
+ ca-certificates \
+ dwz
diff --git a/vendor/backtrace/ci/docker/x86_64-unknown-linux-musl/Dockerfile b/vendor/backtrace/ci/docker/x86_64-unknown-linux-musl/Dockerfile
new file mode 100644
index 000000000..e77e41f5b
--- /dev/null
+++ b/vendor/backtrace/ci/docker/x86_64-unknown-linux-musl/Dockerfile
@@ -0,0 +1,6 @@
+FROM ubuntu:20.04
+RUN apt-get update && apt-get install -y --no-install-recommends \
+ gcc \
+ libc6-dev \
+ ca-certificates \
+ musl-tools
diff --git a/vendor/backtrace/ci/run-docker.sh b/vendor/backtrace/ci/run-docker.sh
new file mode 100755
index 000000000..8aa6d84a4
--- /dev/null
+++ b/vendor/backtrace/ci/run-docker.sh
@@ -0,0 +1,33 @@
+# Small script to run tests for a target (or all targets) inside all the
+# respective docker images.
+
+set -ex
+
+run() {
+ docker build -t backtrace -f ci/docker/$1/Dockerfile ci
+ mkdir -p target
+ docker run \
+ --user `id -u`:`id -g` \
+ --rm \
+ --init \
+ --volume $(dirname $(dirname `which cargo`)):/cargo \
+ --env CARGO_HOME=/cargo \
+ --volume `rustc --print sysroot`:/rust:ro \
+ --env TARGET=$1 \
+ --volume `pwd`:/checkout:ro \
+ --volume `pwd`/target:/checkout/target \
+ --workdir /checkout \
+ --privileged \
+ --env RUSTFLAGS \
+ backtrace \
+ bash \
+ -c 'PATH=$PATH:/rust/bin exec ci/run.sh'
+}
+
+if [ -z "$1" ]; then
+ for d in `ls ci/docker/`; do
+ run $d
+ done
+else
+ run $1
+fi
diff --git a/vendor/backtrace/ci/run.sh b/vendor/backtrace/ci/run.sh
new file mode 100755
index 000000000..166b387e4
--- /dev/null
+++ b/vendor/backtrace/ci/run.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+set -ex
+
+cargo test --target $TARGET
+cargo build --target $TARGET --manifest-path crates/as-if-std/Cargo.toml
diff --git a/vendor/backtrace/ci/runtest-android.rs b/vendor/backtrace/ci/runtest-android.rs
new file mode 100644
index 000000000..dc70121dc
--- /dev/null
+++ b/vendor/backtrace/ci/runtest-android.rs
@@ -0,0 +1,50 @@
+use std::env;
+use std::process::Command;
+use std::path::{Path, PathBuf};
+
+fn main() {
+ let args = env::args_os()
+ .skip(1)
+ .filter(|arg| arg != "--quiet")
+ .collect::<Vec<_>>();
+ assert_eq!(args.len(), 1);
+ let test = PathBuf::from(&args[0]);
+ let dst = Path::new("/data/local/tmp").join(test.file_name().unwrap());
+
+ println!("waiting for device to come online...");
+ let status = Command::new("adb")
+ .arg("wait-for-device")
+ .status()
+ .expect("failed to run: adb wait-for-device");
+ assert!(status.success());
+
+ println!("pushing executable...");
+ let status = Command::new("adb")
+ .arg("push")
+ .arg(&test)
+ .arg(&dst)
+ .status()
+ .expect("failed to run: adb pushr");
+ assert!(status.success());
+
+ println!("executing tests...");
+ let output = Command::new("adb")
+ .arg("shell")
+ .arg(&dst)
+ .output()
+ .expect("failed to run: adb shell");
+ assert!(status.success());
+
+ println!("status: {}\nstdout ---\n{}\nstderr ---\n{}",
+ output.status,
+ String::from_utf8_lossy(&output.stdout),
+ String::from_utf8_lossy(&output.stderr));
+
+ let stdout = String::from_utf8_lossy(&output.stdout);
+ stdout.lines().find(|l|
+ (l.starts_with("PASSED ") && l.contains(" tests")) ||
+ l.starts_with("test result: ok")
+ ).unwrap_or_else(|| {
+ panic!("failed to find successful test run");
+ });
+}
diff --git a/vendor/backtrace/examples/backtrace.rs b/vendor/backtrace/examples/backtrace.rs
new file mode 100644
index 000000000..7ff6cd39e
--- /dev/null
+++ b/vendor/backtrace/examples/backtrace.rs
@@ -0,0 +1,5 @@
+use backtrace::Backtrace;
+
+fn main() {
+ println!("{:?}", Backtrace::new());
+}
diff --git a/vendor/backtrace/examples/raw.rs b/vendor/backtrace/examples/raw.rs
new file mode 100644
index 000000000..d96a127a2
--- /dev/null
+++ b/vendor/backtrace/examples/raw.rs
@@ -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
+ });
+}
diff --git a/vendor/backtrace/src/android-api.c b/vendor/backtrace/src/android-api.c
new file mode 100644
index 000000000..1bfeadf5b
--- /dev/null
+++ b/vendor/backtrace/src/android-api.c
@@ -0,0 +1,4 @@
+// Used from the build script to detect the value of the `__ANDROID_API__`
+// builtin #define
+
+APIVERSION __ANDROID_API__
diff --git a/vendor/backtrace/src/backtrace/dbghelp.rs b/vendor/backtrace/src/backtrace/dbghelp.rs
new file mode 100644
index 000000000..ba0f05f3b
--- /dev/null
+++ b/vendor/backtrace/src/backtrace/dbghelp.rs
@@ -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
+}
diff --git a/vendor/backtrace/src/backtrace/libunwind.rs b/vendor/backtrace/src/backtrace/libunwind.rs
new file mode 100644
index 000000000..ef77edda5
--- /dev/null
+++ b/vendor/backtrace/src/backtrace/libunwind.rs
@@ -0,0 +1,267 @@
+//! 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_os = "macos") || cfg!(target_os = "ios") {
+ 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"))
+ ))] {
+ 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
+ }
+ }
+ }
+}
diff --git a/vendor/backtrace/src/backtrace/miri.rs b/vendor/backtrace/src/backtrace/miri.rs
new file mode 100644
index 000000000..9a5f65b80
--- /dev/null
+++ b/vendor/backtrace/src/backtrace/miri.rs
@@ -0,0 +1,107 @@
+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,
+ },
+ }
+}
+
+pub 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);
+ cb(&super::Frame { inner: frame });
+ }
+}
diff --git a/vendor/backtrace/src/backtrace/mod.rs b/vendor/backtrace/src/backtrace/mod.rs
new file mode 100644
index 000000000..93355d744
--- /dev/null
+++ b/vendor/backtrace/src/backtrace/mod.rs
@@ -0,0 +1,162 @@
+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")),
+ ),
+ 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;
+ }
+}
diff --git a/vendor/backtrace/src/backtrace/noop.rs b/vendor/backtrace/src/backtrace/noop.rs
new file mode 100644
index 000000000..7bcea67aa
--- /dev/null
+++ b/vendor/backtrace/src/backtrace/noop.rs
@@ -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
+ }
+}
diff --git a/vendor/backtrace/src/capture.rs b/vendor/backtrace/src/capture.rs
new file mode 100644
index 000000000..e0dd9c474
--- /dev/null
+++ b/vendor/backtrace/src/capture.rs
@@ -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());
+ }
+ }
+}
diff --git a/vendor/backtrace/src/dbghelp.rs b/vendor/backtrace/src/dbghelp.rs
new file mode 100644
index 000000000..e01002beb
--- /dev/null
+++ b/vendor/backtrace/src/dbghelp.rs
@@ -0,0 +1,351 @@
+//! 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 _,
+ // Initiall 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};
+
+ 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 {
+ lock = CreateMutexA(
+ ptr::null_mut(),
+ 0,
+ "Local\\RustBacktraceMutex\0".as_ptr() as _,
+ ) 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);
+ }
+ }
+}
diff --git a/vendor/backtrace/src/lib.rs b/vendor/backtrace/src/lib.rs
new file mode 100644
index 000000000..e5dea3387
--- /dev/null
+++ b/vendor/backtrace/src/lib.rs
@@ -0,0 +1,193 @@
+//! 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!
+
+#![doc(html_root_url = "https://docs.rs/backtrace")]
+#![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;
diff --git a/vendor/backtrace/src/print.rs b/vendor/backtrace/src/print.rs
new file mode 100644
index 000000000..cc677122a
--- /dev/null
+++ b/vendor/backtrace/src/print.rs
@@ -0,0 +1,302 @@
+#[cfg(feature = "std")]
+use super::{BacktraceFrame, BacktraceSymbol};
+use super::{BytesOrWideString, Frame, SymbolName};
+use core::ffi::c_void;
+use core::fmt;
+
+const HEX_WIDTH: usize = 2 + 2 * core::mem::size_of::<usize>();
+
+#[cfg(target_os = "fuchsia")]
+mod fuchsia;
+
+/// A formatter for backtraces.
+///
+/// This type can be used to print a backtrace regardless of where the backtrace
+/// itself comes from. If you have a `Backtrace` type then its `Debug`
+/// implementation already uses this printing format.
+pub struct BacktraceFmt<'a, 'b> {
+ fmt: &'a mut fmt::Formatter<'b>,
+ frame_index: usize,
+ format: PrintFmt,
+ print_path:
+ &'a mut (dyn FnMut(&mut fmt::Formatter<'_>, BytesOrWideString<'_>) -> fmt::Result + 'b),
+}
+
+/// The styles of printing that we can print
+#[derive(Copy, Clone, Eq, PartialEq)]
+pub enum PrintFmt {
+ /// Prints a terser backtrace which ideally only contains relevant information
+ Short,
+ /// Prints a backtrace that contains all possible information
+ Full,
+ #[doc(hidden)]
+ __Nonexhaustive,
+}
+
+impl<'a, 'b> BacktraceFmt<'a, 'b> {
+ /// Create a new `BacktraceFmt` which will write output to the provided
+ /// `fmt`.
+ ///
+ /// The `format` argument will control the style in which the backtrace is
+ /// printed, and the `print_path` argument will be used to print the
+ /// `BytesOrWideString` instances of filenames. This type itself doesn't do
+ /// any printing of filenames, but this callback is required to do so.
+ pub fn new(
+ fmt: &'a mut fmt::Formatter<'b>,
+ format: PrintFmt,
+ print_path: &'a mut (dyn FnMut(&mut fmt::Formatter<'_>, BytesOrWideString<'_>) -> fmt::Result
+ + 'b),
+ ) -> Self {
+ BacktraceFmt {
+ fmt,
+ frame_index: 0,
+ format,
+ print_path,
+ }
+ }
+
+ /// Prints a preamble for the backtrace about to be printed.
+ ///
+ /// This is required on some platforms for backtraces to be fully
+ /// symbolicated later, and otherwise this should just be the first method
+ /// you call after creating a `BacktraceFmt`.
+ pub fn add_context(&mut self) -> fmt::Result {
+ #[cfg(target_os = "fuchsia")]
+ fuchsia::print_dso_context(self.fmt)?;
+ Ok(())
+ }
+
+ /// Adds a frame to the backtrace output.
+ ///
+ /// This commit returns an RAII instance of a `BacktraceFrameFmt` which can be used
+ /// to actually print a frame, and on destruction it will increment the
+ /// frame counter.
+ pub fn frame(&mut self) -> BacktraceFrameFmt<'_, 'a, 'b> {
+ BacktraceFrameFmt {
+ fmt: self,
+ symbol_index: 0,
+ }
+ }
+
+ /// Completes the backtrace output.
+ ///
+ /// This is currently a no-op but is added for future compatibility with
+ /// backtrace formats.
+ pub fn finish(&mut self) -> fmt::Result {
+ // Currently a no-op-- including this hook to allow for future additions.
+ Ok(())
+ }
+}
+
+/// 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 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;
+ }
+}
diff --git a/vendor/backtrace/src/print/fuchsia.rs b/vendor/backtrace/src/print/fuchsia.rs
new file mode 100644
index 000000000..959253acb
--- /dev/null
+++ b/vendor/backtrace/src/print/fuchsia.rs
@@ -0,0 +1,436 @@
+use core::fmt::{self, Write};
+use core::mem::{size_of, transmute};
+use core::slice::from_raw_parts;
+use libc::c_char;
+
+extern "C" {
+ // dl_iterate_phdr takes a callback that will receive a dl_phdr_info pointer
+ // for every DSO that has been linked into the process. dl_iterate_phdr also
+ // ensures that the dynamic linker is locked from start to finish of the
+ // iteration. If the callback returns a non-zero value the iteration is
+ // terminated early. 'data' will be passed as the third argument to the
+ // callback on each call. 'size' gives the size of the dl_phdr_info.
+ #[allow(improper_ctypes)]
+ fn dl_iterate_phdr(
+ f: extern "C" fn(info: &dl_phdr_info, size: usize, data: &mut DsoPrinter<'_, '_>) -> i32,
+ data: &mut DsoPrinter<'_, '_>,
+ ) -> i32;
+}
+
+// We need to parse out the build ID and some basic program header data
+// which means that we need a bit of stuff from the ELF spec as well.
+
+const PT_LOAD: u32 = 1;
+const PT_NOTE: u32 = 4;
+
+// Now we have to replicate, bit for bit, the structure of the dl_phdr_info
+// type used by fuchsia's current dynamic linker. Chromium also has this ABI
+// boundary as well as crashpad. Eventully we'd like to move these cases to
+// use elf-search but we'd need to provide that in the SDK and that has not
+// yet been done. Thus we (and they) are stuck having to use this method
+// which incurs a tight coupling with the fuchsia libc.
+
+#[allow(non_camel_case_types)]
+#[repr(C)]
+struct dl_phdr_info {
+ addr: *const u8,
+ name: *const c_char,
+ phdr: *const Elf_Phdr,
+ phnum: u16,
+ adds: u64,
+ subs: u64,
+ tls_modid: usize,
+ tls_data: *const u8,
+}
+
+impl dl_phdr_info {
+ fn program_headers(&self) -> PhdrIter<'_> {
+ PhdrIter {
+ phdrs: self.phdr_slice(),
+ base: self.addr,
+ }
+ }
+ // We have no way of knowing of checking if e_phoff and e_phnum are valid.
+ // libc should ensure this for us however so it's safe to form a slice here.
+ fn phdr_slice(&self) -> &[Elf_Phdr] {
+ unsafe { from_raw_parts(self.phdr, self.phnum as usize) }
+ }
+}
+
+struct PhdrIter<'a> {
+ phdrs: &'a [Elf_Phdr],
+ base: *const u8,
+}
+
+impl<'a> Iterator for PhdrIter<'a> {
+ type Item = Phdr<'a>;
+ fn next(&mut self) -> Option<Self::Item> {
+ self.phdrs.split_first().map(|(phdr, new_phdrs)| {
+ self.phdrs = new_phdrs;
+ Phdr {
+ phdr,
+ base: self.base,
+ }
+ })
+ }
+}
+
+// Elf_Phdr represents a 64-bit ELF program header in the endianness of the target
+// architecture.
+#[allow(non_camel_case_types)]
+#[derive(Clone, Debug)]
+#[repr(C)]
+struct Elf_Phdr {
+ p_type: u32,
+ p_flags: u32,
+ p_offset: u64,
+ p_vaddr: u64,
+ p_paddr: u64,
+ p_filesz: u64,
+ p_memsz: u64,
+ p_align: u64,
+}
+
+// Phdr represents a valid ELF program header and its contents.
+struct Phdr<'a> {
+ phdr: &'a Elf_Phdr,
+ base: *const u8,
+}
+
+impl<'a> Phdr<'a> {
+ // We have no way of checking if p_addr or p_memsz are valid. Fuchsia's libc
+ // parses the notes first however so by virtue of being here these headers
+ // must be valid. NoteIter does not require the underlying data to be valid
+ // but it does require the bounds to be valid. We trust that libc has ensured
+ // that this is the case for us here.
+ fn notes(&self) -> NoteIter<'a> {
+ unsafe {
+ NoteIter::new(
+ self.base.add(self.phdr.p_offset as usize),
+ self.phdr.p_memsz as usize,
+ )
+ }
+ }
+}
+
+// The note type for build IDs.
+const NT_GNU_BUILD_ID: u32 = 3;
+
+// Elf_Nhdr represents an ELF note header in the endianness of the target.
+#[allow(non_camel_case_types)]
+#[repr(C)]
+struct Elf_Nhdr {
+ n_namesz: u32,
+ n_descsz: u32,
+ n_type: u32,
+}
+
+// Note represents an ELF note (header + contents). The name is left as a u8
+// slice because it is not always null terminated and rust makes it easy enough
+// to check that the bytes match eitherway.
+struct Note<'a> {
+ name: &'a [u8],
+ desc: &'a [u8],
+ tipe: u32,
+}
+
+// NoteIter lets you safely iterate over a note segment. It terminates as soon
+// as an error occurs or there are no more notes. If you iterate over invalid
+// data it will function as though no notes were found.
+struct NoteIter<'a> {
+ base: &'a [u8],
+ error: bool,
+}
+
+impl<'a> NoteIter<'a> {
+ // It is an invariant of function that the pointer and size given denote a
+ // valid range of bytes that can all be read. The contents of these bytes
+ // can be anything but the range must be valid for this to be safe.
+ unsafe fn new(base: *const u8, size: usize) -> Self {
+ NoteIter {
+ base: from_raw_parts(base, size),
+ error: false,
+ }
+ }
+}
+
+// align_to aligns 'x' to 'to'-byte alignment assuming 'to' is a power of 2.
+// This follows a standard pattern in C/C++ ELF parsing code where
+// (x + to - 1) & -to is used. Rust does not let you negate usize so I use
+// 2's-complement conversion to recreate that.
+fn align_to(x: usize, to: usize) -> usize {
+ (x + to - 1) & (!to + 1)
+}
+
+// take_bytes_align4 consumes num bytes from the slice (if present) and
+// additionally ensures that the final slice is properlly aligned. If an
+// either the number of bytes requested is too large or the slice can't be
+// realigned afterwards due to not enough remaining bytes existing, None is
+// returned and the slice is not modified.
+fn take_bytes_align4<'a>(num: usize, bytes: &mut &'a [u8]) -> Option<&'a [u8]> {
+ if bytes.len() < align_to(num, 4) {
+ return None;
+ }
+ let (out, bytes_new) = bytes.split_at(num);
+ *bytes = &bytes_new[align_to(num, 4) - num..];
+ Some(out)
+}
+
+// This function has no real invariants the caller must uphold other than
+// perhaps that 'bytes' should be aligned for performance (and on some
+// architectures correctness). The values in the Elf_Nhdr fields might
+// be nonsense but this function ensures no such thing.
+fn take_nhdr<'a>(bytes: &mut &'a [u8]) -> Option<&'a Elf_Nhdr> {
+ if size_of::<Elf_Nhdr>() > bytes.len() {
+ return None;
+ }
+ // This is safe as long as there is enough space and we just confirmed that
+ // in the if statement above so this should not be unsafe.
+ let out = unsafe { transmute::<*const u8, &'a Elf_Nhdr>(bytes.as_ptr()) };
+ // Note that sice_of::<Elf_Nhdr>() is always 4-byte aligned.
+ *bytes = &bytes[size_of::<Elf_Nhdr>()..];
+ Some(out)
+}
+
+impl<'a> Iterator for NoteIter<'a> {
+ type Item = Note<'a>;
+ fn next(&mut self) -> Option<Self::Item> {
+ // Check if we've reached the end.
+ if self.base.len() == 0 || self.error {
+ return None;
+ }
+ // We transmute out an nhdr but we carefully consider the resulting
+ // struct. We don't trust the namesz or descsz and we make no unsafe
+ // decisions based on the type. So even if we get out complete garbage
+ // we should still be safe.
+ let nhdr = take_nhdr(&mut self.base)?;
+ let name = take_bytes_align4(nhdr.n_namesz as usize, &mut self.base)?;
+ let desc = take_bytes_align4(nhdr.n_descsz as usize, &mut self.base)?;
+ Some(Note {
+ name: name,
+ desc: desc,
+ tipe: nhdr.n_type,
+ })
+ }
+}
+
+struct Perm(u32);
+
+/// Indicates that a segment is executable.
+const PERM_X: u32 = 0b00000001;
+/// Indicates that a segment is writable.
+const PERM_W: u32 = 0b00000010;
+/// Indicates that a segment is readable.
+const PERM_R: u32 = 0b00000100;
+
+impl core::fmt::Display for Perm {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let v = self.0;
+ if v & PERM_R != 0 {
+ f.write_char('r')?
+ }
+ if v & PERM_W != 0 {
+ f.write_char('w')?
+ }
+ if v & PERM_X != 0 {
+ f.write_char('x')?
+ }
+ Ok(())
+ }
+}
+
+/// Represents an ELF segment at runtime.
+struct Segment {
+ /// Gives the runtime virtual address of this segment's contents.
+ addr: usize,
+ /// Gives the memory size of this segment's contents.
+ size: usize,
+ /// Gives the module virtual address of this segment with the ELF file.
+ mod_rel_addr: usize,
+ /// Gives the permissions found in the ELF file. These permissions are not
+ /// necessarily the permissions present at runtime however.
+ flags: Perm,
+}
+
+/// Lets one iterate over Segments from a DSO.
+struct SegmentIter<'a> {
+ phdrs: &'a [Elf_Phdr],
+ base: usize,
+}
+
+impl Iterator for SegmentIter<'_> {
+ type Item = Segment;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.phdrs.split_first().and_then(|(phdr, new_phdrs)| {
+ self.phdrs = new_phdrs;
+ if phdr.p_type != PT_LOAD {
+ self.next()
+ } else {
+ Some(Segment {
+ addr: phdr.p_vaddr as usize + self.base,
+ size: phdr.p_memsz as usize,
+ mod_rel_addr: phdr.p_vaddr as usize,
+ flags: Perm(phdr.p_flags),
+ })
+ }
+ })
+ }
+}
+
+/// Represents an ELF DSO (Dynamic Shared Object). This type references
+/// the data stored in the actual DSO rather than making its own copy.
+struct Dso<'a> {
+ /// The dynamic linker always gives us a name, even if the name is empty.
+ /// In the case of the main executable this name will be empty. In the case
+ /// of a shared object it will be the soname (see DT_SONAME).
+ name: &'a str,
+ /// On Fuchsia virtually all binaries have build IDs but this is not a strict
+ /// requirement. There's no way to match up DSO information with a real ELF
+ /// file afterwards if there is no build_id so we require that every DSO
+ /// have one here. DSO's without a build_id are ignored.
+ build_id: &'a [u8],
+
+ base: usize,
+ phdrs: &'a [Elf_Phdr],
+}
+
+impl Dso<'_> {
+ /// Returns an iterator over Segments in this DSO.
+ fn segments(&self) -> SegmentIter<'_> {
+ SegmentIter {
+ phdrs: self.phdrs.as_ref(),
+ base: self.base,
+ }
+ }
+}
+
+struct HexSlice<'a> {
+ bytes: &'a [u8],
+}
+
+impl fmt::Display for HexSlice<'_> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ for byte in self.bytes {
+ write!(f, "{:02x}", byte)?;
+ }
+ Ok(())
+ }
+}
+
+fn get_build_id<'a>(info: &'a dl_phdr_info) -> Option<&'a [u8]> {
+ for phdr in info.program_headers() {
+ if phdr.phdr.p_type == PT_NOTE {
+ for note in phdr.notes() {
+ if note.tipe == NT_GNU_BUILD_ID && (note.name == b"GNU\0" || note.name == b"GNU") {
+ return Some(note.desc);
+ }
+ }
+ }
+ }
+ None
+}
+
+/// These errors encode issues that arise while parsing information about
+/// each DSO.
+enum Error {
+ /// NameError means that an error occurred while converting a C style string
+ /// into a rust string.
+ NameError(core::str::Utf8Error),
+ /// BuildIDError means that we didn't find a build ID. This could either be
+ /// because the DSO had no build ID or because the segment containing the
+ /// build ID was malformed.
+ BuildIDError,
+}
+
+/// Calls either 'dso' or 'error' for each DSO linked into the process by the
+/// dynamic linker.
+///
+/// # Arguments
+///
+/// * `visitor` - A DsoPrinter that will have one of eats methods called foreach DSO.
+fn for_each_dso(mut visitor: &mut DsoPrinter<'_, '_>) {
+ extern "C" fn callback(
+ info: &dl_phdr_info,
+ _size: usize,
+ visitor: &mut DsoPrinter<'_, '_>,
+ ) -> i32 {
+ // dl_iterate_phdr ensures that info.name will point to a valid
+ // location.
+ let name_len = unsafe { libc::strlen(info.name) };
+ let name_slice: &[u8] =
+ unsafe { core::slice::from_raw_parts(info.name as *const u8, name_len) };
+ let name = match core::str::from_utf8(name_slice) {
+ Ok(name) => name,
+ Err(err) => {
+ return visitor.error(Error::NameError(err)) as i32;
+ }
+ };
+ let build_id = match get_build_id(info) {
+ Some(build_id) => build_id,
+ None => {
+ return visitor.error(Error::BuildIDError) as i32;
+ }
+ };
+ visitor.dso(Dso {
+ name: name,
+ build_id: build_id,
+ phdrs: info.phdr_slice(),
+ base: info.addr as usize,
+ }) as i32
+ }
+ unsafe { dl_iterate_phdr(callback, &mut visitor) };
+}
+
+struct DsoPrinter<'a, 'b> {
+ writer: &'a mut core::fmt::Formatter<'b>,
+ module_count: usize,
+ error: core::fmt::Result,
+}
+
+impl DsoPrinter<'_, '_> {
+ fn dso(&mut self, dso: Dso<'_>) -> bool {
+ let mut write = || {
+ write!(
+ self.writer,
+ "{{{{{{module:{:#x}:{}:elf:{}}}}}}}\n",
+ self.module_count,
+ dso.name,
+ HexSlice {
+ bytes: dso.build_id.as_ref()
+ }
+ )?;
+ for seg in dso.segments() {
+ write!(
+ self.writer,
+ "{{{{{{mmap:{:#x}:{:#x}:load:{:#x}:{}:{:#x}}}}}}}\n",
+ seg.addr, seg.size, self.module_count, seg.flags, seg.mod_rel_addr
+ )?;
+ }
+ self.module_count += 1;
+ Ok(())
+ };
+ match write() {
+ Ok(()) => false,
+ Err(err) => {
+ self.error = Err(err);
+ true
+ }
+ }
+ }
+ fn error(&mut self, _error: Error) -> bool {
+ false
+ }
+}
+
+/// This function prints the Fuchsia symbolizer markup for all information contained in a DSO.
+pub fn print_dso_context(out: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ out.write_str("{{{reset}}}\n")?;
+ let mut visitor = DsoPrinter {
+ writer: out,
+ module_count: 0,
+ error: Ok(()),
+ };
+ for_each_dso(&mut visitor);
+ visitor.error
+}
diff --git a/vendor/backtrace/src/symbolize/dbghelp.rs b/vendor/backtrace/src/symbolize/dbghelp.rs
new file mode 100644
index 000000000..181dba731
--- /dev/null
+++ b/vendor/backtrace/src/symbolize/dbghelp.rs
@@ -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() {}
diff --git a/vendor/backtrace/src/symbolize/gimli.rs b/vendor/backtrace/src/symbolize/gimli.rs
new file mode 100644
index 000000000..5f10122dd
--- /dev/null
+++ b/vendor/backtrace/src/symbolize/gimli.rs
@@ -0,0 +1,462 @@
+//! 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>,
+}
+
+impl<'data> Context<'data> {
+ fn new(
+ stash: &'data Stash,
+ object: Object<'data>,
+ sup: 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()?;
+
+ Some(Context { dwarf, object })
+ }
+}
+
+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::Object;
+ } else if #[cfg(any(
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "tvos",
+ target_os = "watchos",
+ ))] {
+ mod macho;
+ use self::macho::Object;
+ } else {
+ mod elf;
+ use self::elf::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",
+ all(target_os = "android", feature = "dl_iterate_phdr"),
+ ),
+ not(target_env = "uclibc"),
+ ))] {
+ mod libs_dl_iterate_phdr;
+ use libs_dl_iterate_phdr::native_libraries;
+ } 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>> {
+ 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 cx: &'a mut Context<'static> = &mut self.mappings[0].1.cx;
+ // 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) })
+ }
+}
+
+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 = match cache.mapping_for_lib(lib) {
+ Some(cx) => cx,
+ None => return,
+ };
+ let mut any_frames = false;
+ if let Ok(mut frames) = cx.dwarf.find_frames(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.dwarf.find_frames(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,
+ }
+ }
+}
diff --git a/vendor/backtrace/src/symbolize/gimli/coff.rs b/vendor/backtrace/src/symbolize/gimli/coff.rs
new file mode 100644
index 000000000..84d334207
--- /dev/null
+++ b/vendor/backtrace/src/symbolize/gimli/coff.rs
@@ -0,0 +1,108 @@
+use super::{Context, Mapping, Path, Stash, Vec};
+use core::convert::TryFrom;
+use object::pe::{ImageDosHeader, ImageSymbol};
+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)
+ })
+ }
+}
+
+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
+ }
+}
diff --git a/vendor/backtrace/src/symbolize/gimli/elf.rs b/vendor/backtrace/src/symbolize/gimli/elf.rs
new file mode 100644
index 000000000..bc71ee2c9
--- /dev/null
+++ b/vendor/backtrace/src/symbolize/gimli/elf.rs
@@ -0,0 +1,423 @@
+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::{Context, Mapping, Stash, Vec};
+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_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_debug, Some(crc)) {
+ return Some(Either::A(mapping));
+ }
+ }
+
+ Context::new(stash, object, None).map(Either::B)
+ })
+ }
+
+ /// Load debuginfo from an external debug file.
+ fn new_debug(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.
+ 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.set_mmap_aux(map_sup);
+ if let Some(sup) = Object::parse(map_sup) {
+ if sup.build_id() == Some(build_id_sup) {
+ return Context::new(stash, object, Some(sup));
+ }
+ }
+ }
+ }
+
+ Context::new(stash, object, 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)
+}
diff --git a/vendor/backtrace/src/symbolize/gimli/libs_dl_iterate_phdr.rs b/vendor/backtrace/src/symbolize/gimli/libs_dl_iterate_phdr.rs
new file mode 100644
index 000000000..a011e6080
--- /dev/null
+++ b/vendor/backtrace/src/symbolize/gimli/libs_dl_iterate_phdr.rs
@@ -0,0 +1,53 @@
+// 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;
+}
+
+// `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 {
+ if libs.is_empty() {
+ env::current_exe().map(|e| e.into()).unwrap_or_default()
+ } 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
+}
diff --git a/vendor/backtrace/src/symbolize/gimli/libs_haiku.rs b/vendor/backtrace/src/symbolize/gimli/libs_haiku.rs
new file mode 100644
index 000000000..87e023e69
--- /dev/null
+++ b/vendor/backtrace/src/symbolize/gimli/libs_haiku.rs
@@ -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
+}
diff --git a/vendor/backtrace/src/symbolize/gimli/libs_illumos.rs b/vendor/backtrace/src/symbolize/gimli/libs_illumos.rs
new file mode 100644
index 000000000..e64975e0c
--- /dev/null
+++ b/vendor/backtrace/src/symbolize/gimli/libs_illumos.rs
@@ -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
+}
diff --git a/vendor/backtrace/src/symbolize/gimli/libs_libnx.rs b/vendor/backtrace/src/symbolize/gimli/libs_libnx.rs
new file mode 100644
index 000000000..93b5ba17e
--- /dev/null
+++ b/vendor/backtrace/src/symbolize/gimli/libs_libnx.rs
@@ -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
+}
diff --git a/vendor/backtrace/src/symbolize/gimli/libs_macos.rs b/vendor/backtrace/src/symbolize/gimli/libs_macos.rs
new file mode 100644
index 000000000..17703b88a
--- /dev/null
+++ b/vendor/backtrace/src/symbolize/gimli/libs_macos.rs
@@ -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 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,
+ })
+}
diff --git a/vendor/backtrace/src/symbolize/gimli/libs_windows.rs b/vendor/backtrace/src/symbolize/gimli/libs_windows.rs
new file mode 100644
index 000000000..b47ed4245
--- /dev/null
+++ b/vendor/backtrace/src/symbolize/gimli/libs_windows.rs
@@ -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,
+ }],
+ })
+}
diff --git a/vendor/backtrace/src/symbolize/gimli/macho.rs b/vendor/backtrace/src/symbolize/gimli/macho.rs
new file mode 100644
index 000000000..ec5673843
--- /dev/null
+++ b/vendor/backtrace/src/symbolize/gimli/macho.rs
@@ -0,0 +1,324 @@
+use super::{Box, Context, Mapping, Path, Stash, Vec};
+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 OSX is is so different we just have a completely
+ // different implementation of the function here. On OSX 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)
+ })
+ }
+
+ 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)
+ });
+ 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)
+ })
+}
+
+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..]))
+}
diff --git a/vendor/backtrace/src/symbolize/gimli/mmap_fake.rs b/vendor/backtrace/src/symbolize/gimli/mmap_fake.rs
new file mode 100644
index 000000000..ce5096415
--- /dev/null
+++ b/vendor/backtrace/src/symbolize/gimli/mmap_fake.rs
@@ -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[..]
+ }
+}
diff --git a/vendor/backtrace/src/symbolize/gimli/mmap_unix.rs b/vendor/backtrace/src/symbolize/gimli/mmap_unix.rs
new file mode 100644
index 000000000..5806c9f7e
--- /dev/null
+++ b/vendor/backtrace/src/symbolize/gimli/mmap_unix.rs
@@ -0,0 +1,44 @@
+use super::mystd::fs::File;
+use super::mystd::os::unix::prelude::*;
+use core::ops::Deref;
+use core::ptr;
+use core::slice;
+
+pub struct Mmap {
+ ptr: *mut libc::c_void,
+ len: usize,
+}
+
+impl Mmap {
+ pub unsafe fn map(file: &File, len: usize) -> Option<Mmap> {
+ let ptr = libc::mmap(
+ 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);
+ }
+ }
+}
diff --git a/vendor/backtrace/src/symbolize/gimli/mmap_windows.rs b/vendor/backtrace/src/symbolize/gimli/mmap_windows.rs
new file mode 100644
index 000000000..22f53fe03
--- /dev/null
+++ b/vendor/backtrace/src/symbolize/gimli/mmap_windows.rs
@@ -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 ebeing 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);
+ }
+ }
+}
diff --git a/vendor/backtrace/src/symbolize/gimli/stash.rs b/vendor/backtrace/src/symbolize/gimli/stash.rs
new file mode 100644
index 000000000..3adfc598a
--- /dev/null
+++ b/vendor/backtrace/src/symbolize/gimli/stash.rs
@@ -0,0 +1,52 @@
+// 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>>>,
+ mmap_aux: UnsafeCell<Option<Mmap>>,
+}
+
+impl Stash {
+ pub fn new() -> Stash {
+ Stash {
+ buffers: UnsafeCell::new(Vec::new()),
+ mmap_aux: UnsafeCell::new(None),
+ }
+ }
+
+ /// 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 set_mmap_aux(&self, map: Mmap) -> &[u8] {
+ // SAFETY: this is the only location for a mutable pointer to
+ // `mmap_aux`, and this structure isn't threadsafe to shared across
+ // threads either. This also is careful to store at most one `mmap_aux`
+ // since overwriting a previous one would invalidate the previous
+ // pointer. Given that though we can safely return a pointer to our
+ // interior-owned contents.
+ unsafe {
+ let mmap_aux = &mut *self.mmap_aux.get();
+ assert!(mmap_aux.is_none());
+ *mmap_aux = Some(map);
+ mmap_aux.as_ref().unwrap()
+ }
+ }
+}
diff --git a/vendor/backtrace/src/symbolize/miri.rs b/vendor/backtrace/src/symbolize/miri.rs
new file mode 100644
index 000000000..5b0dc3084
--- /dev/null
+++ b/vendor/backtrace/src/symbolize/miri.rs
@@ -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() {}
diff --git a/vendor/backtrace/src/symbolize/mod.rs b/vendor/backtrace/src/symbolize/mod.rs
new file mode 100644
index 000000000..dbc346522
--- /dev/null
+++ b/vendor/backtrace/src/symbolize/mod.rs
@@ -0,0 +1,485 @@
+use core::{fmt, str};
+
+cfg_if::cfg_if! {
+ if #[cfg(feature = "std")] {
+ use std::path::Path;
+ use std::prelude::v1::*;
+ }
+}
+
+use super::backtrace::Frame;
+use super::types::BytesOrWideString;
+use core::ffi::c_void;
+use rustc_demangle::{try_demangle, Demangle};
+
+/// Resolve an address to a symbol, passing the symbol to the specified
+/// closure.
+///
+/// This function will look up the given address in areas such as the local
+/// symbol table, dynamic symbol table, or DWARF debug info (depending on the
+/// activated implementation) to find symbols to yield.
+///
+/// The closure may not be called if resolution could not be performed, and it
+/// also may be called more than once in the case of inlined functions.
+///
+/// Symbols yielded represent the execution at the specified `addr`, returning
+/// file/line pairs for that address (if available).
+///
+/// Note that if you have a `Frame` then it's recommended to use the
+/// `resolve_frame` function instead of this one.
+///
+/// # Required features
+///
+/// This function requires the `std` feature of the `backtrace` crate to be
+/// enabled, and the `std` feature is enabled by default.
+///
+/// # Panics
+///
+/// This function strives to never panic, but if the `cb` provided panics then
+/// some platforms will force a double panic to abort the process. Some
+/// platforms use a C library which internally uses callbacks which cannot be
+/// unwound through, so panicking from `cb` may trigger a process abort.
+///
+/// # Example
+///
+/// ```
+/// extern crate backtrace;
+///
+/// fn main() {
+/// backtrace::trace(|frame| {
+/// let ip = frame.ip();
+///
+/// backtrace::resolve(ip, |symbol| {
+/// // ...
+/// });
+///
+/// false // only look at the top frame
+/// });
+/// }
+/// ```
+#[cfg(feature = "std")]
+pub fn resolve<F: FnMut(&Symbol)>(addr: *mut c_void, cb: F) {
+ let _guard = crate::lock::lock();
+ unsafe { resolve_unsynchronized(addr, cb) }
+}
+
+/// Resolve a previously capture frame to a symbol, passing the symbol to the
+/// specified closure.
+///
+/// This function performs the same function as `resolve` except that it takes a
+/// `Frame` as an argument instead of an address. This can allow some platform
+/// implementations of backtracing to provide more accurate symbol information
+/// or information about inline frames for example. It's recommended to use this
+/// if you can.
+///
+/// # Required features
+///
+/// This function requires the `std` feature of the `backtrace` crate to be
+/// enabled, and the `std` feature is enabled by default.
+///
+/// # Panics
+///
+/// This function strives to never panic, but if the `cb` provided panics then
+/// some platforms will force a double panic to abort the process. Some
+/// platforms use a C library which internally uses callbacks which cannot be
+/// unwound through, so panicking from `cb` may trigger a process abort.
+///
+/// # Example
+///
+/// ```
+/// extern crate backtrace;
+///
+/// fn main() {
+/// backtrace::trace(|frame| {
+/// backtrace::resolve_frame(frame, |symbol| {
+/// // ...
+/// });
+///
+/// false // only look at the top frame
+/// });
+/// }
+/// ```
+#[cfg(feature = "std")]
+pub fn resolve_frame<F: FnMut(&Symbol)>(frame: &Frame, cb: F) {
+ let _guard = crate::lock::lock();
+ unsafe { resolve_frame_unsynchronized(frame, cb) }
+}
+
+pub enum ResolveWhat<'a> {
+ Address(*mut c_void),
+ Frame(&'a Frame),
+}
+
+impl<'a> ResolveWhat<'a> {
+ #[allow(dead_code)]
+ fn address_or_ip(&self) -> *mut c_void {
+ match self {
+ ResolveWhat::Address(a) => adjust_ip(*a),
+ ResolveWhat::Frame(f) => adjust_ip(f.ip()),
+ }
+ }
+}
+
+// IP values from stack frames are typically (always?) the instruction
+// *after* the call that's the actual stack trace. Symbolizing this on
+// causes the filename/line number to be one ahead and perhaps into
+// the void if it's near the end of the function.
+//
+// This appears to basically always be the case on all platforms, so we always
+// subtract one from a resolved ip to resolve it to the previous call
+// instruction instead of the instruction being returned to.
+//
+// Ideally we would not do this. Ideally we would require callers of the
+// `resolve` APIs here to manually do the -1 and account that they want location
+// information for the *previous* instruction, not the current. Ideally we'd
+// also expose on `Frame` if we are indeed the address of the next instruction
+// or the current.
+//
+// For now though this is a pretty niche concern so we just internally always
+// subtract one. Consumers should keep working and getting pretty good results,
+// so we should be good enough.
+fn adjust_ip(a: *mut c_void) -> *mut c_void {
+ if a.is_null() {
+ a
+ } else {
+ (a as usize - 1) as *mut c_void
+ }
+}
+
+/// Same as `resolve`, only unsafe as it's unsynchronized.
+///
+/// This function does not have synchronization guarantees but is available when
+/// the `std` feature of this crate isn't compiled in. See the `resolve`
+/// function for more documentation and examples.
+///
+/// # Panics
+///
+/// See information on `resolve` for caveats on `cb` panicking.
+pub unsafe fn resolve_unsynchronized<F>(addr: *mut c_void, mut cb: F)
+where
+ F: FnMut(&Symbol),
+{
+ imp::resolve(ResolveWhat::Address(addr), &mut cb)
+}
+
+/// Same as `resolve_frame`, only unsafe as it's unsynchronized.
+///
+/// This function does not have synchronization guarantees but is available
+/// when the `std` feature of this crate isn't compiled in. See the
+/// `resolve_frame` function for more documentation and examples.
+///
+/// # Panics
+///
+/// See information on `resolve_frame` for caveats on `cb` panicking.
+pub unsafe fn resolve_frame_unsynchronized<F>(frame: &Frame, mut cb: F)
+where
+ F: FnMut(&Symbol),
+{
+ imp::resolve(ResolveWhat::Frame(frame), &mut cb)
+}
+
+/// A trait representing the resolution of a symbol in a file.
+///
+/// This trait is yielded as a trait object to the closure given to the
+/// `backtrace::resolve` function, and it is virtually dispatched as it's
+/// unknown which implementation is behind it.
+///
+/// A symbol can give contextual information about a function, for example the
+/// name, filename, line number, precise address, etc. Not all information is
+/// always available in a symbol, however, so all methods return an `Option`.
+pub struct Symbol {
+ // TODO: this lifetime bound needs to be persisted eventually to `Symbol`,
+ // but that's currently a breaking change. For now this is safe since
+ // `Symbol` is only ever handed out by reference and can't be cloned.
+ inner: imp::Symbol<'static>,
+}
+
+impl Symbol {
+ /// Returns the name of this function.
+ ///
+ /// The returned structure can be used to query various properties about the
+ /// symbol name:
+ ///
+ /// * The `Display` implementation will print out the demangled symbol.
+ /// * The raw `str` value of the symbol can be accessed (if it's valid
+ /// utf-8).
+ /// * The raw bytes for the symbol name can be accessed.
+ pub fn name(&self) -> Option<SymbolName<'_>> {
+ self.inner.name()
+ }
+
+ /// Returns the starting address of this function.
+ pub fn addr(&self) -> Option<*mut c_void> {
+ self.inner.addr().map(|p| p as *mut _)
+ }
+
+ /// Returns the raw filename as a slice. This is mainly useful for `no_std`
+ /// environments.
+ pub fn filename_raw(&self) -> Option<BytesOrWideString<'_>> {
+ self.inner.filename_raw()
+ }
+
+ /// Returns the column number for where this symbol is currently executing.
+ ///
+ /// Only gimli currently provides a value here and even then only if `filename`
+ /// returns `Some`, and so it is then consequently subject to similar caveats.
+ pub fn colno(&self) -> Option<u32> {
+ self.inner.colno()
+ }
+
+ /// Returns the line number for where this symbol is currently executing.
+ ///
+ /// This return value is typically `Some` if `filename` returns `Some`, and
+ /// is consequently subject to similar caveats.
+ pub fn lineno(&self) -> Option<u32> {
+ self.inner.lineno()
+ }
+
+ /// Returns the file name where this function was defined.
+ ///
+ /// This is currently only available when libbacktrace or gimli is being
+ /// used (e.g. unix platforms other) and when a binary is compiled with
+ /// debuginfo. If neither of these conditions is met then this will likely
+ /// return `None`.
+ ///
+ /// # Required features
+ ///
+ /// This function requires the `std` feature of the `backtrace` crate to be
+ /// enabled, and the `std` feature is enabled by default.
+ #[cfg(feature = "std")]
+ #[allow(unreachable_code)]
+ pub fn filename(&self) -> Option<&Path> {
+ self.inner.filename()
+ }
+}
+
+impl fmt::Debug for Symbol {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut d = f.debug_struct("Symbol");
+ if let Some(name) = self.name() {
+ d.field("name", &name);
+ }
+ if let Some(addr) = self.addr() {
+ d.field("addr", &addr);
+ }
+
+ #[cfg(feature = "std")]
+ {
+ if let Some(filename) = self.filename() {
+ d.field("filename", &filename);
+ }
+ }
+
+ if let Some(lineno) = self.lineno() {
+ d.field("lineno", &lineno);
+ }
+ d.finish()
+ }
+}
+
+cfg_if::cfg_if! {
+ if #[cfg(feature = "cpp_demangle")] {
+ // Maybe a parsed C++ symbol, if parsing the mangled symbol as Rust
+ // failed.
+ struct OptionCppSymbol<'a>(Option<::cpp_demangle::BorrowedSymbol<'a>>);
+
+ impl<'a> OptionCppSymbol<'a> {
+ fn parse(input: &'a [u8]) -> OptionCppSymbol<'a> {
+ OptionCppSymbol(::cpp_demangle::BorrowedSymbol::new(input).ok())
+ }
+
+ fn none() -> OptionCppSymbol<'a> {
+ OptionCppSymbol(None)
+ }
+ }
+ } else {
+ use core::marker::PhantomData;
+
+ // Make sure to keep this zero-sized, so that the `cpp_demangle` feature
+ // has no cost when disabled.
+ struct OptionCppSymbol<'a>(PhantomData<&'a ()>);
+
+ impl<'a> OptionCppSymbol<'a> {
+ fn parse(_: &'a [u8]) -> OptionCppSymbol<'a> {
+ OptionCppSymbol(PhantomData)
+ }
+
+ fn none() -> OptionCppSymbol<'a> {
+ OptionCppSymbol(PhantomData)
+ }
+ }
+ }
+}
+
+/// A wrapper around a symbol name to provide ergonomic accessors to the
+/// demangled name, the raw bytes, the raw string, etc.
+// Allow dead code for when the `cpp_demangle` feature is not enabled.
+#[allow(dead_code)]
+pub struct SymbolName<'a> {
+ bytes: &'a [u8],
+ demangled: Option<Demangle<'a>>,
+ cpp_demangled: OptionCppSymbol<'a>,
+}
+
+impl<'a> SymbolName<'a> {
+ /// Creates a new symbol name from the raw underlying bytes.
+ pub fn new(bytes: &'a [u8]) -> SymbolName<'a> {
+ let str_bytes = str::from_utf8(bytes).ok();
+ let demangled = str_bytes.and_then(|s| try_demangle(s).ok());
+
+ let cpp = if demangled.is_none() {
+ OptionCppSymbol::parse(bytes)
+ } else {
+ OptionCppSymbol::none()
+ };
+
+ SymbolName {
+ bytes: bytes,
+ demangled: demangled,
+ cpp_demangled: cpp,
+ }
+ }
+
+ /// Returns the raw (mangled) symbol name as a `str` if the symbol is valid utf-8.
+ ///
+ /// Use the `Display` implementation if you want the demangled version.
+ pub fn as_str(&self) -> Option<&'a str> {
+ self.demangled
+ .as_ref()
+ .map(|s| s.as_str())
+ .or_else(|| str::from_utf8(self.bytes).ok())
+ }
+
+ /// Returns the raw symbol name as a list of bytes
+ pub fn as_bytes(&self) -> &'a [u8] {
+ self.bytes
+ }
+}
+
+fn format_symbol_name(
+ fmt: fn(&str, &mut fmt::Formatter<'_>) -> fmt::Result,
+ mut bytes: &[u8],
+ f: &mut fmt::Formatter<'_>,
+) -> fmt::Result {
+ while bytes.len() > 0 {
+ match str::from_utf8(bytes) {
+ Ok(name) => {
+ fmt(name, f)?;
+ break;
+ }
+ Err(err) => {
+ fmt("\u{FFFD}", f)?;
+
+ match err.error_len() {
+ Some(len) => bytes = &bytes[err.valid_up_to() + len..],
+ None => break,
+ }
+ }
+ }
+ }
+ Ok(())
+}
+
+cfg_if::cfg_if! {
+ if #[cfg(feature = "cpp_demangle")] {
+ impl<'a> fmt::Display for SymbolName<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ if let Some(ref s) = self.demangled {
+ s.fmt(f)
+ } else if let Some(ref cpp) = self.cpp_demangled.0 {
+ cpp.fmt(f)
+ } else {
+ format_symbol_name(fmt::Display::fmt, self.bytes, f)
+ }
+ }
+ }
+ } else {
+ impl<'a> fmt::Display for SymbolName<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ if let Some(ref s) = self.demangled {
+ s.fmt(f)
+ } else {
+ format_symbol_name(fmt::Display::fmt, self.bytes, f)
+ }
+ }
+ }
+ }
+}
+
+cfg_if::cfg_if! {
+ if #[cfg(all(feature = "std", feature = "cpp_demangle"))] {
+ impl<'a> fmt::Debug for SymbolName<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ use std::fmt::Write;
+
+ if let Some(ref s) = self.demangled {
+ return s.fmt(f)
+ }
+
+ // This may to print if the demangled symbol isn't actually
+ // valid, so handle the error here gracefully by not propagating
+ // it outwards.
+ if let Some(ref cpp) = self.cpp_demangled.0 {
+ let mut s = String::new();
+ if write!(s, "{}", cpp).is_ok() {
+ return s.fmt(f)
+ }
+ }
+
+ format_symbol_name(fmt::Debug::fmt, self.bytes, f)
+ }
+ }
+ } else {
+ impl<'a> fmt::Debug for SymbolName<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ if let Some(ref s) = self.demangled {
+ s.fmt(f)
+ } else {
+ format_symbol_name(fmt::Debug::fmt, self.bytes, f)
+ }
+ }
+ }
+ }
+}
+
+/// Attempt to reclaim that cached memory used to symbolicate addresses.
+///
+/// This method will attempt to release any global data structures that have
+/// otherwise been cached globally or in the thread which typically represent
+/// parsed DWARF information or similar.
+///
+/// # Caveats
+///
+/// While this function is always available it doesn't actually do anything on
+/// most implementations. Libraries like dbghelp or libbacktrace do not provide
+/// facilities to deallocate state and manage the allocated memory. For now the
+/// `gimli-symbolize` feature of this crate is the only feature where this
+/// function has any effect.
+#[cfg(feature = "std")]
+pub fn clear_symbol_cache() {
+ let _guard = crate::lock::lock();
+ unsafe {
+ imp::clear_symbol_cache();
+ }
+}
+
+cfg_if::cfg_if! {
+ if #[cfg(miri)] {
+ mod miri;
+ use miri as imp;
+ } else if #[cfg(all(windows, target_env = "msvc", not(target_vendor = "uwp")))] {
+ mod dbghelp;
+ use dbghelp as imp;
+ } else if #[cfg(all(
+ any(unix, windows),
+ not(target_vendor = "uwp"),
+ not(target_os = "emscripten"),
+ any(not(backtrace_in_libstd), feature = "backtrace"),
+ ))] {
+ mod gimli;
+ use gimli as imp;
+ } else {
+ mod noop;
+ use noop as imp;
+ }
+}
diff --git a/vendor/backtrace/src/symbolize/noop.rs b/vendor/backtrace/src/symbolize/noop.rs
new file mode 100644
index 000000000..c53336531
--- /dev/null
+++ b/vendor/backtrace/src/symbolize/noop.rs
@@ -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() {}
diff --git a/vendor/backtrace/src/types.rs b/vendor/backtrace/src/types.rs
new file mode 100644
index 000000000..c7e551059
--- /dev/null
+++ b/vendor/backtrace/src/types.rs
@@ -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)
+ }
+}
diff --git a/vendor/backtrace/src/windows.rs b/vendor/backtrace/src/windows.rs
new file mode 100644
index 000000000..d091874f1
--- /dev/null
+++ b/vendor/backtrace/src/windows.rs
@@ -0,0 +1,691 @@
+//! 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)*);
+ );
+
+ (extern "system" { $(pub fn $name:ident($($args:tt)*) -> $ret:ty;)* } $($rest:tt)*) => (
+ 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;
+ drop(x);
+ x = winapi::$name;
+ drop(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;
+
+ 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! {
+ 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)
diff --git a/vendor/backtrace/tests/accuracy/auxiliary.rs b/vendor/backtrace/tests/accuracy/auxiliary.rs
new file mode 100644
index 000000000..9c8015d9a
--- /dev/null
+++ b/vendor/backtrace/tests/accuracy/auxiliary.rs
@@ -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!()))
+}
diff --git a/vendor/backtrace/tests/accuracy/main.rs b/vendor/backtrace/tests/accuracy/main.rs
new file mode 100644
index 000000000..149203a1b
--- /dev/null
+++ b/vendor/backtrace/tests/accuracy/main.rs
@@ -0,0 +1,117 @@
+mod auxiliary;
+
+macro_rules! pos {
+ () => {
+ (file!(), line!())
+ };
+}
+
+macro_rules! check {
+ ($($pos:expr),*) => ({
+ verify(&[$($pos,)* pos!()]);
+ })
+}
+
+type Pos = (&'static str, u32);
+
+#[test]
+fn doit() {
+ if
+ // Skip musl which is by default statically linked and doesn't support
+ // dynamic libraries.
+ !cfg!(target_env = "musl")
+ // Skip Miri, since it doesn't support dynamic libraries.
+ && !cfg!(miri)
+ {
+ // TODO(#238) this shouldn't have to happen first in this function, but
+ // currently it does.
+ let mut dir = std::env::current_exe().unwrap();
+ dir.pop();
+ if cfg!(windows) {
+ dir.push("dylib_dep.dll");
+ } else if cfg!(target_os = "macos") {
+ dir.push("libdylib_dep.dylib");
+ } else {
+ dir.push("libdylib_dep.so");
+ }
+ unsafe {
+ let lib = libloading::Library::new(&dir).unwrap();
+ let api = lib.get::<extern "C" fn(Pos, fn(Pos, Pos))>(b"foo").unwrap();
+ api(pos!(), |a, b| {
+ check!(a, b);
+ });
+ }
+ }
+
+ outer(pos!());
+}
+
+#[inline(never)]
+fn outer(main_pos: Pos) {
+ inner(main_pos, pos!());
+ inner_inlined(main_pos, pos!());
+}
+
+#[inline(never)]
+#[rustfmt::skip]
+fn inner(main_pos: Pos, outer_pos: Pos) {
+ check!(main_pos, outer_pos);
+ check!(main_pos, outer_pos);
+ let inner_pos = pos!(); auxiliary::callback(|aux_pos| {
+ check!(main_pos, outer_pos, inner_pos, aux_pos);
+ });
+ let inner_pos = pos!(); auxiliary::callback_inlined(|aux_pos| {
+ check!(main_pos, outer_pos, inner_pos, aux_pos);
+ });
+}
+
+#[inline(always)]
+#[rustfmt::skip]
+fn inner_inlined(main_pos: Pos, outer_pos: Pos) {
+ check!(main_pos, outer_pos);
+ check!(main_pos, outer_pos);
+
+ #[inline(always)]
+ fn inner_further_inlined(main_pos: Pos, outer_pos: Pos, inner_pos: Pos) {
+ check!(main_pos, outer_pos, inner_pos);
+ }
+ inner_further_inlined(main_pos, outer_pos, pos!());
+
+ let inner_pos = pos!(); auxiliary::callback(|aux_pos| {
+ check!(main_pos, outer_pos, inner_pos, aux_pos);
+ });
+ let inner_pos = pos!(); auxiliary::callback_inlined(|aux_pos| {
+ check!(main_pos, outer_pos, inner_pos, aux_pos);
+ });
+
+ // this tests a distinction between two independent calls to the inlined function.
+ // (un)fortunately, LLVM somehow merges two consecutive such calls into one node.
+ inner_further_inlined(main_pos, outer_pos, pos!());
+}
+
+fn verify(filelines: &[Pos]) {
+ let trace = backtrace::Backtrace::new();
+ println!("-----------------------------------");
+ println!("looking for:");
+ for (file, line) in filelines.iter().rev() {
+ println!("\t{}:{}", file, line);
+ }
+ println!("found:\n{:?}", trace);
+ let mut symbols = trace.frames().iter().flat_map(|frame| frame.symbols());
+ let mut iter = filelines.iter().rev();
+ while let Some((file, line)) = iter.next() {
+ loop {
+ let sym = match symbols.next() {
+ Some(sym) => sym,
+ None => panic!("failed to find {}:{}", file, line),
+ };
+ if let Some(filename) = sym.filename() {
+ if let Some(lineno) = sym.lineno() {
+ if filename.ends_with(file) && lineno == *line {
+ break;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/vendor/backtrace/tests/concurrent-panics.rs b/vendor/backtrace/tests/concurrent-panics.rs
new file mode 100644
index 000000000..470245cc9
--- /dev/null
+++ b/vendor/backtrace/tests/concurrent-panics.rs
@@ -0,0 +1,78 @@
+use std::env;
+use std::panic;
+use std::process::Command;
+use std::sync::atomic::{AtomicBool, Ordering::SeqCst};
+use std::sync::Arc;
+use std::thread;
+
+const PANICS: usize = 100;
+const THREADS: usize = 8;
+const VAR: &str = "__THE_TEST_YOU_ARE_LUKE";
+
+fn main() {
+ // These run in docker containers on CI where they can't re-exec the test,
+ // so just skip these for CI. No other reason this can't run on those
+ // platforms though.
+ // Miri does not have support for re-execing a file
+ if cfg!(unix)
+ && (cfg!(target_arch = "arm")
+ || cfg!(target_arch = "aarch64")
+ || cfg!(target_arch = "s390x"))
+ || cfg!(miri)
+ {
+ println!("test result: ok");
+ return;
+ }
+
+ if env::var(VAR).is_err() {
+ parent();
+ } else {
+ child();
+ }
+}
+
+fn parent() {
+ let me = env::current_exe().unwrap();
+ let result = Command::new(&me)
+ .env("RUST_BACKTRACE", "1")
+ .env(VAR, "1")
+ .output()
+ .unwrap();
+ if result.status.success() {
+ println!("test result: ok");
+ return;
+ }
+ println!("stdout:\n{}", String::from_utf8_lossy(&result.stdout));
+ println!("stderr:\n{}", String::from_utf8_lossy(&result.stderr));
+ println!("code: {}", result.status);
+ panic!();
+}
+
+fn child() {
+ let done = Arc::new(AtomicBool::new(false));
+ let done2 = done.clone();
+ let a = thread::spawn(move || {
+ while !done2.load(SeqCst) {
+ format!("{:?}", backtrace::Backtrace::new());
+ }
+ });
+
+ let threads = (0..THREADS)
+ .map(|_| {
+ thread::spawn(|| {
+ for _ in 0..PANICS {
+ assert!(panic::catch_unwind(|| {
+ panic!();
+ })
+ .is_err());
+ }
+ })
+ })
+ .collect::<Vec<_>>();
+ for thread in threads {
+ thread.join().unwrap();
+ }
+
+ done.store(true, SeqCst);
+ a.join().unwrap();
+}
diff --git a/vendor/backtrace/tests/long_fn_name.rs b/vendor/backtrace/tests/long_fn_name.rs
new file mode 100644
index 000000000..fa4cfda15
--- /dev/null
+++ b/vendor/backtrace/tests/long_fn_name.rs
@@ -0,0 +1,48 @@
+use backtrace::Backtrace;
+
+// 50-character module name
+mod _234567890_234567890_234567890_234567890_234567890 {
+ // 50-character struct name
+ #[allow(non_camel_case_types)]
+ pub struct _234567890_234567890_234567890_234567890_234567890<T>(T);
+ impl<T> _234567890_234567890_234567890_234567890_234567890<T> {
+ #[allow(dead_code)]
+ pub fn new() -> crate::Backtrace {
+ crate::Backtrace::new()
+ }
+ }
+}
+
+// Long function names must be truncated to (MAX_SYM_NAME - 1) characters.
+// Only run this test for msvc, since gnu prints "<no info>" for all frames.
+#[test]
+#[cfg(all(windows, target_env = "msvc"))]
+fn test_long_fn_name() {
+ use _234567890_234567890_234567890_234567890_234567890::_234567890_234567890_234567890_234567890_234567890 as S;
+
+ // 10 repetitions of struct name, so fully qualified function name is
+ // atleast 10 * (50 + 50) * 2 = 2000 characters long.
+ // It's actually longer since it also includes `::`, `<>` and the
+ // name of the current module
+ let bt = S::<S<S<S<S<S<S<S<S<S<i32>>>>>>>>>>::new();
+ println!("{:?}", bt);
+
+ let mut found_long_name_frame = false;
+
+ for frame in bt.frames() {
+ let symbols = frame.symbols();
+ if symbols.is_empty() {
+ continue;
+ }
+
+ if let Some(function_name) = symbols[0].name() {
+ let function_name = function_name.as_str().unwrap();
+ if function_name.contains("::_234567890_234567890_234567890_234567890_234567890") {
+ found_long_name_frame = true;
+ assert!(function_name.len() > 200);
+ }
+ }
+ }
+
+ assert!(found_long_name_frame);
+}
diff --git a/vendor/backtrace/tests/skip_inner_frames.rs b/vendor/backtrace/tests/skip_inner_frames.rs
new file mode 100644
index 000000000..8b57bef52
--- /dev/null
+++ b/vendor/backtrace/tests/skip_inner_frames.rs
@@ -0,0 +1,44 @@
+use backtrace::Backtrace;
+
+// This test only works on platforms which have a working `symbol_address`
+// function for frames which reports the starting address of a symbol. As a
+// result it's only enabled on a few platforms.
+const ENABLED: bool = cfg!(all(
+ // Windows hasn't really been tested, and OSX doesn't support actually
+ // finding an enclosing frame, so disable this
+ target_os = "linux",
+ // On ARM finding the enclosing function is simply returning the ip itself.
+ not(target_arch = "arm"),
+));
+
+#[test]
+fn backtrace_new_unresolved_should_start_with_call_site_trace() {
+ if !ENABLED {
+ return;
+ }
+ let mut b = Backtrace::new_unresolved();
+ b.resolve();
+ println!("{:?}", b);
+
+ assert!(!b.frames().is_empty());
+
+ let this_ip = backtrace_new_unresolved_should_start_with_call_site_trace as usize;
+ println!("this_ip: {:?}", this_ip as *const usize);
+ let frame_ip = b.frames().first().unwrap().symbol_address() as usize;
+ assert_eq!(this_ip, frame_ip);
+}
+
+#[test]
+fn backtrace_new_should_start_with_call_site_trace() {
+ if !ENABLED {
+ return;
+ }
+ let b = Backtrace::new();
+ println!("{:?}", b);
+
+ assert!(!b.frames().is_empty());
+
+ let this_ip = backtrace_new_should_start_with_call_site_trace as usize;
+ let frame_ip = b.frames().first().unwrap().symbol_address() as usize;
+ assert_eq!(this_ip, frame_ip);
+}
diff --git a/vendor/backtrace/tests/smoke.rs b/vendor/backtrace/tests/smoke.rs
new file mode 100644
index 000000000..683a6f0db
--- /dev/null
+++ b/vendor/backtrace/tests/smoke.rs
@@ -0,0 +1,323 @@
+use backtrace::Frame;
+use std::thread;
+
+#[test]
+// FIXME: shouldn't ignore this test on i686-msvc, unsure why it's failing
+#[cfg_attr(all(target_arch = "x86", target_env = "msvc"), ignore)]
+#[rustfmt::skip] // we care about line numbers here
+fn smoke_test_frames() {
+ frame_1(line!());
+ #[inline(never)] fn frame_1(start_line: u32) { frame_2(start_line) }
+ #[inline(never)] fn frame_2(start_line: u32) { frame_3(start_line) }
+ #[inline(never)] fn frame_3(start_line: u32) { frame_4(start_line) }
+ #[inline(never)] fn frame_4(start_line: u32) {
+ let mut v = Vec::new();
+ backtrace::trace(|cx| {
+ v.push(cx.clone());
+ true
+ });
+
+ // Various platforms have various bits of weirdness about their
+ // backtraces. To find a good starting spot let's search through the
+ // frames
+ let target = frame_4 as usize;
+ let offset = v
+ .iter()
+ .map(|frame| frame.symbol_address() as usize)
+ .enumerate()
+ .filter_map(|(i, sym)| {
+ if sym >= target {
+ Some((sym, i))
+ } else {
+ None
+ }
+ })
+ .min()
+ .unwrap()
+ .1;
+ let mut frames = v[offset..].iter();
+
+ assert_frame(
+ frames.next().unwrap(),
+ frame_4 as usize,
+ "frame_4",
+ "tests/smoke.rs",
+ start_line + 6,
+ 9,
+ );
+ assert_frame(
+ frames.next().unwrap(),
+ frame_3 as usize,
+ "frame_3",
+ "tests/smoke.rs",
+ start_line + 3,
+ 52,
+ );
+ assert_frame(
+ frames.next().unwrap(),
+ frame_2 as usize,
+ "frame_2",
+ "tests/smoke.rs",
+ start_line + 2,
+ 52,
+ );
+ assert_frame(
+ frames.next().unwrap(),
+ frame_1 as usize,
+ "frame_1",
+ "tests/smoke.rs",
+ start_line + 1,
+ 52,
+ );
+ assert_frame(
+ frames.next().unwrap(),
+ smoke_test_frames as usize,
+ "smoke_test_frames",
+ "",
+ 0,
+ 0,
+ );
+ }
+
+ fn assert_frame(
+ frame: &Frame,
+ actual_fn_pointer: usize,
+ expected_name: &str,
+ expected_file: &str,
+ expected_line: u32,
+ expected_col: u32,
+ ) {
+ backtrace::resolve_frame(frame, |sym| {
+ print!("symbol ip:{:?} address:{:?} ", frame.ip(), frame.symbol_address());
+ if let Some(name) = sym.name() {
+ print!("name:{} ", name);
+ }
+ if let Some(file) = sym.filename() {
+ print!("file:{} ", file.display());
+ }
+ if let Some(lineno) = sym.lineno() {
+ print!("lineno:{} ", lineno);
+ }
+ if let Some(colno) = sym.colno() {
+ print!("colno:{} ", colno);
+ }
+ println!();
+ });
+
+ let ip = frame.ip() as usize;
+ let sym = frame.symbol_address() as usize;
+ assert!(ip >= sym);
+ assert!(
+ sym >= actual_fn_pointer,
+ "{:?} < {:?} ({} {}:{}:{})",
+ sym as *const usize,
+ actual_fn_pointer as *const usize,
+ expected_name,
+ expected_file,
+ expected_line,
+ expected_col,
+ );
+
+ // windows dbghelp is *quite* liberal (and wrong) in many of its reports
+ // right now...
+ //
+ // This assertion can also fail for release builds, so skip it there
+ if cfg!(debug_assertions) {
+ assert!(sym - actual_fn_pointer < 1024);
+ }
+
+ let mut resolved = 0;
+
+ let mut name = None;
+ let mut addr = None;
+ let mut col = None;
+ let mut line = None;
+ let mut file = None;
+ backtrace::resolve_frame(frame, |sym| {
+ resolved += 1;
+ name = sym.name().map(|v| v.to_string());
+ addr = sym.addr();
+ col = sym.colno();
+ line = sym.lineno();
+ file = sym.filename().map(|v| v.to_path_buf());
+ });
+ assert!(resolved > 0);
+
+ let name = name.expect("didn't find a name");
+
+ // in release mode names get weird as functions can get merged
+ // together with `mergefunc`, so only assert this in debug mode
+ if cfg!(debug_assertions) {
+ assert!(
+ name.contains(expected_name),
+ "didn't find `{}` in `{}`",
+ expected_name,
+ name
+ );
+ }
+
+ addr.expect("didn't find a symbol");
+
+ if cfg!(debug_assertions) {
+ let line = line.expect("didn't find a line number");
+ let file = file.expect("didn't find a line number");
+ if !expected_file.is_empty() {
+ assert!(
+ file.ends_with(expected_file),
+ "{:?} didn't end with {:?}",
+ file,
+ expected_file
+ );
+ }
+ if expected_line != 0 {
+ assert!(
+ line == expected_line,
+ "bad line number on frame for `{}`: {} != {}",
+ expected_name,
+ line,
+ expected_line
+ );
+ }
+
+ // dbghelp on MSVC doesn't support column numbers
+ if !cfg!(target_env = "msvc") {
+ let col = col.expect("didn't find a column number");
+ if expected_col != 0 {
+ assert!(
+ col == expected_col,
+ "bad column number on frame for `{}`: {} != {}",
+ expected_name,
+ col,
+ expected_col
+ );
+ }
+ }
+ }
+ }
+}
+
+#[test]
+fn many_threads() {
+ let threads = (0..16)
+ .map(|_| {
+ thread::spawn(|| {
+ for _ in 0..16 {
+ backtrace::trace(|frame| {
+ backtrace::resolve(frame.ip(), |symbol| {
+ let _s = symbol.name().map(|s| s.to_string());
+ });
+ true
+ });
+ }
+ })
+ })
+ .collect::<Vec<_>>();
+
+ for t in threads {
+ t.join().unwrap()
+ }
+}
+
+#[test]
+#[cfg(feature = "rustc-serialize")]
+fn is_rustc_serialize() {
+ extern crate rustc_serialize;
+
+ fn is_encode<T: rustc_serialize::Encodable>() {}
+ fn is_decode<T: rustc_serialize::Decodable>() {}
+
+ is_encode::<backtrace::Backtrace>();
+ is_decode::<backtrace::Backtrace>();
+}
+
+#[test]
+#[cfg(feature = "serde")]
+fn is_serde() {
+ extern crate serde;
+
+ fn is_serialize<T: serde::ser::Serialize>() {}
+ fn is_deserialize<T: serde::de::DeserializeOwned>() {}
+
+ is_serialize::<backtrace::Backtrace>();
+ is_deserialize::<backtrace::Backtrace>();
+}
+
+#[test]
+fn sp_smoke_test() {
+ let mut refs = vec![];
+ recursive_stack_references(&mut refs);
+ return;
+
+ #[inline(never)]
+ fn recursive_stack_references(refs: &mut Vec<usize>) {
+ assert!(refs.len() < 5);
+
+ let x = refs.len();
+ refs.push(&x as *const _ as usize);
+
+ if refs.len() < 5 {
+ recursive_stack_references(refs);
+ eprintln!("exiting: {}", x);
+ return;
+ }
+
+ backtrace::trace(make_trace_closure(refs));
+ eprintln!("exiting: {}", x);
+ }
+
+ // NB: the following `make_*` functions are pulled out of line, rather than
+ // defining their results as inline closures at their call sites, so that
+ // the resulting closures don't have "recursive_stack_references" in their
+ // mangled names.
+
+ fn make_trace_closure<'a>(
+ refs: &'a mut Vec<usize>,
+ ) -> impl FnMut(&backtrace::Frame) -> bool + 'a {
+ let mut child_sp = None;
+ let mut child_ref = None;
+ move |frame| {
+ eprintln!("\n=== frame ===================================");
+
+ let mut is_recursive_stack_references = false;
+ backtrace::resolve(frame.ip(), |sym| {
+ is_recursive_stack_references |=
+ sym.name()
+ .and_then(|name| name.as_str())
+ .map_or(false, |name| {
+ eprintln!("name = {}", name);
+ name.contains("recursive_stack_references")
+ })
+ });
+
+ let sp = frame.sp() as usize;
+ eprintln!("sp = {:p}", sp as *const u8);
+ if sp == 0 {
+ // If the SP is null, then we don't have an implementation for
+ // getting the SP on this target. Just keep walking the stack,
+ // but don't make our assertions about the on-stack pointers and
+ // SP values.
+ return true;
+ }
+
+ // The stack grows down.
+ if let Some(child_sp) = child_sp {
+ assert!(child_sp <= sp);
+ }
+
+ if is_recursive_stack_references {
+ let r = refs.pop().unwrap();
+ eprintln!("ref = {:p}", r as *const u8);
+ if sp != 0 {
+ assert!(r > sp);
+ if let Some(child_ref) = child_ref {
+ assert!(sp >= child_ref);
+ }
+ }
+ child_ref = Some(r);
+ }
+
+ child_sp = Some(sp);
+ true
+ }
+ }
+}