blob: 8847e0e5bb1ca9912dbe2b0500e5d6f85b8f3a1b [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
31#include "core.h"
njn04e16982005-05-31 00:23:43 +000032#include "pub_core_aspacemgr.h"
njn97405b22005-06-02 03:39:33 +000033#include "pub_core_libcbase.h"
njn132bfcc2005-06-04 19:16:06 +000034#include "pub_core_libcassert.h"
njn36a20fa2005-06-03 03:08:39 +000035#include "pub_core_libcprint.h"
njnf536bbb2005-06-13 04:21:38 +000036#include "pub_core_machine.h"
njn20242342005-05-16 23:31:24 +000037#include "pub_core_options.h"
njn31513b42005-06-01 03:09:59 +000038#include "pub_core_profile.h"
njnd01fef72005-03-25 23:35:48 +000039#include "pub_core_stacktrace.h"
40
41/*------------------------------------------------------------*/
42/*--- Exported functions. ---*/
43/*------------------------------------------------------------*/
44
njn88b5a982005-05-16 00:16:56 +000045// Stack frame layout and linkage
46#if defined(VGA_x86)
47# define FIRST_STACK_FRAME(ebp) (ebp)
48# define STACK_FRAME_RET(ebp) (((UWord*)ebp)[1])
49# define STACK_FRAME_NEXT(ebp) (((UWord*)ebp)[0])
50#elif defined(VGA_amd64)
51# define FIRST_STACK_FRAME(rbp) (rbp)
52# define STACK_FRAME_RET(rbp) (((UWord*)rbp)[1])
53# define STACK_FRAME_NEXT(rbp) (((UWord*)rbp)[0])
54#else
55# error Unknown platform
56#endif
57
njnd01fef72005-03-25 23:35:48 +000058/* Take a snapshot of the client's stack, putting the up to 'n_ips' IPs
59 into 'ips'. In order to be thread-safe, we pass in the thread's IP
60 and FP. Returns number of IPs put in 'ips'. */
sewardj35165532005-04-30 18:47:48 +000061UInt VG_(get_StackTrace2) ( Addr* ips, UInt n_ips,
62 Addr ip, Addr sp, Addr fp,
njnd01fef72005-03-25 23:35:48 +000063 Addr fp_min, Addr fp_max_orig )
64{
65 static const Bool debug = False;
66 Int i;
67 Addr fp_max;
68 UInt n_found = 0;
69
70 VGP_PUSHCC(VgpExeContext);
71
72 /* First snaffle IPs from the client's stack into ips[0 .. n_ips-1],
73 putting zeroes in when the trail goes cold, which we guess to be when
74 FP is not a reasonable stack location. We also assert that FP
75 increases down the chain. */
76
77 // Gives shorter stack trace for tests/badjump.c
78 // JRS 2002-aug-16: I don't think this is a big deal; looks ok for
79 // most "normal" backtraces.
80 // NJN 2002-sep-05: traces for pthreaded programs are particularly bad.
81
82 // JRS 2002-sep-17: hack, to round up fp_max to the end of the
83 // current page, at least. Dunno if it helps.
84 // NJN 2002-sep-17: seems to -- stack traces look like 1.0.X again
85 fp_max = (fp_max_orig + VKI_PAGE_SIZE - 1) & ~(VKI_PAGE_SIZE - 1);
86 fp_max -= sizeof(Addr);
87
88 if (debug)
89 VG_(printf)("n_ips=%d fp_min=%p fp_max_orig=%p, fp_max=%p ip=%p fp=%p\n",
90 n_ips, fp_min, fp_max_orig, fp_max, ip, fp);
91
92 /* Assertion broken before main() is reached in pthreaded programs; the
93 * offending stack traces only have one item. --njn, 2002-aug-16 */
94 /* vg_assert(fp_min <= fp_max);*/
95
sewardj35165532005-04-30 18:47:48 +000096 ips[0] = ip;
97 i = 1;
98
99 if (fp_min + VG_(clo_max_stackframe) <= fp_max) {
njnd01fef72005-03-25 23:35:48 +0000100 /* If the stack is ridiculously big, don't poke around ... but
101 don't bomb out either. Needed to make John Regehr's
102 user-space threads package work. JRS 20021001 */
njnd01fef72005-03-25 23:35:48 +0000103 } else {
sewardj35165532005-04-30 18:47:48 +0000104
njn88b5a982005-05-16 00:16:56 +0000105 // XXX: I think this line is needed for PPC to work, but I'm not
106 // certain, so I'm commenting it out for the moment.
107 //fp = FIRST_STACK_FRAME(fp)
108
sewardj35165532005-04-30 18:47:48 +0000109 while (True) {
110
111 if (i >= n_ips)
112 break;
113
114 /* Try to derive a new (ip,sp,fp) triple from the current
115 set. */
116
117 /* First off, see if there is any CFI info to hand which can
118 be used. */
119 if ( VG_(use_CFI_info)( &ip, &sp, &fp, fp_min, fp_max ) ) {
120 ips[i++] = ip;
121 if (debug)
122 VG_(printf)(" ipsC[%d]=%08p\n", i-1, ips[i-1]);
123 continue;
124 }
125
126 /* If VG_(use_CFI_info) fails, it won't modify ip/sp/fp, so
127 we can safely try the old-fashioned method. */
128 /* This bit is supposed to deal with frames resulting from
129 functions which begin "pushl% ebp ; movl %esp, %ebp" (x86)
sewardj0b954fd2005-05-16 11:47:17 +0000130 or "pushq %rbp ; movq %rsp, %rbp" (amd64). Unfortunately,
sewardj35165532005-04-30 18:47:48 +0000131 since we can't (easily) look at the insns at the start of
132 the fn, like GDB does, there's no reliable way to tell.
133 Hence the hack of first trying out CFI, and if that fails,
134 then use this as a fallback. */
135 if (fp_min <= fp && fp <= fp_max) {
136 /* fp looks sane, so use it. */
njn88b5a982005-05-16 00:16:56 +0000137 ip = STACK_FRAME_RET(fp);
sewardj35165532005-04-30 18:47:48 +0000138 sp = fp + sizeof(Addr) /*saved %ebp/%rbp*/
139 + sizeof(Addr) /*ra*/;
njn88b5a982005-05-16 00:16:56 +0000140 fp = STACK_FRAME_NEXT(fp);
sewardj35165532005-04-30 18:47:48 +0000141 ips[i++] = ip;
142 if (debug)
143 VG_(printf)(" ipsF[%d]=%08p\n", i-1, ips[i-1]);
144 continue;
145 }
146
147 /* No luck there. We have to give up. */
148 break;
njnd01fef72005-03-25 23:35:48 +0000149 }
sewardj35165532005-04-30 18:47:48 +0000150
njnd01fef72005-03-25 23:35:48 +0000151 }
152 n_found = i;
153
154 /* Put zeroes in the rest. */
155 for (; i < n_ips; i++) {
156 ips[i] = 0;
157 }
158 VGP_POPCC(VgpExeContext);
159
160 return n_found;
161}
162
163UInt VG_(get_StackTrace) ( ThreadId tid, StackTrace ips, UInt n_ips )
164{
165 /* thread in thread table */
njnf536bbb2005-06-13 04:21:38 +0000166 Addr ip = VG_(get_IP)(tid);
167 Addr fp = VG_(get_FP)(tid);
168 Addr sp = VG_(get_SP)(tid);
169 Addr stack_highest_word = VG_(threads)[tid].client_stack_highest_word;
njnd01fef72005-03-25 23:35:48 +0000170
sewardj520e3492005-05-02 10:39:16 +0000171#if defined(VGP_x86_linux)
njnd01fef72005-03-25 23:35:48 +0000172 /* Nasty little hack to deal with sysinfo syscalls - if libc is
173 using the sysinfo page for syscalls (the TLS version does), then
174 ip will always appear to be in that page when doing a syscall,
175 not the actual libc function doing the syscall. This check sees
176 if IP is within the syscall code, and pops the return address
177 off the stack so that ip is placed within the library function
178 calling the syscall. This makes stack backtraces much more
179 useful. */
180 if (ip >= VG_(client_trampoline_code)+VG_(tramp_syscall_offset) &&
181 ip < VG_(client_trampoline_code)+VG_(trampoline_code_length) &&
182 VG_(is_addressable)(sp, sizeof(Addr), VKI_PROT_READ)) {
183 ip = *(Addr *)sp;
184 sp += sizeof(Addr);
185 }
186#endif
187 if (0)
188 VG_(printf)("tid %d: stack_highest=%p ip=%p sp=%p fp=%p\n",
189 tid, stack_highest_word, ip, sp, fp);
190
sewardj35165532005-04-30 18:47:48 +0000191 return VG_(get_StackTrace2)(ips, n_ips, ip, sp, fp, sp, stack_highest_word);
njnd01fef72005-03-25 23:35:48 +0000192}
193
194static void printIpDesc(UInt n, Addr ip)
195{
njn83f9e792005-06-11 05:04:09 +0000196 #define BUF_LEN 4096
197
198 static UChar buf[BUF_LEN];
njnd01fef72005-03-25 23:35:48 +0000199
njn83f9e792005-06-11 05:04:09 +0000200 VG_(describe_IP)(ip, buf, BUF_LEN);
sewardj71bc3cb2005-05-19 00:25:45 +0000201
202 if (VG_(clo_xml)) {
203 VG_(message)(Vg_UserMsg, " %s", buf);
204 } else {
205 VG_(message)(Vg_UserMsg, " %s %s", ( n == 0 ? "at" : "by" ), buf);
206 }
njnd01fef72005-03-25 23:35:48 +0000207}
208
209/* Print a StackTrace. */
210void VG_(pp_StackTrace) ( StackTrace ips, UInt n_ips )
211{
212 vg_assert( n_ips > 0 );
sewardj71bc3cb2005-05-19 00:25:45 +0000213
214 if (VG_(clo_xml))
215 VG_(message)(Vg_UserMsg, " <stack>");
216
njnd01fef72005-03-25 23:35:48 +0000217 VG_(apply_StackTrace)( printIpDesc, ips, n_ips );
sewardj71bc3cb2005-05-19 00:25:45 +0000218
219 if (VG_(clo_xml))
220 VG_(message)(Vg_UserMsg, " </stack>");
njnd01fef72005-03-25 23:35:48 +0000221}
222
223/* Get and immediately print a StackTrace. */
224void VG_(get_and_pp_StackTrace) ( ThreadId tid, UInt n_ips )
225{
226 Addr ips[n_ips];
227 VG_(get_StackTrace)(tid, ips, n_ips);
228 VG_(pp_StackTrace) ( ips, n_ips);
229}
230
231
232void VG_(apply_StackTrace)( void(*action)(UInt n, Addr ip),
233 StackTrace ips, UInt n_ips )
234{
235 #define MYBUF_LEN 10 // only needs to be long enough for "main"
236
237 Bool main_done = False;
238 Char mybuf[MYBUF_LEN]; // ok to stack allocate mybuf[] -- it's tiny
239 Int i = 0;
240
241 vg_assert(n_ips > 0);
242 do {
243 Addr ip = ips[i];
244 if (i > 0)
njna60a7c12005-05-08 17:49:37 +0000245 ip -= VGA_MIN_INSTR_SZB; // point to calling line
njnd01fef72005-03-25 23:35:48 +0000246
247 // Stop after "main"; if main() is recursive, stop after last main().
248 if ( ! VG_(clo_show_below_main)) {
249 VG_(get_fnname_nodemangle)( ip, mybuf, MYBUF_LEN );
250 if ( VG_STREQ("main", mybuf) )
251 main_done = True;
252 else if (main_done)
253 break;
254 }
255
256 // Act on the ip
257 action(i, ip);
258
259 i++;
260 } while (i < n_ips && ips[i] != 0);
261
262 #undef MYBUF_LEN
263}
264
265
266/*--------------------------------------------------------------------*/
sewardj267100d2005-04-24 12:33:12 +0000267/*--- end m_stacktrace.c ---*/
njnd01fef72005-03-25 23:35:48 +0000268/*--------------------------------------------------------------------*/