- 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:
Eloi Sanfelix 2011-05-11 20:08:19 +02:00
parent ed15598061
commit b4b909ec1a
6 changed files with 113 additions and 40 deletions

View File

@ -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;

View File

@ -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;
}

View File

@ -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");

View File

@ -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,

View File

@ -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);
}

View File

@ -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