From: Nicholas Nethercote Date: Wed, 21 Jan 2004 16:12:55 +0000 (+0000) Subject: Fix a bug in Cachegrind: when invalidating BBs, the lookup in the BBCC_table X-Git-Tag: svn/VALGRIND_2_1_1~90 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=32b992d36a5067934e167cb5dc3455b42fc5ec7a;p=thirdparty%2Fvalgrind.git Fix a bug in Cachegrind: when invalidating BBs, the lookup in the BBCC_table sometimes failed, causing an assertion failure. This is because the debug info for the code address, which is used in the lookup, can change -- eg. "myprint.c:myprint()" is found at instrumentation, but by the time the invalidation occurs, it's changed to "myprint.c:???". So it now falls back to a slow exhaustive search of the table. This was causing cachegrind/tests/dlclose to fail, and should hopefully fix bug #72781. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@2218 --- diff --git a/cachegrind/cg_main.c b/cachegrind/cg_main.c index 54850a957f..2f83e76f67 100644 --- a/cachegrind/cg_main.c +++ b/cachegrind/cg_main.c @@ -399,6 +399,63 @@ static UInt hash(Char *s, UInt table_size) return hash_value; } +/* This is a backup for get_BBCC() when removing BBs from the table. + * Necessary because the debug info can change when code is removed. For + * example, when inserting, the info might be "myprint.c:myprint()", but + * upon removal, the info might be "myprint.c:???", which causes the + * hash-lookup to fail (but it doesn't always happen). So we do a horrible, + * slow search through all the file nodes and function nodes (but we can do + * 3rd stage with the fast hash-lookup). */ +static BBCC* get_BBCC_slow_removal(Addr bb_orig_addr) +{ + Int i, j; + UInt BBCC_hash; + file_node *curr_file_node; + fn_node *curr_fn_node; + BBCC **prev_BBCC_next_ptr, *curr_BBCC; + + for (i = 0; i < N_FILE_ENTRIES; i++) { + + for (curr_file_node = BBCC_table[i]; + NULL != curr_file_node; + curr_file_node = curr_file_node->next) + { + for (j = 0; j < N_FN_ENTRIES; j++) { + + for (curr_fn_node = curr_file_node->fns[j]; + NULL != curr_fn_node; + curr_fn_node = curr_fn_node->next) + { + BBCC_hash = bb_orig_addr % N_BBCC_ENTRIES; + prev_BBCC_next_ptr = &(curr_fn_node->BBCCs[BBCC_hash]); + curr_BBCC = curr_fn_node->BBCCs[BBCC_hash]; + + while (NULL != curr_BBCC) { + if (bb_orig_addr == curr_BBCC->orig_addr) { + // Found it! + sk_assert(curr_BBCC->array_size > 0 + && curr_BBCC->array_size < 1000000); + if (VG_(clo_verbosity) > 2) { + VG_(message)(Vg_DebugMsg, "did slow BB removal"); + } + + // Remove curr_BBCC from chain; it will be used and + // free'd by the caller. + *prev_BBCC_next_ptr = curr_BBCC->next; + return curr_BBCC; + } + + prev_BBCC_next_ptr = &(curr_BBCC->next); + curr_BBCC = curr_BBCC->next; + } + } + } + } + } + VG_(printf)("failing BB address: %p\n", bb_orig_addr); + VG_(skin_panic)("slow BB removal failed"); +} + /* Do a three step traversal: by filename, then fn_name, then instr_addr. * In all cases prepends new nodes to their chain. Returns a pointer to the * cost centre. Also sets BB_seen_before by reference. @@ -449,18 +506,23 @@ static BBCC* get_BBCC(Addr bb_orig_addr, UCodeBlock* cb, } if (curr_BBCC == NULL) { - sk_assert(False == remove); - - curr_fn_node->BBCCs[BBCC_hash] = curr_BBCC = - new_BBCC(bb_orig_addr, cb, curr_fn_node->BBCCs[BBCC_hash]); - *BB_seen_before = False; + if (remove == False) { + curr_fn_node->BBCCs[BBCC_hash] = curr_BBCC = + new_BBCC(bb_orig_addr, cb, curr_fn_node->BBCCs[BBCC_hash]); + *BB_seen_before = False; + } else { + // Ok, BB not found when removing: the debug info must have + // changed. Do a slow removal. + curr_BBCC = get_BBCC_slow_removal(bb_orig_addr); + *BB_seen_before = True; + } } else { sk_assert(bb_orig_addr == curr_BBCC->orig_addr); sk_assert(curr_BBCC->array_size > 0 && curr_BBCC->array_size < 1000000); if (VG_(clo_verbosity) > 2) { VG_(message)(Vg_DebugMsg, - "BB retranslation, retrieving from BBCC table"); + "BB retranslation/invalidation, retrieving from BBCC table"); } *BB_seen_before = True;