Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Refactor/Move esil_trace to anal #23812

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions libr/anal/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ include ${STATIC_ANAL_PLUGINS}
STATIC_OBJS=$(addprefix $(LTOP)/anal/p/,$(STATIC_OBJ))
OBJLIBS=meta.o reflines.o op.o fcn.o bb.o var.o block.o c2/kv.o
OBJLIBS+=value.o class.o type.o type_pdb.o dwarf_process.o
OBJLIBS+=hint.o anal.o data.o xrefs.o sign.o btrace.o
OBJLIBS+=switch.o cycles.o esil_dfg.o esil_cfg.o cond.o
OBJLIBS+=flirt.o labels.o cparse.o tid.o diff.o cc.o
OBJLIBS+=hint.o anal.o data.o xrefs.o sign.o btrace.o diff.o
OBJLIBS+=switch.o cycles.o esil_dfg.o esil_cfg.o cond.o cc.o
OBJLIBS+=flirt.o labels.o cparse.o tid.o anal_esil_trace.o
OBJLIBS+=pin.o vtable.o rtti.o codemeta.o anplugs.o global.o
OBJLIBS+=rtti_msvc.o rtti_itanium.o jmptbl.o function.o

Expand Down
291 changes: 291 additions & 0 deletions libr/anal/anal_esil_trace.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,291 @@
#include <r_arch.h>
#include <r_anal.h>
#include <r_esil.h>
#include <r_reg.h>

static void update_trace_db_op(RAnalEsilTraceDB *db) {
const ut32 trace_op_len = RVecAnalEsilTraceOp_length (&db->ops);
if (!trace_op_len) {
return;
}
RAnalEsilTraceOp *last = RVecAnalEsilTraceOp_at (&db->ops, trace_op_len - 1);
if (!last) {
return;
}
const ut32 vec_idx = RVecAnalEsilAccess_length (&db->accesses);
if (!vec_idx) {
R_LOG_ERROR ("Invalid access database");
return;
}
last->end = vec_idx; // - 1;
}

static void anal_esil_trace_voyeur_reg_read (void *user, const char *name, ut64 val) {
R_RETURN_IF_FAIL (user && name);
char *name_dup = strdup (name);
if (!name_dup) {
R_LOG_ERROR ("Failed to allocate(strdup) memory for storing access");
return;
}
RAnalEsilTraceDB *db = user;
RAnalEsilTraceAccess *access = RVecAnalEsilAccess_emplace_back (&db->accesses);
if (!access) {
free (name_dup);
R_LOG_ERROR ("Failed to allocate memory for storing access");
return;
}
access->reg.name = name_dup;
access->reg.value = val;
access->is_reg = true;
access->is_write = false;
update_trace_db_op (db);
}

static void add_reg_change(RAnalEsilTrace *trace, RRegItem *ri, ut64 data) {
R_RETURN_IF_FAIL (trace && ri);
ut64 addr = ri->offset | (ri->arena << 16);
RVector *vreg = ht_up_find (trace->registers, addr, NULL);
if (R_UNLIKELY (!vreg)) {
vreg = r_vector_new (sizeof (RAnalEsilTraceRegChange), NULL, NULL);
if (R_UNLIKELY (!vreg)) {
R_LOG_ERROR ("creating a register vector");
return;
}
ht_up_insert (trace->registers, addr, vreg);
}
RAnalEsilTraceRegChange reg = {trace->cur_idx, data}; // imho cur_idx is not necessary, we keep track of this in the other vector
r_vector_push (vreg, &reg);
}

static void anal_esil_trace_voyeur_reg_write (void *user, const char *name, ut64 old, ut64 val) {
R_RETURN_IF_FAIL (user && name);
RAnalEsilTrace *trace = user;
RRegItem *ri = r_reg_get (trace->reg, name, -1);
if (!ri) {
return;
}
char *name_dup = strdup (name);
if (!name_dup) {
R_LOG_ERROR ("Failed to allocate(strdup) memory for storing access");
goto fail_name_dup;
}
RAnalEsilTraceAccess *access = RVecAnalEsilAccess_emplace_back (&trace->db.accesses);
if (!access) {
R_LOG_ERROR ("Failed to allocate memory for storing access");
goto fail_emplace_back;
}
access->is_reg = true;
access->reg.name = name_dup;
access->reg.value = val;
access->is_write = true;

add_reg_change (trace, ri, val);
update_trace_db_op (&trace->db);
r_unref (ri);
return;
fail_emplace_back:
free (name_dup);
fail_name_dup:
r_unref (ri);
}

