Stack unwinding library in Rust

Related tags

Utilities unwinding
Overview

Unwinding library in Rust and for Rust

crates.io docs.rs license

This library serves two purposes:

  1. Provide a pure Rust alternative to libgcc_eh or libunwind.
  2. Provide easier unwinding support for #![no_std] targets.

Currently supports x86_64, x86, RV64 and AArch64.

Unwinder

The unwinder can be enabled with unwinder feature. Here are the feature gates related to the unwinder:

Feature Default Description
unwinder Yes The primary feature gate to enable the unwinder
fde-phdr-dl Yes Use dl_iterator_phdr to retrieve frame unwind table. Depends on libc.
fde-phdr-aux No Use ELF auxiliary vector to retrieve frame unwind table. Depends on libc.
fde-registry Yes Provide __register__frame and others for dynamic registration. Requires either libc or spin for a mutex implementation.
fde-gnu-eh-frame-hdr No Use __executable_start, __etext and __GNU_EH_FRAME_HDR to retrieve frame unwind table. The former two symbols are usually provided by the linker, while the last one is provided if GNU LD is used and --eh-frame-hdr option is enabled.
fde-static No Use __executable_start, __etext and __eh_frame to retrieve frame unwind table. The former two symbols are usually provided by the linker, while the last one would need to be provided by the user via linker script.
dwarf-expr Yes Enable the dwarf expression evaluator. Usually not necessary for Rust
hide-trace Yes Hide unwinder frames in back trace

