Stack unwinding library in Rust

Overview

Unwinding library in Rust and for Rust

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 and RV64.

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 Yes Use dl_iterator_phdr to retrieve frame unwind table. Depends on libc.
fde-registry Yes Provide __register__frame and others for dynamic registration
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.
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 unwind_dyn crate provided, and use LD_PRELOAD to replace the system unwinder with it.

cd cdylib
cargo build --release
# Test the unwinder using rustc. Why not :)
LD_PRELOAD=`../target/release/libunwind_dyn.so` rustc +nightly -Ztreat-err-as-bug

If you want to link to the unwinder in a Rust binary, simply add

extern crate unwind;

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 provide things. Depends on libc.
panic No Provides 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 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

/* 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 unwind::panic::begin_panic to initiate an unwing and catch using unwind::panic::catch_unwind, as if you have a std.

If you have your own version of thread_local and println! working, you can port panic_handler.rs for double-panic protection and stack traces!

TODO

  • A better project name!
  • Remove dependencies on alloc.
Comments
  • bare-metal link-script modification with rust-lld

    bare-metal link-script modification with rust-lld

    Modify the linker script by

    /* Inserting these two lines */ . = ALIGN(8); PROVIDE(__eh_frame = .); /* before .eh_frame rule */ .eh_frame : { KEEP (*(.eh_frame)) *(.eh_frame.*) }

    How would I do this with rust-lld?

    In my target.json, I tried to use linker: ld and then used the feature fde-gnu-eh-frame-hdr instead of fde-static, but that gives me an error saying that ld doesn't know the argument -Wl,--as-needed. That is why I believe I am stuck with rust-lld with flavour gnu, but that doesn't seem to recognise the __GNU_EH_FRAME_HDR. Is there a way I can make this work? Modifying the link script that rust-lld uses or with a build.rs or similar?

    my target.json
    {
      "llvm-target": "x86_64-unknown-none",
      "arch": "x86_64",
      "os": "none",
      "executables": true,
      "linker-flavor": "ld.lld",
      "linker": "rust-lld",
      "panic-strategy": "unwind",
      ...
    }
    
    question 
    opened by tsatke 8
  • Fix print macros without newline

    Fix print macros without newline

    print! and eprint! macros were calling writeln! instead of write!.

    Also why StdoutPrinter uses libc::printf but StderrPrinter uses libc::write? I think to avoid calling printf is better since the string is already formatted.

    opened by DBLouis 5
  • Fails to compile on recent Rust nightlies

    Fails to compile on recent Rust nightlies

    Looks like the LLVM 15 upgrade broke something:

       Compiling unwinding v0.1.4 (/private/tmp/unwinding)
    inlinable function call in a function with debug info must have a !dbg location
      call void @_Unwind_Resume(ptr %40) #15
    inlinable function call in a function with debug info must have a !dbg location
      call void @_Unwind_Resume(ptr %20) #15
    inlinable function call in a function with debug info must have a !dbg location
      call void @_Unwind_Resume(ptr %50) #15
    inlinable function call in a function with debug info must have a !dbg location
      call void @_Unwind_Resume(ptr %47) #15
    LLVM ERROR: Broken module found, compilation aborted!
    error: could not compile `unwinding`
    

    I assume this is a rustc bug, so I've filed rust-lang/rust#101121 - but filing a bug here too, just in case.

    opened by Gaelan 3
  • Extend from existing linker script?

    Extend from existing linker script?

    Currently I use this to dump the used linker script to stdout and add in the eh_frames:

    [target.x86_64-unknown-none]
    rustflags = [
        "-C", "link-arg=-Wl,-verbose"
    ]
    

    This worked ok but the problem is it is certainly not good accounting for multiple targets. For each build target we will need each linker script and that's a pretty big burden. Wonder if there is any possible way to extend from the existing linker script by patching or just stick it to some specific platforms as a setback?

    PS: --eh-frame-hdr is broken in rust-lld. IDK why. I specified it directly in rustflags link-args, but even that didn't add in the GNU EH frames. That's the whole reason I needed linker script extension, or otherwise I could just use fde-gnu-eh-frame-hdr feature instead. This has something in common with #6

    question 
    opened by stevefan1999-personal 3
  • Add a way to find `.eh_frame_hdr` using `__GNU_EH_FRAME_HDR`.

    Add a way to find `.eh_frame_hdr` using `__GNU_EH_FRAME_HDR`.

    GNU ld on at least some platforms adds a symbol __GNU_EH_FRAME_HDR for the .eh_frame_hdr section. Add a cargo feature fde-gnu-eh-frame-hdr to enable use of this.

    opened by sunfishcode 3
  • Add `fde-deferred` feature

    Add `fde-deferred` feature

    This PR proposes a feature called fde-deferred which, when selected, enables a new FDE finding strategy. This strategy depends on the following symbols, which may be defined by dependent crates:

    extern "Rust" {
        // Required
        fn __unwinding_get_text_base(pc: usize) -> Option<usize>;
    
        // At least one of these must be defined
        fn __unwinding_get_eh_frame_hdr() -> Option<usize>;
        fn __unwinding_get_eh_frame() -> Option<usize>;
    }
    

    This strategy provides maximal flexibility, at the expense of requiring support from dependent crates. That is, the discovery of these base addresses is deferred to dependent crates.

    As a concrete example of the usefulness of a feature like this, I'm using this crate in a bare microkernel userspace environment. In this instance, a program's PHDRs are made available to it in a nonstandard way. This fde-deferred feature would allow dependent runtime crates to pass the relevant base address information back to unwinding. In this case, for example, fde-deferred has the advantage of being linker-independent (unlike fde-gnu-eh-frame-hdr) and does not require a custom linker script (unlike fde-static).

    If you are considering accepting this PR, then I will, of course, add documentation.

    opened by nspin 5
  • Unwind support on ARM architecture

    Unwind support on ARM architecture

    WIP support for ARM, can do backtrace on basic functions. Eventually, this PR will solve https://github.com/nbdd0121/unwinding/issues/3.

    For a working (backtrace) example you can check https://github.com/arturkow2000/qemu-example/pull/1. You need to

    export DEFMT_LOG=trace
    export RUSTFLAGS=-Cforce-unwind-tables=on
    

    before building app. For details see README in the repo.

    opened by arturkow2000 0
