instrlist_t* instrlist_clone(dcontext_t *dcontext, instrlist_t *old) { instr_t *inst, *copy; instrlist_t *newlist = instrlist_create(dcontext); inst = instrlist_first(old); while (inst != NULL) { copy = instr_clone(dcontext, inst); /* to copy instr targets we temporarily clobber note field */ instr_set_note(inst, (void *)copy); instrlist_append(newlist, copy); inst = instr_get_next(inst); } /* Fix up instr src if it is an instr and restore note field */ /* Note: we do not allows instruction update code cache, * which is very dangerous. * So we do not support instr as dst opnd and won't fix up here if any. */ for (inst = instrlist_first(old), copy = instrlist_first(newlist); inst != NULL && copy != NULL; inst = instr_get_next(inst), copy = instr_get_next(copy)) { int i; for (i = 0; i < inst->num_srcs; i++) { instr_t *tgt; opnd_t op = instr_get_src(copy, i); if (!opnd_is_instr(op)) continue; CLIENT_ASSERT(opnd_get_instr(op) != NULL, "instrlist_clone: NULL instr operand"); tgt = (instr_t *) instr_get_note(opnd_get_instr(op)); CLIENT_ASSERT(tgt != NULL, "instrlist_clone: operand instr not in instrlist"); if (opnd_is_far_instr(op)) { instr_set_src(copy, i, opnd_create_far_instr (opnd_get_segment_selector(op), tgt)); } else instr_set_src(copy, i, opnd_create_instr(tgt)); } } for (inst = instrlist_first(old), copy = instrlist_first(newlist); inst != NULL && copy != NULL; inst = instr_get_next(inst), copy = instr_get_next(copy)) { /* restore note field */ instr_set_note(inst, instr_get_note(copy)); } #ifdef CLIENT_INTERFACE newlist->fall_through_bb = old->fall_through_bb; #endif return newlist; }
/* Insert arithmetic flags restore code with more control. * For x86: * - skip %eax restore if !restore_reg * - restore %eax from reg if reg is not DR_REG_NULL * - restore %eax from slot otherwise * For ARM: * - restores flags from reg * - restores reg to slot, unless !restore_reg. * Routine merge_prev_drx_aflags_switch looks for labels inserted by * drx_restore_arith_flags, so changes to this routine may affect * merge_prev_drx_aflags_switch. */ static void drx_restore_arith_flags(void *drcontext, instrlist_t *ilist, instr_t *where, bool restore_reg, bool restore_oflag, dr_spill_slot_t slot, reg_id_t reg) { instr_t *instr; ilist_insert_note_label(drcontext, ilist, where, NOTE_VAL(DRX_NOTE_AFLAGS_RESTORE_BEGIN)); #ifdef X86 if (restore_oflag) { /* add 0x7f, %al */ instr = INSTR_CREATE_add(drcontext, opnd_create_reg(DR_REG_AL), OPND_CREATE_INT8(0x7f)); MINSERT(ilist, where, instr); } /* sahf */ instr = INSTR_CREATE_sahf(drcontext); instr_set_note(instr, NOTE_VAL(DRX_NOTE_AFLAGS_RESTORE_SAHF)); MINSERT(ilist, where, instr); /* restore eax if necessary */ if (restore_reg) { if (reg != DR_REG_NULL) { ASSERT(reg >= DR_REG_START_GPR && reg <= DR_REG_STOP_GPR && reg != DR_REG_XAX, "wrong dead reg"); MINSERT(ilist, where, INSTR_CREATE_mov_st(drcontext, opnd_create_reg(DR_REG_XAX), opnd_create_reg(reg))); } else { ASSERT(slot >= SPILL_SLOT_1 && slot <= SPILL_SLOT_MAX, "wrong spill slot"); dr_restore_reg(drcontext, ilist, where, DR_REG_XAX, slot); } } #elif defined(ARM) ASSERT(reg >= DR_REG_START_GPR && reg <= DR_REG_STOP_GPR, "reg must be a GPR"); instr = INSTR_CREATE_mrs(drcontext, opnd_create_reg(reg), opnd_create_reg(DR_REG_CPSR)); instr_set_note(instr, NOTE_VAL(DRX_NOTE_AFLAGS_RESTORE_SAHF)); MINSERT(ilist, where, instr); if (restore_reg) { ASSERT(slot >= SPILL_SLOT_1 && slot <= SPILL_SLOT_MAX, "wrong spill slot"); dr_restore_reg(drcontext, ilist, where, reg, slot); } #endif ilist_insert_note_label(drcontext, ilist, where, NOTE_VAL(DRX_NOTE_AFLAGS_RESTORE_END)); }
/* If has_instr_jmp_targets is true, this routine trashes the note field * of each instr_t to store the offset in order to properly encode * the relative pc for an instr_t jump target */ byte * instrlist_encode_to_copy(dcontext_t *dcontext, instrlist_t *ilist, byte *copy_pc, byte *final_pc, byte *max_pc, bool has_instr_jmp_targets) { instr_t *inst; int len = 0; if (has_instr_jmp_targets || max_pc != NULL) { /* must set note fields first with offset, or compute length */ for (inst = instrlist_first(ilist); inst; inst = instr_get_next(inst)) { if (has_instr_jmp_targets) instr_set_note(inst, (void *)(ptr_int_t)len); len += instr_length(dcontext, inst); } } if (max_pc != NULL && (copy_pc + len > max_pc || POINTER_OVERFLOW_ON_ADD(copy_pc, len))) return NULL; for (inst = instrlist_first(ilist); inst != NULL; inst = instr_get_next(inst)) { byte *pc = instr_encode_to_copy(dcontext, inst, copy_pc, final_pc); if (pc == NULL) return NULL; final_pc += pc - copy_pc; copy_pc = pc; } return copy_pc; }
/* insert a label instruction with note */ static void ilist_insert_note_label(void *drcontext, instrlist_t *ilist, instr_t *where, void *note) { instr_t *instr = INSTR_CREATE_label(drcontext); instr_set_note(instr, note); MINSERT(ilist, where, instr); }