Code transformation utilities. More...
#include "dr_ir_instr.h"
Macros | |
#define | SPILL_SLOT_REDIRECT_NATIVE_TGT SPILL_SLOT_1 |
Typedefs | |
typedef enum _dr_isa_mode_t | dr_isa_mode_t |
Enumerations | |
enum | _dr_isa_mode_t { DR_ISA_IA32, DR_ISA_X86 = DR_ISA_IA32, DR_ISA_AMD64, DR_ISA_ARM_A32, DR_ISA_ARM_THUMB, DR_ISA_ARM_A64 } |
enum | dr_spill_slot_t { , SPILL_SLOT_2 = 1, SPILL_SLOT_3 = 2, SPILL_SLOT_4 = 3, SPILL_SLOT_5 = 4, SPILL_SLOT_6 = 5, SPILL_SLOT_7 = 6, SPILL_SLOT_8 = 7, SPILL_SLOT_9 = 8, SPILL_SLOT_10 = 9, SPILL_SLOT_11 = 10, SPILL_SLOT_12 = 11, SPILL_SLOT_13 = 12, SPILL_SLOT_14 = 13, SPILL_SLOT_15 = 14, SPILL_SLOT_16 = 15, SPILL_SLOT_17 = 16, SPILL_SLOT_MAX = SPILL_SLOT_17 } |
enum | dr_cleancall_save_t { DR_CLEANCALL_SAVE_FLOAT = 0x0001, DR_CLEANCALL_NOSAVE_FLAGS = 0x0002, DR_CLEANCALL_NOSAVE_XMM = 0x0004, DR_CLEANCALL_NOSAVE_XMM_NONPARAM = 0x0008, DR_CLEANCALL_NOSAVE_XMM_NONRET = 0x0010, DR_CLEANCALL_INDIRECT = 0x0020 , DR_CLEANCALL_ALWAYS_OUT_OF_LINE = 0x0080 } |
enum | dr_disasm_flags_t { DR_DISASM_DR = 0x0, DR_DISASM_INTEL = 0x1, DR_DISASM_ATT = 0x2, DR_DISASM_STRICT_INVALID = 0x4, DR_DISASM_NO_OPND_SIZE = 0x8, DR_DISASM_ARM = 0x10 } |
Functions | |
bool | dr_set_isa_mode (void *drcontext, dr_isa_mode_t new_mode, dr_isa_mode_t *old_mode OUT) |
dr_isa_mode_t | dr_get_isa_mode (void *drcontext) |
void | dr_save_reg (void *drcontext, instrlist_t *ilist, instr_t *where, reg_id_t reg, dr_spill_slot_t slot) |
void | dr_restore_reg (void *drcontext, instrlist_t *ilist, instr_t *where, reg_id_t reg, dr_spill_slot_t slot) |
dr_spill_slot_t | dr_max_opnd_accessible_spill_slot (void) |
opnd_t | dr_reg_spill_slot_opnd (void *drcontext, dr_spill_slot_t slot) |
reg_t | dr_read_saved_reg (void *drcontext, dr_spill_slot_t slot) |
void | dr_write_saved_reg (void *drcontext, dr_spill_slot_t slot, reg_t value) |
void | dr_save_arith_flags (void *drcontext, instrlist_t *ilist, instr_t *where, dr_spill_slot_t slot) |
void | dr_restore_arith_flags (void *drcontext, instrlist_t *ilist, instr_t *where, dr_spill_slot_t slot) |
void | dr_save_arith_flags_to_xax (void *drcontext, instrlist_t *ilist, instr_t *where) |
void | dr_restore_arith_flags_from_xax (void *drcontext, instrlist_t *ilist, instr_t *where) |
void | dr_save_arith_flags_to_reg (void *drcontext, instrlist_t *ilist, instr_t *where, reg_id_t reg) |
void | dr_restore_arith_flags_from_reg (void *drcontext, instrlist_t *ilist, instr_t *where, reg_id_t reg) |
void | dr_insert_read_tls_field (void *drcontext, instrlist_t *ilist, instr_t *where, reg_id_t reg) |
void | dr_insert_write_tls_field (void *drcontext, instrlist_t *ilist, instr_t *where, reg_id_t reg) |
void | instrlist_meta_preinsert (instrlist_t *ilist, instr_t *where, instr_t *instr) |
void | instrlist_meta_postinsert (instrlist_t *ilist, instr_t *where, instr_t *instr) |
void | instrlist_meta_append (instrlist_t *ilist, instr_t *instr) |
void | instrlist_meta_fault_preinsert (instrlist_t *ilist, instr_t *where, instr_t *instr) |
void | instrlist_meta_fault_postinsert (instrlist_t *ilist, instr_t *where, instr_t *instr) |
void | instrlist_meta_fault_append (instrlist_t *ilist, instr_t *instr) |
void | dr_insert_clean_call (void *drcontext, instrlist_t *ilist, instr_t *where, void *callee, bool save_fpstate, uint num_args,...) |
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,...) |
void | dr_insert_call (void *drcontext, instrlist_t *ilist, instr_t *where, void *callee, uint num_args,...) |
bool | dr_insert_call_ex (void *drcontext, instrlist_t *ilist, instr_t *where, byte *encode_pc, void *callee, uint num_args,...) |
uint | dr_prepare_for_call (void *drcontext, instrlist_t *ilist, instr_t *instr) |
void | dr_cleanup_after_call (void *drcontext, instrlist_t *ilist, instr_t *where, uint sizeof_param_area) |
void | dr_swap_to_clean_stack (void *drcontext, instrlist_t *ilist, instr_t *where) |
void | dr_restore_app_stack (void *drcontext, instrlist_t *ilist, instr_t *where) |
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) |
void | dr_insert_call_instrumentation (void *drcontext, instrlist_t *ilist, instr_t *instr, void *callee) |
void | dr_insert_mbr_instrumentation (void *drcontext, instrlist_t *ilist, instr_t *instr, void *callee, dr_spill_slot_t scratch_slot) |
void | dr_insert_cbr_instrumentation (void *drcontext, instrlist_t *ilist, instr_t *instr, void *callee) |
void | dr_insert_cbr_instrumentation_ex (void *drcontext, instrlist_t *ilist, instr_t *instr, void *callee, opnd_t user_data) |
void | dr_insert_ubr_instrumentation (void *drcontext, instrlist_t *ilist, instr_t *instr, void *callee) |
bool | dr_clobber_retaddr_after_read (void *drcontext, instrlist_t *ilist, instr_t *instr, ptr_uint_t value) |
bool | dr_mcontext_xmm_fields_valid (void) |
bool | dr_get_mcontext (void *drcontext, dr_mcontext_t *context) |
bool | dr_set_mcontext (void *drcontext, dr_mcontext_t *context) |
bool | dr_redirect_execution (dr_mcontext_t *context) |
byte * | dr_redirect_native_target (void *drcontext) |
bool | dr_mcontext_to_context (CONTEXT *dst, dr_mcontext_t *src) |
void | instrlist_insert_mov_immed_ptrsz (void *drcontext, ptr_int_t val, opnd_t dst, instrlist_t *ilist, instr_t *where, instr_t **first OUT, instr_t **last OUT) |
void | instrlist_insert_push_immed_ptrsz (void *drcontext, ptr_int_t val, instrlist_t *ilist, instr_t *where, instr_t **first OUT, instr_t **last OUT) |
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 OUT, instr_t **last OUT) |
void | instrlist_insert_push_instr_addr (void *drcontext, instr_t *src_inst, byte *encode_estimate, instrlist_t *ilist, instr_t *where, instr_t **first OUT, instr_t **last OUT) |
reg_id_t | dr_get_stolen_reg (void) |
bool | dr_insert_get_stolen_reg_value (void *drcontext, instrlist_t *ilist, instr_t *instr, reg_id_t reg) |
bool | dr_insert_set_stolen_reg_value (void *drcontext, instrlist_t *ilist, instr_t *instr, reg_id_t reg) |
int | dr_remove_it_instrs (void *drcontext, instrlist_t *ilist) |
int | dr_insert_it_instrs (void *drcontext, instrlist_t *ilist) |
app_pc | decode_memory_reference_size (void *drcontext, app_pc pc, uint *size_in_bytes) |
byte * | decode_eflags_usage (void *drcontext, byte *pc, uint *usage, dr_opnd_query_flags_t flags) |
byte * | decode (void *drcontext, byte *pc, instr_t *instr) |
byte * | decode_from_copy (void *drcontext, byte *copy_pc, byte *orig_pc, instr_t *instr) |
instrlist_t * | decode_as_bb (void *drcontext, byte *start_pc) |
instrlist_t * | decode_trace (void *drcontext, void *tag) |
byte | decode_first_opcode_byte (int opcode) |
const char * | decode_opcode_name (int opcode) |
bool | set_x86_mode (void *drcontext, bool x86) |
bool | get_x86_mode (void *drcontext) |
app_pc | dr_app_pc_as_jump_target (dr_isa_mode_t isa_mode, app_pc pc) |
app_pc | dr_app_pc_as_load_target (dr_isa_mode_t isa_mode, app_pc pc) |
int | decode_sizeof (void *drcontext, byte *pc, int *num_prefixes _IF_X86_64(uint *rip_rel_pos)) |
byte * | decode_next_pc (void *drcontext, byte *pc) |
void | disassemble_set_syntax (dr_disasm_flags_t flags) |
byte * | disassemble (void *drcontext, byte *pc, file_t outfile) |
byte * | disassemble_with_info (void *drcontext, byte *pc, file_t outfile, bool show_pc, bool show_bytes) |
byte * | disassemble_from_copy (void *drcontext, byte *copy_pc, byte *orig_pc, file_t outfile, bool show_pc, bool show_bytes) |
byte * | disassemble_to_buffer (void *drcontext, byte *pc, byte *orig_pc, bool show_pc, bool show_bytes, char *buf, size_t bufsz, int *printed OUT) |
Code transformation utilities.
#define SPILL_SLOT_REDIRECT_NATIVE_TGT SPILL_SLOT_1 |
Flags to request non-default preservation of state in a clean call
typedef enum _dr_isa_mode_t dr_isa_mode_t |
Specifies which processor mode to use when decoding or encoding.
enum _dr_isa_mode_t |
Specifies which processor mode to use when decoding or encoding.
enum dr_cleancall_save_t |
Flags to request non-default preservation of state in a clean call as well as other call options.
Enumerator | |
---|---|
DR_CLEANCALL_SAVE_FLOAT | Save floating-point state (x86-specific). 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). |
DR_CLEANCALL_NOSAVE_FLAGS | Skip saving the flags and skip clearing the flags (including DF) for client execution. Note that this can cause problems if dr_redirect_execution() is called from a clean call, as an uninitialized flags value can cause subtle errors. |
DR_CLEANCALL_NOSAVE_XMM | Skip saving any XMM or YMM registers. |
DR_CLEANCALL_NOSAVE_XMM_NONPARAM | Skip saving any XMM or YMM registers that are never used as parameters. |
DR_CLEANCALL_NOSAVE_XMM_NONRET | Skip saving any XMM or YMM registers that are never used as return values. |
DR_CLEANCALL_INDIRECT | Requests that an indirect call be used to ensure reachability, both for reaching the callee and for any out-of-line helper routine calls. Only honored for 64-bit mode, where r11 will be used for the indirection. |
DR_CLEANCALL_ALWAYS_OUT_OF_LINE | Requests that out-of-line state save and restore routines be used even when a subset of the state does not need to be preserved for this callee. Also disables inlining. This helps guarantee that the inserted code remains small. |
enum dr_disasm_flags_t |
Flags controlling disassembly style
enum dr_spill_slot_t |
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().
byte* decode | ( | void * | drcontext, |
byte * | pc, | ||
instr_t * | instr | ||
) |
Decodes the instruction at address pc
into instr
, filling in the instruction's opcode, eflags usage, prefixes, and operands. The instruction's raw bits are set to valid and pointed at pc
(xref instr_get_raw_bits()). Assumes that instr
is already initialized, but uses the x86/x64 mode for the thread dcontext
rather than that set in instr. If caller is re-using same instr_t struct over multiple decodings, caller should call instr_reset() or instr_reuse(). Returns the address of the next byte after the decoded instruction. Returns NULL on decoding an invalid instr and sets opcode to OP_INVALID.
instrlist_t* decode_as_bb | ( | void * | drcontext, |
byte * | start_pc | ||
) |
Client routine to decode instructions at an arbitrary app address, following all the rules that DynamoRIO follows internally for terminating basic blocks. Note that DynamoRIO does not validate that start_pc
is actually the first instruction of a basic block.
byte* decode_eflags_usage | ( | void * | drcontext, |
byte * | pc, | ||
uint * | usage, | ||
dr_opnd_query_flags_t | flags | ||
) |
Decodes only enough of the instruction at address pc
to determine its eflags usage, which is returned in usage
as EFLAGS_ constants or'ed together. Returns the address of the next byte after the decoded instruction. Returns NULL on decoding an invalid instruction.
byte decode_first_opcode_byte | ( | int | opcode | ) |
Given an OP_ constant, returns the first byte of its opcode when encoded as an IA-32 instruction.
byte* decode_from_copy | ( | void * | drcontext, |
byte * | copy_pc, | ||
byte * | orig_pc, | ||
instr_t * | instr | ||
) |
Decodes the instruction at address copy_pc
into instr
as though it were located at address orig_pc
. Any pc-relative operands have their values calculated as though the instruction were actually at orig_pc
, though that address is never de-referenced. The instruction's raw bits are not valid, but its application address field (see instr_get_app_pc()) is set to orig_pc
. The instruction's opcode, eflags usage, prefixes, and operands are all filled in. Assumes that instr
is already initialized, but uses the x86/x64 mode for the thread dcontext
rather than that set in instr. If caller is re-using same instr_t struct over multiple decodings, caller should call instr_reset() or instr_reuse(). Returns the address of the next byte after the decoded instruction copy at copy_pc
. Returns NULL on decoding an invalid instr and sets opcode to OP_INVALID.
app_pc decode_memory_reference_size | ( | void * | drcontext, |
app_pc | pc, | ||
uint * | size_in_bytes | ||
) |
Calculates the size, in bytes, of the memory read or write of the instr at pc
. If the instruction is a repeating string instruction, considers only one iteration. Returns the pc of the following instruction. If the instruction at pc
does not reference memory, or is invalid, returns NULL.
byte* decode_next_pc | ( | void * | drcontext, |
byte * | pc | ||
) |
Decodes only enough of the instruction at address pc
to determine its size. Returns the address of the byte following the instruction. May return NULL on decoding certain invalid instructions.
const char* decode_opcode_name | ( | int | opcode | ) |
Given an OP_ constant, returns the string name of its opcode.
int decode_sizeof | ( | void * | drcontext, |
byte * | pc, | ||
int *num_prefixes | _IF_X86_64uint *rip_rel_pos | ||
) |
Decodes only enough of the instruction at address pc
to determine its size. Returns that size. If num_prefixes
is non-NULL, returns the number of prefix bytes. If rip_rel_pos
is non-NULL, returns the offset into the instruction of a rip-relative addressing displacement (for data only: ignores control-transfer relative addressing), or 0 if none. May return 0 size for certain invalid instructions.
instrlist_t* decode_trace | ( | void * | drcontext, |
void * | tag | ||
) |
Decodes the trace with tag tag
, and returns an instrlist_t of the instructions comprising that fragment. If tag
is not a valid tag for an existing trace, the routine returns NULL. Clients can use dr_trace_exists_at() to determine whether the trace exists.
byte* disassemble | ( | void * | drcontext, |
byte * | pc, | ||
file_t | outfile | ||
) |
Decodes and then prints the instruction at address pc
to file outfile
. The default is to use DR's custom syntax (see disassemble_set_syntax()). Returns the address of the subsequent instruction, or NULL if the instruction at pc
is invalid.
byte* disassemble_from_copy | ( | void * | drcontext, |
byte * | copy_pc, | ||
byte * | orig_pc, | ||
file_t | outfile, | ||
bool | show_pc, | ||
bool | show_bytes | ||
) |
Decodes the instruction at address copy_pc
as though it were located at address orig_pc
, and then prints the instruction to file outfile
. Prior to the instruction the address orig_pc
is printed if show_pc
and the raw bytes are printed if show_bytes
. The default is to use DR's custom syntax (see disassemble_set_syntax()). Returns the address of the subsequent instruction after the copy at copy_pc
, or NULL if the instruction at copy_pc
is invalid.
void disassemble_set_syntax | ( | dr_disasm_flags_t | flags | ) |
Sets the disassembly style and decoding options. The default is to use DR's custom syntax, unless one of the -syntax_intel, -syntax_att, or -syntax_arm runtime options is specified.
byte* disassemble_to_buffer | ( | void * | drcontext, |
byte * | pc, | ||
byte * | orig_pc, | ||
bool | show_pc, | ||
bool | show_bytes, | ||
char * | buf, | ||
size_t | bufsz, | ||
int *printed | OUT | ||
) |
Decodes the instruction at address pc
as though it were located at address orig_pc
, and then prints the instruction to the buffer buf
. Always null-terminates, and will not print more than bufsz
characters, which includes the final null character. Indicates the number of characters printed, not including the final null, in printed
, if printed
is non-NULL.
Prior to the instruction the address orig_pc
is printed if show_pc
and the raw bytes are printed if show_bytes
. The default is to use DR's custom syntax (see disassemble_set_syntax()). Returns the address of the subsequent instruction after the copy at copy_pc
, or NULL if the instruction at copy_pc
is invalid.
byte* disassemble_with_info | ( | void * | drcontext, |
byte * | pc, | ||
file_t | outfile, | ||
bool | show_pc, | ||
bool | show_bytes | ||
) |
Decodes and then prints the instruction at address pc
to file outfile
. Prior to the instruction the address is printed if show_pc
and the raw bytes are printed if show_bytes
. The default is to use DR's custom syntax (see disassemble_set_syntax()). Returns the address of the subsequent instruction, or NULL if the instruction at pc
is invalid.
app_pc dr_app_pc_as_jump_target | ( | dr_isa_mode_t | isa_mode, |
app_pc | pc | ||
) |
Given an application program counter value, returns the corresponding value to use as an indirect branch target for the given isa_mode
. For ARM's Thumb mode (DR_ISA_ARM_THUMB), this involves setting the least significant bit of the address.
app_pc dr_app_pc_as_load_target | ( | dr_isa_mode_t | isa_mode, |
app_pc | pc | ||
) |
Given an application program counter value, returns the corresponding value to use as a memory load target for the given isa_mode
, or for comparing to the application address inside a basic block or trace. For ARM's Thumb mode (DR_ISA_ARM_THUMB), this involves clearing the least significant bit of the address.
void* dr_call_on_clean_stack | ( | void * | drcontext, |
void *(*)(void) | func, | ||
void * | arg1, | ||
void * | arg2, | ||
void * | arg3, | ||
void * | arg4, | ||
void * | arg5, | ||
void * | arg6, | ||
void * | arg7, | ||
void * | arg8 | ||
) |
Calls the specified function func
after switching to the DR stack for the thread corresponding to drcontext
. Passes in 8 arguments. Uses the C calling convention, so 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 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_cleanup_after_call | ( | void * | drcontext, |
instrlist_t * | ilist, | ||
instr_t * | where, | ||
uint | sizeof_param_area | ||
) |
Inserts into ilist
prior to where
meta-instruction(s) to restore state after a call.
bool dr_clobber_retaddr_after_read | ( | void * | drcontext, |
instrlist_t * | ilist, | ||
instr_t * | instr, | ||
ptr_uint_t | value | ||
) |
Causes DynamoRIO to insert code that stores value
into the return address slot on the stack immediately after the original value is read by the return instruction instr
. instr
must be a return instruction or this routine will fail.
On ARM, 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.
dr_isa_mode_t dr_get_isa_mode | ( | void * | drcontext | ) |
The decode and encode routines use a per-thread persistent flag that indicates which processor mode to use. This routine returns the value of that flag.
bool dr_get_mcontext | ( | void * | drcontext, |
dr_mcontext_t * | context | ||
) |
Copies the fields of the current application machine context selected by the flags
field of context
into context
.
This routine may only be called from:
for_trace
and translating
are false, and for trace creation only when translating
is false.flags
field of 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 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 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.
reg_id_t dr_get_stolen_reg | ( | void | ) |
Returns the register that is stolen and used by DynamoRIO. Reference Register Stolen by DynamoRIO for more information.
void dr_insert_call | ( | void * | drcontext, |
instrlist_t * | ilist, | ||
instr_t * | where, | ||
void * | callee, | ||
uint | num_args, | ||
... | |||
) |
Inserts into ilist
prior to where
meta-instruction(s) to set up the passed-in parameters, make a call to 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.
bool dr_insert_call_ex | ( | void * | drcontext, |
instrlist_t * | ilist, | ||
instr_t * | where, | ||
byte * | encode_pc, | ||
void * | callee, | ||
uint | num_args, | ||
... | |||
) |
Identical to dr_insert_call() except it takes in encode_pc
indicating roughly where the call sequence will be encoded. If callee
is not reachable from 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.
void dr_insert_call_instrumentation | ( | void * | drcontext, |
instrlist_t * | ilist, | ||
instr_t * | instr, | ||
void * | callee | ||
) |
Assumes that instr
is a near call. Inserts into ilist
prior to instr
instruction(s) to call callee passing two arguments:
void dr_insert_cbr_instrumentation | ( | void * | drcontext, |
instrlist_t * | ilist, | ||
instr_t * | instr, | ||
void * | callee | ||
) |
Assumes that instr
is a conditional branch Inserts into ilist
prior to instr
instruction(s) to call callee passing three arguments:
void dr_insert_cbr_instrumentation_ex | ( | void * | drcontext, |
instrlist_t * | ilist, | ||
instr_t * | instr, | ||
void * | callee, | ||
opnd_t | user_data | ||
) |
Assumes that instr
is a conditional branch Inserts into ilist
prior to instr
instruction(s) to call callee passing four arguments:
void dr_insert_clean_call | ( | void * | drcontext, |
instrlist_t * | ilist, | ||
instr_t * | where, | ||
void * | callee, | ||
bool | save_fpstate, | ||
uint | num_args, | ||
... | |||
) |
Inserts into ilist
prior to 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 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 num_args
equal to the value of 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 callee
using dr_get_mcontext() and modified using dr_set_mcontext().
On x86, if save_fpstate
is true, preserves the fp/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).
On ARM/AArch64, 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 -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().
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 callee's
return point.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, | ||
... | |||
) |
Identical to dr_insert_clean_call() except it takes in 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().
bool dr_insert_get_stolen_reg_value | ( | void * | drcontext, |
instrlist_t * | ilist, | ||
instr_t * | instr, | ||
reg_id_t | reg | ||
) |
Insert code to get the application value of the register stolen by DynamoRIO into register reg
. Reference Register Stolen by DynamoRIO for more information.
int dr_insert_it_instrs | ( | void * | drcontext, |
instrlist_t * | ilist | ||
) |
Inserts enough OP_it instructions with proper parameters into ilist
to make all predicated instructions in 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()).
void dr_insert_mbr_instrumentation | ( | void * | drcontext, |
instrlist_t * | ilist, | ||
instr_t * | instr, | ||
void * | callee, | ||
dr_spill_slot_t | scratch_slot | ||
) |
Assumes that instr
is an indirect branch. Inserts into ilist
prior to instr
instruction(s) to call callee passing two arguments:
scratch_slot
must be <= dr_max_opnd_accessible_spill_slot(). scratch_slot
is used internally to this routine and will be clobbered. void dr_insert_read_tls_field | ( | void * | drcontext, |
instrlist_t * | ilist, | ||
instr_t * | where, | ||
reg_id_t | reg | ||
) |
Inserts into ilist
prior to where
meta-instruction(s) to read into the general-purpose full-size register reg
from the user-controlled drcontext field for this thread. Reads from the same field as dr_get_tls_field().
bool dr_insert_set_stolen_reg_value | ( | void * | drcontext, |
instrlist_t * | ilist, | ||
instr_t * | instr, | ||
reg_id_t | reg | ||
) |
Insert code to set the value of register reg
as the application value of the register stolen by DynamoRIO Reference Register Stolen by DynamoRIO for more information.
void dr_insert_ubr_instrumentation | ( | void * | drcontext, |
instrlist_t * | ilist, | ||
instr_t * | instr, | ||
void * | callee | ||
) |
Assumes that instr
is a direct, near, unconditional branch. Inserts into ilist
prior to instr
instruction(s) to call callee passing two arguments:
void dr_insert_write_tls_field | ( | void * | drcontext, |
instrlist_t * | ilist, | ||
instr_t * | where, | ||
reg_id_t | reg | ||
) |
Inserts into ilist
prior to where
meta-instruction(s) to write the general-purpose full-size register reg
to the user-controlled drcontext field for this thread. Writes to the same field as dr_set_tls_field().
dr_spill_slot_t dr_max_opnd_accessible_spill_slot | ( | void | ) |
Returns the largest dr_spill_slot_t that can be accessed with an opnd_t from dr_reg_spill_slot_opnd().
bool dr_mcontext_to_context | ( | CONTEXT * | dst, |
dr_mcontext_t * | src | ||
) |
Copies the machine state in src
into dst
. Sets the ContextFlags
field of dst
to reflect the flags
field of 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 dst
is allocated and initialized properly in order to contain multimedia processor state, if DR_MC_MULTIMEDIA is set in the flags
field of src
.
The current segment register values are filled in under the assumption that this context is for the calling thread.
dst
. bool dr_mcontext_xmm_fields_valid | ( | void | ) |
Returns true if the xmm fields in dr_mcontext_t are valid (i.e., whether the underlying processor supports SSE).
uint dr_prepare_for_call | ( | void * | drcontext, |
instrlist_t * | ilist, | ||
instr_t * | instr | ||
) |
Inserts into ilist
prior to 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).
reg_t dr_read_saved_reg | ( | void * | drcontext, |
dr_spill_slot_t | slot | ||
) |
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 slot
by dr_save_reg().
bool dr_redirect_execution | ( | dr_mcontext_t * | context | ) |
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 mcontext
(including pc, and including the xmm fields that are valid according to dr_mcontext_xmm_fields_valid()). The flags field of context
must contain DR_MC_ALL; using a partial set of fields is not suported.
byte* dr_redirect_native_target | ( | void * | drcontext | ) |
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 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.
opnd_t dr_reg_spill_slot_opnd | ( | void * | drcontext, |
dr_spill_slot_t | slot | ||
) |
Returns an opnd_t that directly accesses the spill slot slot
. Only slots <= dr_max_opnd_accessible_spill_slot() can be used with this routine.
slot
must be <= dr_max_opnd_accessible_spill_slot() int dr_remove_it_instrs | ( | void * | drcontext, |
instrlist_t * | ilist | ||
) |
Removes all OP_it instructions from 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.
void dr_restore_app_stack | ( | void * | drcontext, |
instrlist_t * | ilist, | ||
instr_t * | where | ||
) |
Inserts into ilist
prior to where
meta-instruction(s) to restore into esp the value saved by dr_swap_to_clean_stack().
void dr_restore_arith_flags | ( | void * | drcontext, |
instrlist_t * | ilist, | ||
instr_t * | where, | ||
dr_spill_slot_t | slot | ||
) |
Inserts into ilist
prior to where
meta-instruction(s) to restore the 6 arithmetic flags, assuming they were saved using dr_save_arith_flags() with slot slot
and that xax holds the same value it did after the save.
void dr_restore_arith_flags_from_reg | ( | void * | drcontext, |
instrlist_t * | ilist, | ||
instr_t * | where, | ||
reg_id_t | reg | ||
) |
Inserts into ilist
prior to where
meta-instruction(s) to restore the arithmetic flags (6 arithmetic flags on X86 or APSR on ARM) from reg
. The caller must ensure that reg
contains the program status flags, most likely from dr_save_arith_flags_to_reg().
void dr_restore_arith_flags_from_xax | ( | void * | drcontext, |
instrlist_t * | ilist, | ||
instr_t * | where | ||
) |
Inserts into ilist
prior to 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().
void dr_restore_reg | ( | void * | drcontext, |
instrlist_t * | ilist, | ||
instr_t * | where, | ||
reg_id_t | reg, | ||
dr_spill_slot_t | slot | ||
) |
Inserts into ilist
prior to where
meta-instruction(s) to restore the register reg
from the spill slot slot
. See dr_save_reg() for notes on lifetime and alternative access to spill slots.
void dr_save_arith_flags | ( | void * | drcontext, |
instrlist_t * | ilist, | ||
instr_t * | where, | ||
dr_spill_slot_t | slot | ||
) |
Inserts into ilist
prior to where
meta-instruction(s) to save the 6 arithmetic flags into xax after first saving xax to the spill slot slot
. This is equivalent to dr_save_reg() of xax to slot
followed by lahf and seto al instructions. See dr_restore_arith_flags().
void dr_save_arith_flags_to_reg | ( | void * | drcontext, |
instrlist_t * | ilist, | ||
instr_t * | where, | ||
reg_id_t | reg | ||
) |
Inserts into ilist
prior to where
meta-instruction(s) to save the arithmetic flags (6 arithmetic flags on X86 or APSR on ARM) into reg
. If the caller wishes to use reg
between saving and restoring these flags, they must save and restore reg
, potentially using dr_save_reg()/dr_restore_reg(). If the caller needs to save both the current value of reg
and the flags stored to reg
by this routine, they must use separate spill slots, or they will overwrite the original reg
value in memory.
reg
; the caller must ensure reg
is dead or saved at where
. void dr_save_arith_flags_to_xax | ( | void * | drcontext, |
instrlist_t * | ilist, | ||
instr_t * | where | ||
) |
Inserts into ilist
prior to 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.
where
. void dr_save_reg | ( | void * | drcontext, |
instrlist_t * | ilist, | ||
instr_t * | where, | ||
reg_id_t | reg, | ||
dr_spill_slot_t | slot | ||
) |
Inserts into ilist
prior to where
meta-instruction(s) to save the register reg
in the spill slot 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()).
bool dr_set_isa_mode | ( | void * | drcontext, |
dr_isa_mode_t | new_mode, | ||
dr_isa_mode_t *old_mode | OUT | ||
) |
The decode and encode routines use a per-thread persistent flag that indicates which processor mode to use. This routine sets that flag to the indicated value and optionally returns the old value. Be sure to restore the old value prior to any further application execution to avoid problems in mis-interpreting application code.
bool dr_set_mcontext | ( | void * | drcontext, |
dr_mcontext_t * | context | ||
) |
Sets the fields of the application machine context selected by the flags field of context
to the values in context
.
This routine may only be called from:
flags
field of 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 for_trace
and translating
are false, and for trace creation only when translating
is false.Ignores the pc field, except for kernel transfer events.
If the size field of 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 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.
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. void dr_swap_to_clean_stack | ( | void * | drcontext, |
instrlist_t * | ilist, | ||
instr_t * | where | ||
) |
Inserts into ilist
prior to where
meta-instruction(s) to save the current esp and switch to this thread's DR stack.
void dr_write_saved_reg | ( | void * | drcontext, |
dr_spill_slot_t | slot, | ||
reg_t | value | ||
) |
Can be used from a clean call to modify the value saved in the spill slot slot
by dr_save_reg() such that a later dr_restore_reg() will see the new value.
bool get_x86_mode | ( | void * | drcontext | ) |
The decode and encode routines use a per-thread persistent flag that indicates whether to treat code as 32-bit (x86) or 64-bit (x64). This routine returns the value of that flag.
void instrlist_insert_mov_immed_ptrsz | ( | void * | drcontext, |
ptr_int_t | val, | ||
opnd_t | dst, | ||
instrlist_t * | ilist, | ||
instr_t * | where, | ||
instr_t **first | OUT, | ||
instr_t **last | OUT | ||
) |
Create meta instructions for storing pointer-size integer val
to dst
, and then insert them into ilist
prior to where
. Pointers to the first and last created meta instructions are returned in first
and 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 | OUT, | ||
instr_t **last | OUT | ||
) |
Create meta instructions for storing the address of src_inst
to dst
, and then insert them into ilist
prior to where
. The encode_estimate
parameter, used only for 64-bit mode, indicates whether the final address of 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 first
and 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_push_immed_ptrsz | ( | void * | drcontext, |
ptr_int_t | val, | ||
instrlist_t * | ilist, | ||
instr_t * | where, | ||
instr_t **first | OUT, | ||
instr_t **last | OUT | ||
) |
Create meta instructions for pushing pointer-size integer val
on the stack, and then insert them into ilist
prior to where
. Pointers to the first and last created meta instructions are returned in first
and 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 | OUT, | ||
instr_t **last | OUT | ||
) |
Create meta instructions for pushing the address of src_inst
on the stack, and then insert them into ilist
prior to where
. The encode_estimate
parameter, used only for 64-bit mode, indicates whether the final address of 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 first
and last
, unless only one meta instruction is created, in which case NULL is returned in last.
void instrlist_meta_append | ( | instrlist_t * | ilist, |
instr_t * | instr | ||
) |
Inserts instr
as a non-application instruction onto the end of ilist
void instrlist_meta_fault_append | ( | instrlist_t * | ilist, |
instr_t * | instr | ||
) |
Inserts instr
as a non-application instruction that can fault (see instr_set_meta_may_fault()) onto the end of ilist
.
Inserts instr
as a non-application instruction that can fault (see instr_set_meta_may_fault()) into ilist
after where
.
Inserts instr
as a non-application instruction that can fault (see instr_set_meta_may_fault()) into ilist
prior to where
.
Inserts instr
as a non-application instruction into ilist
after where
.
Inserts instr
as a non-application instruction into ilist
prior to where
.
bool set_x86_mode | ( | void * | drcontext, |
bool | x86 | ||
) |
The decode and encode routines use a per-thread persistent flag that indicates whether to treat code as 32-bit (x86) or 64-bit (x64). This routine sets that flag to the indicated value and returns the old value. Be sure to restore the old value prior to any further application execution to avoid problems in mis-interpreting application code.