blob: 5821d584d37d255c9b96bba5d87fb6e9e172e299 [file] [log] [blame]
njnd01fef72005-03-25 23:35:48 +00001/*--------------------------------------------------------------------*/
2/*--- stacktrace.c ---*/
3/*--------------------------------------------------------------------*/
4
5/*
6 This file is part of Valgrind, a dynamic binary instrumentation
7 framework.
8
9 Copyright (C) 2000-2005 Julian Seward
10 jseward@acm.org
11
12 This program is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License as
14 published by the Free Software Foundation; either version 2 of the
15 License, or (at your option) any later version.
16
17 This program is distributed in the hope that it will be useful, but
18 WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
25 02111-1307, USA.
26
27 The GNU General Public License is contained in the file COPYING.
28*/
29
30#include "core.h"
31#include "pub_core_stacktrace.h"
32
33/*------------------------------------------------------------*/
34/*--- Exported functions. ---*/
35/*------------------------------------------------------------*/
36
37/* Take a snapshot of the client's stack, putting the up to 'n_ips' IPs
38 into 'ips'. In order to be thread-safe, we pass in the thread's IP
39 and FP. Returns number of IPs put in 'ips'. */
40UInt VG_(get_StackTrace2) ( Addr* ips, UInt n_ips, Addr ip, Addr fp,
41 Addr fp_min, Addr fp_max_orig )
42{
43 static const Bool debug = False;
44 Int i;
45 Addr fp_max;
46 UInt n_found = 0;
47
48 VGP_PUSHCC(VgpExeContext);
49
50 /* First snaffle IPs from the client's stack into ips[0 .. n_ips-1],
51 putting zeroes in when the trail goes cold, which we guess to be when
52 FP is not a reasonable stack location. We also assert that FP
53 increases down the chain. */
54
55 // Gives shorter stack trace for tests/badjump.c
56 // JRS 2002-aug-16: I don't think this is a big deal; looks ok for
57 // most "normal" backtraces.
58 // NJN 2002-sep-05: traces for pthreaded programs are particularly bad.
59
60 // JRS 2002-sep-17: hack, to round up fp_max to the end of the
61 // current page, at least. Dunno if it helps.
62 // NJN 2002-sep-17: seems to -- stack traces look like 1.0.X again
63 fp_max = (fp_max_orig + VKI_PAGE_SIZE - 1) & ~(VKI_PAGE_SIZE - 1);
64 fp_max -= sizeof(Addr);
65
66 if (debug)
67 VG_(printf)("n_ips=%d fp_min=%p fp_max_orig=%p, fp_max=%p ip=%p fp=%p\n",
68 n_ips, fp_min, fp_max_orig, fp_max, ip, fp);
69
70 /* Assertion broken before main() is reached in pthreaded programs; the
71 * offending stack traces only have one item. --njn, 2002-aug-16 */
72 /* vg_assert(fp_min <= fp_max);*/
73
74 if (fp_min + 4000000 <= fp_max) {
75 /* If the stack is ridiculously big, don't poke around ... but
76 don't bomb out either. Needed to make John Regehr's
77 user-space threads package work. JRS 20021001 */
78 ips[0] = ip;
79 i = 1;
80 } else {
81 /* Get whatever we safely can ... */
82 ips[0] = ip;
njndb9b7732005-03-26 00:32:29 +000083 fp = VGA_FIRST_STACK_FRAME(fp);
njnd01fef72005-03-25 23:35:48 +000084 for (i = 1; i < n_ips; i++) {
85 if (!(fp_min <= fp && fp <= fp_max)) {
86 if (debug)
87 VG_(printf)("... out of range %p\n", fp);
88 break; /* fp gone baaaad */
89 }
90 // NJN 2002-sep-17: monotonicity doesn't work -- gives wrong traces...
91 // if (fp >= ((UInt*)fp)[0]) {
92 // VG_(printf)("nonmonotonic\n");
93 // break; /* fp gone nonmonotonic */
94 // }
njndb9b7732005-03-26 00:32:29 +000095 ips[i] = VGA_STACK_FRAME_RET(fp); /* ret addr */
96 fp = VGA_STACK_FRAME_NEXT(fp); /* old fp */
njnd01fef72005-03-25 23:35:48 +000097 if (debug)
98 VG_(printf)(" ips[%d]=%08p\n", i, ips[i]);
99 }
100 }
101 n_found = i;
102
103 /* Put zeroes in the rest. */
104 for (; i < n_ips; i++) {
105 ips[i] = 0;
106 }
107 VGP_POPCC(VgpExeContext);
108
109 return n_found;
110}
111
112UInt VG_(get_StackTrace) ( ThreadId tid, StackTrace ips, UInt n_ips )
113{
114 /* thread in thread table */
115 ThreadState* tst = & VG_(threads)[ tid ];
116 Addr ip = INSTR_PTR(tst->arch);
117 Addr fp = FRAME_PTR(tst->arch);
118 Addr sp = STACK_PTR(tst->arch);
njn50ba34e2005-04-04 02:41:42 +0000119 Addr stack_highest_word = tst->client_stack_highest_word;
njnd01fef72005-03-25 23:35:48 +0000120
121#ifdef __x86__
122 /* Nasty little hack to deal with sysinfo syscalls - if libc is
123 using the sysinfo page for syscalls (the TLS version does), then
124 ip will always appear to be in that page when doing a syscall,
125 not the actual libc function doing the syscall. This check sees
126 if IP is within the syscall code, and pops the return address
127 off the stack so that ip is placed within the library function
128 calling the syscall. This makes stack backtraces much more
129 useful. */
130 if (ip >= VG_(client_trampoline_code)+VG_(tramp_syscall_offset) &&
131 ip < VG_(client_trampoline_code)+VG_(trampoline_code_length) &&
132 VG_(is_addressable)(sp, sizeof(Addr), VKI_PROT_READ)) {
133 ip = *(Addr *)sp;
134 sp += sizeof(Addr);
135 }
136#endif
137 if (0)
138 VG_(printf)("tid %d: stack_highest=%p ip=%p sp=%p fp=%p\n",
139 tid, stack_highest_word, ip, sp, fp);
140
141 return VG_(get_StackTrace2)(ips, n_ips, ip, fp, sp, stack_highest_word);
142}
143
144static void printIpDesc(UInt n, Addr ip)
145{
njn47b209a2005-03-25 23:47:16 +0000146 static UChar buf[VG_ERRTXT_LEN];
njnd01fef72005-03-25 23:35:48 +0000147
njn47b209a2005-03-25 23:47:16 +0000148 VG_(describe_IP)(ip, buf, VG_ERRTXT_LEN);
njnd01fef72005-03-25 23:35:48 +0000149 VG_(message)(Vg_UserMsg, " %s %s", ( n == 0 ? "at" : "by" ), buf);
150}
151
152/* Print a StackTrace. */
153void VG_(pp_StackTrace) ( StackTrace ips, UInt n_ips )
154{
155 vg_assert( n_ips > 0 );
156 VG_(apply_StackTrace)( printIpDesc, ips, n_ips );
157}
158
159/* Get and immediately print a StackTrace. */
160void VG_(get_and_pp_StackTrace) ( ThreadId tid, UInt n_ips )
161{
162 Addr ips[n_ips];
163 VG_(get_StackTrace)(tid, ips, n_ips);
164 VG_(pp_StackTrace) ( ips, n_ips);
165}
166
167
168void VG_(apply_StackTrace)( void(*action)(UInt n, Addr ip),
169 StackTrace ips, UInt n_ips )
170{
171 #define MYBUF_LEN 10 // only needs to be long enough for "main"
172
173 Bool main_done = False;
174 Char mybuf[MYBUF_LEN]; // ok to stack allocate mybuf[] -- it's tiny
175 Int i = 0;
176
177 vg_assert(n_ips > 0);
178 do {
179 Addr ip = ips[i];
180 if (i > 0)
njn9fb73db2005-03-27 01:55:21 +0000181 ip -= VGA_MIN_INSTR_SIZE; // point to calling line
njnd01fef72005-03-25 23:35:48 +0000182
183 // Stop after "main"; if main() is recursive, stop after last main().
184 if ( ! VG_(clo_show_below_main)) {
185 VG_(get_fnname_nodemangle)( ip, mybuf, MYBUF_LEN );
186 if ( VG_STREQ("main", mybuf) )
187 main_done = True;
188 else if (main_done)
189 break;
190 }
191
192 // Act on the ip
193 action(i, ip);
194
195 i++;
196 } while (i < n_ips && ips[i] != 0);
197
198 #undef MYBUF_LEN
199}
200
201
202/*--------------------------------------------------------------------*/
203/*--- end ---*/
204/*--------------------------------------------------------------------*/