2015-02-22 10:18:40 +00:00
|
|
|
/* radare - LGPL - Copyright 2008-2015 - pancake */
|
2010-03-12 18:11:43 +00:00
|
|
|
|
|
|
|
#include <r_debug.h>
|
|
|
|
|
2014-11-02 00:21:45 +00:00
|
|
|
#define R_DEBUG_SDB_TRACES 1
|
|
|
|
|
2014-10-30 22:58:22 +00:00
|
|
|
// DO IT WITH SDB
|
|
|
|
|
2010-06-03 22:56:44 +00:00
|
|
|
R_API RDebugTrace *r_debug_trace_new () {
|
2016-05-24 20:22:15 +00:00
|
|
|
RDebugTrace *t = R_NEW0 (RDebugTrace);
|
|
|
|
if (!t) return NULL;
|
2010-06-04 21:47:35 +00:00
|
|
|
t->tag = 1; // UT32_MAX;
|
2010-06-13 09:59:17 +00:00
|
|
|
t->addresses = NULL;
|
2015-09-14 00:08:31 +00:00
|
|
|
t->enabled = false;
|
2010-06-03 22:56:44 +00:00
|
|
|
t->traces = r_list_new ();
|
2016-05-24 20:22:15 +00:00
|
|
|
if (!t->traces) {
|
|
|
|
r_debug_trace_free (t);
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-06-03 22:56:44 +00:00
|
|
|
t->traces->free = free;
|
2014-11-02 00:21:45 +00:00
|
|
|
t->db = sdb_new0 ();
|
2016-05-24 20:22:15 +00:00
|
|
|
if (!t->db) {
|
|
|
|
r_debug_trace_free (t);
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-06-03 22:56:44 +00:00
|
|
|
return t;
|
2010-03-12 18:11:43 +00:00
|
|
|
}
|
|
|
|
|
2010-06-03 22:56:44 +00:00
|
|
|
R_API void r_debug_trace_free (RDebug *dbg) {
|
|
|
|
if (dbg->trace == NULL)
|
|
|
|
return;
|
2014-05-02 14:54:27 +00:00
|
|
|
r_list_purge (dbg->trace->traces);
|
2013-11-17 10:25:45 +00:00
|
|
|
free (dbg->trace->traces);
|
2014-11-02 00:21:45 +00:00
|
|
|
sdb_free (dbg->trace->db);
|
2010-06-03 22:56:44 +00:00
|
|
|
free (dbg->trace);
|
|
|
|
dbg->trace = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: added overlap/mask support here... wtf?
|
|
|
|
// TODO: think about tagged traces
|
|
|
|
R_API int r_debug_trace_tag (RDebug *dbg, int tag) {
|
|
|
|
//if (tag>0 && tag<31) core->dbg->trace->tag = 1<<(sz-1);
|
|
|
|
return (dbg->trace->tag = (tag>0)? tag: UT32_MAX);
|
2010-03-12 18:11:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
R_API int r_debug_trace_pc (RDebug *dbg) {
|
2010-06-04 21:47:35 +00:00
|
|
|
ut8 buf[32];
|
2010-09-18 00:51:17 +00:00
|
|
|
RRegItem *ri;
|
2011-02-24 13:06:49 +00:00
|
|
|
RAnalOp op;
|
2010-07-15 22:02:33 +00:00
|
|
|
static ut64 oldpc = 0LL; // Must trace the previously traced instruction
|
2015-09-14 00:08:31 +00:00
|
|
|
r_debug_reg_sync (dbg, R_REG_TYPE_GPR, false);
|
2010-06-04 21:47:35 +00:00
|
|
|
if ((ri = r_reg_get (dbg->reg, dbg->reg->name[R_REG_NAME_PC], -1))) {
|
2010-03-12 18:11:43 +00:00
|
|
|
ut64 addr = r_reg_get_value (dbg->reg, ri);
|
2014-10-30 22:58:22 +00:00
|
|
|
if (!addr) {
|
2015-09-14 00:08:31 +00:00
|
|
|
return false;
|
2014-10-30 22:58:22 +00:00
|
|
|
}
|
2010-06-04 21:47:35 +00:00
|
|
|
if (dbg->iob.read_at (dbg->iob.io, addr, buf, sizeof (buf))>0) {
|
2011-02-24 13:06:49 +00:00
|
|
|
if (r_anal_op (dbg->anal, &op, addr, buf, sizeof (buf))>0) {
|
2015-02-22 10:18:40 +00:00
|
|
|
if (oldpc!=0LL) {
|
|
|
|
if (dbg->anal->esil) {
|
|
|
|
if (dbg->anal->trace) {
|
|
|
|
r_anal_esil_trace (dbg->anal->esil, &op);
|
|
|
|
}
|
|
|
|
}
|
2013-12-06 04:18:57 +00:00
|
|
|
r_debug_trace_add (dbg, oldpc, op.size);
|
2015-02-22 10:18:40 +00:00
|
|
|
}
|
2010-07-15 22:02:33 +00:00
|
|
|
oldpc = addr;
|
2015-09-14 00:08:31 +00:00
|
|
|
return true;
|
2010-06-04 21:47:35 +00:00
|
|
|
} else eprintf ("trace_pc: cannot get opcode size at 0x%"PFMT64x"\n", addr);
|
2011-10-09 02:15:32 +00:00
|
|
|
} //else eprintf ("trace_pc: cannot read memory at 0x%"PFMT64x"\n", addr);
|
2010-06-04 21:47:35 +00:00
|
|
|
} else eprintf ("trace_pc: cannot get program counter\n");
|
2015-09-14 00:08:31 +00:00
|
|
|
return false;
|
2010-03-12 18:11:43 +00:00
|
|
|
}
|
|
|
|
|
2010-06-13 09:59:17 +00:00
|
|
|
R_API void r_debug_trace_at(RDebug *dbg, const char *str) {
|
|
|
|
// TODO: parse offsets and so use ut64 instead of strstr()
|
|
|
|
free (dbg->trace->addresses);
|
|
|
|
dbg->trace->addresses = (str&&*str)? strdup (str): NULL;
|
|
|
|
}
|
|
|
|
|
2010-06-04 21:47:35 +00:00
|
|
|
R_API RDebugTracepoint *r_debug_trace_get (RDebug *dbg, ut64 addr) {
|
2014-11-02 00:21:45 +00:00
|
|
|
Sdb *db = dbg->trace->db;
|
2010-06-04 21:47:35 +00:00
|
|
|
int tag = dbg->trace->tag;
|
2012-02-14 17:19:16 +00:00
|
|
|
RDebugTracepoint *trace;
|
2014-11-02 00:21:45 +00:00
|
|
|
#if R_DEBUG_SDB_TRACES
|
|
|
|
trace = (RDebugTracepoint*)(void*)(size_t)sdb_num_get (db,
|
|
|
|
sdb_fmt (0, "trace.%d.%"PFMT64x, tag, addr), NULL);
|
|
|
|
return trace;
|
|
|
|
#else
|
|
|
|
RListIter *iter;
|
2012-02-14 17:19:16 +00:00
|
|
|
r_list_foreach (dbg->trace->traces, iter, trace) {
|
2010-06-03 22:56:44 +00:00
|
|
|
if (tag != 0 && !(dbg->trace->tag & (1<<tag)))
|
2010-03-12 18:11:43 +00:00
|
|
|
continue;
|
|
|
|
if (trace->addr == addr)
|
|
|
|
return trace;
|
|
|
|
}
|
2014-11-02 00:21:45 +00:00
|
|
|
#endif
|
2010-03-12 18:11:43 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-06-04 21:47:35 +00:00
|
|
|
R_API void r_debug_trace_list (RDebug *dbg, int mode) {
|
|
|
|
int tag = dbg->trace->tag;
|
2012-02-14 17:19:16 +00:00
|
|
|
RListIter *iter;
|
|
|
|
RDebugTracepoint *trace;
|
|
|
|
r_list_foreach (dbg->trace->traces, iter, trace) {
|
2010-06-04 21:47:35 +00:00
|
|
|
if (!trace->tag || (tag & trace->tag)) {
|
2015-08-12 08:40:24 +00:00
|
|
|
switch (mode) {
|
|
|
|
case 1:
|
|
|
|
case '*':
|
2015-08-08 18:15:13 +00:00
|
|
|
dbg->cb_printf ("at+ 0x%"PFMT64x" %d\n", trace->addr, trace->times);
|
2015-08-12 08:40:24 +00:00
|
|
|
break;
|
|
|
|
case 'd':
|
|
|
|
dbg->cb_printf ("pd 1 @ 0x%"PFMT64x"\n", trace->addr);
|
|
|
|
break;
|
|
|
|
case 'l':
|
|
|
|
dbg->cb_printf ("0x%"PFMT64x" ", trace->addr);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
dbg->cb_printf ("0x%08"PFMT64x" size=%d count=%d times=%d tag=%d\n",
|
|
|
|
trace->addr, trace->size, trace->count, trace->times, trace->tag);
|
|
|
|
break;
|
|
|
|
}
|
2010-06-04 21:47:35 +00:00
|
|
|
}
|
2010-03-12 18:11:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-06-13 09:59:17 +00:00
|
|
|
// XXX: find better name, make it public?
|
|
|
|
static int r_debug_trace_is_traceable(RDebug *dbg, ut64 addr) {
|
|
|
|
if (dbg->trace->addresses) {
|
2015-09-14 00:08:31 +00:00
|
|
|
char addr_str[32];
|
2010-06-13 09:59:17 +00:00
|
|
|
snprintf (addr_str, sizeof (addr_str), "0x%08"PFMT64x, addr);
|
2010-06-18 09:09:19 +00:00
|
|
|
if (!strstr (dbg->trace->addresses, addr_str))
|
2015-09-14 00:08:31 +00:00
|
|
|
return false;
|
2010-06-13 09:59:17 +00:00
|
|
|
}
|
2015-09-14 00:08:31 +00:00
|
|
|
return true;
|
2010-06-13 09:59:17 +00:00
|
|
|
}
|
|
|
|
|
2010-06-04 21:47:35 +00:00
|
|
|
R_API RDebugTracepoint *r_debug_trace_add (RDebug *dbg, ut64 addr, int size) {
|
2010-06-13 09:59:17 +00:00
|
|
|
RDebugTracepoint *tp;
|
2010-06-04 21:47:35 +00:00
|
|
|
int tag = dbg->trace->tag;
|
2010-06-13 09:59:17 +00:00
|
|
|
if (!r_debug_trace_is_traceable (dbg, addr))
|
|
|
|
return NULL;
|
2011-02-11 10:22:43 +00:00
|
|
|
r_anal_trace_bb (dbg->anal, addr);
|
2010-06-13 09:59:17 +00:00
|
|
|
tp = r_debug_trace_get (dbg, addr);
|
2010-06-03 22:56:44 +00:00
|
|
|
if (!tp) {
|
2014-10-30 22:58:22 +00:00
|
|
|
tp = R_NEW0 (RDebugTracepoint);
|
2016-05-24 20:22:15 +00:00
|
|
|
if (!tp) return NULL;
|
2010-06-03 22:56:44 +00:00
|
|
|
tp->stamp = r_sys_now ();
|
|
|
|
tp->addr = addr;
|
|
|
|
tp->tags = tag;
|
|
|
|
tp->size = size;
|
2014-10-30 22:58:22 +00:00
|
|
|
tp->count = ++dbg->trace->count;
|
2010-06-17 00:22:50 +00:00
|
|
|
tp->times = 1;
|
2010-06-03 22:56:44 +00:00
|
|
|
r_list_append (dbg->trace->traces, tp);
|
2014-11-02 00:21:45 +00:00
|
|
|
#if R_DEBUG_SDB_TRACES
|
|
|
|
sdb_num_set (dbg->trace->db, sdb_fmt (0, "trace.%d.%"PFMT64x, tag, addr),
|
|
|
|
(ut64)(size_t)tp, 0);
|
|
|
|
#endif
|
2010-06-04 21:47:35 +00:00
|
|
|
} else tp->times++;
|
2010-06-03 22:56:44 +00:00
|
|
|
return tp;
|
2010-03-12 18:11:43 +00:00
|
|
|
}
|
2010-11-24 22:19:17 +00:00
|
|
|
|
|
|
|
R_API void r_debug_trace_reset (RDebug *dbg) {
|
|
|
|
RDebugTrace *t = dbg->trace;
|
2014-05-02 14:54:27 +00:00
|
|
|
r_list_purge (t->traces);
|
2014-11-02 00:21:45 +00:00
|
|
|
#if R_DEBUG_SDB_TRACES
|
|
|
|
sdb_free (t->db);
|
|
|
|
t->db = sdb_new0 ();
|
|
|
|
#endif
|
2010-11-24 22:19:17 +00:00
|
|
|
t->traces = r_list_new ();
|
|
|
|
t->traces->free = free;
|
|
|
|
}
|