radare2/libr/bp/bp_traptrace.c

179 lines
3.9 KiB
C

/* radare - LGPL - Copyright 2010 pancake<nopcode.org> */
// TODO: use r_range here??
#include <r_bp.h>
#include <r_list.h>
R_API void r_bp_traptrace_free(void *ptr) {
RBreakpointTrace *trace = ptr;
free (trace->buffer);
free (trace->traps);
free (trace->bits);
free (trace);
}
R_API RList *r_bp_traptrace_new() {
RList *list = r_list_new ();
if (!list) {
return NULL;
}
list->free = &r_bp_traptrace_free;
return list;
}
R_API void r_bp_traptrace_enable(RBreakpoint *bp, int enable) {
RListIter *iter;
RBreakpointTrace *trace;
r_list_foreach (bp->traces, iter, trace) {
ut8 *buf = (enable)?trace->traps:trace->buffer;
bp->iob.write_at (bp->iob.io, trace->addr, buf, trace->length);
}
}
R_API void r_bp_traptrace_reset(RBreakpoint *bp, int hard) {
RListIter *iter;
RBreakpointTrace *trace;
r_list_foreach (bp->traces, iter, trace) {
if (hard) {
r_bp_traptrace_free (trace);
// XXX: This segfaults
//r_list_delete (bp->traces, r_list_iter_cur (iter));
} else {
memset (trace->bits, 0x00, trace->bitlen);
}
}
if (hard) {
// XXX: traces not freed correctly (memleak)
bp->traces = r_list_new ();
bp->traces->free = r_bp_traptrace_free;
}
}
// FIX: efficiency
R_API ut64 r_bp_traptrace_next(RBreakpoint *bp, ut64 addr) {
int i, delta;
RListIter *iter;
RBreakpointTrace *trace;
r_list_foreach (bp->traces, iter, trace) {
if (addr>=trace->addr && addr<=trace->addr_end) {
delta = (int)(addr-trace->addr);
for (i=delta; i<trace->length; i++) {
if (R_BIT_CHK (trace->bits, i)) {
return addr + i;
}
}
}
}
return 0LL;
}
R_API int r_bp_traptrace_add(RBreakpoint *bp, ut64 from, ut64 to) {
RBreakpointTrace *trace;
ut8 *buf, *trap, *bits;
ut64 len;
int bitlen;
/* cannot map addr 0 */
if (from == 0LL) {
return false;
}
if (from > to) {
return false;
}
len = to-from;
if (len >= ST32_MAX) {
return false;
}
buf = (ut8*) malloc ((int)len);
if (!buf) {
return false;
}
trap = (ut8*) malloc ((int)len+4);
if (!trap) {
free (buf);
return false;
}
bitlen = (len>>4)+1;
bits = malloc (bitlen);
if (!bits) {
free (buf);
free (trap);
return false;
}
// TODO: check return value
bp->iob.read_at (bp->iob.io, from, buf, len);
memset (bits, 0x00, bitlen);
r_bp_get_bytes (bp, trap, len, bp->endian, 0);
trace = R_NEW (RBreakpointTrace);
if (!trace) {
free (buf);
free (trap);
free (bits);
return false;
}
trace->addr = from;
trace->addr_end = to;
trace->bits = bits;
trace->traps = trap;
trace->buffer = buf;
trace->length = len;
if (!r_list_append (bp->traces, trace)){
free (buf);
free (trap);
free (trace);
return false;
}
// read a memory, overwrite it as breakpointing area
// every time it is hitted, instruction is restored
return true;
}
R_API int r_bp_traptrace_free_at(RBreakpoint *bp, ut64 from) {
int ret = false;
RListIter *iter, *iter_tmp;
RBreakpointTrace *trace;
r_list_foreach_safe (bp->traces, iter, iter_tmp, trace) {
if (from>=trace->addr && from<=trace->addr_end) {
bp->iob.write_at (bp->iob.io, trace->addr,
trace->buffer, trace->length);
r_bp_traptrace_free (trace);
r_list_delete (bp->traces, iter);
ret = true;
}
}
return ret;
}
R_API void r_bp_traptrace_list(RBreakpoint *bp) {
int i;
RListIter *iter;
RBreakpointTrace *trace;
r_list_foreach (bp->traces, iter, trace) {
for (i = 0; i < trace->bitlen; i++) {
if (R_BIT_CHK (trace->bits, i)) {
eprintf (" - 0x%08" PFMT64x "\n", trace->addr + (i << 4));
}
}
}
}
R_API int r_bp_traptrace_at(RBreakpoint *bp, ut64 from, int len) {
int delta;
RListIter *iter;
RBreakpointTrace *trace;
r_list_foreach (bp->traces, iter, trace) {
// TODO: do we really need len?
if (from>=trace->addr && from+len<=trace->addr_end) {
delta = (int) (from-trace->addr);
if (R_BIT_CHK (trace->bits, delta)) {
if (trace->traps[delta] == 0x00) {
return false; // already traced..debugger should stop
}
}
R_BIT_SET (trace->bits, delta);
return true;
}
}
return false;
}