1 #[cfg(feature = "std")]
2 use super::{BacktraceFrame, BacktraceSymbol}
;
3 use super::{BytesOrWideString, Frame, SymbolName}
;
7 const HEX_WIDTH
: usize = 2 + 2 * core
::mem
::size_of
::<usize>();
9 #[cfg(target_os = "fuchsia")]
12 /// A formatter for backtraces.
14 /// This type can be used to print a backtrace regardless of where the backtrace
15 /// itself comes from. If you have a `Backtrace` type then its `Debug`
16 /// implementation already uses this printing format.
17 pub struct BacktraceFmt
<'a
, 'b
> {
18 fmt
: &'a
mut fmt
::Formatter
<'b
>,
22 &'a
mut (dyn FnMut(&mut fmt
::Formatter
<'_
>, BytesOrWideString
<'_
>) -> fmt
::Result
+ 'b
),
25 /// The styles of printing that we can print
26 #[derive(Copy, Clone, Eq, PartialEq)]
28 /// Prints a terser backtrace which ideally only contains relevant information
30 /// Prints a backtrace that contains all possible information
36 impl<'a
, 'b
> BacktraceFmt
<'a
, 'b
> {
37 /// Create a new `BacktraceFmt` which will write output to the provided
40 /// The `format` argument will control the style in which the backtrace is
41 /// printed, and the `print_path` argument will be used to print the
42 /// `BytesOrWideString` instances of filenames. This type itself doesn't do
43 /// any printing of filenames, but this callback is required to do so.
45 fmt
: &'a
mut fmt
::Formatter
<'b
>,
47 print_path
: &'a
mut (dyn FnMut(&mut fmt
::Formatter
<'_
>, BytesOrWideString
<'_
>) -> fmt
::Result
58 /// Prints a preamble for the backtrace about to be printed.
60 /// This is required on some platforms for backtraces to be fully
61 /// symbolicated later, and otherwise this should just be the first method
62 /// you call after creating a `BacktraceFmt`.
63 pub fn add_context(&mut self) -> fmt
::Result
{
64 #[cfg(target_os = "fuchsia")]
65 fuchsia
::print_dso_context(self.fmt
)?
;
69 /// Adds a frame to the backtrace output.
71 /// This commit returns an RAII instance of a `BacktraceFrameFmt` which can be used
72 /// to actually print a frame, and on destruction it will increment the
74 pub fn frame(&mut self) -> BacktraceFrameFmt
<'_
, 'a
, 'b
> {
81 /// Completes the backtrace output.
83 /// This is currently a no-op but is added for future compatibility with
84 /// backtrace formats.
85 pub fn finish(&mut self) -> fmt
::Result
{
86 // Currently a no-op-- including this hook to allow for future additions.
91 /// A formatter for just one frame of a backtrace.
93 /// This type is created by the `BacktraceFmt::frame` function.
94 pub struct BacktraceFrameFmt
<'fmt
, 'a
, 'b
> {
95 fmt
: &'fmt
mut BacktraceFmt
<'a
, 'b
>,
99 impl BacktraceFrameFmt
<'_
, '_
, '_
> {
100 /// Prints a `BacktraceFrame` with this frame formatter.
102 /// This will recursively print all `BacktraceSymbol` instances within the
103 /// `BacktraceFrame`.
105 /// # Required features
107 /// This function requires the `std` feature of the `backtrace` crate to be
108 /// enabled, and the `std` feature is enabled by default.
109 #[cfg(feature = "std")]
110 pub fn backtrace_frame(&mut self, frame
: &BacktraceFrame
) -> fmt
::Result
{
111 let symbols
= frame
.symbols();
112 for symbol
in symbols
{
113 self.backtrace_symbol(frame
, symbol
)?
;
115 if symbols
.is_empty() {
116 self.print_raw(frame
.ip(), None
, None
, None
)?
;
121 /// Prints a `BacktraceSymbol` within a `BacktraceFrame`.
123 /// # Required features
125 /// This function requires the `std` feature of the `backtrace` crate to be
126 /// enabled, and the `std` feature is enabled by default.
127 #[cfg(feature = "std")]
128 pub fn backtrace_symbol(
130 frame
: &BacktraceFrame
,
131 symbol
: &BacktraceSymbol
,
133 self.print_raw_with_column(
136 // TODO: this isn't great that we don't end up printing anything
137 // with non-utf8 filenames. Thankfully almost everything is utf8 so
138 // this shouldn't be too too bad.
141 .and_then(|p
| Some(BytesOrWideString
::Bytes(p
.to_str()?
.as_bytes()))),
148 /// Prints a raw traced `Frame` and `Symbol`, typically from within the raw
149 /// callbacks of this crate.
150 pub fn symbol(&mut self, frame
: &Frame
, symbol
: &super::Symbol
) -> fmt
::Result
{
151 self.print_raw_with_column(
154 symbol
.filename_raw(),
161 /// Adds a raw frame to the backtrace output.
163 /// This method, unlike the previous, takes the raw arguments in case
164 /// they're being source from different locations. Note that this may be
165 /// called multiple times for one frame.
168 frame_ip
: *mut c_void
,
169 symbol_name
: Option
<SymbolName
<'_
>>,
170 filename
: Option
<BytesOrWideString
<'_
>>,
173 self.print_raw_with_column(frame_ip
, symbol_name
, filename
, lineno
, None
)
176 /// Adds a raw frame to the backtrace output, including column information.
178 /// This method, like the previous, takes the raw arguments in case
179 /// they're being source from different locations. Note that this may be
180 /// called multiple times for one frame.
181 pub fn print_raw_with_column(
183 frame_ip
: *mut c_void
,
184 symbol_name
: Option
<SymbolName
<'_
>>,
185 filename
: Option
<BytesOrWideString
<'_
>>,
189 // Fuchsia is unable to symbolize within a process so it has a special
190 // format which can be used to symbolize later. Print that instead of
191 // printing addresses in our own format here.
192 if cfg
!(target_os
= "fuchsia") {
193 self.print_raw_fuchsia(frame_ip
)?
;
195 self.print_raw_generic(frame_ip
, symbol_name
, filename
, lineno
, colno
)?
;
197 self.symbol_index
+= 1;
202 fn print_raw_generic(
204 mut frame_ip
: *mut c_void
,
205 symbol_name
: Option
<SymbolName
<'_
>>,
206 filename
: Option
<BytesOrWideString
<'_
>>,
210 // No need to print "null" frames, it basically just means that the
211 // system backtrace was a bit eager to trace back super far.
212 if let PrintFmt
::Short
= self.fmt
.format
{
213 if frame_ip
.is_null() {
218 // To reduce TCB size in Sgx enclave, we do not want to implement symbol
219 // resolution functionality. Rather, we can print the offset of the
220 // address here, which could be later mapped to correct function.
221 #[cfg(all(feature = "std", target_env = "sgx", target_vendor = "fortanix"))]
223 let image_base
= std
::os
::fortanix_sgx
::mem
::image_base();
224 frame_ip
= usize::wrapping_sub(frame_ip
as usize, image_base
as _
) as _
;
227 // Print the index of the frame as well as the optional instruction
228 // pointer of the frame. If we're beyond the first symbol of this frame
229 // though we just print appropriate whitespace.
230 if self.symbol_index
== 0 {
231 write
!(self.fmt
.fmt
, "{:4}: ", self.fmt
.frame_index
)?
;
232 if let PrintFmt
::Full
= self.fmt
.format
{
233 write
!(self.fmt
.fmt
, "{:1$?} - ", frame_ip
, HEX_WIDTH
)?
;
236 write
!(self.fmt
.fmt
, " ")?
;
237 if let PrintFmt
::Full
= self.fmt
.format
{
238 write
!(self.fmt
.fmt
, "{:1$}", "", HEX_WIDTH
+ 3)?
;
242 // Next up write out the symbol name, using the alternate formatting for
243 // more information if we're a full backtrace. Here we also handle
244 // symbols which don't have a name,
245 match (symbol_name
, &self.fmt
.format
) {
246 (Some(name
), PrintFmt
::Short
) => write
!(self.fmt
.fmt
, "{:#}", name
)?
,
247 (Some(name
), PrintFmt
::Full
) => write
!(self.fmt
.fmt
, "{}", name
)?
,
248 (None
, _
) | (_
, PrintFmt
::__Nonexhaustive
) => write
!(self.fmt
.fmt
, "<unknown>")?
,
250 self.fmt
.fmt
.write_str("\n")?
;
252 // And last up, print out the filename/line number if they're available.
253 if let (Some(file
), Some(line
)) = (filename
, lineno
) {
254 self.print_fileline(file
, line
, colno
)?
;
262 file
: BytesOrWideString
<'_
>,
266 // Filename/line are printed on lines under the symbol name, so print
267 // some appropriate whitespace to sort of right-align ourselves.
268 if let PrintFmt
::Full
= self.fmt
.format
{
269 write
!(self.fmt
.fmt
, "{:1$}", "", HEX_WIDTH
)?
;
271 write
!(self.fmt
.fmt
, " at ")?
;
273 // Delegate to our internal callback to print the filename and then
274 // print out the line number.
275 (self.fmt
.print_path
)(self.fmt
.fmt
, file
)?
;
276 write
!(self.fmt
.fmt
, ":{}", line
)?
;
278 // Add column number, if available.
279 if let Some(colno
) = colno
{
280 write
!(self.fmt
.fmt
, ":{}", colno
)?
;
283 write
!(self.fmt
.fmt
, "\n")?
;
287 fn print_raw_fuchsia(&mut self, frame_ip
: *mut c_void
) -> fmt
::Result
{
288 // We only care about the first symbol of a frame
289 if self.symbol_index
== 0 {
290 self.fmt
.fmt
.write_str("{{{bt:")?
;
291 write
!(self.fmt
.fmt
, "{}:{:?}", self.fmt
.frame_index
, frame_ip
)?
;
292 self.fmt
.fmt
.write_str("}}}\n")?
;
298 impl Drop
for BacktraceFrameFmt
<'_
, '_
, '_
> {
300 self.fmt
.frame_index
+= 1;