blob: 9d5228ac961ddf314721552bbf9c5c9214b83adf [file] [log] [blame]
sewardj267100d2005-04-24 12:33:12 +00001
njnd01fef72005-03-25 23:35:48 +00002/*--------------------------------------------------------------------*/
sewardj267100d2005-04-24 12:33:12 +00003/*--- Take snapshots of client stacks. m_stacktrace.c ---*/
njnd01fef72005-03-25 23:35:48 +00004/*--------------------------------------------------------------------*/
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
njnc7561b92005-06-19 01:24:32 +000031#include "pub_core_basics.h"
32#include "pub_core_threadstate.h"
njn88c51482005-06-25 20:49:33 +000033#include "pub_core_debuginfo.h"
njn24a6efb2005-06-20 03:36:51 +000034#include "pub_core_aspacemgr.h" // For VG_(is_addressable)()
njn97405b22005-06-02 03:39:33 +000035#include "pub_core_libcbase.h"
njn132bfcc2005-06-04 19:16:06 +000036#include "pub_core_libcassert.h"
njn36a20fa2005-06-03 03:08:39 +000037#include "pub_core_libcprint.h"
njnf536bbb2005-06-13 04:21:38 +000038#include "pub_core_machine.h"
njn20242342005-05-16 23:31:24 +000039#include "pub_core_options.h"
njn31513b42005-06-01 03:09:59 +000040#include "pub_core_profile.h"
njnd01fef72005-03-25 23:35:48 +000041#include "pub_core_stacktrace.h"
njna7598f62005-06-18 03:27:58 +000042#include "pub_core_trampoline.h"
njnd01fef72005-03-25 23:35:48 +000043
44/*------------------------------------------------------------*/
45/*--- Exported functions. ---*/
46/*------------------------------------------------------------*/
47
sewardjacaec5f2005-08-19 16:02:59 +000048/* 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*/
sewardj35165532005-04-30 18:47:48 +000053UInt VG_(get_StackTrace2) ( Addr* ips, UInt n_ips,
sewardjacaec5f2005-08-19 16:02:59 +000054 Addr ip, Addr sp, Addr fp, Addr lr,
njnd01fef72005-03-25 23:35:48 +000055 Addr fp_min, Addr fp_max_orig )
56{
njn2a3b9292005-08-24 01:56:15 +000057#if defined(VGP_ppc32_linux)
sewardjacaec5f2005-08-19 16:02:59 +000058 Bool lr_is_first_RA = False; /* ppc only */
njn2a3b9292005-08-24 01:56:15 +000059#endif
sewardjacaec5f2005-08-19 16:02:59 +000060 Bool debug = False;
61 Int i;
62 Addr fp_max;
63 UInt n_found = 0;
njnd01fef72005-03-25 23:35:48 +000064
65 VGP_PUSHCC(VgpExeContext);
66
sewardjacaec5f2005-08-19 16:02:59 +000067 vg_assert(sizeof(Addr) == sizeof(UWord));
68 vg_assert(sizeof(Addr) == sizeof(void*));
njnd01fef72005-03-25 23:35:48 +000069
sewardjacaec5f2005-08-19 16:02:59 +000070 /* 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;
njnd01fef72005-03-25 23:35:48 +000076
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
sewardj45f4e7c2005-09-27 19:20:21 +000080 fp_max = VG_PGROUNDUP(fp_max_orig);
njnd01fef72005-03-25 23:35:48 +000081 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
sewardj35165532005-04-30 18:47:48 +000091 if (fp_min + VG_(clo_max_stackframe) <= fp_max) {
njnd01fef72005-03-25 23:35:48 +000092 /* 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 */
sewardjacaec5f2005-08-19 16:02:59 +000095 ips[0] = ip;
96 VGP_POPCC(VgpExeContext);
97 return 1;
98 }
sewardj35165532005-04-30 18:47:48 +000099
sewardjacaec5f2005-08-19 16:02:59 +0000100 /* Otherwise unwind the stack in a platform-specific way. Trying
101 to merge the x86, amd64 and ppc32 logic into a single piece of
sewardj75ea7982005-11-14 15:18:25 +0000102 code is just too confusing and difficult to performance-tune. */
njn88b5a982005-05-16 00:16:56 +0000103
sewardj75ea7982005-11-14 15:18:25 +0000104# if defined(VGP_x86_linux)
sewardj35165532005-04-30 18:47:48 +0000105
sewardj75ea7982005-11-14 15:18:25 +0000106 /*--------------------- x86 ---------------------*/
sewardj35165532005-04-30 18:47:48 +0000107
sewardj75ea7982005-11-14 15:18:25 +0000108 /* fp is %ebp. sp is %esp. ip is %eip. */
109
110 ips[0] = ip;
111 i = 1;
112
113 /* Loop unwinding the stack. Note that the IP value we get on
114 * each pass (whether from CFI info or a stack frame) is a
115 * return address so is actually after the calling instruction
116 * in the calling function.
117 *
118 * Because of this we subtract one from the IP after each pass
119 * of the loop so that we find the right CFI block on the next
120 * pass - otherwise we can find the wrong CFI info if it happens
121 * to change after the calling instruction and that will mean
122 * that we will fail to unwind the next step.
123 *
124 * This most frequently happens at the end of a function when
125 * a tail call occurs and we wind up using the CFI info for the
126 * next function which is completely wrong.
127 */
128 while (True) {
129
130 if (i >= n_ips)
131 break;
132
133 /* Try to derive a new (ip,sp,fp) triple from the current
134 set. */
135
136 /* On x86, first try the old-fashioned method of following the
137 %ebp-chain. Code which doesn't use this (that is, compiled
138 with -fomit-frame-pointer) is not ABI compliant and so
139 relatively rare. Besides, trying the CFI first almost always
140 fails, and is expensive. */
141 /* Deal with frames resulting from functions which begin "pushl%
142 ebp ; movl %esp, %ebp" which is the ABI-mandated preamble. */
143 if (fp_min <= fp && fp <= fp_max) {
144 /* fp looks sane, so use it. */
145 ip = (((UWord*)fp)[1]);
146 sp = fp + sizeof(Addr) /*saved %ebp*/
147 + sizeof(Addr) /*ra*/;
148 fp = (((UWord*)fp)[0]);
149 ips[i++] = ip;
150 if (debug)
151 VG_(printf)(" ipsF[%d]=%08p\n", i-1, ips[i-1]);
152 ip = ip - 1;
153 continue;
154 }
155
156 /* That didn't work out, so see if there is any CFI info to hand
157 which can be used. */
158 if ( VG_(use_CFI_info)( &ip, &sp, &fp, fp_min, fp_max ) ) {
159 ips[i++] = ip;
160 if (debug)
161 VG_(printf)(" ipsC[%d]=%08p\n", i-1, ips[i-1]);
162 ip = ip - 1;
163 continue;
164 }
165
166 /* No luck. We have to give up. */
167 break;
168 }
169
170# elif defined(VGP_amd64_linux)
171
172 /*--------------------- amd64 ---------------------*/
173
174 /* fp is %rbp. sp is %rsp. ip is %rip. */
sewardj35165532005-04-30 18:47:48 +0000175
sewardjacaec5f2005-08-19 16:02:59 +0000176 ips[0] = ip;
177 i = 1;
sewardj35165532005-04-30 18:47:48 +0000178
tomac35f102005-11-05 00:17:21 +0000179 /* Loop unwinding the stack. Note that the IP value we get on
180 * each pass (whether from CFI info or a stack frame) is a
181 * return address so is actually after the calling instruction
182 * in the calling function.
183 *
184 * Because of this we subtract one from the IP after each pass
185 * of the loop so that we find the right CFI block on the next
186 * pass - otherwise we can find the wrong CFI info if it happens
187 * to change after the calling instruction and that will mean
188 * that we will fail to unwind the next step.
189 *
190 * This most frequently happens at the end of a function when
191 * a tail call occurs and we wind up using the CFI info for the
192 * next function which is completely wrong.
193 */
sewardjacaec5f2005-08-19 16:02:59 +0000194 while (True) {
sewardj35165532005-04-30 18:47:48 +0000195
sewardjacaec5f2005-08-19 16:02:59 +0000196 if (i >= n_ips)
sewardj35165532005-04-30 18:47:48 +0000197 break;
sewardjacaec5f2005-08-19 16:02:59 +0000198
199 /* Try to derive a new (ip,sp,fp) triple from the current
200 set. */
201
202 /* First off, see if there is any CFI info to hand which can
203 be used. */
204 if ( VG_(use_CFI_info)( &ip, &sp, &fp, fp_min, fp_max ) ) {
205 ips[i++] = ip;
206 if (debug)
207 VG_(printf)(" ipsC[%d]=%08p\n", i-1, ips[i-1]);
tom121d1d02005-11-04 11:31:33 +0000208 ip = ip - 1;
sewardjacaec5f2005-08-19 16:02:59 +0000209 continue;
njnd01fef72005-03-25 23:35:48 +0000210 }
sewardj35165532005-04-30 18:47:48 +0000211
sewardjacaec5f2005-08-19 16:02:59 +0000212 /* If VG_(use_CFI_info) fails, it won't modify ip/sp/fp, so
213 we can safely try the old-fashioned method. */
214 /* This bit is supposed to deal with frames resulting from
sewardj75ea7982005-11-14 15:18:25 +0000215 functions which begin "pushq %rbp ; movq %rsp, %rbp".
216 Unfortunately, since we can't (easily) look at the insns at
217 the start of the fn, like GDB does, there's no reliable way
218 to tell. Hence the hack of first trying out CFI, and if that
219 fails, then use this as a fallback. */
sewardjacaec5f2005-08-19 16:02:59 +0000220 if (fp_min <= fp && fp <= fp_max) {
221 /* fp looks sane, so use it. */
222 ip = (((UWord*)fp)[1]);
sewardj75ea7982005-11-14 15:18:25 +0000223 sp = fp + sizeof(Addr) /*saved %rbp*/
sewardjacaec5f2005-08-19 16:02:59 +0000224 + sizeof(Addr) /*ra*/;
225 fp = (((UWord*)fp)[0]);
226 ips[i++] = ip;
227 if (debug)
228 VG_(printf)(" ipsF[%d]=%08p\n", i-1, ips[i-1]);
tom121d1d02005-11-04 11:31:33 +0000229 ip = ip - 1;
sewardjacaec5f2005-08-19 16:02:59 +0000230 continue;
231 }
232
233 /* No luck there. We have to give up. */
234 break;
njnd01fef72005-03-25 23:35:48 +0000235 }
sewardjacaec5f2005-08-19 16:02:59 +0000236
sewardjacaec5f2005-08-19 16:02:59 +0000237# elif defined(VGP_ppc32_linux)
238
sewardj75ea7982005-11-14 15:18:25 +0000239 /*--------------------- ppc32 ---------------------*/
240
sewardjacaec5f2005-08-19 16:02:59 +0000241 /* fp is %r1. ip is %cia. Note, ppc uses r1 as both the stack and
242 frame pointers. */
243
244 lr_is_first_RA = False;
245 {
246# define M_VG_ERRTXT 1000
247 UChar buf_lr[M_VG_ERRTXT], buf_ip[M_VG_ERRTXT];
248 if (VG_(get_fnname_nodemangle) (lr, buf_lr, M_VG_ERRTXT))
249 if (VG_(get_fnname_nodemangle) (ip, buf_ip, M_VG_ERRTXT))
250 if (VG_(strncmp)(buf_lr, buf_ip, M_VG_ERRTXT))
251 lr_is_first_RA = True;
252# undef M_VG_ERRTXT
253 }
254
255 ips[0] = ip;
256 i = 1;
sewardjacaec5f2005-08-19 16:02:59 +0000257
sewardj525e2322005-11-13 02:41:35 +0000258 if (fp_min <= fp && fp < fp_max-4+1) {
sewardjacaec5f2005-08-19 16:02:59 +0000259
sewardj525e2322005-11-13 02:41:35 +0000260 /* initial FP is sane; keep going */
261 fp = (((UWord*)fp)[0]);
262
263 while (True) {
264
265 if (i >= n_ips)
266 break;
267
268 /* Try to derive a new (ip,fp) pair from the current set. */
269
270 if (fp_min <= fp && fp <= fp_max) {
271 /* fp looks sane, so use it. */
272
273 if (i == 1 && lr_is_first_RA)
274 ip = lr;
275 else
276 ip = (((UWord*)fp)[1]);
277
278 fp = (((UWord*)fp)[0]);
279 ips[i++] = ip;
280 if (debug)
281 VG_(printf)(" ipsF[%d]=%08p\n", i-1, ips[i-1]);
282 continue;
283 }
284
285 /* No luck there. We have to give up. */
sewardjacaec5f2005-08-19 16:02:59 +0000286 break;
sewardjacaec5f2005-08-19 16:02:59 +0000287 }
sewardjacaec5f2005-08-19 16:02:59 +0000288 }
289
290# else
291# error "Unknown platform"
292# endif
293
njnd01fef72005-03-25 23:35:48 +0000294 n_found = i;
njnd01fef72005-03-25 23:35:48 +0000295 VGP_POPCC(VgpExeContext);
njnd01fef72005-03-25 23:35:48 +0000296 return n_found;
297}
298
299UInt VG_(get_StackTrace) ( ThreadId tid, StackTrace ips, UInt n_ips )
300{
301 /* thread in thread table */
njnf536bbb2005-06-13 04:21:38 +0000302 Addr ip = VG_(get_IP)(tid);
303 Addr fp = VG_(get_FP)(tid);
304 Addr sp = VG_(get_SP)(tid);
sewardjacaec5f2005-08-19 16:02:59 +0000305 Addr lr = VG_(get_LR)(tid);
njnf536bbb2005-06-13 04:21:38 +0000306 Addr stack_highest_word = VG_(threads)[tid].client_stack_highest_word;
njnd01fef72005-03-25 23:35:48 +0000307
sewardjb9bce632005-06-21 01:41:34 +0000308# if defined(VGP_x86_linux)
njnd01fef72005-03-25 23:35:48 +0000309 /* Nasty little hack to deal with sysinfo syscalls - if libc is
310 using the sysinfo page for syscalls (the TLS version does), then
311 ip will always appear to be in that page when doing a syscall,
312 not the actual libc function doing the syscall. This check sees
313 if IP is within the syscall code, and pops the return address
314 off the stack so that ip is placed within the library function
315 calling the syscall. This makes stack backtraces much more
316 useful. */
sewardjb9bce632005-06-21 01:41:34 +0000317 if (ip >= (Addr)&VG_(trampoline_stuff_start)
318 && ip < (Addr)&VG_(trampoline_stuff_end)
sewardj45f4e7c2005-09-27 19:20:21 +0000319 && VG_(am_is_valid_for_client)(sp, sizeof(Addr), VKI_PROT_READ)) {
njnd01fef72005-03-25 23:35:48 +0000320 ip = *(Addr *)sp;
321 sp += sizeof(Addr);
322 }
sewardjb9bce632005-06-21 01:41:34 +0000323# endif
324
njnd01fef72005-03-25 23:35:48 +0000325 if (0)
326 VG_(printf)("tid %d: stack_highest=%p ip=%p sp=%p fp=%p\n",
327 tid, stack_highest_word, ip, sp, fp);
328
sewardjacaec5f2005-08-19 16:02:59 +0000329 return VG_(get_StackTrace2)(ips, n_ips, ip, sp, fp, lr, sp, stack_highest_word);
njnd01fef72005-03-25 23:35:48 +0000330}
331
332static void printIpDesc(UInt n, Addr ip)
333{
njn83f9e792005-06-11 05:04:09 +0000334 #define BUF_LEN 4096
335
336 static UChar buf[BUF_LEN];
njnd01fef72005-03-25 23:35:48 +0000337
njn83f9e792005-06-11 05:04:09 +0000338 VG_(describe_IP)(ip, buf, BUF_LEN);
sewardj71bc3cb2005-05-19 00:25:45 +0000339
340 if (VG_(clo_xml)) {
341 VG_(message)(Vg_UserMsg, " %s", buf);
342 } else {
343 VG_(message)(Vg_UserMsg, " %s %s", ( n == 0 ? "at" : "by" ), buf);
344 }
njnd01fef72005-03-25 23:35:48 +0000345}
346
347/* Print a StackTrace. */
348void VG_(pp_StackTrace) ( StackTrace ips, UInt n_ips )
349{
350 vg_assert( n_ips > 0 );
sewardj71bc3cb2005-05-19 00:25:45 +0000351
352 if (VG_(clo_xml))
353 VG_(message)(Vg_UserMsg, " <stack>");
354
njnd01fef72005-03-25 23:35:48 +0000355 VG_(apply_StackTrace)( printIpDesc, ips, n_ips );
sewardj71bc3cb2005-05-19 00:25:45 +0000356
357 if (VG_(clo_xml))
358 VG_(message)(Vg_UserMsg, " </stack>");
njnd01fef72005-03-25 23:35:48 +0000359}
360
361/* Get and immediately print a StackTrace. */
362void VG_(get_and_pp_StackTrace) ( ThreadId tid, UInt n_ips )
363{
364 Addr ips[n_ips];
365 VG_(get_StackTrace)(tid, ips, n_ips);
366 VG_(pp_StackTrace) ( ips, n_ips);
367}
368
369
370void VG_(apply_StackTrace)( void(*action)(UInt n, Addr ip),
371 StackTrace ips, UInt n_ips )
372{
373 #define MYBUF_LEN 10 // only needs to be long enough for "main"
374
375 Bool main_done = False;
376 Char mybuf[MYBUF_LEN]; // ok to stack allocate mybuf[] -- it's tiny
377 Int i = 0;
378
379 vg_assert(n_ips > 0);
380 do {
381 Addr ip = ips[i];
382 if (i > 0)
njnaf839f52005-06-23 03:27:57 +0000383 ip -= VG_MIN_INSTR_SZB; // point to calling line
njnd01fef72005-03-25 23:35:48 +0000384
385 // Stop after "main"; if main() is recursive, stop after last main().
386 if ( ! VG_(clo_show_below_main)) {
387 VG_(get_fnname_nodemangle)( ip, mybuf, MYBUF_LEN );
388 if ( VG_STREQ("main", mybuf) )
389 main_done = True;
390 else if (main_done)
391 break;
392 }
393
394 // Act on the ip
395 action(i, ip);
396
397 i++;
398 } while (i < n_ips && ips[i] != 0);
399
400 #undef MYBUF_LEN
401}
402
403
404/*--------------------------------------------------------------------*/
njn24a6efb2005-06-20 03:36:51 +0000405/*--- end ---*/
njnd01fef72005-03-25 23:35:48 +0000406/*--------------------------------------------------------------------*/