/* radare2 - LGPL - Copyright 2009-2015 - pancake */ #include #include "../config.h" R_LIB_VERSION (r_bp); static struct r_bp_plugin_t *bp_static_plugins[] = { R_BP_STATIC_PLUGINS }; static void r_bp_item_free (RBreakpointItem *b) { free (b->name); free (b->bbytes); free (b->obytes); free (b); } R_API RBreakpoint *r_bp_new() { RBreakpoint *bp = R_NEW0 (RBreakpoint); RBreakpointPlugin *static_plugin; int i; if (!bp) return NULL; bp->bps_idx_count = 16; bp->bps_idx = R_NEWS0 (RBreakpointItem*, bp->bps_idx_count); bp->stepcont = R_BP_CONT_NORMAL; bp->traces = r_bp_traptrace_new (); bp->cb_printf = (PrintfCallback)printf; bp->bps = r_list_newf ((RListFree)r_bp_item_free); bp->plugins = r_list_newf ((RListFree)free); for (i = 0; bp_static_plugins[i]; i++) { static_plugin = R_NEW (RBreakpointPlugin); memcpy (static_plugin, bp_static_plugins[i], sizeof (RBreakpointPlugin)); r_bp_plugin_add (bp, static_plugin); } memset (&bp->iob, 0, sizeof (bp->iob)); return bp; } R_API RBreakpoint *r_bp_free(RBreakpoint *bp) { r_list_free (bp->bps); r_list_free (bp->plugins); r_list_free (bp->traces); free (bp); return NULL; } R_API int r_bp_get_bytes(RBreakpoint *bp, ut8 *buf, int len, int endian, int idx) { int i; struct r_bp_arch_t *b; if (bp->cur) { // find matching size breakpoint repeat: for (i=0; i< bp->cur->nbps; i++) { b = &bp->cur->bps[i]; if (bp->cur->bps[i].bits) { if (bp->bits != bp->cur->bps[i].bits) continue; } if (bp->cur->bps[i].length == len) { memcpy (buf, b->bytes, b->length); return b->length; } } if (len != 4) { len = 4; goto repeat; } /* if not found try to pad with the first one */ b = &bp->cur->bps[0]; if (len % b->length) { eprintf ("No matching bpsize\n"); return 0; } for (i = 0; i < len; i++) { memcpy (buf + i, b->bytes, b->length); } return b->length; } return 0; } R_API RBreakpointItem *r_bp_get_at(RBreakpoint *bp, ut64 addr) { RListIter *iter; RBreakpointItem *b; r_list_foreach(bp->bps, iter, b) { if (b->addr == addr) return b; } return NULL; } R_API RBreakpointItem *r_bp_get_in(RBreakpoint *bp, ut64 addr, int rwx) { RBreakpointItem *b; 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; } R_API RBreakpointItem *r_bp_enable(RBreakpoint *bp, ut64 addr, int set) { RBreakpointItem *b = r_bp_get_in (bp, addr, 0); if (b) { b->enabled = set; return b; } return NULL; } R_API int r_bp_enable_all(RBreakpoint *bp, int set) { RListIter *iter; RBreakpointItem *b; r_list_foreach (bp->bps, iter, b) { b->enabled = set; } return true; } R_API int r_bp_stepy_continuation(RBreakpoint *bp) { // TODO: implement return bp->stepcont; } /* TODO: detect overlapping of breakpoints */ static RBreakpointItem *r_bp_add(RBreakpoint *bp, const ut8 *obytes, ut64 addr, int size, int hw, int rwx) { int ret; RBreakpointItem *b; if (addr == UT64_MAX || size < 1) return NULL; if (r_bp_get_in (bp, addr, rwx)) { eprintf ("Breakpoint already set at this address.\n"); return NULL; } b = r_bp_item_new (bp); b->addr = addr + bp->delta; b->size = size; b->enabled = true; b->rwx = rwx; b->hw = hw; if (!hw) { b->bbytes = calloc (size + 16, 1); if (obytes) { b->obytes = malloc (size); memcpy (b->obytes, obytes, size); } else { b->obytes = NULL; } /* XXX: endian .. use bp->endian */ // XXX for hw breakpoints there are no bytes ret = r_bp_get_bytes (bp, b->bbytes, size, 0, 0); if (ret == 0) { eprintf ("Cannot get breakpoint bytes. No r_bp_use()?\n"); r_bp_item_free (b); return NULL; } b->recoil = ret; } bp->nbps++; r_list_append (bp->bps, b); return b; } R_API int r_bp_add_fault(RBreakpoint *bp, ut64 addr, int size, int rwx) { // TODO return false; } R_API RBreakpointItem* r_bp_add_sw(RBreakpoint *bp, ut64 addr, int size, int rwx) { RBreakpointItem *item; ut8 *bytes; if (size < 1) size = 1; bytes = calloc (1, size); if (bytes == NULL) return NULL; if (bp->iob.read_at) bp->iob.read_at (bp->iob.io, addr, bytes, size); else memset (bytes, 0, size); item = r_bp_add (bp, bytes, addr, size, R_BP_TYPE_SW, rwx); free (bytes); return item; } R_API RBreakpointItem* r_bp_add_hw(RBreakpoint *bp, ut64 addr, int size, int rwx) { return r_bp_add (bp, NULL, addr, size, R_BP_TYPE_HW, rwx); } R_API int r_bp_del_all(RBreakpoint *bp) { if (r_list_empty (bp->bps)) return false; r_list_purge (bp->bps); return true; } R_API int r_bp_del(RBreakpoint *bp, ut64 addr) { RListIter *iter; RBreakpointItem *b; /* No _safe loop necessary because we return immediately after the delete. */ r_list_foreach (bp->bps, iter, b) { if (b->addr == addr) { r_list_delete (bp->bps, iter); return true; } } return false; } R_API int r_bp_set_trace(RBreakpoint *bp, ut64 addr, int set) { RBreakpointItem *b = r_bp_get_in (bp, addr, 0); if (b) { b->trace = set; return true; } return false; } R_API int r_bp_set_trace_all(RBreakpoint *bp, int set) { RListIter *iter; RBreakpointItem *b; r_list_foreach (bp->bps, iter, b) { b->trace = set; } return true; } // TODO: deprecate R_API int r_bp_list(RBreakpoint *bp, int rad) { int n = 0; RBreakpointItem *b; RListIter *iter; if (rad == 'j') bp->cb_printf ("["); //eprintf ("Breakpoint list:\n"); r_list_foreach (bp->bps, iter, b) { switch (rad) { case 0: bp->cb_printf ("0x%08"PFMT64x" - 0x%08"PFMT64x \ "%d %c%c%c %s %s %s cmd=\"%s\" " \ "name=\"%s\"\n", b->addr, b->addr + b->size, b->size, (b->rwx & R_BP_PROT_READ) ? 'r' : '-', (b->rwx & R_BP_PROT_WRITE) ? 'w' : '-', (b->rwx & R_BP_PROT_EXEC) ? 'x' : '-', b->hw ? "hw": "sw", b->trace ? "trace" : "break", b->enabled ? "enabled" : "disabled", b->data ? b->data : "", b->name ? b->name : ""); break; case 1: case 'r': case '*': // TODO: add command, tracing, enable, .. bp->cb_printf ("db 0x%08"PFMT64x"\n", b->addr); //b->trace? "trace": "break", //b->enabled? "enabled": "disabled", // b->data? b->data: ""); break; case 'j': bp->cb_printf ("%s{\"addr\":%"PFMT64d",\"size\":%d,\ \"prot\":\"%c%c%c\",\"hw\":%s,\ \"trace\":%s,\"enabled\":%s,\ \"data\":\"%s\"}", iter->p ? "," : "", b->addr, b->size, (b->rwx & R_BP_PROT_READ) ? 'r' : '-', (b->rwx & R_BP_PROT_WRITE) ? 'w' : '-', (b->rwx & R_BP_PROT_EXEC) ? 'x' : '-', b->hw ? "true" : "false", b->trace ? "true" : "false", b->enabled ? "true" : "false", b->data ? b->data : ""); break; } /* TODO: Show list of pids and trace points, conditionals */ n++; } if (rad == 'j') { bp->cb_printf ("]\n"); } return n; } R_API RBreakpointItem *r_bp_item_new (RBreakpoint *bp) { int i, j; /* find empty slot */ for (i = 0; i < bp->bps_idx_count; i++) { if (!bp->bps_idx[i]) { goto return_slot; } } /* allocate new slot */ bp->bps_idx_count += 16; // alocate space for 16 more bps bp->bps_idx = realloc (bp->bps_idx, bp->bps_idx_count * sizeof(RBreakpointItem*)); for (j = i; j < bp->bps_idx_count; j++) { bp->bps_idx[j] = NULL; } return_slot: /* empty slot */ return (bp->bps_idx[i] = R_NEW0 (RBreakpointItem)); } R_API RBreakpointItem *r_bp_get_index(RBreakpoint *bp, int idx) { if (idx >= 0 && idx < bp->bps_idx_count) return bp->bps_idx[idx]; return NULL; } R_API int r_bp_del_index(RBreakpoint *bp, int idx) { if (idx >= 0 && idx < bp->bps_idx_count) { r_list_delete_data (bp->bps, bp->bps_idx[idx]); free (bp->bps_idx[idx]); bp->bps_idx[idx] = NULL; return true; } return false; }