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