22/// supported platforms.
33
44use crate :: env;
5+ use crate :: fmt;
56use crate :: io;
67use crate :: io:: prelude:: * ;
7- use crate :: mem;
88use crate :: path:: { self , Path } ;
9- use crate :: ptr;
109use crate :: sync:: atomic:: { self , Ordering } ;
1110use crate :: sys:: mutex:: Mutex ;
1211
13- use backtrace:: { BytesOrWideString , Frame , Symbol } ;
14-
15- pub const HEX_WIDTH : usize = 2 + 2 * mem:: size_of :: < usize > ( ) ;
12+ use backtrace:: { BacktraceFmt , BytesOrWideString , PrintFmt } ;
1613
1714/// Max number of frames to print.
1815const MAX_NB_FRAMES : usize = 100 ;
1916
2017/// Prints the current backtrace.
21- pub fn print ( w : & mut dyn Write , format : PrintFormat ) -> io:: Result < ( ) > {
18+ pub fn print ( w : & mut dyn Write , format : PrintFmt ) -> io:: Result < ( ) > {
2219 static LOCK : Mutex = Mutex :: new ( ) ;
2320
2421 // There are issues currently linking libbacktrace into tests, and in
@@ -39,26 +36,66 @@ pub fn print(w: &mut dyn Write, format: PrintFormat) -> io::Result<()> {
3936 }
4037}
4138
42- fn _print ( w : & mut dyn Write , format : PrintFormat ) -> io:: Result < ( ) > {
43- writeln ! ( w, "stack backtrace:" ) ?;
39+ fn _print ( w : & mut dyn Write , format : PrintFmt ) -> io:: Result < ( ) > {
40+ struct DisplayBacktrace {
41+ format : PrintFmt ,
42+ }
43+ impl fmt:: Display for DisplayBacktrace {
44+ fn fmt ( & self , fmt : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
45+ _print_fmt ( fmt, self . format )
46+ }
47+ }
48+ write ! ( w, "{}" , DisplayBacktrace { format } )
49+ }
4450
45- let mut printer = Printer :: new ( format, w) ;
51+ fn _print_fmt ( fmt : & mut fmt:: Formatter < ' _ > , print_fmt : PrintFmt ) -> fmt:: Result {
52+ let mut print_path = move |fmt : & mut fmt:: Formatter < ' _ > , bows : BytesOrWideString < ' _ > | {
53+ output_filename ( fmt, bows, print_fmt)
54+ } ;
55+ let mut bt_fmt = BacktraceFmt :: new ( fmt, print_fmt, & mut print_path) ;
56+ bt_fmt. add_context ( ) ?;
57+ let mut skipped = false ;
4658 unsafe {
59+ let mut idx = 0 ;
60+ let mut res = Ok ( ( ) ) ;
4761 backtrace:: trace_unsynchronized ( |frame| {
62+ if print_fmt == PrintFmt :: Short && idx > MAX_NB_FRAMES {
63+ skipped = true ;
64+ return false ;
65+ }
66+
4867 let mut hit = false ;
68+ let mut stop = false ;
4969 backtrace:: resolve_frame_unsynchronized ( frame, |symbol| {
5070 hit = true ;
51- printer. output ( frame, Some ( symbol) ) ;
71+ if print_fmt == PrintFmt :: Short {
72+ if let Some ( sym) = symbol. name ( ) . and_then ( |s| s. as_str ( ) ) {
73+ if sym. contains ( "__rust_begin_short_backtrace" ) {
74+ skipped = true ;
75+ stop = true ;
76+ return ;
77+ }
78+ }
79+ }
80+
81+ res = bt_fmt. frame ( ) . symbol ( frame, symbol) ;
5282 } ) ;
83+ if stop {
84+ return false ;
85+ }
5386 if !hit {
54- printer . output ( frame, None ) ;
87+ res = bt_fmt . frame ( ) . print_raw ( frame. ip ( ) , None , None , None ) ;
5588 }
56- !printer. done
89+
90+ idx += 1 ;
91+ res. is_ok ( )
5792 } ) ;
93+ res?;
5894 }
59- if printer. skipped {
95+ bt_fmt. finish ( ) ?;
96+ if skipped {
6097 writeln ! (
61- w ,
98+ fmt ,
6299 "note: Some details are omitted, \
63100 run with `RUST_BACKTRACE=full` for a verbose backtrace."
64101 ) ?;
@@ -77,33 +114,24 @@ where
77114 f ( )
78115}
79116
80- /// Controls how the backtrace should be formatted.
81- #[ derive( Debug , Copy , Clone , Eq , PartialEq ) ]
82- pub enum PrintFormat {
83- /// Show only relevant data from the backtrace.
84- Short = 2 ,
85- /// Show all the frames with absolute path for files.
86- Full = 3 ,
87- }
88-
89117// For now logging is turned off by default, and this function checks to see
90118// whether the magical environment variable is present to see if it's turned on.
91- pub fn log_enabled ( ) -> Option < PrintFormat > {
119+ pub fn log_enabled ( ) -> Option < PrintFmt > {
92120 static ENABLED : atomic:: AtomicIsize = atomic:: AtomicIsize :: new ( 0 ) ;
93121 match ENABLED . load ( Ordering :: SeqCst ) {
94122 0 => { }
95123 1 => return None ,
96- 2 => return Some ( PrintFormat :: Short ) ,
97- _ => return Some ( PrintFormat :: Full ) ,
124+ 2 => return Some ( PrintFmt :: Short ) ,
125+ _ => return Some ( PrintFmt :: Full ) ,
98126 }
99127
100128 let val = env:: var_os ( "RUST_BACKTRACE" ) . and_then ( |x| {
101129 if & x == "0" {
102130 None
103131 } else if & x == "full" {
104- Some ( PrintFormat :: Full )
132+ Some ( PrintFmt :: Full )
105133 } else {
106- Some ( PrintFormat :: Short )
134+ Some ( PrintFmt :: Short )
107135 }
108136 } ) ;
109137 ENABLED . store (
@@ -116,130 +144,45 @@ pub fn log_enabled() -> Option<PrintFormat> {
116144 val
117145}
118146
119- struct Printer < ' a , ' b > {
120- format : PrintFormat ,
121- done : bool ,
122- skipped : bool ,
123- idx : usize ,
124- out : & ' a mut ( dyn Write + ' b ) ,
125- }
126-
127- impl < ' a , ' b > Printer < ' a , ' b > {
128- fn new ( format : PrintFormat , out : & ' a mut ( dyn Write + ' b ) ) -> Printer < ' a , ' b > {
129- Printer { format, done : false , skipped : false , idx : 0 , out }
130- }
131-
132- /// Prints the symbol of the backtrace frame.
133- ///
134- /// These output functions should now be used everywhere to ensure consistency.
135- /// You may want to also use `output_fileline`.
136- fn output ( & mut self , frame : & Frame , symbol : Option < & Symbol > ) {
137- if self . idx > MAX_NB_FRAMES {
138- self . done = true ;
139- self . skipped = true ;
140- return ;
141- }
142- if self . _output ( frame, symbol) . is_err ( ) {
143- self . done = true ;
144- }
145- self . idx += 1 ;
146- }
147-
148- fn _output ( & mut self , frame : & Frame , symbol : Option < & Symbol > ) -> io:: Result < ( ) > {
149- if self . format == PrintFormat :: Short {
150- if let Some ( sym) = symbol. and_then ( |s| s. name ( ) ) . and_then ( |s| s. as_str ( ) ) {
151- if sym. contains ( "__rust_begin_short_backtrace" ) {
152- self . skipped = true ;
153- self . done = true ;
154- return Ok ( ( ) ) ;
155- }
156- }
157-
158- // Remove the `17: 0x0 - <unknown>` line.
159- if self . format == PrintFormat :: Short && frame. ip ( ) == ptr:: null_mut ( ) {
160- self . skipped = true ;
161- return Ok ( ( ) ) ;
162- }
163- }
164-
165- match self . format {
166- PrintFormat :: Full => {
167- write ! ( self . out, " {:2}: {:2$?} - " , self . idx, frame. ip( ) , HEX_WIDTH ) ?
168- }
169- PrintFormat :: Short => write ! ( self . out, " {:2}: " , self . idx) ?,
170- }
171-
172- match symbol. and_then ( |s| s. name ( ) ) {
173- Some ( symbol) => {
174- match self . format {
175- PrintFormat :: Full => write ! ( self . out, "{}" , symbol) ?,
176- // Strip the trailing hash if short mode.
177- PrintFormat :: Short => write ! ( self . out, "{:#}" , symbol) ?,
178- }
179- }
180- None => self . out . write_all ( b"<unknown>" ) ?,
147+ /// Prints the filename of the backtrace frame.
148+ ///
149+ /// See also `output`.
150+ fn output_filename (
151+ fmt : & mut fmt:: Formatter < ' _ > ,
152+ bows : BytesOrWideString < ' _ > ,
153+ print_fmt : PrintFmt ,
154+ ) -> fmt:: Result {
155+ #[ cfg( windows) ]
156+ let path_buf;
157+ let file = match bows {
158+ #[ cfg( unix) ]
159+ BytesOrWideString :: Bytes ( bytes) => {
160+ use crate :: os:: unix:: prelude:: * ;
161+ Path :: new ( crate :: ffi:: OsStr :: from_bytes ( bytes) )
181162 }
182- self . out . write_all ( b" \n " ) ? ;
183- if let Some ( sym ) = symbol {
184- self . output_fileline ( sym ) ? ;
163+ # [ cfg ( not ( unix ) ) ]
164+ BytesOrWideString :: Bytes ( bytes ) => {
165+ Path :: new ( crate :: str :: from_utf8 ( bytes ) . unwrap_or ( "<unknown>" ) )
185166 }
186- Ok ( ( ) )
187- }
188-
189- /// Prints the filename and line number of the backtrace frame.
190- ///
191- /// See also `output`.
192- fn output_fileline ( & mut self , symbol : & Symbol ) -> io:: Result < ( ) > {
193167 #[ cfg( windows) ]
194- let path_buf;
195- let file = match symbol. filename_raw ( ) {
196- #[ cfg( unix) ]
197- Some ( BytesOrWideString :: Bytes ( bytes) ) => {
198- use crate :: os:: unix:: prelude:: * ;
199- Path :: new ( crate :: ffi:: OsStr :: from_bytes ( bytes) )
200- }
201- #[ cfg( not( unix) ) ]
202- Some ( BytesOrWideString :: Bytes ( bytes) ) => {
203- Path :: new ( crate :: str:: from_utf8 ( bytes) . unwrap_or ( "<unknown>" ) )
204- }
205- #[ cfg( windows) ]
206- Some ( BytesOrWideString :: Wide ( wide) ) => {
207- use crate :: os:: windows:: prelude:: * ;
208- path_buf = crate :: ffi:: OsString :: from_wide ( wide) ;
209- Path :: new ( & path_buf)
210- }
211- #[ cfg( not( windows) ) ]
212- Some ( BytesOrWideString :: Wide ( _wide) ) => {
213- Path :: new ( "<unknown>" )
214- }
215- None => return Ok ( ( ) ) ,
216- } ;
217- let line = match symbol. lineno ( ) {
218- Some ( line) => line,
219- None => return Ok ( ( ) ) ,
220- } ;
221- // prior line: " ##: {:2$} - func"
222- self . out . write_all ( b"" ) ?;
223- match self . format {
224- PrintFormat :: Full => write ! ( self . out, " {:1$}" , "" , HEX_WIDTH ) ?,
225- PrintFormat :: Short => write ! ( self . out, " " ) ?,
168+ BytesOrWideString :: Wide ( wide) => {
169+ use crate :: os:: windows:: prelude:: * ;
170+ path_buf = crate :: ffi:: OsString :: from_wide ( wide) ;
171+ Path :: new ( & path_buf)
226172 }
227-
228- let mut already_printed = false ;
229- if self . format == PrintFormat :: Short && file. is_absolute ( ) {
230- if let Ok ( cwd) = env:: current_dir ( ) {
231- if let Ok ( stripped) = file. strip_prefix ( & cwd) {
232- if let Some ( s) = stripped. to_str ( ) {
233- write ! ( self . out, " at .{}{}:{}" , path:: MAIN_SEPARATOR , s, line) ?;
234- already_printed = true ;
235- }
173+ #[ cfg( not( windows) ) ]
174+ BytesOrWideString :: Wide ( _wide) => {
175+ Path :: new ( "<unknown>" )
176+ }
177+ } ;
178+ if print_fmt == PrintFmt :: Short && file. is_absolute ( ) {
179+ if let Ok ( cwd) = env:: current_dir ( ) {
180+ if let Ok ( stripped) = file. strip_prefix ( & cwd) {
181+ if let Some ( s) = stripped. to_str ( ) {
182+ return write ! ( fmt, ".{}{}" , path:: MAIN_SEPARATOR , s) ;
236183 }
237184 }
238185 }
239- if !already_printed {
240- write ! ( self . out, " at {}:{}" , file. display( ) , line) ?;
241- }
242-
243- self . out . write_all ( b"\n " )
244186 }
187+ fmt:: Display :: fmt ( & file. display ( ) , fmt)
245188}
0 commit comments