summaryrefslogtreecommitdiffstats
path: root/vendor/unwinding
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-19 09:25:56 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-19 09:25:56 +0000
commit018c4950b9406055dec02ef0fb52f132e2bb1e2c (patch)
treea835ebdf2088ef88fa681f8fad45f09922c1ae9a /vendor/unwinding
parentAdding debian version 1.75.0+dfsg1-5. (diff)
downloadrustc-018c4950b9406055dec02ef0fb52f132e2bb1e2c.tar.xz
rustc-018c4950b9406055dec02ef0fb52f132e2bb1e2c.zip
Merging upstream version 1.76.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/unwinding')
-rw-r--r--vendor/unwinding/.cargo-checksum.json1
-rw-r--r--vendor/unwinding/Cargo.toml92
-rw-r--r--vendor/unwinding/LICENSE-APACHE176
-rw-r--r--vendor/unwinding/LICENSE-MIT23
-rw-r--r--vendor/unwinding/README.md75
-rw-r--r--vendor/unwinding/rust-toolchain2
-rw-r--r--vendor/unwinding/src/abi.rs172
-rw-r--r--vendor/unwinding/src/arch.rs80
-rw-r--r--vendor/unwinding/src/lib.rs57
-rw-r--r--vendor/unwinding/src/panic.rs88
-rw-r--r--vendor/unwinding/src/panic_handler.rs103
-rw-r--r--vendor/unwinding/src/panic_handler_dummy.rs6
-rw-r--r--vendor/unwinding/src/panicking.rs71
-rw-r--r--vendor/unwinding/src/personality.rs181
-rw-r--r--vendor/unwinding/src/personality_dummy.rs16
-rw-r--r--vendor/unwinding/src/print.rs70
-rw-r--r--vendor/unwinding/src/system_alloc.rs63
-rw-r--r--vendor/unwinding/src/unwinder/arch/aarch64.rs142
-rw-r--r--vendor/unwinding/src/unwinder/arch/mod.rs33
-rw-r--r--vendor/unwinding/src/unwinder/arch/riscv32.rs242
-rw-r--r--vendor/unwinding/src/unwinder/arch/riscv64.rs242
-rw-r--r--vendor/unwinding/src/unwinder/arch/x86.rs136
-rw-r--r--vendor/unwinding/src/unwinder/arch/x86_64.rs140
-rw-r--r--vendor/unwinding/src/unwinder/find_fde/custom.rs171
-rw-r--r--vendor/unwinding/src/unwinder/find_fde/fixed.rs44
-rw-r--r--vendor/unwinding/src/unwinder/find_fde/gnu_eh_frame_hdr.rs66
-rw-r--r--vendor/unwinding/src/unwinder/find_fde/mod.rs64
-rw-r--r--vendor/unwinding/src/unwinder/find_fde/phdr.rs166
-rw-r--r--vendor/unwinding/src/unwinder/find_fde/registry.rs250
-rw-r--r--vendor/unwinding/src/unwinder/frame.rs198
-rw-r--r--vendor/unwinding/src/unwinder/mod.rs430
-rw-r--r--vendor/unwinding/src/util.rs41
-rw-r--r--vendor/unwinding/tests/compile_tests.rs20
33 files changed, 3661 insertions, 0 deletions
diff --git a/vendor/unwinding/.cargo-checksum.json b/vendor/unwinding/.cargo-checksum.json
new file mode 100644
index 000000000..1ac67f6b7
--- /dev/null
+++ b/vendor/unwinding/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"Cargo.toml":"fd7e41cc7b3744108423fea02f7345294c68c18fb67b0004588836d1cf526a7c","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"e0dfc20bf5b45a644a36eda999e3d62271f716a2d98dd5fb04528e8bef011769","rust-toolchain":"2ce1c1fe5e79a52424c9d88d99f5a2c95dcf5b4f4a82431bb9e5710cfb39e184","src/abi.rs":"f60ea0aa4be05500d84b2237a23a3657edef2ba19cdd91722c506e396ffcff19","src/arch.rs":"87953b9d1cb4b8cdd8f5a2c9f9446b70697579729957af59500ae0b257758a14","src/lib.rs":"014e2cd20833989f44e7547985b782c2b4f5dcbeefe9a38762b75549f7e10121","src/panic.rs":"2e1b8f0785d91c8b730683aebfb287d73dee5751e51e3bd1d1512abfc4ea15d4","src/panic_handler.rs":"d536b09d9ff1d26d41494f89a4dada3aa491a7612e9de6d4b18952dad4ad2799","src/panic_handler_dummy.rs":"e3c0b2961a5606aa1833abd0693b08ff350bcbf91ba2e732d00b9c35c619df2d","src/panicking.rs":"17f0c97225be532e69e16c9d1fe076ff6a74903462bb4180ff13691405a19972","src/personality.rs":"7335b8d7189e4380690111f5afe9049f9b4e19bed681b9d23b596c0fd3206516","src/personality_dummy.rs":"8dc3248a84e0aec700594be066603f7e4134566d7dc8e9969f2e6a62cd46290e","src/print.rs":"429278d7f2cd847b2d01fbc374f2b54aae72a46f7f0e86a8755f402328ea6c8f","src/system_alloc.rs":"7c9dab07314052fd5be6d729345f7caa83ad1b7e39f29e696c9ad2852a06ae26","src/unwinder/arch/aarch64.rs":"cf05a04ff270053a7aef1dc0ae73b493c071e7673897d94e37d37328c44e4887","src/unwinder/arch/mod.rs":"6b798447db635c19b4451395e2922e45698808b989a6bf59902e424726897db4","src/unwinder/arch/riscv32.rs":"77382b6560051dc1d0a719badc8bb74706ae6493d07b0cdba07b5fabf699e048","src/unwinder/arch/riscv64.rs":"eed32b7417bd9cc6469c3e31b3dcff518fa6d2022f2e580bfdc6a44ff24d9f15","src/unwinder/arch/x86.rs":"33242747dc9d553bc4c7ff3c4e7f1278d81d8a664739750eada60906b73409cd","src/unwinder/arch/x86_64.rs":"273eaf66bf81fcbd9b46f50a51bf2108b1e7116bbf4121830b86fe8fc94d4887","src/unwinder/find_fde/custom.rs":"1703194d9ed61991865e05b27b6ef52031a18a54959d583d6f9769ceeb11b6f8","src/unwinder/find_fde/fixed.rs":"79ebddc97feb899fdaa23b7831e7cc8f9406dd627bddc7dc4f66793a5196e1e5","src/unwinder/find_fde/gnu_eh_frame_hdr.rs":"3e150d182ee67417b7c0f71f2e359790cc7962c882c00710f5d4f653db453e85","src/unwinder/find_fde/mod.rs":"17f1ae38fd3cc237c6a735168e47430515e234b822cb24155af78c3b5a62f152","src/unwinder/find_fde/phdr.rs":"0086778de0e8f979327dfc8f3384aaa9a8903bb6add168ad44d6cd5066ca6930","src/unwinder/find_fde/registry.rs":"e367166bcb27a4270a388eb972924f0f4892e2b8008cf96f6f9a6b4ebd1f5f29","src/unwinder/frame.rs":"e9db5603611b8be52dca09a17cc006f8f48965f2de66470848afc4876402b102","src/unwinder/mod.rs":"de7091270ba75eb1e2383a10b3fbbd2df32a326e8444b17bcab2dd2fff1cf7f7","src/util.rs":"23347e2066173c980dbc48403045b3967c1685afa674dabc6493aa494179b944","tests/compile_tests.rs":"5bac8c161112e360ce58acd62f324180f029c7ba683afcb7e9fc5e3a00b9a3ef"},"package":"37a19a21a537f635c16c7576f22d0f2f7d63353c1337ad4ce0d8001c7952a25b"} \ No newline at end of file
diff --git a/vendor/unwinding/Cargo.toml b/vendor/unwinding/Cargo.toml
new file mode 100644
index 000000000..851d1eee0
--- /dev/null
+++ b/vendor/unwinding/Cargo.toml
@@ -0,0 +1,92 @@
+# 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 = "2021"
+name = "unwinding"
+version = "0.2.1"
+authors = ["Gary Guo <gary@garyguo.net>"]
+description = "Unwinding library in Rust and for Rust"
+readme = "README.md"
+license = "MIT OR Apache-2.0"
+repository = "https://github.com/nbdd0121/unwinding/"
+
+[package.metadata.docs.rs]
+features = ["panic-handler"]
+
+[profile.release]
+debug = 2
+
+[dependencies.compiler_builtins]
+version = "0.1.2"
+optional = true
+
+[dependencies.core]
+version = "1.0.0"
+optional = true
+package = "rustc-std-workspace-core"
+
+[dependencies.gimli]
+version = "0.28"
+features = ["read-core"]
+default-features = false
+
+[dependencies.libc]
+version = "0.2"
+optional = true
+
+[dependencies.spin]
+version = "0.9.8"
+features = [
+ "mutex",
+ "spin_mutex",
+]
+optional = true
+default-features = false
+
+[features]
+alloc = []
+default = [
+ "unwinder",
+ "dwarf-expr",
+ "hide-trace",
+ "fde-phdr-dl",
+ "fde-registry",
+]
+dwarf-expr = []
+fde-custom = []
+fde-gnu-eh-frame-hdr = []
+fde-phdr = ["libc"]
+fde-phdr-aux = ["fde-phdr"]
+fde-phdr-dl = ["fde-phdr"]
+fde-registry = ["alloc"]
+fde-static = []
+hide-trace = []
+panic = [
+ "panicking",
+ "alloc",
+]
+panic-handler = [
+ "print",
+ "panic",
+]
+panic-handler-dummy = []
+panicking = []
+personality = []
+personality-dummy = []
+print = ["libc"]
+rustc-dep-of-std = [
+ "core",
+ "gimli/rustc-dep-of-std",
+ "compiler_builtins",
+]
+system-alloc = []
+unwinder = []
diff --git a/vendor/unwinding/LICENSE-APACHE b/vendor/unwinding/LICENSE-APACHE
new file mode 100644
index 000000000..1b5ec8b78
--- /dev/null
+++ b/vendor/unwinding/LICENSE-APACHE
@@ -0,0 +1,176 @@
+ 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
diff --git a/vendor/unwinding/LICENSE-MIT b/vendor/unwinding/LICENSE-MIT
new file mode 100644
index 000000000..31aa79387
--- /dev/null
+++ b/vendor/unwinding/LICENSE-MIT
@@ -0,0 +1,23 @@
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/vendor/unwinding/README.md b/vendor/unwinding/README.md
new file mode 100644
index 000000000..3b5f86bda
--- /dev/null
+++ b/vendor/unwinding/README.md
@@ -0,0 +1,75 @@
+Unwinding library in Rust and for Rust
+======================================
+
+[![crates.io](https://img.shields.io/crates/v/unwinding.svg)](https://crates.io/crates/unwinding)
+[![docs.rs](https://docs.rs/unwinding/badge.svg)](https://docs.rs/unwinding)
+[![license](https://img.shields.io/crates/l/unwinding.svg)](https://crates.io/crates/unwinding)
+
+This library serves two purposes:
+1. Provide a pure Rust alternative to libgcc_eh or libunwind.
+2. Provide easier unwinding support for `#![no_std]` targets.
+
+Currently supports x86_64, x86, RV64, RV32 and AArch64.
+
+## Unwinder
+
+The unwinder can be enabled with `unwinder` feature. Here are the feature gates related to the unwinder:
+
+| Feature | Default | Description |
+|--------------------- |---------|-|
+| unwinder | Yes | The primary feature gate to enable the unwinder |
+| fde-phdr-dl | Yes | Use `dl_iterator_phdr` to retrieve frame unwind table. Depends on libc. |
+| fde-phdr-aux | No | Use ELF auxiliary vector to retrieve frame unwind table. Depends on libc. |
+| fde-registry | Yes | Provide `__register__frame` and others for dynamic registration. Requires either `libc` or `spin` for a mutex implementation. |
+| fde-gnu-eh-frame-hdr | No | Use `__executable_start`, `__etext` and `__GNU_EH_FRAME_HDR` to retrieve frame unwind table. The former two symbols are usually provided by the linker, while the last one is provided if GNU LD is used and --eh-frame-hdr option is enabled. |
+| fde-static | No | Use `__executable_start`, `__etext` and `__eh_frame` to retrieve frame unwind table. The former two symbols are usually provided by the linker, while the last one would need to be provided by the user via linker script. |
+| fde-custom | No | Allow the program to provide a custom means of retrieving frame unwind table at runtime via the `set_custom_eh_frame_finder` function. |
+| dwarf-expr | Yes | Enable the dwarf expression evaluator. Usually not necessary for Rust |
+| hide-trace | Yes | Hide unwinder frames in back trace |
+
+If you want to use the unwinder for other Rust (C++, or any programs that utilize the unwinder), you can build the [`unwinding_dyn`](cdylib) crate provided, and use `LD_PRELOAD` to replace the system unwinder with it.
+```sh
+cd cdylib
+cargo build --release
+# Test the unwinder using rustc. Why not :)
+LD_PRELOAD=`../target/release/libunwinding_dyn.so` rustc +nightly -Ztreat-err-as-bug
+```
+
+If you want to link to the unwinder in a Rust binary, simply add
+```rust
+extern crate unwinding;
+```
+
+## Personality and other utilities
+
+The library also provides Rust personality function. This can work with the unwinder described above or with a different unwinder. This can be handy if you are working on a `#![no_std]` binary/staticlib/cdylib and you still want unwinding support.
+
+Here are the feature gates related:
+
+| Feature | Default | Description |
+|---------------|---------|-|
+| personality | No | Provides `#[lang = eh_personality]` |
+| print | No | Provides `(e)?print(ln)?`. This is really only here because panic handler needs to print things. Depends on libc. |
+| panicking | No | Provides a generic `begin_panic` and `catch_unwind`. Only stack unwinding functionality is provided, memory allocation and panic handling is left to the user. |
+| panic | No | Provides Rust `begin_panic` and `catch_unwind`. Only stack unwinding functionality is provided and no printing is done, because this feature does not depend on libc. |
+| panic-handler | No | Provides `#[panic_handler]`. Provides similar behaviour on panic to std, with `RUST_BACKTRACE` support as well. Stack trace won't have symbols though. Depends on libc. |
+| system-alloc | No | Provides a global allocator which calls `malloc` and friends. Provided for convience. |
+
+If you are writing a `#![no_std]` program, simply enable `personality`, `panic-handler` and `system-alloc` in addition to the defaults, you instantly obtains the ability to do unwinding! An example is given in the [`example/` folder](example).
+
+## Baremetal
+
+To use this library for baremetal projects, disable default features and enable `unwinder`, `fde-static`, `personality`, `panic`. `dwarf-expr` and `hide-trace` are optional. Modify the linker script by
+```ld
+/* Inserting these two lines */
+. = ALIGN(8);
+PROVIDE(__eh_frame = .);
+/* before .eh_frame rule */
+.eh_frame : { KEEP (*(.eh_frame)) *(.eh_frame.*) }
+```
+
+And that's it! After you ensured that the global allocator is functional, you can use `unwinding::panic::begin_panic` to initiate an unwing and catch using `unwinding::panic::catch_unwind`, as if you have a `std`.
+
+If your linker supports `--eh-frame-hdr` you can also try to use `fde-gnu-eh-frame-hdr` instead of `fde-static`. GNU LD will provides a `__GNU_EH_FRAME_HDR` magic symbol so you don't have to provide `__eh_frame` through linker script.
+
+If you have your own version of `thread_local` and `println!` working, you can port [`panic_handler.rs`](src/panic_handler.rs) for double-panic protection and stack traces!
diff --git a/vendor/unwinding/rust-toolchain b/vendor/unwinding/rust-toolchain
new file mode 100644
index 000000000..5d56faf9a
--- /dev/null
+++ b/vendor/unwinding/rust-toolchain
@@ -0,0 +1,2 @@
+[toolchain]
+channel = "nightly"
diff --git a/vendor/unwinding/src/abi.rs b/vendor/unwinding/src/abi.rs
new file mode 100644
index 000000000..12766c118
--- /dev/null
+++ b/vendor/unwinding/src/abi.rs
@@ -0,0 +1,172 @@
+use core::ffi::c_void;
+use core::ops;
+
+use crate::util::*;
+
+#[cfg(not(feature = "unwinder"))]
+use crate::arch::Arch;
+#[cfg(feature = "unwinder")]
+pub use crate::unwinder::*;
+
+#[repr(transparent)]
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub struct UnwindReasonCode(pub c_int);
+
+#[allow(unused)]
+impl UnwindReasonCode {
+ pub const NO_REASON: Self = Self(0);
+ pub const FOREIGN_EXCEPTION_CAUGHT: Self = Self(1);
+ pub const FATAL_PHASE2_ERROR: Self = Self(2);
+ pub const FATAL_PHASE1_ERROR: Self = Self(3);
+ pub const NORMAL_STOP: Self = Self(4);
+ pub const END_OF_STACK: Self = Self(5);
+ pub const HANDLER_FOUND: Self = Self(6);
+ pub const INSTALL_CONTEXT: Self = Self(7);
+ pub const CONTINUE_UNWIND: Self = Self(8);
+}
+
+#[repr(transparent)]
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub struct UnwindAction(pub c_int);
+
+impl UnwindAction {
+ pub const SEARCH_PHASE: Self = Self(1);
+ pub const CLEANUP_PHASE: Self = Self(2);
+ pub const HANDLER_FRAME: Self = Self(4);
+ pub const FORCE_UNWIND: Self = Self(8);
+ pub const END_OF_STACK: Self = Self(16);
+}
+
+impl ops::BitOr for UnwindAction {
+ type Output = Self;
+
+ #[inline]
+ fn bitor(self, rhs: Self) -> Self {
+ Self(self.0 | rhs.0)
+ }
+}
+
+impl UnwindAction {
+ #[inline]
+ pub const fn empty() -> Self {
+ Self(0)
+ }
+
+ #[inline]
+ pub const fn contains(&self, other: Self) -> bool {
+ self.0 & other.0 != 0
+ }
+}
+
+pub type UnwindExceptionCleanupFn = unsafe extern "C" fn(UnwindReasonCode, *mut UnwindException);
+
+pub type UnwindStopFn = unsafe extern "C" fn(
+ c_int,
+ UnwindAction,
+ u64,
+ *mut UnwindException,
+ &mut UnwindContext<'_>,
+ *mut c_void,
+) -> UnwindReasonCode;
+
+#[cfg(not(feature = "unwinder"))]
+#[repr(C)]
+pub struct UnwindException {
+ pub exception_class: u64,
+ pub exception_cleanup: Option<UnwindExceptionCleanupFn>,
+ private: [usize; Arch::UNWIND_PRIVATE_DATA_SIZE],
+}
+
+pub type UnwindTraceFn =
+ extern "C" fn(ctx: &UnwindContext<'_>, arg: *mut c_void) -> UnwindReasonCode;
+
+#[cfg(not(feature = "unwinder"))]
+#[repr(C)]
+pub struct UnwindContext<'a> {
+ opaque: usize,
+ phantom: core::marker::PhantomData<&'a ()>,
+}
+
+pub type PersonalityRoutine = unsafe extern "C" fn(
+ c_int,
+ UnwindAction,
+ u64,
+ *mut UnwindException,
+ &mut UnwindContext<'_>,
+) -> UnwindReasonCode;
+
+#[cfg(not(feature = "unwinder"))]
+macro_rules! binding {
+ () => {};
+ (unsafe extern $abi: literal fn $name: ident ($($arg: ident : $arg_ty: ty),*$(,)?) $(-> $ret: ty)?; $($rest: tt)*) => {
+ extern $abi {
+ pub fn $name($($arg: $arg_ty),*) $(-> $ret)?;
+ }
+ binding!($($rest)*);
+ };
+
+ (extern $abi: literal fn $name: ident ($($arg: ident : $arg_ty: ty),*$(,)?) $(-> $ret: ty)?; $($rest: tt)*) => {
+ #[allow(non_snake_case)]
+ #[inline]
+ pub fn $name($($arg: $arg_ty),*) $(-> $ret)? {
+ extern $abi {
+ fn $name($($arg: $arg_ty),*) $(-> $ret)?;
+ }
+ unsafe { $name($($arg),*) }
+ }
+ binding!($($rest)*);
+ };
+}
+
+#[cfg(feature = "unwinder")]
+macro_rules! binding {
+ () => {};
+ (unsafe extern $abi: literal fn $name: ident ($($arg: ident : $arg_ty: ty),*$(,)?) $(-> $ret: ty)?; $($rest: tt)*) => {
+ const _: unsafe extern $abi fn($($arg_ty),*) $(-> $ret)? = $name;
+ };
+
+ (extern $abi: literal fn $name: ident ($($arg: ident : $arg_ty: ty),*$(,)?) $(-> $ret: ty)?; $($rest: tt)*) => {
+ const _: extern $abi fn($($arg_ty),*) $(-> $ret)? = $name;
+ };
+}
+
+binding! {
+ extern "C" fn _Unwind_GetGR(unwind_ctx: &UnwindContext<'_>, index: c_int) -> usize;
+ extern "C" fn _Unwind_GetCFA(unwind_ctx: &UnwindContext<'_>) -> usize;
+ extern "C" fn _Unwind_SetGR(
+ unwind_ctx: &mut UnwindContext<'_>,
+ index: c_int,
+ value: usize,
+ );
+ extern "C" fn _Unwind_GetIP(unwind_ctx: &UnwindContext<'_>) -> usize;
+ extern "C" fn _Unwind_GetIPInfo(
+ unwind_ctx: &UnwindContext<'_>,
+ ip_before_insn: &mut c_int,
+ ) -> usize;
+ extern "C" fn _Unwind_SetIP(
+ unwind_ctx: &mut UnwindContext<'_>,
+ value: usize,
+ );
+ extern "C" fn _Unwind_GetLanguageSpecificData(unwind_ctx: &UnwindContext<'_>) -> *mut c_void;
+ extern "C" fn _Unwind_GetRegionStart(unwind_ctx: &UnwindContext<'_>) -> usize;
+ extern "C" fn _Unwind_GetTextRelBase(unwind_ctx: &UnwindContext<'_>) -> usize;
+ extern "C" fn _Unwind_GetDataRelBase(unwind_ctx: &UnwindContext<'_>) -> usize;
+ extern "C" fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void;
+ unsafe extern "C-unwind" fn _Unwind_RaiseException(
+ exception: *mut UnwindException,
+ ) -> UnwindReasonCode;
+ unsafe extern "C-unwind" fn _Unwind_ForcedUnwind(
+ exception: *mut UnwindException,
+ stop: UnwindStopFn,
+ stop_arg: *mut c_void,
+ ) -> UnwindReasonCode;
+ unsafe extern "C-unwind" fn _Unwind_Resume(exception: *mut UnwindException) -> !;
+ unsafe extern "C-unwind" fn _Unwind_Resume_or_Rethrow(
+ exception: *mut UnwindException,
+ ) -> UnwindReasonCode;
+ unsafe extern "C" fn _Unwind_DeleteException(exception: *mut UnwindException);
+ extern "C-unwind" fn _Unwind_Backtrace(
+ trace: UnwindTraceFn,
+ trace_argument: *mut c_void,
+ ) -> UnwindReasonCode;
+}
diff --git a/vendor/unwinding/src/arch.rs b/vendor/unwinding/src/arch.rs
new file mode 100644
index 000000000..33b38119c
--- /dev/null
+++ b/vendor/unwinding/src/arch.rs
@@ -0,0 +1,80 @@
+#[cfg(target_arch = "x86_64")]
+mod x86_64 {
+ use gimli::{Register, X86_64};
+
+ pub struct Arch;
+
+ #[allow(unused)]
+ impl Arch {
+ pub const SP: Register = X86_64::RSP;
+ pub const RA: Register = X86_64::RA;
+
+ pub const UNWIND_DATA_REG: (Register, Register) = (X86_64::RAX, X86_64::RDX);
+ pub const UNWIND_PRIVATE_DATA_SIZE: usize = 6;
+ }
+}
+#[cfg(target_arch = "x86_64")]
+pub use x86_64::*;
+
+#[cfg(target_arch = "x86")]
+mod x86 {
+ use gimli::{Register, X86};
+
+ pub struct Arch;
+
+ #[allow(unused)]
+ impl Arch {
+ pub const SP: Register = X86::ESP;
+ pub const RA: Register = X86::RA;
+
+ pub const UNWIND_DATA_REG: (Register, Register) = (X86::EAX, X86::EDX);
+ pub const UNWIND_PRIVATE_DATA_SIZE: usize = 5;
+ }
+}
+#[cfg(target_arch = "x86")]
+pub use x86::*;
+
+#[cfg(any(target_arch = "riscv64", target_arch = "riscv32"))]
+mod riscv {
+ use gimli::{Register, RiscV};
+
+ pub struct Arch;
+
+ #[allow(unused)]
+ impl Arch {
+ pub const SP: Register = RiscV::SP;
+ pub const RA: Register = RiscV::RA;
+
+ pub const UNWIND_DATA_REG: (Register, Register) = (RiscV::A0, RiscV::A1);
+ pub const UNWIND_PRIVATE_DATA_SIZE: usize = 2;
+ }
+}
+#[cfg(any(target_arch = "riscv64", target_arch = "riscv32"))]
+pub use riscv::*;
+
+#[cfg(target_arch = "aarch64")]
+mod aarch64 {
+ use gimli::{AArch64, Register};
+
+ pub struct Arch;
+
+ #[allow(unused)]
+ impl Arch {
+ pub const SP: Register = AArch64::SP;
+ pub const RA: Register = AArch64::X30;
+
+ pub const UNWIND_DATA_REG: (Register, Register) = (AArch64::X0, AArch64::X1);
+ pub const UNWIND_PRIVATE_DATA_SIZE: usize = 2;
+ }
+}
+#[cfg(target_arch = "aarch64")]
+pub use aarch64::*;
+
+#[cfg(not(any(
+ target_arch = "x86_64",
+ target_arch = "x86",
+ target_arch = "riscv64",
+ target_arch = "riscv32",
+ target_arch = "aarch64"
+)))]
+compile_error!("Current architecture is not supported");
diff --git a/vendor/unwinding/src/lib.rs b/vendor/unwinding/src/lib.rs
new file mode 100644
index 000000000..44ecc37fc
--- /dev/null
+++ b/vendor/unwinding/src/lib.rs
@@ -0,0 +1,57 @@
+#![doc = include_str!("../README.md")]
+#![feature(c_unwind)]
+#![feature(naked_functions)]
+#![feature(non_exhaustive_omitted_patterns_lint)]
+// lang_items is an internal feature. `internal_features` lint is added recently
+// so also allow unknown lints to prevent warning in older nightly versions.
+#![cfg_attr(
+ any(feature = "personality", feature = "personality-dummy"),
+ allow(internal_features)
+)]
+#![cfg_attr(
+ any(feature = "personality", feature = "personality-dummy"),
+ feature(lang_items)
+)]
+#![cfg_attr(
+ any(feature = "panicking", feature = "panic-handler-dummy"),
+ feature(core_intrinsics)
+)]
+#![cfg_attr(feature = "panic-handler", feature(thread_local))]
+#![warn(rust_2018_idioms)]
+#![warn(unsafe_op_in_unsafe_fn)]
+#![no_std]
+
+#[cfg(feature = "alloc")]
+extern crate alloc;
+
+#[cfg(feature = "unwinder")]
+mod unwinder;
+
+#[cfg(all(feature = "unwinder", feature = "fde-custom"))]
+pub use unwinder::custom_eh_frame_finder;
+
+pub mod abi;
+
+mod arch;
+mod util;
+
+#[cfg(feature = "print")]
+pub mod print;
+
+#[cfg(feature = "personality")]
+mod personality;
+#[cfg(all(not(feature = "personality"), feature = "personality-dummy"))]
+mod personality_dummy;
+
+#[cfg(feature = "panic")]
+pub mod panic;
+#[cfg(feature = "panicking")]
+pub mod panicking;
+
+#[cfg(feature = "panic-handler")]
+mod panic_handler;
+#[cfg(all(not(feature = "panic-handler"), feature = "panic-handler-dummy"))]
+mod panic_handler_dummy;
+
+#[cfg(feature = "system-alloc")]
+mod system_alloc;
diff --git a/vendor/unwinding/src/panic.rs b/vendor/unwinding/src/panic.rs
new file mode 100644
index 000000000..b69e958eb
--- /dev/null
+++ b/vendor/unwinding/src/panic.rs
@@ -0,0 +1,88 @@
+use alloc::boxed::Box;
+use core::any::Any;
+use core::mem::MaybeUninit;
+
+use crate::abi::*;
+#[cfg(feature = "panic-handler")]
+pub use crate::panic_handler::*;
+use crate::panicking::Exception;
+
+static CANARY: u8 = 0;
+
+#[repr(transparent)]
+struct RustPanic(Box<dyn Any + Send>, DropGuard);
+
+struct DropGuard;
+
+impl Drop for DropGuard {
+ fn drop(&mut self) {
+ #[cfg(feature = "panic-handler")]
+ {
+ drop_panic();
+ }
+ crate::util::abort();
+ }
+}
+
+#[repr(C)]
+struct ExceptionWithPayload {
+ exception: MaybeUninit<UnwindException>,
+ // See rust/library/panic_unwind/src/gcc.rs for the canary values
+ canary: *const u8,
+ payload: RustPanic,
+}
+
+unsafe impl Exception for RustPanic {
+ const CLASS: [u8; 8] = *b"MOZ\0RUST";
+
+ fn wrap(this: Self) -> *mut UnwindException {
+ Box::into_raw(Box::new(ExceptionWithPayload {
+ exception: MaybeUninit::uninit(),
+ canary: &CANARY,
+ payload: this,
+ })) as *mut UnwindException
+ }
+
+ unsafe fn unwrap(ex: *mut UnwindException) -> Self {
+ let ex = ex as *mut ExceptionWithPayload;
+ let canary = unsafe { core::ptr::addr_of!((*ex).canary).read() };
+ if !core::ptr::eq(canary, &CANARY) {
+ // This is a Rust exception but not generated by us.
+ #[cfg(feature = "panic-handler")]
+ {
+ foreign_exception();
+ }
+ crate::util::abort();
+ }
+ let ex = unsafe { Box::from_raw(ex) };
+ ex.payload
+ }
+}
+
+pub fn begin_panic(payload: Box<dyn Any + Send>) -> UnwindReasonCode {
+ crate::panicking::begin_panic(RustPanic(payload, DropGuard))
+}
+
+pub fn catch_unwind<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>> {
+ #[cold]
+ fn process_panic(p: Option<RustPanic>) -> Box<dyn Any + Send> {
+ match p {
+ None => {
+ #[cfg(feature = "panic-handler")]
+ {
+ foreign_exception();
+ }
+ crate::util::abort();
+ }
+ Some(e) => {
+ #[cfg(feature = "panic-handler")]
+ {
+ panic_caught();
+ }
+ core::mem::forget(e.1);
+ e.0
+ }
+ }
+ }
+ crate::panicking::catch_unwind(f).map_err(process_panic)
+}
diff --git a/vendor/unwinding/src/panic_handler.rs b/vendor/unwinding/src/panic_handler.rs
new file mode 100644
index 000000000..1d07768d7
--- /dev/null
+++ b/vendor/unwinding/src/panic_handler.rs
@@ -0,0 +1,103 @@
+use crate::abi::*;
+use crate::print::*;
+use alloc::boxed::Box;
+use core::any::Any;
+use core::cell::Cell;
+use core::ffi::c_void;
+use core::panic::{Location, PanicInfo};
+use core::sync::atomic::{AtomicI32, Ordering};
+
+#[thread_local]
+static PANIC_COUNT: Cell<usize> = Cell::new(0);
+
+#[link(name = "c")]
+extern "C" {}
+
+pub(crate) fn drop_panic() {
+ eprintln!("Rust panics must be rethrown");
+}
+
+pub(crate) fn foreign_exception() {
+ eprintln!("Rust cannot catch foreign exceptions");
+}
+
+pub(crate) fn panic_caught() {
+ PANIC_COUNT.set(0);
+}
+
+fn check_env() -> bool {
+ static ENV: AtomicI32 = AtomicI32::new(-1);
+
+ let env = ENV.load(Ordering::Relaxed);
+ if env != -1 {
+ return env != 0;
+ }
+
+ let val = unsafe {
+ let ptr = libc::getenv(b"RUST_BACKTRACE\0".as_ptr() as _);
+ if ptr.is_null() {
+ b""
+ } else {
+ let len = libc::strlen(ptr);
+ core::slice::from_raw_parts(ptr as *const u8, len)
+ }
+ };
+ let (note, env) = match val {
+ b"" => (true, false),
+ b"1" | b"full" => (false, true),
+ _ => (false, false),
+ };
+
+ // Issue a note for the first panic.
+ if ENV.swap(env as _, Ordering::Relaxed) == -1 && note {
+ eprintln!("note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace");
+ }
+ env
+}
+
+fn stack_trace() {
+ struct CallbackData {
+ counter: usize,
+ }
+ extern "C" fn callback(unwind_ctx: &UnwindContext<'_>, arg: *mut c_void) -> UnwindReasonCode {
+ let data = unsafe { &mut *(arg as *mut CallbackData) };
+ data.counter += 1;
+ eprintln!(
+ "{:4}:{:#19x} - <unknown>",
+ data.counter,
+ _Unwind_GetIP(unwind_ctx)
+ );
+ UnwindReasonCode::NO_REASON
+ }
+ let mut data = CallbackData { counter: 0 };
+ _Unwind_Backtrace(callback, &mut data as *mut _ as _);
+}
+
+fn do_panic(msg: Box<dyn Any + Send>) -> ! {
+ if PANIC_COUNT.get() >= 1 {
+ stack_trace();
+ eprintln!("thread panicked while processing panic. aborting.");
+ crate::util::abort();
+ }
+ PANIC_COUNT.set(1);
+ if check_env() {
+ stack_trace();
+ }
+ let code = crate::panic::begin_panic(Box::new(msg));
+ eprintln!("failed to initiate panic, error {}", code.0);
+ crate::util::abort();
+}
+
+#[panic_handler]
+fn panic(info: &PanicInfo<'_>) -> ! {
+ eprintln!("{}", info);
+
+ struct NoPayload;
+ do_panic(Box::new(NoPayload))
+}
+
+#[track_caller]
+pub fn panic_any<M: 'static + Any + Send>(msg: M) -> ! {
+ eprintln!("panicked at {}", Location::caller());
+ do_panic(Box::new(msg))
+}
diff --git a/vendor/unwinding/src/panic_handler_dummy.rs b/vendor/unwinding/src/panic_handler_dummy.rs
new file mode 100644
index 000000000..6770705ec
--- /dev/null
+++ b/vendor/unwinding/src/panic_handler_dummy.rs
@@ -0,0 +1,6 @@
+use core::panic::PanicInfo;
+
+#[panic_handler]
+fn panic(_info: &PanicInfo<'_>) -> ! {
+ crate::util::abort();
+}
diff --git a/vendor/unwinding/src/panicking.rs b/vendor/unwinding/src/panicking.rs
new file mode 100644
index 000000000..9c83bfe4a
--- /dev/null
+++ b/vendor/unwinding/src/panicking.rs
@@ -0,0 +1,71 @@
+use core::mem::ManuallyDrop;
+
+use crate::abi::*;
+
+pub unsafe trait Exception {
+ const CLASS: [u8; 8];
+
+ fn wrap(this: Self) -> *mut UnwindException;
+ unsafe fn unwrap(ex: *mut UnwindException) -> Self;
+}
+
+pub fn begin_panic<E: Exception>(exception: E) -> UnwindReasonCode {
+ unsafe extern "C" fn exception_cleanup<E: Exception>(
+ _unwind_code: UnwindReasonCode,
+ exception: *mut UnwindException,
+ ) {
+ unsafe { E::unwrap(exception) };
+ }
+
+ let ex = E::wrap(exception);
+ unsafe {
+ (*ex).exception_class = u64::from_be_bytes(E::CLASS);
+ (*ex).exception_cleanup = Some(exception_cleanup::<E>);
+ _Unwind_RaiseException(ex)
+ }
+}
+
+pub fn catch_unwind<E: Exception, R, F: FnOnce() -> R>(f: F) -> Result<R, Option<E>> {
+ #[repr(C)]
+ union Data<F, R, E> {
+ f: ManuallyDrop<F>,
+ r: ManuallyDrop<R>,
+ p: ManuallyDrop<Option<E>>,
+ }
+
+ let mut data = Data {
+ f: ManuallyDrop::new(f),
+ };
+
+ let data_ptr = &mut data as *mut _ as *mut u8;
+ unsafe {
+ return if core::intrinsics::r#try(do_call::<F, R>, data_ptr, do_catch::<E>) == 0 {
+ Ok(ManuallyDrop::into_inner(data.r))
+ } else {
+ Err(ManuallyDrop::into_inner(data.p))
+ };
+ }
+
+ #[inline]
+ fn do_call<F: FnOnce() -> R, R>(data: *mut u8) {
+ unsafe {
+ let data = &mut *(data as *mut Data<F, R, ()>);
+ let f = ManuallyDrop::take(&mut data.f);
+ data.r = ManuallyDrop::new(f());
+ }
+ }
+
+ #[cold]
+ fn do_catch<E: Exception>(data: *mut u8, exception: *mut u8) {
+ unsafe {
+ let data = &mut *(data as *mut ManuallyDrop<Option<E>>);
+ let exception = exception as *mut UnwindException;
+ if (*exception).exception_class != u64::from_be_bytes(E::CLASS) {
+ _Unwind_DeleteException(exception);
+ *data = ManuallyDrop::new(None);
+ return;
+ }
+ *data = ManuallyDrop::new(Some(E::unwrap(exception)));
+ }
+ }
+}
diff --git a/vendor/unwinding/src/personality.rs b/vendor/unwinding/src/personality.rs
new file mode 100644
index 000000000..3bbdb1698
--- /dev/null
+++ b/vendor/unwinding/src/personality.rs
@@ -0,0 +1,181 @@
+// References:
+// https://github.com/rust-lang/rust/blob/c4be230b4a30eb74e3a3908455731ebc2f731d3d/library/panic_unwind/src/gcc.rs
+// https://github.com/rust-lang/rust/blob/c4be230b4a30eb74e3a3908455731ebc2f731d3d/library/panic_unwind/src/dwarf/eh.rs
+// https://docs.rs/gimli/0.25.0/src/gimli/read/cfi.rs.html
+
+use core::mem;
+use gimli::{constants, NativeEndian};
+use gimli::{EndianSlice, Error, Pointer, Reader};
+
+use crate::abi::*;
+use crate::arch::*;
+use crate::util::*;
+
+#[derive(Debug)]
+enum EHAction {
+ None,
+ Cleanup(usize),
+ Catch(usize),
+}
+
+fn parse_pointer_encoding(input: &mut StaticSlice) -> gimli::Result<constants::DwEhPe> {
+ let eh_pe = input.read_u8()?;
+ let eh_pe = constants::DwEhPe(eh_pe);
+
+ if eh_pe.is_valid_encoding() {
+ Ok(eh_pe)
+ } else {
+ Err(gimli::Error::UnknownPointerEncoding)
+ }
+}
+
+fn parse_encoded_pointer(
+ encoding: constants::DwEhPe,
+ unwind_ctx: &UnwindContext<'_>,
+ input: &mut StaticSlice,
+) -> gimli::Result<Pointer> {
+ if encoding == constants::DW_EH_PE_omit {
+ return Err(Error::CannotParseOmitPointerEncoding);
+ }
+
+ let base = match encoding.application() {
+ constants::DW_EH_PE_absptr => 0,
+ constants::DW_EH_PE_pcrel => input.slice().as_ptr() as u64,
+ constants::DW_EH_PE_textrel => _Unwind_GetTextRelBase(unwind_ctx) as u64,
+ constants::DW_EH_PE_datarel => _Unwind_GetDataRelBase(unwind_ctx) as u64,
+ constants::DW_EH_PE_funcrel => _Unwind_GetRegionStart(unwind_ctx) as u64,
+ constants::DW_EH_PE_aligned => return Err(Error::UnsupportedPointerEncoding),
+ _ => unreachable!(),
+ };
+
+ let offset = match encoding.format() {
+ constants::DW_EH_PE_absptr => input.read_address(mem::size_of::<usize>() as _),
+ constants::DW_EH_PE_uleb128 => input.read_uleb128(),
+ constants::DW_EH_PE_udata2 => input.read_u16().map(u64::from),
+ constants::DW_EH_PE_udata4 => input.read_u32().map(u64::from),
+ constants::DW_EH_PE_udata8 => input.read_u64(),
+ constants::DW_EH_PE_sleb128 => input.read_sleb128().map(|a| a as u64),
+ constants::DW_EH_PE_sdata2 => input.read_i16().map(|a| a as u64),
+ constants::DW_EH_PE_sdata4 => input.read_i32().map(|a| a as u64),
+ constants::DW_EH_PE_sdata8 => input.read_i64().map(|a| a as u64),
+ _ => unreachable!(),
+ }?;
+
+ let address = base.wrapping_add(offset);
+ Ok(if encoding.is_indirect() {
+ Pointer::Indirect(address)
+ } else {
+ Pointer::Direct(address)
+ })
+}
+
+fn find_eh_action(
+ reader: &mut StaticSlice,
+ unwind_ctx: &UnwindContext<'_>,
+) -> gimli::Result<EHAction> {
+ let func_start = _Unwind_GetRegionStart(unwind_ctx);
+ let mut ip_before_instr = 0;
+ let ip = _Unwind_GetIPInfo(unwind_ctx, &mut ip_before_instr);
+ let ip = if ip_before_instr != 0 { ip } else { ip - 1 };
+
+ let start_encoding = parse_pointer_encoding(reader)?;
+ let lpad_base = if !start_encoding.is_absent() {
+ unsafe { deref_pointer(parse_encoded_pointer(start_encoding, unwind_ctx, reader)?) }
+ } else {
+ func_start
+ };
+
+ let ttype_encoding = parse_pointer_encoding(reader)?;
+ if !ttype_encoding.is_absent() {
+ reader.read_uleb128()?;
+ }
+
+ let call_site_encoding = parse_pointer_encoding(reader)?;
+ let call_site_table_length = reader.read_uleb128()?;
+ reader.truncate(call_site_table_length as _)?;
+
+ while !reader.is_empty() {
+ let cs_start = unsafe {
+ deref_pointer(parse_encoded_pointer(
+ call_site_encoding,
+ unwind_ctx,
+ reader,
+ )?)
+ };
+ let cs_len = unsafe {
+ deref_pointer(parse_encoded_pointer(
+ call_site_encoding,
+ unwind_ctx,
+ reader,
+ )?)
+ };
+ let cs_lpad = unsafe {
+ deref_pointer(parse_encoded_pointer(
+ call_site_encoding,
+ unwind_ctx,
+ reader,
+ )?)
+ };
+ let cs_action = reader.read_uleb128()?;
+ if ip < func_start + cs_start {
+ break;
+ }
+ if ip < func_start + cs_start + cs_len {
+ if cs_lpad == 0 {
+ return Ok(EHAction::None);
+ } else {
+ let lpad = lpad_base + cs_lpad;
+ return Ok(match cs_action {
+ 0 => EHAction::Cleanup(lpad),
+ _ => EHAction::Catch(lpad),
+ });
+ }
+ }
+ }
+ Ok(EHAction::None)
+}
+
+#[lang = "eh_personality"]
+unsafe fn rust_eh_personality(
+ version: c_int,
+ actions: UnwindAction,
+ _exception_class: u64,
+ exception: *mut UnwindException,
+ unwind_ctx: &mut UnwindContext<'_>,
+) -> UnwindReasonCode {
+ if version != 1 {
+ return UnwindReasonCode::FATAL_PHASE1_ERROR;
+ }
+
+ let lsda = _Unwind_GetLanguageSpecificData(unwind_ctx);
+ if lsda.is_null() {
+ return UnwindReasonCode::CONTINUE_UNWIND;
+ }
+
+ let mut lsda = EndianSlice::new(unsafe { get_unlimited_slice(lsda as _) }, NativeEndian);
+ let eh_action = match find_eh_action(&mut lsda, unwind_ctx) {
+ Ok(v) => v,
+ Err(_) => return UnwindReasonCode::FATAL_PHASE1_ERROR,
+ };
+
+ if actions.contains(UnwindAction::SEARCH_PHASE) {
+ match eh_action {
+ EHAction::None | EHAction::Cleanup(_) => UnwindReasonCode::CONTINUE_UNWIND,
+ EHAction::Catch(_) => UnwindReasonCode::HANDLER_FOUND,
+ }
+ } else {
+ match eh_action {
+ EHAction::None => UnwindReasonCode::CONTINUE_UNWIND,
+ EHAction::Cleanup(lpad) | EHAction::Catch(lpad) => {
+ _Unwind_SetGR(
+ unwind_ctx,
+ Arch::UNWIND_DATA_REG.0 .0 as _,
+ exception as usize,
+ );
+ _Unwind_SetGR(unwind_ctx, Arch::UNWIND_DATA_REG.1 .0 as _, 0);
+ _Unwind_SetIP(unwind_ctx, lpad);
+ UnwindReasonCode::INSTALL_CONTEXT
+ }
+ }
+ }
+}
diff --git a/vendor/unwinding/src/personality_dummy.rs b/vendor/unwinding/src/personality_dummy.rs
new file mode 100644
index 000000000..ff026c7b9
--- /dev/null
+++ b/vendor/unwinding/src/personality_dummy.rs
@@ -0,0 +1,16 @@
+use crate::abi::*;
+use crate::util::*;
+
+#[lang = "eh_personality"]
+unsafe extern "C" fn personality(
+ version: c_int,
+ _actions: UnwindAction,
+ _exception_class: u64,
+ _exception: *mut UnwindException,
+ _ctx: &mut UnwindContext<'_>,
+) -> UnwindReasonCode {
+ if version != 1 {
+ return UnwindReasonCode::FATAL_PHASE1_ERROR;
+ }
+ UnwindReasonCode::CONTINUE_UNWIND
+}
diff --git a/vendor/unwinding/src/print.rs b/vendor/unwinding/src/print.rs
new file mode 100644
index 000000000..fc6d9ac63
--- /dev/null
+++ b/vendor/unwinding/src/print.rs
@@ -0,0 +1,70 @@
+pub use crate::{eprint, eprintln, print, println};
+
+#[doc(hidden)]
+pub struct StdoutPrinter;
+impl core::fmt::Write for StdoutPrinter {
+ fn write_str(&mut self, s: &str) -> core::fmt::Result {
+ unsafe { libc::printf(b"%.*s\0".as_ptr() as _, s.len() as i32, s.as_ptr()) };
+ Ok(())
+ }
+}
+
+#[doc(hidden)]
+pub struct StderrPrinter;
+impl core::fmt::Write for StderrPrinter {
+ fn write_str(&mut self, s: &str) -> core::fmt::Result {
+ unsafe { libc::write(libc::STDERR_FILENO, s.as_ptr() as _, s.len() as _) };
+ Ok(())
+ }
+}
+
+#[macro_export]
+macro_rules! println {
+ ($($arg:tt)*) => ({
+ use core::fmt::Write;
+ let _ = core::writeln!($crate::print::StdoutPrinter, $($arg)*);
+ })
+}
+
+#[macro_export]
+macro_rules! print {
+ ($($arg:tt)*) => ({
+ use core::fmt::Write;
+ let _ = core::write!($crate::print::StdoutPrinter, $($arg)*);
+ })
+}
+
+#[macro_export]
+macro_rules! eprintln {
+ ($($arg:tt)*) => ({
+ use core::fmt::Write;
+ let _ = core::writeln!($crate::print::StderrPrinter, $($arg)*);
+ })
+}
+
+#[macro_export]
+macro_rules! eprint {
+ ($($arg:tt)*) => ({
+ use core::fmt::Write;
+ let _ = core::write!($crate::print::StderrPrinter, $($arg)*);
+ })
+}
+
+#[macro_export]
+macro_rules! dbg {
+ () => {
+ $crate::eprintln!("[{}:{}]", ::core::file!(), ::core::line!())
+ };
+ ($val:expr $(,)?) => {
+ match $val {
+ tmp => {
+ $crate::eprintln!("[{}:{}] {} = {:#?}",
+ ::core::file!(), ::core::line!(), ::core::stringify!($val), &tmp);
+ tmp
+ }
+ }
+ };
+ ($($val:expr),+ $(,)?) => {
+ ($($crate::dbg!($val)),+,)
+ };
+}
diff --git a/vendor/unwinding/src/system_alloc.rs b/vendor/unwinding/src/system_alloc.rs
new file mode 100644
index 000000000..51e8bdbf0
--- /dev/null
+++ b/vendor/unwinding/src/system_alloc.rs
@@ -0,0 +1,63 @@
+use core::alloc::{GlobalAlloc, Layout};
+use core::{cmp, mem, ptr};
+
+pub struct System;
+
+const MIN_ALIGN: usize = mem::size_of::<usize>() * 2;
+
+// Taken std
+unsafe impl GlobalAlloc for System {
+ #[inline]
+ unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+ if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
+ unsafe { libc::malloc(layout.size()) as *mut u8 }
+ } else {
+ let mut out = ptr::null_mut();
+ let align = layout.align().max(mem::size_of::<usize>());
+ let ret = unsafe { libc::posix_memalign(&mut out, align, layout.size()) };
+ if ret != 0 {
+ ptr::null_mut()
+ } else {
+ out as *mut u8
+ }
+ }
+ }
+
+ #[inline]
+ unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
+ if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
+ unsafe { libc::calloc(layout.size(), 1) as *mut u8 }
+ } else {
+ let ptr = unsafe { self.alloc(layout) };
+ if !ptr.is_null() {
+ unsafe { ptr::write_bytes(ptr, 0, layout.size()) };
+ }
+ ptr
+ }
+ }
+
+ #[inline]
+ unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
+ unsafe { libc::free(ptr as *mut libc::c_void) }
+ }
+
+ #[inline]
+ unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
+ if layout.align() <= MIN_ALIGN && layout.align() <= new_size {
+ unsafe { libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8 }
+ } else {
+ let new_layout = unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) };
+
+ let new_ptr = unsafe { self.alloc(new_layout) };
+ if !new_ptr.is_null() {
+ let size = cmp::min(layout.size(), new_size);
+ unsafe { ptr::copy_nonoverlapping(ptr, new_ptr, size) };
+ unsafe { self.dealloc(ptr, layout) };
+ }
+ new_ptr
+ }
+ }
+}
+
+#[global_allocator]
+pub static GLOBAL: System = System;
diff --git a/vendor/unwinding/src/unwinder/arch/aarch64.rs b/vendor/unwinding/src/unwinder/arch/aarch64.rs
new file mode 100644
index 000000000..f65332cc4
--- /dev/null
+++ b/vendor/unwinding/src/unwinder/arch/aarch64.rs
@@ -0,0 +1,142 @@
+use core::arch::asm;
+use core::fmt;
+use core::ops;
+use gimli::{AArch64, Register};
+
+// Match DWARF_FRAME_REGISTERS in libgcc
+pub const MAX_REG_RULES: usize = 97;
+
+#[repr(C)]
+#[derive(Clone, Default)]
+pub struct Context {
+ pub gp: [usize; 31],
+ pub sp: usize,
+ pub fp: [usize; 32],
+}
+
+impl fmt::Debug for Context {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut fmt = fmt.debug_struct("Context");
+ for i in 0..=30 {
+ fmt.field(
+ AArch64::register_name(Register(i as _)).unwrap(),
+ &self.gp[i],
+ );
+ }
+ fmt.field("sp", &self.sp);
+ for i in 0..=31 {
+ fmt.field(
+ AArch64::register_name(Register((i + 64) as _)).unwrap(),
+ &self.fp[i],
+ );
+ }
+ fmt.finish()
+ }
+}
+
+impl ops::Index<Register> for Context {
+ type Output = usize;
+
+ fn index(&self, reg: Register) -> &usize {
+ match reg {
+ Register(0..=30) => &self.gp[reg.0 as usize],
+ AArch64::SP => &self.sp,
+ Register(64..=95) => &self.fp[(reg.0 - 64) as usize],
+ _ => unimplemented!(),
+ }
+ }
+}
+
+impl ops::IndexMut<gimli::Register> for Context {
+ fn index_mut(&mut self, reg: Register) -> &mut usize {
+ match reg {
+ Register(0..=30) => &mut self.gp[reg.0 as usize],
+ AArch64::SP => &mut self.sp,
+ Register(64..=95) => &mut self.fp[(reg.0 - 64) as usize],
+ _ => unimplemented!(),
+ }
+ }
+}
+
+#[naked]
+pub extern "C-unwind" fn save_context(f: extern "C" fn(&mut Context, *mut ()), ptr: *mut ()) {
+ // No need to save caller-saved registers here.
+ unsafe {
+ asm!(
+ "
+ stp x29, x30, [sp, -16]!
+ sub sp, sp, 512
+ mov x8, x0
+ mov x0, sp
+
+ stp d8, d9, [sp, 0x140]
+ stp d10, d11, [sp, 0x150]
+ stp d12, d13, [sp, 0x160]
+ stp d14, d15, [sp, 0x170]
+
+ str x19, [sp, 0x98]
+ stp x20, x21, [sp, 0xA0]
+ stp x22, x23, [sp, 0xB0]
+ stp x24, x25, [sp, 0xC0]
+ stp x26, x27, [sp, 0xD0]
+ stp x28, x29, [sp, 0xE0]
+ add x2, sp, 528
+ stp x30, x2, [sp, 0xF0]
+
+ blr x8
+
+ add sp, sp, 512
+ ldp x29, x30, [sp], 16
+ ret
+ ",
+ options(noreturn)
+ );
+ }
+}
+
+#[naked]
+pub unsafe extern "C" fn restore_context(ctx: &Context) -> ! {
+ unsafe {
+ asm!(
+ "
+ ldp d0, d1, [x0, 0x100]
+ ldp d2, d3, [x0, 0x110]
+ ldp d4, d5, [x0, 0x120]
+ ldp d6, d7, [x0, 0x130]
+ ldp d8, d9, [x0, 0x140]
+ ldp d10, d11, [x0, 0x150]
+ ldp d12, d13, [x0, 0x160]
+ ldp d14, d15, [x0, 0x170]
+ ldp d16, d17, [x0, 0x180]
+ ldp d18, d19, [x0, 0x190]
+ ldp d20, d21, [x0, 0x1A0]
+ ldp d22, d23, [x0, 0x1B0]
+ ldp d24, d25, [x0, 0x1C0]
+ ldp d26, d27, [x0, 0x1D0]
+ ldp d28, d29, [x0, 0x1E0]
+ ldp d30, d31, [x0, 0x1F0]
+
+ ldp x2, x3, [x0, 0x10]
+ ldp x4, x5, [x0, 0x20]
+ ldp x6, x7, [x0, 0x30]
+ ldp x8, x9, [x0, 0x40]
+ ldp x10, x11, [x0, 0x50]
+ ldp x12, x13, [x0, 0x60]
+ ldp x14, x15, [x0, 0x70]
+ ldp x16, x17, [x0, 0x80]
+ ldp x18, x19, [x0, 0x90]
+ ldp x20, x21, [x0, 0xA0]
+ ldp x22, x23, [x0, 0xB0]
+ ldp x24, x25, [x0, 0xC0]
+ ldp x26, x27, [x0, 0xD0]
+ ldp x28, x29, [x0, 0xE0]
+ ldp x30, x1, [x0, 0xF0]
+ mov sp, x1
+
+ ldp x0, x1, [x0, 0x00]
+ ret
+ ",
+ options(noreturn)
+ );
+ }
+}
diff --git a/vendor/unwinding/src/unwinder/arch/mod.rs b/vendor/unwinding/src/unwinder/arch/mod.rs
new file mode 100644
index 000000000..815835358
--- /dev/null
+++ b/vendor/unwinding/src/unwinder/arch/mod.rs
@@ -0,0 +1,33 @@
+#[cfg(target_arch = "x86_64")]
+mod x86_64;
+#[cfg(target_arch = "x86_64")]
+pub use x86_64::*;
+
+#[cfg(target_arch = "x86")]
+mod x86;
+#[cfg(target_arch = "x86")]
+pub use x86::*;
+
+#[cfg(target_arch = "riscv64")]
+mod riscv64;
+#[cfg(target_arch = "riscv64")]
+pub use riscv64::*;
+
+#[cfg(target_arch = "riscv32")]
+mod riscv32;
+#[cfg(target_arch = "riscv32")]
+pub use riscv32::*;
+
+#[cfg(target_arch = "aarch64")]
+mod aarch64;
+#[cfg(target_arch = "aarch64")]
+pub use aarch64::*;
+
+#[cfg(not(any(
+ target_arch = "x86_64",
+ target_arch = "x86",
+ target_arch = "riscv64",
+ target_arch = "riscv32",
+ target_arch = "aarch64"
+)))]
+compile_error!("Current architecture is not supported");
diff --git a/vendor/unwinding/src/unwinder/arch/riscv32.rs b/vendor/unwinding/src/unwinder/arch/riscv32.rs
new file mode 100644
index 000000000..1e8709e2c
--- /dev/null
+++ b/vendor/unwinding/src/unwinder/arch/riscv32.rs
@@ -0,0 +1,242 @@
+use core::arch::asm;
+use core::fmt;
+use core::ops;
+use gimli::{Register, RiscV};
+
+// Match DWARF_FRAME_REGISTERS in libgcc
+pub const MAX_REG_RULES: usize = 65;
+
+#[cfg(all(target_feature = "f", not(target_feature = "d")))]
+compile_error!("RISC-V with only F extension is not supported");
+
+#[repr(C)]
+#[derive(Clone, Default)]
+pub struct Context {
+ pub gp: [usize; 32],
+ #[cfg(target_feature = "d")]
+ pub fp: [u64; 32],
+}
+
+impl fmt::Debug for Context {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut fmt = fmt.debug_struct("Context");
+ for i in 0..=31 {
+ fmt.field(RiscV::register_name(Register(i as _)).unwrap(), &self.gp[i]);
+ }
+ #[cfg(target_feature = "d")]
+ for i in 0..=31 {
+ fmt.field(
+ RiscV::register_name(Register((i + 32) as _)).unwrap(),
+ &self.fp[i],
+ );
+ }
+ fmt.finish()
+ }
+}
+
+impl ops::Index<Register> for Context {
+ type Output = usize;
+
+ fn index(&self, reg: Register) -> &usize {
+ match reg {
+ Register(0..=31) => &self.gp[reg.0 as usize],
+ // We cannot support indexing fp here. It is 64-bit if D extension is implemented,
+ // and 32-bit if only F extension is implemented.
+ _ => unimplemented!(),
+ }
+ }
+}
+
+impl ops::IndexMut<gimli::Register> for Context {
+ fn index_mut(&mut self, reg: Register) -> &mut usize {
+ match reg {
+ Register(0..=31) => &mut self.gp[reg.0 as usize],
+ // We cannot support indexing fp here. It is 64-bit if D extension is implemented,
+ // and 32-bit if only F extension is implemented.
+ _ => unimplemented!(),
+ }
+ }
+}
+
+macro_rules! code {
+ (save_gp) => {
+ "
+ sw x0, 0x00(sp)
+ sw ra, 0x04(sp)
+ sw t0, 0x08(sp)
+ sw gp, 0x0C(sp)
+ sw tp, 0x10(sp)
+ sw s0, 0x20(sp)
+ sw s1, 0x24(sp)
+ sw s2, 0x48(sp)
+ sw s3, 0x4C(sp)
+ sw s4, 0x50(sp)
+ sw s5, 0x54(sp)
+ sw s6, 0x58(sp)
+ sw s7, 0x5C(sp)
+ sw s8, 0x60(sp)
+ sw s9, 0x64(sp)
+ sw s10, 0x68(sp)
+ sw s11, 0x6C(sp)
+ "
+ };
+ (save_fp) => {
+ "
+ fsd fs0, 0xC0(sp)
+ fsd fs1, 0xC8(sp)
+ fsd fs2, 0x110(sp)
+ fsd fs3, 0x118(sp)
+ fsd fs4, 0x120(sp)
+ fsd fs5, 0x128(sp)
+ fsd fs6, 0x130(sp)
+ fsd fs7, 0x138(sp)
+ fsd fs8, 0x140(sp)
+ fsd fs9, 0x148(sp)
+ fsd fs10, 0x150(sp)
+ fsd fs11, 0x158(sp)
+ "
+ };
+ (restore_gp) => {
+ "
+ lw ra, 0x04(a0)
+ lw sp, 0x08(a0)
+ lw gp, 0x0C(a0)
+ lw tp, 0x10(a0)
+ lw t0, 0x14(a0)
+ lw t1, 0x18(a0)
+ lw t2, 0x1C(a0)
+ lw s0, 0x20(a0)
+ lw s1, 0x24(a0)
+ lw a1, 0x2C(a0)
+ lw a2, 0x30(a0)
+ lw a3, 0x34(a0)
+ lw a4, 0x38(a0)
+ lw a5, 0x3C(a0)
+ lw a6, 0x40(a0)
+ lw a7, 0x44(a0)
+ lw s2, 0x48(a0)
+ lw s3, 0x4C(a0)
+ lw s4, 0x50(a0)
+ lw s5, 0x54(a0)
+ lw s6, 0x58(a0)
+ lw s7, 0x5C(a0)
+ lw s8, 0x60(a0)
+ lw s9, 0x64(a0)
+ lw s10, 0x68(a0)
+ lw s11, 0x6C(a0)
+ lw t3, 0x70(a0)
+ lw t4, 0x74(a0)
+ lw t5, 0x78(a0)
+ lw t6, 0x7C(a0)
+ "
+ };
+ (restore_fp) => {
+ "
+ fld ft0, 0x80(a0)
+ fld ft1, 0x88(a0)
+ fld ft2, 0x90(a0)
+ fld ft3, 0x98(a0)
+ fld ft4, 0xA0(a0)
+ fld ft5, 0xA8(a0)
+ fld ft6, 0xB0(a0)
+ fld ft7, 0xB8(a0)
+ fld fs0, 0xC0(a0)
+ fld fs1, 0xC8(a0)
+ fld fa0, 0xD0(a0)
+ fld fa1, 0xD8(a0)
+ fld fa2, 0xE0(a0)
+ fld fa3, 0xE8(a0)
+ fld fa4, 0xF0(a0)
+ fld fa5, 0xF8(a0)
+ fld fa6, 0x100(a0)
+ fld fa7, 0x108(a0)
+ fld fs2, 0x110(a0)
+ fld fs3, 0x118(a0)
+ fld fs4, 0x120(a0)
+ fld fs5, 0x128(a0)
+ fld fs6, 0x130(a0)
+ fld fs7, 0x138(a0)
+ fld fs8, 0x140(a0)
+ fld fs9, 0x148(a0)
+ fld fs10, 0x150(a0)
+ fld fs11, 0x158(a0)
+ fld ft8, 0x160(a0)
+ fld ft9, 0x168(a0)
+ fld ft10, 0x170(a0)
+ fld ft11, 0x178(a0)
+ "
+ };
+}
+
+#[naked]
+pub extern "C-unwind" fn save_context(f: extern "C" fn(&mut Context, *mut ()), ptr: *mut ()) {
+ // No need to save caller-saved registers here.
+ #[cfg(target_feature = "d")]
+ unsafe {
+ asm!(
+ "
+ mv t0, sp
+ add sp, sp, -0x188
+ sw ra, 0x180(sp)
+ ",
+ code!(save_gp),
+ code!(save_fp),
+ "
+ mv t0, a0
+ mv a0, sp
+ jalr t0
+ lw ra, 0x180(sp)
+ add sp, sp, 0x188
+ ret
+ ",
+ options(noreturn)
+ );
+ }
+ #[cfg(not(target_feature = "d"))]
+ unsafe {
+ asm!(
+ "
+ mv t0, sp
+ add sp, sp, -0x88
+ sw ra, 0x80(sp)
+ ",
+ code!(save_gp),
+ "
+ mv t0, a0
+ mv a0, sp
+ jalr t0
+ lw ra, 0x80(sp)
+ add sp, sp, 0x88
+ ret
+ ",
+ options(noreturn)
+ );
+ }
+}
+
+#[naked]
+pub unsafe extern "C" fn restore_context(ctx: &Context) -> ! {
+ #[cfg(target_feature = "d")]
+ unsafe {
+ asm!(
+ code!(restore_fp),
+ code!(restore_gp),
+ "
+ lw a0, 0x28(a0)
+ ret
+ ",
+ options(noreturn)
+ );
+ }
+ #[cfg(not(target_feature = "d"))]
+ unsafe {
+ asm!(
+ code!(restore_gp),
+ "
+ lw a0, 0x28(a0)
+ ret
+ ",
+ options(noreturn)
+ );
+ }
+}
diff --git a/vendor/unwinding/src/unwinder/arch/riscv64.rs b/vendor/unwinding/src/unwinder/arch/riscv64.rs
new file mode 100644
index 000000000..a680d7057
--- /dev/null
+++ b/vendor/unwinding/src/unwinder/arch/riscv64.rs
@@ -0,0 +1,242 @@
+use core::arch::asm;
+use core::fmt;
+use core::ops;
+use gimli::{Register, RiscV};
+
+// Match DWARF_FRAME_REGISTERS in libgcc
+pub const MAX_REG_RULES: usize = 65;
+
+#[cfg(all(target_feature = "f", not(target_feature = "d")))]
+compile_error!("RISC-V with only F extension is not supported");
+
+#[repr(C)]
+#[derive(Clone, Default)]
+pub struct Context {
+ pub gp: [usize; 32],
+ #[cfg(target_feature = "d")]
+ pub fp: [usize; 32],
+}
+
+impl fmt::Debug for Context {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut fmt = fmt.debug_struct("Context");
+ for i in 0..=31 {
+ fmt.field(RiscV::register_name(Register(i as _)).unwrap(), &self.gp[i]);
+ }
+ #[cfg(target_feature = "d")]
+ for i in 0..=31 {
+ fmt.field(
+ RiscV::register_name(Register((i + 32) as _)).unwrap(),
+ &self.fp[i],
+ );
+ }
+ fmt.finish()
+ }
+}
+
+impl ops::Index<Register> for Context {
+ type Output = usize;
+
+ fn index(&self, reg: Register) -> &usize {
+ match reg {
+ Register(0..=31) => &self.gp[reg.0 as usize],
+ #[cfg(target_feature = "d")]
+ Register(32..=63) => &self.fp[(reg.0 - 32) as usize],
+ _ => unimplemented!(),
+ }
+ }
+}
+
+impl ops::IndexMut<gimli::Register> for Context {
+ fn index_mut(&mut self, reg: Register) -> &mut usize {
+ match reg {
+ Register(0..=31) => &mut self.gp[reg.0 as usize],
+ #[cfg(target_feature = "d")]
+ Register(32..=63) => &mut self.fp[(reg.0 - 32) as usize],
+ _ => unimplemented!(),
+ }
+ }
+}
+
+macro_rules! code {
+ (save_gp) => {
+ "
+ sd x0, 0x00(sp)
+ sd ra, 0x08(sp)
+ sd t0, 0x10(sp)
+ sd gp, 0x18(sp)
+ sd tp, 0x20(sp)
+ sd s0, 0x40(sp)
+ sd s1, 0x48(sp)
+ sd s2, 0x90(sp)
+ sd s3, 0x98(sp)
+ sd s4, 0xA0(sp)
+ sd s5, 0xA8(sp)
+ sd s6, 0xB0(sp)
+ sd s7, 0xB8(sp)
+ sd s8, 0xC0(sp)
+ sd s9, 0xC8(sp)
+ sd s10, 0xD0(sp)
+ sd s11, 0xD8(sp)
+ "
+ };
+ (save_fp) => {
+ "
+ fsd fs0, 0x140(sp)
+ fsd fs1, 0x148(sp)
+ fsd fs2, 0x190(sp)
+ fsd fs3, 0x198(sp)
+ fsd fs4, 0x1A0(sp)
+ fsd fs5, 0x1A8(sp)
+ fsd fs6, 0x1B0(sp)
+ fsd fs7, 0x1B8(sp)
+ fsd fs8, 0x1C0(sp)
+ fsd fs9, 0x1C8(sp)
+ fsd fs10, 0x1D0(sp)
+ fsd fs11, 0x1D8(sp)
+ "
+ };
+ (restore_gp) => {
+ "
+ ld ra, 0x08(a0)
+ ld sp, 0x10(a0)
+ ld gp, 0x18(a0)
+ ld tp, 0x20(a0)
+ ld t0, 0x28(a0)
+ ld t1, 0x30(a0)
+ ld t2, 0x38(a0)
+ ld s0, 0x40(a0)
+ ld s1, 0x48(a0)
+ ld a1, 0x58(a0)
+ ld a2, 0x60(a0)
+ ld a3, 0x68(a0)
+ ld a4, 0x70(a0)
+ ld a5, 0x78(a0)
+ ld a6, 0x80(a0)
+ ld a7, 0x88(a0)
+ ld s2, 0x90(a0)
+ ld s3, 0x98(a0)
+ ld s4, 0xA0(a0)
+ ld s5, 0xA8(a0)
+ ld s6, 0xB0(a0)
+ ld s7, 0xB8(a0)
+ ld s8, 0xC0(a0)
+ ld s9, 0xC8(a0)
+ ld s10, 0xD0(a0)
+ ld s11, 0xD8(a0)
+ ld t3, 0xE0(a0)
+ ld t4, 0xE8(a0)
+ ld t5, 0xF0(a0)
+ ld t6, 0xF8(a0)
+ "
+ };
+ (restore_fp) => {
+ "
+ fld ft0, 0x100(a0)
+ fld ft1, 0x108(a0)
+ fld ft2, 0x110(a0)
+ fld ft3, 0x118(a0)
+ fld ft4, 0x120(a0)
+ fld ft5, 0x128(a0)
+ fld ft6, 0x130(a0)
+ fld ft7, 0x138(a0)
+ fld fs0, 0x140(a0)
+ fld fs1, 0x148(a0)
+ fld fa0, 0x150(a0)
+ fld fa1, 0x158(a0)
+ fld fa2, 0x160(a0)
+ fld fa3, 0x168(a0)
+ fld fa4, 0x170(a0)
+ fld fa5, 0x178(a0)
+ fld fa6, 0x180(a0)
+ fld fa7, 0x188(a0)
+ fld fs2, 0x190(a0)
+ fld fs3, 0x198(a0)
+ fld fs4, 0x1A0(a0)
+ fld fs5, 0x1A8(a0)
+ fld fs6, 0x1B0(a0)
+ fld fs7, 0x1B8(a0)
+ fld fs8, 0x1C0(a0)
+ fld fs9, 0x1C8(a0)
+ fld fs10, 0x1D0(a0)
+ fld fs11, 0x1D8(a0)
+ fld ft8, 0x1E0(a0)
+ fld ft9, 0x1E8(a0)
+ fld ft10, 0x1F0(a0)
+ fld ft11, 0x1F8(a0)
+ "
+ };
+}
+
+#[naked]
+pub extern "C-unwind" fn save_context(f: extern "C" fn(&mut Context, *mut ()), ptr: *mut ()) {
+ // No need to save caller-saved registers here.
+ #[cfg(target_feature = "d")]
+ unsafe {
+ asm!(
+ "
+ mv t0, sp
+ add sp, sp, -0x210
+ sd ra, 0x200(sp)
+ ",
+ code!(save_gp),
+ code!(save_fp),
+ "
+ mv t0, a0
+ mv a0, sp
+ jalr t0
+ ld ra, 0x200(sp)
+ add sp, sp, 0x210
+ ret
+ ",
+ options(noreturn)
+ );
+ }
+ #[cfg(not(target_feature = "d"))]
+ unsafe {
+ asm!(
+ "
+ mv t0, sp
+ add sp, sp, -0x110
+ sd ra, 0x100(sp)
+ ",
+ code!(save_gp),
+ "
+ mv t0, a0
+ mv a0, sp
+ jalr t0
+ ld ra, 0x100(sp)
+ add sp, sp, 0x110
+ ret
+ ",
+ options(noreturn)
+ );
+ }
+}
+
+#[naked]
+pub unsafe extern "C" fn restore_context(ctx: &Context) -> ! {
+ #[cfg(target_feature = "d")]
+ unsafe {
+ asm!(
+ code!(restore_fp),
+ code!(restore_gp),
+ "
+ ld a0, 0x50(a0)
+ ret
+ ",
+ options(noreturn)
+ );
+ }
+ #[cfg(not(target_feature = "d"))]
+ unsafe {
+ asm!(
+ code!(restore_gp),
+ "
+ ld a0, 0x50(a0)
+ ret
+ ",
+ options(noreturn)
+ );
+ }
+}
diff --git a/vendor/unwinding/src/unwinder/arch/x86.rs b/vendor/unwinding/src/unwinder/arch/x86.rs
new file mode 100644
index 000000000..992afb66a
--- /dev/null
+++ b/vendor/unwinding/src/unwinder/arch/x86.rs
@@ -0,0 +1,136 @@
+use core::arch::asm;
+use core::fmt;
+use core::ops;
+use gimli::{Register, X86};
+
+// Match DWARF_FRAME_REGISTERS in libgcc
+pub const MAX_REG_RULES: usize = 17;
+
+#[repr(C)]
+#[derive(Clone, Default)]
+pub struct Context {
+ pub registers: [usize; 8],
+ pub ra: usize,
+ pub mcxsr: usize,
+ pub fcw: usize,
+}
+
+impl fmt::Debug for Context {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut fmt = fmt.debug_struct("Context");
+ for i in 0..=7 {
+ fmt.field(
+ X86::register_name(Register(i as _)).unwrap(),
+ &self.registers[i],
+ );
+ }
+ fmt.field("ra", &self.ra)
+ .field("mcxsr", &self.mcxsr)
+ .field("fcw", &self.fcw)
+ .finish()
+ }
+}
+
+impl ops::Index<Register> for Context {
+ type Output = usize;
+
+ fn index(&self, reg: Register) -> &usize {
+ match reg {
+ Register(0..=7) => &self.registers[reg.0 as usize],
+ X86::RA => &self.ra,
+ X86::MXCSR => &self.mcxsr,
+ _ => unimplemented!(),
+ }
+ }
+}
+
+impl ops::IndexMut<gimli::Register> for Context {
+ fn index_mut(&mut self, reg: Register) -> &mut usize {
+ match reg {
+ Register(0..=7) => &mut self.registers[reg.0 as usize],
+ X86::RA => &mut self.ra,
+ X86::MXCSR => &mut self.mcxsr,
+ _ => unimplemented!(),
+ }
+ }
+}
+
+#[naked]
+pub extern "C-unwind" fn save_context(f: extern "C" fn(&mut Context, *mut ()), ptr: *mut ()) {
+ // No need to save caller-saved registers here.
+ unsafe {
+ asm!(
+ "
+ sub esp, 52
+
+ mov [esp + 4], ecx
+ mov [esp + 8], edx
+ mov [esp + 12], ebx
+
+ /* Adjust the stack to account for the return address */
+ lea eax, [esp + 56]
+ mov [esp + 16], eax
+
+ mov [esp + 20], ebp
+ mov [esp + 24], esi
+ mov [esp + 28], edi
+
+ /* Return address */
+ mov eax, [esp + 52]
+ mov [esp + 32], eax
+
+ stmxcsr [esp + 36]
+ fnstcw [esp + 40]
+
+ mov eax, [esp + 60]
+ mov ecx, esp
+ push eax
+ push ecx
+ call [esp + 64]
+
+ add esp, 60
+ ret
+ ",
+ options(noreturn)
+ );
+ }
+}
+
+#[naked]
+pub unsafe extern "C" fn restore_context(ctx: &Context) -> ! {
+ unsafe {
+ asm!(
+ "
+ mov edx, [esp + 4]
+
+ /* Restore stack */
+ mov esp, [edx + 16]
+
+ /* Restore callee-saved control registers */
+ ldmxcsr [edx + 36]
+ fldcw [edx + 40]
+
+ /* Restore return address */
+ mov eax, [edx + 32]
+ push eax
+
+ /*
+ * Restore general-purpose registers. Non-callee-saved registers are
+ * also restored because sometimes it's used to pass unwind arguments.
+ */
+ mov eax, [edx + 0]
+ mov ecx, [edx + 4]
+ mov ebx, [edx + 12]
+ mov ebp, [edx + 20]
+ mov esi, [edx + 24]
+ mov edi, [edx + 28]
+
+ /* EDX restored last */
+ mov edx, [edx + 8]
+
+ ret
+ ",
+ options(noreturn)
+ );
+ }
+}
diff --git a/vendor/unwinding/src/unwinder/arch/x86_64.rs b/vendor/unwinding/src/unwinder/arch/x86_64.rs
new file mode 100644
index 000000000..43876865c
--- /dev/null
+++ b/vendor/unwinding/src/unwinder/arch/x86_64.rs
@@ -0,0 +1,140 @@
+use core::arch::asm;
+use core::fmt;
+use core::ops;
+use gimli::{Register, X86_64};
+
+// Match DWARF_FRAME_REGISTERS in libgcc
+pub const MAX_REG_RULES: usize = 17;
+
+#[repr(C)]
+#[derive(Clone, Default)]
+pub struct Context {
+ pub registers: [usize; 16],
+ pub ra: usize,
+ pub mcxsr: usize,
+ pub fcw: usize,
+}
+
+impl fmt::Debug for Context {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut fmt = fmt.debug_struct("Context");
+ for i in 0..=15 {
+ fmt.field(
+ X86_64::register_name(Register(i as _)).unwrap(),
+ &self.registers[i],
+ );
+ }
+ fmt.field("ra", &self.ra)
+ .field("mcxsr", &self.mcxsr)
+ .field("fcw", &self.fcw)
+ .finish()
+ }
+}
+
+impl ops::Index<Register> for Context {
+ type Output = usize;
+
+ fn index(&self, reg: Register) -> &usize {
+ match reg {
+ Register(0..=15) => &self.registers[reg.0 as usize],
+ X86_64::RA => &self.ra,
+ X86_64::MXCSR => &self.mcxsr,
+ X86_64::FCW => &self.fcw,
+ _ => unimplemented!(),
+ }
+ }
+}
+
+impl ops::IndexMut<gimli::Register> for Context {
+ fn index_mut(&mut self, reg: Register) -> &mut usize {
+ match reg {
+ Register(0..=15) => &mut self.registers[reg.0 as usize],
+ X86_64::RA => &mut self.ra,
+ X86_64::MXCSR => &mut self.mcxsr,
+ X86_64::FCW => &mut self.fcw,
+ _ => unimplemented!(),
+ }
+ }
+}
+
+#[naked]
+pub extern "C-unwind" fn save_context(f: extern "C" fn(&mut Context, *mut ()), ptr: *mut ()) {
+ // No need to save caller-saved registers here.
+ unsafe {
+ asm!(
+ "
+ sub rsp, 0x98
+ mov [rsp + 0x18], rbx
+ mov [rsp + 0x30], rbp
+
+ /* Adjust the stack to account for the return address */
+ lea rax, [rsp + 0xA0]
+ mov [rsp + 0x38], rax
+
+ mov [rsp + 0x60], r12
+ mov [rsp + 0x68], r13
+ mov [rsp + 0x70], r14
+ mov [rsp + 0x78], r15
+
+ /* Return address */
+ mov rax, [rsp + 0x98]
+ mov [rsp + 0x80], rax
+
+ stmxcsr [rsp + 0x88]
+ fnstcw [rsp + 0x90]
+
+ mov rax, rdi
+ mov rdi, rsp
+ call rax
+ add rsp, 0x98
+ ret
+ ",
+ options(noreturn)
+ );
+ }
+}
+
+#[naked]
+pub unsafe extern "C" fn restore_context(ctx: &Context) -> ! {
+ unsafe {
+ asm!(
+ "
+ /* Restore stack */
+ mov rsp, [rdi + 0x38]
+
+ /* Restore callee-saved control registers */
+ ldmxcsr [rdi + 0x88]
+ fldcw [rdi + 0x90]
+
+ /* Restore return address */
+ mov rax, [rdi + 0x80]
+ push rax
+
+ /*
+ * Restore general-purpose registers. Non-callee-saved registers are
+ * also restored because sometimes it's used to pass unwind arguments.
+ */
+ mov rax, [rdi + 0x00]
+ mov rdx, [rdi + 0x08]
+ mov rcx, [rdi + 0x10]
+ mov rbx, [rdi + 0x18]
+ mov rsi, [rdi + 0x20]
+ mov rbp, [rdi + 0x30]
+ mov r8 , [rdi + 0x40]
+ mov r9 , [rdi + 0x48]
+ mov r10, [rdi + 0x50]
+ mov r11, [rdi + 0x58]
+ mov r12, [rdi + 0x60]
+ mov r13, [rdi + 0x68]
+ mov r14, [rdi + 0x70]
+ mov r15, [rdi + 0x78]
+
+ /* RDI restored last */
+ mov rdi, [rdi + 0x28]
+
+ ret
+ ",
+ options(noreturn)
+ );
+ }
+}
diff --git a/vendor/unwinding/src/unwinder/find_fde/custom.rs b/vendor/unwinding/src/unwinder/find_fde/custom.rs
new file mode 100644
index 000000000..25da562db
--- /dev/null
+++ b/vendor/unwinding/src/unwinder/find_fde/custom.rs
@@ -0,0 +1,171 @@
+use super::{FDEFinder, FDESearchResult};
+use crate::util::{deref_pointer, get_unlimited_slice};
+
+use core::sync::atomic::{AtomicU32, Ordering};
+use gimli::{BaseAddresses, EhFrame, EhFrameHdr, NativeEndian, UnwindSection};
+
+pub(crate) struct CustomFinder(());
+
+pub(crate) fn get_finder() -> &'static CustomFinder {
+ &CustomFinder(())
+}
+
+impl FDEFinder for CustomFinder {
+ fn find_fde(&self, pc: usize) -> Option<FDESearchResult> {
+ get_custom_eh_frame_finder().and_then(|eh_frame_finder| find_fde(eh_frame_finder, pc))
+ }
+}
+
+/// A trait for types whose values can be used as the global EH frame finder set by [`set_custom_eh_frame_finder`].
+pub unsafe trait EhFrameFinder {
+ fn find(&self, pc: usize) -> Option<FrameInfo>;
+}
+
+pub struct FrameInfo {
+ pub text_base: Option<usize>,
+ pub kind: FrameInfoKind,
+}
+
+pub enum FrameInfoKind {
+ EhFrameHdr(usize),
+ EhFrame(usize),
+}
+
+static mut CUSTOM_EH_FRAME_FINDER: Option<&(dyn EhFrameFinder + Sync)> = None;
+
+static CUSTOM_EH_FRAME_FINDER_STATE: AtomicU32 = AtomicU32::new(UNINITIALIZED);
+
+const UNINITIALIZED: u32 = 0;
+const INITIALIZING: u32 = 1;
+const INITIALIZED: u32 = 2;
+
+/// The type returned by [`set_custom_eh_frame_finder`] if [`set_custom_eh_frame_finder`] has
+/// already been called.
+#[derive(Debug)]
+pub struct SetCustomEhFrameFinderError(());
+
+/// Sets the global EH frame finder.
+///
+/// This function should only be called once during the lifetime of the program.
+///
+/// # Errors
+///
+/// An error is returned if this function has already been called during the lifetime of the
+/// program.
+pub fn set_custom_eh_frame_finder(
+ fde_finder: &'static (dyn EhFrameFinder + Sync),
+) -> Result<(), SetCustomEhFrameFinderError> {
+ match CUSTOM_EH_FRAME_FINDER_STATE.compare_exchange(
+ UNINITIALIZED,
+ INITIALIZING,
+ Ordering::SeqCst,
+ Ordering::SeqCst,
+ ) {
+ Ok(UNINITIALIZED) => {
+ unsafe {
+ CUSTOM_EH_FRAME_FINDER = Some(fde_finder);
+ }
+ CUSTOM_EH_FRAME_FINDER_STATE.store(INITIALIZED, Ordering::SeqCst);
+ Ok(())
+ }
+ Err(INITIALIZING) => {
+ while CUSTOM_EH_FRAME_FINDER_STATE.load(Ordering::SeqCst) == INITIALIZING {
+ core::hint::spin_loop();
+ }
+ Err(SetCustomEhFrameFinderError(()))
+ }
+ Err(INITIALIZED) => Err(SetCustomEhFrameFinderError(())),
+ _ => {
+ unreachable!()
+ }
+ }
+}
+
+fn get_custom_eh_frame_finder() -> Option<&'static dyn EhFrameFinder> {
+ if CUSTOM_EH_FRAME_FINDER_STATE.load(Ordering::SeqCst) == INITIALIZED {
+ Some(unsafe { CUSTOM_EH_FRAME_FINDER.unwrap() })
+ } else {
+ None
+ }
+}
+
+fn find_fde<T: EhFrameFinder + ?Sized>(eh_frame_finder: &T, pc: usize) -> Option<FDESearchResult> {
+ let info = eh_frame_finder.find(pc)?;
+ let text_base = info.text_base;
+ match info.kind {
+ FrameInfoKind::EhFrameHdr(eh_frame_hdr) => {
+ find_fde_with_eh_frame_hdr(pc, text_base, eh_frame_hdr)
+ }
+ FrameInfoKind::EhFrame(eh_frame) => find_fde_with_eh_frame(pc, text_base, eh_frame),
+ }
+}
+
+fn find_fde_with_eh_frame_hdr(
+ pc: usize,
+ text_base: Option<usize>,
+ eh_frame_hdr: usize,
+) -> Option<FDESearchResult> {
+ unsafe {
+ let mut bases = BaseAddresses::default().set_eh_frame_hdr(eh_frame_hdr as _);
+ if let Some(text_base) = text_base {
+ bases = bases.set_text(text_base as _);
+ }
+ let eh_frame_hdr = EhFrameHdr::new(
+ get_unlimited_slice(eh_frame_hdr as usize as _),
+ NativeEndian,
+ )
+ .parse(&bases, core::mem::size_of::<usize>() as _)
+ .ok()?;
+ let eh_frame = deref_pointer(eh_frame_hdr.eh_frame_ptr());
+ let bases = bases.set_eh_frame(eh_frame as _);
+ let eh_frame = EhFrame::new(get_unlimited_slice(eh_frame as _), NativeEndian);
+
+ // Use binary search table for address if available.
+ if let Some(table) = eh_frame_hdr.table() {
+ if let Ok(fde) =
+ table.fde_for_address(&eh_frame, &bases, pc as _, EhFrame::cie_from_offset)
+ {
+ return Some(FDESearchResult {
+ fde,
+ bases,
+ eh_frame,
+ });
+ }
+ }
+
+ // Otherwise do the linear search.
+ if let Ok(fde) = eh_frame.fde_for_address(&bases, pc as _, EhFrame::cie_from_offset) {
+ return Some(FDESearchResult {
+ fde,
+ bases,
+ eh_frame,
+ });
+ }
+
+ None
+ }
+}
+
+fn find_fde_with_eh_frame(
+ pc: usize,
+ text_base: Option<usize>,
+ eh_frame: usize,
+) -> Option<FDESearchResult> {
+ unsafe {
+ let mut bases = BaseAddresses::default().set_eh_frame(eh_frame as _);
+ if let Some(text_base) = text_base {
+ bases = bases.set_text(text_base as _);
+ }
+ let eh_frame = EhFrame::new(get_unlimited_slice(eh_frame as _), NativeEndian);
+
+ if let Ok(fde) = eh_frame.fde_for_address(&bases, pc as _, EhFrame::cie_from_offset) {
+ return Some(FDESearchResult {
+ fde,
+ bases,
+ eh_frame,
+ });
+ }
+
+ None
+ }
+}
diff --git a/vendor/unwinding/src/unwinder/find_fde/fixed.rs b/vendor/unwinding/src/unwinder/find_fde/fixed.rs
new file mode 100644
index 000000000..c9d619379
--- /dev/null
+++ b/vendor/unwinding/src/unwinder/find_fde/fixed.rs
@@ -0,0 +1,44 @@
+use super::FDESearchResult;
+use crate::util::*;
+
+use gimli::{BaseAddresses, EhFrame, NativeEndian, UnwindSection};
+
+pub struct StaticFinder(());
+
+pub fn get_finder() -> &'static StaticFinder {
+ &StaticFinder(())
+}
+
+extern "C" {
+ static __executable_start: u8;
+ static __etext: u8;
+ static __eh_frame: u8;
+}
+
+impl super::FDEFinder for StaticFinder {
+ fn find_fde(&self, pc: usize) -> Option<FDESearchResult> {
+ unsafe {
+ let text_start = &__executable_start as *const u8 as usize;
+ let text_end = &__etext as *const u8 as usize;
+ if !(text_start..text_end).contains(&pc) {
+ return None;
+ }
+
+ let eh_frame = &__eh_frame as *const u8 as usize;
+ let bases = BaseAddresses::default()
+ .set_eh_frame(eh_frame as _)
+ .set_text(text_start as _);
+ let eh_frame = EhFrame::new(get_unlimited_slice(eh_frame as _), NativeEndian);
+
+ if let Ok(fde) = eh_frame.fde_for_address(&bases, pc as _, EhFrame::cie_from_offset) {
+ return Some(FDESearchResult {
+ fde,
+ bases,
+ eh_frame,
+ });
+ }
+
+ None
+ }
+ }
+}
diff --git a/vendor/unwinding/src/unwinder/find_fde/gnu_eh_frame_hdr.rs b/vendor/unwinding/src/unwinder/find_fde/gnu_eh_frame_hdr.rs
new file mode 100644
index 000000000..07507698f
--- /dev/null
+++ b/vendor/unwinding/src/unwinder/find_fde/gnu_eh_frame_hdr.rs
@@ -0,0 +1,66 @@
+use super::FDESearchResult;
+use crate::util::*;
+
+use gimli::{BaseAddresses, EhFrame, EhFrameHdr, NativeEndian, UnwindSection};
+
+pub struct StaticFinder(());
+
+pub fn get_finder() -> &'static StaticFinder {
+ &StaticFinder(())
+}
+
+extern "C" {
+ static __executable_start: u8;
+ static __etext: u8;
+ static __GNU_EH_FRAME_HDR: u8;
+}
+
+impl super::FDEFinder for StaticFinder {
+ fn find_fde(&self, pc: usize) -> Option<FDESearchResult> {
+ unsafe {
+ let text_start = &__executable_start as *const u8 as usize;
+ let text_end = &__etext as *const u8 as usize;
+ if !(text_start..text_end).contains(&pc) {
+ return None;
+ }
+
+ let eh_frame_hdr = &__GNU_EH_FRAME_HDR as *const u8 as usize;
+ let bases = BaseAddresses::default()
+ .set_text(text_start as _)
+ .set_eh_frame_hdr(eh_frame_hdr as _);
+ let eh_frame_hdr = EhFrameHdr::new(
+ get_unlimited_slice(eh_frame_hdr as usize as _),
+ NativeEndian,
+ )
+ .parse(&bases, core::mem::size_of::<usize>() as _)
+ .ok()?;
+ let eh_frame = deref_pointer(eh_frame_hdr.eh_frame_ptr());
+ let bases = bases.set_eh_frame(eh_frame as _);
+ let eh_frame = EhFrame::new(get_unlimited_slice(eh_frame as _), NativeEndian);
+
+ // Use binary search table for address if available.
+ if let Some(table) = eh_frame_hdr.table() {
+ if let Ok(fde) =
+ table.fde_for_address(&eh_frame, &bases, pc as _, EhFrame::cie_from_offset)
+ {
+ return Some(FDESearchResult {
+ fde,
+ bases,
+ eh_frame,
+ });
+ }
+ }
+
+ // Otherwise do the linear search.
+ if let Ok(fde) = eh_frame.fde_for_address(&bases, pc as _, EhFrame::cie_from_offset) {
+ return Some(FDESearchResult {
+ fde,
+ bases,
+ eh_frame,
+ });
+ }
+
+ None
+ }
+ }
+}
diff --git a/vendor/unwinding/src/unwinder/find_fde/mod.rs b/vendor/unwinding/src/unwinder/find_fde/mod.rs
new file mode 100644
index 000000000..4db64a039
--- /dev/null
+++ b/vendor/unwinding/src/unwinder/find_fde/mod.rs
@@ -0,0 +1,64 @@
+#[cfg(feature = "fde-custom")]
+mod custom;
+#[cfg(feature = "fde-static")]
+mod fixed;
+#[cfg(feature = "fde-gnu-eh-frame-hdr")]
+mod gnu_eh_frame_hdr;
+#[cfg(feature = "fde-phdr")]
+mod phdr;
+#[cfg(feature = "fde-registry")]
+mod registry;
+
+use crate::util::*;
+use gimli::{BaseAddresses, EhFrame, FrameDescriptionEntry};
+
+#[cfg(feature = "fde-custom")]
+pub mod custom_eh_frame_finder {
+ pub use super::custom::{
+ set_custom_eh_frame_finder, EhFrameFinder, FrameInfo, FrameInfoKind,
+ SetCustomEhFrameFinderError,
+ };
+}
+
+#[derive(Debug)]
+pub struct FDESearchResult {
+ pub fde: FrameDescriptionEntry<StaticSlice>,
+ pub bases: BaseAddresses,
+ pub eh_frame: EhFrame<StaticSlice>,
+}
+
+pub trait FDEFinder {
+ fn find_fde(&self, pc: usize) -> Option<FDESearchResult>;
+}
+
+pub struct GlobalFinder(());
+
+impl FDEFinder for GlobalFinder {
+ fn find_fde(&self, pc: usize) -> Option<FDESearchResult> {
+ #[cfg(feature = "fde-custom")]
+ if let Some(v) = custom::get_finder().find_fde(pc) {
+ return Some(v);
+ }
+ #[cfg(feature = "fde-registry")]
+ if let Some(v) = registry::get_finder().find_fde(pc) {
+ return Some(v);
+ }
+ #[cfg(feature = "fde-gnu-eh-frame-hdr")]
+ if let Some(v) = gnu_eh_frame_hdr::get_finder().find_fde(pc) {
+ return Some(v);
+ }
+ #[cfg(feature = "fde-phdr")]
+ if let Some(v) = phdr::get_finder().find_fde(pc) {
+ return Some(v);
+ }
+ #[cfg(feature = "fde-static")]
+ if let Some(v) = fixed::get_finder().find_fde(pc) {
+ return Some(v);
+ }
+ None
+ }
+}
+
+pub fn get_finder() -> &'static GlobalFinder {
+ &GlobalFinder(())
+}
diff --git a/vendor/unwinding/src/unwinder/find_fde/phdr.rs b/vendor/unwinding/src/unwinder/find_fde/phdr.rs
new file mode 100644
index 000000000..a677fb272
--- /dev/null
+++ b/vendor/unwinding/src/unwinder/find_fde/phdr.rs
@@ -0,0 +1,166 @@
+use super::FDESearchResult;
+use crate::util::*;
+
+use core::mem;
+use core::slice;
+use gimli::{BaseAddresses, EhFrame, EhFrameHdr, NativeEndian, UnwindSection};
+use libc::{PT_DYNAMIC, PT_GNU_EH_FRAME, PT_LOAD};
+
+#[cfg(target_pointer_width = "32")]
+use libc::Elf32_Phdr as Elf_Phdr;
+#[cfg(target_pointer_width = "64")]
+use libc::Elf64_Phdr as Elf_Phdr;
+
+pub struct PhdrFinder(());
+
+pub fn get_finder() -> &'static PhdrFinder {
+ &PhdrFinder(())
+}
+
+impl super::FDEFinder for PhdrFinder {
+ fn find_fde(&self, pc: usize) -> Option<FDESearchResult> {
+ #[cfg(feature = "fde-phdr-aux")]
+ if let Some(v) = search_aux_phdr(pc) {
+ return Some(v);
+ }
+ #[cfg(feature = "fde-phdr-dl")]
+ if let Some(v) = search_dl_phdr(pc) {
+ return Some(v);
+ }
+ None
+ }
+}
+
+#[cfg(feature = "fde-phdr-aux")]
+fn search_aux_phdr(pc: usize) -> Option<FDESearchResult> {
+ use libc::{getauxval, AT_PHDR, AT_PHNUM, PT_PHDR};
+
+ unsafe {
+ let phdr = getauxval(AT_PHDR) as *const Elf_Phdr;
+ let phnum = getauxval(AT_PHNUM) as usize;
+ let phdrs = slice::from_raw_parts(phdr, phnum);
+ // With known address of PHDR, we can calculate the base address in reverse.
+ let base =
+ phdrs.as_ptr() as usize - phdrs.iter().find(|x| x.p_type == PT_PHDR)?.p_vaddr as usize;
+ search_phdr(phdrs, base, pc)
+ }
+}
+
+#[cfg(feature = "fde-phdr-dl")]
+fn search_dl_phdr(pc: usize) -> Option<FDESearchResult> {
+ use core::ffi::c_void;
+ use libc::{dl_iterate_phdr, dl_phdr_info};
+
+ struct CallbackData {
+ pc: usize,
+ result: Option<FDESearchResult>,
+ }
+
+ unsafe extern "C" fn phdr_callback(
+ info: *mut dl_phdr_info,
+ _size: usize,
+ data: *mut c_void,
+ ) -> c_int {
+ unsafe {
+ let data = &mut *(data as *mut CallbackData);
+ let phdrs = slice::from_raw_parts((*info).dlpi_phdr, (*info).dlpi_phnum as usize);
+ if let Some(v) = search_phdr(phdrs, (*info).dlpi_addr as _, data.pc) {
+ data.result = Some(v);
+ return 1;
+ }
+ 0
+ }
+ }
+
+ let mut data = CallbackData { pc, result: None };
+ unsafe { dl_iterate_phdr(Some(phdr_callback), &mut data as *mut CallbackData as _) };
+ data.result
+}
+
+fn search_phdr(phdrs: &[Elf_Phdr], base: usize, pc: usize) -> Option<FDESearchResult> {
+ unsafe {
+ let mut text = None;
+ let mut eh_frame_hdr = None;
+ let mut dynamic = None;
+
+ for phdr in phdrs {
+ let start = base + phdr.p_vaddr as usize;
+ match phdr.p_type {
+ PT_LOAD => {
+ let end = start + phdr.p_memsz as usize;
+ let range = start..end;
+ if range.contains(&pc) {
+ text = Some(range);
+ }
+ }
+ PT_GNU_EH_FRAME => {
+ eh_frame_hdr = Some(start);
+ }
+ PT_DYNAMIC => {
+ dynamic = Some(start);
+ }
+ _ => (),
+ }
+ }
+
+ let text = text?;
+ let eh_frame_hdr = eh_frame_hdr?;
+
+ let mut bases = BaseAddresses::default()
+ .set_eh_frame_hdr(eh_frame_hdr as _)
+ .set_text(text.start as _);
+
+ // Find the GOT section.
+ if let Some(start) = dynamic {
+ const DT_NULL: usize = 0;
+ const DT_PLTGOT: usize = 3;
+
+ let mut tags = start as *const [usize; 2];
+ let mut tag = *tags;
+ while tag[0] != DT_NULL {
+ if tag[0] == DT_PLTGOT {
+ bases = bases.set_got(tag[1] as _);
+ break;
+ }
+ tags = tags.add(1);
+ tag = *tags;
+ }
+ }
+
+ // Parse .eh_frame_hdr section.
+ let eh_frame_hdr = EhFrameHdr::new(
+ get_unlimited_slice(eh_frame_hdr as usize as _),
+ NativeEndian,
+ )
+ .parse(&bases, mem::size_of::<usize>() as _)
+ .ok()?;
+
+ let eh_frame = deref_pointer(eh_frame_hdr.eh_frame_ptr());
+ bases = bases.set_eh_frame(eh_frame as _);
+ let eh_frame = EhFrame::new(get_unlimited_slice(eh_frame as usize as _), NativeEndian);
+
+ // Use binary search table for address if available.
+ if let Some(table) = eh_frame_hdr.table() {
+ if let Ok(fde) =
+ table.fde_for_address(&eh_frame, &bases, pc as _, EhFrame::cie_from_offset)
+ {
+ return Some(FDESearchResult {
+ fde,
+ bases,
+ eh_frame,
+ });
+ }
+ }
+
+ // Otherwise do the linear search.
+ if let Ok(fde) = eh_frame.fde_for_address(&bases, pc as _, EhFrame::cie_from_offset) {
+ return Some(FDESearchResult {
+ fde,
+ bases,
+ eh_frame,
+ });
+ }
+
+ None
+ }
+}
diff --git a/vendor/unwinding/src/unwinder/find_fde/registry.rs b/vendor/unwinding/src/unwinder/find_fde/registry.rs
new file mode 100644
index 000000000..5341a35ac
--- /dev/null
+++ b/vendor/unwinding/src/unwinder/find_fde/registry.rs
@@ -0,0 +1,250 @@
+use super::FDESearchResult;
+use crate::util::get_unlimited_slice;
+use alloc::boxed::Box;
+use core::ffi::c_void;
+use core::mem::MaybeUninit;
+use core::ops;
+use core::ptr;
+use gimli::{BaseAddresses, EhFrame, NativeEndian, UnwindSection};
+
+enum Table {
+ Single(*const c_void),
+ Multiple(*const *const c_void),
+}
+
+struct Object {
+ next: *mut Object,
+ tbase: usize,
+ dbase: usize,
+ table: Table,
+}
+
+struct GlobalState {
+ object: *mut Object,
+}
+
+unsafe impl Send for GlobalState {}
+
+pub struct Registry(());
+
+// `unsafe` because there is no protection for reentrance.
+unsafe fn lock_global_state() -> impl ops::DerefMut<Target = GlobalState> {
+ #[cfg(feature = "libc")]
+ {
+ static mut MUTEX: libc::pthread_mutex_t = libc::PTHREAD_MUTEX_INITIALIZER;
+ unsafe { libc::pthread_mutex_lock(&mut MUTEX) };
+
+ static mut STATE: GlobalState = GlobalState {
+ object: ptr::null_mut(),
+ };
+
+ struct LockGuard;
+ impl Drop for LockGuard {
+ fn drop(&mut self) {
+ unsafe { libc::pthread_mutex_unlock(&mut MUTEX) };
+ }
+ }
+
+ impl ops::Deref for LockGuard {
+ type Target = GlobalState;
+ fn deref(&self) -> &GlobalState {
+ unsafe { &STATE }
+ }
+ }
+
+ impl ops::DerefMut for LockGuard {
+ fn deref_mut(&mut self) -> &mut GlobalState {
+ unsafe { &mut STATE }
+ }
+ }
+
+ LockGuard
+ }
+ #[cfg(not(feature = "libc"))]
+ {
+ static MUTEX: spin::Mutex<GlobalState> = spin::Mutex::new(GlobalState {
+ object: ptr::null_mut(),
+ });
+ MUTEX.lock()
+ }
+ #[cfg(not(any(feature = "libc", feature = "spin")))]
+ compile_error!("Either feature \"libc\" or \"spin\" must be enabled to use \"fde-registry\".");
+}
+
+pub fn get_finder() -> &'static Registry {
+ &Registry(())
+}
+
+impl super::FDEFinder for Registry {
+ fn find_fde(&self, pc: usize) -> Option<FDESearchResult> {
+ unsafe {
+ let guard = lock_global_state();
+ let mut cur = guard.object;
+
+ while !cur.is_null() {
+ let bases = BaseAddresses::default()
+ .set_text((*cur).tbase as _)
+ .set_got((*cur).dbase as _);
+ match (*cur).table {
+ Table::Single(addr) => {
+ let eh_frame = EhFrame::new(get_unlimited_slice(addr as _), NativeEndian);
+ let bases = bases.clone().set_eh_frame(addr as usize as _);
+ if let Ok(fde) =
+ eh_frame.fde_for_address(&bases, pc as _, EhFrame::cie_from_offset)
+ {
+ return Some(FDESearchResult {
+ fde,
+ bases,
+ eh_frame,
+ });
+ }
+ }
+ Table::Multiple(mut addrs) => {
+ let mut addr = *addrs;
+ while !addr.is_null() {
+ let eh_frame =
+ EhFrame::new(get_unlimited_slice(addr as _), NativeEndian);
+ let bases = bases.clone().set_eh_frame(addr as usize as _);
+ if let Ok(fde) =
+ eh_frame.fde_for_address(&bases, pc as _, EhFrame::cie_from_offset)
+ {
+ return Some(FDESearchResult {
+ fde,
+ bases,
+ eh_frame,
+ });
+ }
+
+ addrs = addrs.add(1);
+ addr = *addrs;
+ }
+ }
+ }
+
+ cur = (*cur).next;
+ }
+ }
+
+ None
+ }
+}
+
+#[no_mangle]
+unsafe extern "C" fn __register_frame_info_bases(
+ begin: *const c_void,
+ ob: *mut Object,
+ tbase: *const c_void,
+ dbase: *const c_void,
+) {
+ if begin.is_null() {
+ return;
+ }
+
+ unsafe {
+ ob.write(Object {
+ next: core::ptr::null_mut(),
+ tbase: tbase as _,
+ dbase: dbase as _,
+ table: Table::Single(begin),
+ });
+
+ let mut guard = lock_global_state();
+ (*ob).next = guard.object;
+ guard.object = ob;
+ }
+}
+
+#[no_mangle]
+unsafe extern "C" fn __register_frame_info(begin: *const c_void, ob: *mut Object) {
+ unsafe { __register_frame_info_bases(begin, ob, core::ptr::null_mut(), core::ptr::null_mut()) }
+}
+
+#[no_mangle]
+unsafe extern "C" fn __register_frame(begin: *const c_void) {
+ if begin.is_null() {
+ return;
+ }
+
+ let storage = Box::into_raw(Box::new(MaybeUninit::<Object>::uninit())) as *mut Object;
+ unsafe { __register_frame_info(begin, storage) }
+}
+
+#[no_mangle]
+unsafe extern "C" fn __register_frame_info_table_bases(
+ begin: *const c_void,
+ ob: *mut Object,
+ tbase: *const c_void,
+ dbase: *const c_void,
+) {
+ unsafe {
+ ob.write(Object {
+ next: core::ptr::null_mut(),
+ tbase: tbase as _,
+ dbase: dbase as _,
+ table: Table::Multiple(begin as _),
+ });
+
+ let mut guard = lock_global_state();
+ (*ob).next = guard.object;
+ guard.object = ob;
+ }
+}
+
+#[no_mangle]
+unsafe extern "C" fn __register_frame_info_table(begin: *const c_void, ob: *mut Object) {
+ unsafe {
+ __register_frame_info_table_bases(begin, ob, core::ptr::null_mut(), core::ptr::null_mut())
+ }
+}
+
+#[no_mangle]
+unsafe extern "C" fn __register_frame_table(begin: *const c_void) {
+ if begin.is_null() {
+ return;
+ }
+
+ let storage = Box::into_raw(Box::new(MaybeUninit::<Object>::uninit())) as *mut Object;
+ unsafe { __register_frame_info_table(begin, storage) }
+}
+
+#[no_mangle]
+extern "C" fn __deregister_frame_info_bases(begin: *const c_void) -> *mut Object {
+ if begin.is_null() {
+ return core::ptr::null_mut();
+ }
+
+ let mut guard = unsafe { lock_global_state() };
+ unsafe {
+ let mut prev = &mut guard.object;
+ let mut cur = *prev;
+
+ while !cur.is_null() {
+ let found = match (*cur).table {
+ Table::Single(addr) => addr == begin,
+ _ => false,
+ };
+ if found {
+ *prev = (*cur).next;
+ return cur;
+ }
+ prev = &mut (*cur).next;
+ cur = *prev;
+ }
+ }
+
+ core::ptr::null_mut()
+}
+
+#[no_mangle]
+extern "C" fn __deregister_frame_info(begin: *const c_void) -> *mut Object {
+ __deregister_frame_info_bases(begin)
+}
+
+#[no_mangle]
+unsafe extern "C" fn __deregister_frame(begin: *const c_void) {
+ if begin.is_null() {
+ return;
+ }
+ let storage = __deregister_frame_info(begin);
+ drop(unsafe { Box::from_raw(storage as *mut MaybeUninit<Object>) })
+}
diff --git a/vendor/unwinding/src/unwinder/frame.rs b/vendor/unwinding/src/unwinder/frame.rs
new file mode 100644
index 000000000..9ede0a12d
--- /dev/null
+++ b/vendor/unwinding/src/unwinder/frame.rs
@@ -0,0 +1,198 @@
+use gimli::{
+ BaseAddresses, CfaRule, Expression, Register, RegisterRule, UnwindContext, UnwindTableRow,
+};
+#[cfg(feature = "dwarf-expr")]
+use gimli::{Evaluation, EvaluationResult, Location, Value};
+
+use super::arch::*;
+use super::find_fde::{self, FDEFinder, FDESearchResult};
+use crate::abi::PersonalityRoutine;
+use crate::arch::*;
+use crate::util::*;
+
+struct StoreOnStack;
+
+// gimli's MSRV doesn't allow const generics, so we need to pick a supported array size.
+const fn next_value(x: usize) -> usize {
+ let supported = [0, 1, 2, 3, 4, 8, 16, 32, 64, 128];
+ let mut i = 0;
+ while i < supported.len() {
+ if supported[i] >= x {
+ return supported[i];
+ }
+ i += 1;
+ }
+ 192
+}
+
+impl<R: gimli::Reader> gimli::UnwindContextStorage<R> for StoreOnStack {
+ type Rules = [(Register, RegisterRule<R>); next_value(MAX_REG_RULES)];
+ type Stack = [UnwindTableRow<R, Self>; 2];
+}
+
+#[cfg(feature = "dwarf-expr")]
+impl<R: gimli::Reader> gimli::EvaluationStorage<R> for StoreOnStack {
+ type Stack = [Value; 64];
+ type ExpressionStack = [(R, R); 0];
+ type Result = [gimli::Piece<R>; 1];
+}
+
+#[derive(Debug)]
+pub struct Frame {
+ fde_result: FDESearchResult,
+ row: UnwindTableRow<StaticSlice, StoreOnStack>,
+}
+
+impl Frame {
+ pub fn from_context(ctx: &Context, signal: bool) -> Result<Option<Self>, gimli::Error> {
+ let mut ra = ctx[Arch::RA];
+
+ // Reached end of stack
+ if ra == 0 {
+ return Ok(None);
+ }
+
+ // RA points to the *next* instruction, so move it back 1 byte for the call instruction.
+ if !signal {
+ ra -= 1;
+ }
+
+ let fde_result = match find_fde::get_finder().find_fde(ra as _) {
+ Some(v) => v,
+ None => return Ok(None),
+ };
+ let mut unwinder = UnwindContext::<_, StoreOnStack>::new_in();
+ let row = fde_result
+ .fde
+ .unwind_info_for_address(
+ &fde_result.eh_frame,
+ &fde_result.bases,
+ &mut unwinder,
+ ra as _,
+ )?
+ .clone();
+
+ Ok(Some(Self { fde_result, row }))
+ }
+
+ #[cfg(feature = "dwarf-expr")]
+ fn evaluate_expression(
+ &self,
+ ctx: &Context,
+ expr: Expression<StaticSlice>,
+ ) -> Result<usize, gimli::Error> {
+ let mut eval =
+ Evaluation::<_, StoreOnStack>::new_in(expr.0, self.fde_result.fde.cie().encoding());
+ let mut result = eval.evaluate()?;
+ loop {
+ match result {
+ EvaluationResult::Complete => break,
+ EvaluationResult::RequiresMemory { address, .. } => {
+ let value = unsafe { (address as usize as *const usize).read_unaligned() };
+ result = eval.resume_with_memory(Value::Generic(value as _))?;
+ }
+ EvaluationResult::RequiresRegister { register, .. } => {
+ let value = ctx[register];
+ result = eval.resume_with_register(Value::Generic(value as _))?;
+ }
+ EvaluationResult::RequiresRelocatedAddress(address) => {
+ let value = unsafe { (address as usize as *const usize).read_unaligned() };
+ result = eval.resume_with_memory(Value::Generic(value as _))?;
+ }
+ _ => unreachable!(),
+ }
+ }
+
+ Ok(
+ match eval
+ .as_result()
+ .last()
+ .ok_or(gimli::Error::PopWithEmptyStack)?
+ .location
+ {
+ Location::Address { address } => address as usize,
+ _ => unreachable!(),
+ },
+ )
+ }
+
+ #[cfg(not(feature = "dwarf-expr"))]
+ fn evaluate_expression(
+ &self,
+ _ctx: &Context,
+ _expr: Expression<StaticSlice>,
+ ) -> Result<usize, gimli::Error> {
+ Err(gimli::Error::UnsupportedEvaluation)
+ }
+
+ pub fn adjust_stack_for_args(&self, ctx: &mut Context) {
+ let size = self.row.saved_args_size();
+ ctx[Arch::SP] = ctx[Arch::SP].wrapping_add(size as usize);
+ }
+
+ pub fn unwind(&self, ctx: &Context) -> Result<Context, gimli::Error> {
+ let row = &self.row;
+ let mut new_ctx = ctx.clone();
+
+ let cfa = match *row.cfa() {
+ CfaRule::RegisterAndOffset { register, offset } => {
+ ctx[register].wrapping_add(offset as usize)
+ }
+ CfaRule::Expression(expr) => self.evaluate_expression(ctx, expr)?,
+ };
+
+ new_ctx[Arch::SP] = cfa as _;
+ new_ctx[Arch::RA] = 0;
+
+ #[warn(non_exhaustive_omitted_patterns)]
+ for (reg, rule) in row.registers() {
+ let value = match *rule {
+ RegisterRule::Undefined | RegisterRule::SameValue => ctx[*reg],
+ RegisterRule::Offset(offset) => unsafe {
+ *((cfa.wrapping_add(offset as usize)) as *const usize)
+ },
+ RegisterRule::ValOffset(offset) => cfa.wrapping_add(offset as usize),
+ RegisterRule::Register(r) => ctx[r],
+ RegisterRule::Expression(expr) => {
+ let addr = self.evaluate_expression(ctx, expr)?;
+ unsafe { *(addr as *const usize) }
+ }
+ RegisterRule::ValExpression(expr) => self.evaluate_expression(ctx, expr)?,
+ RegisterRule::Architectural => unreachable!(),
+ RegisterRule::Constant(value) => value as usize,
+ _ => unreachable!(),
+ };
+ new_ctx[*reg] = value;
+ }
+
+ Ok(new_ctx)
+ }
+
+ pub fn bases(&self) -> &BaseAddresses {
+ &self.fde_result.bases
+ }
+
+ pub fn personality(&self) -> Option<PersonalityRoutine> {
+ self.fde_result
+ .fde
+ .personality()
+ .map(|x| unsafe { deref_pointer(x) })
+ .map(|x| unsafe { core::mem::transmute(x) })
+ }
+
+ pub fn lsda(&self) -> usize {
+ self.fde_result
+ .fde
+ .lsda()
+ .map(|x| unsafe { deref_pointer(x) })
+ .unwrap_or(0)
+ }
+
+ pub fn initial_address(&self) -> usize {
+ self.fde_result.fde.initial_address() as _
+ }
+
+ pub fn is_signal_trampoline(&self) -> bool {
+ self.fde_result.fde.is_signal_trampoline()
+ }
+}
diff --git a/vendor/unwinding/src/unwinder/mod.rs b/vendor/unwinding/src/unwinder/mod.rs
new file mode 100644
index 000000000..5bcc38323
--- /dev/null
+++ b/vendor/unwinding/src/unwinder/mod.rs
@@ -0,0 +1,430 @@
+mod arch;
+mod find_fde;
+mod frame;
+
+use core::ffi::c_void;
+use core::ptr;
+use gimli::Register;
+
+use crate::abi::*;
+use crate::arch::*;
+use crate::util::*;
+use arch::*;
+use find_fde::FDEFinder;
+use frame::Frame;
+
+#[cfg(feature = "fde-custom")]
+pub use find_fde::custom_eh_frame_finder;
+
+// Helper function to turn `save_context` which takes function pointer to a closure-taking function.
+fn with_context<T, F: FnOnce(&mut Context) -> T>(f: F) -> T {
+ use core::mem::ManuallyDrop;
+
+ union Data<T, F> {
+ f: ManuallyDrop<F>,
+ t: ManuallyDrop<T>,
+ }
+
+ extern "C" fn delegate<T, F: FnOnce(&mut Context) -> T>(ctx: &mut Context, ptr: *mut ()) {
+ // SAFETY: This function is called exactly once; it extracts the function, call it and
+ // store the return value. This function is `extern "C"` so we don't need to worry about
+ // unwinding past it.
+ unsafe {
+ let data = &mut *ptr.cast::<Data<T, F>>();
+ let t = ManuallyDrop::take(&mut data.f)(ctx);
+ data.t = ManuallyDrop::new(t);
+ }
+ }
+
+ let mut data = Data {
+ f: ManuallyDrop::new(f),
+ };
+ save_context(delegate::<T, F>, ptr::addr_of_mut!(data).cast());
+ unsafe { ManuallyDrop::into_inner(data.t) }
+}
+
+#[repr(C)]
+pub struct UnwindException {
+ pub exception_class: u64,
+ pub exception_cleanup: Option<UnwindExceptionCleanupFn>,
+ private_1: Option<UnwindStopFn>,
+ private_2: usize,
+ private_unused: [usize; Arch::UNWIND_PRIVATE_DATA_SIZE - 2],
+}
+
+pub struct UnwindContext<'a> {
+ frame: Option<&'a Frame>,
+ ctx: &'a mut Context,
+ signal: bool,
+}
+
+#[no_mangle]
+pub extern "C" fn _Unwind_GetGR(unwind_ctx: &UnwindContext<'_>, index: c_int) -> usize {
+ unwind_ctx.ctx[Register(index as u16)]
+}
+
+#[no_mangle]
+pub extern "C" fn _Unwind_GetCFA(unwind_ctx: &UnwindContext<'_>) -> usize {
+ unwind_ctx.ctx[Arch::SP]
+}
+
+#[no_mangle]
+pub extern "C" fn _Unwind_SetGR(unwind_ctx: &mut UnwindContext<'_>, index: c_int, value: usize) {
+ unwind_ctx.ctx[Register(index as u16)] = value;
+}
+
+#[no_mangle]
+pub extern "C" fn _Unwind_GetIP(unwind_ctx: &UnwindContext<'_>) -> usize {
+ unwind_ctx.ctx[Arch::RA]
+}
+
+#[no_mangle]
+pub extern "C" fn _Unwind_GetIPInfo(
+ unwind_ctx: &UnwindContext<'_>,
+ ip_before_insn: &mut c_int,
+) -> usize {
+ *ip_before_insn = unwind_ctx.signal as _;
+ unwind_ctx.ctx[Arch::RA]
+}
+
+#[no_mangle]
+pub extern "C" fn _Unwind_SetIP(unwind_ctx: &mut UnwindContext<'_>, value: usize) {
+ unwind_ctx.ctx[Arch::RA] = value;
+}
+
+#[no_mangle]
+pub extern "C" fn _Unwind_GetLanguageSpecificData(unwind_ctx: &UnwindContext<'_>) -> *mut c_void {
+ unwind_ctx
+ .frame
+ .map(|f| f.lsda() as *mut c_void)
+ .unwrap_or(ptr::null_mut())
+}
+
+#[no_mangle]
+pub extern "C" fn _Unwind_GetRegionStart(unwind_ctx: &UnwindContext<'_>) -> usize {
+ unwind_ctx.frame.map(|f| f.initial_address()).unwrap_or(0)
+}
+
+#[no_mangle]
+pub extern "C" fn _Unwind_GetTextRelBase(unwind_ctx: &UnwindContext<'_>) -> usize {
+ unwind_ctx
+ .frame
+ .map(|f| f.bases().eh_frame.text.unwrap() as _)
+ .unwrap_or(0)
+}
+
+#[no_mangle]
+pub extern "C" fn _Unwind_GetDataRelBase(unwind_ctx: &UnwindContext<'_>) -> usize {
+ unwind_ctx
+ .frame
+ .map(|f| f.bases().eh_frame.data.unwrap() as _)
+ .unwrap_or(0)
+}
+
+#[no_mangle]
+pub extern "C" fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void {
+ find_fde::get_finder()
+ .find_fde(pc as usize - 1)
+ .map(|r| r.fde.initial_address() as usize as _)
+ .unwrap_or(ptr::null_mut())
+}
+
+macro_rules! try1 {
+ ($e: expr) => {{
+ match $e {
+ Ok(v) => v,
+ Err(_) => return UnwindReasonCode::FATAL_PHASE1_ERROR,
+ }
+ }};
+}
+
+macro_rules! try2 {
+ ($e: expr) => {{
+ match $e {
+ Ok(v) => v,
+ Err(_) => return UnwindReasonCode::FATAL_PHASE2_ERROR,
+ }
+ }};
+}
+
+#[inline(never)]
+#[no_mangle]
+pub unsafe extern "C-unwind" fn _Unwind_RaiseException(
+ exception: *mut UnwindException,
+) -> UnwindReasonCode {
+ with_context(|saved_ctx| {
+ // Phase 1: Search for handler
+ let mut ctx = saved_ctx.clone();
+ let mut signal = false;
+ loop {
+ if let Some(frame) = try1!(Frame::from_context(&ctx, signal)) {
+ if let Some(personality) = frame.personality() {
+ let result = unsafe {
+ personality(
+ 1,
+ UnwindAction::SEARCH_PHASE,
+ (*exception).exception_class,
+ exception,
+ &mut UnwindContext {
+ frame: Some(&frame),
+ ctx: &mut ctx,
+ signal,
+ },
+ )
+ };
+
+ match result {
+ UnwindReasonCode::CONTINUE_UNWIND => (),
+ UnwindReasonCode::HANDLER_FOUND => {
+ break;
+ }
+ _ => return UnwindReasonCode::FATAL_PHASE1_ERROR,
+ }
+ }
+
+ ctx = try1!(frame.unwind(&ctx));
+ signal = frame.is_signal_trampoline();
+ } else {
+ return UnwindReasonCode::END_OF_STACK;
+ }
+ }
+
+ // Disambiguate normal frame and signal frame.
+ let handler_cfa = ctx[Arch::SP] - signal as usize;
+ unsafe {
+ (*exception).private_1 = None;
+ (*exception).private_2 = handler_cfa;
+ }
+
+ let code = raise_exception_phase2(exception, saved_ctx, handler_cfa);
+ match code {
+ UnwindReasonCode::INSTALL_CONTEXT => unsafe { restore_context(saved_ctx) },
+ _ => code,
+ }
+ })
+}
+
+fn raise_exception_phase2(
+ exception: *mut UnwindException,
+ ctx: &mut Context,
+ handler_cfa: usize,
+) -> UnwindReasonCode {
+ let mut signal = false;
+ loop {
+ if let Some(frame) = try2!(Frame::from_context(ctx, signal)) {
+ let frame_cfa = ctx[Arch::SP] - signal as usize;
+ if let Some(personality) = frame.personality() {
+ let code = unsafe {
+ personality(
+ 1,
+ UnwindAction::CLEANUP_PHASE
+ | if frame_cfa == handler_cfa {
+ UnwindAction::HANDLER_FRAME
+ } else {
+ UnwindAction::empty()
+ },
+ (*exception).exception_class,
+ exception,
+ &mut UnwindContext {
+ frame: Some(&frame),
+ ctx,
+ signal,
+ },
+ )
+ };
+
+ match code {
+ UnwindReasonCode::CONTINUE_UNWIND => (),
+ UnwindReasonCode::INSTALL_CONTEXT => {
+ frame.adjust_stack_for_args(ctx);
+ return UnwindReasonCode::INSTALL_CONTEXT;
+ }
+ _ => return UnwindReasonCode::FATAL_PHASE2_ERROR,
+ }
+ }
+
+ *ctx = try2!(frame.unwind(ctx));
+ signal = frame.is_signal_trampoline();
+ } else {
+ return UnwindReasonCode::FATAL_PHASE2_ERROR;
+ }
+ }
+}
+
+#[inline(never)]
+#[no_mangle]
+pub unsafe extern "C-unwind" fn _Unwind_ForcedUnwind(
+ exception: *mut UnwindException,
+ stop: UnwindStopFn,
+ stop_arg: *mut c_void,
+) -> UnwindReasonCode {
+ with_context(|ctx| {
+ unsafe {
+ (*exception).private_1 = Some(stop);
+ (*exception).private_2 = stop_arg as _;
+ }
+
+ let code = force_unwind_phase2(exception, ctx, stop, stop_arg);
+ match code {
+ UnwindReasonCode::INSTALL_CONTEXT => unsafe { restore_context(ctx) },
+ _ => code,
+ }
+ })
+}
+
+fn force_unwind_phase2(
+ exception: *mut UnwindException,
+ ctx: &mut Context,
+ stop: UnwindStopFn,
+ stop_arg: *mut c_void,
+) -> UnwindReasonCode {
+ let mut signal = false;
+ loop {
+ let frame = try2!(Frame::from_context(ctx, signal));
+
+ let code = unsafe {
+ stop(
+ 1,
+ UnwindAction::FORCE_UNWIND
+ | UnwindAction::END_OF_STACK
+ | if frame.is_none() {
+ UnwindAction::END_OF_STACK
+ } else {
+ UnwindAction::empty()
+ },
+ (*exception).exception_class,
+ exception,
+ &mut UnwindContext {
+ frame: frame.as_ref(),
+ ctx,
+ signal,
+ },
+ stop_arg,
+ )
+ };
+ match code {
+ UnwindReasonCode::NO_REASON => (),
+ _ => return UnwindReasonCode::FATAL_PHASE2_ERROR,
+ }
+
+ if let Some(frame) = frame {
+ if let Some(personality) = frame.personality() {
+ let code = unsafe {
+ personality(
+ 1,
+ UnwindAction::FORCE_UNWIND | UnwindAction::CLEANUP_PHASE,
+ (*exception).exception_class,
+ exception,
+ &mut UnwindContext {
+ frame: Some(&frame),
+ ctx,
+ signal,
+ },
+ )
+ };
+
+ match code {
+ UnwindReasonCode::CONTINUE_UNWIND => (),
+ UnwindReasonCode::INSTALL_CONTEXT => {
+ frame.adjust_stack_for_args(ctx);
+ return UnwindReasonCode::INSTALL_CONTEXT;
+ }
+ _ => return UnwindReasonCode::FATAL_PHASE2_ERROR,
+ }
+ }
+
+ *ctx = try2!(frame.unwind(ctx));
+ signal = frame.is_signal_trampoline();
+ } else {
+ return UnwindReasonCode::END_OF_STACK;
+ }
+ }
+}
+
+#[inline(never)]
+#[no_mangle]
+pub unsafe extern "C-unwind" fn _Unwind_Resume(exception: *mut UnwindException) -> ! {
+ with_context(|ctx| {
+ let code = match unsafe { (*exception).private_1 } {
+ None => {
+ let handler_cfa = unsafe { (*exception).private_2 };
+ raise_exception_phase2(exception, ctx, handler_cfa)
+ }
+ Some(stop) => {
+ let stop_arg = unsafe { (*exception).private_2 as _ };
+ force_unwind_phase2(exception, ctx, stop, stop_arg)
+ }
+ };
+ assert!(code == UnwindReasonCode::INSTALL_CONTEXT);
+
+ unsafe { restore_context(ctx) }
+ })
+}
+
+#[inline(never)]
+#[no_mangle]
+pub unsafe extern "C-unwind" fn _Unwind_Resume_or_Rethrow(
+ exception: *mut UnwindException,
+) -> UnwindReasonCode {
+ let stop = match unsafe { (*exception).private_1 } {
+ None => return unsafe { _Unwind_RaiseException(exception) },
+ Some(v) => v,
+ };
+
+ with_context(|ctx| {
+ let stop_arg = unsafe { (*exception).private_2 as _ };
+ let code = force_unwind_phase2(exception, ctx, stop, stop_arg);
+ assert!(code == UnwindReasonCode::INSTALL_CONTEXT);
+
+ unsafe { restore_context(ctx) }
+ })
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn _Unwind_DeleteException(exception: *mut UnwindException) {
+ if let Some(cleanup) = unsafe { (*exception).exception_cleanup } {
+ unsafe { cleanup(UnwindReasonCode::FOREIGN_EXCEPTION_CAUGHT, exception) };
+ }
+}
+
+#[inline(never)]
+#[no_mangle]
+pub extern "C-unwind" fn _Unwind_Backtrace(
+ trace: UnwindTraceFn,
+ trace_argument: *mut c_void,
+) -> UnwindReasonCode {
+ with_context(|ctx| {
+ let mut ctx = ctx.clone();
+ let mut signal = false;
+ let mut skipping = cfg!(feature = "hide-trace");
+
+ loop {
+ let frame = try1!(Frame::from_context(&ctx, signal));
+ if !skipping {
+ let code = trace(
+ &UnwindContext {
+ frame: frame.as_ref(),
+ ctx: &mut ctx,
+ signal,
+ },
+ trace_argument,
+ );
+ match code {
+ UnwindReasonCode::NO_REASON => (),
+ _ => return UnwindReasonCode::FATAL_PHASE1_ERROR,
+ }
+ }
+ if let Some(frame) = frame {
+ if skipping {
+ if frame.initial_address() == _Unwind_Backtrace as usize {
+ skipping = false;
+ }
+ }
+ ctx = try1!(frame.unwind(&ctx));
+ signal = frame.is_signal_trampoline();
+ } else {
+ return UnwindReasonCode::END_OF_STACK;
+ }
+ }
+ })
+}
diff --git a/vendor/unwinding/src/util.rs b/vendor/unwinding/src/util.rs
new file mode 100644
index 000000000..7c66e81fa
--- /dev/null
+++ b/vendor/unwinding/src/util.rs
@@ -0,0 +1,41 @@
+use gimli::{EndianSlice, NativeEndian, Pointer};
+
+pub type StaticSlice = EndianSlice<'static, NativeEndian>;
+
+pub unsafe fn get_unlimited_slice<'a>(start: *const u8) -> &'a [u8] {
+ // Create the largest possible slice for this address.
+ let start = start as usize;
+ let end = start.saturating_add(isize::MAX as _);
+ let len = end - start;
+ unsafe { core::slice::from_raw_parts(start as *const _, len) }
+}
+
+pub unsafe fn deref_pointer(ptr: Pointer) -> usize {
+ match ptr {
+ Pointer::Direct(x) => x as _,
+ Pointer::Indirect(x) => unsafe { *(x as *const _) },
+ }
+}
+
+#[cfg(feature = "libc")]
+pub use libc::c_int;
+
+#[cfg(not(feature = "libc"))]
+#[allow(non_camel_case_types)]
+pub type c_int = i32;
+
+#[cfg(all(
+ any(feature = "panic", feature = "panic-handler-dummy"),
+ feature = "libc"
+))]
+pub fn abort() -> ! {
+ unsafe { libc::abort() };
+}
+
+#[cfg(all(
+ any(feature = "panic", feature = "panic-handler-dummy"),
+ not(feature = "libc")
+))]
+pub fn abort() -> ! {
+ core::intrinsics::abort();
+}
diff --git a/vendor/unwinding/tests/compile_tests.rs b/vendor/unwinding/tests/compile_tests.rs
new file mode 100644
index 000000000..26a5697da
--- /dev/null
+++ b/vendor/unwinding/tests/compile_tests.rs
@@ -0,0 +1,20 @@
+use std::process::Command;
+
+#[test]
+fn main() {
+ let dir = env!("CARGO_MANIFEST_DIR");
+
+ let tests = [
+ "throw_and_catch",
+ "catch_std_exception",
+ "std_catch_exception",
+ ];
+
+ for test in tests {
+ let status = Command::new("./check.sh")
+ .current_dir(format!("{dir}/test_crates/{test}"))
+ .status()
+ .unwrap();
+ assert!(status.success());
+ }
+}