DynamoRIO
|
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, DRREG_USER_RESTORES_AT_BB_END = 0x004, DRREG_HANDLE_MULTI_PHASE_SLOT_RESERVATIONS = 0x008 } |
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 (DR_PARAM_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, DR_PARAM_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, DR_PARAM_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, DR_PARAM_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, DR_PARAM_INOUT reg_id_t *swap) |
DR_EXPORT drreg_status_t | drreg_restore_all (void *drcontext, instrlist_t *bb, instr_t *where) |
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 DR_PARAM_OUT, bool *respill_needed DR_PARAM_OUT) |
DR_EXPORT drreg_status_t | drreg_statelessly_restore_all (void *drcontext, instrlist_t *ilist, instr_t *where_restore, instr_t *where_respill, bool *restore_needed DR_PARAM_OUT, bool *respill_needed DR_PARAM_OUT) |
DR_EXPORT drreg_status_t | drreg_reservation_info (void *drcontext, reg_id_t reg, opnd_t *opnd DR_PARAM_OUT, bool *is_dr_slot DR_PARAM_OUT, uint *tls_offs DR_PARAM_OUT) |
DR_EXPORT drreg_status_t | drreg_reservation_info_ex (void *drcontext, reg_id_t reg, drreg_reserve_info_t *info DR_PARAM_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 DR_PARAM_OUT, bool *restore DR_PARAM_OUT, reg_id_t *reg_spilled DR_PARAM_OUT) |
Detailed Description
Macro Definition Documentation
◆ DRMGR_PRIORITY_NAME_DRREG_FAULT
#define DRMGR_PRIORITY_NAME_DRREG_FAULT "drreg_fault" |
Name of drreg fault handling event.
◆ DRMGR_PRIORITY_NAME_DRREG_HIGH
#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.
◆ DRMGR_PRIORITY_NAME_DRREG_LOW
#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 Documentation
◆ drreg_options_t
typedef struct _drreg_options_t drreg_options_t |
Specifies the options when initializing drreg.
◆ drreg_reserve_info_t
typedef struct _drreg_reserve_info_t drreg_reserve_info_t |
Contains information about a register's reservation and restoration status.
Enumeration Type Documentation
◆ anonymous enum
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.
◆ drreg_bb_properties_t
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. |
DRREG_USER_RESTORES_AT_BB_END | Turns off register restoration at the end of the block. Note that it is still required that registers have their original values at the end of a basic block. Therefore, restoration needs to be handled by the user manually, usually via drreg_restore_all(). |
DRREG_HANDLE_MULTI_PHASE_SLOT_RESERVATIONS | Turns on stricter logic to find free register spill slots. This avoids conflicts with slots used to spill some register value in prior instrumentation passes. An example usage is in drx_expand_scatter_gather() which is used in the app2app pass and requires spilling of registers to slots that may conflict with slots used during later instrumentation passes. Using this option also makes spill slots used in prior phases less available in future phases; the current logic skips over a slot if there's a usage found anywhere later in the bb added by any previous phase. So it requires additional spill slots as well. |
◆ drreg_status_t
enum drreg_status_t |
Success code for each drreg operation
Function Documentation
◆ drreg_aflags_liveness()
DR_EXPORT drreg_status_t drreg_aflags_liveness | ( | void * | drcontext, |
instr_t * | inst, | ||
DR_PARAM_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.
- Returns
- whether successful or an error code on failure.
◆ drreg_are_aflags_dead()
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.
- Returns
- whether successful or an error code on failure.
◆ drreg_exit()
DR_EXPORT drreg_status_t drreg_exit | ( | void | ) |
Cleans up the drreg extension.
- Returns
- whether successful or an error code on failure.
◆ drreg_get_app_value()
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.
- Returns
- whether successful or an error code on failure.
◆ drreg_init()
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).
- Parameters
-
[in] ops Specifies the optional parameters that control how drreg operates.
- Returns
- whether successful or an error code on failure.
◆ drreg_init_and_fill_vector()
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().
- Returns
- whether successful or an error code on failure.
◆ drreg_is_instr_spill_or_restore()
DR_EXPORT drreg_status_t drreg_is_instr_spill_or_restore | ( | void * | drcontext, |
instr_t * | instr, | ||
bool *spill | DR_PARAM_OUT, | ||
bool *restore | DR_PARAM_OUT, | ||
reg_id_t *reg_spilled | DR_PARAM_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.
- Returns
- whether successful or an error code on failure.
◆ drreg_is_register_dead()
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.
- Returns
- whether successful or an error code on failure.
◆ drreg_max_slots_used()
DR_EXPORT drreg_status_t drreg_max_slots_used | ( | DR_PARAM_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.
- Parameters
-
[out] max The maximum number of spill slots used is written here.
- Returns
- whether successful or an error code on failure. In release build, this routine always fails.
◆ drreg_reservation_info()
DR_EXPORT drreg_status_t drreg_reservation_info | ( | void * | drcontext, |
reg_id_t | reg, | ||
opnd_t *opnd | DR_PARAM_OUT, | ||
bool *is_dr_slot | DR_PARAM_OUT, | ||
uint *tls_offs | DR_PARAM_OUT | ||
) |
Returns information about the TLS slot assigned to reg
, which must be a currently-reserved register. To query information about the arithmetic flags, pass DR_REG_NULL for reg
.
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
.
- Returns
- whether successful or an error code on failure.
◆ drreg_reservation_info_ex()
DR_EXPORT drreg_status_t drreg_reservation_info_ex | ( | void * | drcontext, |
reg_id_t | reg, | ||
drreg_reserve_info_t *info | DR_PARAM_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
.
- Returns
- whether successful or an error code on failure.
◆ drreg_reserve_aflags()
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.
TODO i#3823: Support multi-phase use. This will require adding support to spill aflags to slots other than AFLAGS_SLOT.
- Returns
- whether successful or an error code on failure.
◆ drreg_reserve_dead_register()
DR_EXPORT drreg_status_t drreg_reserve_dead_register | ( | void * | drcontext, |
instrlist_t * | ilist, | ||
instr_t * | where, | ||
drvector_t * | reg_allowed, | ||
DR_PARAM_OUT reg_id_t * | reg | ||
) |
Identical to drreg_reserve_register() except returns failure if no register is available that does not require a spill.
- Returns
- whether successful or an error code on failure.
◆ drreg_reserve_register()
DR_EXPORT drreg_status_t drreg_reserve_register | ( | void * | drcontext, |
instrlist_t * | ilist, | ||
instr_t * | where, | ||
drvector_t * | reg_allowed, | ||
DR_PARAM_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
.
- Returns
- whether successful or an error code on failure.
◆ drreg_restore_all()
DR_EXPORT drreg_status_t drreg_restore_all | ( | void * | drcontext, |
instrlist_t * | bb, | ||
instr_t * | where | ||
) |
Restores the spilled value (typically the application value) for all registers and flags at where
.
◆ drreg_restore_app_aflags()
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.
TODO i#3823: Support multi-phase use. This will require adding support to spill aflags to slots other than AFLAGS_SLOT.
- Returns
- whether successful or an error code on failure.
◆ drreg_restore_app_values()
DR_EXPORT drreg_status_t drreg_restore_app_values | ( | void * | drcontext, |
instrlist_t * | ilist, | ||
instr_t * | where, | ||
opnd_t | opnd, | ||
DR_PARAM_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.
- Returns
- whether successful or an error code on failure. On failure, any values that were already restored are not undone.
◆ drreg_set_bb_properties()
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.
- Returns
- whether successful or an error code on failure.
◆ drreg_set_vector_entry()
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().
- Returns
- whether successful or an error code on failure.
◆ drreg_statelessly_restore_all()
DR_EXPORT drreg_status_t drreg_statelessly_restore_all | ( | void * | drcontext, |
instrlist_t * | ilist, | ||
instr_t * | where_restore, | ||
instr_t * | where_respill, | ||
bool *restore_needed | DR_PARAM_OUT, | ||
bool *respill_needed | DR_PARAM_OUT | ||
) |
Invokes drreg_statelessly_restore_app_value() for the arithmetic flags and every general-purpose register. Returns the logical OR of the 'restore_needed' and 'respill_needed' results from all of the drreg_statelessly_restore_app_value() calls. If any step results in an error, that error is returned and the output parameters are not filled in (despite partial restores potentially remaining in place).
◆ drreg_statelessly_restore_app_value()
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 | DR_PARAM_OUT, | ||
bool *respill_needed | DR_PARAM_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.
For correct operation on x86 in the case when aflags are in xax and this routine is invoked to get app value of xax, there shouldn't be any new reservation between where_restore
and where_respill
that may write to a spill slot and clobber the temporary slot used in this routine.
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.
- Returns
- whether successful or an error code on failure.
◆ drreg_unreserve_aflags()
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.
- Returns
- whether successful or an error code on failure.
◆ drreg_unreserve_register()
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.
- Returns
- whether successful or an error code on failure.