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; }
/* 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; }