diff --git a/api/docs/release.dox b/api/docs/release.dox index a0edc75a787..76378c8c9b4 100644 --- a/api/docs/release.dox +++ b/api/docs/release.dox @@ -255,6 +255,7 @@ Further non-compatibility-affecting changes include: - Added instr_is_sse() and instr_is_sse2(). - Added instr_is_3DNow(), instr_is_sse3(), and instr_is_ssse3(). - Added instr_is_sse41(), instr_is_sse42(), and instr_is_sse4A(). + - Added instr_is_reg_spill_or_restore(). **************************************************
diff --git a/core/arch/arm/mangle.c b/core/arch/arm/mangle.c index 29178aa3a80..805f90fe54f 100644 --- a/core/arch/arm/mangle.c +++ b/core/arch/arm/mangle.c @@ -438,7 +438,7 @@ find_prior_scratch_reg_restore(dcontext_t *dcontext, instr_t *instr, reg_id_t *p instr_is_label(prev) && instr_is_our_mangling(prev)) prev = instr_get_prev(prev); if (prev != NULL && - instr_is_reg_spill_or_restore(dcontext, prev, &tls, &spill, prior_reg)) { + instr_is_DR_reg_spill_or_restore(dcontext, prev, &tls, &spill, prior_reg)) { if (tls && !spill && *prior_reg >= SCRATCH_REG0 && *prior_reg <= SCRATCH_REG3) return prev; @@ -461,8 +461,8 @@ insert_save_to_tls_if_necessary(dcontext_t *dcontext, instrlist_t *ilist, STATS_INC(non_mbr_spills); prev = find_prior_scratch_reg_restore(dcontext, where, &prior_reg); if (INTERNAL_OPTION(opt_mangle) > 0 && prev != NULL && prior_reg == reg) { - ASSERT(instr_is_reg_spill_or_restore(dcontext, prev, &tls, - &spill, &prior_reg) && + ASSERT(instr_is_DR_reg_spill_or_restore(dcontext, prev, &tls, + &spill, &prior_reg) && tls && !spill && prior_reg == reg); /* remove the redundant restore-spill pair */ instrlist_remove(ilist, prev); @@ -710,7 +710,7 @@ mangle_syscall_arch(dcontext_t *dcontext, instrlist_t *ilist, uint flags, * For now we assume that the kernel honors the calling convention * and won't clobber callee-saved regs. */ - /* The instructions inserted here are checked in instr_is_reg_spill_or_restore + /* The instructions inserted here are checked in instr_is_DR_reg_spill_or_restore * and translate_walk_restore, so any update here must be sync-ed there too. */ if (dr_reg_stolen != DR_REG_R10 && dr_reg_stolen != DR_REG_R11) { @@ -809,7 +809,7 @@ mangle_add_predicated_fall_through(dcontext_t *dcontext, instrlist_t *ilist, instr_t *prev = instr_get_next(mangle_start); for (; prev != next_instr; prev = instr_get_next(prev)) { if (instr_is_app(prev) || - !instr_is_reg_spill_or_restore(dcontext, prev, NULL, NULL, NULL)) + !instr_is_DR_reg_spill_or_restore(dcontext, prev, NULL, NULL, NULL)) instr_set_predicate(prev, pred); } } diff --git a/core/arch/instr.h b/core/arch/instr.h index e5e10a25986..e5acaae78ed 100644 --- a/core/arch/instr.h +++ b/core/arch/instr.h @@ -2691,9 +2691,26 @@ bool instr_is_tls_xcx_spill(instr_t *instr); /* Pass REG_NULL to not care about the reg */ bool instr_is_tls_restore(instr_t *instr, reg_id_t reg, ushort offs); + +DR_API +/** + * Returns whether \p instr is a register spill or restore, whether it was + * created by dr_save_reg(), dr_restore_reg(), dr_insert_read_raw_tls(), + * dr_insert_write_raw_tls(), routines that call the aforementioned routines + * (e.g., dr_save_arith_flags()), or DR's own internal spills and restores. + * Returns information about the spill/restore in the OUT parameters. + * The returned \p offs is the raw offset in bytes from the TLS segment base, + * the stolen register base, or the thread-private context area. + */ bool -instr_is_reg_spill_or_restore(dcontext_t *dcontext, instr_t *instr, - bool *tls, bool *spill, reg_id_t *reg); +instr_is_reg_spill_or_restore(void *drcontext, instr_t *instr, + bool *tls OUT, bool *spill OUT, reg_id_t *reg OUT, + uint *offs OUT); + +bool +instr_is_DR_reg_spill_or_restore(void *drcontext, instr_t *instr, + bool *tls OUT, bool *spill OUT, reg_id_t *reg OUT); + #ifdef ARM bool instr_reads_thread_register(instr_t *instr); bool instr_is_stolen_reg_move(instr_t *instr, bool *save, reg_id_t *reg); diff --git a/core/arch/instr_shared.c b/core/arch/instr_shared.c index a3565e1a429..fbf0937dcb7 100644 --- a/core/arch/instr_shared.c +++ b/core/arch/instr_shared.c @@ -3240,20 +3240,24 @@ instr_check_mcontext_spill_restore(dcontext_t *dcontext, instr_t *instr, #endif } -bool -instr_is_reg_spill_or_restore(dcontext_t *dcontext, instr_t *instr, - bool *tls, bool *spill, reg_id_t *reg) +static bool +instr_is_reg_spill_or_restore_ex(void *drcontext, instr_t *instr, bool DR_only, + bool *tls, bool *spill, reg_id_t *reg, uint *offs_out) { + dcontext_t *dcontext = (dcontext_t *) drcontext; int check_disp = 0; /* init to satisfy some compilers */ reg_id_t myreg; - CLIENT_ASSERT(instr != NULL, "internal error: NULL argument"); + CLIENT_ASSERT(instr != NULL, "invalid NULL argument"); if (reg == NULL) reg = &myreg; if (instr_check_tls_spill_restore(instr, spill, reg, &check_disp)) { int offs = reg_spill_tls_offs(*reg); - if (offs != -1 && check_disp == os_tls_offset((ushort)offs)) { + if (!DR_only || + (offs != -1 && check_disp == os_tls_offset((ushort)offs))) { if (tls != NULL) *tls = true; + if (offs_out != NULL) + *offs_out = check_disp; return true; } #ifdef ARM @@ -3271,6 +3275,8 @@ instr_is_reg_spill_or_restore(dcontext_t *dcontext, instr_t *instr, }); if (tls != NULL) *tls = true; + if (offs_out != NULL) + *offs_out = check_disp; return true; } #endif @@ -3279,15 +3285,35 @@ instr_is_reg_spill_or_restore(dcontext_t *dcontext, instr_t *instr, instr_check_mcontext_spill_restore(dcontext, instr, spill, reg, &check_disp)) { int offs = opnd_get_reg_dcontext_offs(dr_reg_fixer[*reg]); - if (offs != -1 && check_disp == offs) { + if (!DR_only || + (offs != -1 && check_disp == offs)) { if (tls != NULL) *tls = false; + if (offs_out != NULL) + *offs_out = check_disp; return true; } } return false; } +DR_API +bool +instr_is_reg_spill_or_restore(void *drcontext, instr_t *instr, + bool *tls, bool *spill, reg_id_t *reg, uint *offs) +{ + return instr_is_reg_spill_or_restore_ex(drcontext, instr, false, + tls, spill, reg, offs); +} + +bool +instr_is_DR_reg_spill_or_restore(void *drcontext, instr_t *instr, + bool *tls, bool *spill, reg_id_t *reg) +{ + return instr_is_reg_spill_or_restore_ex(drcontext, instr, true, + tls, spill, reg, NULL); +} + /* N.B. : client meta routines (dr_insert_* etc.) should never use anything other * then TLS_XAX_SLOT unless the client has specified a slot to use as we let the * client use the rest. */ diff --git a/core/translate.c b/core/translate.c index 3913a3dcfc1..0baeb71fa34 100644 --- a/core/translate.c +++ b/core/translate.c @@ -257,7 +257,7 @@ translate_walk_track(dcontext_t *tdcontext, instr_t *inst, translate_walk_t *wal for (r = 0; r < REG_SPILL_NUM; r++) walk->reg_spilled[r] = false; } - if (instr_is_reg_spill_or_restore(tdcontext, inst, &spill_tls, &spill, ®)) { + if (instr_is_DR_reg_spill_or_restore(tdcontext, inst, &spill_tls, &spill, ®)) { r = reg - REG_START_SPILL; ASSERT(r < REG_SPILL_NUM); IF_ARM({ @@ -1637,7 +1637,7 @@ stress_test_recreate_state(dcontext_t *dcontext, fragment_t *f, instrlist_t *ili */ ASSERT(success_so_far /* ok to fail */ || (!res && - (instr_is_reg_spill_or_restore(dcontext, in, NULL, NULL, NULL) || + (instr_is_DR_reg_spill_or_restore(dcontext, in, NULL, NULL, NULL) || (!instr_reads_memory(in) && !instr_writes_memory(in))))); /* check that xsp and xcx are adjusted properly */ @@ -1651,7 +1651,7 @@ stress_test_recreate_state(dcontext_t *dcontext, fragment_t *f, instrlist_t *ili instr_check_xsp_mangling(dcontext, in, &xsp_adjust); if (xsp_adjust != 0) LOG(THREAD, LOG_INTERP, 3, " xsp_adjust=%d\n", xsp_adjust); - if (instr_is_reg_spill_or_restore(dcontext, in, NULL, &spill, ®) && + if (instr_is_DR_reg_spill_or_restore(dcontext, in, NULL, &spill, ®) && reg == REG_XCX) spill_xcx_outstanding = spill; }