DR_EXPORT bool drmgr_insert_read_tls_field(void *drcontext, int idx, instrlist_t *ilist, instr_t *where, reg_id_t reg) { tls_array_t *tls = (tls_array_t *) dr_get_tls_field(drcontext); if (idx < 0 || idx > MAX_NUM_TLS || !tls_taken[idx] || tls == NULL) return false; if (!reg_is_gpr(reg) || !reg_is_pointer_sized(reg)) return false; dr_insert_read_tls_field(drcontext, ilist, where, reg); instrlist_meta_preinsert(ilist, where, INSTR_CREATE_mov_ld (drcontext, opnd_create_reg(reg), OPND_CREATE_MEMPTR(reg, offsetof(tls_array_t, tls) + idx*sizeof(void*)))); return true; }
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) or by doing a liveness analysis on the flags and saving * only if live. */ dr_save_reg(drcontext, bb, where, DR_REG_XAX, SPILL_SLOT_1); dr_save_arith_flags_to_xax(drcontext, bb, where); /* 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 *) dr_get_tls_field(drcontext); /* 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 */ /* We spill xbx to use a scratch register (we could do a liveness * analysis to try and find a dead register to use). Note that xax * is currently holding the saved eflags. */ dr_save_reg(drcontext, bb, where, DR_REG_XBX, SPILL_SLOT_2); dr_insert_read_tls_field(drcontext, bb, where, DR_REG_XBX); instrlist_meta_preinsert(bb, where, INSTR_CREATE_inc(drcontext, OPND_CREATE_MEM32(DR_REG_XBX, offset))); dr_restore_reg(drcontext, bb, where, DR_REG_XBX, SPILL_SLOT_2); } /* Restore flags and xax. */ dr_restore_arith_flags_from_xax(drcontext, bb, where); dr_restore_reg(drcontext, bb, where, DR_REG_XAX, SPILL_SLOT_1); }
/** Adds instrumentation that records fragment execution. */ struct instr_info_t instrument_frag(void* ctx, instrlist_t* frag, frag_id_t id) { const size_t offsetof_current = offsetof(struct trace_buffer_t, current); ptr_int_t frag_id = id; // sign-extended for OPND_CREATE_INT32 #ifdef TRACE_DEBUG app_pc frag_pc; #endif app_pc xl8_pc; instr_t* where; instr_t* before; struct instr_info_t instr_info; instr_t* store; instr_t* first; #ifdef TRACE_DEBUG dr_fprintf(STDERR, "debug: instrument_frag(0x%" PRIxPTR ")\n", frag_id); frag_pc = instr_get_app_pc(instrlist_first(frag)); instrlist_disassemble(ctx, frag_pc, frag, STDERR); #endif where = configure_instr(&instr_info, frag); xl8_pc = instr_get_app_pc(where); before = instr_get_prev(where); #define INSERT(instr) prexl8(frag, where, (instr), xl8_pc) // Add instrumentation. // save tls_reg if(instr_info.restore_tls_reg) { dr_save_reg(ctx, frag, where, instr_info.tls_reg, SPILL_SLOT_2); } // save current_reg if(instr_info.restore_current_reg) { dr_save_reg(ctx, frag, where, instr_info.current_reg, SPILL_SLOT_3); } // tls_reg = tb dr_insert_read_tls_field(ctx, frag, where, instr_info.tls_reg); // current_reg = tb->current INSERT( INSTR_CREATE_mov_ld( ctx, opnd_create_reg(instr_info.current_reg), OPND_CREATE_MEMPTR(instr_info.tls_reg, offsetof_current))); // *current_reg = bb_id store = INSERT( INSTR_CREATE_mov_st( ctx, OPND_CREATE_MEMPTR(instr_info.current_reg, 0), OPND_CREATE_INT32(frag_id))); // current_reg += sizeof(bb_id) INSERT( INSTR_CREATE_lea( ctx, opnd_create_reg(instr_info.current_reg), OPND_CREATE_MEM_lea(instr_info.current_reg, DR_REG_NULL, 0, sizeof(frag_id_t)))); // tb->current = current_reg INSERT( INSTR_CREATE_mov_st( ctx, OPND_CREATE_MEMPTR(instr_info.tls_reg, offsetof_current), opnd_create_reg(instr_info.current_reg))); // restore current_reg if(instr_info.restore_current_reg) { dr_restore_reg(ctx, frag, where, instr_info.current_reg, SPILL_SLOT_3); } // restore tls_reg if(instr_info.restore_tls_reg) { dr_restore_reg(ctx, frag, where, instr_info.tls_reg, SPILL_SLOT_2); } #undef INSERT // Compute instrumentation instructions offsets. if(before) { first = instr_get_next(before); } else { first = instrlist_first(frag); } instr_info.first_offset = get_offset(ctx, instrlist_first(frag), first); instr_info.store_offset = get_offset(ctx, instrlist_first(frag), store); #ifdef TRACE_DUMP_BB instrlist_disassemble(ctx, frag_pc, frag, STDERR); #endif #ifdef TRACE_DEBUG dr_fprintf(STDERR, "debug: instrument_frag() done," " first_offset=0x%" PRIx32 " store_offset=0x%" PRIx32 "\n", instr_info.first_offset, instr_info.store_offset); #endif return instr_info; }