Owner
Gary Guo
Gary Guo
Rust bindings for accessing the Go containers/image stack

Rust bindings for accessing the Go containers/image stack This crate contains a Rust API that forks /usr/bin/skopeo and talks to it via a custom API.

Colin Walters 1 Oct 15, 2021
A dynamically typed, interpreted, stack-based language.

Stacc A dynamically typed, interpreted, stack-based language. How does it work? Each call-frame/scope has its own variables and stack, so you can get/

null 8 Nov 12, 2021
Dc improved: Feature-added rewrite of a 50+ year old RPN calculator/stack machine/programming language

dcim [WIP] dc improved: Feature-added rewrite of a 50+ year old RPN calculator/stack machine/programming language This readme is currently incomplete.

null 3 Jun 18, 2022
Rust library for build scripts to compile C/C++ code into a Rust library

A library to compile C/C++/assembly into a Rust library/application.

Alex Crichton 1.3k Dec 21, 2022
Rust Attribute-Based Encryption library rabe's C FFI binding , support CP-ABE and KP-ABE encrypt and decrypt, submodule of Rabe.Core c# library.

Rabe-ffi Rust Attribute-Based Encryption library rabe's C FFI binding , support CP-ABE and KP-ABE encrypt and decrypt, submodule of Rabe.Core c# libra

Aya0wind 2 Oct 10, 2022
Rust library to interface with Lua

hlua This library is a high-level binding for Lua 5.2. You don't have access to the Lua stack, all you can do is read/write variables (including callb

Pierre Krieger 488 Dec 26, 2022
A minimalist and safe ECS library for rust!

The full ECS (Entity-Component-System) library. Support an Open Source Developer! ♥️ Composed of two smaller libraries: world_dispatcher: the System p

Joël Lupien 124 Dec 19, 2022
A library for functional programming in Rust

It contains purely functional data structures to supplement the functional programming needs alongside with the Rust Standard Library.

Jason Shin 1.1k Dec 30, 2022
A rust library containing typings and utility functions dealing with the Public specification of the Internet Computer.

IC Types Contributing Please follow the guidelines in the CONTRIBUTING.md document. Goal This library contains typings and utility functions dealing w

DFINITY 5 Nov 28, 2022
Lineiform is a meta-JIT library for Rust interpreters

Lineiform Lineiform is a meta-JIT library for Rust interpreters. Given an interpreter that uses closure generation, it allows an author to add minimal

null 112 Jan 4, 2023
libnotcurses-sys is a low-level Rust wrapper for the notcurses C library

libnotcurses-sys is a low-level Rust wrapper for the notcurses C library This library is built with several layers of zero-overhead abstractions over

nick black 29 Nov 26, 2022
A minimal library for building compiled Node.js add-ons in Rust via Node-API

A minimal library for building compiled Node.js add-ons in Rust via Node-API

Node-API (N-API) for Rust 3.1k Dec 29, 2022
witgen is a library to generate .wit files for WebAssembly in Rust

witgen witgen is a library to help you generate wit definitions in a wit file for WebAssembly. Using this lib in addition to wit-bindgen will help you

Coenen Benjamin 28 Nov 9, 2022
A simple library to allow for easy use of python from rust.

Rustpy A simple library to allow for easy use of python from rust. Status Currently this library has not received much love (pull requests welcome for

Luke 74 Jun 20, 2022
Robust and Fast tokenizations alignment library for Rust and Python

Robust and Fast tokenizations alignment library for Rust and Python Demo: demo Rust document: docs.rs Blog post: How to calculate the alignment betwee

Explosion 157 Dec 28, 2022
Very experimental Python bindings for the Rust biscuit-auth library

Overview This is a very experimental take on Python bindings for the biscuit_auth Rust library. It is very much a work in progress (limited testing, m

Josh Wright 5 Sep 14, 2022
Python bindings for heck, the Rust case conversion library

pyheck PyHeck is a case conversion library (for converting strings to snake_case, camelCase etc). It is a thin wrapper around the Rust library heck. R

Kevin Heavey 35 Nov 7, 2022
Arrowdantic is a small Python library backed by a mature Rust implementation of Apache Arrow

Welcome to arrowdantic Arrowdantic is a small Python library backed by a mature Rust implementation of Apache Arrow that can interoperate with Parquet

Jorge Leitao 52 Dec 21, 2022
Rust bindings for Supabase JavaScript library via WebAssembly.

supabase-js-rs Rust bindings for Supabase JavaScript library via WebAssembly. Usage Add supabase-js-rs to Cargo.toml supabase-js-rs = { version = "0.1

Valery Stepanov 8 Jan 13, 2023