blob: bd17ee0b6ea0f1e46569dd932cd27d5e5666b167 [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
80 fp_max = (fp_max_orig + VKI_PAGE_SIZE - 1) & ~(VKI_PAGE_SIZE - 1);
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
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
102 code is just too confusing. */
njn88b5a982005-05-16 00:16:56 +0000103
sewardjacaec5f2005-08-19 16:02:59 +0000104 /*--------------------- x86 and amd64 ---------------------*/
sewardj35165532005-04-30 18:47:48 +0000105
sewardjacaec5f2005-08-19 16:02:59 +0000106# if defined(VGP_x86_linux) || defined(VGP_amd64_linux)
sewardj35165532005-04-30 18:47:48 +0000107
sewardjacaec5f2005-08-19 16:02:59 +0000108 /* fp is %ebp/%rbp. sp is %esp/%rsp. ip is %eip/%rip. */
sewardj35165532005-04-30 18:47:48 +0000109
sewardjacaec5f2005-08-19 16:02:59 +0000110 ips[0] = ip;
111 i = 1;
sewardj35165532005-04-30 18:47:48 +0000112
sewardjacaec5f2005-08-19 16:02:59 +0000113 while (True) {
sewardj35165532005-04-30 18:47:48 +0000114
sewardjacaec5f2005-08-19 16:02:59 +0000115 if (i >= n_ips)
sewardj35165532005-04-30 18:47:48 +0000116 break;
sewardjacaec5f2005-08-19 16:02:59 +0000117
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 continue;
njnd01fef72005-03-25 23:35:48 +0000128 }
sewardj35165532005-04-30 18:47:48 +0000129
sewardjacaec5f2005-08-19 16:02:59 +0000130 /* If VG_(use_CFI_info) fails, it won't modify ip/sp/fp, so
131 we can safely try the old-fashioned method. */
132 /* This bit is supposed to deal with frames resulting from
133 functions which begin "pushl% ebp ; movl %esp, %ebp" (x86)
134 or "pushq %rbp ; movq %rsp, %rbp" (amd64). Unfortunately,
135 since we can't (easily) look at the insns at the start of
136 the fn, like GDB does, there's no reliable way to tell.
137 Hence the hack of first trying out CFI, and if that fails,
138 then use this as a fallback. */
139 if (fp_min <= fp && fp <= fp_max) {
140 /* fp looks sane, so use it. */
141 ip = (((UWord*)fp)[1]);
142 sp = fp + sizeof(Addr) /*saved %ebp/%rbp*/
143 + sizeof(Addr) /*ra*/;
144 fp = (((UWord*)fp)[0]);
145 ips[i++] = ip;
146 if (debug)
147 VG_(printf)(" ipsF[%d]=%08p\n", i-1, ips[i-1]);
148 continue;
149 }
150
151 /* No luck there. We have to give up. */
152 break;
njnd01fef72005-03-25 23:35:48 +0000153 }
sewardjacaec5f2005-08-19 16:02:59 +0000154
155 /*--------------------- ppc32 ---------------------*/
156
157# elif defined(VGP_ppc32_linux)
158
159 /* fp is %r1. ip is %cia. Note, ppc uses r1 as both the stack and
160 frame pointers. */
161
162 lr_is_first_RA = False;
163 {
164# define M_VG_ERRTXT 1000
165 UChar buf_lr[M_VG_ERRTXT], buf_ip[M_VG_ERRTXT];
166 if (VG_(get_fnname_nodemangle) (lr, buf_lr, M_VG_ERRTXT))
167 if (VG_(get_fnname_nodemangle) (ip, buf_ip, M_VG_ERRTXT))
168 if (VG_(strncmp)(buf_lr, buf_ip, M_VG_ERRTXT))
169 lr_is_first_RA = True;
170# undef M_VG_ERRTXT
171 }
172
173 ips[0] = ip;
174 i = 1;
175 fp = (((UWord*)fp)[0]);
176
177 while (True) {
178
179 if (i >= n_ips)
180 break;
181
182 /* Try to derive a new (ip,fp) pair from the current set. */
183
184 if (fp_min <= fp && fp <= fp_max) {
185 /* fp looks sane, so use it. */
186
187 if (i == 1 && lr_is_first_RA)
188 ip = lr;
189 else
190 ip = (((UWord*)fp)[1]);
191
192 fp = (((UWord*)fp)[0]);
193 ips[i++] = ip;
194 if (debug)
195 VG_(printf)(" ipsF[%d]=%08p\n", i-1, ips[i-1]);
196 continue;
197 }
198
199 /* No luck there. We have to give up. */
200 break;
201 }
202
203# else
204# error "Unknown platform"
205# endif
206
njnd01fef72005-03-25 23:35:48 +0000207 n_found = i;
njnd01fef72005-03-25 23:35:48 +0000208 VGP_POPCC(VgpExeContext);
njnd01fef72005-03-25 23:35:48 +0000209 return n_found;
210}
211
212UInt VG_(get_StackTrace) ( ThreadId tid, StackTrace ips, UInt n_ips )
213{
214 /* thread in thread table */
njnf536bbb2005-06-13 04:21:38 +0000215 Addr ip = VG_(get_IP)(tid);
216 Addr fp = VG_(get_FP)(tid);
217 Addr sp = VG_(get_SP)(tid);
sewardjacaec5f2005-08-19 16:02:59 +0000218 Addr lr = VG_(get_LR)(tid);
njnf536bbb2005-06-13 04:21:38 +0000219 Addr stack_highest_word = VG_(threads)[tid].client_stack_highest_word;
njnd01fef72005-03-25 23:35:48 +0000220
sewardjb9bce632005-06-21 01:41:34 +0000221# if defined(VGP_x86_linux)
njnd01fef72005-03-25 23:35:48 +0000222 /* Nasty little hack to deal with sysinfo syscalls - if libc is
223 using the sysinfo page for syscalls (the TLS version does), then
224 ip will always appear to be in that page when doing a syscall,
225 not the actual libc function doing the syscall. This check sees
226 if IP is within the syscall code, and pops the return address
227 off the stack so that ip is placed within the library function
228 calling the syscall. This makes stack backtraces much more
229 useful. */
sewardjb9bce632005-06-21 01:41:34 +0000230 if (ip >= (Addr)&VG_(trampoline_stuff_start)
231 && ip < (Addr)&VG_(trampoline_stuff_end)
232 && VG_(is_addressable)(sp, sizeof(Addr), VKI_PROT_READ)) {
njnd01fef72005-03-25 23:35:48 +0000233 ip = *(Addr *)sp;
234 sp += sizeof(Addr);
235 }
sewardjb9bce632005-06-21 01:41:34 +0000236# endif
237
njnd01fef72005-03-25 23:35:48 +0000238 if (0)
239 VG_(printf)("tid %d: stack_highest=%p ip=%p sp=%p fp=%p\n",
240 tid, stack_highest_word, ip, sp, fp);
241
sewardjacaec5f2005-08-19 16:02:59 +0000242 return VG_(get_StackTrace2)(ips, n_ips, ip, sp, fp, lr, sp, stack_highest_word);
njnd01fef72005-03-25 23:35:48 +0000243}
244
245static void printIpDesc(UInt n, Addr ip)
246{
njn83f9e792005-06-11 05:04:09 +0000247 #define BUF_LEN 4096
248
249 static UChar buf[BUF_LEN];
njnd01fef72005-03-25 23:35:48 +0000250
njn83f9e792005-06-11 05:04:09 +0000251 VG_(describe_IP)(ip, buf, BUF_LEN);
sewardj71bc3cb2005-05-19 00:25:45 +0000252
253 if (VG_(clo_xml)) {
254 VG_(message)(Vg_UserMsg, " %s", buf);
255 } else {
256 VG_(message)(Vg_UserMsg, " %s %s", ( n == 0 ? "at" : "by" ), buf);
257 }
njnd01fef72005-03-25 23:35:48 +0000258}
259
260/* Print a StackTrace. */
261void VG_(pp_StackTrace) ( StackTrace ips, UInt n_ips )
262{
263 vg_assert( n_ips > 0 );
sewardj71bc3cb2005-05-19 00:25:45 +0000264
265 if (VG_(clo_xml))
266 VG_(message)(Vg_UserMsg, " <stack>");
267
njnd01fef72005-03-25 23:35:48 +0000268 VG_(apply_StackTrace)( printIpDesc, ips, n_ips );
sewardj71bc3cb2005-05-19 00:25:45 +0000269
270 if (VG_(clo_xml))
271 VG_(message)(Vg_UserMsg, " </stack>");
njnd01fef72005-03-25 23:35:48 +0000272}
273
274/* Get and immediately print a StackTrace. */
275void VG_(get_and_pp_StackTrace) ( ThreadId tid, UInt n_ips )
276{
277 Addr ips[n_ips];
278 VG_(get_StackTrace)(tid, ips, n_ips);
279 VG_(pp_StackTrace) ( ips, n_ips);
280}
281
282
283void VG_(apply_StackTrace)( void(*action)(UInt n, Addr ip),
284 StackTrace ips, UInt n_ips )
285{
286 #define MYBUF_LEN 10 // only needs to be long enough for "main"
287
288 Bool main_done = False;
289 Char mybuf[MYBUF_LEN]; // ok to stack allocate mybuf[] -- it's tiny
290 Int i = 0;
291
292 vg_assert(n_ips > 0);
293 do {
294 Addr ip = ips[i];
295 if (i > 0)
njnaf839f52005-06-23 03:27:57 +0000296 ip -= VG_MIN_INSTR_SZB; // point to calling line
njnd01fef72005-03-25 23:35:48 +0000297
298 // Stop after "main"; if main() is recursive, stop after last main().
299 if ( ! VG_(clo_show_below_main)) {
300 VG_(get_fnname_nodemangle)( ip, mybuf, MYBUF_LEN );
301 if ( VG_STREQ("main", mybuf) )
302 main_done = True;
303 else if (main_done)
304 break;
305 }
306
307 // Act on the ip
308 action(i, ip);
309
310 i++;
311 } while (i < n_ips && ips[i] != 0);
312
313 #undef MYBUF_LEN
314}
315
316
317/*--------------------------------------------------------------------*/
njn24a6efb2005-06-20 03:36:51 +0000318/*--- end ---*/
njnd01fef72005-03-25 23:35:48 +0000319/*--------------------------------------------------------------------*/