@@ -128,7 +128,7 @@ pub fn write(w: &mut Writer) -> IoResult<()> {
128
128
129
129
// skipping the first one as it is write itself
130
130
let iter = ( 1 ..cnt) . map ( |i| {
131
- print ( w, i as int , buf[ i] )
131
+ print ( w, i as int , buf[ i] , buf [ i ] )
132
132
} ) ;
133
133
result:: fold ( iter, ( ) , |_, _| ( ) )
134
134
}
@@ -172,7 +172,16 @@ pub fn write(w: &mut Writer) -> IoResult<()> {
172
172
extern fn trace_fn ( ctx : * mut uw:: _Unwind_Context ,
173
173
arg : * mut libc:: c_void ) -> uw:: _Unwind_Reason_Code {
174
174
let cx: & mut Context = unsafe { mem:: transmute ( arg) } ;
175
- let ip = unsafe { uw:: _Unwind_GetIP ( ctx) as * mut libc:: c_void } ;
175
+ let mut ip_before_insn = 0 ;
176
+ let mut ip = unsafe {
177
+ uw:: _Unwind_GetIPInfo ( ctx, & mut ip_before_insn) as * mut libc:: c_void
178
+ } ;
179
+ if ip_before_insn == 0 {
180
+ // this is a non-signaling frame, so `ip` refers to the address
181
+ // after the calling instruction. account for that.
182
+ ip = ( ip as usize - 1 ) as * mut _ ;
183
+ }
184
+
176
185
// dladdr() on osx gets whiny when we use FindEnclosingFunction, and
177
186
// it appears to work fine without it, so we only use
178
187
// FindEnclosingFunction on non-osx platforms. In doing so, we get a
@@ -183,7 +192,7 @@ pub fn write(w: &mut Writer) -> IoResult<()> {
183
192
// instructions after it. This means that the return instruction
184
193
// pointer points *outside* of the calling function, and by
185
194
// unwinding it we go back to the original function.
186
- let ip = if cfg ! ( target_os = "macos" ) || cfg ! ( target_os = "ios" ) {
195
+ let symaddr = if cfg ! ( target_os = "macos" ) || cfg ! ( target_os = "ios" ) {
187
196
ip
188
197
} else {
189
198
unsafe { uw:: _Unwind_FindEnclosingFunction ( ip) }
@@ -204,7 +213,7 @@ pub fn write(w: &mut Writer) -> IoResult<()> {
204
213
// Once we hit an error, stop trying to print more frames
205
214
if cx. last_error . is_some ( ) { return uw:: _URC_FAILURE }
206
215
207
- match print ( cx. writer , cx. idx , ip) {
216
+ match print ( cx. writer , cx. idx , ip, symaddr ) {
208
217
Ok ( ( ) ) => { }
209
218
Err ( e) => { cx. last_error = Some ( e) ; }
210
219
}
@@ -215,7 +224,8 @@ pub fn write(w: &mut Writer) -> IoResult<()> {
215
224
}
216
225
217
226
#[ cfg( any( target_os = "macos" , target_os = "ios" ) ) ]
218
- fn print ( w : & mut Writer , idx : int , addr : * mut libc:: c_void ) -> IoResult < ( ) > {
227
+ fn print ( w : & mut Writer , idx : int , addr : * mut libc:: c_void ,
228
+ _symaddr : * mut libc:: c_void ) -> IoResult < ( ) > {
219
229
use intrinsics;
220
230
#[ repr( C ) ]
221
231
struct Dl_info {
@@ -240,7 +250,8 @@ fn print(w: &mut Writer, idx: int, addr: *mut libc::c_void) -> IoResult<()> {
240
250
}
241
251
242
252
#[ cfg( not( any( target_os = "macos" , target_os = "ios" ) ) ) ]
243
- fn print ( w : & mut Writer , idx : int , addr : * mut libc:: c_void ) -> IoResult < ( ) > {
253
+ fn print ( w : & mut Writer , idx : int , addr : * mut libc:: c_void ,
254
+ symaddr : * mut libc:: c_void ) -> IoResult < ( ) > {
244
255
use env;
245
256
use ptr;
246
257
@@ -253,6 +264,12 @@ fn print(w: &mut Writer, idx: int, addr: *mut libc::c_void) -> IoResult<()> {
253
264
symname : * const libc:: c_char ,
254
265
symval : libc:: uintptr_t ,
255
266
symsize : libc:: uintptr_t ) ;
267
+ type backtrace_full_callback =
268
+ extern "C" fn ( data : * mut libc:: c_void ,
269
+ pc : libc:: uintptr_t ,
270
+ filename : * const libc:: c_char ,
271
+ lineno : libc:: c_int ,
272
+ function : * const libc:: c_char ) -> libc:: c_int ;
256
273
type backtrace_error_callback =
257
274
extern "C" fn ( data : * mut libc:: c_void ,
258
275
msg : * const libc:: c_char ,
@@ -273,12 +290,19 @@ fn print(w: &mut Writer, idx: int, addr: *mut libc::c_void) -> IoResult<()> {
273
290
cb : backtrace_syminfo_callback ,
274
291
error : backtrace_error_callback ,
275
292
data : * mut libc:: c_void ) -> libc:: c_int ;
293
+ fn backtrace_pcinfo ( state : * mut backtrace_state ,
294
+ addr : libc:: uintptr_t ,
295
+ cb : backtrace_full_callback ,
296
+ error : backtrace_error_callback ,
297
+ data : * mut libc:: c_void ) -> libc:: c_int ;
276
298
}
277
299
278
300
////////////////////////////////////////////////////////////////////////
279
301
// helper callbacks
280
302
////////////////////////////////////////////////////////////////////////
281
303
304
+ type FileLine = ( * const libc:: c_char , libc:: c_int ) ;
305
+
282
306
extern fn error_cb ( _data : * mut libc:: c_void , _msg : * const libc:: c_char ,
283
307
_errnum : libc:: c_int ) {
284
308
// do nothing for now
@@ -291,6 +315,25 @@ fn print(w: &mut Writer, idx: int, addr: *mut libc::c_void) -> IoResult<()> {
291
315
let slot = data as * mut * const libc:: c_char ;
292
316
unsafe { * slot = symname; }
293
317
}
318
+ extern fn pcinfo_cb ( data : * mut libc:: c_void ,
319
+ _pc : libc:: uintptr_t ,
320
+ filename : * const libc:: c_char ,
321
+ lineno : libc:: c_int ,
322
+ _function : * const libc:: c_char ) -> libc:: c_int {
323
+ if !filename. is_null ( ) {
324
+ let slot = data as * mut & mut [ FileLine ] ;
325
+ let buffer = unsafe { ptr:: read ( slot) } ;
326
+
327
+ // if the buffer is not full, add file:line to the buffer
328
+ // and adjust the buffer for next possible calls to pcinfo_cb.
329
+ if !buffer. is_empty ( ) {
330
+ buffer[ 0 ] = ( filename, lineno) ;
331
+ unsafe { ptr:: write ( slot, & mut buffer[ 1 ..] ) ; }
332
+ }
333
+ }
334
+
335
+ 0
336
+ }
294
337
295
338
// The libbacktrace API supports creating a state, but it does not
296
339
// support destroying a state. I personally take this to mean that a
@@ -359,15 +402,42 @@ fn print(w: &mut Writer, idx: int, addr: *mut libc::c_void) -> IoResult<()> {
359
402
let mut data = ptr:: null ( ) ;
360
403
let data_addr = & mut data as * mut * const libc:: c_char ;
361
404
let ret = unsafe {
362
- backtrace_syminfo ( state, addr as libc:: uintptr_t ,
405
+ backtrace_syminfo ( state, symaddr as libc:: uintptr_t ,
363
406
syminfo_cb, error_cb,
364
407
data_addr as * mut libc:: c_void )
365
408
} ;
366
409
if ret == 0 || data. is_null ( ) {
367
- output ( w, idx, addr, None )
410
+ try! ( output ( w, idx, addr, None ) ) ;
368
411
} else {
369
- output ( w, idx, addr, Some ( unsafe { CStr :: from_ptr ( data) . to_bytes ( ) } ) )
412
+ try!( output ( w, idx, addr, Some ( unsafe { CStr :: from_ptr ( data) . to_bytes ( ) } ) ) ) ;
413
+ }
414
+
415
+ // pcinfo may return an arbitrary number of file:line pairs,
416
+ // in the order of stack trace (i.e. inlined calls first).
417
+ // in order to avoid allocation, we stack-allocate a fixed size of entries.
418
+ const FILELINE_SIZE : usize = 32 ;
419
+ let mut fileline_buf = [ ( ptr:: null ( ) , -1 ) ; FILELINE_SIZE ] ;
420
+ let ret;
421
+ let fileline_count;
422
+ {
423
+ let mut fileline_win: & mut [ FileLine ] = & mut fileline_buf;
424
+ let fileline_addr = & mut fileline_win as * mut & mut [ FileLine ] ;
425
+ ret = unsafe {
426
+ backtrace_pcinfo ( state, addr as libc:: uintptr_t ,
427
+ pcinfo_cb, error_cb,
428
+ fileline_addr as * mut libc:: c_void )
429
+ } ;
430
+ fileline_count = FILELINE_SIZE - fileline_win. len ( ) ;
370
431
}
432
+ if ret == 0 {
433
+ for ( i, & ( file, line) ) in fileline_buf[ ..fileline_count] . iter ( ) . enumerate ( ) {
434
+ if file. is_null ( ) { continue ; } // just to be sure
435
+ let file = unsafe { CStr :: from_ptr ( file) . to_bytes ( ) } ;
436
+ try!( output_fileline ( w, file, line, i == FILELINE_SIZE - 1 ) ) ;
437
+ }
438
+ }
439
+
440
+ Ok ( ( ) )
371
441
}
372
442
373
443
// Finally, after all that work above, we can emit a symbol.
@@ -381,6 +451,18 @@ fn output(w: &mut Writer, idx: int, addr: *mut libc::c_void,
381
451
w. write_all ( & [ '\n' as u8 ] )
382
452
}
383
453
454
+ #[ allow( dead_code) ]
455
+ fn output_fileline ( w : & mut Writer , file : & [ u8 ] , line : libc:: c_int ,
456
+ more : bool ) -> IoResult < ( ) > {
457
+ let file = str:: from_utf8 ( file) . ok ( ) . unwrap_or ( "<unknown>" ) ;
458
+ // prior line: " ##: {:2$} - func"
459
+ try!( write ! ( w, " {:3$}at {}:{}" , "" , file, line, HEX_WIDTH ) ) ;
460
+ if more {
461
+ try!( write ! ( w, " <... and possibly more>" ) ) ;
462
+ }
463
+ w. write_all ( & [ '\n' as u8 ] )
464
+ }
465
+
384
466
/// Unwind library interface used for backtraces
385
467
///
386
468
/// Note that dead code is allowed as here are just bindings
@@ -421,9 +503,12 @@ mod uw {
421
503
trace_argument : * mut libc:: c_void )
422
504
-> _Unwind_Reason_Code ;
423
505
506
+ // available since GCC 4.2.0, should be fine for our purpose
424
507
#[ cfg( all( not( all( target_os = "android" , target_arch = "arm" ) ) ,
425
508
not( all( target_os = "linux" , target_arch = "arm" ) ) ) ) ]
426
- pub fn _Unwind_GetIP ( ctx : * mut _Unwind_Context ) -> libc:: uintptr_t ;
509
+ pub fn _Unwind_GetIPInfo ( ctx : * mut _Unwind_Context ,
510
+ ip_before_insn : * mut libc:: c_int )
511
+ -> libc:: uintptr_t ;
427
512
428
513
#[ cfg( all( not( target_os = "android" ) ,
429
514
not( all( target_os = "linux" , target_arch = "arm" ) ) ) ) ]
@@ -479,6 +564,18 @@ mod uw {
479
564
( val & !1 ) as libc:: uintptr_t
480
565
}
481
566
567
+ // This function doesn't exist on Android or ARM/Linux, so make it same
568
+ // to _Unwind_GetIP
569
+ #[ cfg( any( target_os = "android" ,
570
+ all( target_os = "linux" , target_arch = "arm" ) ) ) ]
571
+ pub unsafe fn _Unwind_GetIPInfo ( ctx : * mut _Unwind_Context ,
572
+ ip_before_insn : * mut libc:: c_int )
573
+ -> libc:: uintptr_t
574
+ {
575
+ * ip_before_insn = 0 ;
576
+ _Unwind_GetIP ( ctx)
577
+ }
578
+
482
579
// This function also doesn't exist on Android or ARM/Linux, so make it
483
580
// a no-op
484
581
#[ cfg( any( target_os = "android" ,
0 commit comments