@@ -45,7 +45,7 @@ pub enum EmitterError {
4545unsafe fn emit_backtrace_by_frames (
4646 w : & mut impl Write ,
4747 resolve_frames : StacktraceCollection ,
48- fault_rsp : usize ,
48+ fault_ip : usize ,
4949) -> Result < ( ) , EmitterError > {
5050 // https://docs.rs/backtrace/latest/backtrace/index.html
5151 writeln ! ( w, "{DD_CRASHTRACK_BEGIN_STACKTRACE}" ) ?;
@@ -61,56 +61,68 @@ unsafe fn emit_backtrace_by_frames(
6161 Ok ( ( ) )
6262 }
6363
64- backtrace :: trace_unsynchronized ( |frame| {
65- // Skip all stack frames whose stack pointer is less than to the determined crash stack
66- // pointer (fault_rsp). These frames belong exclusively to the crash tracker and the
67- // backtrace functionality and are therefore not relevant for troubleshooting.
68- let sp = frame . sp ( ) ;
69- if !sp . is_null ( ) && ( sp as usize ) < fault_rsp {
70- return true ;
71- }
72- if resolve_frames == StacktraceCollection :: EnabledWithInprocessSymbols {
73- backtrace :: resolve_frame_unsynchronized ( frame , |symbol| {
74- # [ allow ( clippy :: unwrap_used ) ]
75- write ! ( w , "{{" ) . unwrap ( ) ;
76- # [ allow ( clippy :: unwrap_used ) ]
77- emit_absolute_addresses ( w , frame ) . unwrap ( ) ;
78- if let Some ( column ) = symbol. colno ( ) {
64+ let mut ip_found = false ;
65+ loop {
66+ backtrace :: trace_unsynchronized ( |frame| {
67+ // Skip all stack frames until we encounter the determined crash instruction pointer
68+ // (fault_ip). These initial frames belong exclusively to the crash tracker and the
69+ // backtrace functionality and are therefore not relevant for troubleshooting.
70+ let ip = frame . ip ( ) ;
71+ if ip as usize == fault_ip {
72+ ip_found = true ;
73+ }
74+ if !ip_found {
75+ return true ;
76+ }
77+ if resolve_frames == StacktraceCollection :: EnabledWithInprocessSymbols {
78+ backtrace :: resolve_frame_unsynchronized ( frame , | symbol| {
7979 #[ allow( clippy:: unwrap_used) ]
80- write ! ( w, ", \" column\" : {column}" ) . unwrap ( ) ;
81- }
82- if let Some ( file) = symbol. filename ( ) {
83- // The debug printer for path already wraps it in `"` marks.
80+ write ! ( w, "{{" ) . unwrap ( ) ;
8481 #[ allow( clippy:: unwrap_used) ]
85- write ! ( w, ", \" file\" : {file:?}" ) . unwrap ( ) ;
86- }
87- if let Some ( function) = symbol. name ( ) {
82+ emit_absolute_addresses ( w, frame) . unwrap ( ) ;
83+ if let Some ( column) = symbol. colno ( ) {
84+ #[ allow( clippy:: unwrap_used) ]
85+ write ! ( w, ", \" column\" : {column}" ) . unwrap ( ) ;
86+ }
87+ if let Some ( file) = symbol. filename ( ) {
88+ // The debug printer for path already wraps it in `"` marks.
89+ #[ allow( clippy:: unwrap_used) ]
90+ write ! ( w, ", \" file\" : {file:?}" ) . unwrap ( ) ;
91+ }
92+ if let Some ( function) = symbol. name ( ) {
93+ #[ allow( clippy:: unwrap_used) ]
94+ write ! ( w, ", \" function\" : \" {function}\" " ) . unwrap ( ) ;
95+ }
96+ if let Some ( line) = symbol. lineno ( ) {
97+ #[ allow( clippy:: unwrap_used) ]
98+ write ! ( w, ", \" line\" : {line}" ) . unwrap ( ) ;
99+ }
88100 #[ allow( clippy:: unwrap_used) ]
89- write ! ( w, ", \" function \" : \" {function} \" " ) . unwrap ( ) ;
90- }
91- if let Some ( line ) = symbol . lineno ( ) {
101+ writeln ! ( w, "}} " ) . unwrap ( ) ;
102+ // Flush eagerly to ensure that each frame gets emitted even if the next one
103+ // fails
92104 #[ allow( clippy:: unwrap_used) ]
93- write ! ( w, ", \" line\" : {line}" ) . unwrap ( ) ;
94- }
105+ w. flush ( ) . unwrap ( ) ;
106+ } ) ;
107+ } else {
108+ #[ allow( clippy:: unwrap_used) ]
109+ write ! ( w, "{{" ) . unwrap ( ) ;
110+ #[ allow( clippy:: unwrap_used) ]
111+ emit_absolute_addresses ( w, frame) . unwrap ( ) ;
95112 #[ allow( clippy:: unwrap_used) ]
96113 writeln ! ( w, "}}" ) . unwrap ( ) ;
97114 // Flush eagerly to ensure that each frame gets emitted even if the next one fails
98115 #[ allow( clippy:: unwrap_used) ]
99116 w. flush ( ) . unwrap ( ) ;
100- } ) ;
101- } else {
102- #[ allow( clippy:: unwrap_used) ]
103- write ! ( w, "{{" ) . unwrap ( ) ;
104- #[ allow( clippy:: unwrap_used) ]
105- emit_absolute_addresses ( w, frame) . unwrap ( ) ;
106- #[ allow( clippy:: unwrap_used) ]
107- writeln ! ( w, "}}" ) . unwrap ( ) ;
108- // Flush eagerly to ensure that each frame gets emitted even if the next one fails
109- #[ allow( clippy:: unwrap_used) ]
110- w. flush ( ) . unwrap ( ) ;
117+ }
118+ true // keep going to the next frame
119+ } ) ;
120+ if ip_found {
121+ break ;
111122 }
112- true // keep going to the next frame
113- } ) ;
123+ // emit anything at all, if the crashing frame is not found for some reason
124+ ip_found = true ;
125+ }
114126 writeln ! ( w, "{DD_CRASHTRACK_END_STACKTRACE}" ) ?;
115127 w. flush ( ) ?;
116128 Ok ( ( ) )
@@ -145,8 +157,8 @@ pub(crate) fn emit_crashreport(
145157 // https://doc.rust-lang.org/src/std/backtrace.rs.html#332
146158 // Do this last, so even if it crashes, we still get the other info.
147159 if config. resolve_frames ( ) != StacktraceCollection :: Disabled {
148- let fault_rsp = extract_rsp ( ucontext) ;
149- unsafe { emit_backtrace_by_frames ( pipe, config. resolve_frames ( ) , fault_rsp ) ? } ;
160+ let fault_ip = extract_ip ( ucontext) ;
161+ unsafe { emit_backtrace_by_frames ( pipe, config. resolve_frames ( ) , fault_ip ) ? } ;
150162 }
151163 writeln ! ( pipe, "{DD_CRASHTRACK_DONE}" ) ?;
152164 pipe. flush ( ) ?;
@@ -307,17 +319,17 @@ fn emit_text_file(w: &mut impl Write, path: &str) -> Result<(), EmitterError> {
307319 Ok ( ( ) )
308320}
309321
310- fn extract_rsp ( ucontext : * const ucontext_t ) -> usize {
322+ fn extract_ip ( ucontext : * const ucontext_t ) -> usize {
311323 unsafe {
312324 #[ cfg( all( target_os = "macos" , target_arch = "x86_64" ) ) ]
313- return ( * ( * ucontext) . uc_mcontext ) . __ss . __rsp as usize ;
325+ return ( * ( * ucontext) . uc_mcontext ) . __ss . __rip as usize ;
314326 #[ cfg( all( target_os = "macos" , target_arch = "aarch64" ) ) ]
315- return ( * ( * ucontext) . uc_mcontext ) . __ss . __sp as usize ;
327+ return ( * ( * ucontext) . uc_mcontext ) . __ss . __pc as usize ;
316328
317329 #[ cfg( all( target_os = "linux" , target_arch = "x86_64" ) ) ]
318- return ( * ucontext) . uc_mcontext . gregs [ libc:: REG_RSP as usize ] as usize ;
330+ return ( * ucontext) . uc_mcontext . gregs [ libc:: REG_RIP as usize ] as usize ;
319331 #[ cfg( all( target_os = "linux" , target_arch = "aarch64" ) ) ]
320- return ( * ucontext) . uc_mcontext . sp as usize ;
332+ return ( * ucontext) . uc_mcontext . pc as usize ;
321333 }
322334}
323335
@@ -326,14 +338,28 @@ mod tests {
326338 use super :: * ;
327339 use std:: str;
328340
329- #[ test]
330- #[ cfg_attr( miri, ignore) ]
331- fn test_emit_backtrace_disabled ( ) {
341+ #[ inline( never) ]
342+ fn inner_test_emit_backtrace_with_symbols ( collection : StacktraceCollection ) -> Vec < u8 > {
343+ let mut ip_of_test_fn = 0 ;
344+ let mut skip = 3 ;
345+ unsafe {
346+ backtrace:: trace_unsynchronized ( |frame| {
347+ ip_of_test_fn = frame. ip ( ) as usize ;
348+ skip -= 1 ;
349+ skip > 0
350+ } )
351+ } ;
332352 let mut buf = Vec :: new ( ) ;
333353 unsafe {
334- emit_backtrace_by_frames ( & mut buf, StacktraceCollection :: Disabled , 0 )
335- . expect ( "to work ;-)" ) ;
354+ emit_backtrace_by_frames ( & mut buf, collection, ip_of_test_fn) . expect ( "to work ;-)" ) ;
336355 }
356+ buf
357+ }
358+
359+ #[ test]
360+ #[ cfg_attr( miri, ignore) ]
361+ fn test_emit_backtrace_disabled ( ) {
362+ let buf = inner_test_emit_backtrace_with_symbols ( StacktraceCollection :: Disabled ) ;
337363 let out = str:: from_utf8 ( & buf) . expect ( "to be valid UTF8" ) ;
338364 assert ! ( out. contains( "BEGIN_STACKTRACE" ) ) ;
339365 assert ! ( out. contains( "END_STACKTRACE" ) ) ;
@@ -353,18 +379,10 @@ mod tests {
353379 #[ test]
354380 #[ cfg_attr( miri, ignore) ]
355381 fn test_emit_backtrace_with_symbols ( ) {
356- let dummy = 0u8 ;
382+ let buf = inner_test_emit_backtrace_with_symbols (
383+ StacktraceCollection :: EnabledWithInprocessSymbols ,
384+ ) ;
357385 // retrieve stack pointer for this function
358- let sp_of_test_fn = & dummy as * const u8 as usize ;
359- let mut buf = Vec :: new ( ) ;
360- unsafe {
361- emit_backtrace_by_frames (
362- & mut buf,
363- StacktraceCollection :: EnabledWithInprocessSymbols ,
364- sp_of_test_fn,
365- )
366- . expect ( "to work ;-)" ) ;
367- }
368386 let out = str:: from_utf8 ( & buf) . expect ( "to be valid UTF8" ) ;
369387 assert ! ( out. contains( "BEGIN_STACKTRACE" ) ) ;
370388 assert ! ( out. contains( "END_STACKTRACE" ) ) ;
0 commit comments