mirror of
https://github.com/radareorg/radare2.git
synced 2024-12-14 08:49:50 +00:00
722c62827b
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.
165 lines
4.4 KiB
C
165 lines
4.4 KiB
C
#ifndef R2_BP_H
|
|
#define R2_BP_H
|
|
|
|
#include <r_types.h>
|
|
#include <r_lib.h>
|
|
#include <r_io.h>
|
|
#include <r_list.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
R_LIB_VERSION_HEADER(r_bp);
|
|
|
|
#define R_BP_MAXPIDS 10
|
|
#define R_BP_CONT_NORMAL 0
|
|
#define R_BP_CONT_NORMAL 0
|
|
|
|
typedef struct r_bp_arch_t {
|
|
int bits;
|
|
int length;
|
|
int endian;
|
|
const ut8 *bytes;
|
|
} RBreakpointArch;
|
|
|
|
enum {
|
|
R_BP_TYPE_SW,
|
|
R_BP_TYPE_HW,
|
|
R_BP_TYPE_COND,
|
|
R_BP_TYPE_FAULT,
|
|
R_BP_TYPE_DELETE,
|
|
};
|
|
|
|
typedef struct r_bp_plugin_t {
|
|
char *name;
|
|
char *arch;
|
|
int type; // R_BP_TYPE_SW
|
|
int nbps;
|
|
RBreakpointArch *bps;
|
|
} RBreakpointPlugin;
|
|
|
|
typedef struct r_bp_item_t {
|
|
char *name;
|
|
char *module_name; /*module where you get the base address*/
|
|
st64 module_delta; /*delta to apply to module */
|
|
ut64 addr;
|
|
int size; /* size of breakpoint area */
|
|
int recoil; /* recoil */
|
|
bool swstep; /* is this breakpoint from a swstep? */
|
|
int rwx;
|
|
int hw;
|
|
int trace;
|
|
int internal; /* used for internal purposes */
|
|
int enabled;
|
|
int hits;
|
|
ut8 *obytes; /* original bytes */
|
|
ut8 *bbytes; /* breakpoint bytes */
|
|
int pids[R_BP_MAXPIDS];
|
|
char *data;
|
|
} RBreakpointItem;
|
|
|
|
typedef int (*RBreakpointCallback)(RBreakpointItem *bp, int set, void *user);
|
|
|
|
typedef struct r_bp_t {
|
|
void *user;
|
|
int stepcont;
|
|
int endian;
|
|
int bits;
|
|
RIOBind iob; // compile time dependency
|
|
RBreakpointPlugin *cur;
|
|
RList *traces; // XXX
|
|
RList *plugins;
|
|
PrintfCallback cb_printf;
|
|
RBreakpointCallback breakpoint;
|
|
/* storage of breakpoints */
|
|
int nbps;
|
|
RList *bps; // list of breakpoints
|
|
RBreakpointItem **bps_idx;
|
|
int bps_idx_count;
|
|
st64 delta;
|
|
} RBreakpoint;
|
|
|
|
enum {
|
|
R_BP_PROT_READ = 1,
|
|
R_BP_PROT_WRITE = 2,
|
|
R_BP_PROT_EXEC = 4,
|
|
};
|
|
|
|
typedef struct r_bp_trace_t {
|
|
ut64 addr;
|
|
ut64 addr_end;
|
|
ut8 *traps;
|
|
ut8 *buffer;
|
|
ut8 *bits;
|
|
int length;
|
|
int bitlen;
|
|
} RBreakpointTrace;
|
|
|
|
#ifdef R_API
|
|
R_API RBreakpoint *r_bp_new(void);
|
|
R_API RBreakpoint *r_bp_free(RBreakpoint *bp);
|
|
|
|
R_API int r_bp_del(RBreakpoint *bp, ut64 addr);
|
|
R_API int r_bp_del_all(RBreakpoint *bp);
|
|
|
|
R_API int r_bp_plugin_add(RBreakpoint *bp, RBreakpointPlugin *foo);
|
|
R_API int r_bp_use(RBreakpoint *bp, const char *name, int bits);
|
|
R_API int r_bp_plugin_del(RBreakpoint *bp, const char *name);
|
|
R_API void r_bp_plugin_list(RBreakpoint *bp);
|
|
|
|
R_API int r_bp_in(RBreakpoint *bp, ut64 addr, int rwx);
|
|
// deprecate?
|
|
R_API int r_bp_list(RBreakpoint *bp, int rad);
|
|
|
|
/* bp item attribs setters */
|
|
R_API int r_bp_get_bytes(RBreakpoint *bp, ut8 *buf, int len, int endian, int idx);
|
|
R_API int r_bp_set_trace(RBreakpoint *bp, ut64 addr, int set);
|
|
R_API int r_bp_set_trace_all(RBreakpoint *bp, int set);
|
|
R_API RBreakpointItem *r_bp_enable(RBreakpoint *bp, ut64 addr, int set);
|
|
R_API int r_bp_enable_all(RBreakpoint *bp, int set);
|
|
|
|
/* index api */
|
|
R_API int r_bp_del_index(RBreakpoint *bp, int idx);
|
|
R_API RBreakpointItem *r_bp_get_index(RBreakpoint *bp, int idx);
|
|
R_API RBreakpointItem *r_bp_item_new (RBreakpoint *bp);
|
|
|
|
R_API RBreakpointItem *r_bp_get_at (RBreakpoint *bp, ut64 addr);
|
|
R_API RBreakpointItem *r_bp_get_in (RBreakpoint *bp, ut64 addr, int rwx);
|
|
|
|
R_API int r_bp_add_cond(RBreakpoint *bp, const char *cond);
|
|
R_API int r_bp_del_cond(RBreakpoint *bp, int idx);
|
|
R_API int r_bp_add_fault(RBreakpoint *bp, ut64 addr, int size, int rwx);
|
|
|
|
R_API RBreakpointItem *r_bp_add_sw(RBreakpoint *bp, ut64 addr, int size, int rwx);
|
|
R_API RBreakpointItem *r_bp_add_hw(RBreakpoint *bp, ut64 addr, int size, int rwx);
|
|
R_API void r_bp_restore_one(RBreakpoint *bp, RBreakpointItem *b, bool set);
|
|
R_API int r_bp_restore(RBreakpoint *bp, bool set);
|
|
R_API bool r_bp_restore_except(RBreakpoint *bp, bool set, ut64 addr);
|
|
|
|
/* traptrace */
|
|
R_API void r_bp_traptrace_free(void *ptr);
|
|
R_API void r_bp_traptrace_enable(RBreakpoint *bp, int enable);
|
|
R_API void r_bp_traptrace_reset(RBreakpoint *bp, int hard);
|
|
R_API ut64 r_bp_traptrace_next(RBreakpoint *bp, ut64 addr);
|
|
R_API int r_bp_traptrace_add(RBreakpoint *bp, ut64 from, ut64 to);
|
|
R_API int r_bp_traptrace_free_at(RBreakpoint *bp, ut64 from);
|
|
R_API void r_bp_traptrace_list(RBreakpoint *bp);
|
|
R_API int r_bp_traptrace_at(RBreakpoint *bp, ut64 from, int len);
|
|
R_API RList *r_bp_traptrace_new(void);
|
|
R_API void r_bp_traptrace_enable(RBreakpoint *bp, int enable);
|
|
|
|
/* plugin pointers */
|
|
extern RBreakpointPlugin r_bp_plugin_x86;
|
|
extern RBreakpointPlugin r_bp_plugin_arm;
|
|
extern RBreakpointPlugin r_bp_plugin_mips;
|
|
extern RBreakpointPlugin r_bp_plugin_ppc;
|
|
extern RBreakpointPlugin r_bp_plugin_sh;
|
|
extern RBreakpointPlugin r_bp_plugin_bf;
|
|
#endif
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif
|