2 /*--------------------------------------------------------------------*/
3 /*--- Store and compare stack backtraces m_execontext.c ---*/
4 /*--------------------------------------------------------------------*/
7 This file is part of Valgrind, a dynamic binary instrumentation
10 Copyright (C) 2000-2013 Julian Seward
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.
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.
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
28 The GNU General Public License is contained in the file COPYING.
31 #include "pub_core_basics.h"
32 #include "pub_core_debuglog.h"
33 #include "pub_core_libcassert.h"
34 #include "pub_core_libcprint.h" // For VG_(message)()
35 #include "pub_core_mallocfree.h"
36 #include "pub_core_options.h"
37 #include "pub_core_stacktrace.h"
38 #include "pub_core_machine.h" // VG_(get_IP)
39 #include "pub_core_threadstate.h" // VG_(is_valid_tid)
40 #include "pub_core_execontext.h" // self
42 /*------------------------------------------------------------*/
43 /*--- Low-level ExeContext storage. ---*/
44 /*------------------------------------------------------------*/
46 /* Depending on VgRes, the first 2, 4 or all IP values are used in
47 comparisons to remove duplicate errors, and for comparing against
48 suppression specifications. If not used in comparison, the rest
49 are purely informational (but often important).
51 The contexts are stored in a traditional chained hash table, so as
52 to allow quick determination of whether a new context already
53 exists. The hash table starts small and expands dynamically, so as
54 to keep the load factor below 1.0.
56 The idea is only to ever store any one context once, so as to save
57 space and make exact comparisons faster. */
60 /* Primes for the hash table */
62 #define N_EC_PRIMES 18
64 static SizeT ec_primes
[N_EC_PRIMES
] = {
65 769UL, 1543UL, 3079UL, 6151UL,
66 12289UL, 24593UL, 49157UL, 98317UL,
67 196613UL, 393241UL, 786433UL, 1572869UL,
68 3145739UL, 6291469UL, 12582917UL, 25165843UL,
69 50331653UL, 100663319UL
73 /* Each element is present in a hash chain, and also contains a
74 variable length array of guest code addresses (the useful part). */
77 struct _ExeContext
* chain
;
78 /* A 32-bit unsigned integer that uniquely identifies this
79 ExeContext. Memcheck uses these for origin tracking. Values
80 must be nonzero (else Memcheck's origin tracking is hosed), must
81 be a multiple of four, and must be unique. Hence they start at
84 /* Variable-length array. The size is 'n_ips'; at
85 least 1, at most VG_DEEPEST_BACKTRACE. [0] is the current IP,
86 [1] is its caller, [2] is the caller of [1], etc. */
92 /* This is the dynamically expanding hash table. */
93 static ExeContext
** ec_htab
; /* array [ec_htab_size] of ExeContext* */
94 static SizeT ec_htab_size
; /* one of the values in ec_primes */
95 static SizeT ec_htab_size_idx
; /* 0 .. N_EC_PRIMES-1 */
97 /* ECU serial number */
98 static UInt ec_next_ecu
= 4; /* We must never issue zero */
100 static ExeContext
* null_ExeContext
;
102 /* Stats only: the number of times the system was searched to locate a
104 static ULong ec_searchreqs
;
106 /* Stats only: the number of full context comparisons done. */
107 static ULong ec_searchcmps
;
109 /* Stats only: total number of stored contexts. */
110 static ULong ec_totstored
;
112 /* Number of 2, 4 and (fast) full cmps done. */
113 static ULong ec_cmp2s
;
114 static ULong ec_cmp4s
;
115 static ULong ec_cmpAlls
;
118 /*------------------------------------------------------------*/
119 /*--- Exported functions. ---*/
120 /*------------------------------------------------------------*/
122 static ExeContext
* record_ExeContext_wrk2 ( const Addr
* ips
, UInt n_ips
);
124 /* Initialise this subsystem. */
125 static void init_ExeContext_storage ( void )
128 static Bool init_done
= False
;
129 if (LIKELY(init_done
))
138 ec_htab_size_idx
= 0;
139 ec_htab_size
= ec_primes
[ec_htab_size_idx
];
140 ec_htab
= VG_(malloc
)("execontext.iEs1",
141 sizeof(ExeContext
*) * ec_htab_size
);
142 for (i
= 0; i
< ec_htab_size
; i
++)
148 null_ExeContext
= record_ExeContext_wrk2(ips
, 1);
149 // null execontext must be the first one created and get ecu 4.
150 vg_assert(null_ExeContext
->ecu
== 4);
158 void VG_(print_ExeContext_stats
) ( Bool with_stacktraces
)
164 init_ExeContext_storage();
166 if (with_stacktraces
) {
167 VG_(message
)(Vg_DebugMsg
, " exectx: Printing contexts stacktraces\n");
168 for (i
= 0; i
< ec_htab_size
; i
++) {
169 for (ec
= ec_htab
[i
]; ec
; ec
= ec
->chain
) {
170 VG_(message
)(Vg_DebugMsg
, " exectx: stacktrace ecu %u n_ips %u\n",
172 VG_(pp_StackTrace
)( ec
->ips
, ec
->n_ips
);
175 VG_(message
)(Vg_DebugMsg
,
176 " exectx: Printed %'llu contexts stacktraces\n",
181 for (i
= 0; i
< ec_htab_size
; i
++) {
182 for (ec
= ec_htab
[i
]; ec
; ec
= ec
->chain
)
183 total_n_ips
+= ec
->n_ips
;
185 VG_(message
)(Vg_DebugMsg
,
186 " exectx: %'lu lists, %'llu contexts (avg %3.2f per list)"
187 " (avg %3.2f IP per context)\n",
188 ec_htab_size
, ec_totstored
, (Double
)ec_totstored
/ (Double
)ec_htab_size
,
189 (Double
)total_n_ips
/ (Double
)ec_htab_size
191 VG_(message
)(Vg_DebugMsg
,
192 " exectx: %'llu searches, %'llu full compares (%'llu per 1000)\n",
193 ec_searchreqs
, ec_searchcmps
,
196 : ( (ec_searchcmps
* 1000ULL) / ec_searchreqs
)
198 VG_(message
)(Vg_DebugMsg
,
199 " exectx: %'llu cmp2, %'llu cmp4, %'llu cmpAll\n",
200 ec_cmp2s
, ec_cmp4s
, ec_cmpAlls
205 /* Print an ExeContext. */
206 void VG_(pp_ExeContext
) ( ExeContext
* ec
)
208 VG_(pp_StackTrace
)( ec
->ips
, ec
->n_ips
);
212 /* Compare two ExeContexts. Number of callers considered depends on res. */
213 Bool
VG_(eq_ExeContext
) ( VgRes res
, const ExeContext
* e1
,
214 const ExeContext
* e2
)
218 if (e1
== NULL
|| e2
== NULL
)
221 // Must be at least one address in each trace.
222 vg_assert(e1
->n_ips
>= 1 && e2
->n_ips
>= 1);
226 /* Just compare the top two callers. */
228 for (i
= 0; i
< 2; i
++) {
229 if ( (e1
->n_ips
<= i
) && (e2
->n_ips
<= i
)) return True
;
230 if ( (e1
->n_ips
<= i
) && !(e2
->n_ips
<= i
)) return False
;
231 if (!(e1
->n_ips
<= i
) && (e2
->n_ips
<= i
)) return False
;
232 if (e1
->ips
[i
] != e2
->ips
[i
]) return False
;
237 /* Just compare the top four callers. */
239 for (i
= 0; i
< 4; i
++) {
240 if ( (e1
->n_ips
<= i
) && (e2
->n_ips
<= i
)) return True
;
241 if ( (e1
->n_ips
<= i
) && !(e2
->n_ips
<= i
)) return False
;
242 if (!(e1
->n_ips
<= i
) && (e2
->n_ips
<= i
)) return False
;
243 if (e1
->ips
[i
] != e2
->ips
[i
]) return False
;
249 /* Compare them all -- just do pointer comparison. */
250 if (e1
!= e2
) return False
;
254 VG_(core_panic
)("VG_(eq_ExeContext): unrecognised VgRes");
258 /* VG_(record_ExeContext) is the head honcho here. Take a snapshot of
259 the client's stack. Search our collection of ExeContexts to see if
260 we already have it, and if not, allocate a new one. Either way,
261 return a pointer to the context. If there is a matching context we
262 guarantee to not allocate a new one. Thus we never store
263 duplicates, and so exact equality can be quickly done as equality
264 on the returned ExeContext* values themselves. Inspired by Hugs's
267 Also checks whether the hash table needs expanding, and expands it
270 static inline UWord
ROLW ( UWord w
, Int n
)
272 Int bpw
= 8 * sizeof(UWord
);
273 w
= (w
<< n
) | (w
>> (bpw
-n
));
277 static UWord
calc_hash ( const Addr
* ips
, UInt n_ips
, UWord htab_sz
)
281 vg_assert(htab_sz
> 0);
282 for (i
= 0; i
< n_ips
; i
++) {
284 hash
= ROLW(hash
, 19);
286 return hash
% htab_sz
;
289 static void resize_ec_htab ( void )
293 ExeContext
** new_ec_htab
;
295 vg_assert(ec_htab_size_idx
>= 0 && ec_htab_size_idx
< N_EC_PRIMES
);
296 if (ec_htab_size_idx
== N_EC_PRIMES
-1)
297 return; /* out of primes - can't resize further */
299 new_size
= ec_primes
[ec_htab_size_idx
+ 1];
300 new_ec_htab
= VG_(malloc
)("execontext.reh1",
301 sizeof(ExeContext
*) * new_size
);
305 "resizing htab from size %lu to %lu (idx %lu) Total#ECs=%llu\n",
306 ec_htab_size
, new_size
, ec_htab_size_idx
+ 1, ec_totstored
);
308 for (i
= 0; i
< new_size
; i
++)
309 new_ec_htab
[i
] = NULL
;
311 for (i
= 0; i
< ec_htab_size
; i
++) {
312 ExeContext
* cur
= ec_htab
[i
];
314 ExeContext
* next
= cur
->chain
;
315 UWord hash
= calc_hash(cur
->ips
, cur
->n_ips
, new_size
);
316 vg_assert(hash
< new_size
);
317 cur
->chain
= new_ec_htab
[hash
];
318 new_ec_htab
[hash
] = cur
;
324 ec_htab
= new_ec_htab
;
325 ec_htab_size
= new_size
;
329 /* Do the first part of getting a stack trace: actually unwind the
330 stack, and hand the results off to the duplicate-trace-finder
332 static ExeContext
* record_ExeContext_wrk ( ThreadId tid
, Word first_ip_delta
,
335 Addr ips
[VG_(clo_backtrace_size
)];
338 init_ExeContext_storage();
340 vg_assert(sizeof(void*) == sizeof(UWord
));
341 vg_assert(sizeof(void*) == sizeof(Addr
));
343 vg_assert(VG_(is_valid_tid
)(tid
));
347 ips
[0] = VG_(get_IP
)(tid
) + first_ip_delta
;
349 n_ips
= VG_(get_StackTrace
)( tid
, ips
, VG_(clo_backtrace_size
),
350 NULL
/*array to dump SP values in*/,
351 NULL
/*array to dump FP values in*/,
355 return record_ExeContext_wrk2 ( ips
, n_ips
);
358 /* Do the second part of getting a stack trace: ips[0 .. n_ips-1]
359 holds a proposed trace. Find or allocate a suitable ExeContext.
360 Note that callers must have done init_ExeContext_storage() before
361 getting to this point. */
362 static ExeContext
* record_ExeContext_wrk2 ( const Addr
* ips
, UInt n_ips
)
369 ExeContext
*prev2
, *prev
;
373 vg_assert(n_ips
>= 1 && n_ips
<= VG_(clo_backtrace_size
));
375 /* Now figure out if we've seen this one before. First hash it so
376 as to determine the list number. */
377 hash
= calc_hash( ips
, n_ips
, ec_htab_size
);
379 /* And (the expensive bit) look a for matching entry in the list. */
385 list
= ec_htab
[hash
];
388 if (list
== NULL
) break;
390 same
= list
->n_ips
== n_ips
;
391 for (i
= 0; i
< n_ips
&& same
; i
++) {
392 same
= list
->ips
[i
] == ips
[i
];
401 /* Yay! We found it. Once every 8 searches, move it one step
402 closer to the start of the list to make future searches
404 if (0 == ((ctr
++) & 7)) {
405 if (prev2
!= NULL
&& prev
!= NULL
) {
406 /* Found at 3rd or later position in the chain. */
407 vg_assert(prev2
->chain
== prev
);
408 vg_assert(prev
->chain
== list
);
410 prev
->chain
= list
->chain
;
413 else if (prev2
== NULL
&& prev
!= NULL
) {
414 /* Found at 2nd position in the chain. */
415 vg_assert(ec_htab
[hash
] == prev
);
416 vg_assert(prev
->chain
== list
);
417 prev
->chain
= list
->chain
;
419 ec_htab
[hash
] = list
;
425 /* Bummer. We have to allocate a new context record. */
428 new_ec
= VG_(perm_malloc
)( sizeof(struct _ExeContext
)
429 + n_ips
* sizeof(Addr
),
430 vg_alignof(struct _ExeContext
));
432 for (i
= 0; i
< n_ips
; i
++)
433 new_ec
->ips
[i
] = ips
[i
];
435 vg_assert(VG_(is_plausible_ECU
)(ec_next_ecu
));
436 new_ec
->ecu
= ec_next_ecu
;
438 if (ec_next_ecu
== 0) {
439 /* Urr. Now we're hosed; we emitted 2^30 ExeContexts already
440 and have run out of numbers. Not sure what to do. */
441 VG_(core_panic
)("m_execontext: more than 2^30 ExeContexts created");
444 new_ec
->n_ips
= n_ips
;
445 new_ec
->chain
= ec_htab
[hash
];
446 ec_htab
[hash
] = new_ec
;
448 /* Resize the hash table, maybe? */
449 if ( ((ULong
)ec_totstored
) > ((ULong
)ec_htab_size
) ) {
450 vg_assert(ec_htab_size_idx
>= 0 && ec_htab_size_idx
< N_EC_PRIMES
);
451 if (ec_htab_size_idx
< N_EC_PRIMES
-1)
458 ExeContext
* VG_(record_ExeContext
)( ThreadId tid
, Word first_ip_delta
) {
459 return record_ExeContext_wrk( tid
, first_ip_delta
,
460 False
/*!first_ip_only*/ );
463 ExeContext
* VG_(record_depth_1_ExeContext
)( ThreadId tid
, Word first_ip_delta
)
465 return record_ExeContext_wrk( tid
, first_ip_delta
,
466 True
/*first_ip_only*/ );
469 ExeContext
* VG_(make_depth_1_ExeContext_from_Addr
)( Addr a
) {
470 init_ExeContext_storage();
471 return record_ExeContext_wrk2( &a
, 1 );
474 StackTrace
VG_(get_ExeContext_StackTrace
) ( ExeContext
* e
) {
478 UInt
VG_(get_ECU_from_ExeContext
)( const ExeContext
* e
) {
479 vg_assert(VG_(is_plausible_ECU
)(e
->ecu
));
483 Int
VG_(get_ExeContext_n_ips
)( const ExeContext
* e
) {
484 vg_assert(e
->n_ips
>= 1);
488 ExeContext
* VG_(get_ExeContext_from_ECU
)( UInt ecu
)
492 vg_assert(VG_(is_plausible_ECU
)(ecu
));
493 vg_assert(ec_htab_size
> 0);
494 for (i
= 0; i
< ec_htab_size
; i
++) {
495 for (ec
= ec_htab
[i
]; ec
; ec
= ec
->chain
) {
503 ExeContext
* VG_(make_ExeContext_from_StackTrace
)( const Addr
* ips
, UInt n_ips
)
505 init_ExeContext_storage();
506 return record_ExeContext_wrk2(ips
, n_ips
);
509 ExeContext
* VG_(null_ExeContext
) (void)
511 init_ExeContext_storage();
512 return null_ExeContext
;
515 /*--------------------------------------------------------------------*/
516 /*--- end m_execontext.c ---*/
517 /*--------------------------------------------------------------------*/