2014-01-08 22:23:06 +00:00
|
|
|
/* radare - LGPL - Copyright 2009-2014 - pancake */
|
2009-09-18 18:11:42 +00:00
|
|
|
|
2009-02-05 21:08:46 +00:00
|
|
|
#include <r_reg.h>
|
2009-09-18 18:11:42 +00:00
|
|
|
#include <r_util.h>
|
2009-09-19 19:54:22 +00:00
|
|
|
#include <list.h>
|
2009-09-18 18:11:42 +00:00
|
|
|
|
2014-01-08 22:23:06 +00:00
|
|
|
R_LIB_VERSION (r_reg);
|
2013-06-14 00:51:33 +00:00
|
|
|
|
2010-02-18 15:36:55 +00:00
|
|
|
static const char *types[R_REG_TYPE_LAST+1] = {
|
2010-01-21 01:38:52 +00:00
|
|
|
"gpr", "drx", "fpu", "mmx", "xmm", "flg", "seg", NULL
|
2010-01-19 10:25:17 +00:00
|
|
|
};
|
|
|
|
|
2010-02-18 15:36:55 +00:00
|
|
|
R_API const char *r_reg_get_type(int idx) {
|
|
|
|
if (idx>=0 && idx<R_REG_TYPE_LAST)
|
|
|
|
return types[idx];
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-09-18 00:51:17 +00:00
|
|
|
static void r_reg_item_free(RRegItem *item) {
|
|
|
|
free (item->name);
|
2010-09-24 02:09:39 +00:00
|
|
|
free (item->flags);
|
2010-09-18 00:51:17 +00:00
|
|
|
free (item);
|
2009-09-18 18:11:42 +00:00
|
|
|
}
|
|
|
|
|
2010-02-03 17:15:31 +00:00
|
|
|
R_API int r_reg_get_name_idx(const char *type) {
|
2010-06-22 18:27:14 +00:00
|
|
|
if (type)
|
|
|
|
switch (*type | (type[1]<<8)) {
|
2014-01-08 22:23:06 +00:00
|
|
|
/* flags */
|
|
|
|
case 'z'+('f'<<8): return R_REG_NAME_ZF;
|
|
|
|
case 's'+('f'<<8): return R_REG_NAME_SF;
|
|
|
|
case 'c'+('f'<<8): return R_REG_NAME_CF;
|
|
|
|
case 'o'+('f'<<8): return R_REG_NAME_OF;
|
|
|
|
/* gpr */
|
2010-06-22 18:27:14 +00:00
|
|
|
case 'p'+('c'<<8): return R_REG_NAME_PC;
|
|
|
|
case 's'+('r'<<8): return R_REG_NAME_SR;
|
|
|
|
case 's'+('p'<<8): return R_REG_NAME_SP;
|
|
|
|
case 'b'+('p'<<8): return R_REG_NAME_BP;
|
2014-01-08 22:23:06 +00:00
|
|
|
/* args */
|
2010-06-22 18:27:14 +00:00
|
|
|
case 'a'+('0'<<8): return R_REG_NAME_A0;
|
|
|
|
case 'a'+('1'<<8): return R_REG_NAME_A1;
|
|
|
|
case 'a'+('2'<<8): return R_REG_NAME_A2;
|
|
|
|
case 'a'+('3'<<8): return R_REG_NAME_A3;
|
2010-02-03 13:34:00 +00:00
|
|
|
}
|
2010-06-22 18:27:14 +00:00
|
|
|
return -1;
|
2010-02-03 17:15:31 +00:00
|
|
|
}
|
|
|
|
|
2010-09-18 00:51:17 +00:00
|
|
|
R_API int r_reg_set_name(RReg *reg, int role, const char *name) {
|
|
|
|
if (role>=0 && role<R_REG_NAME_LAST) {
|
2010-02-03 13:34:00 +00:00
|
|
|
reg->name[role] = r_str_dup (reg->name[role], name);
|
2010-09-18 00:51:17 +00:00
|
|
|
return R_TRUE;
|
|
|
|
}
|
|
|
|
return R_FALSE;
|
2010-02-03 13:34:00 +00:00
|
|
|
}
|
|
|
|
|
2010-09-18 00:51:17 +00:00
|
|
|
R_API const char *r_reg_get_name(RReg *reg, int role) {
|
2010-06-16 07:42:46 +00:00
|
|
|
if (reg && role>=0 && role<R_REG_NAME_LAST)
|
2010-02-03 17:15:31 +00:00
|
|
|
return reg->name[role];
|
2010-02-28 21:58:21 +00:00
|
|
|
return NULL;
|
2010-02-03 17:15:31 +00:00
|
|
|
}
|
|
|
|
|
2010-09-18 00:51:17 +00:00
|
|
|
R_API void r_reg_free_internal(RReg *reg) {
|
|
|
|
int i;
|
2011-07-02 21:15:40 +00:00
|
|
|
for (i=0; i<R_REG_TYPE_LAST; i++) {
|
2010-09-18 00:51:17 +00:00
|
|
|
r_list_destroy (reg->regset[i].regs);
|
2012-12-23 12:52:57 +00:00
|
|
|
reg->regset[i].regs = r_list_newf ((RListFree)r_reg_item_free);
|
2011-07-02 21:15:40 +00:00
|
|
|
}
|
2010-09-18 00:51:17 +00:00
|
|
|
}
|
|
|
|
|
2012-03-07 09:43:02 +00:00
|
|
|
R_API void r_reg_free(RReg *reg) {
|
|
|
|
int i;
|
|
|
|
if (!reg) return;
|
|
|
|
for (i=0; i<R_REG_TYPE_LAST; i++) {
|
|
|
|
r_list_destroy (reg->regset[i].pool);
|
|
|
|
reg->regset[i].pool = NULL;
|
2009-09-18 18:11:42 +00:00
|
|
|
}
|
2012-03-07 09:43:02 +00:00
|
|
|
r_reg_free_internal (reg);
|
|
|
|
free (reg);
|
2009-09-18 18:11:42 +00:00
|
|
|
}
|
|
|
|
|
2010-09-18 00:51:17 +00:00
|
|
|
R_API RReg *r_reg_new() {
|
2009-09-19 19:54:22 +00:00
|
|
|
int i;
|
2011-06-04 01:14:04 +00:00
|
|
|
RRegArena *arena;
|
2011-04-02 16:55:47 +00:00
|
|
|
RReg *reg = R_NEW (RReg);
|
2010-09-23 18:42:35 +00:00
|
|
|
reg->iters = 0;
|
2010-02-05 11:21:37 +00:00
|
|
|
reg->profile = NULL;
|
2011-04-02 16:55:47 +00:00
|
|
|
reg->reg_profile_str = NULL;
|
2010-02-05 11:21:37 +00:00
|
|
|
for (i=0; i<R_REG_NAME_LAST; i++)
|
|
|
|
reg->name[i] = NULL;
|
|
|
|
for (i=0; i<R_REG_TYPE_LAST; i++) {
|
2011-06-04 01:14:04 +00:00
|
|
|
arena = r_reg_arena_new (0);
|
|
|
|
if (!arena) return NULL;
|
2012-12-23 12:52:57 +00:00
|
|
|
reg->regset[i].pool = r_list_newf ((RListFree)r_reg_arena_free);
|
|
|
|
reg->regset[i].regs = r_list_newf ((RListFree)r_reg_item_free);
|
2013-08-29 14:59:24 +00:00
|
|
|
reg->regset[i].arena = arena;
|
|
|
|
//r_list_append (reg->regset[i].pool, arena);
|
2009-09-13 22:37:28 +00:00
|
|
|
}
|
|
|
|
return reg;
|
|
|
|
}
|
2009-02-05 21:08:46 +00:00
|
|
|
|
2010-09-18 00:51:17 +00:00
|
|
|
static RRegItem *r_reg_item_new() {
|
2011-06-04 01:14:04 +00:00
|
|
|
RRegItem *item = R_NEW0 (RRegItem);
|
2009-09-19 19:54:22 +00:00
|
|
|
return item;
|
|
|
|
}
|
|
|
|
|
2010-02-28 21:58:21 +00:00
|
|
|
R_API int r_reg_type_by_name(const char *str) {
|
2010-01-19 10:25:17 +00:00
|
|
|
int i;
|
2010-06-16 07:42:46 +00:00
|
|
|
for (i=0; types[i] && i<R_REG_TYPE_LAST; i++)
|
2010-02-18 15:36:55 +00:00
|
|
|
if (!strcmp (types[i], str))
|
2010-01-19 10:25:17 +00:00
|
|
|
return i;
|
|
|
|
if (!strcmp (str, "all"))
|
|
|
|
return R_REG_TYPE_ALL;
|
|
|
|
eprintf ("Unknown register type: '%s'\n", str);
|
2014-01-08 22:23:06 +00:00
|
|
|
return -1;
|
2009-09-25 02:04:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* TODO: make this parser better and cleaner */
|
2010-09-18 00:51:17 +00:00
|
|
|
static int r_reg_set_word(RRegItem *item, int idx, char *word) {
|
2009-09-19 19:54:22 +00:00
|
|
|
int ret = R_TRUE;
|
2011-03-24 10:03:23 +00:00
|
|
|
switch (idx) {
|
2009-09-19 19:54:22 +00:00
|
|
|
case 0:
|
2010-02-03 13:34:00 +00:00
|
|
|
item->type = r_reg_type_by_name (word);
|
2014-01-08 22:23:06 +00:00
|
|
|
if (item->type == -1) {
|
|
|
|
eprintf ("Invalid reg type\n");
|
|
|
|
ret = R_FALSE;
|
|
|
|
}
|
2009-09-19 19:54:22 +00:00
|
|
|
break;
|
|
|
|
case 1:
|
2010-02-03 13:34:00 +00:00
|
|
|
item->name = strdup (word);
|
2009-09-19 19:54:22 +00:00
|
|
|
break;
|
|
|
|
/* spaguetti ftw!!1 */
|
|
|
|
case 2:
|
|
|
|
if (*word=='.') // XXX; this is kinda ugly
|
2010-02-03 13:34:00 +00:00
|
|
|
item->size = atoi (word+1);
|
|
|
|
else item->size = atoi (word)*8;
|
2009-09-19 19:54:22 +00:00
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
if (*word=='.') // XXX; this is kinda ugly
|
2010-02-03 13:34:00 +00:00
|
|
|
item->offset = atoi (word+1);
|
|
|
|
else item->offset = atoi (word)*8;
|
2009-09-19 19:54:22 +00:00
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
if (*word=='.') // XXX; this is kinda ugly
|
2010-02-03 13:34:00 +00:00
|
|
|
item->packed_size = atoi (word+1);
|
|
|
|
else item->packed_size = atoi (word)*8;
|
2009-09-19 19:54:22 +00:00
|
|
|
break;
|
2010-09-24 02:09:39 +00:00
|
|
|
case 5:
|
|
|
|
item->flags = strdup (word);
|
|
|
|
break;
|
2009-09-19 19:54:22 +00:00
|
|
|
default:
|
2010-02-03 17:15:31 +00:00
|
|
|
eprintf ("register set fail (%s)\n", word);
|
2009-09-19 19:54:22 +00:00
|
|
|
ret = R_FALSE;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* TODO: make this parser better and cleaner */
|
2010-09-18 00:51:17 +00:00
|
|
|
R_API int r_reg_set_profile_string(RReg *reg, const char *str) {
|
|
|
|
RRegItem *item;
|
2010-02-03 17:15:31 +00:00
|
|
|
int setname = -1;
|
2009-09-18 18:11:42 +00:00
|
|
|
int ret = R_FALSE;
|
2009-09-19 19:54:22 +00:00
|
|
|
int lastchar = 0;
|
|
|
|
int chidx = 0;
|
2010-01-21 01:38:52 +00:00
|
|
|
int word = 0;
|
2011-04-02 16:55:47 +00:00
|
|
|
char buf[512];
|
2009-09-19 19:54:22 +00:00
|
|
|
|
2010-06-16 07:42:46 +00:00
|
|
|
if (!str||!reg)
|
2009-09-19 19:54:22 +00:00
|
|
|
return R_FALSE;
|
2011-11-11 16:14:09 +00:00
|
|
|
// XXX double free
|
|
|
|
free (reg->reg_profile_str);
|
2011-04-02 16:55:47 +00:00
|
|
|
reg->reg_profile_str = strdup (str);
|
2011-11-11 16:14:09 +00:00
|
|
|
memset (buf, 0, sizeof (buf));
|
2009-09-19 19:54:22 +00:00
|
|
|
/* format file is: 'type name size offset packedsize' */
|
2010-02-03 13:34:00 +00:00
|
|
|
r_reg_free_internal (reg);
|
|
|
|
item = r_reg_item_new ();
|
2009-09-19 19:54:22 +00:00
|
|
|
|
2010-02-03 13:34:00 +00:00
|
|
|
while (*str) {
|
2009-09-19 19:54:22 +00:00
|
|
|
if (*str == '#') {
|
|
|
|
/* skip until newline */
|
2010-02-03 13:34:00 +00:00
|
|
|
while (*str && *str != '\n') str++;
|
2009-09-19 19:54:22 +00:00
|
|
|
continue;
|
|
|
|
}
|
2010-02-03 13:34:00 +00:00
|
|
|
switch (*str) {
|
2009-09-19 19:54:22 +00:00
|
|
|
case ' ':
|
|
|
|
case '\t':
|
2010-09-18 00:51:17 +00:00
|
|
|
/* UGLY PASTAFARIAN PARSING */
|
2010-02-03 13:34:00 +00:00
|
|
|
if (word==0 && *buf=='=') {
|
2010-02-03 17:15:31 +00:00
|
|
|
setname = r_reg_get_name_idx (buf+1);
|
|
|
|
if (setname == -1)
|
|
|
|
eprintf ("Invalid register type: '%s'\n", buf+1);
|
2010-02-03 13:34:00 +00:00
|
|
|
} else
|
2010-06-16 07:42:46 +00:00
|
|
|
if (lastchar != ' ' && lastchar != '\t')
|
2010-02-03 13:34:00 +00:00
|
|
|
r_reg_set_word (item, word, buf);
|
|
|
|
chidx = 0;
|
|
|
|
word++;
|
2009-09-19 19:54:22 +00:00
|
|
|
break;
|
|
|
|
case '\n':
|
2010-06-16 07:42:46 +00:00
|
|
|
if (setname != -1)
|
2010-02-03 17:15:31 +00:00
|
|
|
r_reg_set_name (reg, setname, buf);
|
2010-06-16 07:42:46 +00:00
|
|
|
else if (word>3) {
|
2010-02-03 13:34:00 +00:00
|
|
|
r_reg_set_word (item, word, buf);
|
2009-09-25 02:04:51 +00:00
|
|
|
if (item->name != NULL) {
|
2011-10-08 21:39:06 +00:00
|
|
|
if (reg->regset[item->type].regs) {
|
|
|
|
r_list_append (reg->regset[item->type].regs, item);
|
|
|
|
item = r_reg_item_new ();
|
|
|
|
} else eprintf ("REGSET is null wtf\n");
|
2009-09-25 02:04:51 +00:00
|
|
|
}
|
2009-09-19 19:54:22 +00:00
|
|
|
}
|
|
|
|
chidx = word = 0;
|
2011-03-24 10:03:23 +00:00
|
|
|
*buf = 0;
|
2010-02-03 17:15:31 +00:00
|
|
|
setname = -1;
|
2009-09-19 19:54:22 +00:00
|
|
|
break;
|
|
|
|
default:
|
2011-03-23 23:54:09 +00:00
|
|
|
if (chidx>128) {// WTF!!
|
|
|
|
eprintf ("PARSE FAILED\n");
|
2009-09-19 19:54:22 +00:00
|
|
|
return R_FALSE;
|
2011-03-23 23:54:09 +00:00
|
|
|
}
|
2009-09-19 19:54:22 +00:00
|
|
|
buf[chidx++] = *str;
|
|
|
|
buf[chidx] = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
lastchar = *str;
|
|
|
|
str++;
|
|
|
|
}
|
2010-09-18 00:51:17 +00:00
|
|
|
r_reg_item_free (item);
|
2010-01-21 01:38:52 +00:00
|
|
|
r_reg_fit_arena (reg);
|
2010-09-18 00:51:17 +00:00
|
|
|
|
2011-11-11 16:14:09 +00:00
|
|
|
return *str? ret: R_TRUE;
|
2009-02-05 21:08:46 +00:00
|
|
|
}
|
|
|
|
|
2010-09-18 00:51:17 +00:00
|
|
|
R_API int r_reg_set_profile(RReg *reg, const char *profile) {
|
2009-09-13 22:37:28 +00:00
|
|
|
int ret = R_FALSE;
|
2011-08-30 17:12:49 +00:00
|
|
|
char *base, *str, *file;
|
2009-09-18 18:11:42 +00:00
|
|
|
/* TODO: append .regs extension to filename */
|
2010-06-16 07:42:46 +00:00
|
|
|
if ((str = r_file_slurp (profile, NULL))==NULL) {
|
2009-09-18 18:11:42 +00:00
|
|
|
// XXX we must define this varname in r_lib.h /compiletime/
|
2010-01-19 10:25:17 +00:00
|
|
|
base = r_sys_getenv ("LIBR_PLUGINS");
|
2009-09-18 18:11:42 +00:00
|
|
|
if (base) {
|
2011-08-27 22:01:03 +00:00
|
|
|
file = r_str_concat (base, profile);
|
2010-01-19 10:25:17 +00:00
|
|
|
str = r_file_slurp (file, NULL);
|
2010-06-16 07:42:46 +00:00
|
|
|
free (file);
|
2009-02-05 21:08:46 +00:00
|
|
|
}
|
|
|
|
}
|
2010-06-16 07:42:46 +00:00
|
|
|
if (str) ret = r_reg_set_profile_string (reg, str);
|
2010-01-19 10:25:17 +00:00
|
|
|
else eprintf ("r_reg_set_profile: Cannot find '%s'\n", profile);
|
2009-02-16 23:09:40 +00:00
|
|
|
return ret;
|
2009-02-05 21:08:46 +00:00
|
|
|
}
|
2009-09-18 18:11:42 +00:00
|
|
|
|
2014-01-28 03:03:35 +00:00
|
|
|
R_API ut64 r_reg_setv(RReg *reg, const char *name, ut64 val) {
|
|
|
|
return r_reg_set_value (reg, r_reg_get (reg, name, -1), val);
|
|
|
|
}
|
|
|
|
|
2013-06-20 00:49:39 +00:00
|
|
|
R_API ut64 r_reg_getv(RReg *reg, const char *name) {
|
|
|
|
return r_reg_get_value (reg, r_reg_get (reg, name, -1));
|
|
|
|
}
|
|
|
|
|
2010-09-18 00:51:17 +00:00
|
|
|
R_API RRegItem *r_reg_get(RReg *reg, const char *name, int type) {
|
|
|
|
RListIter *iter;
|
|
|
|
RRegItem *r;
|
2009-10-12 15:41:52 +00:00
|
|
|
int i, e;
|
2010-10-14 17:01:14 +00:00
|
|
|
if (!reg || !name)
|
2010-06-16 07:42:46 +00:00
|
|
|
return NULL;
|
2009-10-12 15:41:52 +00:00
|
|
|
if (type == -1) {
|
|
|
|
i = 0;
|
|
|
|
e = R_REG_TYPE_LAST;
|
|
|
|
} else {
|
|
|
|
i = type;
|
|
|
|
e = type+1;
|
|
|
|
}
|
2009-09-18 18:11:42 +00:00
|
|
|
|
2010-09-18 00:51:17 +00:00
|
|
|
for (; i<e; i++) {
|
|
|
|
r_list_foreach (reg->regset[i].regs, iter, r) {
|
2014-01-28 03:03:35 +00:00
|
|
|
if (r->name && !strcmp (r->name, name))
|
2010-09-18 00:51:17 +00:00
|
|
|
return r;
|
|
|
|
}
|
2009-09-18 18:11:42 +00:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-09-18 00:51:17 +00:00
|
|
|
R_API RList *r_reg_get_list(RReg *reg, int type) {
|
2014-04-26 22:31:04 +00:00
|
|
|
if (type < 0 || type > (R_REG_TYPE_LAST-1))
|
2009-09-18 18:11:42 +00:00
|
|
|
return NULL;
|
2010-09-18 00:51:17 +00:00
|
|
|
return reg->regset[type].regs;
|
2009-09-18 18:11:42 +00:00
|
|
|
}
|
2010-09-20 12:02:45 +00:00
|
|
|
|
2010-09-24 14:45:56 +00:00
|
|
|
R_API ut64 r_reg_cmp(RReg *reg, RRegItem *item) {
|
2012-06-14 00:18:15 +00:00
|
|
|
ut64 ret, ret2;
|
2013-08-29 14:59:24 +00:00
|
|
|
RListIter *it;
|
2012-06-14 00:18:15 +00:00
|
|
|
int ptr = !(reg->iters%2);
|
2010-09-20 12:02:45 +00:00
|
|
|
int len = (item->size/8); // TODO: must use r_mem_bitcmp or so.. flags not correctly checked
|
2010-09-24 14:45:56 +00:00
|
|
|
int off = BITS2BYTES (item->offset);
|
2013-08-29 14:59:24 +00:00
|
|
|
RRegArena *dst, *src;
|
|
|
|
it = r_list_head (reg->regset[item->type].pool);
|
|
|
|
if (!it || !it->n)
|
|
|
|
return UT64_MAX;
|
|
|
|
src = r_list_head (reg->regset[item->type].pool)->data;
|
|
|
|
dst = it->n->data;
|
2011-06-04 01:14:04 +00:00
|
|
|
if (off+len>src->size) len = src->size-off;
|
2012-02-01 10:49:46 +00:00
|
|
|
if (off+len>dst->size) len = dst->size-off;
|
2013-03-01 11:20:18 +00:00
|
|
|
if (len>1 && memcmp (dst->bytes+off, src->bytes+off, len)) {
|
2010-09-24 14:45:56 +00:00
|
|
|
r_reg_arena_set (reg, ptr, 0);
|
|
|
|
ret = r_reg_get_value (reg, item);
|
|
|
|
r_reg_arena_set (reg, !ptr, 0);
|
2012-06-14 00:18:15 +00:00
|
|
|
ret2 = r_reg_get_value (reg, item);
|
|
|
|
return ret-ret2;
|
2010-09-24 14:45:56 +00:00
|
|
|
}
|
|
|
|
return 0LL;
|
2010-09-20 12:02:45 +00:00
|
|
|
}
|