radare2/libr/include/r_reg.h

217 lines
6.3 KiB
C
Raw Normal View History

2014-03-27 15:34:17 +00:00
#ifndef R2_REG_H
#define R2_REG_H
#include <r_types.h>
#include <r_util.h>
2014-01-07 03:29:56 +00:00
2015-12-08 23:41:44 +00:00
R_LIB_VERSION_HEADER (r_reg);
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
/*
* various CPUs have registers within various types/classes
* this enum aims to cover them all.
*/
typedef enum {
R_REG_TYPE_GPR,
R_REG_TYPE_DRX,
R_REG_TYPE_FPU,
R_REG_TYPE_MMX,
R_REG_TYPE_XMM,
R_REG_TYPE_FLG,
R_REG_TYPE_SEG,
R_REG_TYPE_LAST,
R_REG_TYPE_ALL = -1, // TODO; rename to ANY
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
} RRegisterType;
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
/*
* pretty much all CPUs share some common registers
* this enum aims to create an abstraction to ease cross-arch handling.
*/
typedef enum {
R_REG_NAME_PC, // program counter
R_REG_NAME_SP, // stack pointer
R_REG_NAME_SR, // status register
R_REG_NAME_BP, // base pointer
2015-12-31 13:10:11 +00:00
R_REG_NAME_LR, // link register
/* args */
R_REG_NAME_A0, // arguments
R_REG_NAME_A1,
R_REG_NAME_A2,
R_REG_NAME_A3,
R_REG_NAME_A4,
R_REG_NAME_A5,
R_REG_NAME_A6,
R_REG_NAME_A7,
R_REG_NAME_A8,
R_REG_NAME_A9,
2015-10-13 21:01:30 +00:00
/* retval */
R_REG_NAME_R0, // arguments
R_REG_NAME_R1,
R_REG_NAME_R2,
R_REG_NAME_R3,
/* flags */
R_REG_NAME_ZF,
R_REG_NAME_SF,
R_REG_NAME_CF,
R_REG_NAME_OF,
/* syscall number (orig_eax,rax,r0,x0) */
R_REG_NAME_SN,
R_REG_NAME_LAST,
Major rework to the native debugger (esp on Linux) (#5185) The major contribution here is completely re-worked breakpoint hit/recoil handling. This work fixes #4907 and lays the ground work for future native debugger improvements (multi-threading, etc). * Give a human friendly type to enums * Change many wait functions to return RDebugReasonType * Better return checking (from r_debug_reg_sync, r_bp_restore) * Optimized register synchronization * Lots of comments and whitespace changes * Improved inferior death detection Handle EXIT_PID events differently than DEAD process events * Move breakpoint/recoil handling to wait/cont/step Rather than handing breakpoint related things inside cmd_debug.c, do that inside the r_debug API functions. This seems like the most logical place for it to live since it should apply to just about any platform/architecture. This also centralizes calling into "cmd.bp" handling via the CoreBind callback. * Track how the caller wishes to continue It turns out that handling break point recoils is very complicated. The ptrace API on Linux returns SIGTRAP for just about every type of operation (not just breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are single-stepping or continuing and whether or not we are inside the recoil. * Proper handling for swstep=true Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil case there. Move the recoil handling from r_debug_step to r_debug_step_hard only. For the swstep=true case, special handling is required inside r_debug_recoil. By resetting all of the breakpoints except the one we just hit, we ensure we can step the original instruction and hit the new swstep breakpoint. Add a new bp function called r_bp_restore_except to do this. To make matters worse, we cannot use a BreakpointItem pointer because that leads to a use-after-free condition. Instead, we the breakpoint address instead. Now breakpoints should work regardless of the swtep setting. * Always call the recoil before continuing Some callers of r_debug_continue might not have ever inserted any breakpoints before. If we don't restore breakpoints before each call to the underlying continue we won't hit them. * Hide software step breakpoint events from the user When a breakpoint even happens due to a software-step, hide it from the user. They aren't really breakpoints as far as they are concerned. * Improve process exit handling on Linux There are three types of process exiting events on Linux: 1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to prevent it from exiting, but it can be used to inspect the pre-exit state. 2. The process can exit for a variety of reasons and we can notice when we call waitpid(2). 3. The process could die randomly on us :-/ On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely on Linux to find out the process is already dead. * Check more bits within waitpid status We can often make a decision about what happened strictly by looking at the status returned from waitpid. In other cases, we need to call r_debug_handle_signals. If we reach the end of this function without knowing what happened, consider it an error.
2016-06-22 08:34:45 +00:00
} RRegisterId;
2014-01-07 03:29:56 +00:00
// TODO: use enum here?
#define R_REG_COND_EQ 0
#define R_REG_COND_NE 1
#define R_REG_COND_CF 2
#define R_REG_COND_CARRY 2
#define R_REG_COND_NEG 3
#define R_REG_COND_NEGATIVE 3
#define R_REG_COND_OF 4
#define R_REG_COND_OVERFLOW 4
// unsigned
#define R_REG_COND_HI 5
#define R_REG_COND_HE 6
#define R_REG_COND_LO 7
#define R_REG_COND_LOE 8
// signed
#define R_REG_COND_GE 9
#define R_REG_COND_GT 10
#define R_REG_COND_LT 11
#define R_REG_COND_LE 12
#define R_REG_COND_LAST 13
typedef struct r_reg_item_t {
char *name;
2016-06-22 17:43:19 +00:00
int /*RRegisterType*/ type;
int size; /* 8,16,32,64 ... 128/256 ??? */
int offset; /* offset in data structure */
int packed_size; /* 0 means no packed register, 1byte pack, 2b pack... */
bool is_float;
char *flags;
int index;
int arena; /* in which arena is this reg living */
} RRegItem;
typedef struct r_reg_arena_t {
ut8 *bytes;
int size;
} RRegArena;
typedef struct r_reg_set_t {
RRegArena *arena;
RList *pool; /* RRegArena */
RList *regs; /* RRegItem */
RListIter *cur;
int maskregstype; /* which type of regs have this reg set (logic mask with RRegisterType R_REG_TYPE_XXX) */
} RRegSet;
typedef struct r_reg_t {
char *profile;
char *reg_profile_cmt;
char *reg_profile_str;
char *name[R_REG_NAME_LAST]; // aliases
RRegSet regset[R_REG_TYPE_LAST];
RList *allregs;
int iters;
int arch;
2014-06-19 02:03:11 +00:00
int bits;
int size;
bool is_thumb;
bool big_endian;
} RReg;
2014-01-07 03:29:56 +00:00
typedef struct r_reg_flags_t {
bool s; // sign, negative number (msb)
bool z; // zero
bool a; // half-carry adjust (if carry happens at nibble level)
bool c; // carry
bool o; // overflow
bool p; // parity (lsb)
2014-01-07 03:29:56 +00:00
} RRegFlags;
#ifdef R_API
2012-03-07 17:18:22 +00:00
R_API void r_reg_free(RReg *reg);
2016-04-03 23:59:30 +00:00
R_API void r_reg_free_internal(RReg *reg, bool init);
R_API RReg *r_reg_new(void);
R_API int r_reg_set_name(RReg *reg, int role, const char *name);
R_API int r_reg_set_profile_string(RReg *reg, const char *profile);
R_API int r_reg_set_profile(RReg *reg, const char *profile);
R_API int r_reg_parse_gdb_profile(const char *profile);
R_API RRegSet *r_reg_regset_get(RReg *r, int type);
R_API ut64 r_reg_getv(RReg *reg, const char *name);
R_API ut64 r_reg_setv(RReg *reg, const char *name, ut64 val);
R_API const char *r_reg_32_to_64(RReg *reg, const char *rreg32);
R_API const char *r_reg_get_type(int idx);
R_API const char *r_reg_get_name(RReg *reg, int kind);
2015-10-31 00:57:52 +00:00
R_API const char *r_reg_get_role(int role);
2012-07-21 10:11:21 +00:00
R_API RRegItem *r_reg_get(RReg *reg, const char *name, int type);
R_API RList *r_reg_get_list(RReg *reg, int type);
2015-12-08 23:41:44 +00:00
R_API RRegItem *r_reg_get_at(RReg *reg, int type, int regsize, int delta);
R_API RRegItem *r_reg_next_diff(RReg *reg, int type, const ut8 *buf, int buflen, RRegItem *prev_ri, int regsize);
R_API void r_reg_reindex(RReg *reg);
R_API RRegItem *r_reg_index_get(RReg *reg, int idx);
/* Item */
R_API void r_reg_item_free(RRegItem *item);
/* XXX: dupped ?? */
R_API int r_reg_type_by_name(const char *str);
R_API int r_reg_get_name_idx(const char *type);
2015-12-08 23:41:44 +00:00
R_API RRegItem *r_reg_cond_get(RReg *reg, const char *name);
R_API int r_reg_cond_get_value(RReg *r, const char *name);
R_API int r_reg_cond_bits(RReg *r, int type, RRegFlags *f);
R_API RRegFlags *r_reg_cond_retrieve(RReg *r, RRegFlags *);
R_API int r_reg_cond(RReg *r, int type);
2014-01-07 03:29:56 +00:00
/* integer value 8-64 bits */
2012-07-21 10:11:21 +00:00
R_API ut64 r_reg_get_value(RReg *reg, RRegItem *item);
R_API ut64 r_reg_get_value_big(RReg *reg, RRegItem *item, utX *val);
R_API ut64 r_reg_get_value_by_role(RReg *reg, RRegisterId role);
R_API bool r_reg_set_value(RReg *reg, RRegItem *item, ut64 value);
R_API bool r_reg_set_value_by_role(RReg *reg, RRegisterId role, ut64 value);
/* float */
R_API float r_reg_get_float(RReg *reg, RRegItem *item);
R_API bool r_reg_set_float(RReg *reg, RRegItem *item, float value);
/* double */
R_API double r_reg_get_double(RReg *reg, RRegItem *item);
R_API bool r_reg_set_double(RReg *reg, RRegItem *item, double value);
/* long double */
R_API long double r_reg_get_longdouble(RReg *reg, RRegItem *item);
R_API bool r_reg_set_longdouble(RReg *reg, RRegItem *item, long double value);
/* boolean */
R_API char *r_reg_get_bvalue(RReg *reg, RRegItem *item);
R_API ut64 r_reg_set_bvalue(RReg *reg, RRegItem *item, const char *str);
/* packed registers */
R_API int r_reg_set_pack(RReg *reg, RRegItem *item, int packidx, int packbits, ut64 val);
R_API ut64 r_reg_get_pack(RReg *reg, RRegItem *item, int packidx, int packbits);
/* byte arena */
2015-12-08 23:41:44 +00:00
R_API ut8 *r_reg_get_bytes(RReg *reg, int type, int *size);
R_API bool r_reg_set_bytes(RReg *reg, int type, const ut8 *buf, const int len);
R_API bool r_reg_read_regs(RReg *reg, ut8 *buf, const int len);
R_API int r_reg_arena_set_bytes(RReg *reg, const char *str);
2015-12-08 23:41:44 +00:00
R_API RRegArena *r_reg_arena_new(int size);
R_API void r_reg_arena_free(RRegArena *ra);
R_API int r_reg_fit_arena(RReg *reg);
R_API void r_reg_arena_swap(RReg *reg, int copy);
R_API int r_reg_arena_push(RReg *reg);
R_API void r_reg_arena_pop(RReg *reg);
R_API void r_reg_arena_zero(RReg *reg);
R_API ut8 *r_reg_arena_peek(RReg *reg);
R_API void r_reg_arena_poke(RReg *reg, const ut8 *buf);
R_API ut8 *r_reg_arena_dup(RReg *reg, const ut8 *source);
2015-12-08 23:41:44 +00:00
R_API const char *r_reg_cond_to_string(int n);
R_API int r_reg_cond_from_string(const char *str);
R_API void r_reg_arena_shrink(RReg *reg);
#endif
#endif