]>
git.proxmox.com Git - rustc.git/blob - vendor/backtrace/src/print.rs
1 use crate::BytesOrWideString
;
5 const HEX_WIDTH
: usize = 2 + 2 * core
::mem
::size_of
::<usize>();
7 #[cfg(target_os = "fuchsia")]
10 /// A formatter for backtraces.
12 /// This type can be used to print a backtrace regardless of where the backtrace
13 /// itself comes from. If you have a `Backtrace` type then its `Debug`
14 /// implementation already uses this printing format.
15 pub struct BacktraceFmt
<'a
, 'b
> {
16 fmt
: &'a
mut fmt
::Formatter
<'b
>,
19 print_path
: &'a
mut (FnMut(&mut fmt
::Formatter
, BytesOrWideString
) -> fmt
::Result
+ 'b
),
22 /// The styles of printing that we can print
23 #[derive(Copy, Clone, Eq, PartialEq)]
25 /// Prints a terser backtrace which ideally only contains relevant information
27 /// Prints a backtrace that contains all possible information
33 impl<'a
, 'b
> BacktraceFmt
<'a
, 'b
> {
34 /// Create a new `BacktraceFmt` which will write output to the provided
37 /// The `format` argument will control the style in which the backtrace is
38 /// printed, and the `print_path` argument will be used to print the
39 /// `BytesOrWideString` instances of filenames. This type itself doesn't do
40 /// any printing of filenames, but this callback is required to do so.
42 fmt
: &'a
mut fmt
::Formatter
<'b
>,
44 print_path
: &'a
mut (FnMut(&mut fmt
::Formatter
, BytesOrWideString
) -> fmt
::Result
+ 'b
),
54 /// Prints a preamble for the backtrace about to be printed.
56 /// This is required on some platforms for backtraces to be fully
57 /// sumbolicated later, and otherwise this should just be the first method
58 /// you call after creating a `BacktraceFmt`.
59 pub fn add_context(&mut self) -> fmt
::Result
{
60 #[cfg(target_os = "fuchsia")]
61 fuchsia
::print_dso_context(self.fmt
)?
;
65 /// Adds a frame to the backtrace output.
67 /// This commit returns an RAII instance of a `BacktraceFrameFmt` which can be used
68 /// to actually print a frame, and on destruction it will increment the
70 pub fn frame(&mut self) -> BacktraceFrameFmt
<'_
, 'a
, 'b
> {
77 /// Completes the backtrace output.
79 /// This is currently a no-op but is added for future compatibility with
80 /// backtrace formats.
81 pub fn finish(&mut self) -> fmt
::Result
{
82 // Currently a no-op-- including this hook to allow for future additions.
87 /// A formatter for just one frame of a backtrace.
89 /// This type is created by the `BacktraceFmt::frame` function.
90 pub struct BacktraceFrameFmt
<'fmt
, 'a
, 'b
> {
91 fmt
: &'fmt
mut BacktraceFmt
<'a
, 'b
>,
95 impl BacktraceFrameFmt
<'_
, '_
, '_
> {
96 /// Prints a `BacktraceFrame` with this frame formatter.
98 /// This will recusrively print all `BacktraceSymbol` instances within the
101 /// # Required features
103 /// This function requires the `std` feature of the `backtrace` crate to be
104 /// enabled, and the `std` feature is enabled by default.
105 #[cfg(feature = "std")]
106 pub fn backtrace_frame(&mut self, frame
: &crate::BacktraceFrame
) -> fmt
::Result
{
107 let symbols
= frame
.symbols();
108 for symbol
in symbols
{
109 self.backtrace_symbol(frame
, symbol
)?
;
111 if symbols
.is_empty() {
112 self.print_raw(frame
.ip(), None
, None
, None
)?
;
117 /// Prints a `BacktraceSymbol` within a `BacktraceFrame`.
119 /// # Required features
121 /// This function requires the `std` feature of the `backtrace` crate to be
122 /// enabled, and the `std` feature is enabled by default.
123 #[cfg(feature = "std")]
124 pub fn backtrace_symbol(
126 frame
: &crate::BacktraceFrame
,
127 symbol
: &crate::BacktraceSymbol
,
132 // TODO: this isn't great that we don't end up printing anything
133 // with non-utf8 filenames. Thankfully almost everything is utf8 so
134 // this shouldn't be too too bad.
137 .and_then(|p
| Some(BytesOrWideString
::Bytes(p
.to_str()?
.as_bytes()))),
143 /// Prints a raw traced `Frame` and `Symbol`, typically from within the raw
144 /// callbacks of this crate.
145 pub fn symbol(&mut self, frame
: &crate::Frame
, symbol
: &crate::Symbol
) -> fmt
::Result
{
149 symbol
.filename_raw(),
155 /// Adds a raw frame to the backtrace output.
157 /// This method, unlike the previous, takes the raw arguments in case
158 /// they're being source from different locations. Note that this may be
159 /// called multiple times for one frame.
162 frame_ip
: *mut c_void
,
163 symbol_name
: Option
<crate::SymbolName
>,
164 filename
: Option
<BytesOrWideString
>,
167 // Fuchsia is unable to symbolize within a process so it has a special
168 // format which can be used to symbolize later. Print that instead of
169 // printing addresses in our own format here.
170 if cfg
!(target_os
= "fuchsia") {
171 self.print_raw_fuchsia(frame_ip
)?
;
173 self.print_raw_generic(frame_ip
, symbol_name
, filename
, lineno
)?
;
175 self.symbol_index
+= 1;
180 fn print_raw_generic(
182 mut frame_ip
: *mut c_void
,
183 symbol_name
: Option
<crate::SymbolName
>,
184 filename
: Option
<BytesOrWideString
>,
187 // No need to print "null" frames, it basically just means that the
188 // system backtrace was a bit eager to trace back super far.
189 if let PrintFmt
::Short
= self.fmt
.format
{
190 if frame_ip
.is_null() {
195 // To reduce TCB size in Sgx enclave, we do not want to implement symbol
196 // resolution functionality. Rather, we can print the offset of the
197 // address here, which could be later mapped to correct function.
198 #[cfg(all(feature = "std", target_env = "sgx", target_vendor = "fortanix"))]
200 let image_base
= std
::os
::fortanix_sgx
::mem
::image_base();
201 frame_ip
= usize::wrapping_sub(frame_ip
as usize, image_base
as _
) as _
;
204 // Print the index of the frame as well as the optional instruction
205 // pointer of the frame. If we're beyond the first symbol of this frame
206 // though we just print appropriate whitespace.
207 if self.symbol_index
== 0 {
208 write
!(self.fmt
.fmt
, "{:4}: ", self.fmt
.frame_index
)?
;
209 if let PrintFmt
::Full
= self.fmt
.format
{
210 write
!(self.fmt
.fmt
, "{:1$?} - ", frame_ip
, HEX_WIDTH
)?
;
213 write
!(self.fmt
.fmt
, " ")?
;
214 if let PrintFmt
::Full
= self.fmt
.format
{
215 write
!(self.fmt
.fmt
, "{:1$}", "", HEX_WIDTH
+ 3)?
;
219 // Next up write out the symbol name, using the alternate formatting for
220 // more information if we're a full backtrace. Here we also handle
221 // symbols which don't have a name,
222 match (symbol_name
, &self.fmt
.format
) {
223 (Some(name
), PrintFmt
::Short
) => write
!(self.fmt
.fmt
, "{:#}", name
)?
,
224 (Some(name
), PrintFmt
::Full
) => write
!(self.fmt
.fmt
, "{}", name
)?
,
225 (None
, _
) | (_
, PrintFmt
::__Nonexhaustive
) => write
!(self.fmt
.fmt
, "<unknown>")?
,
227 self.fmt
.fmt
.write_str("\n")?
;
229 // And last up, print out the filename/line number if they're available.
230 if let (Some(file
), Some(line
)) = (filename
, lineno
) {
231 self.print_fileline(file
, line
)?
;
237 fn print_fileline(&mut self, file
: BytesOrWideString
, line
: u32) -> fmt
::Result
{
238 // Filename/line are printed on lines under the symbol name, so print
239 // some appropriate whitespace to sort of right-align ourselves.
240 if let PrintFmt
::Full
= self.fmt
.format
{
241 write
!(self.fmt
.fmt
, "{:1$}", "", HEX_WIDTH
)?
;
243 write
!(self.fmt
.fmt
, " at ")?
;
245 // Delegate to our internal callback to print the filename and then
246 // print out the line number.
247 (self.fmt
.print_path
)(self.fmt
.fmt
, file
)?
;
248 write
!(self.fmt
.fmt
, ":{}\n", line
)?
;
252 fn print_raw_fuchsia(&mut self, frame_ip
: *mut c_void
) -> fmt
::Result
{
253 // We only care about the first symbol of a frame
254 if self.symbol_index
== 0 {
255 self.fmt
.fmt
.write_str("{{{bt:")?
;
256 write
!(self.fmt
.fmt
, "{}:{:?}", self.fmt
.frame_index
, frame_ip
)?
;
257 self.fmt
.fmt
.write_str("}}}\n")?
;
263 impl Drop
for BacktraceFrameFmt
<'_
, '_
, '_
> {
265 self.fmt
.frame_index
+= 1;