blob: 8dd606ec609fb73d80574a7e1fd9da323ba3acb7 [file] [log] [blame]
/* **********************************************************
* Copyright (c) 2010-2022 Google, Inc. All rights reserved.
* Copyright (c) 2002-2010 VMware, Inc. All rights reserved.
* **********************************************************/
/*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of VMware, Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
#ifndef _DR_IR_UTILS_H_
#define _DR_IR_UTILS_H_ 1
/**************************************************
* CODE TRANSFORMATION UTILITIES
*/
/**
* @file dr_ir_utils.h
* @brief Code transformation utilities.
*/
/**
* An enum of spill slots to use with dr_save_reg(), dr_restore_reg(),
* dr_save_arith_flags(), dr_restore_arith_flags() and
* dr_insert_mbr_instrumentation(). Values stored in spill slots remain
* valid only until the next non-meta (i.e. application) instruction. Spill slots
* can be accessed/modifed during clean calls and restore_state_events (see
* dr_register_restore_state_event()) with dr_read_saved_reg() and
* dr_write_saved_reg().
*
* Spill slots <= dr_max_opnd_accessible_spill_slot() can be directly accessed
* from client inserted instructions with dr_reg_spill_slot_opnd().
*
* \note Some spill slots may be faster to access than others. Currently spill
* slots 1-3 are significantly faster to access than the others when running
* without -thread_private. When running with -thread_private all spill slots
* are expected to have similar performance. This is subject to change in future
* releases, but clients may assume that smaller numbered spill slots are faster
* or the same cost to access as larger numbered spill slots.
*
* \note The number of spill slots may change in future releases.
*/
typedef enum {
SPILL_SLOT_1 = 0, /** spill slot for register save/restore routines */
SPILL_SLOT_2 = 1, /** spill slot for register save/restore routines */
SPILL_SLOT_3 = 2, /** spill slot for register save/restore routines */
SPILL_SLOT_4 = 3, /** spill slot for register save/restore routines */
SPILL_SLOT_5 = 4, /** spill slot for register save/restore routines */
SPILL_SLOT_6 = 5, /** spill slot for register save/restore routines */
SPILL_SLOT_7 = 6, /** spill slot for register save/restore routines */
SPILL_SLOT_8 = 7, /** spill slot for register save/restore routines */
SPILL_SLOT_9 = 8, /** spill slot for register save/restore routines */
#ifdef X64
SPILL_SLOT_10 = 9, /** spill slot for register save/restore routines
* \note x64 only */
SPILL_SLOT_11 = 10, /** spill slot for register save/restore routines
* \note x64 only */
SPILL_SLOT_12 = 11, /** spill slot for register save/restore routines
* \note x64 only */
SPILL_SLOT_13 = 12, /** spill slot for register save/restore routines
* \note x64 only */
SPILL_SLOT_14 = 13, /** spill slot for register save/restore routines
* \note x64 only */
SPILL_SLOT_15 = 14, /** spill slot for register save/restore routines
* \note x64 only */
SPILL_SLOT_16 = 15, /** spill slot for register save/restore routines
* \note x64 only */
SPILL_SLOT_17 = 16, /** spill slot for register save/restore routines
* \note x64 only */
SPILL_SLOT_MAX = SPILL_SLOT_17 /** Enum value of the last register save/restore
* spill slot. */
#else
SPILL_SLOT_MAX = SPILL_SLOT_9 /** Enum value of the last register save/restore
* spill slot. */
#endif
} dr_spill_slot_t;
DR_API
/**
* Inserts into \p ilist prior to \p where meta-instruction(s) to save the
* register \p reg in the spill slot \p slot. See dr_restore_reg(). Use
* dr_read_saved_reg() and dr_write_saved_reg() to access spill slots from clean
* calls and restore_state_events (see dr_register_restore_state_event()).
* \note The stored value remains available only until the next non-meta (i.e.
* application) instruction. Use dr_insert_write_tls_field() and
* dr_insert_read_tls_field() for a persistent (but more costly to access)
* thread-local-storage location. See also dr_raw_tls_calloc().
*
* Generally, using the \ref page_drreg Extension Library instead is recommended.
* When using custom spills and restores, be sure to look for the labels
* #DR_NOTE_ANNOTATION and #DR_NOTE_REG_BARRIER at which all application values
* should be restored to registers.
*/
void
dr_save_reg(void *drcontext, instrlist_t *ilist, instr_t *where, reg_id_t reg,
dr_spill_slot_t slot);
DR_API
/**
* Inserts into \p ilist prior to \p where meta-instruction(s) to restore the
* register \p reg from the spill slot \p slot. See dr_save_reg() for notes on
* lifetime and alternative access to spill slots.
*/
void
dr_restore_reg(void *drcontext, instrlist_t *ilist, instr_t *where, reg_id_t reg,
dr_spill_slot_t slot);
DR_API
/**
* Returns the largest dr_spill_slot_t that can be accessed with an opnd_t from
* dr_reg_spill_slot_opnd().
*/
dr_spill_slot_t
dr_max_opnd_accessible_spill_slot(void);
DR_API
/**
* Returns an opnd_t that directly accesses the spill slot \p slot. Only slots
* <= dr_max_opnd_accessible_spill_slot() can be used with this routine.
* \note \p slot must be <= dr_max_opnd_accessible_spill_slot()
*/
opnd_t
dr_reg_spill_slot_opnd(void *drcontext, dr_spill_slot_t slot);
/* internal version */
opnd_t
reg_spill_slot_opnd(void *drcontext, dr_spill_slot_t slot);
DR_API
/**
* Can be used from a clean call or a restore_state_event (see
* dr_register_restore_state_event()) to see the value saved in spill slot
* \p slot by dr_save_reg().
*/
reg_t
dr_read_saved_reg(void *drcontext, dr_spill_slot_t slot);
DR_API
/**
* Can be used from a clean call to modify the value saved in the spill slot
* \p slot by dr_save_reg() such that a later dr_restore_reg() will see the
* new value.
*
* \note This routine should only be used during a clean call out of the
* cache. Use at any other time could corrupt application or DynamoRIO
* state.
*/
void
dr_write_saved_reg(void *drcontext, dr_spill_slot_t slot, reg_t value);
DR_API
/**
* Inserts into \p ilist prior to \p where meta-instruction(s) to save the 6
* arithmetic flags into xax after first saving xax to the spill slot \p slot.
* This is equivalent to dr_save_reg() of xax to \p slot followed by lahf and
* seto al instructions. See dr_restore_arith_flags().
*
* \warning At completion of the inserted instructions the saved flags are in the
* xax register. The xax register should not be modified after using this
* routine unless it is first saved (and later restored prior to
* using dr_restore_arith_flags()).
*
* \note X86-only
*
* \deprecated This routine is equivalent to dr_save_reg() followed by
* dr_save_arith_flags_to_xax().
*/
void
dr_save_arith_flags(void *drcontext, instrlist_t *ilist, instr_t *where,
dr_spill_slot_t slot);
DR_API
/**
* Inserts into \p ilist prior to \p where meta-instruction(s) to restore the 6
* arithmetic flags, assuming they were saved using dr_save_arith_flags() with
* slot \p slot and that xax holds the same value it did after the save.
*
* \note X86-only
*
* \deprecated This routine is equivalent to dr_restore_arith_flags_from_xax()
* followed by dr_restore_reg().
*/
void
dr_restore_arith_flags(void *drcontext, instrlist_t *ilist, instr_t *where,
dr_spill_slot_t slot);
DR_API
/**
* Inserts into \p ilist prior to \p where meta-instruction(s) to save the 6
* arithmetic flags into xax. This currently uses DynamoRIO's "lahf ; seto al"
* code sequence, which is faster and easier than pushf. If the caller wishes
* to use xax between saving and restoring these flags, they must save and
* restore xax, potentially using dr_save_reg()/dr_restore_reg(). If the caller
* needs to save both the current value of xax and the flags stored to xax by
* this routine, they must use separate spill slots, or they will overwrite the
* original xax value in memory.
* \note X86-only
*
* \warning Clobbers xax; the caller must ensure xax is dead or saved at
* \p where.
*/
void
dr_save_arith_flags_to_xax(void *drcontext, instrlist_t *ilist, instr_t *where);
DR_API
/**
* Inserts into \p ilist prior to \p where meta-instruction(s) to restore the 6
* arithmetic flags from xax. This currently uses DynamoRIO's "add $0x7f %al ;
* sahf" code sequence, which is faster and easier than popf. The caller must
* ensure that xax contains the arithmetic flags, most likely from
* dr_save_arith_flags_to_xax().
* \note X86-only
*/
void
dr_restore_arith_flags_from_xax(void *drcontext, instrlist_t *ilist, instr_t *where);
DR_API
/**
* Inserts into \p ilist prior to \p where meta-instruction(s) to save the
* arithmetic flags (6 arithmetic flags on X86 or APSR on ARM) into \p reg.
* If the caller wishes to use \p reg between saving and restoring these flags,
* they must save and restore \p reg, potentially using dr_save_reg()/dr_restore_reg().
* If the caller needs to save both the current value of \p reg and the flags stored
* to \p reg by this routine, they must use separate spill slots, or they will
* overwrite the original \p reg value in memory.
*
* \note On X86, only DR_REG_XAX should be passed in.
*
* \warning Clobbers \p reg; the caller must ensure \p reg is dead or saved at
* \p where.
*/
void
dr_save_arith_flags_to_reg(void *drcontext, instrlist_t *ilist, instr_t *where,
reg_id_t reg);
DR_API
/**
* Inserts into \p ilist prior to \p where meta-instruction(s) to restore
* the arithmetic flags (6 arithmetic flags on X86 or APSR on ARM) from \p reg.
* The caller must ensure that \p reg contains the program status flags,
* most likely from dr_save_arith_flags_to_reg().
*
* \note On X86, only DR_REG_XAX should be passed in.
*/
void
dr_restore_arith_flags_from_reg(void *drcontext, instrlist_t *ilist, instr_t *where,
reg_id_t reg);
DR_API
/**
* A convenience routine to aid restoring the arith flags done by outlined code,
* such as when handling restore state events. The routine takes the current value of
* the flags register \p cur_xflags, as well as the saved value \p saved_xflag, in order
* to return the original app value.
*/
reg_t
dr_merge_arith_flags(reg_t cur_xflags, reg_t saved_xflag);
/* FIXME PR 315327: add routines to save, restore and access from C code xmm registers
* from our dcontext slots. Not clear we really need to since we can't do it all
* that much faster than the client can already with read/write tls field (only one
* extra load) or (if -thread_private) absolute addresses.
*/
DR_API
/**
* Inserts into \p ilist prior to \p where meta-instruction(s) to read into the
* general-purpose full-size register \p reg from the user-controlled drcontext
* field for this thread. Reads from the same field as dr_get_tls_field().
*/
void
dr_insert_read_tls_field(void *drcontext, instrlist_t *ilist, instr_t *where,
reg_id_t reg);
DR_API
/**
* Inserts into \p ilist prior to \p where meta-instruction(s) to write the
* general-purpose full-size register \p reg to the user-controlled drcontext field
* for this thread. Writes to the same field as dr_set_tls_field().
*/
void
dr_insert_write_tls_field(void *drcontext, instrlist_t *ilist, instr_t *where,
reg_id_t reg);
DR_API
/** Inserts \p instr as a non-application instruction into \p ilist prior to \p where. */
void
instrlist_meta_preinsert(instrlist_t *ilist, instr_t *where, instr_t *instr);
DR_API
/** Inserts \p instr as a non-application instruction into \p ilist after \p where. */
void
instrlist_meta_postinsert(instrlist_t *ilist, instr_t *where, instr_t *instr);
DR_API
/** Inserts \p instr as a non-application instruction onto the end of \p ilist */
void
instrlist_meta_append(instrlist_t *ilist, instr_t *instr);
DR_API
/**
* Inserts \p instr as a non-application instruction that can fault (see
* instr_set_meta_may_fault()) into \p ilist prior to \p where.
*
* \deprecated Essentially equivalent to instrlist_meta_preinsert()
*/
void
instrlist_meta_fault_preinsert(instrlist_t *ilist, instr_t *where, instr_t *instr);
DR_API
/**
* Inserts \p instr as a non-application instruction that can fault (see
* instr_set_meta_may_fault()) into \p ilist after \p where.
*
* \deprecated Essentially equivalent to instrlist_meta_postinsert()
*/
void
instrlist_meta_fault_postinsert(instrlist_t *ilist, instr_t *where, instr_t *instr);
DR_API
/**
* Inserts \p instr as a non-application instruction that can fault (see
* instr_set_meta_may_fault()) onto the end of \p ilist.
*
* \deprecated Essentially equivalent to instrlist_meta_append()
*/
void
instrlist_meta_fault_append(instrlist_t *ilist, instr_t *instr);
/* dr_insert_* are used by general DR */
/* FIXME PR 213600: for clean call args that reference memory the
* client may prefer to receive the fault itself rather than it being treated
* as an app exception (xref PR 302951).
*/
DR_API
/**
* Inserts into \p ilist prior to \p where meta-instruction(s) to save state
* for a call, switch to this thread's DR stack, set up the passed-in
* parameters, make a call to \p callee, clean up the parameters, and
* then restore the saved state.
*
* The callee must use the standard C calling convention that matches the
* underlying 32-bit or 64-bit binary interface convention ("cdecl"). Other
* calling conventions, such as "fastcall" and "stdcall", are not supported.
*
* This routine expects to be passed a number of arguments beyond \p
* num_args equal to the value of \p num_args. Each of those
* arguments is a parameter to pass to the clean call, in the order
* passed to this routine. Each argument should be of type #opnd_t
* and will be copied into the proper location for that argument
* slot as specified by the calling convention.
*
* Stores the application state information on the DR stack, where it can be
* accessed from \c callee using dr_get_mcontext() and modified using
* dr_set_mcontext(). However, if register reservation code is in use (e.g.,
* via the drreg extension library: \ref page_drreg), dr_insert_clean_call_ex()
* must be called with its flags argument including
* #DR_CLEANCALL_READS_APP_CONTEXT (for dr_get_mcontext() use) and/or
* #DR_CLEANCALL_WRITES_APP_CONTEXT (for dr_set_mcontext() use) (and
* possibly #DR_CLEANCALL_MULTIPATH) to ensure proper interaction with
* register reservations.
*
* On x86, if \p save_fpstate is true, preserves the x87 floating-point and
* MMX state on the
* DR stack. Note that it is relatively expensive to save this state (on the
* order of 200 cycles) and that it typically takes 512 bytes to store
* it (see proc_fpstate_save_size()).
* The last floating-point instruction address in the saved state is left in an
* untranslated state (i.e., it may point into the code cache). This optional
* floating-point state preservation is specific to x87; floating-point values in
* XMM, YMM, or ZMM registers, or any SIMD register on any non-x86 architecture, are
* always preserved. Thus, on ARM/AArch64, \p save_fpstate is ignored.
*
* DR does support translating a fault in an argument (e.g., an
* argument that references application memory); such a fault will be
* treated as an application exception.
*
* The clean call sequence will be optimized based on the runtime option
* \ref op_cleancall "-opt_cleancall".
*
* For 64-bit, for purposes of reachability, this call is assumed to
* be destined for encoding into DR's code cache-reachable memory region.
* This includes the code cache as well as memory allocated with
* dr_thread_alloc(), dr_global_alloc(), dr_nonheap_alloc(), or
* dr_custom_alloc() with #DR_ALLOC_CACHE_REACHABLE. The call used
* here will be direct if it is reachable from those locations; if it
* is not reachable, an indirect call through r11 will be used (with
* r11's contents being clobbered). Use dr_insert_clean_call_ex()
* with #DR_CLEANCALL_INDIRECT to ensure reachability when encoding to
* a location other than DR's regular code region. See also
* dr_insert_call_ex().
*
* \note The stack used to save state and call \p callee is limited to
* 20KB by default; this can be changed with the -stack_size DR runtime
* parameter. This stack cannot be used to store state that persists
* beyond \c callee's return point.
*
* \note This routine only supports passing arguments that are
* integers or pointers of a size equal to the register size: i.e., no
* floating-point, multimedia, or aggregate data types.
* The routine also supports immediate integers that are smaller than
* the register size, and for 64-bit mode registers or memory references that
* are OPSZ_4.
*
* \note For 64-bit mode, passing arguments that use calling
* convention registers (for Windows, RCX, RDX, R8, R9; for Linux,
* RDI, RSI, RDX, RCX, R8 and R9) are supported but may incur
* additional stack usage.
*
* \note For 64-bit mode, if a 32-bit immediate integer is specified as an
* argument and it has its top bit set, we assume it is intended to be
* sign-extended to 64-bits; otherwise we zero-extend it.
*
* \note For 64-bit mode, variable-sized argument operands may not work
* properly.
*
* \note Arguments that reference sub-register portions of DR_REG_XSP are
* not supported (full DR_REG_XSP is supported).
*/
void
dr_insert_clean_call(void *drcontext, instrlist_t *ilist, instr_t *where, void *callee,
bool save_fpstate, uint num_args, ...);
DR_API
/**
* Identical to dr_insert_clean_call() except it takes in \p
* save_flags which allows requests to not save certain state. This
* is intended for use at application call entry points or other
* contexts where a client is comfortable making assumptions. Keep in
* mind that any register that is not saved will not be present in a
* context obtained from dr_get_mcontext().
*/
void
dr_insert_clean_call_ex(void *drcontext, instrlist_t *ilist, instr_t *where, void *callee,
dr_cleancall_save_t save_flags, uint num_args, ...);
/* Inserts a complete call to callee with the passed-in arguments, wrapped
* by an app save and restore.
* On x86, if \p save_fpstate is true, saves the x87 fp/mmx state.
* On ARM/AArch64, \p save_fpstate is ignored.
*
* NOTE : this routine clobbers TLS_XAX_SLOT and the XSP mcontext slot via
* dr_prepare_for_call(). We guarantee to clients that all other slots
* (except the XAX mcontext slot) will remain untouched.
*
* NOTE : dr_insert_cbr_instrumentation has assumption about the clean call
* instrumentation layout, changes to the clean call instrumentation may break
* dr_insert_cbr_instrumentation.
*/
void
dr_insert_clean_call_ex_varg(void *drcontext, instrlist_t *ilist, instr_t *where,
void *callee, dr_cleancall_save_t save_flags, uint num_args,
opnd_t *args);
DR_API
/**
* Inserts into \p ilist prior to \p where meta-instruction(s) to set
* up the passed-in parameters, make a call to \p callee, and clean up
* the parameters.
*
* The callee must use the standard C calling convention that matches the
* underlying 32-bit or 64-bit binary interface convention ("cdecl"). Other
* calling conventions, such as "fastcall" and "stdcall", are not supported.
*
* This routine uses the existing stack. In 64-bit mode, this routine assumes
* that the stack pointer is currently 16-byte aligned.
*
* The application state is NOT saved or restored (use dr_prepare_for_call()
* and dr_cleanup_after_call(), or replace this routine with dr_insert_clean_call()).
* The parameter set-up may write to registers if the calling convention so
* dictates. The registers are NOT saved beforehand (to do so, use
* dr_insert_clean_call()).
*
* It is up to the caller of this routine to preserve any caller-saved registers
* that the callee might modify.
*
* DR does not support translating a fault in an argument. For fault
* transparency, the client must perform the translation (see
* #dr_register_restore_state_event()), or use
* #dr_insert_clean_call().
*
* For 64-bit, for purposes of reachability, this call is assumed to
* be destined for encoding into DR's code cache-reachable memory region.
* This includes the code cache as well as memory allocated with
* dr_thread_alloc(), dr_global_alloc(), dr_nonheap_alloc(), or
* dr_custom_alloc() with #DR_ALLOC_CACHE_REACHABLE. The call used
* here will be direct if it is reachable from those locations; if it
* is not reachable, an indirect call through r11 will be used (with
* r11's contents being clobbered). Use dr_insert_call_ex() when
* encoding to a location other than DR's regular code region.
*
* \note This routine only supports passing arguments that are
* integers or pointers of a size equal to the register size: i.e., no
* floating-point, multimedia, or aggregate data types.
* The routine also supports immediate integers that are smaller than
* the register size, and for 64-bit mode registers or memory references that
* are OPSZ_4.
*
* \note For 64-bit mode, passing arguments that use calling
* convention registers (for Windows, RCX, RDX, R8, R9; for Linux,
* RDI, RSI, RDX, RCX, R8 and R9) are supported but may incur
* additional stack usage.
*
* \note For 64-bit mode, if a 32-bit immediate integer is specified as an
* argument and it has its top bit set, we assume it is intended to be
* sign-extended to 64-bits; otherwise we zero-extend it.
*
* \note For 64-bit mode, variable-sized argument operands may not work
* properly.
*
* \note Arguments that reference DR_REG_XSP are not supported in 64-bit mode.
*/
void
dr_insert_call(void *drcontext, instrlist_t *ilist, instr_t *where, void *callee,
uint num_args, ...);
DR_API
/**
* Identical to dr_insert_call() except it takes in \p encode_pc
* indicating roughly where the call sequence will be encoded. If \p
* callee is not reachable from \p encode_pc plus or minus one page,
* an indirect call will be used instead of the direct call used by
* dr_insert_call(). The indirect call overwrites the r11 register.
*
* \return true if the inserted call is direct and false if indirect.
*/
bool
dr_insert_call_ex(void *drcontext, instrlist_t *ilist, instr_t *where, byte *encode_pc,
void *callee, uint num_args, ...);
/* Not exported. Currently used for ARM to avoid storing to %lr. */
void
dr_insert_call_noreturn(void *drcontext, instrlist_t *ilist, instr_t *where, void *callee,
uint num_args, ...);
DR_API
/**
* Inserts into \p ilist prior to \p where meta-instruction(s) to save state for a call.
* Stores the application state information on the DR stack.
* Returns the size of the data stored on the DR stack (in case the caller
* needs to align the stack pointer).
*
* \warning On x86, this routine does NOT save the x87 floating-point or MMX state: to do
* that the instrumentation routine should call proc_save_fpstate() to save and then
* proc_restore_fpstate() to restore (or use dr_insert_clean_call()).
*
* \note The preparation modifies the DR_REG_XSP and DR_REG_XAX registers
* (after saving them). Use dr_insert_clean_call() instead if an
* argument to the subsequent call that references DR_REG_XAX is
* desired.
*
* \note The stack used to save the state is limited to
* 20KB by default; this can be changed with the -stack_size DR runtime
* parameter. This stack cannot be used to store state that persists
* beyond a single clean call, code cache execution, or probe callback
* function execution.
*/
uint
dr_prepare_for_call(void *drcontext, instrlist_t *ilist, instr_t *instr);
DR_API
/**
* Inserts into \p ilist prior to \p where meta-instruction(s) to restore state
* after a call.
*/
void
dr_cleanup_after_call(void *drcontext, instrlist_t *ilist, instr_t *where,
uint sizeof_param_area);
DR_API
/**
* Inserts into \p ilist prior to \p where meta-instruction(s) to save the current
* esp and switch to this thread's DR stack.
* \note The DR stack is limited to 20KB by default; this can be changed with
* the -stack_size DR runtime parameter. This stack cannot be used to store
* state that persists beyond a single clean call, code cache execution,
* or probe callback function execution.
*/
void
dr_swap_to_clean_stack(void *drcontext, instrlist_t *ilist, instr_t *where);
DR_API
/**
* Inserts into \p ilist prior to \p where meta-instruction(s) to restore into
* esp the value saved by dr_swap_to_clean_stack().
*/
void
dr_restore_app_stack(void *drcontext, instrlist_t *ilist, instr_t *where);
DR_API
/**
* Calls the specified function \p func after switching to the DR stack
* for the thread corresponding to \p drcontext.
* Passes in 8 arguments. Uses the C calling convention, so \p func will work
* just fine even if if takes fewer than 8 args.
* Swaps the stack back upon return and returns the value returned by \p func.
*
* On Windows, this routine does swap the TEB stack fields, avoiding
* issues with fault handling on Windows 8.1. This means there is no need
* for the callee to use dr_switch_to_dr_state_ex() with DR_STATE_STACK_BOUNDS.
*/
void *
dr_call_on_clean_stack(void *drcontext, void *(*func)(void), void *arg1, void *arg2,
void *arg3, void *arg4, void *arg5, void *arg6, void *arg7,
void *arg8);
/* providing functionality of old -instr_calls and -instr_branches flags */
DR_API
/**
* Assumes that \p instr is a near call.
* Inserts into \p ilist prior to \p instr instruction(s) to call callee passing
* two arguments:
* -# address of call instruction (caller)
* -# target address of call (callee)
* \note Sets #DR_CLEANCALL_READS_APP_CONTEXT and #DR_CLEANCALL_WRITES_APP_CONTEXT.
* Conditionally skipping the instrumentation inserted by this routine is not
* supported (i.e., #DR_CLEANCALL_MULTIPATH is not supported here).
*/
void
dr_insert_call_instrumentation(void *drcontext, instrlist_t *ilist, instr_t *instr,
void *callee);
DR_API
/**
* Assumes that \p instr is an indirect branch.
* Inserts into \p ilist prior to \p instr instruction(s) to call callee passing
* two arguments:
* -# address of branch instruction
* -# target address of branch
* \note Only the address portion of a far indirect branch is considered.
* \note \p scratch_slot must be <= dr_max_opnd_accessible_spill_slot(). \p
* scratch_slot is used internally to this routine and will be clobbered.
* \note Sets #DR_CLEANCALL_READS_APP_CONTEXT and #DR_CLEANCALL_WRITES_APP_CONTEXT.
* Conditionally skipping the instrumentation inserted by this routine is not
* supported (i.e., #DR_CLEANCALL_MULTIPATH is not supported here).
*/
/* If we re-enable -opt_speed (or -indcall2direct directly) we should add back:
* \note This routine is not supported when the -opt_speed option is specified.
*/
void
dr_insert_mbr_instrumentation(void *drcontext, instrlist_t *ilist, instr_t *instr,
void *callee, dr_spill_slot_t scratch_slot);
DR_API
/**
* Assumes that \p instr is a conditional branch
* Inserts into \p ilist prior to \p instr instruction(s) to call callee passing
* three arguments:
* -# address of branch instruction
* -# target address of branch
* -# 0 if the branch is not taken, 1 if it is taken
* \note Sets #DR_CLEANCALL_READS_APP_CONTEXT and #DR_CLEANCALL_WRITES_APP_CONTEXT.
* Conditionally skipping the instrumentation inserted by this routine is not
* supported (i.e., #DR_CLEANCALL_MULTIPATH is not supported here).
*/
void
dr_insert_cbr_instrumentation(void *drcontext, instrlist_t *ilist, instr_t *instr,
void *callee);
DR_API
/**
* Assumes that \p instr is a conditional branch
* Inserts into \p ilist prior to \p instr instruction(s) to call callee passing
* four arguments:
* -# address of branch instruction
* -# target address of branch
* -# fall-through address of branch
* -# 0 if the branch is not taken, 1 if it is taken
* -# user defined operand (e.g., TLS slot, immed value, register, etc.)
* \note The user defined operand cannot use register ebx!
* \note Sets #DR_CLEANCALL_READS_APP_CONTEXT and #DR_CLEANCALL_WRITES_APP_CONTEXT.
* Conditionally skipping the instrumentation inserted by this routine is not
* supported (i.e., #DR_CLEANCALL_MULTIPATH is not supported here).
*/
void
dr_insert_cbr_instrumentation_ex(void *drcontext, instrlist_t *ilist, instr_t *instr,
void *callee, opnd_t user_data);
/* FIXME: will never see any ubrs! */
DR_API
/**
* Assumes that \p instr is a direct, near, unconditional branch.
* Inserts into \p ilist prior to \p instr instruction(s) to call callee passing
* two arguments:
* -# address of branch instruction
* -# target address of branch
*
* \warning Basic block eliding is controlled by -max_elide_jmp. If that
* option is set to non-zero, ubrs may never be seen.
* \note Sets #DR_CLEANCALL_READS_APP_CONTEXT and #DR_CLEANCALL_WRITES_APP_CONTEXT.
* Conditionally skipping the instrumentation inserted by this routine is not
* supported (i.e., #DR_CLEANCALL_MULTIPATH is not supported here).
*/
void
dr_insert_ubr_instrumentation(void *drcontext, instrlist_t *ilist, instr_t *instr,
void *callee);
DR_API
/**
* Causes DynamoRIO to insert code that stores \p value into the
* return address slot on the stack immediately after the original
* value is read by the return instruction \p instr.
* \p instr must be a return instruction or this routine will fail.
*
* On ARM, \p value is ignored and instead a value that is guaranteed
* to not look like a return address is used. This is for efficiency
* reasons, as on ARM it would require an extra register spill in
* order to write an arbitrary value.
*
* \note This is meant to make it easier to obtain efficient
* callstacks by eliminating stale return addresses from prior stack
* frames. However, it is possible that writing to the application
* stack could result in incorrect application behavior, so use this
* at your own risk.
*
* \return whether successful.
*/
bool
dr_clobber_retaddr_after_read(void *drcontext, instrlist_t *ilist, instr_t *instr,
ptr_uint_t value);
DR_API
/**
* Returns true if the simd fields in dr_mcontext_t are valid xmm, ymm, or zmm values
* (i.e., whether the underlying processor supports SSE).
* \note If #DR_MC_MULTIMEDIA is not specified when calling dr_get_mcontext(),
* the simd fields will not be filled in regardless of the return value
* of this routine.
*/
bool
dr_mcontext_xmm_fields_valid(void);
DR_API
/**
* Returns true if the simd fields in dr_mcontext_t are valid zmm values
* (i.e., whether the underlying processor and OS support AVX-512 and AVX-512 code
* is present).
* \note If #DR_MC_MULTIMEDIA is not specified when calling dr_get_mcontext(),
* the simd fields will not be filled in regardless of the return value
* of this routine.
*/
bool
dr_mcontext_zmm_fields_valid(void);
/* dr_get_mcontext() needed for translating clean call arg errors */
DR_API
/**
* Copies the fields of the current application machine context selected
* by the \p flags field of \p context into \p context.
*
* This routine may only be called from:
* - A clean call invoked by dr_insert_clean_call() or dr_prepare_for_call(). If
* register reservation code is in use (e.g., via the drreg extension library \ref
* page_drreg), dr_insert_clean_call_ex() must be used with its flags argument
* including #DR_CLEANCALL_READS_APP_CONTEXT (and possibly
* #DR_CLEANCALL_MULTIPATH)to ensure proper interaction with register reservations.
* - A pre- or post-syscall event (dr_register_pre_syscall_event(),
* dr_register_post_syscall_event())
* - Basic block or trace creation events (dr_register_bb_event(),
* dr_register_trace_event()), but for basic block creation only when the
* basic block callback parameters \p for_trace and \p translating are
* false, and for trace creation only when \p translating is false.
* - A nudge callback (dr_register_nudge_event()) on Linux.
* (On Windows nudges happen in separate dedicated threads.)
* - A thread or process exit event (dr_register_thread_exit_event(),
* dr_register_exit_event())
* - A thread init event (dr_register_thread_init_event()) for all but
* the initial thread.
* - A kernel transfer event (dr_register_kernel_xfer_event()). Here the obtained
* context is the target context of the transfer, not the source (about to be
* changed) context. For Windows system call event types #DR_XFER_CONTINUE and
* #DR_XFER_SET_CONTEXT_THREAD, only the portions of the context selected by the
* application are available. The \p flags field of \p context is adjusted to
* reflect which fields were returned. Given the disparity in how Ebp/Rbp is
* handled (in #DR_MC_INTEGER but in CONTEXT_CONTROL), clients that care about that
* register are better off using system call events instead of kernel transfer events
* to take actions on these two system calls.
*
* Even when #DR_MC_CONTROL is specified, does NOT copy the pc field,
* except for system call events, when it will point at the
* post-syscall address, and kernel transfer events, when it will point to the
* target pc.
*
* Returns false if called from the init event or the initial thread's
* init event; returns true otherwise (cannot distinguish whether the
* caller is in a clean call so it is up to the caller to ensure it is
* used properly).
*
* The size field of \p context must be set to the size of the
* structure as known at compile time. If the size field is invalid,
* this routine will return false.
*
* The flags field of \p context must be set to the desired amount of
* information using the dr_mcontext_flags_t values. Asking for
* multimedia registers incurs a higher performance cost. An invalid
* flags value will return false.
*
* \note NUM_SIMD_SLOTS in the dr_mcontext_t.xmm array are filled in,
* but only if dr_mcontext_xmm_fields_valid() returns true and
* #DR_MC_MULTIMEDIA is set in the flags field.
*
* \note The context is the context saved at the dr_insert_clean_call() or
* dr_prepare_for_call() points. It does not correct for any registers saved
* with dr_save_reg(). To access registers saved with dr_save_reg() from a
* clean call use dr_read_saved_reg().
*
* \note System data structures are swapped to private versions prior to
* invoking clean calls or client events. Use dr_switch_to_app_state()
* to examine the application version of system state.
*/
bool
dr_get_mcontext(void *drcontext, dr_mcontext_t *context);
DR_API
/**
* Sets the fields of the application machine context selected by the
* flags field of \p context to the values in \p context.
*
* This routine may only be called from:
* - A clean call invoked by dr_insert_clean_call() or dr_prepare_for_call(). If
* register reservation code is in use (e.g., via the drreg extension library \ref
* page_drreg), dr_insert_clean_call_ex() must be used with its flags argument
* including #DR_CLEANCALL_WRITES_APP_CONTEXT (and possibly
* #DR_CLEANCALL_MULTIPATH) to ensure proper interaction with register
* reservations.
* - A pre- or post-syscall event (dr_register_pre_syscall_event(),
* dr_register_post_syscall_event())
* dr_register_thread_exit_event())
* - A kernel transfer event (dr_register_kernel_xfer_event()) other than
* #DR_XFER_CALLBACK_RETURN. Here the modified context is the target context of
* the transfer, not the source (about to be changed) context. For Windows system
* call event types #DR_XFER_CONTINUE and #DR_XFER_SET_CONTEXT_THREAD, only the
* portions of the context selected by the application can be changed. The \p
* flags field of \p context is adjusted to reflect which fields these are. Given
* the disparity in how Ebp/Rbp is handled (in #DR_MC_INTEGER but in
* CONTEXT_CONTROL), clients that care about that register are better off using
* system call events instead of kernel transfer events to take actions on these
* two system calls. - Basic block or trace creation events
* (dr_register_bb_event(), dr_register_trace_event()), but for basic block
* creation only when the basic block callback parameters \p for_trace and \p
* translating are false, and for trace creation only when \p translating is false.
*
* Ignores the pc field, except for kernel transfer events.
*
* If the size field of \p context is invalid, this routine will
* return false. A dr_mcontext_t obtained from DR will have the size field set.
*
* The flags field of \p context must be set to select the desired
* fields for copying, using the dr_mcontext_flags_t values. Asking
* to copy multimedia registers incurs a higher performance cost. An
* invalid flags value will return false.
*
* \return whether successful.
*
* \note The xmm fields are only set for processes where the underlying
* processor supports them (and when DR_MC_MULTIMEDIA is set in the flags field).
* For dr_insert_clean_call() that requested \p
* save_fpstate, the xmm values set here override that saved state. Use
* dr_mcontext_xmm_fields_valid() to determine whether the xmm fields are valid.
*/
bool
dr_set_mcontext(void *drcontext, dr_mcontext_t *context);
/* FIXME - combine with dr_set_mcontext()? Implementation wise it's nice to split the
* two since handling the pc with dr_set_mcontext() would complicate the clean call
* handling. But perhaps would be nicer from an interface perspective to combine them. */
DR_API
/**
* Immediately resumes application execution from a clean call out of the cache (see
* dr_insert_clean_call() or dr_prepare_for_call()) or an exception event with the
* state specified in \p mcontext (including pc, and including the xmm fields
* that are valid according to dr_mcontext_xmm_fields_valid()).
* The flags field of \p context must contain DR_MC_ALL; using a partial set
* of fields is not suported.
*
* For 32-bit ARM, be sure to use dr_app_pc_as_jump_target() to properly set the ISA
* mode for the continuation pc if it was obtained from instr_get_app_pc() or a
* similar source rather than from dr_get_proc_address(). This will set the least
* significant bit of the mcontext pc field to 1 when in Thumb mode
* (#DR_ISA_ARM_THUMB), \ref sec_thumb for more information.
*
* \note dr_get_mcontext() can be used to get the register state (except pc)
* saved in dr_insert_clean_call() or dr_prepare_for_call().
*
* \note If x87 floating point state was saved by dr_prepare_for_call() or
* dr_insert_clean_call() it is not restored (other than the valid xmm
* fields according to dr_mcontext_xmm_fields_valid(), if
* #DR_MC_MULTIMEDIA is specified in the flags field). The caller
* should instead manually save and restore the floating point state
* with proc_save_fpstate() and proc_restore_fpstate() if necessary.
*
* \note If the caller wishes to set any other state (such as xmm
* registers that are not part of the mcontext) they may do so by just
* setting that state in the current thread before making this call.
* To set system data structures, use dr_switch_to_app_state(), make
* the changes, and then switch back with dr_switch_to_dr_state()
* before calling this routine.
*
* \note This routine may only be called from a clean call from the cache. It can not be
* called from any registered event callback except the exception event
* (dr_register_exception_event()). From a signal event callback, use the
* #DR_SIGNAL_REDIRECT return value rather than calling this routine.
*
* \note If control is being redirected to a new pc (determined using drsyms,
* dr_get_proc_address, or any other way) ensure that the app state (such as
* the register values) are set as expected by the transfer point.
*
* \return false if unsuccessful; if successful, does not return.
*/
bool
dr_redirect_execution(dr_mcontext_t *context);
/** Flags to request non-default preservation of state in a clean call */
#define SPILL_SLOT_REDIRECT_NATIVE_TGT SPILL_SLOT_1
DR_API
/**
* Returns the target to use for a native context transfer to a target
* application address.
*
* Normally, redirection is performed from a client context in a clean
* call or event callback by invoking dr_redirect_execution(). In
* some circumstances, redirection from an application (or "native")
* context is desirable without creating an application control
* transfer in a basic block.
*
* To accomplish such a redirection, store the target application
* address in #SPILL_SLOT_REDIRECT_NATIVE_TGT by calling
* dr_write_saved_reg(). Set up any other application state as
* desired directly in the current machine context. Then jump to the
* target returned by this routine. By default, the target is global
* and can be cached globally. However, if traces are thread-private,
* or if traces are disabled and basic blocks are thread-private,
* there will be a separate target per \p drcontext.
*
* If a basic block is exited via such a redirection, the block should
* be emitted with the flag DR_EMIT_MUST_END_TRACE in order to avoid
* trace building errors.
*
* For ARM, the address returned by this routine has its least significant
* bit set to 1 if the target is Thumb.
*
* Returns null on error.
*/
byte *
dr_redirect_native_target(void *drcontext);
#ifdef WINDOWS
DR_API
/**
* Copies the machine state in \p src into \p dst. Sets the \p
* ContextFlags field of \p dst to reflect the \p flags field of \p
* src. However, CONTEXT_CONTROL includes Ebp/Rbp, while that's under
* #DR_MC_INTEGER, so we recommend always setting both #DR_MC_INTEGER
* and #DR_MC_CONTROL when calling this routine.
*
* It is up to the caller to ensure that \p dst is allocated and
* initialized properly in order to contain multimedia processor
* state, if #DR_MC_MULTIMEDIA is set in the \p flags field of \p src.
*
* The current segment register values are filled in under the assumption
* that this context is for the calling thread.
*
* \note floating-point values are not filled in for \p dst.
* \note Windows only.
*
* \return false if unsuccessful; if successful, does not return.
*/
bool
dr_mcontext_to_context(CONTEXT *dst, dr_mcontext_t *src);
#endif
DR_API
/**
* Create meta instructions for storing pointer-size integer \p val to \p dst,
* and then insert them into \p ilist prior to \p where.
* Pointers to the first and last created meta instructions are returned
* in \p first and \p last, unless only one meta instruction is created,
* in which case NULL is returned in last.
* If the instruction is a no-op (when dst is the zero register on AArch64)
* then no instructions are created and NULL is returned in first and last.
*/
void
instrlist_insert_mov_immed_ptrsz(void *drcontext, ptr_int_t val, opnd_t dst,
instrlist_t *ilist, instr_t *where,
instr_t **first DR_PARAM_OUT,
instr_t **last DR_PARAM_OUT);
DR_API
/**
* Create meta instructions for pushing pointer-size integer \p val on the stack,
* and then insert them into \p ilist prior to \p where.
* Pointers to the first and last created meta instructions are returned
* in \p first and \p last, unless only one meta instruction is created,
* in which case NULL is returned in last.
*/
void
instrlist_insert_push_immed_ptrsz(void *drcontext, ptr_int_t val, instrlist_t *ilist,
instr_t *where, instr_t **first DR_PARAM_OUT,
instr_t **last DR_PARAM_OUT);
DR_API
/**
* Create meta instructions for storing the address of \p src_inst to \p dst,
* and then insert them into \p ilist prior to \p where.
* The \p encode_estimate parameter, used only for 64-bit mode,
* indicates whether the final address of \p src_inst, when it is
* encoded later, will fit in 32 bits or needs 64 bits.
* If the encoding will be in DynamoRIO's code cache, pass NULL.
* If the final encoding location is unknown, pass a high address to be on
* the safe side.
* Pointers to the first and last created meta instructions are returned
* in \p first and \p last, unless only one meta instruction is created,
* in which case NULL is returned in last.
* If the instruction is a no-op (when dst is the zero register on AArch64)
* then no instructions are created and NULL is returned in first and last.
*/
void
instrlist_insert_mov_instr_addr(void *drcontext, instr_t *src_inst, byte *encode_estimate,
opnd_t dst, instrlist_t *ilist, instr_t *where,
instr_t **first DR_PARAM_OUT,
instr_t **last DR_PARAM_OUT);
DR_API
/**
* Create meta instructions for pushing the address of \p src_inst on the stack,
* and then insert them into \p ilist prior to \p where.
* The \p encode_estimate parameter, used only for 64-bit mode,
* indicates whether the final address of \p src_inst, when it is
* encoded later, will fit in 32 bits or needs 64 bits.
* If the encoding will be in DynamoRIO's code cache, pass NULL.
* If the final encoding location is unknown, pass a high address to be on
* the safe side.
* Pointers to the first and last created meta instructions are returned
* in \p first and \p last, unless only one meta instruction is created,
* in which case NULL is returned in last.
*/
void
instrlist_insert_push_instr_addr(void *drcontext, instr_t *src_inst,
byte *encode_estimate, instrlist_t *ilist,
instr_t *where, instr_t **first DR_PARAM_OUT,
instr_t **last DR_PARAM_OUT);
DR_API
/**
* Returns the register that is stolen and used by DynamoRIO.
* Reference \ref sec_reg_stolen for more information.
*/
reg_id_t
dr_get_stolen_reg(void);
DR_API
/**
* Insert code to get the application value of the register stolen by DynamoRIO
* into register \p reg.
* Reference \ref sec_reg_stolen for more information.
*
* \return whether successful.
*
* \note ARM-only
*/
bool
dr_insert_get_stolen_reg_value(void *drcontext, instrlist_t *ilist, instr_t *instr,
reg_id_t reg);
DR_API
/**
* Insert code to set the value of register \p reg as the application value of
* the register stolen by DynamoRIO
* Reference \ref sec_reg_stolen for more information.
*
* \return whether successful.
*
* \note ARM-only
*/
bool
dr_insert_set_stolen_reg_value(void *drcontext, instrlist_t *ilist, instr_t *instr,
reg_id_t reg);
DR_API
/**
* Removes all OP_it instructions from \p ilist without changing the
* instructions that were inside each IT block. This is intended to
* be paired with dr_insert_it_instrs(), where a client's examination
* of the application instruction list and insertion of
* instrumentation occurs in between the two calls and thus does not
* have to worry about groups of instructions that cannot be separated
* or changed. The resulting predicated instructions are not
* encodable in Thumb mode (#DR_ISA_ARM_THUMB): dr_insert_it_instrs()
* must be called before encoding.
*
* \return the number of OP_it instructions removed; -1 on error.
*
* \note ARM-only
*/
int
dr_remove_it_instrs(void *drcontext, instrlist_t *ilist);
DR_API
/**
* Inserts enough OP_it instructions with proper parameters into \p
* ilist to make all predicated instructions in \p ilist legal in
* Thumb mode (#DR_ISA_ARM_THUMB). Treats predicated app and tool
* instructions identically, but marks inserted OP_it instructions as
* app instructions (see instr_set_app()).
*
* \return the number of OP_it instructions inserted; -1 on error.
*
* \note ARM-only
*/
int
dr_insert_it_instrs(void *drcontext, instrlist_t *ilist);
DR_API
/**
* Insert code to get the application value of the thread pointer register
* into register \p reg.
*
* \return whether successful.
*
* \note RISCV-only
*/
bool
dr_insert_get_app_tls(void *drcontext, instrlist_t *ilist, instr_t *instr,
reg_id_t tls_reg, reg_id_t reg);
DR_API
/**
* Inserts into \p ilist prior to \p where meta-instruction(s) to save the
* x87 floating point state into the 16-byte-aligned buffer referred to by
* \p buf, which must be 512 bytes for processors with the FXSR
* feature, and 108 bytes for those without (where this routine does
* not support 16-bit operand sizing). \p buf should have size of
* OPSZ_512; this routine will automatically adjust it to OPSZ_108 if
* necessary. \note proc_fpstate_save_size() can be used to determine
* the particular size needed.
*
* When the FXSR feature is present, the fxsave format matches the bitwidth
* of the ISA mode of the current thread (see dr_get_isa_mode()).
*
* The last floating-point instruction address is left in an
* untranslated state (i.e., it may point into the code cache).
*/
void
dr_insert_save_fpstate(void *drcontext, instrlist_t *ilist, instr_t *where, opnd_t buf);
DR_API
/**
* Inserts into \p ilist prior to \p where meta-instruction(s) to restore the
* x87 floating point state from the 16-byte-aligned buffer referred to by
* buf, which must be 512 bytes for processors with the FXSR feature,
* and 108 bytes for those without (where this routine does not
* support 16-bit operand sizing). \p buf should have size of
* OPSZ_512; this routine will automatically adjust it to OPSZ_108 if
* necessary. \note proc_fpstate_save_size() can be used to determine
* the particular size needed.
*
* When the FXSR feature is present, the fxsave format matches the bitwidth
* of the ISA mode of the current thread (see dr_get_isa_mode()).
*/
void
dr_insert_restore_fpstate(void *drcontext, instrlist_t *ilist, instr_t *where,
opnd_t buf);
DR_API
/**
* Insert code to get the segment base address pointed to by seg into
* register reg. In Linux, it is only supported with -mangle_app_seg option.
* In Windows, it only supports getting base address of the TLS segment.
*
* \return whether successful.
*/
bool
dr_insert_get_seg_base(void *drcontext, instrlist_t *ilist, instr_t *instr, reg_id_t seg,
reg_id_t reg);
#endif /* _DR_IR_UTILS_H_ */