static void anal_esil_trace_voyeur_mem_read (void *user, ut64 addr, const ut8 *buf, int len) {
R_RETURN_IF_FAIL (user && buf && (len > 0));
char *hexbuf = r_hex_bin2strdup (buf, len); //why?
if (!hexbuf) {
R_LOG_ERROR ("Failed to allocate(r_hex_bin2strdup) memory for storing access");
return;
}
RAnalEsilTraceDB *db = user;
RAnalEsilTraceAccess *access = RVecAnalEsilAccess_emplace_back (&db->accesses);
if (!access) {
free (hexbuf);
R_LOG_ERROR ("Failed to allocate memory for storing access");
return;
}
access->is_reg = false;
access->mem.data = hexbuf;
access->mem.addr = addr;
access->is_write = false;
update_trace_db_op (db);
}

static void anal_esil_trace_voyeur_mem_write (void *user, ut64 addr, const ut8 *old, const ut8 *buf, int len) {
R_RETURN_IF_FAIL (user && buf && (len > 0));
char *hexbuf = r_hex_bin2strdup (buf, len); //why?
if (!hexbuf) {
R_LOG_ERROR ("Failed to allocate(r_hex_bin2strdup) memory for storing access");
return;
}
RAnalEsilTrace *trace = user;
RAnalEsilTraceAccess *access = RVecAnalEsilAccess_emplace_back (&trace->db.accesses);
if (!access) {
free (hexbuf);
R_LOG_ERROR ("Failed to allocate memory for storing access");
return;
}
access->is_reg = false;
access->mem.data = hexbuf;
access->mem.addr = addr;
access->is_write = true;
ut32 i;
for (i = 0; i < len; i++) {
//adding each byte one by one is utterly stupid, typical gsoc crap
//ideally this would use a tree structure, that splits nodes when necessary
RVector *vmem = ht_up_find (trace->memory, addr, NULL);
if (!vmem) {
vmem = r_vector_new (sizeof (RAnalEsilTraceMemChange), NULL, NULL);
if (!vmem) {
R_LOG_ERROR ("creating a memory vector");
break;
}
ht_up_insert (trace->memory, addr, vmem);
}
RAnalEsilTraceMemChange mem = {trace->cur_idx, buf[i]};
r_vector_push (vmem, &mem);
}
update_trace_db_op (&trace->db);
}

static void htup_vector_free(HtUPKv *kv) {
if (kv) {
r_vector_free (kv->value);
}
}

static void trace_db_init(RAnalEsilTraceDB *db) {
RVecAnalEsilTraceOp_init (&db->ops);
RVecAnalEsilAccess_init (&db->accesses);
db->loop_counts = ht_uu_new0 ();
}

R_API bool r_anal_esil_trace_init(RAnalEsilTrace *trace, REsil *esil, RReg *reg,
ut64 stack_addr, ut64 stack_size) {
R_RETURN_VAL_IF_FAIL (trace && esil && reg && stack_size, false);
*trace = (const RAnalEsilTrace){0};
trace_db_init (&trace->db);
trace->registers = ht_up_new (NULL, htup_vector_free, NULL);
if (!trace->registers) {
goto fail_registers_ht;
}
trace->memory = ht_up_new (NULL, htup_vector_free, NULL);
if (!trace->memory) {
goto fail_memory_ht;
}
trace->stack_data = malloc (stack_size);
if (!trace->stack_data) {
goto fail_malloc;
}
if (!r_esil_mem_read_silent (esil, stack_addr, trace->stack_data, stack_size)) {
goto fail_read;
}
ut32 i;
for (i = 0; i < R_REG_TYPE_LAST; i++) {
RRegArena *a = reg->regset[i].arena;
RRegArena *b = r_reg_arena_new (a->size);
if (!b) {
goto fail_regs_copy;
}
if (b->bytes && a->bytes && b->size > 0) {
memcpy (b->bytes, a->bytes, b->size);
}
trace->arena[i] = b;
}
trace->reg = reg;
trace->stack_addr = stack_addr;
trace->stack_size = stack_size;
return true;
fail_regs_copy:
while (i) {
i--;
r_reg_arena_free (trace->arena[i]);
}
fail_read:
R_FREE (trace->stack_data);
fail_malloc:
ht_up_free (trace->memory);
trace->memory = NULL;
fail_memory_ht:
ht_up_free (trace->registers);
trace->registers = NULL;
fail_registers_ht:
return false;
}

