Next Generation WASM Microkernel Operating System
at trap_handler 157 lines 5.2 kB view raw
1// Copyright 2025 Jonas Kruckenberg 2// 3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or 4// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or 5// http://opensource.org/licenses/MIT>, at your option. This file may not be 6// copied, modified, or distributed except according to those terms. 7 8#![no_std] // this is crate is fully incompatible with `std` due to clashing lang item definitions 9#![cfg(target_os = "none")] 10 11mod symbolize; 12 13use arrayvec::ArrayVec; 14use core::fmt; 15use core::fmt::Formatter; 16use fallible_iterator::FallibleIterator; 17use unwind2::FrameIter; 18 19pub use crate::symbolize::SymbolizeContext; 20 21#[derive(Clone)] 22pub struct Backtrace<'a, 'data, const MAX_FRAMES: usize> { 23 symbolize_ctx: &'a SymbolizeContext<'data>, 24 pub frames: ArrayVec<usize, MAX_FRAMES>, 25 pub frames_omitted: usize, 26} 27 28impl<'a, 'data, const MAX_FRAMES: usize> Backtrace<'a, 'data, MAX_FRAMES> { 29 /// Captures a backtrace at the callsite of this function, returning an owned representation. 30 /// 31 /// The returned object is almost entirely self-contained. It can be cloned, or send to other threads. 32 /// 33 /// Note that this step is quite cheap, contrary to the `Backtrace` implementation in the standard 34 /// library this resolves the symbols (the expensive step) lazily, so this struct can be constructed 35 /// in performance sensitive codepaths and only later resolved. 36 /// 37 /// # Errors 38 /// 39 /// Returns the underlying [`unwind2::Error`] if walking the stack fails. 40 #[inline] 41 pub fn capture(ctx: &'a SymbolizeContext<'data>) -> Result<Self, unwind2::Error> { 42 Self::new_inner(ctx, FrameIter::new()) 43 } 44 45 /// Constructs a backtrace from the provided register context, returning an owned representation. 46 /// 47 /// The returned object is almost entirely self-contained. It can be cloned, or send to other threads. 48 /// 49 /// Note that this step is quite cheap, contrary to the `Backtrace` implementation in the standard 50 /// library this resolves the symbols (the expensive step) lazily, so this struct can be constructed 51 /// in performance sensitive codepaths and only later resolved. 52 /// 53 /// # Errors 54 /// 55 /// Returns the underlying [`unwind2::Error`] if walking the stack fails. 56 #[inline] 57 pub fn from_registers( 58 ctx: &'a SymbolizeContext<'data>, 59 regs: unwind2::Registers, 60 ip: usize, 61 ) -> Result<Self, unwind2::Error> { 62 let iter = FrameIter::from_registers(regs, ip); 63 Self::new_inner(ctx, iter) 64 } 65 66 fn new_inner( 67 ctx: &'a SymbolizeContext<'data>, 68 mut iter: FrameIter, 69 ) -> Result<Self, unwind2::Error> { 70 let mut frames = ArrayVec::new(); 71 let mut frames_omitted: usize = 0; 72 73 while let Some(frame) = iter.next()? { 74 if frames.try_push(frame.ip()).is_err() { 75 frames_omitted += 1; 76 } 77 } 78 79 Ok(Self { 80 symbolize_ctx: ctx, 81 frames, 82 frames_omitted, 83 }) 84 } 85} 86 87impl<const MAX_FRAMES: usize> fmt::Display for Backtrace<'_, '_, MAX_FRAMES> { 88 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 89 writeln!(f, "stack backtrace:")?; 90 91 let mut frame_idx: i32 = 0; 92 for ip in &self.frames { 93 let mut syms = self 94 .symbolize_ctx 95 .resolve_unsynchronized(*ip as u64) 96 .unwrap(); 97 98 while let Some(sym) = syms.next().unwrap() { 99 write!(f, "{frame_idx}: {address:#x} -", address = ip)?; 100 if let Some(name) = sym.name() { 101 writeln!(f, " {name}")?; 102 } else { 103 writeln!(f, " <unknown>")?; 104 } 105 if let Some(filename) = sym.filename() { 106 write!(f, " at {filename}")?; 107 if let Some(lineno) = sym.lineno() { 108 write!(f, ":{lineno}")?; 109 } else { 110 write!(f, "??")?; 111 } 112 if let Some(colno) = sym.colno() { 113 writeln!(f, ":{colno}")?; 114 } else { 115 writeln!(f, "??")?; 116 } 117 } 118 119 frame_idx += 1i32; 120 } 121 } 122 123 Ok(()) 124 } 125} 126 127/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. Note that 128/// this is only inline(never) when backtraces in std are enabled, otherwise 129/// it's fine to optimize away. 130#[inline(never)] 131pub fn __rust_begin_short_backtrace<F, T>(f: F) -> T 132where 133 F: FnOnce() -> T, 134{ 135 let result = f(); 136 137 // prevent this frame from being tail-call optimised away 138 core::hint::black_box(()); 139 140 result 141} 142 143/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. Note that 144/// this is only inline(never) when backtraces in std are enabled, otherwise 145/// it's fine to optimize away. 146#[inline(never)] 147pub fn __rust_end_short_backtrace<F, T>(f: F) -> T 148where 149 F: FnOnce() -> T, 150{ 151 let result = f(); 152 153 // prevent this frame from being tail-call optimised away 154 core::hint::black_box(()); 155 156 result 157}