radare2/libr/vm/reg.c
pancake 8f9dbbd0d1 * Remove some use of alloca()
* Fix lock when using 'r2 -d'
* Invalid program name results in error, not warning
2010-10-12 13:22:19 +02:00

256 lines
5.2 KiB
C

/* radare - LGPL - Copyright 2008-2010 pancake<nopcode.org> */
#include "r_vm.h"
/* TODO: use r_reg here..instead of reimplement the fucking same all the time */
static char *unkreg = "(unk)";
/* static */
static struct r_vm_reg_type r_vm_reg_types[] = {
{ R_VMREG_BIT, "bit" },
{ R_VMREG_INT64, "int64" },
{ R_VMREG_INT32, "int32" },
{ R_VMREG_INT16, "int16" },
{ R_VMREG_INT8, "int8" },
{ R_VMREG_FLOAT32, "float32" },
{ R_VMREG_FLOAT64, "float64" },
{ 0, NULL }
};
R_API void r_vm_reg_type_list() {
struct r_vm_reg_type *p = r_vm_reg_types;
while (p && p->str) {
if (p->str==NULL)
break;
printf(" .%s\n", p->str);
p++;
}
}
R_API const char *r_vm_reg_type(int type) {
struct r_vm_reg_type *p = r_vm_reg_types;
while (p && p->str) {
if (p->type == type)
return p->str;
p++;
}
return unkreg;
}
R_API int r_vm_reg_type_i(const char *str) {
struct r_vm_reg_type *p = r_vm_reg_types;
while (p && p->str) {
if (!strcmp(str, p->str))
return p->type;
p++;
}
return -1;
}
R_API int r_vm_reg_del(RVm *vm, const char *name) {
struct list_head *pos;
list_for_each(pos, &vm->regs) {
struct r_vm_reg_t *r = list_entry(pos, struct r_vm_reg_t, list);
if (!strcmp(name, r->name)) {
list_del(&r->list);
return R_FALSE;
}
}
return R_TRUE;
}
R_API int r_vm_reg_set(RVm *vm, const char *name, ut64 value) {
struct list_head *pos;
if (name)
list_for_each(pos, &vm->regs) {
struct r_vm_reg_t *r = list_entry(pos, struct r_vm_reg_t, list);
if (!strcmp(name, r->name)) {
r->value = value;
if (vm->rec == NULL && r->set != NULL) {
vm->rec = r;
r_vm_eval(vm, r->set);
vm->rec = NULL;
}
return R_TRUE;
}
}
return R_FALSE;
}
R_API int r_vm_reg_alias_list(RVm *vm) {
struct r_vm_reg_t *reg;
struct list_head *pos;
int len,space;
eprintf ("Register alias:\n");
list_for_each (pos, &vm->regs) {
reg= list_entry (pos, struct r_vm_reg_t, list);
if (reg->get == NULL && reg->set == NULL)
continue;
len = strlen(reg->name)+1;
printf("%s:", reg->name);
if (len>=R_VM_ALEN) {
space = R_VM_ALEN;
printf("\n");
} else space = R_VM_ALEN-len;
eprintf ("%*cget = %s\n%*cset = %s\n",
space, ' ', reg->get, R_VM_ALEN,' ', reg->set);
}
return 0;
}
R_API int r_vm_reg_alias(RVm *vm, const char *name, const char *get, const char *set) {
struct r_vm_reg_t *reg;
struct list_head *pos;
list_for_each(pos, &vm->regs) {
reg = list_entry(pos, struct r_vm_reg_t, list);
if (!strcmp(name, reg->name)) {
free(reg->get);
reg->get = NULL;
if (get) reg->get = strdup(get);
free(reg->set);
reg->set = NULL;
if (set) reg->set = strdup(set);
return 1;
}
}
eprintf ("Register '%s' not defined.\n", name);
return 0;
}
R_API int r_vm_cmd_eval(RVm *vm, const char *cmd) {
char *next;
do {
next = strchr (cmd,'\n');
if (next) {
*next=0;
next++;
}
if (strlen (cmd)>2 && !memcmp (cmd, "av", 2))
r_vm_cmd_reg (vm, cmd+2);
cmd = next;
} while (next);
return R_TRUE;
}
R_API int r_vm_cmd_reg(RVm *vm, const char *_str) {
char *str, ostr[128], *ptr;
str = ostr;
strncpy (str, _str, sizeof (ostr)-1);
switch(*str) {
case '*':
r_vm_print (vm, -2);
return 0;
case '\0':
r_vm_print (vm, -1);
return 0;
case 'o':
r_vm_cmd_op (vm, str+2);
return 0;
}
str++;
switch (*str) {
case 'r':
r_vm_setup_ret (vm, str+2);
break;
case 'c':
{
char *sp, *bp, *pc = str+2;
sp = strchr(pc, ' ');
if (!sp) return 0;
*sp=0;sp++;
bp = strchr(sp, ' ');
if (!sp) return 0;
*bp=0;bp++;
r_vm_setup_cpu (vm, pc, sp, bp);
}
break;
case 'a':
if (str[1]==' ') {
char *get,*set;
get = strchr (str+2, ' ');
if (get) {
get[0]='\0';
get = get+1;
set = strchr (get, ' ');
if (set) {
*set = '\0';
set++;
r_vm_reg_alias (vm, str+2, get, set);
}
}
} else r_vm_reg_alias_list (vm);
break;
case 't':
r_vm_reg_type_list (vm);
break;
case '+':
// add register
// avr+ eax int32
for (str=str+1;str&&*str==' ';str=str+1);
ptr = strchr(str, ' ');
if (ptr) {
ptr[0]='\0';
r_vm_reg_add (vm, str, r_vm_reg_type_i(ptr+1), 0);
} else r_vm_reg_add (vm, str, R_VMREG_INT32, 0);
break;
case '-':
// rm register
// avr- eax
// avr-*
for(str=str+1;str&&*str==' ';str=str+1);
if (str[0]=='*')
INIT_LIST_HEAD (&vm->regs); // XXX Memory leak
else r_vm_reg_del (vm, str);
break;
case 'f':
r_vm_setup_flags (vm, str+2);
break;
default:
for (;str && *str==' '; str++);
ptr = strchr (str, '=');
if (ptr) {
//vm_eval(str);
r_vm_op_eval (vm, str);
#if 0
/* set register value */
ptr[0]='\0';
vm_eval_eq(str, ptr+1);
ptr[0]='=';
#endif
} else {
if (*str=='.') r_vm_print (vm, r_vm_reg_type_i(str+1));
else eprintf ("%s = 0x%08"PFMT64x"\n", str, r_vm_reg_get(vm, str));
}
}
return 0;
}
R_API ut64 r_vm_reg_get(RVm *vm, const char *name) {
struct list_head *pos;
int len;
if (!name)
return 0LL;
len = strlen (name);
if (name[len-1]==']')
len--;
list_for_each (pos, &vm->regs) {
RVmReg *r = list_entry(pos, struct r_vm_reg_t, list);
if (!strncmp (name, r->name, len)) {
if (vm->rec==NULL && r->get != NULL) {
vm->rec = r;
r_vm_eval(vm, r->get);
//vm_op_eval(r->get);
vm->rec = NULL;
}
return r->value;
}
}
return -1LL;
}