Skip to content

Commit

Permalink
Expose the unwinding crate's "personality" and "panic-handler" features.
Browse files Browse the repository at this point in the history
The unwinding crate provides "personality" and "panic-handler" features
which define real `#[lang = eh_personality]` and `#[panic_handler]`
implementations that support unwinding.

This follows the suggestion in sunfishcode/eyra#51.
  • Loading branch information
sunfishcode committed Oct 7, 2024
1 parent cb63742 commit d7ca156
Show file tree
Hide file tree
Showing 10 changed files with 117 additions and 2 deletions.
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,6 @@ using `#![no_builtins]`.
[c-gull]: https://github.com/sunfishcode/c-ward/tree/main/c-gull#readme
[relibc]: https://gitlab.redox-os.org/redox-os/relibc/
[tinyrlibc]: https://github.com/rust-embedded-community/tinyrlibc
[c-scape-example]: https://github.com/sunfishcode/c-ward/blob/main/example-crates/c-scape-example
[c-gull-example]: https://github.com/sunfishcode/c-ward/blob/main/example-crates/c-gull-example
[Mustang]: https://github.com/sunfishcode/mustang#readme
[Eyra]: https://github.com/sunfishcode/eyra#readme
["coexist-with-libc" mode]: https://github.com/sunfishcode/c-ward/blob/main/example-crates/libc-replacement#readme
8 changes: 8 additions & 0 deletions c-gull/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,11 @@ todo = ["c-scape/todo"]

# Enable `unimplemented!()` stubs for deprecated functions.
deprecated-and-unimplemented = ["c-scape/deprecated-and-unimplemented"]

# Provide a `#[lang = eh_personality]` function suitable for unwinding.
# https://crates.io/crates/unwinding#personality-and-other-utilities
personality = ["c-scape/personality"]

# Provide a `#[panic_handler]` function suitable for unwinding.
# https://crates.io/crates/unwinding#personality-and-other-utilities
panic-handler = ["c-scape/panic-handler"]
8 changes: 8 additions & 0 deletions c-scape/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,14 @@ todo = []
# Enable `unimplemented!()` stubs for deprecated functions.
deprecated-and-unimplemented = []

# Provide a `#[lang = eh_personality]` function suitable for unwinding.
# https://crates.io/crates/unwinding#personality-and-other-utilities
personality = ["unwinding/personality"]

# Provide a `#[panic_handler]` function suitable for unwinding.
# https://crates.io/crates/unwinding#personality-and-other-utilities
panic-handler = ["unwinding/panic-handler"]

# This extends the `syscall` function with suppport for more syscalls. This is
# not enabled by default because it increases the code size of `syscall` by
# several kibibytes and isn't needed by most Rust programs.
Expand Down
7 changes: 7 additions & 0 deletions example-crates/c-scape-example/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,10 @@ and `no_std`.

This version uses `-nostartfiles` and origin is in control from the very
beginning.

This crate uses stub `#[panic_handler]` and `#[lang = "eh_personality"]`
functions which are simple and have small code size, but which don't support
unwinding. See the [c-scape-unwinding] crate for an example that includes
unwinding support.

[c-scape-unwinding]: https://github.com/sunfishcode/c-ward/tree/main/example-crates/c-scape-unwinding#readme
2 changes: 2 additions & 0 deletions example-crates/c-scape-unwinding/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/target
Cargo.lock
31 changes: 31 additions & 0 deletions example-crates/c-scape-unwinding/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
[package]
name = "c-scape-unwinding"
version = "0.0.0"
edition = "2021"
publish = false

[dependencies.libc]
path = "../../c-scape"
# Disable the default features, enable "take-charge" mode, and enable the
# "personality" and "panic-handler" features.
default-features = false
features = [
"take-charge",
"thread",
"call-main",
"malloc-via-rust-global-alloc",
"define-mem-functions",
"threadsafe-setenv",
"personality",
"panic-handler",
]
package = "c-scape"

[dependencies]
errno = { version = "0.3.3", default-features = false }
rustix-dlmalloc = { version = "0.1.0", features = ["global"] }
# Depend on `unwinding` so that we can do `catch_unwind`.
unwinding = { version = "0.2.2", default-features = false, features = ["panic"] }

# This is just an example crate, and not part of the c-ward workspace.
[workspace]
8 changes: 8 additions & 0 deletions example-crates/c-scape-unwinding/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
This crate demonstrates the use of c-scape in "take-charge" mode with `no_main`
and `no_std`, and includes unwinding panic support.

It's the same as [c-scape-example], but enables the "personality" and
"panic-handler" features instead of defining stub `#[panic_handler]` and
`#[lang = "eh_personality"]` functions, and performs an unwind.

[c-scape-example]: https://github.com/sunfishcode/c-ward/tree/main/example-crates/c-scape-example#readme
4 changes: 4 additions & 0 deletions example-crates/c-scape-unwinding/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
fn main() {
// Pass -nostartfiles to the linker.
println!("cargo:rustc-link-arg=-nostartfiles");
}
37 changes: 37 additions & 0 deletions example-crates/c-scape-unwinding/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//! A simple example using `no_main`, `no_std`, and "take-charge" mode, using
//! the "personaliity" and "panic_handler" to support unwinding.
#![no_std]
#![no_main]

#[global_allocator]
static GLOBAL_ALLOCATOR: rustix_dlmalloc::GlobalDlmalloc = rustix_dlmalloc::GlobalDlmalloc;

#[no_mangle]
unsafe extern "C" fn main(_argc: i32, _argv: *const *const u8, _envp: *const *const u8) -> i32 {
// Panic and catch it.
unwinding::panic::catch_unwind(|| call_do_panic()).unwrap_err();

// Call functions declared in the `libc` crate, which will be resolved by
// c-scape. c-scape doesn't have `printf`, so we do it by hand.
let message = b"Hello, world!\n";
let mut remaining = &message[..];
while !remaining.is_empty() {
match libc::write(1, message.as_ptr().cast(), message.len()) {
-1 => match errno::errno().0 {
libc::EINTR => continue,
_ => panic!(),
},
n => remaining = &remaining[n as usize..],
}
}
libc::exit(0);
}

fn call_do_panic() {
do_panic()
}

fn do_panic() {
panic!("catch me!");
}
12 changes: 12 additions & 0 deletions tests/example_crates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,18 @@ fn example_crate_c_scape_example() {
test_crate("c-scape-example", &[], &[], "Hello, world!\n", "", None);
}

#[test]
fn example_crate_c_scape_unwinding() {
test_crate(
"c-scape-unwinding",
&[],
&[],
"Hello, world!\n",
"panicked at src/main.rs:36:5:\ncatch me!\nnote: run with `RUST_BACKTRACE=1` environment variable to display a backtrace\n",
None
);
}

#[test]
fn example_crate_dns() {
test_crate(
Expand Down

0 comments on commit d7ca156

Please sign in to comment.