diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-19 09:25:56 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-19 09:25:56 +0000 |
commit | 018c4950b9406055dec02ef0fb52f132e2bb1e2c (patch) | |
tree | a835ebdf2088ef88fa681f8fad45f09922c1ae9a /vendor/unwinding | |
parent | Adding debian version 1.75.0+dfsg1-5. (diff) | |
download | rustc-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')
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()); + } +} |