static void insert_counter_update(void *drcontext, instrlist_t *bb, instr_t *where, int offset) { /* Since the inc instruction clobbers 5 of the arithmetic eflags, * we have to save them around the inc. We could be more efficient * by not bothering to save the overflow flag and constructing our * own sequence of instructions to save the other 5 flags (using * lahf). */ if (drreg_reserve_aflags(drcontext, bb, where) != DRREG_SUCCESS) { DR_ASSERT(false); /* cannot recover */ return; } /* Increment the global counter using the lock prefix to make it atomic * across threads. It would be cheaper to aggregate the thread counters * in the exit events, but this sample is intended to illustrate inserted * instrumentation. */ instrlist_meta_preinsert( bb, where, LOCK(INSTR_CREATE_inc( drcontext, OPND_CREATE_ABSMEM(((byte *)&global_count) + offset, OPSZ_4)))); /* Increment the thread private counter. */ if (dr_using_all_private_caches()) { per_thread_t *data = (per_thread_t *)drmgr_get_tls_field(drcontext, tls_idx); /* private caches - we can use an absolute address */ instrlist_meta_preinsert( bb, where, INSTR_CREATE_inc(drcontext, OPND_CREATE_ABSMEM(((byte *)&data) + offset, OPSZ_4))); } else { /* shared caches - we must indirect via thread local storage */ reg_id_t scratch; if (drreg_reserve_register(drcontext, bb, where, NULL, &scratch) != DRREG_SUCCESS) DR_ASSERT(false); drmgr_insert_read_tls_field(drcontext, tls_idx, bb, where, scratch); instrlist_meta_preinsert( bb, where, INSTR_CREATE_inc(drcontext, OPND_CREATE_MEM32(scratch, offset))); if (drreg_unreserve_register(drcontext, bb, where, scratch) != DRREG_SUCCESS) DR_ASSERT(false); } if (drreg_unreserve_aflags(drcontext, bb, where) != DRREG_SUCCESS) DR_ASSERT(false); /* cannot recover */ }
static dr_emit_flags_t event_app_instruction(void *drcontext, void *tag, instrlist_t *bb, instr_t *inst, bool for_trace, bool translating, void *user_data) { #ifdef SHOW_RESULTS bool aflags_dead; #endif if (!drmgr_is_first_instr(drcontext, inst)) return DR_EMIT_DEFAULT; #ifdef VERBOSE dr_printf("in dynamorio_basic_block(tag="PFX")\n", tag); # ifdef VERBOSE_VERBOSE instrlist_disassemble(drcontext, tag, bb, STDOUT); # endif #endif #ifdef SHOW_RESULTS if (drreg_are_aflags_dead(drcontext, inst, &aflags_dead) == DRREG_SUCCESS && !aflags_dead) bbs_eflags_saved++; else bbs_no_eflags_saved++; #endif /* We demonstrate how to use drreg for aflags save/restore here. * We could use drx_insert_counter_update instead of drreg. * Xref sample opcodes.c as an example of using drx_insert_counter_update. */ if (drreg_reserve_aflags(drcontext, bb, inst) != DRREG_SUCCESS) DR_ASSERT(false && "fail to reserve aflags!"); /* racy update on the counter for better performance */ instrlist_meta_preinsert (bb, inst, INSTR_CREATE_inc(drcontext, OPND_CREATE_ABSMEM ((byte *)&global_count, OPSZ_4))); if (drreg_unreserve_aflags(drcontext, bb, inst) != DRREG_SUCCESS) DR_ASSERT(false && "fail to unreserve aflags!"); #if defined(VERBOSE) && defined(VERBOSE_VERBOSE) dr_printf("Finished instrumenting dynamorio_basic_block(tag="PFX")\n", tag); instrlist_disassemble(drcontext, tag, bb, STDOUT); #endif return DR_EMIT_DEFAULT; }