blob: 9cb3ffccccd72cd9bd662ad4e553f423b0a2b9d4 [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"
32#include "pub_core_stacktrace.h"
33
34/*------------------------------------------------------------*/
35/*--- Exported functions. ---*/
36/*------------------------------------------------------------*/
37
njn88b5a982005-05-16 00:16:56 +000038// Stack frame layout and linkage
39#if defined(VGA_x86)
40# define FIRST_STACK_FRAME(ebp) (ebp)
41# define STACK_FRAME_RET(ebp) (((UWord*)ebp)[1])
42# define STACK_FRAME_NEXT(ebp) (((UWord*)ebp)[0])
43#elif defined(VGA_amd64)
44# define FIRST_STACK_FRAME(rbp) (rbp)
45# define STACK_FRAME_RET(rbp) (((UWord*)rbp)[1])
46# define STACK_FRAME_NEXT(rbp) (((UWord*)rbp)[0])
47#else
48# error Unknown platform
49#endif
50
njnd01fef72005-03-25 23:35:48 +000051/* Take a snapshot of the client's stack, putting the up to 'n_ips' IPs
52 into 'ips'. In order to be thread-safe, we pass in the thread's IP
53 and FP. Returns number of IPs put in 'ips'. */
sewardj35165532005-04-30 18:47:48 +000054UInt VG_(get_StackTrace2) ( Addr* ips, UInt n_ips,
55 Addr ip, Addr sp, Addr fp,
njnd01fef72005-03-25 23:35:48 +000056 Addr fp_min, Addr fp_max_orig )
57{
58 static const Bool debug = False;
59 Int i;
60 Addr fp_max;
61 UInt n_found = 0;
62
63 VGP_PUSHCC(VgpExeContext);
64
65 /* First snaffle IPs from the client's stack into ips[0 .. n_ips-1],
66 putting zeroes in when the trail goes cold, which we guess to be when
67 FP is not a reasonable stack location. We also assert that FP
68 increases down the chain. */
69
70 // Gives shorter stack trace for tests/badjump.c
71 // JRS 2002-aug-16: I don't think this is a big deal; looks ok for
72 // most "normal" backtraces.
73 // NJN 2002-sep-05: traces for pthreaded programs are particularly bad.
74
75 // JRS 2002-sep-17: hack, to round up fp_max to the end of the
76 // current page, at least. Dunno if it helps.
77 // NJN 2002-sep-17: seems to -- stack traces look like 1.0.X again
78 fp_max = (fp_max_orig + VKI_PAGE_SIZE - 1) & ~(VKI_PAGE_SIZE - 1);
79 fp_max -= sizeof(Addr);
80
81 if (debug)
82 VG_(printf)("n_ips=%d fp_min=%p fp_max_orig=%p, fp_max=%p ip=%p fp=%p\n",
83 n_ips, fp_min, fp_max_orig, fp_max, ip, fp);
84
85 /* Assertion broken before main() is reached in pthreaded programs; the
86 * offending stack traces only have one item. --njn, 2002-aug-16 */
87 /* vg_assert(fp_min <= fp_max);*/
88
sewardj35165532005-04-30 18:47:48 +000089 ips[0] = ip;
90 i = 1;
91
92 if (fp_min + VG_(clo_max_stackframe) <= fp_max) {
njnd01fef72005-03-25 23:35:48 +000093 /* If the stack is ridiculously big, don't poke around ... but
94 don't bomb out either. Needed to make John Regehr's
95 user-space threads package work. JRS 20021001 */
njnd01fef72005-03-25 23:35:48 +000096 } else {
sewardj35165532005-04-30 18:47:48 +000097
njn88b5a982005-05-16 00:16:56 +000098 // XXX: I think this line is needed for PPC to work, but I'm not
99 // certain, so I'm commenting it out for the moment.
100 //fp = FIRST_STACK_FRAME(fp)
101
sewardj35165532005-04-30 18:47:48 +0000102 while (True) {
103
104 if (i >= n_ips)
105 break;
106
107 /* Try to derive a new (ip,sp,fp) triple from the current
108 set. */
109
110 /* First off, see if there is any CFI info to hand which can
111 be used. */
112 if ( VG_(use_CFI_info)( &ip, &sp, &fp, fp_min, fp_max ) ) {
113 ips[i++] = ip;
114 if (debug)
115 VG_(printf)(" ipsC[%d]=%08p\n", i-1, ips[i-1]);
116 continue;
117 }
118
119 /* If VG_(use_CFI_info) fails, it won't modify ip/sp/fp, so
120 we can safely try the old-fashioned method. */
121 /* This bit is supposed to deal with frames resulting from
122 functions which begin "pushl% ebp ; movl %esp, %ebp" (x86)
sewardj0b954fd2005-05-16 11:47:17 +0000123 or "pushq %rbp ; movq %rsp, %rbp" (amd64). Unfortunately,
sewardj35165532005-04-30 18:47:48 +0000124 since we can't (easily) look at the insns at the start of
125 the fn, like GDB does, there's no reliable way to tell.
126 Hence the hack of first trying out CFI, and if that fails,
127 then use this as a fallback. */
128 if (fp_min <= fp && fp <= fp_max) {
129 /* fp looks sane, so use it. */
njn88b5a982005-05-16 00:16:56 +0000130 ip = STACK_FRAME_RET(fp);
sewardj35165532005-04-30 18:47:48 +0000131 sp = fp + sizeof(Addr) /*saved %ebp/%rbp*/
132 + sizeof(Addr) /*ra*/;
njn88b5a982005-05-16 00:16:56 +0000133 fp = STACK_FRAME_NEXT(fp);
sewardj35165532005-04-30 18:47:48 +0000134 ips[i++] = ip;
135 if (debug)
136 VG_(printf)(" ipsF[%d]=%08p\n", i-1, ips[i-1]);
137 continue;
138 }
139
140 /* No luck there. We have to give up. */
141 break;
njnd01fef72005-03-25 23:35:48 +0000142 }
sewardj35165532005-04-30 18:47:48 +0000143
njnd01fef72005-03-25 23:35:48 +0000144 }
145 n_found = i;
146
147 /* Put zeroes in the rest. */
148 for (; i < n_ips; i++) {
149 ips[i] = 0;
150 }
151 VGP_POPCC(VgpExeContext);
152
153 return n_found;
154}
155
156UInt VG_(get_StackTrace) ( ThreadId tid, StackTrace ips, UInt n_ips )
157{
158 /* thread in thread table */
159 ThreadState* tst = & VG_(threads)[ tid ];
160 Addr ip = INSTR_PTR(tst->arch);
161 Addr fp = FRAME_PTR(tst->arch);
162 Addr sp = STACK_PTR(tst->arch);
njn50ba34e2005-04-04 02:41:42 +0000163 Addr stack_highest_word = tst->client_stack_highest_word;
njnd01fef72005-03-25 23:35:48 +0000164
sewardj520e3492005-05-02 10:39:16 +0000165#if defined(VGP_x86_linux)
njnd01fef72005-03-25 23:35:48 +0000166 /* Nasty little hack to deal with sysinfo syscalls - if libc is
167 using the sysinfo page for syscalls (the TLS version does), then
168 ip will always appear to be in that page when doing a syscall,
169 not the actual libc function doing the syscall. This check sees
170 if IP is within the syscall code, and pops the return address
171 off the stack so that ip is placed within the library function
172 calling the syscall. This makes stack backtraces much more
173 useful. */
174 if (ip >= VG_(client_trampoline_code)+VG_(tramp_syscall_offset) &&
175 ip < VG_(client_trampoline_code)+VG_(trampoline_code_length) &&
176 VG_(is_addressable)(sp, sizeof(Addr), VKI_PROT_READ)) {
177 ip = *(Addr *)sp;
178 sp += sizeof(Addr);
179 }
180#endif
181 if (0)
182 VG_(printf)("tid %d: stack_highest=%p ip=%p sp=%p fp=%p\n",
183 tid, stack_highest_word, ip, sp, fp);
184
sewardj35165532005-04-30 18:47:48 +0000185 return VG_(get_StackTrace2)(ips, n_ips, ip, sp, fp, sp, stack_highest_word);
njnd01fef72005-03-25 23:35:48 +0000186}
187
188static void printIpDesc(UInt n, Addr ip)
189{
njn47b209a2005-03-25 23:47:16 +0000190 static UChar buf[VG_ERRTXT_LEN];
njnd01fef72005-03-25 23:35:48 +0000191
njn47b209a2005-03-25 23:47:16 +0000192 VG_(describe_IP)(ip, buf, VG_ERRTXT_LEN);
njnd01fef72005-03-25 23:35:48 +0000193 VG_(message)(Vg_UserMsg, " %s %s", ( n == 0 ? "at" : "by" ), buf);
194}
195
196/* Print a StackTrace. */
197void VG_(pp_StackTrace) ( StackTrace ips, UInt n_ips )
198{
199 vg_assert( n_ips > 0 );
200 VG_(apply_StackTrace)( printIpDesc, ips, n_ips );
201}
202
203/* Get and immediately print a StackTrace. */
204void VG_(get_and_pp_StackTrace) ( ThreadId tid, UInt n_ips )
205{
206 Addr ips[n_ips];
207 VG_(get_StackTrace)(tid, ips, n_ips);
208 VG_(pp_StackTrace) ( ips, n_ips);
209}
210
211
212void VG_(apply_StackTrace)( void(*action)(UInt n, Addr ip),
213 StackTrace ips, UInt n_ips )
214{
215 #define MYBUF_LEN 10 // only needs to be long enough for "main"
216
217 Bool main_done = False;
218 Char mybuf[MYBUF_LEN]; // ok to stack allocate mybuf[] -- it's tiny
219 Int i = 0;
220
221 vg_assert(n_ips > 0);
222 do {
223 Addr ip = ips[i];
224 if (i > 0)
njna60a7c12005-05-08 17:49:37 +0000225 ip -= VGA_MIN_INSTR_SZB; // point to calling line
njnd01fef72005-03-25 23:35:48 +0000226
227 // Stop after "main"; if main() is recursive, stop after last main().
228 if ( ! VG_(clo_show_below_main)) {
229 VG_(get_fnname_nodemangle)( ip, mybuf, MYBUF_LEN );
230 if ( VG_STREQ("main", mybuf) )
231 main_done = True;
232 else if (main_done)
233 break;
234 }
235
236 // Act on the ip
237 action(i, ip);
238
239 i++;
240 } while (i < n_ips && ips[i] != 0);
241
242 #undef MYBUF_LEN
243}
244
245
246/*--------------------------------------------------------------------*/
sewardj267100d2005-04-24 12:33:12 +0000247/*--- end m_stacktrace.c ---*/
njnd01fef72005-03-25 23:35:48 +0000248/*--------------------------------------------------------------------*/