DynamoRIO
Register Usage Coordinator

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

Specifies the options when initializing drreg.

◆ 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.

Enumerator
DRMGR_PRIORITY_INSERT_DRREG_HIGH 

Priority of drreg analysis and pre-insert

DRMGR_PRIORITY_INSERT_DRREG_LOW 

Priority of drreg post-insert

DRMGR_PRIORITY_FAULT_DRREG 

Priority of drreg fault handling event

◆ 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

Success code for each drreg operation

Enumerator
DRREG_SUCCESS 

Operation succeeded.

DRREG_ERROR 

Operation failed.

DRREG_ERROR_INVALID_PARAMETER 

Operation failed: invalid parameter

DRREG_ERROR_FEATURE_NOT_AVAILABLE 

Operation failed: not available

DRREG_ERROR_REG_CONFLICT 

Operation failed: register conflict

DRREG_ERROR_IN_USE 

Operation failed: resource already in use

DRREG_ERROR_OUT_OF_SLOTS 

Operation failed: no more TLS slots

DRREG_ERROR_NO_APP_VALUE 

Operation failed: app value not available. Set conservative in drreg_options_t to avoid this error.

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]opsSpecifies 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]maxThe 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.