thank you very much for your answer!
I had already removed my question because I found out that if I dump coverage through an DR annotation, the application will wait until the DR annotation handler (where I dump the coverage) is executed. Therefore, I would assume that no further synchronization is required.
However, surprisingly, I'm facing several issues with my DR instrumentation. I've tried 3 different approaches for the instrumentation, but all of them either crash the client, do not work with the -debug DR option, or are incorrectly incrementing the BB hit counts for each module.
I've attached an excerpt from my instrumentation; I've added comments to the 3 instrumentation approaches. I would greatly appreciate, if you could briefly have a look at it and let me know what it is that I'm doing wrong here. I took all of my code from the many DR samples and from drcov(lib).
Another problem I face is with attaching the DR client to a running process (i.e., a JVM). Here, I seem to run into a deadlock when the JVM process attempts to exit (both, client and JVM are stuck then). Do you have any idea, what could be the problem? I tried using nudges similarly as in drcovlib which didn't help either.
Thanks in advance!
Daniel
------------------------------------------------------------
// Data structure
typedef struct _covered_bb_t {
uint start_offset; /* Offset to the parent module's start address. */
uint hit_count;
} covered_bb_t;
typedef struct _module_entry_t {
uint id;
module_data_t* data;
drvector_t covered_blocks;
} module_entry_t;
// Clean call
static void
clean_call(uint* ptr)
{
*ptr += 1;
}
// Instrumentation handler
static dr_emit_flags_t
event_bb_instrumentation(void* drcontext, void* tag, instrlist_t* bb, instr_t* instr, bool for_trace, bool translating, void* user_data)
{
if (!instr_is_app(instr))
return DR_EMIT_DEFAULT;
if (!drmgr_is_first_instr(drcontext, instr))
return DR_EMIT_DEFAULT;
app_pc start_pc;
start_pc = dr_fragment_app_pc(tag);
module_entry_t* mod_entry;
mod_entry = module_table_lookup(module_table, start_pc);
if (mod_entry == NULL || mod_entry->data == NULL) return DR_EMIT_DEFAULT;
uint start_offset = start_pc - mod_entry->data->start;
covered_bb_t* entry;
int i;
drvector_lock(&mod_entry->covered_blocks);
for (i = mod_entry->covered_blocks.entries - 1; i >= 0; i--) {
entry = drvector_get_entry(&mod_entry->covered_blocks, i);
ASSERT(entry != NULL, "failed to get BB entry");
if (entry->start_offset == start_offset) {
break;
}
entry = NULL;
}
if (entry == NULL) {
entry = dr_global_alloc(sizeof(*entry));
entry->hit_count = 0; // init to zero here
entry->start_offset = start_offset;
drvector_append(&mod_entry->covered_blocks, entry);
}
drvector_unlock(&mod_entry->covered_blocks);
/* Option 1: Clean call (supposedly slow and raises exception with -debug). Will also only increment counters for the last loaded module (?). */
// dr_insert_clean_call(drcontext, bb, instr, (void*)clean_call, false, 1, OPND_CREATE_INTPTR(&(entry->hit_count)));
/* Option 2: Insert meta instruction for increment (raises exception with -debug). */
// drreg_reserve_aflags(drcontext, bb, instr);
// instrlist_meta_preinsert(bb, instr, INSTR_CREATE_inc(drcontext, OPND_CREATE_ABSMEM(&(entry->hit_count), OPSZ_4)));
// drreg_unreserve_aflags(drcontext, bb, instr);
/* Option 3: Supposedly fast counter update (raises exceptions and crashes client). */
// drx_insert_counter_update(drcontext, bb, instr, SPILL_SLOT_MAX + 1, IF_AARCHXX_(SPILL_SLOT_MAX + 1) & (entry->hit_count), 1, 0);
return DR_EMIT_DEFAULT;
}
// DR Setup
drmgr_register_bb_instrumentation_event(NULL, event_bb_instrumentation, NULL)
// If Option 2: Init drreg
drreg_options_t ops = { sizeof(ops), 1, false };
drreg_init(&ops);