If you want to use the unwinder for other Rust (C++, or any programs that utilize the unwinder), you can build the unwinding_dyn 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/libunwinding_dyn.so` rustc +nightly -Ztreat-err-as-bug

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

extern crate unwinding;

Personality and other utilities

The library also provides Rust personality function. This can work with the unwinder described above or with a different unwinder. This can be handy if you are working on a #![no_std] binary/staticlib/cdylib and you still want unwinding support.

Here are the feature gates related:

Feature Default Description
personality No Provides #[lang = eh_personality]
print No Provides (e)?print(ln)?. This is really only here because panic handler needs to print things. Depends on libc.
panicking No Provides a generic begin_panic and catch_unwind. Only stack unwinding functionality is provided, memory allocation and panic handling is left to the user.
panic No Provides Rust begin_panic and catch_unwind. Only stack unwinding functionality is provided and no printing is done, because this feature does not depend on libc.
panic-handler No Provides #[panic_handler]. Provides similar behaviour on panic to std, with RUST_BACKTRACE support as well. Stack trace won't have symbols though. Depends on libc.
system-alloc No Provides a global allocator which calls malloc and friends. Provided for convience.

If you are writing a #![no_std] program, simply enable personality, panic-handler and system-alloc in addition to the defaults, you instantly obtains the ability to do unwinding! An example is given in the example/ folder.

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

If your linker supports --eh-frame-hdr you can also try to use fde-gnu-eh-frame-hdr instead of fde-static. GNU LD will provides a __GNU_EH_FRAME_HDR magic symbol so you don't have to provide __eh_frame through linker script.

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

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 + Yew + Axum + Tauri, full-stack Rust development for Desktop apps.

rust-yew-axum-tauri-desktop template Rust + Yew + Axum + Tauri, full-stack Rust development for Desktop apps. Crates frontend: Yew frontend app for de

Jet Li 54 Dec 23, 2022
A Bancho implementation made in Rust for the *cursed* stack.

cu.rs A Bancho implementation made in Rust for the cursed stack. THIS PROJECT IS REALLY UNFINISHED AND IN ITS EARLY STAGES A drag and drop replacement

RealistikOsu! 5 Feb 1, 2022
Rust macro to make recursive function run on the heap (i.e. no stack overflow).

Decurse Example #[decurse::decurse] // ?? Slap this on your recursive function and stop worrying about stack overflow! fn factorial(x: u32) -> u32 {

Wisha W. 18 Dec 28, 2022
A stack for rust trait objects that minimizes allocations

dynstack A stack for trait objects that minimizes allocations COMPATIBILITY NOTE: dynstack relies on an underspecified fat pointer representation. Tho

Gui Andrade 114 Nov 28, 2022
Awesome full-stack template using Yew and Rust

Docker + Actix + Yew Full Stack Template ??‍?? YouTube videos Full Stack Rust App Template using Yew + Actix! https://youtu.be/oCiGjrpGk4A Add Docker

Security Union 143 Jun 22, 2023
A stack-allocated box that stores trait objects.

This crate allows saving DST objects in the provided buffer. It allows users to create global dynamic objects on a no_std environment without a global allocator.

Aleksey Sidorov 19 Dec 13, 2022
A memory efficient immutable string type that can store up to 24* bytes on the stack

compact_str A memory efficient immutable string type that can store up to 24* bytes on the stack. * 12 bytes for 32-bit architectures About A CompactS

Parker Timmerman 342 Jan 2, 2023
A library to compile USDT probes into a Rust library

sonde sonde is a library to compile USDT probes into a Rust library, and to generate a friendly Rust idiomatic API around it. Userland Statically Defi

Ivan Enderlin 40 Jan 7, 2023
A Rust library for calculating sun positions

sun A rust port of the JS library suncalc. Install Add the following to your Cargo.toml [dependencies] sun = "0.2" Usage pub fn main() { let unixti

Markus Kohlhase 36 Dec 28, 2022
A cross-platform serial port library in Rust.

Introduction serialport-rs is a general-purpose cross-platform serial port library for Rust. It provides a blocking I/O interface and port enumeration

Bryant Mairs 143 Nov 5, 2021
A high level diffing library for rust based on diffs

Similar: A Diffing Library Similar is a dependency free crate for Rust that implements different diffing algorithms and high level interfaces for it.

Armin Ronacher 617 Dec 30, 2022
A reactive DOM library for Rust in WASM

maple A VDOM-less web library with fine-grained reactivity. Getting started The recommended build tool is Trunk. Start by adding maple-core to your Ca

Luke Chu 1.8k Jan 3, 2023
transmute-free Rust library to work with the Arrow format

Arrow2: Transmute-free Arrow This repository contains a Rust library to work with the Arrow format. It is a re-write of the official Arrow crate using

Jorge Leitao 708 Dec 30, 2022
Cross-platform Window library in Rust for Tauri. [WIP]

Cross-platform application window creation library in Rust that supports all major platforms like Windows, macOS, Linux, iOS and Android. Built for you, maintained for Tauri.

Tauri 899 Jan 1, 2023
A library in Rust for theorem proving with Intuitionistic Propositional Logic.

Prop Propositional logic with types in Rust. A library in Rust for theorem proving with Intuitionistic Propositional Logic. Supports theorem proving i

AdvancedResearch 48 Jan 3, 2023
A Rust library for constructing tilings of regular polygons

tiling tiling is a library for constructing tilings of regular polygons and their dual tilings. Resources Documentation Tilings by regular polygons Li

Jonas Michel 29 Sep 30, 2021
miette is a diagnostic library for Rust. It includes a series of traits/protocols that allow you to hook into its error reporting facilities, and even write your own error reports!

miette is a diagnostic library for Rust. It includes a series of traits/protocols that allow you to hook into its error reporting facilities, and even write your own error reports!

Kat Marchán 1.2k Jan 1, 2023
Generative arts library in Rust

Generative Generative (WIP) is 2D generational arts creation library written in Rust. Currently it is in nascent stage and is somewhat unstable. Examp

Gaurav Patel 22 May 13, 2022
Membrane is an opinionated crate that generates a Dart package from a Rust library. Extremely fast performance with strict typing and zero copy returns over the FFI boundary via bincode.

Membrane is an opinionated crate that generates a Dart package from a Rust library. Extremely fast performance with strict typing and zero copy returns over the FFI boundary via bincode.

Jerel Unruh 70 Dec 13, 2022