radare2/libr/reg/arena.c

205 lines
4.7 KiB
C

/* radare - LGPL - Copyright 2009-2013 - pancake */
#include <r_reg.h>
/* non-endian safe - used for raw mapping with system registers */
R_API ut8* r_reg_get_bytes(RReg *reg, int type, int *size) {
RRegArena *arena;
int i, sz, osize;
ut8 *buf;
if (type == -1) {
/* serialize ALL register types in a single buffer */
// owned buffer is returned
osize = sz = 0;
buf = malloc (8);
for (i=0; i<R_REG_TYPE_LAST; i++) {
arena = reg->regset[i].arena;
sz += arena->size;
buf = realloc (buf, sz);
if (!buf) break;
memcpy (buf+osize, arena->bytes, arena->size);
osize = sz;
}
if (size)
*size = sz;
return buf;
}
if (type<0 || type>R_REG_TYPE_LAST)
return NULL;
sz = reg->regset[type].arena->size;
if (size)
*size = sz;
buf = malloc (sz);
if (buf == NULL)
return NULL;
memcpy (buf, reg->regset[type].arena->bytes, sz);
return buf;
}
/* reduce number of return statements */
R_API int r_reg_set_bytes(RReg *reg, int type, const ut8* buf, int len) {
int i, ret = R_FALSE;
struct r_reg_set_t *regset;
RRegArena *arena;
int off = 0;
if (len<0)
return R_FALSE;
if (type == -1) {
ret = R_TRUE;
/* deserialize ALL register types in a single buffer */
for (i=0; i<R_REG_TYPE_LAST; i++) {
if (!reg->regset[i].arena) {
arena = reg->regset[i].arena = R_NEW (RRegArena);
arena->size = len;
arena->bytes = malloc (len);
} else arena = reg->regset[i].arena;
if (arena->bytes == NULL)
return R_FALSE;
memcpy (arena->bytes, buf+off, arena->size);
off += arena->size;
if (off>len) {
ret = R_FALSE;
break;
}
}
} else {
if (type>=0 && type<=R_REG_TYPE_LAST) {
regset = &reg->regset[type];
arena = regset->arena;
if (len<1) return R_FALSE;
if ((arena->size !=len ) || (arena->bytes == NULL)) {
arena->size = len;
arena->bytes = malloc (len);
}
if (arena->size != len) {
arena->size = len;
// arena->bytes = malloc (len);
regset->arena->bytes = realloc (regset->arena->bytes, len);
}
if (len > arena->size)
len = arena->size;
memset (arena->bytes, 0, arena->size);
memcpy (arena->bytes, buf, len);
ret = R_TRUE;
}
}
return ret;
}
#if 0
R_API int r_reg_arena_copy(RReg *reg, RRegArena *b) {
RReg *
RRegItem *r;
RListIter *iter;
int i, ret = R_FALSE;
if (dst) {
for(i=0;i<R_REG_TYPE_LAST;i++) {
// TODO
}
}
return ret;
}
#endif
R_API int r_reg_fit_arena(RReg *reg) {
RRegArena *arena;
RListIter *iter;
RRegItem *r;
int size, i;
for (i=0; i<R_REG_TYPE_LAST; i++) {
arena = reg->regset[i].arena;
arena->size = 0;
r_list_foreach (reg->regset[i].regs, iter, r) {
size = BITS2BYTES (r->offset+r->size);
if (size>arena->size) {
arena->size = size;
arena->bytes = realloc (arena->bytes, size);
if (arena->bytes == NULL)
return R_FALSE;
}
}
memset (arena->bytes, 0, arena->size);
}
return R_TRUE;
}
R_API RRegArena *r_reg_arena_new (int size) {
RRegArena *arena = R_NEW (RRegArena);
if (arena) {
if (size<1)
size = 1;
if (!(arena->bytes = malloc (size+8))) {
free (arena);
arena = NULL;
} else arena->size = size;
}
return arena;
}
R_API void r_reg_arena_free(RRegArena* ra) {
free (ra->bytes);
free (ra);
}
R_API void r_reg_arena_swap(RReg *reg, int copy) {
int index = (++reg->iters)%2;
r_reg_arena_set (reg, index, copy);
}
R_API int r_reg_arena_set(RReg *reg, int n, int copy) {
int i;
if (n>r_list_length (reg->regset[0].pool)) {
return R_FALSE;
}
for (i=0; i<R_REG_TYPE_LAST; i++) {
RRegArena *o = reg->regset[i].arena;
RRegArena *a = (RRegArena*)r_list_get_n (reg->regset[i].pool, n);
if (!a) {
a = r_reg_arena_new (o->size);
r_list_append (reg->regset[i].pool, a);
}
if (!a) continue;
reg->regset[i].arena = a;
if ((a->size != o->size) && (o->size>0)) {
a->size = o->size;
a->bytes = realloc (a->bytes, a->size+4);
if (!a->bytes) {
eprintf ("Cannot malloc %d in arena\n", a->size);
// XXX This is critical!
return R_FALSE;
}
}
if (copy)
r_reg_set_bytes (reg, i, o->bytes, a->size);
}
return R_TRUE;
}
R_API void r_reg_arena_pop(RReg *reg) {
int i;
for (i=0; i<R_REG_TYPE_LAST; i++) {
if (r_list_length (reg->regset[i].pool)>0) {
RRegArena *arena = r_list_pop (reg->regset[i].pool);
//RRegArena *arena = (RRegArena*) r_list_head (reg->regset[i].pool);
reg->regset[i].arena = arena;
} else {
eprintf ("Cannot pop more\n");
break;
}
}
}
R_API int r_reg_arena_push(RReg *reg) {
int i;
for (i=0; i<R_REG_TYPE_LAST; i++) {
//eprintf ("PUSH %p\n", reg->regset[i].arena);
r_list_push (reg->regset[i].pool, reg->regset[i].arena);
if (!(reg->regset[i].arena = r_reg_arena_new (0)))
return 0;
}
return r_list_length (reg->regset[0].pool);
}