Next Generation WASM Microkernel Operating System
at trap_handler 184 lines 6.8 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//! Printing of backtraces. This is adapted from the standard library. 9 10use crate::backtrace::BacktraceStyle; 11use crate::backtrace::symbolize::{Symbol, SymbolName}; 12use core::fmt; 13 14const HEX_WIDTH: usize = 2 + 2 * size_of::<usize>(); 15 16/// A formatter for backtraces. 17/// 18/// This type can be used to print a backtrace regardless of where the backtrace 19/// itself comes from. If you have a `Backtrace` type then its `Debug` 20/// implementation already uses this printing format. 21pub struct BacktraceFmt<'a, 'b> { 22 fmt: &'a mut fmt::Formatter<'b>, 23 frame_index: usize, 24 format: BacktraceStyle, 25} 26impl<'a, 'b> BacktraceFmt<'a, 'b> { 27 /// Create a new `BacktraceFmt` which will write output to the provided 28 /// `fmt`. 29 /// 30 /// The `format` argument will control the style in which the backtrace is 31 /// printed, and the `print_path` argument will be used to print the 32 /// `BytesOrWideString` instances of filenames. This type itself doesn't do 33 /// any printing of filenames, but this callback is required to do so. 34 pub fn new(fmt: &'a mut fmt::Formatter<'b>, format: BacktraceStyle) -> Self { 35 BacktraceFmt { 36 fmt, 37 frame_index: 0, 38 format, 39 } 40 } 41 42 /// Adds a frame to the backtrace output. 43 /// 44 /// This commit returns an RAII instance of a `BacktraceFrameFmt` which can be used 45 /// to actually print a frame, and on destruction it will increment the 46 /// frame counter. 47 pub fn frame(&mut self) -> BacktraceFrameFmt<'_, 'a, 'b> { 48 BacktraceFrameFmt { 49 fmt: self, 50 symbol_index: 0, 51 } 52 } 53 54 /// Return the inner formatter. 55 /// 56 /// This is used for writing custom information between frames with `write!` and `writeln!`, 57 /// and won't increment the `frame_index` unlike the `frame` method. 58 pub fn formatter(&mut self) -> &mut fmt::Formatter<'b> { 59 self.fmt 60 } 61} 62 63/// A formatter for just one frame of a backtrace. 64/// 65/// This type is created by the `BacktraceFmt::frame` function. 66pub struct BacktraceFrameFmt<'fmt, 'a, 'b> { 67 fmt: &'fmt mut BacktraceFmt<'a, 'b>, 68 symbol_index: usize, 69} 70 71impl BacktraceFrameFmt<'_, '_, '_> { 72 /// Prints a symbol with this frame formatter. 73 pub fn print_symbol(&mut self, frame_ip: usize, sym: Symbol<'_>) -> fmt::Result { 74 self.print_raw_with_column( 75 frame_ip, 76 sym.name(), 77 sym.filename(), 78 sym.lineno(), 79 sym.colno(), 80 ) 81 } 82 83 /// Print a raw (read un-symbolized) address with this frame formatter. A raw address 84 /// will just show up as the address and `<unknown>` and should be used in places where we 85 /// couldn't find any symbol information for an address. 86 pub fn print_raw(&mut self, frame_ip: usize) -> fmt::Result { 87 self.print_raw_with_column(frame_ip, None, None, None, None) 88 } 89 90 fn print_raw_with_column( 91 &mut self, 92 frame_ip: usize, 93 symbol_name: Option<SymbolName<'_>>, 94 filename: Option<&str>, 95 lineno: Option<u32>, 96 colno: Option<u32>, 97 ) -> fmt::Result { 98 self.print_raw_generic(frame_ip, symbol_name, filename, lineno, colno)?; 99 self.symbol_index += 1; 100 Ok(()) 101 } 102 103 // #[allow(unused_mut)] 104 fn print_raw_generic( 105 &mut self, 106 frame_ip: usize, 107 symbol_name: Option<SymbolName<'_>>, 108 filename: Option<&str>, 109 lineno: Option<u32>, 110 colno: Option<u32>, 111 ) -> fmt::Result { 112 // No need to print "null" frames, it basically just means that the 113 // system backtrace was a bit eager to trace back super far. 114 if let BacktraceStyle::Short = self.fmt.format { 115 if frame_ip == 0 { 116 return Ok(()); 117 } 118 } 119 120 // Print the index of the frame as well as the optional instruction 121 // pointer of the frame. If we're beyond the first symbol of this frame 122 // though we just print appropriate whitespace. 123 if self.symbol_index == 0 { 124 write!(self.fmt.fmt, "{:4}: ", self.fmt.frame_index)?; 125 126 // Print the instruction pointer. If the symbol name is None we always print 127 // the address. Those weird frames don't happen that often and are always the most 128 // interesting in a backtrace, so we need to make sure to print at least the address so 129 // we have somewhere to start investigating! 130 if self.fmt.format == BacktraceStyle::Full || symbol_name.is_some() { 131 write!(self.fmt.fmt, "{frame_ip:HEX_WIDTH$x?} - ")?; 132 } 133 } else { 134 write!(self.fmt.fmt, " ")?; 135 if let BacktraceStyle::Full = self.fmt.format { 136 write!(self.fmt.fmt, "{:1$}", "", HEX_WIDTH + 3)?; 137 } 138 } 139 140 // Next up write out the symbol name, using the alternate formatting for 141 // more information if we're a full backtrace. Here we also handle 142 // symbols which don't have a name, 143 match (symbol_name, &self.fmt.format) { 144 (Some(name), BacktraceStyle::Short) => write!(self.fmt.fmt, "{name:#}")?, 145 (Some(name), BacktraceStyle::Full) => write!(self.fmt.fmt, "{name}")?, 146 (None, _) => write!(self.fmt.fmt, "<unknown>")?, 147 } 148 self.fmt.fmt.write_str("\n")?; 149 150 // And last up, print out the filename/line number if they're available. 151 if let (Some(file), Some(line)) = (filename, lineno) { 152 self.print_fileline(file, line, colno)?; 153 } 154 155 Ok(()) 156 } 157 158 fn print_fileline(&mut self, file: &str, line: u32, colno: Option<u32>) -> fmt::Result { 159 // Filename/line are printed on lines under the symbol name, so print 160 // some appropriate whitespace to sort of right-align ourselves. 161 if let BacktraceStyle::Full = self.fmt.format { 162 write!(self.fmt.fmt, "{:1$}", "", HEX_WIDTH)?; 163 } 164 write!(self.fmt.fmt, " at ")?; 165 166 // Print the filename and line number. 167 write!(self.fmt.fmt, "at {file}")?; 168 write!(self.fmt.fmt, ":{line}")?; 169 170 // Add column number, if available. 171 if let Some(colno) = colno { 172 write!(self.fmt.fmt, ":{colno}")?; 173 } 174 175 writeln!(self.fmt.fmt)?; 176 Ok(()) 177 } 178} 179 180impl Drop for BacktraceFrameFmt<'_, '_, '_> { 181 fn drop(&mut self) { 182 self.fmt.frame_index += 1; 183 } 184}