92
92
// a backtrace or actually symbolizing it.
93
93
94
94
use crate :: env;
95
+ use crate :: ffi:: c_void;
95
96
use crate :: fmt;
96
97
use crate :: sync:: atomic:: { AtomicUsize , Ordering :: SeqCst } ;
97
98
use crate :: sync:: Mutex ;
@@ -144,10 +145,16 @@ fn _assert_send_sync() {
144
145
}
145
146
146
147
struct BacktraceFrame {
147
- frame : backtrace :: Frame ,
148
+ frame : RawFrame ,
148
149
symbols : Vec < BacktraceSymbol > ,
149
150
}
150
151
152
+ enum RawFrame {
153
+ Actual ( backtrace:: Frame ) ,
154
+ #[ cfg( test) ]
155
+ Fake ,
156
+ }
157
+
151
158
struct BacktraceSymbol {
152
159
name : Option < Vec < u8 > > ,
153
160
filename : Option < BytesOrWide > ,
@@ -162,8 +169,8 @@ enum BytesOrWide {
162
169
impl fmt:: Debug for Backtrace {
163
170
fn fmt ( & self , fmt : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
164
171
let mut capture = match & self . inner {
165
- Inner :: Unsupported => return fmt. write_str ( "unsupported backtrace " ) ,
166
- Inner :: Disabled => return fmt. write_str ( "disabled backtrace " ) ,
172
+ Inner :: Unsupported => return fmt. write_str ( "< unsupported> " ) ,
173
+ Inner :: Disabled => return fmt. write_str ( "< disabled> " ) ,
167
174
Inner :: Captured ( c) => c. lock ( ) . unwrap ( ) ,
168
175
} ;
169
176
capture. resolve ( ) ;
@@ -193,11 +200,11 @@ impl fmt::Debug for BacktraceSymbol {
193
200
if let Some ( fn_name) = self . name . as_ref ( ) . map ( |b| backtrace:: SymbolName :: new ( b) ) {
194
201
write ! ( fmt, "fn: \" {:#}\" " , fn_name) ?;
195
202
} else {
196
- write ! ( fmt, "fn: \" <unknown>\" " ) ?;
203
+ write ! ( fmt, "fn: <unknown>" ) ?;
197
204
}
198
205
199
206
if let Some ( fname) = self . filename . as_ref ( ) {
200
- write ! ( fmt, ", file: {:?}" , fname) ?;
207
+ write ! ( fmt, ", file: \" {:?}\" " , fname) ?;
201
208
}
202
209
203
210
if let Some ( line) = self . lineno . as_ref ( ) {
@@ -293,7 +300,10 @@ impl Backtrace {
293
300
let mut actual_start = None ;
294
301
unsafe {
295
302
backtrace:: trace_unsynchronized ( |frame| {
296
- frames. push ( BacktraceFrame { frame : frame. clone ( ) , symbols : Vec :: new ( ) } ) ;
303
+ frames. push ( BacktraceFrame {
304
+ frame : RawFrame :: Actual ( frame. clone ( ) ) ,
305
+ symbols : Vec :: new ( ) ,
306
+ } ) ;
297
307
if frame. symbol_address ( ) as usize == ip && actual_start. is_none ( ) {
298
308
actual_start = Some ( frames. len ( ) ) ;
299
309
}
@@ -393,8 +403,13 @@ impl Capture {
393
403
let _lock = lock ( ) ;
394
404
for frame in self . frames . iter_mut ( ) {
395
405
let symbols = & mut frame. symbols ;
406
+ let frame = match & frame. frame {
407
+ RawFrame :: Actual ( frame) => frame,
408
+ #[ cfg( test) ]
409
+ RawFrame :: Fake => unimplemented ! ( ) ,
410
+ } ;
396
411
unsafe {
397
- backtrace:: resolve_frame_unsynchronized ( & frame . frame , |symbol| {
412
+ backtrace:: resolve_frame_unsynchronized ( frame, |symbol| {
398
413
symbols. push ( BacktraceSymbol {
399
414
name : symbol. name ( ) . map ( |m| m. as_bytes ( ) . to_vec ( ) ) ,
400
415
filename : symbol. filename_raw ( ) . map ( |b| match b {
@@ -408,3 +423,65 @@ impl Capture {
408
423
}
409
424
}
410
425
}
426
+
427
+ impl RawFrame {
428
+ fn ip ( & self ) -> * mut c_void {
429
+ match self {
430
+ RawFrame :: Actual ( frame) => frame. ip ( ) ,
431
+ #[ cfg( test) ]
432
+ RawFrame :: Fake => 1 as * mut c_void ,
433
+ }
434
+ }
435
+ }
436
+
437
+ #[ test]
438
+ fn test_debug ( ) {
439
+ let backtrace = Backtrace {
440
+ inner : Inner :: Captured ( Mutex :: new ( Capture {
441
+ actual_start : 1 ,
442
+ resolved : true ,
443
+ frames : vec ! [
444
+ BacktraceFrame {
445
+ frame: RawFrame :: Fake ,
446
+ symbols: vec![ BacktraceSymbol {
447
+ name: Some ( b"std::backtrace::Backtrace::create" . to_vec( ) ) ,
448
+ filename: Some ( BytesOrWide :: Bytes ( b"rust/backtrace.rs" . to_vec( ) ) ) ,
449
+ lineno: Some ( 100 ) ,
450
+ } ] ,
451
+ } ,
452
+ BacktraceFrame {
453
+ frame: RawFrame :: Fake ,
454
+ symbols: vec![ BacktraceSymbol {
455
+ name: Some ( b"__rust_maybe_catch_panic" . to_vec( ) ) ,
456
+ filename: None ,
457
+ lineno: None ,
458
+ } ] ,
459
+ } ,
460
+ BacktraceFrame {
461
+ frame: RawFrame :: Fake ,
462
+ symbols: vec![
463
+ BacktraceSymbol {
464
+ name: Some ( b"std::rt::lang_start_internal" . to_vec( ) ) ,
465
+ filename: Some ( BytesOrWide :: Bytes ( b"rust/rt.rs" . to_vec( ) ) ) ,
466
+ lineno: Some ( 300 ) ,
467
+ } ,
468
+ BacktraceSymbol {
469
+ name: Some ( b"std::rt::lang_start" . to_vec( ) ) ,
470
+ filename: Some ( BytesOrWide :: Bytes ( b"rust/rt.rs" . to_vec( ) ) ) ,
471
+ lineno: Some ( 400 ) ,
472
+ } ,
473
+ ] ,
474
+ } ,
475
+ ] ,
476
+ } ) ) ,
477
+ } ;
478
+
479
+ #[ rustfmt:: skip]
480
+ let expected = "Backtrace [\
481
+ \n { fn: \" __rust_maybe_catch_panic\" },\
482
+ \n { fn: \" std::rt::lang_start_internal\" , file: \" rust/rt.rs\" , line: 300 },\
483
+ \n { fn: \" std::rt::lang_start\" , file: \" rust/rt.rs\" , line: 400 },\
484
+ \n ]";
485
+
486
+ assert_eq ! ( format!( "{:#?}" , backtrace) , expected) ;
487
+ }
0 commit comments