/* inserts "inst" before "where" ("inst" can be a chain of insts) */ void instrlist_preinsert(instrlist_t *ilist, instr_t *where, instr_t *inst) { instr_t *whereprev; instr_t *top = inst; instr_t *bot; if (where == NULL) { /* if where is NULL there is no inst to send for a "before" */ instrlist_append(ilist, inst); return; } CLIENT_ASSERT(where != NULL, "instrlist_preinsert: where cannot be NULL"); CLIENT_ASSERT(instr_get_prev(inst) == NULL, "instrlist_preinsert: cannot add middle of list"); whereprev = instr_get_prev(where); check_translation(ilist, inst); while (instr_get_next(inst)) { inst = instr_get_next(inst); check_translation(ilist, inst); } bot = inst; if (whereprev) { instr_set_next(whereprev, top); instr_set_prev(top, whereprev); } else { ilist->first = top; } instr_set_next(bot, where); instr_set_prev(where, bot); }
/* Check if current instrumentation can be merged into previous aflags * (or on ARM, GPR) save/restore inserted by drx_restore_arith_flags. * Returns NULL if cannot merge. Otherwise, returns the right insertion point, * i.e., DRX_NOTE_AFLAGS_RESTORE_BEGIN label instr. * * This routine looks for labels inserted by drx_restore_arith_flags, * so changes to drx_restore_arith_flags may affect this routine. * On ARM the labels are from drx_insert_counter_update. */ static instr_t * merge_prev_drx_spill(instr_t *where, bool aflags) { instr_t *instr; #ifdef DEBUG bool has_sahf = false; #endif if (where == NULL) return NULL; instr = instr_get_prev(where); if (instr == NULL) return NULL; if (!instr_is_label(instr)) return NULL; /* Check if prev instr is DRX_NOTE_AFLAGS_RESTORE_END. * We bail even there is only a label instr in between, which * might be a target of internal cti. */ if (instr_get_note(instr) != NOTE_VAL(DRX_NOTE_AFLAGS_RESTORE_END)) return NULL; /* find DRX_NOTE_AFLAGS_RESTORE_BEGIN */ for (instr = instr_get_prev(instr); instr != NULL; instr = instr_get_prev(instr)) { if (instr_is_app(instr)) { /* we do not expect any app instr */ ASSERT(false, "drx aflags restore is corrupted"); return NULL; } if (instr_is_label(instr)) { if (instr_get_note(instr) == NOTE_VAL(DRX_NOTE_AFLAGS_RESTORE_BEGIN)) { ASSERT(!aflags || has_sahf, "missing sahf"); return instr; } /* we do not expect any other label instr */ ASSERT(false, "drx aflags restore is corrupted"); return NULL; #ifdef DEBUG } else { if (instr_get_note(instr) == NOTE_VAL(DRX_NOTE_AFLAGS_RESTORE_SAHF)) has_sahf = true; #endif } } return NULL; }
/* removes "inst" from the instrlist_t it currently belongs to */ void instrlist_remove(instrlist_t *ilist, instr_t *inst) { if (instr_get_prev(inst)) instr_set_next(instr_get_prev(inst), instr_get_next(inst)); else ilist->first = instr_get_next(inst); if (instr_get_next(inst)) instr_set_prev(instr_get_next(inst), instr_get_prev(inst)); else ilist->last = instr_get_prev(inst); instr_set_prev(inst, NULL); instr_set_next(inst, NULL); }
/* inserts "inst" after "where" ("inst" can be a chain of insts) */ void instrlist_postinsert(instrlist_t *ilist, instr_t *where, instr_t *inst) { instr_t *wherenext; instr_t *top = inst; instr_t *bot; if (where == NULL) { /* if where is NULL there is no inst to send for an "after" */ instrlist_prepend(ilist, inst); return; } CLIENT_ASSERT(where != NULL, "instrlist_postinsert: where cannot be NULL"); CLIENT_ASSERT(instr_get_prev(inst) == NULL, "instrlist_postinsert: cannot add middle of list"); wherenext = instr_get_next(where); check_translation(ilist, inst); while (instr_get_next(inst)) { inst = instr_get_next(inst); check_translation(ilist, inst); } bot = inst; instr_set_next(where, top); instr_set_prev(top, where); if (wherenext) { instr_set_next(bot, wherenext); instr_set_prev(wherenext, bot); } else { ilist->last = bot; } }
/* replace oldinst with newinst, remove oldinst from ilist, and return oldinst (newinst can be a chain of insts) */ instr_t * instrlist_replace(instrlist_t *ilist, instr_t *oldinst, instr_t *newinst) { instr_t *where; CLIENT_ASSERT(oldinst != NULL, "instrlist_replace: oldinst cannot be NULL"); CLIENT_ASSERT(instr_get_prev(newinst) == NULL, "instrlist_replace: cannot add middle of list"); where = instr_get_prev(oldinst); instrlist_remove(ilist, oldinst); if (where) instrlist_postinsert(ilist, where, newinst); else instrlist_prepend(ilist, newinst); return oldinst; }
int offline_instru_t::instrument_memref(void *drcontext, instrlist_t *ilist, instr_t *where, reg_id_t reg_ptr, reg_id_t reg_tmp, int adjust, opnd_t ref, bool write, dr_pred_type_t pred) { // Post-processor distinguishes read, write, prefetch, flush, and finds size. instr_t *label = INSTR_CREATE_label(drcontext); MINSERT(ilist, where, label); insert_save_addr(drcontext, ilist, where, reg_ptr, reg_tmp, adjust, ref); #ifdef ARM // X86 does not support general predicated execution if (pred != DR_PRED_NONE) { instr_t *instr; for (instr = instr_get_prev(where); instr != label; instr = instr_get_prev(instr)) { DR_ASSERT(!instr_is_predicated(instr)); instr_set_predicate(instr, pred); } } #endif return (adjust + sizeof(offline_entry_t)); }
void cfi_cleanup_after_native_call(void *drcontext, instrlist_t *ilist, instr_t *where) { instr_t *in = (where == NULL) ? instrlist_last(ilist) : instr_get_prev(where); CFI_ASSERT(drcontext != NULL, "dr_cleanup_after_call: drcontext cannot be NULL"); /* PRE(ilist, where, INSTR_CREATE_pop(drcontext, opnd_create_reg(REG_RDI))); PRE(ilist, where, INSTR_CREATE_pop(drcontext, opnd_create_reg(REG_RSI))); PRE(ilist, where, INSTR_CREATE_pop(drcontext, opnd_create_reg(REG_RBP)));*/ /* skip xsp by popping into dead rbx */ /* PRE(ilist, where, INSTR_CREATE_pop(drcontext, opnd_create_reg(REG_RBX))); PRE(ilist, where, INSTR_CREATE_pop(drcontext, opnd_create_reg(REG_RBX))); PRE(ilist, where, INSTR_CREATE_pop(drcontext, opnd_create_reg(REG_RDX))); PRE(ilist, where, INSTR_CREATE_pop(drcontext, opnd_create_reg(REG_RCX))); PRE(ilist, where, INSTR_CREATE_pop(drcontext, opnd_create_reg(REG_RAX))); PRE(ilist, where, INSTR_CREATE_pop(drcontext, opnd_create_reg(REG_R8))); PRE(ilist, where, INSTR_CREATE_pop(drcontext, opnd_create_reg(REG_R9))); PRE(ilist, where, INSTR_CREATE_pop(drcontext, opnd_create_reg(REG_R10))); PRE(ilist, where, INSTR_CREATE_pop(drcontext, opnd_create_reg(REG_R11))); PRE(ilist, where, INSTR_CREATE_pop(drcontext, opnd_create_reg(REG_R12))); PRE(ilist, where, INSTR_CREATE_pop(drcontext, opnd_create_reg(REG_R13))); PRE(ilist, where, INSTR_CREATE_pop(drcontext, opnd_create_reg(REG_R14))); PRE(ilist, where, INSTR_CREATE_pop(drcontext, opnd_create_reg(REG_R15))); PRE(ilist, where, INSTR_CREATE_lea (drcontext, opnd_create_reg(REG_XSP), OPND_CREATE_MEM_lea(REG_XSP, REG_NULL, 0, XMM_SLOTS_SIZE))); */ PRE(ilist, where, INSTR_CREATE_popf(drcontext)); /* now go through and mark inserted instrs as meta */ if (in == NULL) in = instrlist_first(ilist); else in = instr_get_next(in); while (in != where) { instr_set_ok_to_mangle(in, false); in = instr_get_next(in); } }
void cfi_insert_meta_native_call_vargs(void *dcontext, instrlist_t *bb, instr_t *cursor, bool clean_call, void *callee) { instr_t *in = (cursor == NULL) ? instrlist_last(bb) : instr_get_prev(cursor); // PRE(ilist, instr, INSTR_CREATE_mov_ld(dcontext, opnd_create_reg(REG_RDI), opnd_create_reg(REG_RSP))); PRE(bb, cursor, INSTR_CREATE_call(dcontext, opnd_create_pc(callee))); /* mark it all meta */ if (in == NULL) in = instrlist_first(bb); else in = instr_get_next(in); while (in != cursor) { instr_set_ok_to_mangle(in, false); in = instr_get_next(in); } }
/* prepends inst to the list ("inst" can be a chain of insts) */ void instrlist_prepend(instrlist_t *ilist, instr_t *inst) { instr_t *top = inst; instr_t *bot; CLIENT_ASSERT(instr_get_prev(inst) == NULL, "instrlist_prepend: cannot add middle of list"); check_translation(ilist, inst); while (instr_get_next(inst)) { inst = instr_get_next(inst); check_translation(ilist, inst); } bot = inst; if (ilist->first) { instr_set_next(bot, ilist->first); instr_set_prev(ilist->first, bot); ilist->first = top; } else { ilist->first = top; ilist->last = bot; } }
unsigned int cfi_prepare_for_native_call(void *drcontext, instrlist_t *ilist, instr_t *where) { unsigned int eflags_offs, dstack_offs = 0; instr_t *in = (where == NULL) ? instrlist_last(ilist) : instr_get_prev(where); CFI_ASSERT(drcontext != NULL, "cfi_prepare_for_native_call: drcontext cannot be NULL"); //PRE(ilist, where, INSTR_CREATE_push_imm(dcontext, OPND_CREATE_INT32(0))); //dstack_offs += XSP_SZ; PRE(ilist, where, INSTR_CREATE_pushf(drcontext)); PRE(ilist, where, INSTR_CREATE_push(drcontext, opnd_create_base_disp(REG_XSP, REG_NULL, 0, 0, OPSZ_STACK))); PRE(ilist, where, INSTR_CREATE_and(drcontext, opnd_create_base_disp(REG_XSP, REG_NULL, 0, 0, OPSZ_STACK), OPND_CREATE_INT32(~(EFLAGS_NON_SYSTEM | EFLAGS_IF)))); PRE(ilist, where, INSTR_CREATE_popf(drcontext)); /* dstack_offs += XSP_SZ; eflags_offs = dstack_offs; PRE(ilist, where, INSTR_CREATE_lea(drcontext, opnd_create_reg(REG_XSP), OPND_CREATE_MEM_lea(REG_XSP, REG_NULL, 0, - XMM_SLOTS_SIZE))); PRE(ilist, where, INSTR_CREATE_push(drcontext, opnd_create_reg(REG_R15))); PRE(ilist, where, INSTR_CREATE_push(drcontext, opnd_create_reg(REG_R14))); PRE(ilist, where, INSTR_CREATE_push(drcontext, opnd_create_reg(REG_R13))); PRE(ilist, where, INSTR_CREATE_push(drcontext, opnd_create_reg(REG_R12))); PRE(ilist, where, INSTR_CREATE_push(drcontext, opnd_create_reg(REG_R11))); PRE(ilist, where, INSTR_CREATE_push(drcontext, opnd_create_reg(REG_R10))); PRE(ilist, where, INSTR_CREATE_push(drcontext, opnd_create_reg(REG_R9))); PRE(ilist, where, INSTR_CREATE_push(drcontext, opnd_create_reg(REG_R8))); PRE(ilist, where, INSTR_CREATE_push(drcontext, opnd_create_reg(REG_RAX))); PRE(ilist, where, INSTR_CREATE_push(drcontext, opnd_create_reg(REG_RCX))); PRE(ilist, where, INSTR_CREATE_push(drcontext, opnd_create_reg(REG_RDX))); PRE(ilist, where, INSTR_CREATE_push(drcontext, opnd_create_reg(REG_RBX)));*/ /* we do NOT match pusha xsp value *//* PRE(ilist, where, INSTR_CREATE_push(drcontext, opnd_create_reg(REG_RSP))); PRE(ilist, where, INSTR_CREATE_push(drcontext, opnd_create_reg(REG_RBP))); PRE(ilist, where, INSTR_CREATE_push(drcontext, opnd_create_reg(REG_RSI))); PRE(ilist, where, INSTR_CREATE_push(drcontext, opnd_create_reg(REG_RDI))); dstack_offs += 16*XSP_SZ + XMM_SLOTS_SIZE; PRE(ilist, where, INSTR_CREATE_push(drcontext, opnd_create_base_disp(REG_XSP, REG_NULL, 0, dstack_offs - eflags_offs, OPSZ_STACK))); PRE(ilist, where, INSTR_CREATE_and(drcontext, opnd_create_base_disp(REG_XSP, REG_NULL, 0, 0, OPSZ_STACK), OPND_CREATE_INT32(~(EFLAGS_NON_SYSTEM | EFLAGS_IF)))); PRE(ilist, where, INSTR_CREATE_popf(drcontext));*/ /* now go through and mark inserted instrs as meta */ if (in == NULL) in = instrlist_first(ilist); else in = instr_get_next(in); while (in != where) { instr_set_ok_to_mangle(in, false); in = instr_get_next(in); } return dstack_offs; }
/** 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; }