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