mirror of
https://github.com/radareorg/radare2.git
synced 2024-12-15 09:21:00 +00:00
550 lines
14 KiB
C
550 lines
14 KiB
C
/* radare - LGPL - Copyright 2007-2014 - pancake */
|
|
|
|
#include <r_flags.h>
|
|
#include <r_util.h>
|
|
#include <r_cons.h>
|
|
#include <stdio.h>
|
|
|
|
R_LIB_VERSION(r_flag);
|
|
|
|
static ut64 num_callback (RNum *user, const char *name, int *ok) {
|
|
RFlag *f = (RFlag*)user;
|
|
RList *list;
|
|
|
|
if (ok) *ok = 0;
|
|
|
|
list = r_hashtable64_lookup (f->ht_name, r_str_hash64 (name));
|
|
if (list) {
|
|
RFlagItem *item = r_list_get_top (list);
|
|
// NOTE: to avoid warning infinite loop here we avoid recursivity
|
|
if (item->alias)
|
|
return 0LL;
|
|
if (ok) *ok = 1;
|
|
return item->offset;
|
|
}
|
|
return 0LL;
|
|
}
|
|
|
|
R_API RFlag * r_flag_new() {
|
|
int i;
|
|
RFlag *f = R_NEW (RFlag);
|
|
if (!f) return NULL;
|
|
f->num = r_num_new (&num_callback, f);
|
|
f->base = 0;
|
|
f->flags = r_list_new ();
|
|
f->flags->free = (RListFree) r_flag_item_free;
|
|
f->space_idx = -1;
|
|
f->space_idx2 = -1;
|
|
f->ht_name = r_hashtable64_new ();
|
|
f->ht_off = r_hashtable64_new ();
|
|
for (i=0; i<R_FLAG_SPACES_MAX; i++)
|
|
f->spaces[i] = NULL;
|
|
return f;
|
|
}
|
|
|
|
R_API void r_flag_item_free (RFlagItem *item) {
|
|
free (item->cmd);
|
|
free (item->color);
|
|
free (item->comment);
|
|
free (item->alias);
|
|
item->cmd = item->comment = NULL;
|
|
free (item);
|
|
}
|
|
|
|
R_API RFlag *r_flag_free(RFlag *f) {
|
|
int i;
|
|
#if 0
|
|
RFlagItem *item;
|
|
RListIter *iter;
|
|
r_list_foreach (f->flags, iter, item) {
|
|
RList *list = r_hashtable64_lookup (f->ht_name, item->namehash);
|
|
// XXX r_list_free (list);
|
|
list = r_hashtable64_lookup (f->ht_off, item->offset);
|
|
// XXX: segfault sometimes wtf -- r_list_free (list);
|
|
}
|
|
#endif
|
|
for (i=0; i<R_FLAG_SPACES_MAX; i++)
|
|
free (f->spaces[i]);
|
|
r_hashtable64_free (f->ht_off);
|
|
r_hashtable64_free (f->ht_name);
|
|
r_list_free (f->flags);
|
|
free (f);
|
|
return NULL;
|
|
}
|
|
|
|
R_API void r_flag_list(RFlag *f, int rad) {
|
|
int fs = -1;
|
|
RListIter *iter;
|
|
RFlagItem *flag;
|
|
|
|
switch (rad) {
|
|
case 'j': {
|
|
int first = 1;
|
|
r_cons_printf ("[");
|
|
r_list_foreach_prev (f->flags, iter, flag) {
|
|
if ((f->space_idx != -1) && (flag->space != f->space_idx))
|
|
continue;
|
|
r_cons_printf ("%s{\"name\":\"%s\",\"size\":\"%"PFMT64d"\",",
|
|
first?"":",", flag->name, flag->size);
|
|
if (flag->alias) {
|
|
r_cons_printf ("\"alias\":\"%s\"", flag->alias);
|
|
} else {
|
|
r_cons_printf ("\"offset\":%"PFMT64d, flag->offset);
|
|
}
|
|
if (flag->comment)
|
|
r_cons_printf (",\"comment\":\"}");
|
|
else r_cons_printf ("}");
|
|
first = 0;
|
|
}
|
|
r_cons_printf ("]\n");
|
|
}
|
|
break;
|
|
case 1:
|
|
case '*':
|
|
r_list_foreach_prev (f->flags, iter, flag) {
|
|
if ((f->space_idx != -1) && (flag->space != f->space_idx))
|
|
continue;
|
|
if (fs == -1 || flag->space != fs) {
|
|
const char *flagspace;
|
|
fs = flag->space;
|
|
flagspace = r_flag_space_get_i (f, fs);
|
|
if (!flagspace || !*flagspace)
|
|
flagspace = "*";
|
|
r_cons_printf ("fs %s\n", flagspace);
|
|
}
|
|
if (flag->alias) {
|
|
r_cons_printf ("fa %s %s\n", flag->name, flag->alias);
|
|
if (flag->comment && *flag->comment)
|
|
r_cons_printf ("\"fC %s %s\"\n", flag->name, flag->comment);
|
|
} else {
|
|
r_cons_printf ("f %s %"PFMT64d" 0x%08"PFMT64x" %s\n",
|
|
flag->name, flag->size, flag->offset,
|
|
flag->comment? flag->comment:"");
|
|
}
|
|
}
|
|
break;
|
|
case 'n': // show original name
|
|
r_list_foreach_prev (f->flags, iter, flag) {
|
|
if ((f->space_idx != -1) && (flag->space != f->space_idx))
|
|
continue;
|
|
if (flag->alias) {
|
|
r_cons_printf ("%s %"PFMT64d" %s\n",
|
|
flag->alias, flag->size, flag->realname);
|
|
} else {
|
|
r_cons_printf ("0x%08"PFMT64x" %"PFMT64d" %s\n",
|
|
flag->offset, flag->size, flag->realname);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
r_list_foreach_prev (f->flags, iter, flag) {
|
|
if ((f->space_idx != -1) && (flag->space != f->space_idx))
|
|
continue;
|
|
if (flag->alias) {
|
|
r_cons_printf ("%s %"PFMT64d" %s\n",
|
|
flag->alias, flag->size, flag->name);
|
|
} else {
|
|
r_cons_printf ("0x%08"PFMT64x" %"PFMT64d" %s\n",
|
|
flag->offset, flag->size, flag->name);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static RFlagItem *evalFlag (RFlag *f, RFlagItem *item) {
|
|
if (item) {
|
|
if (item->alias) {
|
|
ut64 res = r_num_math (f->num, item->alias);
|
|
item->offset = res;
|
|
}
|
|
}
|
|
return item;
|
|
}
|
|
|
|
R_API RFlagItem *r_flag_get(RFlag *f, const char *name) {
|
|
RList *list = r_hashtable64_lookup (f->ht_name, r_str_hash64 (name));
|
|
if (list) {
|
|
RFlagItem *item = r_list_get_top (list);
|
|
return evalFlag (f, item);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
R_API RFlagItem *r_flag_get_i2(RFlag *f, ut64 off) {
|
|
// TODO: this is buggy, do not use, must rewrite in sdb
|
|
RFlagItem *oitem = NULL;
|
|
RFlagItem *item = NULL;
|
|
RList *list = r_hashtable64_lookup (f->ht_off, off);
|
|
if (list) {
|
|
RListIter *iter;
|
|
r_list_foreach (list, iter, item) {
|
|
// XXX: hack, because some times the hashtable is poluted by ghost values
|
|
if (item->offset != off)
|
|
continue;
|
|
if (!strchr (item->name, '.'))
|
|
oitem = item;
|
|
if (strlen (item->name) < 5 || item->name[3]!='.')
|
|
continue;
|
|
oitem = item;
|
|
}
|
|
}
|
|
return oitem;
|
|
}
|
|
|
|
#define R_FLAG_TEST 0
|
|
R_API RFlagItem *r_flag_get_i(RFlag *f, ut64 off) {
|
|
RList *list = r_hashtable64_lookup (f->ht_off, off);
|
|
if (list) {
|
|
RFlagItem *item = r_list_get_top (list);
|
|
#if R_FLAG_TEST
|
|
return item;
|
|
#else
|
|
// XXX: hack, because some times the hashtable is poluted by ghost values
|
|
if (item->offset == off)
|
|
return item;
|
|
#endif
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
R_API RFlagItem *r_flag_set(RFlag *f, const char *name, ut64 off, ut32 size, int dup) {
|
|
RFlagItem *item = NULL;
|
|
RListIter *iter2 = NULL;
|
|
RFlagItem *item2 = NULL;
|
|
RList *list2, *list;
|
|
|
|
dup = 0; // XXX: force nondup
|
|
|
|
/* contract fail */
|
|
if (!name || !*name)
|
|
return NULL;
|
|
if (dup) {
|
|
// XXX: doesnt works well
|
|
item = R_NEW0 (RFlagItem);
|
|
if (!r_flag_item_set_name (item, name, NULL)) {
|
|
eprintf ("Invalid flag name '%s'.\n", name);
|
|
free (item);
|
|
return NULL;
|
|
}
|
|
item->space = f->space_idx;
|
|
r_list_append (f->flags, item);
|
|
|
|
item->offset = off + f->base;
|
|
item->size = size;
|
|
|
|
list = r_hashtable64_lookup (f->ht_name, item->namehash);
|
|
if (!list) {
|
|
list = r_list_new ();
|
|
r_hashtable64_insert (f->ht_name, item->namehash, list);
|
|
}
|
|
r_list_append (list, item);
|
|
|
|
list2 = r_hashtable64_lookup (f->ht_off, off);
|
|
if (list2 == NULL) {
|
|
list2 = r_list_new ();
|
|
r_hashtable64_insert (f->ht_name, off, list2);
|
|
}
|
|
r_list_append (list2, item);
|
|
} else {
|
|
item = r_flag_get (f, name);
|
|
if (item) {
|
|
RList *list2, *lol;
|
|
if (item->offset == off)
|
|
return item;
|
|
/* remove old entry */
|
|
list2 = r_hashtable64_lookup (f->ht_off, item->offset);
|
|
if (list2)
|
|
/* No _safe loop necessary because we break immediately after the delete. */
|
|
r_list_foreach (list2, iter2, item2) {
|
|
if (item->namehash != item2->namehash)
|
|
continue;
|
|
if (item2->offset == item->offset) {
|
|
// r_list_delete (list2, iter2);
|
|
// delete without freeing contents
|
|
r_list_split_iter (list2, iter2);
|
|
free (iter2);
|
|
if (r_list_empty (list2)) {
|
|
r_list_free (list2);
|
|
r_hashtable64_remove (f->ht_off, item2->offset);
|
|
r_hashtable64_insert (f->ht_off, item2->offset, NULL);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
lol = r_hashtable64_lookup (f->ht_off, off);
|
|
if (lol == NULL) {
|
|
lol = r_list_new ();
|
|
r_hashtable64_insert (f->ht_off, off, lol);
|
|
}
|
|
r_list_append (lol, item);
|
|
/* update new entry */
|
|
item->offset = off;
|
|
item->size = size;
|
|
} else {
|
|
item = R_NEW0 (RFlagItem);
|
|
if (!r_flag_item_set_name (item, name, NULL)) {
|
|
eprintf ("Invalid flag name '%s'.\n", name);
|
|
free (item);
|
|
return NULL;
|
|
}
|
|
item->space = f->space_idx;
|
|
r_list_append (f->flags, item);
|
|
item->offset = off + f->base;
|
|
item->size = size;
|
|
|
|
list = r_hashtable64_lookup (f->ht_name, item->namehash);
|
|
if (!list) {
|
|
list = r_list_new ();
|
|
r_hashtable64_insert (f->ht_name, item->namehash, list);
|
|
}
|
|
r_list_append (list, item);
|
|
|
|
list2 = r_hashtable64_lookup (f->ht_off, off);
|
|
if (list2 == NULL) {
|
|
list2 = r_list_new ();
|
|
r_hashtable64_insert (f->ht_off, off, list2);
|
|
}
|
|
r_list_append (list2, item);
|
|
}
|
|
}
|
|
return item;
|
|
}
|
|
|
|
#define ISNULLSTR(x) (!x||!*x)
|
|
R_API void r_flag_item_set_alias(RFlagItem *item, const char *alias) {
|
|
if (item) {
|
|
free (item->alias);
|
|
item->alias = ISNULLSTR(alias)? NULL: strdup (alias);
|
|
}
|
|
}
|
|
|
|
R_API void r_flag_item_set_comment(RFlagItem *item, const char *comment) {
|
|
if (item) {
|
|
free (item->comment);
|
|
item->comment = ISNULLSTR(comment)? NULL: strdup (comment);
|
|
}
|
|
}
|
|
|
|
R_API int r_flag_item_set_name(RFlagItem *item, const char *name, const char *realname) {
|
|
int len;
|
|
if (!item)
|
|
return R_FALSE;
|
|
if (!realname)
|
|
realname = name;
|
|
if (!r_name_check (name))
|
|
return R_FALSE;
|
|
/* original name. maybe do some char mangling : printable*/
|
|
/* filtered name : typable */
|
|
strncpy (item->realname, realname, R_FLAG_NAME_SIZE);
|
|
strncpy (item->name, name, R_FLAG_NAME_SIZE);
|
|
len = R_MIN (R_FLAG_NAME_SIZE, strlen (r_str_chop (item->name)) + 1);
|
|
memmove (item->name, r_str_chop (item->name), len);
|
|
r_name_filter (item->name, 0);
|
|
item->name[R_FLAG_NAME_SIZE-1]='\0';
|
|
item->namehash = r_str_hash64 (item->realname);
|
|
return R_TRUE;
|
|
}
|
|
|
|
R_API int r_flag_rename(RFlag *f, RFlagItem *item, const char *name) {
|
|
ut64 hash;
|
|
RList *list;
|
|
if (!f || !item || !name || !*name) {
|
|
eprintf ("r_flag_rename: contract fail\n");
|
|
return R_FALSE;
|
|
}
|
|
hash = r_str_hash64 (item->name);
|
|
list = r_hashtable64_lookup (f->ht_name, hash);
|
|
if (list) {
|
|
RFlagItem *item = r_list_get_top (list);
|
|
if (r_list_empty (list)) {
|
|
//r_list_free (list);
|
|
r_hashtable64_remove (f->ht_name, hash);
|
|
} else {
|
|
r_hashtable64_remove (f->ht_name, hash);
|
|
r_list_delete_data (list, item);
|
|
}
|
|
if (!r_flag_item_set_name (item, name, NULL)) {
|
|
r_list_append (list, item);
|
|
return R_FALSE;
|
|
}
|
|
list = r_hashtable64_lookup (f->ht_name, item->namehash);
|
|
if (!list) {
|
|
list = r_list_new ();
|
|
r_hashtable64_insert (f->ht_name, item->namehash, list);
|
|
}
|
|
r_list_append (list, item);
|
|
}
|
|
return R_TRUE;
|
|
}
|
|
|
|
R_API int r_flag_unset_i(RFlag *f, ut64 off, RFlagItem *p) {
|
|
RFlagItem *flag = r_flag_get_i (f, off);
|
|
if (flag) {
|
|
r_flag_unset (f, flag->name, NULL); //, flag);
|
|
return R_TRUE;
|
|
}
|
|
return R_FALSE;
|
|
}
|
|
|
|
R_API int r_flag_unset_glob(RFlag *f, const char *glob) {
|
|
int n = 0;
|
|
RListIter it, *iter;
|
|
RFlagItem *flag;
|
|
r_list_foreach (f->flags, iter, flag) {
|
|
if ((f->space_idx != -1) && (flag->space != f->space_idx))
|
|
continue;
|
|
if (r_str_glob (flag->name, glob)) {
|
|
it.n = iter->n;
|
|
r_flag_unset (f, flag->name, flag);
|
|
iter = ⁢
|
|
n++;
|
|
}
|
|
}
|
|
return n;
|
|
}
|
|
|
|
static void unflag(RFlag *f, ut64 namehash) {
|
|
RFlagItem *item;
|
|
RListIter *iter;
|
|
/* No _safe loop necessary because we return immediately after the delete. */
|
|
r_list_foreach (f->flags, iter, item) {
|
|
if (item->namehash == namehash) {
|
|
r_list_delete (f->flags, iter);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
R_API int r_flag_unset(RFlag *f, const char *name, RFlagItem *p) {
|
|
ut64 off;
|
|
RListIter *iter2;
|
|
RFlagItem *item2, *item = p;
|
|
ut64 hash = r_str_hash64 (name);
|
|
RList *list2, *list = r_hashtable64_lookup (f->ht_name, hash);
|
|
// list = name hash
|
|
// list2 = off hash
|
|
if (list && list->head) {
|
|
if (!item) item = r_list_pop (list);
|
|
if (!item) return R_FALSE;
|
|
off = item->offset;
|
|
|
|
list2 = r_hashtable64_lookup (f->ht_off, off);
|
|
if (list2) {
|
|
/* delete flag by name */
|
|
/* No _safe loop necessary because we break immediately after the delete. */
|
|
r_list_foreach (list2, iter2, item2) {
|
|
if (hash == item2->namehash) {
|
|
r_list_delete (list2, iter2);
|
|
break;
|
|
}
|
|
}
|
|
if (list2 && r_list_empty (list2)) {
|
|
r_list_free (list2);
|
|
r_hashtable64_remove (f->ht_off, off);
|
|
}
|
|
}
|
|
/* delete from f->flags list */
|
|
unflag (f, hash);
|
|
if (list && r_list_empty (list)) {
|
|
r_list_free (list);
|
|
r_hashtable64_remove (f->ht_name, hash);
|
|
}
|
|
return R_TRUE;
|
|
}
|
|
return R_FALSE;
|
|
}
|
|
|
|
R_API RFlagItem *r_flag_get_at(RFlag *f, ut64 off) {
|
|
RFlagItem *item, *nice = NULL;
|
|
RListIter *iter;
|
|
|
|
r_list_foreach (f->flags, iter, item) {
|
|
if (item->offset == off)
|
|
return item;
|
|
if (off > item->offset) {
|
|
if (nice) {
|
|
if (nice->offset < item->offset)
|
|
nice = item;
|
|
} else nice = item;
|
|
}
|
|
}
|
|
return nice;
|
|
}
|
|
|
|
R_API int r_flag_relocate (RFlag *f, ut64 off, ut64 off_mask, ut64 to) {
|
|
ut64 neg_mask = ~(off_mask);
|
|
RFlagItem *item;
|
|
RListIter *iter;
|
|
int n = 0;
|
|
|
|
r_list_foreach (f->flags, iter, item) {
|
|
ut64 fn = item->offset & neg_mask;
|
|
ut64 on = off & neg_mask;
|
|
if (fn == on) {
|
|
ut64 fm = item->offset & off_mask;
|
|
ut64 om = to & off_mask;
|
|
item->offset = (to&neg_mask) + fm + om;
|
|
n++;
|
|
}
|
|
}
|
|
return n;
|
|
}
|
|
|
|
R_API int r_flag_move (RFlag *f, ut64 at, ut64 to) {
|
|
RFlagItem *item = r_flag_get_i (f, at);
|
|
if (item) {
|
|
r_flag_set (f, item->name, to, item->size, 0);
|
|
return R_TRUE;
|
|
}
|
|
return R_FALSE;
|
|
}
|
|
|
|
#ifdef MYTEST
|
|
int main () {
|
|
RFlagItem *i;
|
|
RFlag *f = r_flag_new ();
|
|
r_flag_set (f, "rip", 0xfff333999000LL, 1, 0);
|
|
r_flag_set (f, "rip", 0xfff333999002LL, 1, 0);
|
|
r_flag_unset (f, "rip", NULL);
|
|
r_flag_set (f, "rip", 3, 4, 0);
|
|
r_flag_set (f, "rip", 4, 4, 0);
|
|
r_flag_set (f, "corwp", 300, 4, 0);
|
|
r_flag_set (f, "barp", 300, 4, 0);
|
|
r_flag_set (f, "rip", 3, 4, 0);
|
|
r_flag_set (f, "rip", 4, 4, 0);
|
|
|
|
i = r_flag_get (f, "rip");
|
|
if (i) printf ("nRIP: %p %llx\n", i, i->offset);
|
|
else printf ("nRIP: null\n");
|
|
|
|
i = r_flag_get_i (f, 0xfff333999000LL);
|
|
if (i) printf ("iRIP: %p %llx\n", i, i->offset);
|
|
else printf ("iRIP: null\n");
|
|
}
|
|
#endif
|
|
|
|
R_API const char *r_flag_color(RFlag *f, RFlagItem *it, const char *color) {
|
|
if (!f || !it)
|
|
return NULL;
|
|
if (!color)
|
|
return it->color;
|
|
free (it->color);
|
|
if (*color)
|
|
it->color = strdup (color);
|
|
else it->color = NULL;
|
|
return it->color;
|
|
}
|
|
|
|
// BIND
|
|
|
|
R_API int r_flag_bind (RFlag *f, RFlagBind *fb) {
|
|
fb->f = f;
|
|
fb->get = r_flag_get;
|
|
fb->set = r_flag_set;
|
|
fb->set_fs = r_flag_space_set;
|
|
return 0;
|
|
}
|