Data Structures | |
struct | _drreg_options_t |
struct | _drreg_reserve_info_t |
Macros | |
#define | DRMGR_PRIORITY_NAME_DRREG_HIGH "drreg_high" |
#define | DRMGR_PRIORITY_NAME_DRREG_LOW "drreg_low" |
#define | DRMGR_PRIORITY_NAME_DRREG_FAULT "drreg_fault" |
Typedefs | |
typedef struct _drreg_options_t | drreg_options_t |
typedef struct _drreg_reserve_info_t | drreg_reserve_info_t |
Enumerations | |
enum | drreg_status_t { DRREG_SUCCESS, DRREG_ERROR, DRREG_ERROR_INVALID_PARAMETER, DRREG_ERROR_FEATURE_NOT_AVAILABLE, DRREG_ERROR_REG_CONFLICT, DRREG_ERROR_IN_USE, DRREG_ERROR_OUT_OF_SLOTS, DRREG_ERROR_NO_APP_VALUE } |
enum | { DRMGR_PRIORITY_INSERT_DRREG_HIGH = -7500, DRMGR_PRIORITY_INSERT_DRREG_LOW = 7500, DRMGR_PRIORITY_FAULT_DRREG = -7500 } |
enum | drreg_bb_properties_t { DRREG_CONTAINS_SPANNING_CONTROL_FLOW = 0x001, DRREG_IGNORE_CONTROL_FLOW = 0x002 } |
Functions | |
DR_EXPORT drreg_status_t | drreg_init (drreg_options_t *ops) |
DR_EXPORT drreg_status_t | drreg_exit (void) |
DR_EXPORT drreg_status_t | drreg_max_slots_used (OUT uint *max) |
DR_EXPORT drreg_status_t | drreg_reserve_aflags (void *drcontext, instrlist_t *ilist, instr_t *where) |
DR_EXPORT drreg_status_t | drreg_unreserve_aflags (void *drcontext, instrlist_t *ilist, instr_t *where) |
DR_EXPORT drreg_status_t | drreg_aflags_liveness (void *drcontext, instr_t *inst, OUT uint *value) |
DR_EXPORT drreg_status_t | drreg_are_aflags_dead (void *drcontext, instr_t *inst, bool *dead) |
DR_EXPORT drreg_status_t | drreg_restore_app_aflags (void *drcontext, instrlist_t *ilist, instr_t *where) |
DR_EXPORT drreg_status_t | drreg_reserve_register (void *drcontext, instrlist_t *ilist, instr_t *where, drvector_t *reg_allowed, OUT reg_id_t *reg) |
DR_EXPORT drreg_status_t | drreg_reserve_dead_register (void *drcontext, instrlist_t *ilist, instr_t *where, drvector_t *reg_allowed, OUT reg_id_t *reg) |
DR_EXPORT drreg_status_t | drreg_init_and_fill_vector (drvector_t *vec, bool allowed) |
DR_EXPORT drreg_status_t | drreg_set_vector_entry (drvector_t *vec, reg_id_t reg, bool allowed) |
DR_EXPORT drreg_status_t | drreg_get_app_value (void *drcontext, instrlist_t *ilist, instr_t *where, reg_id_t app_reg, reg_id_t dst_reg) |
DR_EXPORT drreg_status_t | drreg_restore_app_values (void *drcontext, instrlist_t *ilist, instr_t *where, opnd_t opnd, INOUT reg_id_t *swap) |
DR_EXPORT drreg_status_t | drreg_statelessly_restore_app_value (void *drcontext, instrlist_t *ilist, reg_id_t reg, instr_t *where_restore, instr_t *where_respill, bool *restore_needed OUT, bool *respill_needed OUT) |
DR_EXPORT drreg_status_t | drreg_reservation_info (void *drcontext, reg_id_t reg, opnd_t *opnd OUT, bool *is_dr_slot OUT, uint *tls_offs OUT) |
DR_EXPORT drreg_status_t | drreg_reservation_info_ex (void *drcontext, reg_id_t reg, drreg_reserve_info_t *info OUT) |
DR_EXPORT drreg_status_t | drreg_unreserve_register (void *drcontext, instrlist_t *ilist, instr_t *where, reg_id_t reg) |
DR_EXPORT drreg_status_t | drreg_is_register_dead (void *drcontext, reg_id_t reg, instr_t *inst, bool *dead) |
DR_EXPORT drreg_status_t | drreg_set_bb_properties (void *drcontext, drreg_bb_properties_t flags) |
DR_EXPORT drreg_status_t | drreg_is_instr_spill_or_restore (void *drcontext, instr_t *instr, bool *spill OUT, bool *restore OUT, reg_id_t *reg_spilled OUT) |
#define DRMGR_PRIORITY_NAME_DRREG_FAULT "drreg_fault" |
Name of drreg fault handling event.
#define DRMGR_PRIORITY_NAME_DRREG_HIGH "drreg_high" |
Name of drreg instrumentation pass priorities for analysis and insert steps that are meant to take place before any tool actions.
#define DRMGR_PRIORITY_NAME_DRREG_LOW "drreg_low" |
Name of drreg instrumentation pass priorities for analysis and insert steps that are meant to take place after any tool actions.
typedef struct _drreg_options_t drreg_options_t |
Specifies the options when initializing drreg.
typedef struct _drreg_reserve_info_t drreg_reserve_info_t |
Contains information about a register's reservation and restoration status.
anonymous enum |
Priorities of drmgr instrumentation passes used by drreg. Users of drreg can use the name DRMGR_PRIORITY_NAME_DRREG in the drmgr_priority_t.before field or can use these numeric priorities in the drmgr_priority_t.priority field to ensure proper instrumentation pass ordering.
Flags passed to drreg_set_bb_properties().
Enumerator | |
---|---|
DRREG_CONTAINS_SPANNING_CONTROL_FLOW | drreg was designed for linear control flow and assumes that it can safely wait to restore an unreserved scratch register across application instructions. If a client inserts internal control flow that crosses application instructions (hence "spanning"), and the client is not explicitly ensuring that each forward jump contains the same set of saved scratch registers at its source and target (typically done by saving all scratch registers needed inside control flow prior to any forward branches), the client should set this property either prior to the drmgr insertion phase or as early as possible in the insertion phase. Setting this property causes application instructions to become barriers to spilled scratch registers that have been unreserved but have not yet been lazily restored. drreg will still collapse adjacent spill+restore pairs for the same app instr. |
DRREG_IGNORE_CONTROL_FLOW | drreg was designed for linear control flow. Normally, drreg disables optimizations if it sees any kind of internal control flow (viz., a branch with an instr_t target) that was added during drmgr's app2app phase, which includes flow added by drutil_expand_rep_string(). The primary consequence of disabling optimizations means that application instructions become barriers to spilled scratch registers that have been unreserved but have not yet been lazily restored, which are restored prior to each application instruction. If this flag is set, drreg assumes that internal control flow either does not cross application instructions or that the client is ensuring that each forward jump contains the same set of saved scratch registers at its source and target (typically done by saving all scratch registers needed inside control flow prior to any forward branches). Such scratch registers are then restored prior to each application instruction. |
enum drreg_status_t |
Success code for each drreg operation
DR_EXPORT drreg_status_t drreg_aflags_liveness | ( | void * | drcontext, |
instr_t * | inst, | ||
OUT uint * | value | ||
) |
Returns in value
EFLAGS_READ_6 bits telling which arithmetic flags are live at the point of inst
. If called during drmgr's insertion phase, inst
must be the current application instruction.
DR_EXPORT drreg_status_t drreg_are_aflags_dead | ( | void * | drcontext, |
instr_t * | inst, | ||
bool * | dead | ||
) |
Returns in dead
whether the arithmetic flags are all dead at the point of inst
. If called during drmgr's insertion phase, inst
must be the current application instruction.
DR_EXPORT drreg_status_t drreg_exit | ( | void | ) |
Cleans up the drreg extension.
DR_EXPORT drreg_status_t drreg_get_app_value | ( | void * | drcontext, |
instrlist_t * | ilist, | ||
instr_t * | where, | ||
reg_id_t | app_reg, | ||
reg_id_t | dst_reg | ||
) |
Inserts instructions at where
in ilist
to retrieve the application value for app_reg
into dst_reg
. This will automatically be done for reserved registers prior to an application instruction that reads app_reg
, but sometimes instrumentation needs to read the application value of a register that has been reserved. If app_reg
is a dead register, DRREG_ERROR_NO_APP_VALUE may be returned. Set conservative
in drreg_options_t
to avoid this error.
If called during drmgr's insertion phase, where
must be the current application instruction.
On ARM, asking to place the application value of the register returned by dr_get_stolen_reg() into itself is not supported. Instead the caller should use dr_insert_get_stolen_reg_value() and opnd_replace_reg() to swap the use of the stolen register within a tool instruction with a scratch register.
DR_EXPORT drreg_status_t drreg_init | ( | drreg_options_t * | ops | ) |
Initializes the drreg extension. Must be called prior to any of the other routines. Can be called multiple times (by separate components, normally) but each call must be paired with a corresponding call to drreg_exit(). The fields of ops
are combined from multiple calls as described in the documentation for each field. Typically the end-user tool itself specifies these options, with most other library components not directly interacting with drreg (libraries often take in scratch registers from the caller for most of their operations).
[in] | ops | Specifies the optional parameters that control how drreg operates. |
DR_EXPORT drreg_status_t drreg_init_and_fill_vector | ( | drvector_t * | vec, |
bool | allowed | ||
) |
Initializes vec
to hold DR_NUM_GPR_REGS entries, each either set to NULL if allowed
is false or a non-NULL value if allowed
is true. This is intendend as a convenience routine for setting up the reg_allowed
parameter to drreg_reserve_register().
DR_EXPORT drreg_status_t drreg_is_instr_spill_or_restore | ( | void * | drcontext, |
instr_t * | instr, | ||
bool *spill | OUT, | ||
bool *restore | OUT, | ||
reg_id_t *reg_spilled | OUT | ||
) |
Analyzes instr
and returns whether it is a drreg register spill in spill
, a drreg register restore in restore
, and which register is being spilled or restored in reg_spilled
. Each output parameter is optional and may be NULL. If DR's spill slots are being used (see drreg_options_t.num_spill_slots), this routine may not be able to distinguish a drreg spill or restore from some other spill or restore.
DR_EXPORT drreg_status_t drreg_is_register_dead | ( | void * | drcontext, |
reg_id_t | reg, | ||
instr_t * | inst, | ||
bool * | dead | ||
) |
Returns in dead
whether the register reg
is dead at the point of inst
. If called during drmgr's insertion phase, inst
must be the current application instruction.
DR_EXPORT drreg_status_t drreg_max_slots_used | ( | OUT uint * | max | ) |
In debug build, drreg tracks the maximum simultaneous number of spill slots in use. This can help a user to tune drreg_options_t.num_spill_slots.
[out] | max | The maximum number of spill slots used is written here. |
DR_EXPORT drreg_status_t drreg_reservation_info | ( | void * | drcontext, |
reg_id_t | reg, | ||
opnd_t *opnd | OUT, | ||
bool *is_dr_slot | OUT, | ||
uint *tls_offs | OUT | ||
) |
Returns information about the TLS slot assigned to reg
, which must be a currently-reserved register.
If opnd
is non-NULL, returns an opnd_t in opnd
that references the TLS slot assigned to reg
. If too many slots are in use and reg
is stored in a non-directly-addressable slot, returns a null opnd_t in opnd
.
If is_dr_slot
is non-NULL, returns true if the slot is a DR slot (and can thus be accessed by dr_read_saved_reg()) and false if the slot is inside the dr_raw_tls_calloc() allocation used by drreg.
If tls_offs
is non-NULL, if the slot is a DR slot, returns the DR slot index; otherwise, returns the offset from the TLS base of the slot assigned to reg
.
DR_EXPORT drreg_status_t drreg_reservation_info_ex | ( | void * | drcontext, |
reg_id_t | reg, | ||
drreg_reserve_info_t *info | OUT | ||
) |
Returns information about the reservation and restoration status of reg
. The size
field of info
must be set before calling. To query information about the arithmetic flags, pass DR_REG_NULL for reg
.
DR_EXPORT drreg_status_t drreg_reserve_aflags | ( | void * | drcontext, |
instrlist_t * | ilist, | ||
instr_t * | where | ||
) |
Requests exclusive use of the arithmetic flags register. Spills the application value at where
in ilist
, if necessary. When used during drmgr's insertion phase, optimizations such as keeping the application flags value in a register and eliding duplicate spills and restores will be automatically applied. If called during drmgr's insertion phase, where
must be the current application instruction.
DR_EXPORT drreg_status_t drreg_reserve_dead_register | ( | void * | drcontext, |
instrlist_t * | ilist, | ||
instr_t * | where, | ||
drvector_t * | reg_allowed, | ||
OUT reg_id_t * | reg | ||
) |
Identical to drreg_reserve_register() except returns failure if no register is available that does not require a spill.
DR_EXPORT drreg_status_t drreg_reserve_register | ( | void * | drcontext, |
instrlist_t * | ilist, | ||
instr_t * | where, | ||
drvector_t * | reg_allowed, | ||
OUT reg_id_t * | reg | ||
) |
Requests exclusive use of an application register, spilling the application value at where
in ilist
if necessary. The register chosen is returned in reg
.
When used during drmgr's insertion phase, optimizations such as keeping the application flags value in a register and eliding duplicate spills and restores will be automatically applied. If called during drmgr's insertion phase, where
must be the current application instruction.
If reg_allowed
is non-NULL, only registers from the specified set will be considered, where reg_allowed
must be a vector with one entry for each general-purpose register in [DR_REG_START_GPR..DR_REG_STOP_GPR] where a NULL entry indicates not allowed and any non-NULL entry indicates allowed. The drreg_init_and_fill_vector() routine can be used to set up reg_allowed
.
DR_EXPORT drreg_status_t drreg_restore_app_aflags | ( | void * | drcontext, |
instrlist_t * | ilist, | ||
instr_t * | where | ||
) |
This routine ensures that the application's value for the arithmetic flags is in place prior to where
. This is automatically done when the flags are reserved prior to an application instruction, but sometimes instrumentation needs to read the value of the flags. This is intended as a convenience barrier for lazy restores performed by drreg.
If called during drmgr's insertion phase, where
must be the current application instruction.
DR_EXPORT drreg_status_t drreg_restore_app_values | ( | void * | drcontext, |
instrlist_t * | ilist, | ||
instr_t * | where, | ||
opnd_t | opnd, | ||
INOUT reg_id_t * | swap | ||
) |
This is a convenience routine that calls drreg_get_app_value() for every register used by opnd
, with that register passed as the application and destination registers. This routine will write to reserved as well as unreserved registers. This is intended as a convenience barrier for lazy restores performed by drreg.
If called during drmgr's insertion phase, where
must be the current application instruction.
On ARM, asking to place the application value of the register returned by dr_get_stolen_reg() into itself is not supported. If opnd
uses the stolen register, this routine will swap it for a scratch register. This scratch register will be *swap
if *swap
is not DR_REG_NULL; otherwise, drreg_reserve_register() with NULL for reg_allowed
will be called, and the result returned in *swap
. It is up to the caller to un-reserve the register in that case.
DR_EXPORT drreg_status_t drreg_set_bb_properties | ( | void * | drcontext, |
drreg_bb_properties_t | flags | ||
) |
May only be called during drmgr's app2app, analysis, or insertion phase. Sets the given properties for the current basic block being instrumented.
DR_EXPORT drreg_status_t drreg_set_vector_entry | ( | drvector_t * | vec, |
reg_id_t | reg, | ||
bool | allowed | ||
) |
Sets the entry in vec
at index reg
minus DR_REG_START_GPR to NULL if allowed
is false or a non-NULL value if allowed
is true. This is intendend as a convenience routine for setting up the reg_allowed
parameter to drreg_reserve_register().
DR_EXPORT drreg_status_t drreg_statelessly_restore_app_value | ( | void * | drcontext, |
instrlist_t * | ilist, | ||
reg_id_t | reg, | ||
instr_t * | where_restore, | ||
instr_t * | where_respill, | ||
bool *restore_needed | OUT, | ||
bool *respill_needed | OUT | ||
) |
This routine is meant for use with instrumentation that uses separate control flow paths, such as a fastpath and a slowpath, where the slowpath needs access to the full application state yet must retain scratch register parity with the fastpath. The application value for reg
is restored into reg
at where_restore
, but internal drreg state is not updated to reflect this. Furthermore, if doing so affects subsequent behavior, such as when reg
is being used to hold the preserved application value for another register or flags, instructions are inserted at where_respill
to restore the state, such that where_respill
will operate correctly whether where_restore
was executed or not. The optional output parameters restore_needed
and respill_needed
are set to indicate whether instructions were inserted at where_restore
and where_respill
, respectively.
The results from drreg_reservation_info_ex() can be used to predict the behavior of this routine. A restore is needed if !drreg_reserve_info_t.holds_app_value. and drreg_reserve_info_t.app_value_retained. A respill is needed if a restore is needed and drreg_reserve_info_t.opnd is a register.
If app_reg
is a dead register, DRREG_ERROR_NO_APP_VALUE may be returned. Set conservative
in drreg_options_t
to avoid this error.
If called during drmgr's insertion phase, where
must be the current application instruction.
To restore the arithmetic flags, pass DR_REG_NULL for reg
.
On ARM, passing reg
equal to dr_get_stolen_reg() is not supported.
DR_EXPORT drreg_status_t drreg_unreserve_aflags | ( | void * | drcontext, |
instrlist_t * | ilist, | ||
instr_t * | where | ||
) |
Terminates exclusive use of the arithmetic flags register. Restores the application value at where
in ilist
, if necessary. If called during drmgr's insertion phase, where
must be the current application instruction.
DR_EXPORT drreg_status_t drreg_unreserve_register | ( | void * | drcontext, |
instrlist_t * | ilist, | ||
instr_t * | where, | ||
reg_id_t | reg | ||
) |
Terminates exclusive use of the register reg
. Restores the application value at where
in ilist
, if necessary. If called during drmgr's insertion phase, where
must be the current application instruction.