Update to latest upstream
This commit is contained in:
commit
30cff68007
35
.github/workflows/ci.yml
vendored
Normal file
35
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
env:
|
||||||
|
CARGO_TERM_COLOR: always
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
target:
|
||||||
|
- x86_64-unknown-linux-gnu
|
||||||
|
- i686-unknown-linux-gnu
|
||||||
|
- aarch64-unknown-linux-gnu
|
||||||
|
- riscv64gc-unknown-linux-gnu
|
||||||
|
- riscv32gc-unknown-linux-gnu
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Install Rust
|
||||||
|
run: |
|
||||||
|
rustup update nightly
|
||||||
|
rustup default nightly
|
||||||
|
- name: Install cross-compilation tools
|
||||||
|
uses: taiki-e/setup-cross-toolchain-action@v1
|
||||||
|
with:
|
||||||
|
target: ${{ matrix.target }}
|
||||||
|
|
||||||
|
- name: Build library
|
||||||
|
run: cargo build --release $BUILD_STD
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
run: cargo test --release $BUILD_STD
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,2 @@
|
|||||||
.vscode/
|
.vscode/
|
||||||
target
|
target
|
||||||
Cargo.lock
|
|
||||||
|
87
Cargo.lock
generated
Normal file
87
Cargo.lock
generated
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "catch_std_exception"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"unwinding",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "compiler_builtins"
|
||||||
|
version = "0.1.101"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "01a6d58e9c3408138099a396a98fd0d0e6cfb25d723594d2ae48b5004513fd5b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gimli"
|
||||||
|
version = "0.28.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
|
||||||
|
dependencies = [
|
||||||
|
"compiler_builtins",
|
||||||
|
"rustc-std-workspace-alloc",
|
||||||
|
"rustc-std-workspace-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.149"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc-std-workspace-alloc"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ff66d57013a5686e1917ed6a025d54dd591fcda71a41fe07edf4d16726aefa86"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc-std-workspace-core"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1956f5517128a2b6f23ab2dadf1a976f4f5b27962e7724c2bf3d45e539ec098c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "spin"
|
||||||
|
version = "0.9.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "std_catch_exception"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"unwinding",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "throw_and_catch"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"unwinding",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unwinding"
|
||||||
|
version = "0.2.1"
|
||||||
|
dependencies = [
|
||||||
|
"compiler_builtins",
|
||||||
|
"gimli",
|
||||||
|
"libc",
|
||||||
|
"rustc-std-workspace-core",
|
||||||
|
"spin",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unwinding_dyn"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"unwinding",
|
||||||
|
]
|
12
Cargo.toml
12
Cargo.toml
@ -1,16 +1,18 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "unwinding"
|
name = "unwinding"
|
||||||
version = "0.1.5"
|
version = "0.2.1"
|
||||||
authors = ["Gary Guo <gary@garyguo.net>"]
|
authors = ["Gary Guo <gary@garyguo.net>"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
description = "Unwinding library in Rust and for Rust"
|
description = "Unwinding library in Rust and for Rust"
|
||||||
repository = "https://github.com/nbdd0121/unwinding/"
|
repository = "https://github.com/nbdd0121/unwinding/"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
gimli = { version = "0.26.1", default-features = false, features = ["read-core"] }
|
gimli = { version = "0.28", default-features = false, features = ["read-core"] }
|
||||||
libc = { version = "0.2", optional = true }
|
libc = { version = "0.2", optional = true }
|
||||||
spin = { version = "0.9", optional = true, default-features = false, features = ["mutex", "spin_mutex"] }
|
spin = { version = "0.9.8", optional = true, default-features = false, features = ["mutex", "spin_mutex"] }
|
||||||
|
core = { version = '1.0.0', optional = true, package = 'rustc-std-workspace-core' }
|
||||||
|
compiler_builtins = { version = "0.1.2", optional = true }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
alloc = []
|
alloc = []
|
||||||
@ -21,6 +23,7 @@ fde-phdr-aux = ["fde-phdr"]
|
|||||||
fde-registry = ["alloc"]
|
fde-registry = ["alloc"]
|
||||||
fde-static = []
|
fde-static = []
|
||||||
fde-gnu-eh-frame-hdr = []
|
fde-gnu-eh-frame-hdr = []
|
||||||
|
fde-custom = []
|
||||||
dwarf-expr = []
|
dwarf-expr = []
|
||||||
hide-trace = []
|
hide-trace = []
|
||||||
personality = []
|
personality = []
|
||||||
@ -32,6 +35,7 @@ panic-handler = ["print", "panic"]
|
|||||||
panic-handler-dummy = []
|
panic-handler-dummy = []
|
||||||
system-alloc = []
|
system-alloc = []
|
||||||
default = ["unwinder", "dwarf-expr", "hide-trace", "fde-phdr-dl", "fde-registry"]
|
default = ["unwinder", "dwarf-expr", "hide-trace", "fde-phdr-dl", "fde-registry"]
|
||||||
|
rustc-dep-of-std = ["core", "gimli/rustc-dep-of-std", "compiler_builtins"]
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
features = ["panic-handler"]
|
features = ["panic-handler"]
|
||||||
|
@ -9,7 +9,7 @@ This library serves two purposes:
|
|||||||
1. Provide a pure Rust alternative to libgcc_eh or libunwind.
|
1. Provide a pure Rust alternative to libgcc_eh or libunwind.
|
||||||
2. Provide easier unwinding support for `#![no_std]` targets.
|
2. Provide easier unwinding support for `#![no_std]` targets.
|
||||||
|
|
||||||
Currently supports x86_64, x86, RV64 and AArch64.
|
Currently supports x86_64, x86, RV64, RV32 and AArch64.
|
||||||
|
|
||||||
## Unwinder
|
## Unwinder
|
||||||
|
|
||||||
@ -23,6 +23,7 @@ The unwinder can be enabled with `unwinder` feature. Here are the feature gates
|
|||||||
| fde-registry | Yes | Provide `__register__frame` and others for dynamic registration. Requires either `libc` or `spin` for a mutex implementation. |
|
| 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-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-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 |
|
| dwarf-expr | Yes | Enable the dwarf expression evaluator. Usually not necessary for Rust |
|
||||||
| hide-trace | Yes | Hide unwinder frames in back trace |
|
| hide-trace | Yes | Hide unwinder frames in back trace |
|
||||||
|
|
||||||
|
2
rust-toolchain
Normal file
2
rust-toolchain
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
[toolchain]
|
||||||
|
channel = "nightly"
|
54
src/abi.rs
54
src/abi.rs
@ -60,11 +60,11 @@ impl UnwindAction {
|
|||||||
|
|
||||||
pub type UnwindExceptionCleanupFn = unsafe extern "C" fn(UnwindReasonCode, *mut UnwindException);
|
pub type UnwindExceptionCleanupFn = unsafe extern "C" fn(UnwindReasonCode, *mut UnwindException);
|
||||||
|
|
||||||
pub type UnwindStopFn = extern "C" fn(
|
pub type UnwindStopFn = unsafe extern "C" fn(
|
||||||
c_int,
|
c_int,
|
||||||
UnwindAction,
|
UnwindAction,
|
||||||
u64,
|
u64,
|
||||||
&mut UnwindException,
|
*mut UnwindException,
|
||||||
&mut UnwindContext<'_>,
|
&mut UnwindContext<'_>,
|
||||||
*mut c_void,
|
*mut c_void,
|
||||||
) -> UnwindReasonCode;
|
) -> UnwindReasonCode;
|
||||||
@ -78,7 +78,7 @@ pub struct UnwindException {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub type UnwindTraceFn =
|
pub type UnwindTraceFn =
|
||||||
extern "C" fn(ctx: &mut UnwindContext<'_>, arg: *mut c_void) -> UnwindReasonCode;
|
extern "C" fn(ctx: &UnwindContext<'_>, arg: *mut c_void) -> UnwindReasonCode;
|
||||||
|
|
||||||
#[cfg(not(feature = "unwinder"))]
|
#[cfg(not(feature = "unwinder"))]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
@ -87,31 +87,49 @@ pub struct UnwindContext<'a> {
|
|||||||
phantom: core::marker::PhantomData<&'a ()>,
|
phantom: core::marker::PhantomData<&'a ()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type PersonalityRoutine = extern "C" fn(
|
pub type PersonalityRoutine = unsafe extern "C" fn(
|
||||||
c_int,
|
c_int,
|
||||||
UnwindAction,
|
UnwindAction,
|
||||||
u64,
|
u64,
|
||||||
&mut UnwindException,
|
*mut UnwindException,
|
||||||
&mut UnwindContext<'_>,
|
&mut UnwindContext<'_>,
|
||||||
) -> UnwindReasonCode;
|
) -> UnwindReasonCode;
|
||||||
|
|
||||||
#[cfg(not(feature = "unwinder"))]
|
#[cfg(not(feature = "unwinder"))]
|
||||||
macro_rules! binding {
|
macro_rules! binding {
|
||||||
($(extern $abi: literal $([$t:tt])? fn $name: ident ($($arg: ident : $arg_ty: ty),*$(,)?) $(-> $ret: ty)?;)*) => {
|
() => {};
|
||||||
$(
|
(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)]
|
#[allow(non_snake_case)]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub $($t)? fn $name($($arg: $arg_ty),*) $(-> $ret)? {
|
pub fn $name($($arg: $arg_ty),*) $(-> $ret)? {
|
||||||
extern $abi {
|
extern $abi {
|
||||||
fn $name($($arg: $arg_ty),*) $(-> $ret)?;
|
fn $name($($arg: $arg_ty),*) $(-> $ret)?;
|
||||||
}
|
}
|
||||||
unsafe { $name($($arg),*) }
|
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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "unwinder"))]
|
|
||||||
binding! {
|
binding! {
|
||||||
extern "C" fn _Unwind_GetGR(unwind_ctx: &UnwindContext<'_>, index: c_int) -> usize;
|
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_GetCFA(unwind_ctx: &UnwindContext<'_>) -> usize;
|
||||||
@ -134,19 +152,19 @@ binding! {
|
|||||||
extern "C" fn _Unwind_GetTextRelBase(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_GetDataRelBase(unwind_ctx: &UnwindContext<'_>) -> usize;
|
||||||
extern "C" fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void;
|
extern "C" fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void;
|
||||||
extern "C-unwind" fn _Unwind_RaiseException(
|
unsafe extern "C-unwind" fn _Unwind_RaiseException(
|
||||||
exception: &mut UnwindException,
|
exception: *mut UnwindException,
|
||||||
) -> UnwindReasonCode;
|
) -> UnwindReasonCode;
|
||||||
extern "C-unwind" fn _Unwind_ForcedUnwind(
|
unsafe extern "C-unwind" fn _Unwind_ForcedUnwind(
|
||||||
exception: &mut UnwindException,
|
exception: *mut UnwindException,
|
||||||
stop: UnwindStopFn,
|
stop: UnwindStopFn,
|
||||||
stop_arg: *mut c_void,
|
stop_arg: *mut c_void,
|
||||||
) -> UnwindReasonCode;
|
) -> UnwindReasonCode;
|
||||||
extern "C-unwind" fn _Unwind_Resume(exception: &mut UnwindException) -> !;
|
unsafe extern "C-unwind" fn _Unwind_Resume(exception: *mut UnwindException) -> !;
|
||||||
extern "C-unwind" fn _Unwind_Resume_or_Rethrow(
|
unsafe extern "C-unwind" fn _Unwind_Resume_or_Rethrow(
|
||||||
exception: &mut UnwindException,
|
exception: *mut UnwindException,
|
||||||
) -> UnwindReasonCode;
|
) -> UnwindReasonCode;
|
||||||
extern "C" [unsafe] fn _Unwind_DeleteException(exception: *mut UnwindException);
|
unsafe extern "C" fn _Unwind_DeleteException(exception: *mut UnwindException);
|
||||||
extern "C-unwind" fn _Unwind_Backtrace(
|
extern "C-unwind" fn _Unwind_Backtrace(
|
||||||
trace: UnwindTraceFn,
|
trace: UnwindTraceFn,
|
||||||
trace_argument: *mut c_void,
|
trace_argument: *mut c_void,
|
||||||
|
19
src/lib.rs
19
src/lib.rs
@ -1,6 +1,18 @@
|
|||||||
#![doc = include_str!("../README.md")]
|
#![doc = include_str!("../README.md")]
|
||||||
#![feature(c_unwind)]
|
#![feature(c_unwind)]
|
||||||
#![feature(naked_functions)]
|
#![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",
|
||||||
|
feature = "panicking",
|
||||||
|
feature = "panic-handler-dummy"
|
||||||
|
),
|
||||||
|
allow(internal_features)
|
||||||
|
)]
|
||||||
#![cfg_attr(
|
#![cfg_attr(
|
||||||
any(feature = "personality", feature = "personality-dummy"),
|
any(feature = "personality", feature = "personality-dummy"),
|
||||||
feature(lang_items)
|
feature(lang_items)
|
||||||
@ -20,6 +32,9 @@ extern crate alloc;
|
|||||||
#[cfg(feature = "unwinder")]
|
#[cfg(feature = "unwinder")]
|
||||||
mod unwinder;
|
mod unwinder;
|
||||||
|
|
||||||
|
#[cfg(all(feature = "unwinder", feature = "fde-custom"))]
|
||||||
|
pub use unwinder::custom_eh_frame_finder;
|
||||||
|
|
||||||
pub mod abi;
|
pub mod abi;
|
||||||
|
|
||||||
mod arch;
|
mod arch;
|
||||||
@ -30,7 +45,7 @@ pub mod print;
|
|||||||
|
|
||||||
#[cfg(feature = "personality")]
|
#[cfg(feature = "personality")]
|
||||||
mod personality;
|
mod personality;
|
||||||
#[cfg(feature = "personality-dummy")]
|
#[cfg(all(not(feature = "personality"), feature = "personality-dummy"))]
|
||||||
mod personality_dummy;
|
mod personality_dummy;
|
||||||
|
|
||||||
#[cfg(feature = "panic")]
|
#[cfg(feature = "panic")]
|
||||||
@ -40,7 +55,7 @@ pub mod panicking;
|
|||||||
|
|
||||||
#[cfg(feature = "panic-handler")]
|
#[cfg(feature = "panic-handler")]
|
||||||
mod panic_handler;
|
mod panic_handler;
|
||||||
#[cfg(feature = "panic-handler-dummy")]
|
#[cfg(all(not(feature = "panic-handler"), feature = "panic-handler-dummy"))]
|
||||||
mod panic_handler_dummy;
|
mod panic_handler_dummy;
|
||||||
|
|
||||||
#[cfg(feature = "system-alloc")]
|
#[cfg(feature = "system-alloc")]
|
||||||
|
21
src/panic.rs
21
src/panic.rs
@ -7,6 +7,8 @@ use crate::abi::*;
|
|||||||
pub use crate::panic_handler::*;
|
pub use crate::panic_handler::*;
|
||||||
use crate::panicking::Exception;
|
use crate::panicking::Exception;
|
||||||
|
|
||||||
|
static CANARY: u8 = 0;
|
||||||
|
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
struct RustPanic(Box<dyn Any + Send>, DropGuard);
|
struct RustPanic(Box<dyn Any + Send>, DropGuard);
|
||||||
|
|
||||||
@ -18,13 +20,15 @@ impl Drop for DropGuard {
|
|||||||
{
|
{
|
||||||
drop_panic();
|
drop_panic();
|
||||||
}
|
}
|
||||||
core::intrinsics::abort();
|
crate::util::abort();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
struct ExceptionWithPayload {
|
struct ExceptionWithPayload {
|
||||||
exception: MaybeUninit<UnwindException>,
|
exception: MaybeUninit<UnwindException>,
|
||||||
|
// See rust/library/panic_unwind/src/gcc.rs for the canary values
|
||||||
|
canary: *const u8,
|
||||||
payload: RustPanic,
|
payload: RustPanic,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,12 +38,23 @@ unsafe impl Exception for RustPanic {
|
|||||||
fn wrap(this: Self) -> *mut UnwindException {
|
fn wrap(this: Self) -> *mut UnwindException {
|
||||||
Box::into_raw(Box::new(ExceptionWithPayload {
|
Box::into_raw(Box::new(ExceptionWithPayload {
|
||||||
exception: MaybeUninit::uninit(),
|
exception: MaybeUninit::uninit(),
|
||||||
|
canary: &CANARY,
|
||||||
payload: this,
|
payload: this,
|
||||||
})) as *mut UnwindException
|
})) as *mut UnwindException
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn unwrap(ex: *mut UnwindException) -> Self {
|
unsafe fn unwrap(ex: *mut UnwindException) -> Self {
|
||||||
let ex = unsafe { Box::from_raw(ex as *mut ExceptionWithPayload) };
|
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
|
ex.payload
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -57,7 +72,7 @@ pub fn catch_unwind<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>>
|
|||||||
{
|
{
|
||||||
foreign_exception();
|
foreign_exception();
|
||||||
}
|
}
|
||||||
core::intrinsics::abort();
|
crate::util::abort();
|
||||||
}
|
}
|
||||||
Some(e) => {
|
Some(e) => {
|
||||||
#[cfg(feature = "panic-handler")]
|
#[cfg(feature = "panic-handler")]
|
||||||
|
@ -59,10 +59,7 @@ fn stack_trace() {
|
|||||||
struct CallbackData {
|
struct CallbackData {
|
||||||
counter: usize,
|
counter: usize,
|
||||||
}
|
}
|
||||||
extern "C" fn callback(
|
extern "C" fn callback(unwind_ctx: &UnwindContext<'_>, arg: *mut c_void) -> UnwindReasonCode {
|
||||||
unwind_ctx: &mut UnwindContext<'_>,
|
|
||||||
arg: *mut c_void,
|
|
||||||
) -> UnwindReasonCode {
|
|
||||||
let data = unsafe { &mut *(arg as *mut CallbackData) };
|
let data = unsafe { &mut *(arg as *mut CallbackData) };
|
||||||
data.counter += 1;
|
data.counter += 1;
|
||||||
eprintln!(
|
eprintln!(
|
||||||
@ -80,7 +77,7 @@ fn do_panic(msg: Box<dyn Any + Send>) -> ! {
|
|||||||
if PANIC_COUNT.get() >= 1 {
|
if PANIC_COUNT.get() >= 1 {
|
||||||
stack_trace();
|
stack_trace();
|
||||||
eprintln!("thread panicked while processing panic. aborting.");
|
eprintln!("thread panicked while processing panic. aborting.");
|
||||||
core::intrinsics::abort();
|
crate::util::abort();
|
||||||
}
|
}
|
||||||
PANIC_COUNT.set(1);
|
PANIC_COUNT.set(1);
|
||||||
if check_env() {
|
if check_env() {
|
||||||
@ -88,7 +85,7 @@ fn do_panic(msg: Box<dyn Any + Send>) -> ! {
|
|||||||
}
|
}
|
||||||
let code = crate::panic::begin_panic(Box::new(msg));
|
let code = crate::panic::begin_panic(Box::new(msg));
|
||||||
eprintln!("failed to initiate panic, error {}", code.0);
|
eprintln!("failed to initiate panic, error {}", code.0);
|
||||||
core::intrinsics::abort();
|
crate::util::abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
|
@ -2,5 +2,5 @@ use core::panic::PanicInfo;
|
|||||||
|
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
fn panic(_info: &PanicInfo<'_>) -> ! {
|
fn panic(_info: &PanicInfo<'_>) -> ! {
|
||||||
core::intrinsics::abort();
|
crate::util::abort();
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ pub fn begin_panic<E: Exception>(exception: E) -> UnwindReasonCode {
|
|||||||
unsafe {
|
unsafe {
|
||||||
(*ex).exception_class = u64::from_be_bytes(E::CLASS);
|
(*ex).exception_class = u64::from_be_bytes(E::CLASS);
|
||||||
(*ex).exception_cleanup = Some(exception_cleanup::<E>);
|
(*ex).exception_cleanup = Some(exception_cleanup::<E>);
|
||||||
_Unwind_RaiseException(&mut *ex)
|
_Unwind_RaiseException(ex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,7 +39,7 @@ pub fn catch_unwind<E: Exception, R, F: FnOnce() -> R>(f: F) -> Result<R, Option
|
|||||||
|
|
||||||
let data_ptr = &mut data as *mut _ as *mut u8;
|
let data_ptr = &mut data as *mut _ as *mut u8;
|
||||||
unsafe {
|
unsafe {
|
||||||
return if core::intrinsics::r#try(do_call::<F, R>, data_ptr, do_catch::<E>) == 0 {
|
return if core::intrinsics::catch_unwind(do_call::<F, R>, data_ptr, do_catch::<E>) == 0 {
|
||||||
Ok(ManuallyDrop::into_inner(data.r))
|
Ok(ManuallyDrop::into_inner(data.r))
|
||||||
} else {
|
} else {
|
||||||
Err(ManuallyDrop::into_inner(data.p))
|
Err(ManuallyDrop::into_inner(data.p))
|
||||||
|
@ -136,11 +136,11 @@ fn find_eh_action(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[lang = "eh_personality"]
|
#[lang = "eh_personality"]
|
||||||
fn rust_eh_personality(
|
unsafe fn rust_eh_personality(
|
||||||
version: c_int,
|
version: c_int,
|
||||||
actions: UnwindAction,
|
actions: UnwindAction,
|
||||||
_exception_class: u64,
|
_exception_class: u64,
|
||||||
exception: &mut UnwindException,
|
exception: *mut UnwindException,
|
||||||
unwind_ctx: &mut UnwindContext<'_>,
|
unwind_ctx: &mut UnwindContext<'_>,
|
||||||
) -> UnwindReasonCode {
|
) -> UnwindReasonCode {
|
||||||
if version != 1 {
|
if version != 1 {
|
||||||
@ -170,7 +170,7 @@ fn rust_eh_personality(
|
|||||||
_Unwind_SetGR(
|
_Unwind_SetGR(
|
||||||
unwind_ctx,
|
unwind_ctx,
|
||||||
Arch::UNWIND_DATA_REG.0 .0 as _,
|
Arch::UNWIND_DATA_REG.0 .0 as _,
|
||||||
exception as *mut _ as usize,
|
exception as usize,
|
||||||
);
|
);
|
||||||
_Unwind_SetGR(unwind_ctx, Arch::UNWIND_DATA_REG.1 .0 as _, 0);
|
_Unwind_SetGR(unwind_ctx, Arch::UNWIND_DATA_REG.1 .0 as _, 0);
|
||||||
_Unwind_SetIP(unwind_ctx, lpad);
|
_Unwind_SetIP(unwind_ctx, lpad);
|
||||||
|
@ -2,11 +2,11 @@ use crate::abi::*;
|
|||||||
use crate::util::*;
|
use crate::util::*;
|
||||||
|
|
||||||
#[lang = "eh_personality"]
|
#[lang = "eh_personality"]
|
||||||
extern "C" fn personality(
|
unsafe extern "C" fn personality(
|
||||||
version: c_int,
|
version: c_int,
|
||||||
_actions: UnwindAction,
|
_actions: UnwindAction,
|
||||||
_exception_class: u64,
|
_exception_class: u64,
|
||||||
_exception: &mut UnwindException,
|
_exception: *mut UnwindException,
|
||||||
_ctx: &mut UnwindContext<'_>,
|
_ctx: &mut UnwindContext<'_>,
|
||||||
) -> UnwindReasonCode {
|
) -> UnwindReasonCode {
|
||||||
if version != 1 {
|
if version != 1 {
|
||||||
|
19
src/print.rs
19
src/print.rs
@ -49,3 +49,22 @@ macro_rules! eprint {
|
|||||||
let _ = core::write!($crate::print::StderrPrinter, $($arg)*);
|
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)),+,)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
@ -59,25 +59,34 @@ impl ops::IndexMut<gimli::Register> for Context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[naked]
|
#[naked]
|
||||||
pub extern "C-unwind" fn save_context() -> Context {
|
pub extern "C-unwind" fn save_context(f: extern "C" fn(&mut Context, *mut ()), ptr: *mut ()) {
|
||||||
// No need to save caller-saved registers here.
|
// No need to save caller-saved registers here.
|
||||||
unsafe {
|
unsafe {
|
||||||
asm!(
|
asm!(
|
||||||
"
|
"
|
||||||
stp d8, d9, [x8, 0x140]
|
stp x29, x30, [sp, -16]!
|
||||||
stp d10, d11, [x8, 0x150]
|
sub sp, sp, 512
|
||||||
stp d12, d13, [x8, 0x160]
|
mov x8, x0
|
||||||
stp d14, d15, [x8, 0x170]
|
|
||||||
|
|
||||||
str x19, [x8, 0x98]
|
|
||||||
stp x20, x21, [x8, 0xA0]
|
|
||||||
stp x22, x23, [x8, 0xB0]
|
|
||||||
stp x24, x25, [x8, 0xC0]
|
|
||||||
stp x26, x27, [x8, 0xD0]
|
|
||||||
stp x28, x29, [x8, 0xE0]
|
|
||||||
mov x0, sp
|
mov x0, sp
|
||||||
stp x30, x0, [x8, 0xF0]
|
|
||||||
|
|
||||||
|
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
|
ret
|
||||||
",
|
",
|
||||||
options(noreturn)
|
options(noreturn)
|
||||||
@ -85,8 +94,7 @@ pub extern "C-unwind" fn save_context() -> Context {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[naked]
|
pub unsafe fn restore_context(ctx: &Context) -> ! {
|
||||||
pub unsafe extern "C" fn restore_context(ctx: &Context) -> ! {
|
|
||||||
unsafe {
|
unsafe {
|
||||||
asm!(
|
asm!(
|
||||||
"
|
"
|
||||||
@ -127,6 +135,7 @@ pub unsafe extern "C" fn restore_context(ctx: &Context) -> ! {
|
|||||||
ldp x0, x1, [x0, 0x00]
|
ldp x0, x1, [x0, 0x00]
|
||||||
ret
|
ret
|
||||||
",
|
",
|
||||||
|
in("x0") ctx,
|
||||||
options(noreturn)
|
options(noreturn)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,11 @@ mod riscv64;
|
|||||||
#[cfg(target_arch = "riscv64")]
|
#[cfg(target_arch = "riscv64")]
|
||||||
pub use riscv64::*;
|
pub use riscv64::*;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "riscv32")]
|
||||||
|
mod riscv32;
|
||||||
|
#[cfg(target_arch = "riscv32")]
|
||||||
|
pub use riscv32::*;
|
||||||
|
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
mod aarch64;
|
mod aarch64;
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
@ -22,6 +27,7 @@ pub use aarch64::*;
|
|||||||
target_arch = "x86_64",
|
target_arch = "x86_64",
|
||||||
target_arch = "x86",
|
target_arch = "x86",
|
||||||
target_arch = "riscv64",
|
target_arch = "riscv64",
|
||||||
|
target_arch = "riscv32",
|
||||||
target_arch = "aarch64"
|
target_arch = "aarch64"
|
||||||
)))]
|
)))]
|
||||||
compile_error!("Current architecture is not supported");
|
compile_error!("Current architecture is not supported");
|
||||||
|
243
src/unwinder/arch/riscv32.rs
Normal file
243
src/unwinder/arch/riscv32.rs
Normal file
@ -0,0 +1,243 @@
|
|||||||
|
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, -0x190
|
||||||
|
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, 0x190
|
||||||
|
ret
|
||||||
|
",
|
||||||
|
options(noreturn)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#[cfg(not(target_feature = "d"))]
|
||||||
|
unsafe {
|
||||||
|
asm!(
|
||||||
|
"
|
||||||
|
mv t0, sp
|
||||||
|
add sp, sp, -0x90
|
||||||
|
sw ra, 0x80(sp)
|
||||||
|
",
|
||||||
|
code!(save_gp),
|
||||||
|
"
|
||||||
|
mv t0, a0
|
||||||
|
mv a0, sp
|
||||||
|
jalr t0
|
||||||
|
lw ra, 0x80(sp)
|
||||||
|
add sp, sp, 0x90
|
||||||
|
ret
|
||||||
|
",
|
||||||
|
options(noreturn)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn restore_context(ctx: &Context) -> ! {
|
||||||
|
#[cfg(target_feature = "d")]
|
||||||
|
unsafe {
|
||||||
|
asm!(
|
||||||
|
code!(restore_fp),
|
||||||
|
code!(restore_gp),
|
||||||
|
"
|
||||||
|
lw a0, 0x28(a0)
|
||||||
|
ret
|
||||||
|
",
|
||||||
|
in("a0") ctx,
|
||||||
|
options(noreturn)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#[cfg(not(target_feature = "d"))]
|
||||||
|
unsafe {
|
||||||
|
asm!(
|
||||||
|
code!(restore_gp),
|
||||||
|
"
|
||||||
|
lw a0, 0x28(a0)
|
||||||
|
ret
|
||||||
|
",
|
||||||
|
in("a0") ctx,
|
||||||
|
options(noreturn)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -6,6 +6,9 @@ use gimli::{Register, RiscV};
|
|||||||
// Match DWARF_FRAME_REGISTERS in libgcc
|
// Match DWARF_FRAME_REGISTERS in libgcc
|
||||||
pub const MAX_REG_RULES: usize = 65;
|
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)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
@ -58,39 +61,39 @@ impl ops::IndexMut<gimli::Register> for Context {
|
|||||||
macro_rules! code {
|
macro_rules! code {
|
||||||
(save_gp) => {
|
(save_gp) => {
|
||||||
"
|
"
|
||||||
sd x0, 0x00(a0)
|
sd x0, 0x00(sp)
|
||||||
sd ra, 0x08(a0)
|
sd ra, 0x08(sp)
|
||||||
sd sp, 0x10(a0)
|
sd t0, 0x10(sp)
|
||||||
sd gp, 0x18(a0)
|
sd gp, 0x18(sp)
|
||||||
sd tp, 0x20(a0)
|
sd tp, 0x20(sp)
|
||||||
sd s0, 0x40(a0)
|
sd s0, 0x40(sp)
|
||||||
sd s1, 0x48(a0)
|
sd s1, 0x48(sp)
|
||||||
sd s2, 0x90(a0)
|
sd s2, 0x90(sp)
|
||||||
sd s3, 0x98(a0)
|
sd s3, 0x98(sp)
|
||||||
sd s4, 0xA0(a0)
|
sd s4, 0xA0(sp)
|
||||||
sd s5, 0xA8(a0)
|
sd s5, 0xA8(sp)
|
||||||
sd s6, 0xB0(a0)
|
sd s6, 0xB0(sp)
|
||||||
sd s7, 0xB8(a0)
|
sd s7, 0xB8(sp)
|
||||||
sd s8, 0xC0(a0)
|
sd s8, 0xC0(sp)
|
||||||
sd s9, 0xC8(a0)
|
sd s9, 0xC8(sp)
|
||||||
sd s10, 0xD0(a0)
|
sd s10, 0xD0(sp)
|
||||||
sd s11, 0xD8(a0)
|
sd s11, 0xD8(sp)
|
||||||
"
|
"
|
||||||
};
|
};
|
||||||
(save_fp) => {
|
(save_fp) => {
|
||||||
"
|
"
|
||||||
fsd fs0, 0x140(a0)
|
fsd fs0, 0x140(sp)
|
||||||
fsd fs1, 0x148(a0)
|
fsd fs1, 0x148(sp)
|
||||||
fsd fs2, 0x190(a0)
|
fsd fs2, 0x190(sp)
|
||||||
fsd fs3, 0x198(a0)
|
fsd fs3, 0x198(sp)
|
||||||
fsd fs4, 0x1A0(a0)
|
fsd fs4, 0x1A0(sp)
|
||||||
fsd fs5, 0x1A8(a0)
|
fsd fs5, 0x1A8(sp)
|
||||||
fsd fs6, 0x1B0(a0)
|
fsd fs6, 0x1B0(sp)
|
||||||
fsd fs7, 0x1B8(a0)
|
fsd fs7, 0x1B8(sp)
|
||||||
fsd fs8, 0x1C0(a0)
|
fsd fs8, 0x1C0(sp)
|
||||||
fsd fs9, 0x1C8(a0)
|
fsd fs9, 0x1C8(sp)
|
||||||
fsd fs10, 0x1D0(a0)
|
fsd fs10, 0x1D0(sp)
|
||||||
fsd fs11, 0x1D8(a0)
|
fsd fs11, 0x1D8(sp)
|
||||||
"
|
"
|
||||||
};
|
};
|
||||||
(restore_gp) => {
|
(restore_gp) => {
|
||||||
@ -166,34 +169,74 @@ macro_rules! code {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[naked]
|
#[naked]
|
||||||
pub extern "C-unwind" fn save_context() -> Context {
|
pub extern "C-unwind" fn save_context(f: extern "C" fn(&mut Context, *mut ()), ptr: *mut ()) {
|
||||||
// No need to save caller-saved registers here.
|
// No need to save caller-saved registers here.
|
||||||
#[cfg(target_feature = "d")]
|
#[cfg(target_feature = "d")]
|
||||||
unsafe {
|
unsafe {
|
||||||
asm!(
|
asm!(
|
||||||
concat!(code!(save_gp), code!(save_fp), "ret"),
|
"
|
||||||
|
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)
|
options(noreturn)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
#[cfg(not(target_feature = "d"))]
|
#[cfg(not(target_feature = "d"))]
|
||||||
unsafe {
|
unsafe {
|
||||||
asm!(concat!(code!(save_gp), "ret"), options(noreturn));
|
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 fn restore_context(ctx: &Context) -> ! {
|
||||||
pub unsafe extern "C" fn restore_context(ctx: &Context) -> ! {
|
|
||||||
#[cfg(target_feature = "d")]
|
#[cfg(target_feature = "d")]
|
||||||
unsafe {
|
unsafe {
|
||||||
asm!(
|
asm!(
|
||||||
concat!(code!(restore_fp), code!(restore_gp), "ld a0, 0x50(a0)\nret"),
|
code!(restore_fp),
|
||||||
|
code!(restore_gp),
|
||||||
|
"
|
||||||
|
ld a0, 0x50(a0)
|
||||||
|
ret
|
||||||
|
",
|
||||||
|
in("a0") ctx,
|
||||||
options(noreturn)
|
options(noreturn)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
#[cfg(not(target_feature = "d"))]
|
#[cfg(not(target_feature = "d"))]
|
||||||
unsafe {
|
unsafe {
|
||||||
asm!(
|
asm!(
|
||||||
concat!(code!(restore_gp), "ld a0, 0x50(a0)\nret"),
|
code!(restore_gp),
|
||||||
|
"
|
||||||
|
ld a0, 0x50(a0)
|
||||||
|
ret
|
||||||
|
",
|
||||||
|
in("a0") ctx,
|
||||||
options(noreturn)
|
options(noreturn)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -56,41 +56,50 @@ impl ops::IndexMut<gimli::Register> for Context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[naked]
|
#[naked]
|
||||||
pub extern "C-unwind" fn save_context() -> Context {
|
pub extern "C-unwind" fn save_context(f: extern "C" fn(&mut Context, *mut ()), ptr: *mut ()) {
|
||||||
// No need to save caller-saved registers here.
|
// No need to save caller-saved registers here.
|
||||||
unsafe {
|
unsafe {
|
||||||
asm!(
|
asm!(
|
||||||
"
|
"
|
||||||
mov eax, [esp + 4]
|
sub esp, 52
|
||||||
mov [eax + 4], ecx
|
|
||||||
mov [eax + 8], edx
|
mov [esp + 4], ecx
|
||||||
mov [eax + 12], ebx
|
mov [esp + 8], edx
|
||||||
mov [eax + 20], ebp
|
mov [esp + 12], ebx
|
||||||
mov [eax + 24], esi
|
|
||||||
mov [eax + 28], edi
|
|
||||||
|
|
||||||
/* Adjust the stack to account for the return address */
|
/* Adjust the stack to account for the return address */
|
||||||
lea edx, [esp + 4]
|
lea eax, [esp + 56]
|
||||||
mov [eax + 16], edx
|
mov [esp + 16], eax
|
||||||
|
|
||||||
mov edx, [esp]
|
mov [esp + 20], ebp
|
||||||
mov [eax + 32], edx
|
mov [esp + 24], esi
|
||||||
stmxcsr [eax + 36]
|
mov [esp + 28], edi
|
||||||
fnstcw [eax + 40]
|
|
||||||
ret 4
|
/* 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)
|
options(noreturn)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[naked]
|
pub unsafe fn restore_context(ctx: &Context) -> ! {
|
||||||
pub unsafe extern "C" fn restore_context(ctx: &Context) -> ! {
|
|
||||||
unsafe {
|
unsafe {
|
||||||
asm!(
|
asm!(
|
||||||
"
|
"
|
||||||
mov edx, [esp + 4]
|
|
||||||
|
|
||||||
/* Restore stack */
|
/* Restore stack */
|
||||||
mov esp, [edx + 16]
|
mov esp, [edx + 16]
|
||||||
|
|
||||||
@ -118,6 +127,7 @@ pub unsafe extern "C" fn restore_context(ctx: &Context) -> ! {
|
|||||||
|
|
||||||
ret
|
ret
|
||||||
",
|
",
|
||||||
|
in("edx") ctx,
|
||||||
options(noreturn)
|
options(noreturn)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -58,27 +58,35 @@ impl ops::IndexMut<gimli::Register> for Context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[naked]
|
#[naked]
|
||||||
pub extern "C-unwind" fn save_context() -> Context {
|
pub extern "C-unwind" fn save_context(f: extern "C" fn(&mut Context, *mut ()), ptr: *mut ()) {
|
||||||
// No need to save caller-saved registers here.
|
// No need to save caller-saved registers here.
|
||||||
unsafe {
|
unsafe {
|
||||||
asm!(
|
asm!(
|
||||||
"
|
"
|
||||||
mov rax, rdi
|
sub rsp, 0x98
|
||||||
mov [rax + 0x18], rbx
|
mov [rsp + 0x18], rbx
|
||||||
mov [rax + 0x30], rbp
|
mov [rsp + 0x30], rbp
|
||||||
|
|
||||||
/* Adjust the stack to account for the return address */
|
/* Adjust the stack to account for the return address */
|
||||||
lea rdi, [rsp + 8]
|
lea rax, [rsp + 0xA0]
|
||||||
mov [rax + 0x38], rdi
|
mov [rsp + 0x38], rax
|
||||||
|
|
||||||
mov [rax + 0x60], r12
|
mov [rsp + 0x60], r12
|
||||||
mov [rax + 0x68], r13
|
mov [rsp + 0x68], r13
|
||||||
mov [rax + 0x70], r14
|
mov [rsp + 0x70], r14
|
||||||
mov [rax + 0x78], r15
|
mov [rsp + 0x78], r15
|
||||||
mov rdx, [rsp]
|
|
||||||
mov [rax + 0x80], rdx
|
/* Return address */
|
||||||
/* stmxcsr [rax + 0x88] */
|
mov rax, [rsp + 0x98]
|
||||||
fnstcw [rax + 0x90]
|
mov [rsp + 0x80], rax
|
||||||
|
|
||||||
|
/* stmxcsr [rsp + 0x88] */
|
||||||
|
fnstcw [rsp + 0x90]
|
||||||
|
|
||||||
|
mov rax, rdi
|
||||||
|
mov rdi, rsp
|
||||||
|
call rax
|
||||||
|
add rsp, 0x98
|
||||||
ret
|
ret
|
||||||
",
|
",
|
||||||
options(noreturn)
|
options(noreturn)
|
||||||
@ -86,8 +94,7 @@ pub extern "C-unwind" fn save_context() -> Context {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[naked]
|
pub unsafe fn restore_context(ctx: &Context) -> ! {
|
||||||
pub unsafe extern "C" fn restore_context(ctx: &Context) -> ! {
|
|
||||||
unsafe {
|
unsafe {
|
||||||
asm!(
|
asm!(
|
||||||
"
|
"
|
||||||
@ -121,11 +128,12 @@ pub unsafe extern "C" fn restore_context(ctx: &Context) -> ! {
|
|||||||
mov r14, [rdi + 0x70]
|
mov r14, [rdi + 0x70]
|
||||||
mov r15, [rdi + 0x78]
|
mov r15, [rdi + 0x78]
|
||||||
|
|
||||||
/* RDI resotred last */
|
/* RDI restored last */
|
||||||
mov rdi, [rdi + 0x28]
|
mov rdi, [rdi + 0x28]
|
||||||
|
|
||||||
ret
|
ret
|
||||||
",
|
",
|
||||||
|
in("rdi") ctx,
|
||||||
options(noreturn)
|
options(noreturn)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
171
src/unwinder/find_fde/custom.rs
Normal file
171
src/unwinder/find_fde/custom.rs
Normal file
@ -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
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,5 @@
|
|||||||
|
#[cfg(feature = "fde-custom")]
|
||||||
|
mod custom;
|
||||||
#[cfg(feature = "fde-static")]
|
#[cfg(feature = "fde-static")]
|
||||||
mod fixed;
|
mod fixed;
|
||||||
#[cfg(feature = "fde-gnu-eh-frame-hdr")]
|
#[cfg(feature = "fde-gnu-eh-frame-hdr")]
|
||||||
@ -10,6 +12,14 @@ mod registry;
|
|||||||
use crate::util::*;
|
use crate::util::*;
|
||||||
use gimli::{BaseAddresses, EhFrame, FrameDescriptionEntry};
|
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)]
|
#[derive(Debug)]
|
||||||
pub struct FDESearchResult {
|
pub struct FDESearchResult {
|
||||||
pub fde: FrameDescriptionEntry<StaticSlice>,
|
pub fde: FrameDescriptionEntry<StaticSlice>,
|
||||||
@ -25,6 +35,10 @@ pub struct GlobalFinder(());
|
|||||||
|
|
||||||
impl FDEFinder for GlobalFinder {
|
impl FDEFinder for GlobalFinder {
|
||||||
fn find_fde(&self, pc: usize) -> Option<FDESearchResult> {
|
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")]
|
#[cfg(feature = "fde-registry")]
|
||||||
if let Some(v) = registry::get_finder().find_fde(pc) {
|
if let Some(v) = registry::get_finder().find_fde(pc) {
|
||||||
return Some(v);
|
return Some(v);
|
||||||
|
@ -32,7 +32,7 @@ unsafe fn lock_global_state() -> impl ops::DerefMut<Target = GlobalState> {
|
|||||||
#[cfg(feature = "libc")]
|
#[cfg(feature = "libc")]
|
||||||
{
|
{
|
||||||
static mut MUTEX: libc::pthread_mutex_t = libc::PTHREAD_MUTEX_INITIALIZER;
|
static mut MUTEX: libc::pthread_mutex_t = libc::PTHREAD_MUTEX_INITIALIZER;
|
||||||
unsafe { libc::pthread_mutex_lock(&mut MUTEX) };
|
unsafe { libc::pthread_mutex_lock(core::ptr::addr_of_mut!(MUTEX)) };
|
||||||
|
|
||||||
static mut STATE: GlobalState = GlobalState {
|
static mut STATE: GlobalState = GlobalState {
|
||||||
object: ptr::null_mut(),
|
object: ptr::null_mut(),
|
||||||
@ -41,20 +41,22 @@ unsafe fn lock_global_state() -> impl ops::DerefMut<Target = GlobalState> {
|
|||||||
struct LockGuard;
|
struct LockGuard;
|
||||||
impl Drop for LockGuard {
|
impl Drop for LockGuard {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe { libc::pthread_mutex_unlock(&mut MUTEX) };
|
unsafe { libc::pthread_mutex_unlock(core::ptr::addr_of_mut!(MUTEX)) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ops::Deref for LockGuard {
|
impl ops::Deref for LockGuard {
|
||||||
type Target = GlobalState;
|
type Target = GlobalState;
|
||||||
|
|
||||||
|
#[allow(static_mut_ref)]
|
||||||
fn deref(&self) -> &GlobalState {
|
fn deref(&self) -> &GlobalState {
|
||||||
unsafe { &STATE }
|
unsafe { &*core::ptr::addr_of!(STATE) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ops::DerefMut for LockGuard {
|
impl ops::DerefMut for LockGuard {
|
||||||
fn deref_mut(&mut self) -> &mut GlobalState {
|
fn deref_mut(&mut self) -> &mut GlobalState {
|
||||||
unsafe { &mut STATE }
|
unsafe { &mut *core::ptr::addr_of_mut!(STATE) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,6 +125,11 @@ impl Frame {
|
|||||||
Err(gimli::Error::UnsupportedEvaluation)
|
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> {
|
pub fn unwind(&self, ctx: &Context) -> Result<Context, gimli::Error> {
|
||||||
let row = &self.row;
|
let row = &self.row;
|
||||||
let mut new_ctx = ctx.clone();
|
let mut new_ctx = ctx.clone();
|
||||||
@ -139,6 +144,7 @@ impl Frame {
|
|||||||
new_ctx[Arch::SP] = cfa as _;
|
new_ctx[Arch::SP] = cfa as _;
|
||||||
new_ctx[Arch::RA] = 0;
|
new_ctx[Arch::RA] = 0;
|
||||||
|
|
||||||
|
#[warn(non_exhaustive_omitted_patterns)]
|
||||||
for (reg, rule) in row.registers() {
|
for (reg, rule) in row.registers() {
|
||||||
let value = match *rule {
|
let value = match *rule {
|
||||||
RegisterRule::Undefined | RegisterRule::SameValue => ctx[*reg],
|
RegisterRule::Undefined | RegisterRule::SameValue => ctx[*reg],
|
||||||
@ -153,6 +159,8 @@ impl Frame {
|
|||||||
}
|
}
|
||||||
RegisterRule::ValExpression(expr) => self.evaluate_expression(ctx, expr)?,
|
RegisterRule::ValExpression(expr) => self.evaluate_expression(ctx, expr)?,
|
||||||
RegisterRule::Architectural => unreachable!(),
|
RegisterRule::Architectural => unreachable!(),
|
||||||
|
RegisterRule::Constant(value) => value as usize,
|
||||||
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
new_ctx[*reg] = value;
|
new_ctx[*reg] = value;
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,36 @@ use arch::*;
|
|||||||
use find_fde::FDEFinder;
|
use find_fde::FDEFinder;
|
||||||
use frame::Frame;
|
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)]
|
#[repr(C)]
|
||||||
pub struct UnwindException {
|
pub struct UnwindException {
|
||||||
pub exception_class: u64,
|
pub exception_class: u64,
|
||||||
@ -119,28 +149,29 @@ macro_rules! try2 {
|
|||||||
|
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C-unwind" fn _Unwind_RaiseException(
|
pub unsafe extern "C-unwind" fn _Unwind_RaiseException(
|
||||||
exception: &mut UnwindException,
|
exception: *mut UnwindException,
|
||||||
) -> UnwindReasonCode {
|
) -> UnwindReasonCode {
|
||||||
let saved_ctx = save_context();
|
with_context(|saved_ctx| {
|
||||||
|
|
||||||
// Phase 1: Search for handler
|
// Phase 1: Search for handler
|
||||||
let mut ctx = saved_ctx.clone();
|
let mut ctx = saved_ctx.clone();
|
||||||
let mut signal = false;
|
let mut signal = false;
|
||||||
loop {
|
loop {
|
||||||
if let Some(frame) = try1!(Frame::from_context(&ctx, signal)) {
|
if let Some(frame) = try1!(Frame::from_context(&ctx, signal)) {
|
||||||
if let Some(personality) = frame.personality() {
|
if let Some(personality) = frame.personality() {
|
||||||
let result = personality(
|
let result = unsafe {
|
||||||
|
personality(
|
||||||
1,
|
1,
|
||||||
UnwindAction::SEARCH_PHASE,
|
UnwindAction::SEARCH_PHASE,
|
||||||
exception.exception_class,
|
(*exception).exception_class,
|
||||||
exception,
|
exception,
|
||||||
&mut UnwindContext {
|
&mut UnwindContext {
|
||||||
frame: Some(&frame),
|
frame: Some(&frame),
|
||||||
ctx: &mut ctx,
|
ctx: &mut ctx,
|
||||||
signal,
|
signal,
|
||||||
},
|
},
|
||||||
);
|
)
|
||||||
|
};
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
UnwindReasonCode::CONTINUE_UNWIND => (),
|
UnwindReasonCode::CONTINUE_UNWIND => (),
|
||||||
@ -160,19 +191,21 @@ pub extern "C-unwind" fn _Unwind_RaiseException(
|
|||||||
|
|
||||||
// Disambiguate normal frame and signal frame.
|
// Disambiguate normal frame and signal frame.
|
||||||
let handler_cfa = ctx[Arch::SP] - signal as usize;
|
let handler_cfa = ctx[Arch::SP] - signal as usize;
|
||||||
exception.private_1 = None;
|
unsafe {
|
||||||
exception.private_2 = handler_cfa;
|
(*exception).private_1 = None;
|
||||||
|
(*exception).private_2 = handler_cfa;
|
||||||
|
}
|
||||||
|
|
||||||
let mut ctx = saved_ctx;
|
let code = raise_exception_phase2(exception, saved_ctx, handler_cfa);
|
||||||
let code = raise_exception_phase2(exception, &mut ctx, handler_cfa);
|
|
||||||
match code {
|
match code {
|
||||||
UnwindReasonCode::INSTALL_CONTEXT => unsafe { restore_context(&ctx) },
|
UnwindReasonCode::INSTALL_CONTEXT => unsafe { restore_context(saved_ctx) },
|
||||||
_ => code,
|
_ => code,
|
||||||
}
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn raise_exception_phase2(
|
fn raise_exception_phase2(
|
||||||
exception: &mut UnwindException,
|
exception: *mut UnwindException,
|
||||||
ctx: &mut Context,
|
ctx: &mut Context,
|
||||||
handler_cfa: usize,
|
handler_cfa: usize,
|
||||||
) -> UnwindReasonCode {
|
) -> UnwindReasonCode {
|
||||||
@ -181,7 +214,8 @@ fn raise_exception_phase2(
|
|||||||
if let Some(frame) = try2!(Frame::from_context(ctx, signal)) {
|
if let Some(frame) = try2!(Frame::from_context(ctx, signal)) {
|
||||||
let frame_cfa = ctx[Arch::SP] - signal as usize;
|
let frame_cfa = ctx[Arch::SP] - signal as usize;
|
||||||
if let Some(personality) = frame.personality() {
|
if let Some(personality) = frame.personality() {
|
||||||
let code = personality(
|
let code = unsafe {
|
||||||
|
personality(
|
||||||
1,
|
1,
|
||||||
UnwindAction::CLEANUP_PHASE
|
UnwindAction::CLEANUP_PHASE
|
||||||
| if frame_cfa == handler_cfa {
|
| if frame_cfa == handler_cfa {
|
||||||
@ -189,18 +223,22 @@ fn raise_exception_phase2(
|
|||||||
} else {
|
} else {
|
||||||
UnwindAction::empty()
|
UnwindAction::empty()
|
||||||
},
|
},
|
||||||
exception.exception_class,
|
(*exception).exception_class,
|
||||||
exception,
|
exception,
|
||||||
&mut UnwindContext {
|
&mut UnwindContext {
|
||||||
frame: Some(&frame),
|
frame: Some(&frame),
|
||||||
ctx,
|
ctx,
|
||||||
signal,
|
signal,
|
||||||
},
|
},
|
||||||
);
|
)
|
||||||
|
};
|
||||||
|
|
||||||
match code {
|
match code {
|
||||||
UnwindReasonCode::CONTINUE_UNWIND => (),
|
UnwindReasonCode::CONTINUE_UNWIND => (),
|
||||||
UnwindReasonCode::INSTALL_CONTEXT => break,
|
UnwindReasonCode::INSTALL_CONTEXT => {
|
||||||
|
frame.adjust_stack_for_args(ctx);
|
||||||
|
return UnwindReasonCode::INSTALL_CONTEXT;
|
||||||
|
}
|
||||||
_ => return UnwindReasonCode::FATAL_PHASE2_ERROR,
|
_ => return UnwindReasonCode::FATAL_PHASE2_ERROR,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -211,31 +249,31 @@ fn raise_exception_phase2(
|
|||||||
return UnwindReasonCode::FATAL_PHASE2_ERROR;
|
return UnwindReasonCode::FATAL_PHASE2_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UnwindReasonCode::INSTALL_CONTEXT
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C-unwind" fn _Unwind_ForcedUnwind(
|
pub unsafe extern "C-unwind" fn _Unwind_ForcedUnwind(
|
||||||
exception: &mut UnwindException,
|
exception: *mut UnwindException,
|
||||||
stop: UnwindStopFn,
|
stop: UnwindStopFn,
|
||||||
stop_arg: *mut c_void,
|
stop_arg: *mut c_void,
|
||||||
) -> UnwindReasonCode {
|
) -> UnwindReasonCode {
|
||||||
let mut ctx = save_context();
|
with_context(|ctx| {
|
||||||
|
unsafe {
|
||||||
|
(*exception).private_1 = Some(stop);
|
||||||
|
(*exception).private_2 = stop_arg as _;
|
||||||
|
}
|
||||||
|
|
||||||
exception.private_1 = Some(stop);
|
let code = force_unwind_phase2(exception, ctx, stop, stop_arg);
|
||||||
exception.private_2 = stop_arg as _;
|
|
||||||
|
|
||||||
let code = force_unwind_phase2(exception, &mut ctx, stop, stop_arg);
|
|
||||||
match code {
|
match code {
|
||||||
UnwindReasonCode::INSTALL_CONTEXT => unsafe { restore_context(&ctx) },
|
UnwindReasonCode::INSTALL_CONTEXT => unsafe { restore_context(ctx) },
|
||||||
_ => code,
|
_ => code,
|
||||||
}
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn force_unwind_phase2(
|
fn force_unwind_phase2(
|
||||||
exception: &mut UnwindException,
|
exception: *mut UnwindException,
|
||||||
ctx: &mut Context,
|
ctx: &mut Context,
|
||||||
stop: UnwindStopFn,
|
stop: UnwindStopFn,
|
||||||
stop_arg: *mut c_void,
|
stop_arg: *mut c_void,
|
||||||
@ -244,7 +282,8 @@ fn force_unwind_phase2(
|
|||||||
loop {
|
loop {
|
||||||
let frame = try2!(Frame::from_context(ctx, signal));
|
let frame = try2!(Frame::from_context(ctx, signal));
|
||||||
|
|
||||||
let code = stop(
|
let code = unsafe {
|
||||||
|
stop(
|
||||||
1,
|
1,
|
||||||
UnwindAction::FORCE_UNWIND
|
UnwindAction::FORCE_UNWIND
|
||||||
| UnwindAction::END_OF_STACK
|
| UnwindAction::END_OF_STACK
|
||||||
@ -253,7 +292,7 @@ fn force_unwind_phase2(
|
|||||||
} else {
|
} else {
|
||||||
UnwindAction::empty()
|
UnwindAction::empty()
|
||||||
},
|
},
|
||||||
exception.exception_class,
|
(*exception).exception_class,
|
||||||
exception,
|
exception,
|
||||||
&mut UnwindContext {
|
&mut UnwindContext {
|
||||||
frame: frame.as_ref(),
|
frame: frame.as_ref(),
|
||||||
@ -261,7 +300,8 @@ fn force_unwind_phase2(
|
|||||||
signal,
|
signal,
|
||||||
},
|
},
|
||||||
stop_arg,
|
stop_arg,
|
||||||
);
|
)
|
||||||
|
};
|
||||||
match code {
|
match code {
|
||||||
UnwindReasonCode::NO_REASON => (),
|
UnwindReasonCode::NO_REASON => (),
|
||||||
_ => return UnwindReasonCode::FATAL_PHASE2_ERROR,
|
_ => return UnwindReasonCode::FATAL_PHASE2_ERROR,
|
||||||
@ -269,21 +309,26 @@ fn force_unwind_phase2(
|
|||||||
|
|
||||||
if let Some(frame) = frame {
|
if let Some(frame) = frame {
|
||||||
if let Some(personality) = frame.personality() {
|
if let Some(personality) = frame.personality() {
|
||||||
let code = personality(
|
let code = unsafe {
|
||||||
|
personality(
|
||||||
1,
|
1,
|
||||||
UnwindAction::FORCE_UNWIND | UnwindAction::CLEANUP_PHASE,
|
UnwindAction::FORCE_UNWIND | UnwindAction::CLEANUP_PHASE,
|
||||||
exception.exception_class,
|
(*exception).exception_class,
|
||||||
exception,
|
exception,
|
||||||
&mut UnwindContext {
|
&mut UnwindContext {
|
||||||
frame: Some(&frame),
|
frame: Some(&frame),
|
||||||
ctx,
|
ctx,
|
||||||
signal,
|
signal,
|
||||||
},
|
},
|
||||||
);
|
)
|
||||||
|
};
|
||||||
|
|
||||||
match code {
|
match code {
|
||||||
UnwindReasonCode::CONTINUE_UNWIND => (),
|
UnwindReasonCode::CONTINUE_UNWIND => (),
|
||||||
UnwindReasonCode::INSTALL_CONTEXT => break,
|
UnwindReasonCode::INSTALL_CONTEXT => {
|
||||||
|
frame.adjust_stack_for_args(ctx);
|
||||||
|
return UnwindReasonCode::INSTALL_CONTEXT;
|
||||||
|
}
|
||||||
_ => return UnwindReasonCode::FATAL_PHASE2_ERROR,
|
_ => return UnwindReasonCode::FATAL_PHASE2_ERROR,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -294,47 +339,45 @@ fn force_unwind_phase2(
|
|||||||
return UnwindReasonCode::END_OF_STACK;
|
return UnwindReasonCode::END_OF_STACK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UnwindReasonCode::INSTALL_CONTEXT
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C-unwind" fn _Unwind_Resume(exception: &mut UnwindException) -> ! {
|
pub unsafe extern "C-unwind" fn _Unwind_Resume(exception: *mut UnwindException) -> ! {
|
||||||
let mut ctx = save_context();
|
with_context(|ctx| {
|
||||||
|
let code = match unsafe { (*exception).private_1 } {
|
||||||
let code = match exception.private_1 {
|
|
||||||
None => {
|
None => {
|
||||||
let handler_cfa = exception.private_2;
|
let handler_cfa = unsafe { (*exception).private_2 };
|
||||||
raise_exception_phase2(exception, &mut ctx, handler_cfa)
|
raise_exception_phase2(exception, ctx, handler_cfa)
|
||||||
}
|
}
|
||||||
Some(stop) => {
|
Some(stop) => {
|
||||||
let stop_arg = exception.private_2 as _;
|
let stop_arg = unsafe { (*exception).private_2 as _ };
|
||||||
force_unwind_phase2(exception, &mut ctx, stop, stop_arg)
|
force_unwind_phase2(exception, ctx, stop, stop_arg)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
assert!(code == UnwindReasonCode::INSTALL_CONTEXT);
|
assert!(code == UnwindReasonCode::INSTALL_CONTEXT);
|
||||||
|
|
||||||
unsafe { restore_context(&ctx) }
|
unsafe { restore_context(ctx) }
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C-unwind" fn _Unwind_Resume_or_Rethrow(
|
pub unsafe extern "C-unwind" fn _Unwind_Resume_or_Rethrow(
|
||||||
exception: &mut UnwindException,
|
exception: *mut UnwindException,
|
||||||
) -> UnwindReasonCode {
|
) -> UnwindReasonCode {
|
||||||
let stop = match exception.private_1 {
|
let stop = match unsafe { (*exception).private_1 } {
|
||||||
None => return _Unwind_RaiseException(exception),
|
None => return unsafe { _Unwind_RaiseException(exception) },
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut ctx = save_context();
|
with_context(|ctx| {
|
||||||
|
let stop_arg = unsafe { (*exception).private_2 as _ };
|
||||||
let stop_arg = exception.private_2 as _;
|
let code = force_unwind_phase2(exception, ctx, stop, stop_arg);
|
||||||
let code = force_unwind_phase2(exception, &mut ctx, stop, stop_arg);
|
|
||||||
assert!(code == UnwindReasonCode::INSTALL_CONTEXT);
|
assert!(code == UnwindReasonCode::INSTALL_CONTEXT);
|
||||||
|
|
||||||
unsafe { restore_context(&ctx) }
|
unsafe { restore_context(ctx) }
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@ -350,7 +393,8 @@ pub extern "C-unwind" fn _Unwind_Backtrace(
|
|||||||
trace: UnwindTraceFn,
|
trace: UnwindTraceFn,
|
||||||
trace_argument: *mut c_void,
|
trace_argument: *mut c_void,
|
||||||
) -> UnwindReasonCode {
|
) -> UnwindReasonCode {
|
||||||
let mut ctx = save_context();
|
with_context(|ctx| {
|
||||||
|
let mut ctx = ctx.clone();
|
||||||
let mut signal = false;
|
let mut signal = false;
|
||||||
let mut skipping = cfg!(feature = "hide-trace");
|
let mut skipping = cfg!(feature = "hide-trace");
|
||||||
|
|
||||||
@ -358,7 +402,7 @@ pub extern "C-unwind" fn _Unwind_Backtrace(
|
|||||||
let frame = try1!(Frame::from_context(&ctx, signal));
|
let frame = try1!(Frame::from_context(&ctx, signal));
|
||||||
if !skipping {
|
if !skipping {
|
||||||
let code = trace(
|
let code = trace(
|
||||||
&mut UnwindContext {
|
&UnwindContext {
|
||||||
frame: frame.as_ref(),
|
frame: frame.as_ref(),
|
||||||
ctx: &mut ctx,
|
ctx: &mut ctx,
|
||||||
signal,
|
signal,
|
||||||
@ -382,4 +426,5 @@ pub extern "C-unwind" fn _Unwind_Backtrace(
|
|||||||
return UnwindReasonCode::END_OF_STACK;
|
return UnwindReasonCode::END_OF_STACK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
16
src/util.rs
16
src/util.rs
@ -23,3 +23,19 @@ pub use libc::c_int;
|
|||||||
#[cfg(not(feature = "libc"))]
|
#[cfg(not(feature = "libc"))]
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
pub type c_int = i32;
|
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();
|
||||||
|
}
|
||||||
|
20
tests/compile_tests.rs
Normal file
20
tests/compile_tests.rs
Normal file
@ -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());
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user