blob: 5ce393ddf19a5aa744ac33d58b5740b7075fbcbe [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
11 Copyright (C) 2000-2002 Julian Seward
12 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
32#include "vg_include.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. */
66void VG_(init_ExeContext_storage) ( void )
67{
68 Int i;
69 vg_ec_searchreqs = 0;
70 vg_ec_searchcmps = 0;
71 vg_ec_totstored = 0;
72 vg_ec_cmp2s = 0;
73 vg_ec_cmp4s = 0;
74 vg_ec_cmpAlls = 0;
75 for (i = 0; i < VG_N_EC_LISTS; i++)
76 vg_ec_list[i] = NULL;
77}
78
79
80/* Show stats. */
81void VG_(show_ExeContext_stats) ( void )
82{
83 VG_(message)(Vg_DebugMsg,
84 "exectx: %d lists, %d contexts (avg %d per list)",
85 VG_N_EC_LISTS, vg_ec_totstored,
86 vg_ec_totstored / VG_N_EC_LISTS
87 );
88 VG_(message)(Vg_DebugMsg,
89 "exectx: %d searches, %d full compares (%d per 1000)",
90 vg_ec_searchreqs, vg_ec_searchcmps,
91 vg_ec_searchreqs == 0
92 ? 0
93 : (UInt)( (((ULong)vg_ec_searchcmps) * 1000)
94 / ((ULong)vg_ec_searchreqs ))
95 );
96 VG_(message)(Vg_DebugMsg,
97 "exectx: %d cmp2, %d cmp4, %d cmpAll",
98 vg_ec_cmp2s, vg_ec_cmp4s, vg_ec_cmpAlls
99 );
100}
101
102
103/* Print an ExeContext. */
104void VG_(pp_ExeContext) ( ExeContext* e )
105{
106 VG_(mini_stack_dump) ( e );
107}
108
109
110/* Compare two ExeContexts, comparing all callers. */
njn25e49d8e72002-09-23 09:36:25 +0000111Bool VG_(eq_ExeContext) ( VgRes res, ExeContext* e1, ExeContext* e2 )
sewardjde4a1d02002-03-22 01:27:54 +0000112{
njn25e49d8e72002-09-23 09:36:25 +0000113 if (e1 == NULL || e2 == NULL)
114 return False;
115 switch (res) {
116 case Vg_LowRes:
117 /* Just compare the top two callers. */
118 vg_ec_cmp2s++;
119 if (e1->eips[0] != e2->eips[0]
120 || e1->eips[1] != e2->eips[1]) return False;
121 return True;
sewardjde4a1d02002-03-22 01:27:54 +0000122
njn25e49d8e72002-09-23 09:36:25 +0000123 case Vg_MedRes:
124 /* Just compare the top four callers. */
125 vg_ec_cmp4s++;
126 if (e1->eips[0] != e2->eips[0]
127 || e1->eips[1] != e2->eips[1]) return False;
sewardjde4a1d02002-03-22 01:27:54 +0000128
njn25e49d8e72002-09-23 09:36:25 +0000129 if (VG_(clo_backtrace_size) < 3) return True;
130 if (e1->eips[2] != e2->eips[2]) return False;
sewardjde4a1d02002-03-22 01:27:54 +0000131
njn25e49d8e72002-09-23 09:36:25 +0000132 if (VG_(clo_backtrace_size) < 4) return True;
133 if (e1->eips[3] != e2->eips[3]) return False;
134 return True;
sewardjde4a1d02002-03-22 01:27:54 +0000135
njn25e49d8e72002-09-23 09:36:25 +0000136 case Vg_HighRes:
137 vg_ec_cmpAlls++;
138 /* Compare them all -- just do pointer comparison. */
139 if (e1 != e2) return False;
140 return True;
sewardjde4a1d02002-03-22 01:27:54 +0000141
njn25e49d8e72002-09-23 09:36:25 +0000142 default:
njne427a662002-10-02 11:08:25 +0000143 VG_(core_panic)("VG_(eq_ExeContext): unrecognised VgRes");
njn25e49d8e72002-09-23 09:36:25 +0000144 }
sewardjde4a1d02002-03-22 01:27:54 +0000145}
146
147
148/* This guy is the head honcho here. Take a snapshot of the client's
149 stack. Search our collection of ExeContexts to see if we already
150 have it, and if not, allocate a new one. Either way, return a
151 pointer to the context. If there is a matching context we
152 guarantee to not allocate a new one. Thus we never store
153 duplicates, and so exact equality can be quickly done as equality
154 on the returned ExeContext* values themselves. Inspired by Hugs's
155 Text type.
sewardj8c824512002-04-14 04:16:48 +0000156
157 In order to be thread-safe, we pass in the thread's %EIP and %EBP.
sewardjde4a1d02002-03-22 01:27:54 +0000158*/
njn25e49d8e72002-09-23 09:36:25 +0000159ExeContext* VG_(get_ExeContext2) ( Addr eip, Addr ebp,
160 Addr ebp_min, Addr ebp_max_orig )
sewardjde4a1d02002-03-22 01:27:54 +0000161{
162 Int i;
sewardjde4a1d02002-03-22 01:27:54 +0000163 Addr eips[VG_DEEPEST_BACKTRACE];
njn25e49d8e72002-09-23 09:36:25 +0000164 Addr ebp_max;
sewardjde4a1d02002-03-22 01:27:54 +0000165 Bool same;
166 UInt hash;
167 ExeContext* new_ec;
168 ExeContext* list;
169
170 VGP_PUSHCC(VgpExeContext);
171
172 vg_assert(VG_(clo_backtrace_size) >= 2
173 && VG_(clo_backtrace_size) <= VG_DEEPEST_BACKTRACE);
174
175 /* First snaffle %EIPs from the client's stack into eips[0
176 .. VG_(clo_backtrace_size)-1], putting zeroes in when the trail
njn25e49d8e72002-09-23 09:36:25 +0000177 goes cold, which we guess to be when %ebp is not a reasonable
178 stack location. We also assert that %ebp increases down the chain. */
sewardjde4a1d02002-03-22 01:27:54 +0000179
njn25e49d8e72002-09-23 09:36:25 +0000180 // Gives shorter stack trace for tests/badjump.c
181 // JRS 2002-aug-16: I don't think this is a big deal; looks ok for
182 // most "normal" backtraces.
183 // NJN 2002-sep-05: traces for pthreaded programs are particularly bad.
184
185 // JRS 2002-sep-17: hack, to round up ebp_max to the end of the
186 // current page, at least. Dunno if it helps.
187 // NJN 2002-sep-17: seems to -- stack traces look like 1.0.X again
188 ebp_max = (ebp_max_orig + VKI_BYTES_PER_PAGE - 1)
189 & ~(VKI_BYTES_PER_PAGE - 1);
190 ebp_max -= sizeof(Addr);
191
192 /* Assertion broken before main() is reached in pthreaded programs; the
193 * offending stack traces only have one item. --njn, 2002-aug-16 */
194 /* vg_assert(ebp_min <= ebp_max);*/
195
njnac5b0612002-10-02 07:56:02 +0000196 if (ebp_min + 4000000 <= ebp_max) {
sewardjc32b9d62002-10-01 09:02:47 +0000197 /* If the stack is ridiculously big, don't poke around ... but
198 don't bomb out either. Needed to make John Regehr's
199 user-space threads package work. JRS 20021001 */
200 eips[0] = eip;
201 i = 1;
202 } else {
203 /* Get whatever we safely can ... */
204 eips[0] = eip;
205 for (i = 1; i < VG_(clo_backtrace_size); i++) {
206 if (!(ebp_min <= ebp && ebp <= ebp_max)) {
207 //VG_(printf)("... out of range %p\n", ebp);
208 break; /* ebp gone baaaad */
209 }
210 // NJN 2002-sep-17: monotonicity doesn't work -- gives wrong traces...
211 // if (ebp >= ((UInt*)ebp)[0]) {
212 // VG_(printf)("nonmonotonic\n");
213 // break; /* ebp gone nonmonotonic */
214 // }
215 eips[i] = ((UInt*)ebp)[1]; /* ret addr */
216 ebp = ((UInt*)ebp)[0]; /* old ebp */
217 //VG_(printf)(" %p\n", eips[i]);
njn25e49d8e72002-09-23 09:36:25 +0000218 }
njn25e49d8e72002-09-23 09:36:25 +0000219 }
220
221 /* Put zeroes in the rest. */
222 for (; i < VG_(clo_backtrace_size); i++) {
sewardjde4a1d02002-03-22 01:27:54 +0000223 eips[i] = 0;
sewardjde4a1d02002-03-22 01:27:54 +0000224 }
225
sewardjde4a1d02002-03-22 01:27:54 +0000226 /* Now figure out if we've seen this one before. First hash it so
227 as to determine the list number. */
228
229 hash = 0;
230 for (i = 0; i < VG_(clo_backtrace_size); i++) {
231 hash ^= (UInt)eips[i];
232 hash = (hash << 29) | (hash >> 3);
233 }
234 hash = hash % VG_N_EC_LISTS;
235
236 /* And (the expensive bit) look a matching entry in the list. */
237
238 vg_ec_searchreqs++;
239
240 list = vg_ec_list[hash];
241
242 while (True) {
243 if (list == NULL) break;
244 vg_ec_searchcmps++;
245 same = True;
246 for (i = 0; i < VG_(clo_backtrace_size); i++) {
247 if (list->eips[i] != eips[i]) {
248 same = False;
249 break;
250 }
251 }
252 if (same) break;
253 list = list->next;
254 }
255
256 if (list != NULL) {
257 /* Yay! We found it. */
njn25e49d8e72002-09-23 09:36:25 +0000258 VGP_POPCC(VgpExeContext);
sewardjde4a1d02002-03-22 01:27:54 +0000259 return list;
260 }
261
262 /* Bummer. We have to allocate a new context record. */
263 vg_ec_totstored++;
264
njn25e49d8e72002-09-23 09:36:25 +0000265 new_ec = VG_(arena_malloc)( VG_AR_EXECTXT,
266 sizeof(struct _ExeContext *)
267 + VG_(clo_backtrace_size) * sizeof(Addr) );
sewardjde4a1d02002-03-22 01:27:54 +0000268
269 for (i = 0; i < VG_(clo_backtrace_size); i++)
270 new_ec->eips[i] = eips[i];
271
272 new_ec->next = vg_ec_list[hash];
273 vg_ec_list[hash] = new_ec;
274
njn25e49d8e72002-09-23 09:36:25 +0000275 VGP_POPCC(VgpExeContext);
sewardjde4a1d02002-03-22 01:27:54 +0000276 return new_ec;
277}
278
njn25e49d8e72002-09-23 09:36:25 +0000279ExeContext* VG_(get_ExeContext) ( ThreadState *tst )
280{
281 return VG_(get_ExeContext2)( tst->m_eip, tst->m_ebp, tst->m_esp,
282 tst->stack_highest_word );
283}
284
sewardjde4a1d02002-03-22 01:27:54 +0000285
286/*--------------------------------------------------------------------*/
287/*--- end vg_execontext.c ---*/
288/*--------------------------------------------------------------------*/