1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/ 3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Take snapshots of client stacks. m_stacktrace.c ---*/ 4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/ 5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* 7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown This file is part of Valgrind, a dynamic binary instrumentation 8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown framework. 9ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 10b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov Copyright (C) 2000-2011 Julian Seward 11ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown jseward@acm.org 12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 13ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown This program is free software; you can redistribute it and/or 14ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown modify it under the terms of the GNU General Public License as 15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown published by the Free Software Foundation; either version 2 of the 16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown License, or (at your option) any later version. 17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown This program is distributed in the hope that it will be useful, but 19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown WITHOUT ANY WARRANTY; without even the implied warranty of 20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown General Public License for more details. 22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown You should have received a copy of the GNU General Public License 24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown along with this program; if not, write to the Free Software 25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 02111-1307, USA. 27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown The GNU General Public License is contained in the file COPYING. 29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/ 30ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_basics.h" 32ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_vki.h" 33b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include "pub_core_libcsetjmp.h" // to keep _threadstate.h happy 34ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_threadstate.h" 35ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_debuginfo.h" // XXX: circular dependency 36ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_aspacemgr.h" // For VG_(is_addressable)() 37ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcbase.h" 38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcassert.h" 39ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcprint.h" 40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_machine.h" 41ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_options.h" 42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_stacks.h" // VG_(stack_limits) 43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_stacktrace.h" 44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_xarray.h" 45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_clientstate.h" // VG_(client__dl_sysinfo_int80) 46ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_trampoline.h" 47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/ 50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- ---*/ 51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- BEGIN platform-dependent unwinder worker functions ---*/ 52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- ---*/ 53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/ 54ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Take a snapshot of the client's stack, putting up to 'max_n_ips' 56ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown IPs into 'ips'. In order to be thread-safe, we pass in the 57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown thread's IP SP, FP if that's meaningful, and LR if that's 58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown meaningful. Returns number of IPs put in 'ips'. 59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown If you know what the thread ID for this stack is, send that as the 61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown first parameter, else send zero. This helps generate better stack 62ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown traces on ppc64-linux and has no effect on other platforms. 63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/ 64ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ------------------------ x86 ------------------------- */ 66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 67ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if defined(VGP_x86_linux) || defined(VGP_x86_darwin) 68ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 69ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known, 70ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /*OUT*/Addr* ips, UInt max_n_ips, 71ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /*OUT*/Addr* sps, /*OUT*/Addr* fps, 72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown UnwindStartRegs* startRegs, 73ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr fp_max_orig ) 74ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 75ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Bool debug = False; 76ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int i; 77ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr fp_max; 78ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown UInt n_found = 0; 79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 80ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vg_assert(sizeof(Addr) == sizeof(UWord)); 81ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vg_assert(sizeof(Addr) == sizeof(void*)); 82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown D3UnwindRegs uregs; 84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown uregs.xip = (Addr)startRegs->r_pc; 85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown uregs.xsp = (Addr)startRegs->r_sp; 86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown uregs.xbp = startRegs->misc.X86.r_ebp; 87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr fp_min = uregs.xsp; 88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Snaffle IPs from the client's stack into ips[0 .. max_n_ips-1], 90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown stopping when the trail goes cold, which we guess to be 91ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown when FP is not a reasonable stack location. */ 92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // JRS 2002-sep-17: hack, to round up fp_max to the end of the 94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // current page, at least. Dunno if it helps. 95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // NJN 2002-sep-17: seems to -- stack traces look like 1.0.X again 96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown fp_max = VG_PGROUNDUP(fp_max_orig); 97ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (fp_max >= sizeof(Addr)) 98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown fp_max -= sizeof(Addr); 99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (debug) 101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(printf)("max_n_ips=%d fp_min=0x%lx fp_max_orig=0x%lx, " 102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "fp_max=0x%lx ip=0x%lx fp=0x%lx\n", 103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown max_n_ips, fp_min, fp_max_orig, fp_max, 104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown uregs.xip, uregs.xbp); 105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Assertion broken before main() is reached in pthreaded programs; the 107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * offending stack traces only have one item. --njn, 2002-aug-16 */ 108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* vg_assert(fp_min <= fp_max);*/ 109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // On Darwin, this kicks in for pthread-related stack traces, so they're 110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // only 1 entry long which is wrong. 111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# if !defined(VGO_darwin) 112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (fp_min + 512 >= fp_max) { 113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* If the stack limits look bogus, don't poke around ... but 114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown don't bomb out either. */ 115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (sps) sps[0] = uregs.xsp; 116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (fps) fps[0] = uregs.xbp; 117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ips[0] = uregs.xip; 118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return 1; 119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# endif 121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* fp is %ebp. sp is %esp. ip is %eip. */ 123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (sps) sps[0] = uregs.xsp; 125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (fps) fps[0] = uregs.xbp; 126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ips[0] = uregs.xip; 127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown i = 1; 128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Loop unwinding the stack. Note that the IP value we get on 130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * each pass (whether from CFI info or a stack frame) is a 131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * return address so is actually after the calling instruction 132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * in the calling function. 133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * 134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * Because of this we subtract one from the IP after each pass 135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * of the loop so that we find the right CFI block on the next 136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * pass - otherwise we can find the wrong CFI info if it happens 137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * to change after the calling instruction and that will mean 138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * that we will fail to unwind the next step. 139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * 140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * This most frequently happens at the end of a function when 141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * a tail call occurs and we wind up using the CFI info for the 142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * next function which is completely wrong. 143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */ 144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown while (True) { 145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (i >= max_n_ips) 147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Try to derive a new (ip,sp,fp) triple from the current 150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown set. */ 151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* On x86, first try the old-fashioned method of following the 153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown %ebp-chain. Code which doesn't use this (that is, compiled 154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown with -fomit-frame-pointer) is not ABI compliant and so 155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown relatively rare. Besides, trying the CFI first almost always 156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown fails, and is expensive. */ 157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Deal with frames resulting from functions which begin "pushl% 158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ebp ; movl %esp, %ebp" which is the ABI-mandated preamble. */ 159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (fp_min <= uregs.xbp && 160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown uregs.xbp <= fp_max - 1 * sizeof(UWord)/*see comment below*/) 161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* fp looks sane, so use it. */ 163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown uregs.xip = (((UWord*)uregs.xbp)[1]); 164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // We stop if we hit a zero (the traditional end-of-stack 165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // marker) or a one -- these correspond to recorded IPs of 0 or -1. 166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // The latter because r8818 (in this file) changes the meaning of 167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // entries [1] and above in a stack trace, by subtracting 1 from 168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // them. Hence stacks that used to end with a zero value now end in 169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // -1 and so we must detect that too. 170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (0 == uregs.xip || 1 == uregs.xip) break; 171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown uregs.xsp = uregs.xbp + sizeof(Addr) /*saved %ebp*/ 172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown + sizeof(Addr) /*ra*/; 173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown uregs.xbp = (((UWord*)uregs.xbp)[0]); 174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (sps) sps[i] = uregs.xsp; 175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (fps) fps[i] = uregs.xbp; 176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ips[i++] = uregs.xip - 1; /* -1: refer to calling insn, not the RA */ 177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (debug) 178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(printf)(" ipsF[%d]=0x%08lx\n", i-1, ips[i-1]); 179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown uregs.xip = uregs.xip - 1; 180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* as per comment at the head of this loop */ 181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown continue; 182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* That didn't work out, so see if there is any CF info to hand 185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown which can be used. */ 186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if ( VG_(use_CF_info)( &uregs, fp_min, fp_max ) ) { 187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (0 == uregs.xip || 1 == uregs.xip) break; 188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (sps) sps[i] = uregs.xsp; 189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (fps) fps[i] = uregs.xbp; 190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ips[i++] = uregs.xip - 1; /* -1: refer to calling insn, not the RA */ 191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (debug) 192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(printf)(" ipsC[%d]=0x%08lx\n", i-1, ips[i-1]); 193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown uregs.xip = uregs.xip - 1; 194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* as per comment at the head of this loop */ 195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown continue; 196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* And, similarly, try for MSVC FPO unwind info. */ 199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if ( VG_(use_FPO_info)( &uregs.xip, &uregs.xsp, &uregs.xbp, 200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown fp_min, fp_max ) ) { 201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (0 == uregs.xip || 1 == uregs.xip) break; 202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (sps) sps[i] = uregs.xsp; 203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (fps) fps[i] = uregs.xbp; 204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ips[i++] = uregs.xip; 205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (debug) 206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(printf)(" ipsC[%d]=0x%08lx\n", i-1, ips[i-1]); 207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown uregs.xip = uregs.xip - 1; 208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown continue; 209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* No luck. We have to give up. */ 212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown n_found = i; 216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return n_found; 217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif 220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ----------------------- amd64 ------------------------ */ 222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if defined(VGP_amd64_linux) || defined(VGP_amd64_darwin) 224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known, 226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /*OUT*/Addr* ips, UInt max_n_ips, 227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /*OUT*/Addr* sps, /*OUT*/Addr* fps, 228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown UnwindStartRegs* startRegs, 229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr fp_max_orig ) 230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Bool debug = False; 232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int i; 233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr fp_max; 234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown UInt n_found = 0; 235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vg_assert(sizeof(Addr) == sizeof(UWord)); 237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vg_assert(sizeof(Addr) == sizeof(void*)); 238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown D3UnwindRegs uregs; 240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown uregs.xip = startRegs->r_pc; 241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown uregs.xsp = startRegs->r_sp; 242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown uregs.xbp = startRegs->misc.AMD64.r_rbp; 243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr fp_min = uregs.xsp; 244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Snaffle IPs from the client's stack into ips[0 .. max_n_ips-1], 246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown stopping when the trail goes cold, which we guess to be 247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown when FP is not a reasonable stack location. */ 248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // JRS 2002-sep-17: hack, to round up fp_max to the end of the 250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // current page, at least. Dunno if it helps. 251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // NJN 2002-sep-17: seems to -- stack traces look like 1.0.X again 252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown fp_max = VG_PGROUNDUP(fp_max_orig); 253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (fp_max >= sizeof(Addr)) 254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown fp_max -= sizeof(Addr); 255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 256f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov extern unsigned long nacl_head; 257f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov 258f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov if (nacl_head && uregs.xip > nacl_head && uregs.xip < nacl_head + (1ULL << 32)) { 259b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fp_min = nacl_head + 0x10000; 260f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov fp_max = nacl_head + (1ULL << 32) - 1; 261f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov } 262f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov 263f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov 264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (debug) 265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(printf)("max_n_ips=%d fp_min=0x%lx fp_max_orig=0x%lx, " 266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "fp_max=0x%lx ip=0x%lx fp=0x%lx\n", 267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown max_n_ips, fp_min, fp_max_orig, fp_max, 268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown uregs.xip, uregs.xbp); 269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Assertion broken before main() is reached in pthreaded programs; the 271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * offending stack traces only have one item. --njn, 2002-aug-16 */ 272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* vg_assert(fp_min <= fp_max);*/ 273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // On Darwin, this kicks in for pthread-related stack traces, so they're 274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // only 1 entry long which is wrong. 275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# if !defined(VGO_darwin) 276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (fp_min + 256 >= fp_max) { 277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* If the stack limits look bogus, don't poke around ... but 278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown don't bomb out either. */ 279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (sps) sps[0] = uregs.xsp; 280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (fps) fps[0] = uregs.xbp; 281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ips[0] = uregs.xip; 282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return 1; 283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# endif 285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* fp is %rbp. sp is %rsp. ip is %rip. */ 287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ips[0] = uregs.xip; 289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (sps) sps[0] = uregs.xsp; 290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (fps) fps[0] = uregs.xbp; 291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown i = 1; 292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Loop unwinding the stack. Note that the IP value we get on 294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * each pass (whether from CFI info or a stack frame) is a 295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * return address so is actually after the calling instruction 296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * in the calling function. 297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * 298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * Because of this we subtract one from the IP after each pass 299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * of the loop so that we find the right CFI block on the next 300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * pass - otherwise we can find the wrong CFI info if it happens 301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * to change after the calling instruction and that will mean 302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * that we will fail to unwind the next step. 303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * 304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * This most frequently happens at the end of a function when 305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * a tail call occurs and we wind up using the CFI info for the 306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * next function which is completely wrong. 307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */ 308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown while (True) { 309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (i >= max_n_ips) 311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Try to derive a new (ip,sp,fp) triple from the current set. */ 314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* First off, see if there is any CFI info to hand which can 316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown be used. */ 317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if ( VG_(use_CF_info)( &uregs, fp_min, fp_max ) ) { 318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (0 == uregs.xip || 1 == uregs.xip) break; 319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (sps) sps[i] = uregs.xsp; 320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (fps) fps[i] = uregs.xbp; 321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ips[i++] = uregs.xip - 1; /* -1: refer to calling insn, not the RA */ 322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (debug) 323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(printf)(" ipsC[%d]=%#08lx\n", i-1, ips[i-1]); 324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown uregs.xip = uregs.xip - 1; /* as per comment at the head of this loop */ 325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown continue; 326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* If VG_(use_CF_info) fails, it won't modify ip/sp/fp, so 329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown we can safely try the old-fashioned method. */ 330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* This bit is supposed to deal with frames resulting from 331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown functions which begin "pushq %rbp ; movq %rsp, %rbp". 332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Unfortunately, since we can't (easily) look at the insns at 333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown the start of the fn, like GDB does, there's no reliable way 334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown to tell. Hence the hack of first trying out CFI, and if that 335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown fails, then use this as a fallback. */ 336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Note: re "- 1 * sizeof(UWord)", need to take account of the 337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown fact that we are prodding at & ((UWord*)fp)[1] and so need to 338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown adjust the limit check accordingly. Omitting this has been 339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown observed to cause segfaults on rare occasions. */ 340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (fp_min <= uregs.xbp && uregs.xbp <= fp_max - 1 * sizeof(UWord)) { 341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* fp looks sane, so use it. */ 342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown uregs.xip = (((UWord*)uregs.xbp)[1]); 343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (0 == uregs.xip || 1 == uregs.xip) break; 344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown uregs.xsp = uregs.xbp + sizeof(Addr) /*saved %rbp*/ 345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown + sizeof(Addr) /*ra*/; 346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown uregs.xbp = (((UWord*)uregs.xbp)[0]); 347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (sps) sps[i] = uregs.xsp; 348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (fps) fps[i] = uregs.xbp; 349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ips[i++] = uregs.xip - 1; /* -1: refer to calling insn, not the RA */ 350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (debug) 351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(printf)(" ipsF[%d]=%#08lx\n", i-1, ips[i-1]); 352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown uregs.xip = uregs.xip - 1; /* as per comment at the head of this loop */ 353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown continue; 354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Last-ditch hack (evidently GDB does something similar). We 357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown are in the middle of nowhere and we have a nonsense value for 358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown the frame pointer. If the stack pointer is still valid, 359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown assume that what it points at is a return address. Yes, 360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown desperate measures. Could do better here: 361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown - check that the supposed return address is in 362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown an executable page 363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown - check that the supposed return address is just after a call insn 364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown - given those two checks, don't just consider *sp as the return 365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown address; instead scan a likely section of stack (eg sp .. sp+256) 366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown and use suitable values found there. 367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */ 368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (fp_min <= uregs.xsp && uregs.xsp < fp_max) { 369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown uregs.xip = ((UWord*)uregs.xsp)[0]; 370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (0 == uregs.xip || 1 == uregs.xip) break; 371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (sps) sps[i] = uregs.xsp; 372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (fps) fps[i] = uregs.xbp; 373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ips[i++] = uregs.xip == 0 374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ? 0 /* sp[0] == 0 ==> stuck at the bottom of a 375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown thread stack */ 376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown : uregs.xip - 1; 377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* -1: refer to calling insn, not the RA */ 378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (debug) 379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(printf)(" ipsH[%d]=%#08lx\n", i-1, ips[i-1]); 380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown uregs.xip = uregs.xip - 1; /* as per comment at the head of this loop */ 381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown uregs.xsp += 8; 382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown continue; 383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* No luck at all. We have to give up. */ 386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown n_found = i; 390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return n_found; 391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif 394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* -----------------------ppc32/64 ---------------------- */ 396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 397b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#if defined(VGP_ppc32_linux) || defined(VGP_ppc64_linux) 398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known, 400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /*OUT*/Addr* ips, UInt max_n_ips, 401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /*OUT*/Addr* sps, /*OUT*/Addr* fps, 402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown UnwindStartRegs* startRegs, 403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr fp_max_orig ) 404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Bool lr_is_first_RA = False; 406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# if defined(VG_PLAT_USES_PPCTOC) 407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Word redir_stack_size = 0; 408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Word redirs_used = 0; 409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# endif 410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Bool debug = False; 412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int i; 413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr fp_max; 414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown UInt n_found = 0; 415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vg_assert(sizeof(Addr) == sizeof(UWord)); 417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vg_assert(sizeof(Addr) == sizeof(void*)); 418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr ip = (Addr)startRegs->r_pc; 420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr sp = (Addr)startRegs->r_sp; 421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr fp = sp; 422b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov# if defined(VGP_ppc32_linux) 423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr lr = startRegs->misc.PPC32.r_lr; 424b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov# elif defined(VGP_ppc64_linux) 425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr lr = startRegs->misc.PPC64.r_lr; 426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# endif 427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr fp_min = sp; 428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Snaffle IPs from the client's stack into ips[0 .. max_n_ips-1], 430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown stopping when the trail goes cold, which we guess to be 431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown when FP is not a reasonable stack location. */ 432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // JRS 2002-sep-17: hack, to round up fp_max to the end of the 434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // current page, at least. Dunno if it helps. 435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // NJN 2002-sep-17: seems to -- stack traces look like 1.0.X again 436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown fp_max = VG_PGROUNDUP(fp_max_orig); 437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (fp_max >= sizeof(Addr)) 438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown fp_max -= sizeof(Addr); 439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (debug) 441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(printf)("max_n_ips=%d fp_min=0x%lx fp_max_orig=0x%lx, " 442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "fp_max=0x%lx ip=0x%lx fp=0x%lx\n", 443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown max_n_ips, fp_min, fp_max_orig, fp_max, ip, fp); 444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Assertion broken before main() is reached in pthreaded programs; the 446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * offending stack traces only have one item. --njn, 2002-aug-16 */ 447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* vg_assert(fp_min <= fp_max);*/ 448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (fp_min + 512 >= fp_max) { 449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* If the stack limits look bogus, don't poke around ... but 450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown don't bomb out either. */ 451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (sps) sps[0] = sp; 452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (fps) fps[0] = fp; 453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ips[0] = ip; 454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return 1; 455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* fp is %r1. ip is %cia. Note, ppc uses r1 as both the stack and 458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown frame pointers. */ 459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 460b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov# if defined(VGP_ppc64_linux) 461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown redir_stack_size = VEX_GUEST_PPC64_REDIR_STACK_SIZE; 462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown redirs_used = 0; 463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# endif 464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# if defined(VG_PLAT_USES_PPCTOC) 466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Deal with bogus LR values caused by function 467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown interception/wrapping on ppc-TOC platforms; see comment on 468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown similar code a few lines further down. */ 469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (ULong_to_Ptr(lr) == (void*)&VG_(ppctoc_magic_redirect_return_stub) 470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown && VG_(is_valid_tid)(tid_if_known)) { 471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Word hsp = VG_(threads)[tid_if_known].arch.vex.guest_REDIR_SP; 472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown redirs_used++; 473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (hsp >= 1 && hsp < redir_stack_size) 474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lr = VG_(threads)[tid_if_known] 475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown .arch.vex.guest_REDIR_STACK[hsp-1]; 476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# endif 478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* We have to determine whether or not LR currently holds this fn 480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (call it F)'s return address. It might not if F has previously 481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown called some other function, hence overwriting LR with a pointer 482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown to some part of F. Hence if LR and IP point to the same 483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown function then we conclude LR does not hold this function's 484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return address; instead the LR at entry must have been saved in 485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown the stack by F's prologue and so we must get it from there 486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown instead. Note all this guff only applies to the innermost 487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown frame. */ 488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lr_is_first_RA = False; 489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# define M_VG_ERRTXT 1000 491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown UChar buf_lr[M_VG_ERRTXT], buf_ip[M_VG_ERRTXT]; 492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* The following conditional looks grossly inefficient and 493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown surely could be majorly improved, with not much effort. */ 494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (VG_(get_fnname_raw) (lr, buf_lr, M_VG_ERRTXT)) 495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (VG_(get_fnname_raw) (ip, buf_ip, M_VG_ERRTXT)) 496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (VG_(strncmp)(buf_lr, buf_ip, M_VG_ERRTXT)) 497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lr_is_first_RA = True; 498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# undef M_VG_ERRTXT 499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (sps) sps[0] = fp; /* NB. not sp */ 502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (fps) fps[0] = fp; 503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ips[0] = ip; 504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown i = 1; 505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (fp_min <= fp && fp < fp_max-VG_WORDSIZE+1) { 507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* initial FP is sane; keep going */ 509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown fp = (((UWord*)fp)[0]); 510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown while (True) { 512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 513b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov /* On ppc64-linux (ppc64-elf, really), the lr save 514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown slot is 2 words back from sp, whereas on ppc32-elf(?) it's 515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown only one word back. */ 516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# if defined(VG_PLAT_USES_PPCTOC) 517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const Int lr_offset = 2; 518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# else 519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const Int lr_offset = 1; 520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# endif 521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (i >= max_n_ips) 523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Try to derive a new (ip,fp) pair from the current set. */ 526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (fp_min <= fp && fp <= fp_max - lr_offset * sizeof(UWord)) { 528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* fp looks sane, so use it. */ 529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (i == 1 && lr_is_first_RA) 531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ip = lr; 532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown else 533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ip = (((UWord*)fp)[lr_offset]); 534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# if defined(VG_PLAT_USES_PPCTOC) 536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Nasty hack to do with function replacement/wrapping on 537b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov ppc64-linux. If LR points to our magic return stub, 538b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov then we are in a wrapped or intercepted function, in 539b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov which LR has been messed with. The original LR will 540b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov have been pushed onto the thread's hidden REDIR stack 541b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov one down from the top (top element is the saved R2) and 542b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov so we should restore the value from there instead. 543b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov Since nested redirections can and do happen, we keep 544b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov track of the number of nested LRs used by the unwinding 545b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov so far with 'redirs_used'. */ 546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (ip == (Addr)&VG_(ppctoc_magic_redirect_return_stub) 547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown && VG_(is_valid_tid)(tid_if_known)) { 548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Word hsp = VG_(threads)[tid_if_known] 549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown .arch.vex.guest_REDIR_SP; 550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown hsp -= 2 * redirs_used; 551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown redirs_used ++; 552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (hsp >= 1 && hsp < redir_stack_size) 553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ip = VG_(threads)[tid_if_known] 554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown .arch.vex.guest_REDIR_STACK[hsp-1]; 555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# endif 557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (0 == ip || 1 == ip) break; 559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (sps) sps[i] = fp; /* NB. not sp */ 560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (fps) fps[i] = fp; 561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown fp = (((UWord*)fp)[0]); 562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ips[i++] = ip - 1; /* -1: refer to calling insn, not the RA */ 563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (debug) 564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(printf)(" ipsF[%d]=%#08lx\n", i-1, ips[i-1]); 565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ip = ip - 1; /* ip is probably dead at this point, but 566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown play safe, a la x86/amd64 above. See 567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown extensive comments above. */ 568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown continue; 569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* No luck there. We have to give up. */ 572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown n_found = i; 577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return n_found; 578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif 581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ------------------------ arm ------------------------- */ 583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if defined(VGP_arm_linux) 585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known, 587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /*OUT*/Addr* ips, UInt max_n_ips, 588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /*OUT*/Addr* sps, /*OUT*/Addr* fps, 589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown UnwindStartRegs* startRegs, 590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr fp_max_orig ) 591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Bool debug = False; 593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int i; 594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr fp_max; 595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown UInt n_found = 0; 596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vg_assert(sizeof(Addr) == sizeof(UWord)); 598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vg_assert(sizeof(Addr) == sizeof(void*)); 599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown D3UnwindRegs uregs; 601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown uregs.r15 = startRegs->r_pc & 0xFFFFFFFE; 602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown uregs.r14 = startRegs->misc.ARM.r14; 603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown uregs.r13 = startRegs->r_sp; 604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown uregs.r12 = startRegs->misc.ARM.r12; 605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown uregs.r11 = startRegs->misc.ARM.r11; 606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown uregs.r7 = startRegs->misc.ARM.r7; 607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr fp_min = uregs.r13; 608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Snaffle IPs from the client's stack into ips[0 .. max_n_ips-1], 610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown stopping when the trail goes cold, which we guess to be 611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown when FP is not a reasonable stack location. */ 612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // JRS 2002-sep-17: hack, to round up fp_max to the end of the 614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // current page, at least. Dunno if it helps. 615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // NJN 2002-sep-17: seems to -- stack traces look like 1.0.X again 616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown fp_max = VG_PGROUNDUP(fp_max_orig); 617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (fp_max >= sizeof(Addr)) 618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown fp_max -= sizeof(Addr); 619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (debug) 621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(printf)("\nmax_n_ips=%d fp_min=0x%lx fp_max_orig=0x%lx, " 622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "fp_max=0x%lx r15=0x%lx r13=0x%lx\n", 623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown max_n_ips, fp_min, fp_max_orig, fp_max, 624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown uregs.r15, uregs.r13); 625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Assertion broken before main() is reached in pthreaded programs; the 627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * offending stack traces only have one item. --njn, 2002-aug-16 */ 628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* vg_assert(fp_min <= fp_max);*/ 629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // On Darwin, this kicks in for pthread-related stack traces, so they're 630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // only 1 entry long which is wrong. 631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (fp_min + 512 >= fp_max) { 632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* If the stack limits look bogus, don't poke around ... but 633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown don't bomb out either. */ 634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (sps) sps[0] = uregs.r13; 635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (fps) fps[0] = 0; 636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ips[0] = uregs.r15; 637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return 1; 638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* */ 641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (sps) sps[0] = uregs.r13; 643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (fps) fps[0] = 0; 644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ips[0] = uregs.r15; 645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown i = 1; 646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Loop unwinding the stack. */ 648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown while (True) { 650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (debug) { 651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(printf)("i: %d, r15: 0x%lx, r13: 0x%lx\n", 652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown i, uregs.r15, uregs.r13); 653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (i >= max_n_ips) 656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (VG_(use_CF_info)( &uregs, fp_min, fp_max )) { 659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (sps) sps[i] = uregs.r13; 660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (fps) fps[i] = 0; 661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ips[i++] = (uregs.r15 & 0xFFFFFFFE) - 1; 662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (debug) 663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(printf)("USING CFI: r15: 0x%lx, r13: 0x%lx\n", 664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown uregs.r15, uregs.r13); 665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown uregs.r15 = (uregs.r15 & 0xFFFFFFFE) - 1; 666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown continue; 667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* No luck. We have to give up. */ 669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown n_found = i; 673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return n_found; 674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif 677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 678b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* ------------------------ s390x ------------------------- */ 679b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#if defined(VGP_s390x_linux) 680b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy StepanovUInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known, 681b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov /*OUT*/Addr* ips, UInt max_n_ips, 682b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov /*OUT*/Addr* sps, /*OUT*/Addr* fps, 683b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov UnwindStartRegs* startRegs, 684b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov Addr fp_max_orig ) 685b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{ 686b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov Bool debug = False; 687b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov Int i; 688b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov Addr fp_max; 689b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov UInt n_found = 0; 690b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 691b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov vg_assert(sizeof(Addr) == sizeof(UWord)); 692b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov vg_assert(sizeof(Addr) == sizeof(void*)); 693b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 694b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov D3UnwindRegs uregs; 695b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov uregs.ia = startRegs->r_pc; 696b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov uregs.sp = startRegs->r_sp; 697b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov Addr fp_min = uregs.sp; 698b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov uregs.fp = startRegs->misc.S390X.r_fp; 699b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov uregs.lr = startRegs->misc.S390X.r_lr; 700b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 701b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fp_max = VG_PGROUNDUP(fp_max_orig); 702b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (fp_max >= sizeof(Addr)) 703b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fp_max -= sizeof(Addr); 704b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 705b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (debug) 706b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov VG_(printf)("max_n_ips=%d fp_min=0x%lx fp_max_orig=0x%lx, " 707b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov "fp_max=0x%lx IA=0x%lx SP=0x%lx FP=0x%lx\n", 708b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov max_n_ips, fp_min, fp_max_orig, fp_max, 709b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov uregs.ia, uregs.sp,uregs.fp); 710b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 711b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov /* The first frame is pretty obvious */ 712b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov ips[0] = uregs.ia; 713b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (sps) sps[0] = uregs.sp; 714b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (fps) fps[0] = uregs.fp; 715b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov i = 1; 716b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 717b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov /* for everything else we have to rely on the eh_frame. gcc defaults to 718b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov not create a backchain and all the other tools (like gdb) also have 719b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov to use the CFI. */ 720b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov while (True) { 721b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (i >= max_n_ips) 722b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov break; 723b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 724b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (VG_(use_CF_info)( &uregs, fp_min, fp_max )) { 725b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (sps) sps[i] = uregs.sp; 726b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (fps) fps[i] = uregs.fp; 727b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov ips[i++] = uregs.ia - 1; 728b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov uregs.ia = uregs.ia - 1; 729b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov continue; 730b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov } 731b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov /* A problem on the first frame? Lets assume it was a bad jump. 732b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov We will use the link register and the current stack and frame 733b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov pointers and see if we can use the CFI in the next round. */ 734b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (i == 1) { 735b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (sps) { 736b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov sps[i] = sps[0]; 737b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov uregs.sp = sps[0]; 738b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov } 739b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (fps) { 740b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fps[i] = fps[0]; 741b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov uregs.fp = fps[0]; 742b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov } 743b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov uregs.ia = uregs.lr - 1; 744b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov ips[i++] = uregs.lr - 1; 745b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov continue; 746b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov } 747b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 748b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov /* No luck. We have to give up. */ 749b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov break; 750b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov } 751b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 752b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov n_found = i; 753b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov return n_found; 754b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov} 755b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#endif 756b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/ 758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- ---*/ 759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- END platform-dependent unwinder worker functions ---*/ 760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- ---*/ 761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/ 762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/ 764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Exported functions. ---*/ 765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/ 766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt VG_(get_StackTrace) ( ThreadId tid, 768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /*OUT*/StackTrace ips, UInt max_n_ips, 769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /*OUT*/StackTrace sps, 770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /*OUT*/StackTrace fps, 771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Word first_ip_delta ) 772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Get the register values with which to start the unwind. */ 774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown UnwindStartRegs startRegs; 775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(memset)( &startRegs, 0, sizeof(startRegs) ); 776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(get_UnwindStartRegs)( &startRegs, tid ); 777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr stack_highest_word = VG_(threads)[tid].client_stack_highest_word; 779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr stack_lowest_word = 0; 780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# if defined(VGP_x86_linux) 782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Nasty little hack to deal with syscalls - if libc is using its 783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown _dl_sysinfo_int80 function for syscalls (the TLS version does), 784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown then ip will always appear to be in that function when doing a 785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown syscall, not the actual libc function doing the syscall. This 786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown check sees if IP is within that function, and pops the return 787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown address off the stack so that ip is placed within the library 788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown function calling the syscall. This makes stack backtraces much 789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown more useful. 790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown The function is assumed to look like this (from glibc-2.3.6 sources): 792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown _dl_sysinfo_int80: 793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown int $0x80 794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ret 795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown That is 3 (2+1) bytes long. We could be more thorough and check 796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown the 3 bytes of the function are as expected, but I can't be 797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown bothered. 798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */ 799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (VG_(client__dl_sysinfo_int80) != 0 /* we know its address */ 800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown && startRegs.r_pc >= VG_(client__dl_sysinfo_int80) 801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown && startRegs.r_pc < VG_(client__dl_sysinfo_int80)+3 802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown && VG_(am_is_valid_for_client)(startRegs.r_pc, sizeof(Addr), 803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VKI_PROT_READ)) { 804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown startRegs.r_pc = (ULong) *(Addr*)(UWord)startRegs.r_sp; 805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown startRegs.r_sp += (ULong) sizeof(Addr); 806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# endif 808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* See if we can get a better idea of the stack limits */ 810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(stack_limits)( (Addr)startRegs.r_sp, 811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown &stack_lowest_word, &stack_highest_word ); 812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Take into account the first_ip_delta. */ 814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown startRegs.r_pc += (Long)(Word)first_ip_delta; 815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (0) 817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(printf)("tid %d: stack_highest=0x%08lx ip=0x%010llx " 818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "sp=0x%010llx\n", 819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tid, stack_highest_word, 820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown startRegs.r_pc, startRegs.r_sp); 821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return VG_(get_StackTrace_wrk)(tid, ips, max_n_ips, 823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown sps, fps, 824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown &startRegs, 825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown stack_highest_word); 826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void printIpDesc(UInt n, Addr ip, void* uu_opaque) 829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown #define BUF_LEN 4096 831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown static UChar buf[BUF_LEN]; 833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(describe_IP)(ip, buf, BUF_LEN); 835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (VG_(clo_xml)) { 837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(printf_xml)(" %s\n", buf); 838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } else { 839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(message)(Vg_UserMsg, " %s %s\n", ( n == 0 ? "at" : "by" ), buf); 840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Print a StackTrace. */ 844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid VG_(pp_StackTrace) ( StackTrace ips, UInt n_ips ) 845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vg_assert( n_ips > 0 ); 847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (VG_(clo_xml)) 849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(printf_xml)(" <stack>\n"); 850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(apply_StackTrace)( printIpDesc, NULL, ips, n_ips ); 852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (VG_(clo_xml)) 854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(printf_xml)(" </stack>\n"); 855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Get and immediately print a StackTrace. */ 858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid VG_(get_and_pp_StackTrace) ( ThreadId tid, UInt max_n_ips ) 859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr ips[max_n_ips]; 861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown UInt n_ips 862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown = VG_(get_StackTrace)(tid, ips, max_n_ips, 863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown NULL/*array to dump SP values in*/, 864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown NULL/*array to dump FP values in*/, 865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 0/*first_ip_delta*/); 866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(pp_StackTrace)(ips, n_ips); 867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid VG_(apply_StackTrace)( 870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void(*action)(UInt n, Addr ip, void* opaque), 871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void* opaque, 872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown StackTrace ips, UInt n_ips 873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ) 874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Bool main_done = False; 876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int i = 0; 877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vg_assert(n_ips > 0); 879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown do { 880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr ip = ips[i]; 881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Stop after the first appearance of "main" or one of the other names 883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // (the appearance of which is a pretty good sign that we've gone past 884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // main without seeing it, for whatever reason) 885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if ( ! VG_(clo_show_below_main) ) { 886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Vg_FnNameKind kind = VG_(get_fnname_kind_from_IP)(ip); 887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (Vg_FnNameMain == kind || Vg_FnNameBelowMain == kind) { 888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown main_done = True; 889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Act on the ip 893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown action(i, ip, opaque); 894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown i++; 896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } while (i < n_ips && !main_done); 897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown #undef MYBUF_LEN 899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/ 903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- end ---*/ 904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/ 905