R_API void r_anal_esil_trace_fini(RAnalEsilTrace *trace) {
R_RETURN_IF_FAIL (trace);
RVecAnalEsilTraceOp_fini (&trace->db.ops);
RVecAnalEsilAccess_fini (&trace->db.accesses);
ht_uu_free (trace->db.loop_counts);
ht_up_free (trace->registers);
ht_up_free (trace->memory);
free (trace->stack_data);
ut32 i;
for (i = 0; i < R_REG_TYPE_LAST; i++) {
r_reg_arena_free (trace->arena[i]);
}
trace[0] = (const RAnalEsilTrace){0};
}

R_API void r_anal_esil_trace_op(RAnalEsilTrace *trace, REsil *esil, RAnalOp *op) {
R_RETURN_IF_FAIL (trace && esil && op);
const char *expr = r_strbuf_get (&op->esil);
if (R_UNLIKELY (!expr || !strlen (expr))) {
R_LOG_WARN ("expr is empty or null");
return;
}
ut32 voy[4];
voy[R_ESIL_VOYEUR_REG_READ] = r_esil_add_voyeur (esil, &trace->db,
anal_esil_trace_voyeur_reg_read, R_ESIL_VOYEUR_REG_READ);
if (R_UNLIKELY (voy[R_ESIL_VOYEUR_REG_READ] == R_ESIL_VOYEUR_ERR)) {
return;
}
voy[R_ESIL_VOYEUR_REG_WRITE] = r_esil_add_voyeur (esil, trace,
anal_esil_trace_voyeur_reg_write, R_ESIL_VOYEUR_REG_WRITE);
if (R_UNLIKELY (voy[R_ESIL_VOYEUR_REG_WRITE] == R_ESIL_VOYEUR_ERR)) {
goto fail_regw_voy;
}
voy[R_ESIL_VOYEUR_MEM_READ] = r_esil_add_voyeur (esil, &trace->db,
anal_esil_trace_voyeur_mem_read, R_ESIL_VOYEUR_MEM_READ);
if (R_UNLIKELY (voy[R_ESIL_VOYEUR_MEM_READ] == R_ESIL_VOYEUR_ERR)) {
goto fail_memr_voy;
}
voy[R_ESIL_VOYEUR_MEM_WRITE] = r_esil_add_voyeur (esil, trace,
anal_esil_trace_voyeur_mem_write, R_ESIL_VOYEUR_MEM_WRITE);
if (R_UNLIKELY (voy[R_ESIL_VOYEUR_MEM_WRITE] == R_ESIL_VOYEUR_ERR)) {
goto fail_memw_voy;
}

RRegItem *ri = r_reg_get (esil->anal->reg, "PC", -1);
if (ri) {
add_reg_change (trace, ri, op->addr);
const bool suc = r_esil_reg_write_silent (esil, ri->name, op->addr);
r_unref (ri);
if (!suc) {
goto fail_set_pc;
}
}

RAnalEsilTraceOp *to = RVecAnalEsilTraceOp_emplace_back (&trace->db.ops);
if (R_LIKELY (to)) {
ut32 vec_idx = RVecAnalEsilAccess_length (&trace->db.accesses);
to->start = vec_idx;
to->end = vec_idx;
to->addr = op->addr;
} else {
R_LOG_WARN ("Couldn't allocate(emplace_back) trace op");
//anything to do here?
}
r_esil_parse (esil, expr);
r_esil_stack_free (esil);
trace->idx++;
trace->end_idx++; // should be vector length?
fail_set_pc:
r_esil_del_voyeur (esil, voy[R_ESIL_VOYEUR_MEM_WRITE]);
fail_memw_voy:
r_esil_del_voyeur (esil, voy[R_ESIL_VOYEUR_MEM_READ]);
fail_memr_voy:
r_esil_del_voyeur (esil, voy[R_ESIL_VOYEUR_REG_WRITE]);
fail_regw_voy:
r_esil_del_voyeur (esil, voy[R_ESIL_VOYEUR_REG_READ]);
}
1 change: 1 addition & 0 deletions libr/anal/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ subdir('d')
r_anal_sources = [
'c2/kv.c',
'anal.c',
'anal_esil_trace.c',
'anplugs.c',
'bb.c',
'block.c',
Expand Down
72 changes: 72 additions & 0 deletions libr/include/r_anal.h
Original file line number Diff line number Diff line change
Expand Up @@ -778,6 +778,73 @@ typedef struct r_anal_esil_dfg_node_t {
ut32 /*RAnalEsilDFGTagType*/ type;
} RAnalEsilDFGNode;

typedef struct r_anal_esil_trace_reg_change_t {
int idx;
ut64 data;
} RAnalEsilTraceRegChange;

typedef struct r_anal_esil_trace_mem_change_t {
int idx;
ut8 data;
} RAnalEsilTraceMemChange;

typedef struct r_anal_esil_trace_register_access_t {
const char *name;
ut64 value;
// TODO: size
} RAnalEsilTraceRegAccess;

typedef struct r_anal_esil_trace_memory_access_t {
char *data;
ut64 addr;
// TODO: size
} RAnalEsilTraceMemAccess;

typedef struct r_anal_esil_trace_access_t {
union {
RAnalEsilTraceRegAccess reg;
RAnalEsilTraceMemAccess mem;
};
bool is_write;
bool is_reg;
} RAnalEsilTraceAccess;

typedef struct r_anal_esil_trace_op_t {
ut64 addr;
ut32 start;
ut32 end; // 1 past the end of the op for this index
} RAnalEsilTraceOp;

static inline void ae_fini_access(RAnalEsilTraceAccess *access) {
if (access->is_reg) {
return;
}
free (access->mem.data);
}

R_VEC_TYPE(RVecAnalEsilTraceOp, RAnalEsilTraceOp);
R_VEC_TYPE_WITH_FINI(RVecAnalEsilAccess, RAnalEsilTraceAccess, ae_fini_access);

typedef struct r_anal_esil_trace_db_t {
RVecAnalEsilTraceOp ops;
RVecAnalEsilAccess accesses;
HtUU *loop_counts;
} RAnalEsilTraceDB;

typedef struct r_anal_esil_trace_t {
RAnalEsilTraceDB db;
int idx;
int end_idx;
int cur_idx;
RReg *reg;
HtUP *registers;
HtUP *memory;
RRegArena *arena[R_REG_TYPE_LAST];
ut64 stack_addr;
ut64 stack_size;
ut8 *stack_data;
} RAnalEsilTrace;

typedef bool (*RAnalCmdCallback)(/* Rcore */RAnal *anal, const char* input);

typedef int (*RAnalOpCallback)(RAnal *a, RAnalOp *op, ut64 addr, const ut8 *data, int len, RAnalOpMask mask);
Expand Down Expand Up @@ -1575,6 +1642,11 @@ R_API void r_anal_esil_dfg_fold_const(RAnal *anal, RAnalEsilDFG *dfg);
R_API RStrBuf *r_anal_esil_dfg_filter(RAnalEsilDFG *dfg, const char *reg);
R_API RStrBuf *r_anal_esil_dfg_filter_expr(RAnal *anal, const char *expr, const char *reg, bool use_map_info, bool use_maps);
R_API bool r_anal_esil_dfg_reg_is_const(RAnalEsilDFG *dfg, const char *reg);

R_API bool r_anal_esil_trace_init(RAnalEsilTrace *trace, REsil *esil, RReg *reg, ut64 stack_addr, ut64 stack_size);
R_API void r_anal_esil_trace_fini(RAnalEsilTrace *trace);
R_API void r_anal_esil_trace_op(RAnalEsilTrace *trace, REsil *esil, RAnalOp *op);

R_API RList *r_anal_types_from_fcn(RAnal *anal, RAnalFunction *fcn);

R_API RAnalBaseType *r_anal_get_base_type(RAnal *anal, const char *name);
Expand Down
Loading