- Fixed breakpoint behaviour
* Find recoil * Set pc to addr-recoil properly * Fixed bp_restore: per bp, check if handled, else do via io.write - Improved debug_gdb * Added 'read all regs to buffer' * Added breakpoint callback: check if supported first time, else return FALSE - Maybe something else...
This commit is contained in:
parent
ed15598061
commit
b4b909ec1a
10
libr/bp/bp.c
10
libr/bp/bp.c
|
@ -66,11 +66,13 @@ R_API RBreakpointItem *r_bp_get(RBreakpoint *bp, ut64 addr) {
|
|||
}
|
||||
|
||||
R_API RBreakpointItem *r_bp_at_addr(RBreakpoint *bp, ut64 addr, int rwx) {
|
||||
RListIter *iter;
|
||||
int n = 0;
|
||||
RBreakpointItem *b;
|
||||
r_list_foreach(bp->bps, iter, b) {
|
||||
// eprintf ("---ataddr--- 0x%08"PFMT64x" %d %d\n", b->addr, b->size, b->recoil);
|
||||
if (addr>=b->addr && addr<=b->addr+b->size && rwx&b->rwx)
|
||||
RListIter *iter;
|
||||
r_list_foreach (bp->bps, iter, b) {
|
||||
// eprintf ("---ataddr--- 0x%08"PFMT64x" %d %d %x\n", b->addr, b->size, b->recoil, b->rwx);
|
||||
//Check addr within range and provided rwx matches (or null)
|
||||
if (addr>=b->addr && addr<=(b->addr+b->size) && (!rwx || rwx&b->rwx))
|
||||
return b;
|
||||
}
|
||||
return NULL;
|
||||
|
|
11
libr/bp/io.c
11
libr/bp/io.c
|
@ -68,10 +68,12 @@ R_API int r_bp_restore(struct r_bp_t *bp, int set) {
|
|||
/* write obytes from every breakpoint in r_bp if not handled by plugin */
|
||||
if (!handled)
|
||||
if (set) {
|
||||
eprintf("Setting bp at 0x%x\n", b->addr);
|
||||
if (b->hw || !b->obytes)
|
||||
eprintf ("hw breakpoints not supported yet\n");
|
||||
else bp->iob.write_at (bp->iob.io, b->addr, b->obytes, b->size);
|
||||
} else {
|
||||
eprintf("Clearing bp at 0x%x\n", b->addr);
|
||||
if (b->hw || !b->bbytes)
|
||||
eprintf ("hw breakpoints not supported yet\n");
|
||||
else bp->iob.write_at (bp->iob.io, b->addr, b->bbytes, b->size);
|
||||
|
@ -82,11 +84,12 @@ R_API int r_bp_restore(struct r_bp_t *bp, int set) {
|
|||
}
|
||||
|
||||
R_API int r_bp_recoil(RBreakpoint *bp, ut64 addr) {
|
||||
RBreakpointItem *b = r_bp_at_addr (bp, addr, 0xFFFFFF);
|
||||
RBreakpointItem *b = r_bp_at_addr (bp, addr, 0); //XXX Don't care about rwx
|
||||
|
||||
if (b) {
|
||||
eprintf("HIT AT ADDR 0x%"PFMT64x"\n", addr);
|
||||
eprintf(" recoil = %d\n", b->recoil);
|
||||
eprintf(" size = %d\n", b->size);
|
||||
//eprintf("HIT AT ADDR 0x%"PFMT64x"\n", addr);
|
||||
//eprintf(" recoil = %d\n", b->recoil);
|
||||
//eprintf(" size = %d\n", b->size);
|
||||
if (!b->hw && ((b->addr + b->size) == addr))
|
||||
return b->recoil;
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ static int r_debug_recoil(RDebug *dbg) {
|
|||
dbg->reason = R_DBG_REASON_BP;
|
||||
r_reg_set_value (dbg->reg, ri, addr-recoil);
|
||||
r_debug_reg_sync (dbg, R_REG_TYPE_GPR, R_TRUE);
|
||||
eprintf ("[BP Hit] Setting pc to 0x%"PFMT64x"\n", (addr-recoil));
|
||||
ret = R_TRUE;
|
||||
}
|
||||
} else eprintf ("r_debug_recoil: Cannot get program counter\n");
|
||||
|
|
|
@ -15,11 +15,17 @@ typedef struct {
|
|||
#define RIOGDB_IS_VALID(x) (x && x->plugin==&r_io_plugin_gdb && x->data)
|
||||
#define NUM_REGS 28
|
||||
|
||||
#define UNKNOWN -1
|
||||
#define UNSUPPORTED 0
|
||||
#define SUPPORTED 1
|
||||
|
||||
/* TODO: The IO stuff must be communicated with the r_dbg */
|
||||
/* a transplant sometimes requires to change the IO */
|
||||
/* so, for here, we need r_io_plugin_gdb */
|
||||
/* TODO: rename to gdbwrap? */
|
||||
static gdbwrap_t *desc = NULL;
|
||||
static int support_sw_bp = UNKNOWN;
|
||||
static int support_hw_bp = UNKNOWN;
|
||||
|
||||
static int r_debug_gdb_step(RDebug *dbg) {
|
||||
gdbwrap_stepi (desc);
|
||||
|
@ -27,22 +33,15 @@ static int r_debug_gdb_step(RDebug *dbg) {
|
|||
}
|
||||
|
||||
static int r_debug_gdb_reg_read(RDebug *dbg, int type, ut8 *buf, int size) {
|
||||
int i;
|
||||
|
||||
// TODO: allow gdbwrap to read regs on own buffer
|
||||
ut8 *p = gdbwrap_readgenreg (desc);
|
||||
|
||||
// TODO: bounds check!!!
|
||||
for (i=0; i< desc->num_registers ; i++) {
|
||||
ut64 p = (ut64)gdbwrap_getreg (desc, i);
|
||||
memcpy (buf+(i*desc->reg_size), &p, desc->reg_size);
|
||||
}
|
||||
gdbwrap_readgenreg(desc);
|
||||
gdbwrap_getreg_buffer(desc,buf,desc->reg_size*desc->num_registers);
|
||||
return desc->num_registers*desc->reg_size;
|
||||
}
|
||||
|
||||
static int r_debug_gdb_reg_write(int pid, int tid, int type, const ut8 *buf, int size) {
|
||||
/* TODO */
|
||||
return R_TRUE;
|
||||
gdbwrap_setreg_buffer(desc,buf,desc->reg_size*desc->num_registers);
|
||||
gdbwrap_shipallreg(desc);
|
||||
return R_TRUE; // XXX Error check
|
||||
}
|
||||
|
||||
static int r_debug_gdb_continue(RDebug *dbg, int pid, int tid, int sig) {
|
||||
|
@ -59,8 +58,11 @@ static int r_debug_gdb_attach(RDebug *dbg, int pid) {
|
|||
// XXX TODO PID must be a socket here !!1
|
||||
RIODesc *d = dbg->iob.io->fd;
|
||||
if (d && d->plugin && d->plugin->name) {
|
||||
|
||||
if (!strcmp ("gdb", d->plugin->name)) {
|
||||
RIOGdb *g = d->data;
|
||||
support_sw_bp = UNKNOWN;
|
||||
support_hw_bp = UNKNOWN;
|
||||
desc = g->desc;
|
||||
switch (dbg->arch){
|
||||
case R_SYS_ARCH_X86:
|
||||
|
@ -80,7 +82,7 @@ static int r_debug_gdb_attach(RDebug *dbg, int pid) {
|
|||
desc->reg_size = 4;
|
||||
break;
|
||||
}
|
||||
eprintf ("SUCCESS: gdb attach with inferior gdb rio worked\n");
|
||||
//eprintf ("SUCCESS: gdb attach with inferior gdb rio worked\n");
|
||||
} else {
|
||||
eprintf ("ERROR: Underlaying IO descriptor is not a GDB one..\n");
|
||||
}
|
||||
|
@ -171,6 +173,29 @@ static const char *r_debug_gdb_reg_profile(RDebug *dbg) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static int r_debug_gdb_breakpoint (void *user, int type, ut64 addr, int hw, int rwx){
|
||||
if (hw && support_hw_bp!=UNSUPPORTED) {
|
||||
//TODO Implement gdb hw breakpoint
|
||||
support_hw_bp = UNSUPPORTED;
|
||||
return R_FALSE;
|
||||
}
|
||||
|
||||
if (!hw && support_sw_bp!=UNSUPPORTED){
|
||||
if(!type && gdbwrap_simplesetbp(desc,addr)){
|
||||
support_sw_bp = SUPPORTED;
|
||||
return R_TRUE;
|
||||
} else if (type ) {
|
||||
gdbwrap_simpledelbp(desc,addr);
|
||||
return R_TRUE;
|
||||
} else {
|
||||
support_sw_bp = UNSUPPORTED;
|
||||
return R_FALSE;
|
||||
}
|
||||
return support_sw_bp;
|
||||
}
|
||||
return R_FALSE;
|
||||
}
|
||||
|
||||
struct r_debug_plugin_t r_debug_plugin_gdb = {
|
||||
.name = "gdb",
|
||||
/* TODO: Add support for more architectures here */
|
||||
|
@ -188,7 +213,7 @@ struct r_debug_plugin_t r_debug_plugin_gdb = {
|
|||
.kill = NULL,
|
||||
.frames = NULL,
|
||||
.map_get = NULL,
|
||||
.breakpoint = NULL,
|
||||
.breakpoint = &r_debug_gdb_breakpoint,
|
||||
.reg_read = &r_debug_gdb_reg_read,
|
||||
.reg_write = &r_debug_gdb_reg_write,
|
||||
.reg_profile = (void *)r_debug_gdb_reg_profile,
|
||||
|
|
|
@ -48,6 +48,20 @@ void gdbwrap_setreg(gdbwrap_t *desc, ut32 idx, ut64 value){
|
|||
}
|
||||
}
|
||||
|
||||
void gdbwrap_getreg_buffer(gdbwrap_t *desc, char *buf, ut32 size){
|
||||
if ( desc->reg_size*desc->num_registers > size )
|
||||
size = desc->reg_size*desc->num_registers;
|
||||
|
||||
//Just copy the output buffer
|
||||
memcpy(buf,desc->regs,size);
|
||||
}
|
||||
|
||||
void gdbwrap_setreg_buffer(gdbwrap_t *desc, char *buf , ut32 size){
|
||||
if ( desc->reg_size*desc->num_registers > size )
|
||||
size = desc->reg_size*desc->num_registers;
|
||||
memcpy (desc->regs, buf, size);
|
||||
}
|
||||
|
||||
ut64 gdbwrap_getreg(gdbwrap_t *desc, ut32 idx){
|
||||
ut64 ret=-1;
|
||||
if ( idx >= desc->num_registers){
|
||||
|
@ -746,7 +760,7 @@ void gdbwrap_setbp(gdbwrap_t *desc, la32 linaddr, void *datasave
|
|||
* It is possible that some gdb servers do not implement it, and we could
|
||||
* fall back to arch-specific methods then.
|
||||
*/
|
||||
void gdbwrap_simplesetbp(gdbwrap_t *desc, la32 linaddr)
|
||||
int gdbwrap_simplesetbp(gdbwrap_t *desc, la32 linaddr)
|
||||
{
|
||||
char *ret;
|
||||
char packet[MSG_BUF];
|
||||
|
@ -755,10 +769,10 @@ void gdbwrap_simplesetbp(gdbwrap_t *desc, la32 linaddr)
|
|||
GDBWRAP_SEP_COMMA, linaddr, GDBWRAP_SEP_COMMA, 0x1);
|
||||
ret = gdbwrap_send_data(desc, packet);
|
||||
fprintf(stderr,"Received from gdb server: %s\n",ret);
|
||||
if ( !strncmp(ret,"$#00",4) ){
|
||||
fprintf( stderr, "Breakpoint command not supported by gdb stub. Consider manually adding trap instructions instead.\n");
|
||||
}
|
||||
|
||||
printf("Received from stub: %s\n",ret);
|
||||
if ( ret[0]=='\0' )
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void gdbwrap_simplesethwbp(gdbwrap_t *desc, la32 linaddr)
|
||||
|
@ -770,9 +784,9 @@ void gdbwrap_simplesethwbp(gdbwrap_t *desc, la32 linaddr)
|
|||
GDBWRAP_SEP_COMMA, linaddr, GDBWRAP_SEP_COMMA, 0x1);
|
||||
ret = gdbwrap_send_data(desc, packet);
|
||||
|
||||
if ( !strncmp(ret,"$#00",4) ){
|
||||
fprintf( stderr, "HW breakpoint command not supported by gdb stub. Consider manually adding trap instructions instead.\n");
|
||||
}
|
||||
if (ret[0]=='\0')
|
||||
return 0;
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
|
@ -783,13 +797,17 @@ void gdbwrap_delbp(gdbwrap_t *desc, la32 linaddr, void *datasave
|
|||
}
|
||||
|
||||
|
||||
void gdbwrap_simpledelbp(gdbwrap_t *desc, la32 linaddr)
|
||||
int gdbwrap_simpledelbp(gdbwrap_t *desc, la32 linaddr)
|
||||
{
|
||||
char packet[MSG_BUF];
|
||||
char *ret;
|
||||
|
||||
snprintf(packet, sizeof(packet), "%s%s%x%s%x", GDBWRAP_REMOVEBP,
|
||||
GDBWRAP_SEP_COMMA, linaddr, GDBWRAP_SEP_COMMA, 0x1);
|
||||
gdbwrap_send_data(desc, packet);
|
||||
ret = gdbwrap_send_data(desc, packet);
|
||||
if(ret[0] == '\0')
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void gdbwrap_simpledelhwbp(gdbwrap_t *desc, la32 linaddr)
|
||||
|
@ -972,32 +990,55 @@ void gdbwrap_writereg(gdbwrap_t *desc, ureg32 regnum, la32 val)
|
|||
}
|
||||
|
||||
|
||||
//This is ugly...
|
||||
char *getfmt(ut32 size){
|
||||
switch (size){
|
||||
case 1:
|
||||
return "%02x";
|
||||
case 2:
|
||||
return "%04x";
|
||||
case 4:
|
||||
return "%08x";
|
||||
case 8:
|
||||
return "%16x";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ship all the registers to the server in only 1 query. This is used
|
||||
* when modifying multiple registers at once for example.
|
||||
*/
|
||||
char *gdbwrap_shipallreg(gdbwrap_t *desc)
|
||||
{
|
||||
ut8 savedregs[sizeof(gdbwrap_gdbreg32)];
|
||||
ut8 *savedregs;
|
||||
char *ret;
|
||||
char *fmt;
|
||||
char locreg[700];
|
||||
uint8_t i;
|
||||
|
||||
ASSERT(desc != NULL);
|
||||
memcpy(savedregs, desc->regs, sizeof(gdbwrap_gdbreg32));
|
||||
savedregs = (ut8 *)malloc(desc->num_registers*desc->reg_size);
|
||||
ASSERT(savedregs!=NULL);
|
||||
memcpy(savedregs, desc->regs, desc->num_registers*desc->reg_size);
|
||||
|
||||
fmt = getfmt(desc->reg_size);
|
||||
|
||||
gdbwrap_readgenreg(desc);
|
||||
ret = gdbwrap_lastmsg(desc);
|
||||
|
||||
/* We modify the 9 GPR only and we copy the rest from the gpr
|
||||
request. */
|
||||
for (i = 0; i < 9; i++)
|
||||
snprintf(locreg + i * 2 * sizeof(ureg32), 2 * sizeof(ureg32) + 1,
|
||||
"%08x", gdbwrap_little_endian(*(ut32 *)(savedregs + desc->reg_size*i)));
|
||||
for (i = 0; i < desc->num_registers; i++)
|
||||
snprintf(locreg + i * 2 * desc->reg_size, 2 * desc->reg_size + 1,
|
||||
fmt, gdbwrap_little_endian(*(ut32 *)(savedregs + desc->reg_size*i)));
|
||||
ASSERT(strlen(locreg) < desc->max_packet_size);
|
||||
memcpy(ret, locreg, strlen(locreg));
|
||||
snprintf(locreg, sizeof(locreg), "%s%s", GDBWRAP_WGENPURPREG, ret);
|
||||
|
||||
free(savedregs);
|
||||
|
||||
return gdbwrap_send_data(desc, locreg);
|
||||
}
|
||||
|
||||
|
|
|
@ -91,9 +91,9 @@ char *gdbwrap_own_command(gdbwrap_t *desc, char *command);
|
|||
ut8 *gdbwrap_readgenreg(gdbwrap_t *desc);
|
||||
void gdbwrap_continue(gdbwrap_t *desc);
|
||||
void gdbwrap_setbp(gdbwrap_t *desc, la32 linaddr, void *datasaved);
|
||||
void gdbwrap_simplesetbp(gdbwrap_t *desc, la32 linaddr);
|
||||
int gdbwrap_simplesetbp(gdbwrap_t *desc, la32 linaddr);
|
||||
void gdbwrap_delbp(gdbwrap_t *desc, la32 linaddr, void *datasaved);
|
||||
void gdbwrap_simpledelbp(gdbwrap_t *desc, la32 linaddr);
|
||||
int gdbwrap_simpledelbp(gdbwrap_t *desc, la32 linaddr);
|
||||
char *gdbwrap_readmem(gdbwrap_t *desc, la32 linaddr, unsigned bytes);
|
||||
void gdbwrap_writemem(gdbwrap_t *desc, la32 linaddr, void *value,
|
||||
unsigned bytes);
|
||||
|
@ -106,6 +106,7 @@ char *gdbwrap_remotecmd(gdbwrap_t *desc, char *cmd);
|
|||
u_char gdbwrap_lasterror(gdbwrap_t *desc);
|
||||
gdbmemap_t gdbwrap_memorymap_get();
|
||||
ut64 gdbwrap_getreg(gdbwrap_t *desc, ut32 idx);
|
||||
void gdbwrap_getreg_buffer(gdbwrap_t *desc, char *buf, ut32 size);
|
||||
void gdbwrap_setreg(gdbwrap_t *desc, ut32 idx, ut64 value);
|
||||
|
||||
void gdbwrap_setreg_buffer(gdbwrap_t *desc, char *buf, ut32 size);
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue