blob: 286f946ca9a080da9b6784f977d7a182c80ec398 [file] [log] [blame]
sewardjde4a1d02002-03-22 01:27:54 +00001
2/*--------------------------------------------------------------------*/
3/*--- Storage, and equality on, execution contexts (backtraces). ---*/
4/*--- vg_execontext.c ---*/
5/*--------------------------------------------------------------------*/
6
7/*
njnc9539842002-10-02 13:26:35 +00008 This file is part of Valgrind, an extensible x86 protected-mode
9 emulator for monitoring program execution on x86-Unixes.
sewardjde4a1d02002-03-22 01:27:54 +000010
nethercotebb1c9912004-01-04 16:43:23 +000011 Copyright (C) 2000-2004 Julian Seward
sewardjde4a1d02002-03-22 01:27:54 +000012 jseward@acm.org
sewardjde4a1d02002-03-22 01:27:54 +000013
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 02111-1307, USA.
28
njn25e49d8e72002-09-23 09:36:25 +000029 The GNU General Public License is contained in the file COPYING.
sewardjde4a1d02002-03-22 01:27:54 +000030*/
31
nethercotef1e5e152004-09-01 23:58:16 +000032#include "core.h"
sewardjde4a1d02002-03-22 01:27:54 +000033
34
35/*------------------------------------------------------------*/
36/*--- Low-level ExeContext storage. ---*/
37/*------------------------------------------------------------*/
38
39/* The idea is only to ever store any one context once, so as to save
40 space and make exact comparisons faster. */
41
42static ExeContext* vg_ec_list[VG_N_EC_LISTS];
43
44/* Stats only: the number of times the system was searched to locate a
45 context. */
46static UInt vg_ec_searchreqs;
47
48/* Stats only: the number of full context comparisons done. */
49static UInt vg_ec_searchcmps;
50
51/* Stats only: total number of stored contexts. */
52static UInt vg_ec_totstored;
53
54/* Number of 2, 4 and (fast) full cmps done. */
55static UInt vg_ec_cmp2s;
56static UInt vg_ec_cmp4s;
57static UInt vg_ec_cmpAlls;
58
59
60/*------------------------------------------------------------*/
61/*--- Exported functions. ---*/
62/*------------------------------------------------------------*/
63
64
65/* Initialise this subsystem. */
sewardjc6b0fe52003-07-23 23:01:11 +000066static void init_ExeContext_storage ( void )
sewardjde4a1d02002-03-22 01:27:54 +000067{
68 Int i;
sewardjc6b0fe52003-07-23 23:01:11 +000069 static Bool init_done = False;
70 if (init_done)
71 return;
sewardjde4a1d02002-03-22 01:27:54 +000072 vg_ec_searchreqs = 0;
73 vg_ec_searchcmps = 0;
74 vg_ec_totstored = 0;
75 vg_ec_cmp2s = 0;
76 vg_ec_cmp4s = 0;
77 vg_ec_cmpAlls = 0;
78 for (i = 0; i < VG_N_EC_LISTS; i++)
79 vg_ec_list[i] = NULL;
sewardjc6b0fe52003-07-23 23:01:11 +000080 init_done = True;
sewardjde4a1d02002-03-22 01:27:54 +000081}
82
83
nethercote3a42fb82004-08-03 18:08:50 +000084/* Print stats. */
85void VG_(print_ExeContext_stats) ( void )
sewardjde4a1d02002-03-22 01:27:54 +000086{
sewardjc6b0fe52003-07-23 23:01:11 +000087 init_ExeContext_storage();
sewardjde4a1d02002-03-22 01:27:54 +000088 VG_(message)(Vg_DebugMsg,
89 "exectx: %d lists, %d contexts (avg %d per list)",
90 VG_N_EC_LISTS, vg_ec_totstored,
91 vg_ec_totstored / VG_N_EC_LISTS
92 );
93 VG_(message)(Vg_DebugMsg,
94 "exectx: %d searches, %d full compares (%d per 1000)",
95 vg_ec_searchreqs, vg_ec_searchcmps,
96 vg_ec_searchreqs == 0
97 ? 0
98 : (UInt)( (((ULong)vg_ec_searchcmps) * 1000)
99 / ((ULong)vg_ec_searchreqs ))
100 );
101 VG_(message)(Vg_DebugMsg,
102 "exectx: %d cmp2, %d cmp4, %d cmpAll",
103 vg_ec_cmp2s, vg_ec_cmp4s, vg_ec_cmpAlls
104 );
105}
106
107
108/* Print an ExeContext. */
109void VG_(pp_ExeContext) ( ExeContext* e )
110{
sewardjc6b0fe52003-07-23 23:01:11 +0000111 init_ExeContext_storage();
nethercote86c5dcb2004-09-05 21:32:37 +0000112 VG_(mini_stack_dump) ( e->ips, VG_(clo_backtrace_size) );
sewardjde4a1d02002-03-22 01:27:54 +0000113}
114
115
116/* Compare two ExeContexts, comparing all callers. */
njn25e49d8e72002-09-23 09:36:25 +0000117Bool VG_(eq_ExeContext) ( VgRes res, ExeContext* e1, ExeContext* e2 )
sewardjde4a1d02002-03-22 01:27:54 +0000118{
njn25e49d8e72002-09-23 09:36:25 +0000119 if (e1 == NULL || e2 == NULL)
120 return False;
121 switch (res) {
122 case Vg_LowRes:
123 /* Just compare the top two callers. */
124 vg_ec_cmp2s++;
nethercote86c5dcb2004-09-05 21:32:37 +0000125 if (e1->ips[0] != e2->ips[0]
126 || e1->ips[1] != e2->ips[1]) return False;
njn25e49d8e72002-09-23 09:36:25 +0000127 return True;
sewardjde4a1d02002-03-22 01:27:54 +0000128
njn25e49d8e72002-09-23 09:36:25 +0000129 case Vg_MedRes:
130 /* Just compare the top four callers. */
131 vg_ec_cmp4s++;
nethercote86c5dcb2004-09-05 21:32:37 +0000132 if (e1->ips[0] != e2->ips[0]) return False;
njn6c846552003-09-16 07:41:43 +0000133
134 if (VG_(clo_backtrace_size) < 2) return True;
nethercote86c5dcb2004-09-05 21:32:37 +0000135 if (e1->ips[1] != e2->ips[1]) return False;
sewardjde4a1d02002-03-22 01:27:54 +0000136
njn25e49d8e72002-09-23 09:36:25 +0000137 if (VG_(clo_backtrace_size) < 3) return True;
nethercote86c5dcb2004-09-05 21:32:37 +0000138 if (e1->ips[2] != e2->ips[2]) return False;
sewardjde4a1d02002-03-22 01:27:54 +0000139
njn25e49d8e72002-09-23 09:36:25 +0000140 if (VG_(clo_backtrace_size) < 4) return True;
nethercote86c5dcb2004-09-05 21:32:37 +0000141 if (e1->ips[3] != e2->ips[3]) return False;
njn25e49d8e72002-09-23 09:36:25 +0000142 return True;
sewardjde4a1d02002-03-22 01:27:54 +0000143
njn25e49d8e72002-09-23 09:36:25 +0000144 case Vg_HighRes:
145 vg_ec_cmpAlls++;
146 /* Compare them all -- just do pointer comparison. */
147 if (e1 != e2) return False;
148 return True;
sewardjde4a1d02002-03-22 01:27:54 +0000149
njn25e49d8e72002-09-23 09:36:25 +0000150 default:
njne427a662002-10-02 11:08:25 +0000151 VG_(core_panic)("VG_(eq_ExeContext): unrecognised VgRes");
njn25e49d8e72002-09-23 09:36:25 +0000152 }
sewardjde4a1d02002-03-22 01:27:54 +0000153}
154
155
nethercote86c5dcb2004-09-05 21:32:37 +0000156/* Take a snapshot of the client's stack, putting the up to 'n_ips' IPs
157 into 'ips'. In order to be thread-safe, we pass in the thread's IP
158 and FP. Returns number of IPs put in 'ips'. */
159static UInt stack_snapshot2 ( Addr* ips, UInt n_ips, Addr ip, Addr fp,
160 Addr fp_min, Addr fp_max_orig )
sewardjde4a1d02002-03-22 01:27:54 +0000161{
162 Int i;
nethercote86c5dcb2004-09-05 21:32:37 +0000163 Addr fp_max;
njn6c846552003-09-16 07:41:43 +0000164 UInt n_found = 0;
sewardjde4a1d02002-03-22 01:27:54 +0000165
166 VGP_PUSHCC(VgpExeContext);
167
nethercote86c5dcb2004-09-05 21:32:37 +0000168 /* First snaffle IPs from the client's stack into ips[0 .. n_ips-1],
njn6c846552003-09-16 07:41:43 +0000169 putting zeroes in when the trail goes cold, which we guess to be when
nethercote86c5dcb2004-09-05 21:32:37 +0000170 FP is not a reasonable stack location. We also assert that FP
njn6c846552003-09-16 07:41:43 +0000171 increases down the chain. */
sewardjde4a1d02002-03-22 01:27:54 +0000172
njn25e49d8e72002-09-23 09:36:25 +0000173 // Gives shorter stack trace for tests/badjump.c
174 // JRS 2002-aug-16: I don't think this is a big deal; looks ok for
175 // most "normal" backtraces.
176 // NJN 2002-sep-05: traces for pthreaded programs are particularly bad.
177
nethercote86c5dcb2004-09-05 21:32:37 +0000178 // JRS 2002-sep-17: hack, to round up fp_max to the end of the
njn25e49d8e72002-09-23 09:36:25 +0000179 // current page, at least. Dunno if it helps.
180 // NJN 2002-sep-17: seems to -- stack traces look like 1.0.X again
nethercote73b526f2004-10-31 18:48:21 +0000181 fp_max = (fp_max_orig + VKI_PAGE_SIZE - 1) & ~(VKI_PAGE_SIZE - 1);
nethercote86c5dcb2004-09-05 21:32:37 +0000182 fp_max -= sizeof(Addr);
njn25e49d8e72002-09-23 09:36:25 +0000183
184 /* Assertion broken before main() is reached in pthreaded programs; the
185 * offending stack traces only have one item. --njn, 2002-aug-16 */
nethercote86c5dcb2004-09-05 21:32:37 +0000186 /* vg_assert(fp_min <= fp_max);*/
njn25e49d8e72002-09-23 09:36:25 +0000187
nethercote86c5dcb2004-09-05 21:32:37 +0000188 if (fp_min + 4000000 <= fp_max) {
sewardjc32b9d62002-10-01 09:02:47 +0000189 /* If the stack is ridiculously big, don't poke around ... but
190 don't bomb out either. Needed to make John Regehr's
191 user-space threads package work. JRS 20021001 */
nethercote86c5dcb2004-09-05 21:32:37 +0000192 ips[0] = ip;
sewardjc32b9d62002-10-01 09:02:47 +0000193 i = 1;
194 } else {
195 /* Get whatever we safely can ... */
nethercote86c5dcb2004-09-05 21:32:37 +0000196 ips[0] = ip;
197 fp = FIRST_STACK_FRAME(fp);
198 for (i = 1; i < n_ips; i++) {
199 if (!(fp_min <= fp && fp <= fp_max)) {
200 //VG_(printf)("... out of range %p\n", fp);
201 break; /* fp gone baaaad */
sewardjc32b9d62002-10-01 09:02:47 +0000202 }
203 // NJN 2002-sep-17: monotonicity doesn't work -- gives wrong traces...
nethercote86c5dcb2004-09-05 21:32:37 +0000204 // if (fp >= ((UInt*)fp)[0]) {
sewardjc32b9d62002-10-01 09:02:47 +0000205 // VG_(printf)("nonmonotonic\n");
nethercote86c5dcb2004-09-05 21:32:37 +0000206 // break; /* fp gone nonmonotonic */
sewardjc32b9d62002-10-01 09:02:47 +0000207 // }
nethercote86c5dcb2004-09-05 21:32:37 +0000208 ips[i] = STACK_FRAME_RET(fp); /* ret addr */
209 fp = STACK_FRAME_NEXT(fp); /* old fp */
210 //VG_(printf)(" %p\n", ips[i]);
njn25e49d8e72002-09-23 09:36:25 +0000211 }
njn25e49d8e72002-09-23 09:36:25 +0000212 }
njn6c846552003-09-16 07:41:43 +0000213 n_found = i;
njn25e49d8e72002-09-23 09:36:25 +0000214
215 /* Put zeroes in the rest. */
nethercote86c5dcb2004-09-05 21:32:37 +0000216 for (; i < n_ips; i++) {
217 ips[i] = 0;
sewardjde4a1d02002-03-22 01:27:54 +0000218 }
njn6c846552003-09-16 07:41:43 +0000219 VGP_POPCC(VgpExeContext);
220
221 return n_found;
222}
223
224/* This guy is the head honcho here. Take a snapshot of the client's
225 stack. Search our collection of ExeContexts to see if we already
226 have it, and if not, allocate a new one. Either way, return a
227 pointer to the context. If there is a matching context we
228 guarantee to not allocate a new one. Thus we never store
229 duplicates, and so exact equality can be quickly done as equality
230 on the returned ExeContext* values themselves. Inspired by Hugs's
231 Text type.
232*/
nethercote86c5dcb2004-09-05 21:32:37 +0000233ExeContext* VG_(get_ExeContext2) ( Addr ip, Addr fp,
234 Addr fp_min, Addr fp_max_orig )
njn6c846552003-09-16 07:41:43 +0000235{
236 Int i;
nethercote86c5dcb2004-09-05 21:32:37 +0000237 Addr ips[VG_DEEPEST_BACKTRACE];
njn6c846552003-09-16 07:41:43 +0000238 Bool same;
nethercote50397c22004-11-04 18:03:06 +0000239 UWord hash;
njn6c846552003-09-16 07:41:43 +0000240 ExeContext* new_ec;
241 ExeContext* list;
242
243 VGP_PUSHCC(VgpExeContext);
244
245 init_ExeContext_storage();
246 vg_assert(VG_(clo_backtrace_size) >= 1
247 && VG_(clo_backtrace_size) <= VG_DEEPEST_BACKTRACE);
248
nethercote86c5dcb2004-09-05 21:32:37 +0000249 stack_snapshot2( ips, VG_(clo_backtrace_size),
250 ip, fp, fp_min, fp_max_orig );
sewardjde4a1d02002-03-22 01:27:54 +0000251
sewardjde4a1d02002-03-22 01:27:54 +0000252 /* Now figure out if we've seen this one before. First hash it so
253 as to determine the list number. */
254
255 hash = 0;
256 for (i = 0; i < VG_(clo_backtrace_size); i++) {
nethercote50397c22004-11-04 18:03:06 +0000257 hash ^= ips[i];
sewardjde4a1d02002-03-22 01:27:54 +0000258 hash = (hash << 29) | (hash >> 3);
259 }
260 hash = hash % VG_N_EC_LISTS;
261
262 /* And (the expensive bit) look a matching entry in the list. */
263
264 vg_ec_searchreqs++;
265
266 list = vg_ec_list[hash];
267
268 while (True) {
269 if (list == NULL) break;
270 vg_ec_searchcmps++;
271 same = True;
272 for (i = 0; i < VG_(clo_backtrace_size); i++) {
nethercote86c5dcb2004-09-05 21:32:37 +0000273 if (list->ips[i] != ips[i]) {
sewardjde4a1d02002-03-22 01:27:54 +0000274 same = False;
275 break;
276 }
277 }
278 if (same) break;
279 list = list->next;
280 }
281
282 if (list != NULL) {
283 /* Yay! We found it. */
njn25e49d8e72002-09-23 09:36:25 +0000284 VGP_POPCC(VgpExeContext);
sewardjde4a1d02002-03-22 01:27:54 +0000285 return list;
286 }
287
288 /* Bummer. We have to allocate a new context record. */
289 vg_ec_totstored++;
290
njn25e49d8e72002-09-23 09:36:25 +0000291 new_ec = VG_(arena_malloc)( VG_AR_EXECTXT,
292 sizeof(struct _ExeContext *)
293 + VG_(clo_backtrace_size) * sizeof(Addr) );
sewardjde4a1d02002-03-22 01:27:54 +0000294
295 for (i = 0; i < VG_(clo_backtrace_size); i++)
nethercote86c5dcb2004-09-05 21:32:37 +0000296 new_ec->ips[i] = ips[i];
sewardjde4a1d02002-03-22 01:27:54 +0000297
298 new_ec->next = vg_ec_list[hash];
299 vg_ec_list[hash] = new_ec;
300
njn25e49d8e72002-09-23 09:36:25 +0000301 VGP_POPCC(VgpExeContext);
sewardjde4a1d02002-03-22 01:27:54 +0000302 return new_ec;
303}
304
nethercote86c5dcb2004-09-05 21:32:37 +0000305void get_needed_regs(ThreadId tid, Addr* ip, Addr* fp, Addr* sp,
njn6c846552003-09-16 07:41:43 +0000306 Addr* stack_highest_word)
njn25e49d8e72002-09-23 09:36:25 +0000307{
njn72718642003-07-24 08:45:32 +0000308 if (VG_(is_running_thread)(tid)) {
sewardj499e3de2002-11-13 22:22:25 +0000309 /* thread currently in baseblock */
nethercote86c5dcb2004-09-05 21:32:37 +0000310 *ip = VG_(baseBlock)[VGOFF_INSTR_PTR];
311 *fp = VG_(baseBlock)[VGOFF_FRAME_PTR];
312 *sp = VG_(baseBlock)[VGOFF_STACK_PTR];
njn6c846552003-09-16 07:41:43 +0000313 *stack_highest_word = VG_(threads)[tid].stack_highest_word;
sewardj499e3de2002-11-13 22:22:25 +0000314 } else {
njn72718642003-07-24 08:45:32 +0000315 /* thread in thread table */
316 ThreadState* tst = & VG_(threads)[ tid ];
nethercote86c5dcb2004-09-05 21:32:37 +0000317 *ip = ARCH_INSTR_PTR(tst->arch);
318 *fp = ARCH_FRAME_PTR(tst->arch);
319 *sp = ARCH_STACK_PTR(tst->arch);
njn6c846552003-09-16 07:41:43 +0000320 *stack_highest_word = tst->stack_highest_word;
sewardj499e3de2002-11-13 22:22:25 +0000321 }
fitzhardinge47735af2004-01-21 01:27:27 +0000322
323 /* Nasty little hack to deal with sysinfo syscalls - if libc is
324 using the sysinfo page for syscalls (the TLS version does), then
nethercote86c5dcb2004-09-05 21:32:37 +0000325 ip will always appear to be in that page when doing a syscall,
fitzhardinge47735af2004-01-21 01:27:27 +0000326 not the actual libc function doing the syscall. This check sees
nethercote86c5dcb2004-09-05 21:32:37 +0000327 if IP is within the syscall code, and pops the return address
328 off the stack so that ip is placed within the library function
fitzhardinge47735af2004-01-21 01:27:27 +0000329 calling the syscall. This makes stack backtraces much more
330 useful. */
nethercote86c5dcb2004-09-05 21:32:37 +0000331 if (*ip >= VG_(client_trampoline_code)+VG_(tramp_syscall_offset) &&
332 *ip < VG_(client_trampoline_code)+VG_(trampoline_code_length) &&
333 VG_(is_addressable)(*sp, sizeof(Addr))) {
334 *ip = *(Addr *)*sp;
335 *sp += sizeof(Addr);
fitzhardinge47735af2004-01-21 01:27:27 +0000336 }
njn6c846552003-09-16 07:41:43 +0000337}
338
339ExeContext* VG_(get_ExeContext) ( ThreadId tid )
340{
nethercote86c5dcb2004-09-05 21:32:37 +0000341 Addr ip, fp, sp, stack_highest_word;
njn6c846552003-09-16 07:41:43 +0000342
nethercote86c5dcb2004-09-05 21:32:37 +0000343 get_needed_regs(tid, &ip, &fp, &sp, &stack_highest_word);
344 return VG_(get_ExeContext2)(ip, fp, sp, stack_highest_word);
njn6c846552003-09-16 07:41:43 +0000345}
346
nethercote86c5dcb2004-09-05 21:32:37 +0000347/* Take a snapshot of the client's stack, putting the up to 'n_ips'
348 instruction pointers into 'ips'. In order to be thread-safe, we pass in
349 the thread's IP and FP. Returns number of IPs put in 'ips'. */
350UInt VG_(stack_snapshot) ( ThreadId tid, Addr* ips, UInt n_ips )
njn6c846552003-09-16 07:41:43 +0000351{
nethercote86c5dcb2004-09-05 21:32:37 +0000352 Addr ip, fp, sp, stack_highest_word;
njn6c846552003-09-16 07:41:43 +0000353
nethercote86c5dcb2004-09-05 21:32:37 +0000354 get_needed_regs(tid, &ip, &fp, &sp, &stack_highest_word);
355 return stack_snapshot2(ips, n_ips, ip, fp, sp, stack_highest_word);
njn6c846552003-09-16 07:41:43 +0000356}
357
358
359Addr VG_(get_EIP_from_ExeContext) ( ExeContext* e, UInt n )
360{
361 if (n > VG_(clo_backtrace_size)) return 0;
nethercote86c5dcb2004-09-05 21:32:37 +0000362 return e->ips[n];
njn25e49d8e72002-09-23 09:36:25 +0000363}
364
njn72718642003-07-24 08:45:32 +0000365Addr VG_(get_EIP) ( ThreadId tid )
sewardj499e3de2002-11-13 22:22:25 +0000366{
367 Addr ret;
368
njn72718642003-07-24 08:45:32 +0000369 if (VG_(is_running_thread)(tid))
nethercote86c5dcb2004-09-05 21:32:37 +0000370 ret = VG_(baseBlock)[VGOFF_INSTR_PTR];
sewardj499e3de2002-11-13 22:22:25 +0000371 else
nethercote86c5dcb2004-09-05 21:32:37 +0000372 ret = ARCH_INSTR_PTR(VG_(threads)[ tid ].arch);
sewardj499e3de2002-11-13 22:22:25 +0000373
374 return ret;
375}
sewardjde4a1d02002-03-22 01:27:54 +0000376
377/*--------------------------------------------------------------------*/
nethercote86c5dcb2004-09-05 21:32:37 +0000378/*--- end ---*/
sewardjde4a1d02002-03-22 01:27:54 +0000379/*--------------------------------------------------------------------*/