diff --git a/coregrind/m_stacktrace.c b/coregrind/m_stacktrace.c index d7d9d165f..b7fb5605e 100644 --- a/coregrind/m_stacktrace.c +++ b/coregrind/m_stacktrace.c @@ -60,9 +60,17 @@ UInt VG_(get_StackTrace2) ( ThreadId tid_if_known, Addr ip, Addr sp, Addr fp, Addr lr, Addr fp_min, Addr fp_max_orig ) { -#if defined(VGP_ppc32_linux) || defined(VGP_ppc64_linux) - Bool lr_is_first_RA = False; /* ppc only */ -#endif +# if defined(VGP_ppc32_linux) || defined(VGP_ppc64_linux) \ + || defined(VGP_ppc32_aix5) \ + || defined(VGP_ppc64_aix5) + Bool lr_is_first_RA = False; +# endif +# if defined(VGP_ppc64_linux) || defined(VGP_ppc64_aix5) \ + || defined(VGP_ppc32_aix5) + Word redir_stack_size = 0; + Word redirs_used = 0; +# endif + Bool debug = False; Int i; Addr fp_max; @@ -154,7 +162,7 @@ UInt VG_(get_StackTrace2) ( ThreadId tid_if_known, continue; } - /* That didn't work out, so see if there is any CFI info to hand + /* That didn't work out, so see if there is any CF info to hand which can be used. */ if ( VG_(use_CF_info)( &ip, &sp, &fp, fp_min, fp_max ) ) { ips[i++] = ip; @@ -235,26 +243,45 @@ UInt VG_(get_StackTrace2) ( ThreadId tid_if_known, break; } -# elif defined(VGP_ppc32_linux) || defined(VGP_ppc64_linux) +# elif defined(VGP_ppc32_linux) || defined(VGP_ppc64_linux) \ + || defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5) /*--------------------- ppc32/64 ---------------------*/ /* fp is %r1. ip is %cia. Note, ppc uses r1 as both the stack and frame pointers. */ -# if defined(VGP_ppc64_linux) +# if defined(VGP_ppc64_linux) || defined(VGP_ppc64_aix5) + redir_stack_size = VEX_GUEST_PPC64_REDIR_STACK_SIZE; + redirs_used = 0; +# elif defined(VGP_ppc32_aix5) + redir_stack_size = VEX_GUEST_PPC32_REDIR_STACK_SIZE; + redirs_used = 0; +# endif + +# if defined(VG_PLAT_USES_PPCTOC) /* Deal with bogus LR values caused by function - interception/wrapping; see comment on similar code a few lines - further down. */ - if (lr == (Addr)&VG_(ppc64_linux_magic_redirect_return_stub) + interception/wrapping on ppc-TOC platforms; see comment on + similar code a few lines further down. */ + if (ULong_to_Ptr(lr) == (void*)&VG_(ppctoc_magic_redirect_return_stub) && VG_(is_valid_tid)(tid_if_known)) { - Long hsp = VG_(threads)[tid_if_known].arch.vex.guest_REDIR_SP; - if (hsp >= 1 && hsp < VEX_GUEST_PPC64_REDIR_STACK_SIZE) + Word hsp = VG_(threads)[tid_if_known].arch.vex.guest_REDIR_SP; + redirs_used++; + if (hsp >= 1 && hsp < redir_stack_size) lr = VG_(threads)[tid_if_known] .arch.vex.guest_REDIR_STACK[hsp-1]; } # endif + /* We have to determine whether or not LR currently holds this fn + (call it F)'s return address. It might not if F has previously + called some other function, hence overwriting LR with a pointer + to some part of F. Hence if LR and IP point to the same + function then we conclude LR does not hold this function's + return address; instead the LR at entry must have been saved in + the stack by F's prologue and so we must get it from there + instead. Note all this guff only applies to the innermost + frame. */ lr_is_first_RA = False; { # define M_VG_ERRTXT 1000 @@ -276,10 +303,11 @@ UInt VG_(get_StackTrace2) ( ThreadId tid_if_known, while (True) { - /* on ppc64-linux (ppc64-elf, really), the lr save slot is 2 - words back from sp, whereas on ppc32-elf(?) it's only one - word back. */ -# if defined(VGP_ppc64_linux) + /* On ppc64-linux (ppc64-elf, really), and on AIX, the lr save + slot is 2 words back from sp, whereas on ppc32-elf(?) it's + only one word back. */ +# if defined(VGP_ppc64_linux) \ + || defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5) const Int lr_offset = 2; # else const Int lr_offset = 1; @@ -298,19 +326,23 @@ UInt VG_(get_StackTrace2) ( ThreadId tid_if_known, else ip = (((UWord*)fp)[lr_offset]); -# if defined(VGP_ppc64_linux) +# if defined(VG_PLAT_USES_PPCTOC) /* Nasty hack to do with function replacement/wrapping on - ppc64-linux. If LR points to our magic return stub, - then we are in a wrapped or intercepted function, in - which LR has been messed with. The original LR will - have been pushed onto the thread's hidden REDIR stack - one down from the top (top element is the saved R2) and - so we should restore the value from there instead. */ - if (i == 1 - && ip == (Addr)&VG_(ppc64_linux_magic_redirect_return_stub) + ppc64-linux/ppc64-aix/ppc32-aix. If LR points to our + magic return stub, then we are in a wrapped or + intercepted function, in which LR has been messed with. + The original LR will have been pushed onto the thread's + hidden REDIR stack one down from the top (top element + is the saved R2) and so we should restore the value + from there instead. Since nested redirections can and + do happen, we keep track of the number of nested LRs + used by the unwinding so far with 'redirs_used'. */ + if (ip == (Addr)&VG_(ppctoc_magic_redirect_return_stub) && VG_(is_valid_tid)(tid_if_known)) { - Long hsp = VG_(threads)[tid_if_known].arch.vex.guest_REDIR_SP; - if (hsp >= 1 && hsp < VEX_GUEST_PPC64_REDIR_STACK_SIZE) + Word hsp = VG_(threads)[tid_if_known].arch.vex.guest_REDIR_SP; + hsp -= 2 * redirs_used; + redirs_used ++; + if (hsp >= 1 && hsp < redir_stack_size) ip = VG_(threads)[tid_if_known] .arch.vex.guest_REDIR_STACK[hsp-1]; }