m_stacktrace.c revision 121d1d082678d9f50ac50f66c93f23122c31739b
1
2/*--------------------------------------------------------------------*/
3/*--- Take snapshots of client stacks.              m_stacktrace.c ---*/
4/*--------------------------------------------------------------------*/
5
6/*
7   This file is part of Valgrind, a dynamic binary instrumentation
8   framework.
9
10   Copyright (C) 2000-2005 Julian Seward
11      jseward@acm.org
12
13   This program is free software; you can redistribute it and/or
14   modify it under the terms of the GNU General Public License as
15   published by the Free Software Foundation; either version 2 of the
16   License, or (at your option) any later version.
17
18   This program is distributed in the hope that it will be useful, but
19   WITHOUT ANY WARRANTY; without even the implied warranty of
20   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21   General Public License for more details.
22
23   You should have received a copy of the GNU General Public License
24   along with this program; if not, write to the Free Software
25   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26   02111-1307, USA.
27
28   The GNU General Public License is contained in the file COPYING.
29*/
30
31#include "pub_core_basics.h"
32#include "pub_core_threadstate.h"
33#include "pub_core_debuginfo.h"
34#include "pub_core_aspacemgr.h"     // For VG_(is_addressable)()
35#include "pub_core_libcbase.h"
36#include "pub_core_libcassert.h"
37#include "pub_core_libcprint.h"
38#include "pub_core_machine.h"
39#include "pub_core_options.h"
40#include "pub_core_profile.h"
41#include "pub_core_stacktrace.h"
42#include "pub_core_trampoline.h"
43
44/*------------------------------------------------------------*/
45/*--- Exported functions.                                  ---*/
46/*------------------------------------------------------------*/
47
48/* Take a snapshot of the client's stack, putting the up to 'n_ips'
49   IPs into 'ips'.  In order to be thread-safe, we pass in the
50   thread's IP SP, FP if that's meaningful, and LR if that's
51   meaningful.  Returns number of IPs put in 'ips'.
52*/
53UInt VG_(get_StackTrace2) ( Addr* ips, UInt n_ips,
54                            Addr ip, Addr sp, Addr fp, Addr lr,
55                            Addr fp_min, Addr fp_max_orig )
56{
57#if defined(VGP_ppc32_linux)
58   Bool  lr_is_first_RA = False; /* ppc only */
59#endif
60   Bool  debug = False;
61   Int   i;
62   Addr  fp_max;
63   UInt  n_found = 0;
64
65   VGP_PUSHCC(VgpExeContext);
66
67   vg_assert(sizeof(Addr) == sizeof(UWord));
68   vg_assert(sizeof(Addr) == sizeof(void*));
69
70   /* Snaffle IPs from the client's stack into ips[0 .. n_ips-1],
71      putting zeroes in when the trail goes cold, which we guess to be
72      when FP is not a reasonable stack location. */
73
74   for (i = 0; i < n_ips; i++)
75      ips[i] = 0;
76
77   // JRS 2002-sep-17: hack, to round up fp_max to the end of the
78   // current page, at least.  Dunno if it helps.
79   // NJN 2002-sep-17: seems to -- stack traces look like 1.0.X again
80   fp_max = VG_PGROUNDUP(fp_max_orig);
81   fp_max -= sizeof(Addr);
82
83   if (debug)
84      VG_(printf)("n_ips=%d fp_min=%p fp_max_orig=%p, fp_max=%p ip=%p fp=%p\n",
85		  n_ips, fp_min, fp_max_orig, fp_max, ip, fp);
86
87   /* Assertion broken before main() is reached in pthreaded programs;  the
88    * offending stack traces only have one item.  --njn, 2002-aug-16 */
89   /* vg_assert(fp_min <= fp_max);*/
90
91   if (fp_min + VG_(clo_max_stackframe) <= fp_max) {
92      /* If the stack is ridiculously big, don't poke around ... but
93         don't bomb out either.  Needed to make John Regehr's
94         user-space threads package work. JRS 20021001 */
95      ips[0] = ip;
96      VGP_POPCC(VgpExeContext);
97      return 1;
98   }
99
100   /* Otherwise unwind the stack in a platform-specific way.  Trying
101      to merge the x86, amd64 and ppc32 logic into a single piece of
102      code is just too confusing. */
103
104   /*--------------------- x86 and amd64 ---------------------*/
105
106#  if defined(VGP_x86_linux) || defined(VGP_amd64_linux)
107
108   /* fp is %ebp/%rbp.  sp is %esp/%rsp.  ip is %eip/%rip. */
109
110   ips[0] = ip;
111   i = 1;
112
113   while (True) {
114
115      if (i >= n_ips)
116         break;
117
118      /* Try to derive a new (ip,sp,fp) triple from the current
119         set. */
120
121      /* First off, see if there is any CFI info to hand which can
122         be used. */
123      if ( VG_(use_CFI_info)( &ip, &sp, &fp, fp_min, fp_max ) ) {
124         ips[i++] = ip;
125         if (debug)
126            VG_(printf)("     ipsC[%d]=%08p\n", i-1, ips[i-1]);
127         ip = ip - 1;
128         continue;
129      }
130
131      /* If VG_(use_CFI_info) fails, it won't modify ip/sp/fp, so
132         we can safely try the old-fashioned method. */
133      /* This bit is supposed to deal with frames resulting from
134         functions which begin "pushl% ebp ; movl %esp, %ebp" (x86)
135         or "pushq %rbp ; movq %rsp, %rbp" (amd64).  Unfortunately,
136         since we can't (easily) look at the insns at the start of
137         the fn, like GDB does, there's no reliable way to tell.
138         Hence the hack of first trying out CFI, and if that fails,
139         then use this as a fallback. */
140      if (fp_min <= fp && fp <= fp_max) {
141         /* fp looks sane, so use it. */
142         ip = (((UWord*)fp)[1]);
143         sp = fp + sizeof(Addr) /*saved %ebp/%rbp*/
144                 + sizeof(Addr) /*ra*/;
145         fp = (((UWord*)fp)[0]);
146         ips[i++] = ip;
147         if (debug)
148            VG_(printf)("     ipsF[%d]=%08p\n", i-1, ips[i-1]);
149         ip = ip - 1;
150         continue;
151      }
152
153      /* No luck there.  We have to give up. */
154      break;
155   }
156
157   /*--------------------- ppc32 ---------------------*/
158
159#  elif defined(VGP_ppc32_linux)
160
161   /* fp is %r1.  ip is %cia.  Note, ppc uses r1 as both the stack and
162      frame pointers. */
163
164   lr_is_first_RA = False;
165   {
166#     define M_VG_ERRTXT 1000
167      UChar buf_lr[M_VG_ERRTXT], buf_ip[M_VG_ERRTXT];
168      if (VG_(get_fnname_nodemangle) (lr, buf_lr, M_VG_ERRTXT))
169         if (VG_(get_fnname_nodemangle) (ip, buf_ip, M_VG_ERRTXT))
170            if (VG_(strncmp)(buf_lr, buf_ip, M_VG_ERRTXT))
171               lr_is_first_RA = True;
172#     undef M_VG_ERRTXT
173   }
174
175   ips[0] = ip;
176   i = 1;
177   fp = (((UWord*)fp)[0]);
178
179   while (True) {
180
181      if (i >= n_ips)
182         break;
183
184      /* Try to derive a new (ip,fp) pair from the current set. */
185
186      if (fp_min <= fp && fp <= fp_max) {
187         /* fp looks sane, so use it. */
188
189         if (i == 1 && lr_is_first_RA)
190            ip = lr;
191         else
192            ip = (((UWord*)fp)[1]);
193
194         fp = (((UWord*)fp)[0]);
195         ips[i++] = ip;
196         if (debug)
197            VG_(printf)("     ipsF[%d]=%08p\n", i-1, ips[i-1]);
198         continue;
199      }
200
201      /* No luck there.  We have to give up. */
202      break;
203   }
204
205#  else
206#    error "Unknown platform"
207#  endif
208
209   n_found = i;
210   VGP_POPCC(VgpExeContext);
211   return n_found;
212}
213
214UInt VG_(get_StackTrace) ( ThreadId tid, StackTrace ips, UInt n_ips )
215{
216   /* thread in thread table */
217   Addr ip                 = VG_(get_IP)(tid);
218   Addr fp                 = VG_(get_FP)(tid);
219   Addr sp                 = VG_(get_SP)(tid);
220   Addr lr                 = VG_(get_LR)(tid);
221   Addr stack_highest_word = VG_(threads)[tid].client_stack_highest_word;
222
223#  if defined(VGP_x86_linux)
224   /* Nasty little hack to deal with sysinfo syscalls - if libc is
225      using the sysinfo page for syscalls (the TLS version does), then
226      ip will always appear to be in that page when doing a syscall,
227      not the actual libc function doing the syscall.  This check sees
228      if IP is within the syscall code, and pops the return address
229      off the stack so that ip is placed within the library function
230      calling the syscall.  This makes stack backtraces much more
231      useful.  */
232   if (ip >= (Addr)&VG_(trampoline_stuff_start)
233       && ip < (Addr)&VG_(trampoline_stuff_end)
234       && VG_(am_is_valid_for_client)(sp, sizeof(Addr), VKI_PROT_READ)) {
235      ip = *(Addr *)sp;
236      sp += sizeof(Addr);
237   }
238#  endif
239
240   if (0)
241      VG_(printf)("tid %d: stack_highest=%p ip=%p sp=%p fp=%p\n",
242		  tid, stack_highest_word, ip, sp, fp);
243
244   return VG_(get_StackTrace2)(ips, n_ips, ip, sp, fp, lr, sp, stack_highest_word);
245}
246
247static void printIpDesc(UInt n, Addr ip)
248{
249   #define BUF_LEN   4096
250
251   static UChar buf[BUF_LEN];
252
253   VG_(describe_IP)(ip, buf, BUF_LEN);
254
255   if (VG_(clo_xml)) {
256      VG_(message)(Vg_UserMsg, "    %s", buf);
257   } else {
258      VG_(message)(Vg_UserMsg, "   %s %s", ( n == 0 ? "at" : "by" ), buf);
259   }
260}
261
262/* Print a StackTrace. */
263void VG_(pp_StackTrace) ( StackTrace ips, UInt n_ips )
264{
265   vg_assert( n_ips > 0 );
266
267   if (VG_(clo_xml))
268      VG_(message)(Vg_UserMsg, "  <stack>");
269
270   VG_(apply_StackTrace)( printIpDesc, ips, n_ips );
271
272   if (VG_(clo_xml))
273      VG_(message)(Vg_UserMsg, "  </stack>");
274}
275
276/* Get and immediately print a StackTrace. */
277void VG_(get_and_pp_StackTrace) ( ThreadId tid, UInt n_ips )
278{
279   Addr ips[n_ips];
280   VG_(get_StackTrace)(tid, ips, n_ips);
281   VG_(pp_StackTrace) (     ips, n_ips);
282}
283
284
285void VG_(apply_StackTrace)( void(*action)(UInt n, Addr ip),
286                            StackTrace ips, UInt n_ips )
287{
288   #define MYBUF_LEN 10    // only needs to be long enough for "main"
289
290   Bool main_done = False;
291   Char mybuf[MYBUF_LEN];     // ok to stack allocate mybuf[] -- it's tiny
292   Int i = 0;
293
294   vg_assert(n_ips > 0);
295   do {
296      Addr ip = ips[i];
297      if (i > 0)
298         ip -= VG_MIN_INSTR_SZB;   // point to calling line
299
300      // Stop after "main";  if main() is recursive, stop after last main().
301      if ( ! VG_(clo_show_below_main)) {
302         VG_(get_fnname_nodemangle)( ip, mybuf, MYBUF_LEN );
303         if ( VG_STREQ("main", mybuf) )
304            main_done = True;
305         else if (main_done)
306            break;
307      }
308
309      // Act on the ip
310      action(i, ip);
311
312      i++;
313   } while (i < n_ips && ips[i] != 0);
314
315   #undef MYBUF_LEN
316}
317
318
319/*--------------------------------------------------------------------*/
320/*--- end                                                          ---*/
321/*--------------------------------------------------------------------*/
322