Remove flag list in RFlags and just use hashtable (#12703)

* Do not directly use flags->flags, but use r_flags_foreach functions
* Remove list of flags because unnecessary
* Do not free flagitem when we just need to change the name(aka key)
* Use skiplist to iterate, so we get order for free
* Use RIOMap instead of RIOSection which is being killed
* Free flagitems when ht is freed

There's already the hashtable that can serve to iterate all flagitems.
This commit is contained in:
Riccardo Schirone 2019-01-14 14:15:12 +01:00 committed by GitHub
parent ea92c06e1a
commit 320a258977
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 560 additions and 414 deletions

View File

@ -3499,10 +3499,22 @@ R_API int r_core_anal_data(RCore *core, ut64 addr, int count, int depth, int wor
return true;
}
struct block_flags_stat_t {
ut64 step;
ut64 from;
RCoreAnalStats *as;
};
static bool block_flags_stat(RFlagItem *fi, void *user) {
struct block_flags_stat_t *u = (struct block_flags_stat_t *)user;
int piece = (fi->offset - u->from) / u->step;
u->as->block[piece].flags++;
return true;
}
/* core analysis stats */
/* stats --- colorful bar */
R_API RCoreAnalStats* r_core_anal_get_stats(RCore *core, ut64 from, ut64 to, ut64 step) {
RFlagItem *f;
RAnalFunction *F;
RBinSymbol *S;
RListIter *iter;
@ -3535,14 +3547,9 @@ R_API RCoreAnalStats* r_core_anal_get_stats(RCore *core, ut64 from, ut64 to, ut6
as->block[piece].perm = map ? map->perm: (core->io->desc ? core->io->desc->perm: 0);
}
// iter all flags
r_list_foreach (core->flags->flags, iter, f) {
//if (f->offset+f->size < from) continue;
if (f->offset < from || f->offset > to) {
continue;
}
piece = (f->offset - from) / step;
as->block[piece].flags++;
}
struct block_flags_stat_t u = { .step = step, .from = from, .as = as };
r_flag_foreach_range (core->flags, from, to + 1, block_flags_stat, &u);
// iter all functions
r_list_foreach (core->anal->fcns, iter, F) {
if (F->addr < from || F->addr > to) {

View File

@ -3041,11 +3041,23 @@ static int foreach_comment(void *user, const char *k, const char *v) {
return 1;
}
struct exec_command_t {
RCore *core;
const char *cmd;
};
static bool exec_command_on_flag(RFlagItem *flg, void *u) {
struct exec_command_t *user = (struct exec_command_t *)u;
r_core_seek (user->core, flg->offset, 1);
r_core_block_size (user->core, flg->size);
r_core_cmd0 (user->core, user->cmd);
return true;
}
R_API int r_core_cmd_foreach3(RCore *core, const char *cmd, char *each) { // "@@@"
RDebug *dbg = core->dbg;
RList *list, *head;
RListIter *iter;
RFlagItem *flg;
int i;
switch (each[0]) {
@ -3194,13 +3206,9 @@ R_API int r_core_cmd_foreach3(RCore *core, const char *cmd, char *each) { // "@@
char *glob = r_str_trim (strdup (each + 1));
ut64 off = core->offset;
ut64 obs = core->blocksize;
r_list_foreach (core->flags->flags, iter, flg) {
if (r_str_glob (flg->name, glob)) {
r_core_seek (core, flg->offset, 1);
r_core_block_size (core, flg->size);
r_core_cmd0 (core, cmd);
}
}
struct exec_command_t u = { .core = core, .cmd = cmd };
r_flag_foreach_glob (core->flags, glob, exec_command_on_flag, &u);
r_core_seek (core, off, 0);
r_core_block_size (core, obs);
free (glob);
@ -3278,6 +3286,24 @@ static void foreachOffset (RCore *core, const char *_cmd, const char *each) {
free (cmd);
}
struct duplicate_flag_t {
RList *ret;
const char *word;
};
static bool duplicate_flag(RFlagItem *flag, void *u) {
struct duplicate_flag_t *user = (struct duplicate_flag_t *)u;
/* filter per flag spaces */
if (r_str_glob (flag->name, user->word)) {
RFlagItem *cloned_item = r_flag_item_clone (flag);
if (!cloned_item) {
return false;
}
r_list_append (user->ret, cloned_item);
}
return true;
}
R_API int r_core_cmd_foreach(RCore *core, const char *cmd, char *each) {
int i, j;
char ch;
@ -3585,20 +3611,11 @@ R_API int r_core_cmd_foreach(RCore *core, const char *cmd, char *each) {
the command is going to be executed on flags
values at the moment the command is called
(without side effects) */
r_list_foreach (core->flags->flags, iter, flag) {
/* filter per flag spaces */
if ((flagspace != -1) && (flag->space != flagspace)) {
continue;
}
if (r_str_glob (flag->name, word)) {
RFlagItem *cloned_item = r_flag_item_clone (flag);
if (!cloned_item) {
break;
}
r_list_append (match_flag_items, cloned_item);
}
}
struct duplicate_flag_t u = {
.ret = match_flag_items,
.word = word,
};
r_flag_foreach_space (core->flags, flagspace, duplicate_flag, &u);
/* for all flags that match */
r_list_foreach (match_flag_items, iter, flag) {

View File

@ -43,7 +43,6 @@ static const char *help_msg_f[] = {
"fr"," [old] [[new]]","rename flag (if no new flag current seek one is used)",
"fR","[?] [f] [t] [m]","relocate all flags matching f&~m 'f'rom, 't'o, 'm'ask",
"fs","[?]+-*","manage flagspaces",
"fS","[on]","sort flags by offset or name",
"ft","[?]*","flag tags, useful to find all flags matching some words",
"fV","[*-] [nkey] [offset]","dump/restore visual marks (mK/'K)",
"fx","[d]","show hexdump (or disasm) of flag:flagsize",
@ -168,45 +167,56 @@ static void cmd_fz(RCore *core, const char *input) {
}
}
struct flagbar_t {
RCore *core;
int cols;
};
static bool flagbar_foreach(RFlagItem *fi, void *user) {
struct flagbar_t *u = (struct flagbar_t *)user;
ut64 min = 0, max = r_io_size (u->core->io);
RIOMap *m = r_io_map_get (u->core->io, fi->offset);
if (m) {
min = m->itv.addr;
max = m->itv.addr + m->itv.size;
}
r_cons_printf ("0x%08"PFMT64x" ", fi->offset);
r_print_rangebar (u->core->print, fi->offset, fi->offset + fi->size, min, max, u->cols);
r_cons_printf (" %s\n", fi->name);
return true;
}
static void flagbars(RCore *core, const char *glob) {
int cols = r_cons_get_size (NULL);
RListIter *iter;
RFlagItem *flag;
cols -= 80;
if (cols < 0) {
cols += 80;
}
r_list_foreach (core->flags->flags, iter, flag) {
ut64 min = 0, max = r_io_size (core->io);
RIOMap *map = r_io_map_get (core->io, flag->offset);
if (map) {
min = map->itv.addr;
max = map->itv.addr + map->itv.size;
}
if (r_str_glob (flag->name, glob)) {
r_cons_printf ("0x%08"PFMT64x" ", flag->offset);
r_print_rangebar (core->print, flag->offset, flag->offset + flag->size, min, max, cols);
r_cons_printf (" %s\n", flag->name);
}
struct flagbar_t u = { .core = core, .cols = cols };
r_flag_foreach_glob (core->flags, glob, flagbar_foreach, &u);
}
struct flag_to_flag_t {
ut64 next;
ut64 offset;
};
static bool flag_to_flag_foreach(RFlagItem *fi, void *user) {
struct flag_to_flag_t *u = (struct flag_to_flag_t *)user;
if (fi->offset < u->next && fi->offset > u->offset) {
u->next = fi->offset;
}
return true;
}
static int flag_to_flag(RCore *core, const char *glob) {
RFlagItem *flag;
RListIter *iter;
ut64 next = UT64_MAX;
r_return_val_if_fail (glob, 0);
glob = r_str_trim_ro (glob);
r_list_foreach (core->flags->flags, iter, flag) {
if (flag->offset < next && flag->offset > core->offset) {
if (glob && *glob && !r_str_glob (flag->name, glob)) {
continue;
}
next = flag->offset;
}
}
if (next != UT64_MAX && next > core->offset) {
return next - core->offset;
struct flag_to_flag_t u = { .next = UT64_MAX, .offset = core->offset };
r_flag_foreach_glob (core->flags, glob, flag_to_flag_foreach, &u);
if (u.next != UT64_MAX && u.next > core->offset) {
return u.next - core->offset;
}
return 0;
}
@ -262,23 +272,34 @@ static void cmd_flag_tags (RCore *core, const char *input) {
free (inp);
}
struct rename_flag_t {
RCore *core;
const char *pfx;
int count;
};
static bool rename_flag_ordinal(RFlagItem *fi, void *user) {
struct rename_flag_t *u = (struct rename_flag_t *)user;
char *newName = r_str_newf ("%s%d", u->pfx, u->count++);
if (!newName) {
return false;
}
r_flag_rename (u->core->flags, fi, newName);
free (newName);
return true;
}
static void flag_ordinals(RCore *core, const char *str) {
RFlagItem *flag;
RListIter *iter;
const char *glob = r_str_trim_ro (str);
int count = 0;
char *pfx = strdup (glob);
char *p = strchr (pfx, '*');
if (p) {
*p = 0;
}
r_list_foreach (core->flags->flags, iter, flag) {
if (r_str_glob (flag->name, glob)) {
char *newName = r_str_newf ("%s%d", pfx, count++);
r_flag_rename (core->flags, flag, newName);
free (newName);
}
}
struct rename_flag_t u = { .core = core, .pfx = pfx, .count = 0 };
r_flag_foreach_glob (core->flags, glob, rename_flag_ordinal, &u);
free (pfx);
}
static int cmpflag(const void *_a, const void *_b) {
@ -286,6 +307,39 @@ static int cmpflag(const void *_a, const void *_b) {
return (flag1->offset - flag2->offset);
}
struct find_flag_t {
RFlagItem *win;
ut64 at;
};
static bool find_flag_after(RFlagItem *flag, void *user) {
struct find_flag_t *u = (struct find_flag_t *)user;
if (flag->offset > u->at && (!u->win || flag->offset < u->win->offset)) {
u->win = flag;
}
return true;
}
static bool find_flag_after_foreach(RFlagItem *flag, void *user) {
if (flag->size != 0) {
return true;
}
RFlag *flags = (RFlag *)user;
struct find_flag_t u = { .win = NULL, .at = flag->offset };
r_flag_foreach (flags, find_flag_after, &u);
if (u.win) {
flag->size = u.win->offset - flag->offset;
}
return true;
}
static bool adjust_offset(RFlagItem *flag, void *user) {
st64 base = *(st64 *)user;
flag->offset += base;
return true;
}
static int cmd_flag(void *data, const char *input) {
static int flagenum = 0;
RCore *core = (RCore *)data;
@ -435,15 +489,10 @@ rep:
str = strdup (input + 2);
ptr = strchr (str, ' ');
if (ptr) {
RListIter *iter;
RFlagItem *flag;
RFlag *f = core->flags;
*ptr = 0;
base = r_num_math (core->num, str);
r_list_foreach (f->flags, iter, flag) {
if (r_str_glob (flag->name, ptr+1))
flag->offset += base;
}
r_flag_foreach_glob (f, ptr + 1, adjust_offset, &base);
} else {
core->flags->base = r_num_math (core->num, input+1);
}
@ -576,24 +625,7 @@ rep:
if (glob) {
glob++;
}
RListIter *iter, *iter2;
RFlagItem *flag, *flag2;
r_list_foreach (core->flags->flags, iter, flag) {
if (flag->size == 0 && (!glob || r_str_glob (flag->name, glob))) {
RFlagItem *win = NULL;
ut64 at = flag->offset;
r_list_foreach (core->flags->flags, iter2, flag2) {
if (flag2->offset > at) {
if (!win || flag2->offset < win->offset) {
win = flag2;
}
}
}
if (win) {
flag->size = win->offset - flag->offset;
}
}
}
r_flag_foreach_glob (core->flags, glob, find_flag_after_foreach, core->flags);
} else if (input[1] == ' ') { // "fl ..."
char *p, *arg = strdup (input + 2);
r_str_trim_head_tail (arg);
@ -660,9 +692,6 @@ rep:
case 't': // "ft"
cmd_flag_tags (core, input);
break;
case 'S':
r_flag_sort (core->flags, (input[1]=='n'));
break;
case 's': // "fs"
switch (input[1]) {
case '?':
@ -901,16 +930,13 @@ rep:
arg++;
if (*arg) {
RFlag *f = core->flags;
RList *temp = r_list_new ();
RList *temp = r_flag_all_list (f);
ut64 loff = 0;
ut64 uoff = 0;
ut64 curseek = core->offset;
char *lmatch = NULL , *umatch = NULL;
RFlagItem *flag;
RListIter *iter;
r_list_foreach (f->flags, iter, flag) { // creating a local copy
r_list_append (temp, flag);
}
r_list_sort (temp, &cmpflag);
r_list_foreach (temp, iter, flag) {
if ((f->space_idx != -1) && (flag->space != f->space_idx)) {

View File

@ -1752,11 +1752,35 @@ R_API void r_core_print_examine(RCore *core, const char *str) {
}
}
struct count_pz_t {
int flagspace;
ut64 addr;
ut64 size;
int *ret;
};
static bool count_pzs(RFlagItem *fi, void *u) {
struct count_pz_t *user = (struct count_pz_t *)u;
if (fi->space == user->flagspace &&
((user->addr <= fi->offset && fi->offset < user->addr + user->size) ||
(user->addr <= fi->offset + fi->size && fi->offset + fi->size < user->addr + user->size))) {
(*user->ret)++;
}
return true;
}
static bool count_pzf(RFlagItem *fi, void *u) {
struct count_pz_t *user = (struct count_pz_t *)u;
if (fi->offset <= user->addr && user->addr < fi->offset + fi->size) {
(*user->ret)++;
}
return true;
}
static int printzoomcallback(void *user, int mode, ut64 addr, ut8 *bufz, ut64 size) {
RCore *core = (RCore *) user;
int j, ret = 0;
RListIter *iter;
RFlagItem *flag;
struct count_pz_t u;
switch (mode) {
case '0': // "pz0"
@ -1770,10 +1794,9 @@ static int printzoomcallback(void *user, int mode, ut64 addr, ut8 *bufz, ut64 si
ret = (ut8) (r_hash_entropy_fraction (bufz, size) * 255);
break;
case 'f': // "pzf"
r_list_foreach (core->flags->flags, iter, flag)
if (flag->offset <= addr && addr < flag->offset + flag->size) {
ret++;
}
u.addr = addr;
u.ret = &ret;
r_flag_foreach (core->flags, count_pzf, &u);
break;
case 'F': // "pzF"
for (j = 0; j < size; j++) {
@ -1791,15 +1814,11 @@ static int printzoomcallback(void *user, int mode, ut64 addr, ut8 *bufz, ut64 si
break;
case 's': // "pzs"
j = r_flag_space_get (core->flags, "strings");
r_list_foreach (core->flags->flags, iter, flag) {
if (flag->space == j &&
((addr <= flag->offset &&
flag->offset < addr + size) ||
(addr <= flag->offset + flag->size &&
flag->offset + flag->size < addr + size))) {
ret++;
}
}
u.flagspace = j;
u.addr = addr;
u.size = size;
u.ret = &ret;
r_flag_foreach (core->flags, count_pzs, &u);
break;
case 'h': // "pzh" head
default:

View File

@ -1140,23 +1140,20 @@ static void autocomplete_breakpoints(RLine* line, const char* str) {
line->completion.argv = tmp_argv;
}
static bool add_argv(RFlagItem *fi, void *user) {
int *i = (int *)user;
tmp_argv[(*i)++] = fi->name;
return *i != TMP_ARGV_SZ - 1;
}
static void autocomplete_flags(RLine* line, const char* str) {
RCore *core = line->user;
if (!core || !str) {
return;
}
RListIter *iter;
RFlagItem *flag;
int n, i = 0;
n = strlen (str);
r_list_foreach (core->flags->flags, iter, flag) {
if (!strncmp (flag->name, str, n)) {
tmp_argv[i++] = flag->name;
if (i == (TMP_ARGV_SZ - 1)) {
break;
}
}
}
r_flag_foreach_prefix (core->flags, str, n, add_argv, &i);
tmp_argv[i] = NULL;
line->completion.argc = i;
line->completion.argv = tmp_argv;
@ -1461,7 +1458,6 @@ static bool find_autocomplete(RLine *line) {
static int autocomplete(RLine *line) {
RCore *core = line->user;
RListIter *iter;
RFlagItem *flag;
if (core) {
r_core_free_autocomplete (core);
char *pipe = strchr (line->buffer.data, '>');
@ -1473,14 +1469,7 @@ static int autocomplete(RLine *line) {
ptr = (char *)r_str_trim_ro (ptr + 1);
n = strlen (ptr);//(line->buffer.data+sdelta);
sdelta = (int)(size_t)(ptr - line->buffer.data);
r_list_foreach (core->flags->flags, iter, flag) {
if (!strncmp (flag->name, line->buffer.data+sdelta, n)) {
tmp_argv[i++] = flag->name;
if (i == TMP_ARGV_SZ - 1) {
break;
}
}
}
r_flag_foreach_prefix (core->flags, line->buffer.data + sdelta, n, add_argv, &i);
tmp_argv[i] = NULL;
line->completion.argc = i;
line->completion.argv = tmp_argv;

View File

@ -14,6 +14,12 @@ enum {
R_QWORD_DATA = 8
};
enum {
SORT_NONE,
SORT_NAME,
SORT_OFFSET
};
typedef struct {
RCore *core;
int t_idx;
@ -858,9 +864,16 @@ R_API bool r_core_visual_hudclasses(RCore *core) {
return res? true: false;
}
static bool hudstuff_append(RFlagItem *fi, void *user) {
RList *list = (RList *)user;
char *s = r_str_newf ("0x%08"PFMT64x" %s", fi->offset, fi->name);
if (s) {
r_list_append (list, s);
}
return true;
}
R_API bool r_core_visual_hudstuff(RCore *core) {
RListIter *iter;
RFlagItem *flag;
ut64 addr;
char *res;
RList *list = r_list_new ();
@ -868,10 +881,7 @@ R_API bool r_core_visual_hudstuff(RCore *core) {
return false;
}
list->free = free;
r_list_foreach (core->flags->flags, iter, flag) {
r_list_append (list, r_str_newf ("0x%08"PFMT64x" %s",
flag->offset, flag->name));
}
r_flag_foreach (core->flags, hudstuff_append, list);
sdb_foreach (core->anal->sdb_meta, cmtcb, list);
res = r_cons_hud (list, NULL);
if (res) {
@ -1201,8 +1211,40 @@ R_API int r_core_visual_classes(RCore *core) {
return true;
}
static int flag_name_sort(const void *a, const void *b) {
const RFlagItem *fa = (const RFlagItem *)a;
const RFlagItem *fb = (const RFlagItem *)b;
return strcmp (fa->name, fb->name);
}
static int flag_offset_sort(const void *a, const void *b) {
const RFlagItem *fa = (const RFlagItem *)a;
const RFlagItem *fb = (const RFlagItem *)b;
if (fa->offset < fb->offset) {
return -1;
}
if (fa->offset > fb->offset) {
return 1;
}
return 0;
}
static void sort_flags(RList *l, int sort) {
switch (sort) {
case SORT_NAME:
r_list_sort (l, flag_name_sort);
break;
case SORT_OFFSET:
r_list_sort (l, flag_offset_sort);
break;
case SORT_NONE:
default:
break;
}
}
typedef void (*PrintItemCallback)(void *user, void *p, bool selected);
static void *widget_list (void *user, RList *list, int rows, int cur, PrintItemCallback cb) {
static void *widget_list(void *user, RList *list, int rows, int cur, PrintItemCallback cb) {
void *item, *curItem = NULL;
RListIter *iter;
int count = 0;
@ -1544,14 +1586,13 @@ R_API int r_core_visual_view_rop(RCore *core) {
R_API int r_core_visual_trackflags(RCore *core) {
const char *fs = NULL, *fs2 = NULL;
int hit, i, j, ch;
RListIter *iter;
RFlagItem *flag;
int _option = 0;
int option = 0;
char cmd[1024];
int format = 0;
int delta = 7;
int menu = 0;
int sort = SORT_NONE;
for (j=i=0; i<R_FLAG_SPACES_MAX; i++) {
if (core->flags->spaces[i]) {
@ -1570,14 +1611,18 @@ R_API int r_core_visual_trackflags(RCore *core) {
(core->flags->space_idx==-1)?"*":core->flags->spaces[core->flags->space_idx]);
hit = 0;
i = j = 0;
r_list_foreach (core->flags->flags, iter, flag) {
RList *l = r_flag_all_list (core->flags);
RListIter *iter;
RFlagItem *fi;
sort_flags (l, sort);
r_list_foreach (l, iter, fi) {
/* filter per flag spaces */
if ((core->flags->space_idx != -1) &&
(flag->space != core->flags->space_idx)) {
(fi->space != core->flags->space_idx)) {
continue;
}
if (option == i) {
fs2 = flag->name;
fs2 = fi->name;
hit = 1;
}
if ((i>=option-delta) && ((i<option+delta)||((option<delta)&&(i<(delta<<1))))) {
@ -1586,7 +1631,7 @@ R_API int r_core_visual_trackflags(RCore *core) {
r_cons_printf (Color_INVERT);
}
r_cons_printf (" %c %03d 0x%08"PFMT64x" %4"PFMT64d" %s\n",
cur?'>':' ', i, flag->offset, flag->size, flag->name);
cur?'>':' ', i, fi->offset, fi->size, fi->name);
if (cur && hasColor) {
r_cons_printf (Color_RESET);
}
@ -1594,6 +1639,8 @@ R_API int r_core_visual_trackflags(RCore *core) {
}
i++;
}
r_list_free (l);
if (!hit && i > 0) {
option = i - 1;
continue;
@ -1667,8 +1714,8 @@ R_API int r_core_visual_trackflags(RCore *core) {
}
break;
case 'J': option += 10; break;
case 'o': r_flag_sort (core->flags, 0); break;
case 'n': r_flag_sort (core->flags, 1); break;
case 'o': sort = SORT_OFFSET; break;
case 'n': sort = SORT_NAME; break;
case 'j': option++; break;
case 'k':
if (--option < 0) {
@ -3087,6 +3134,26 @@ beach:
r_config_set_i (core->config, "asm.bytes", asmbytes);
}
struct seek_flag_offset_t {
ut64 offset;
ut64 *next;
bool is_next;
};
static bool seek_flag_offset(RFlagItem *fi, void *user) {
struct seek_flag_offset_t *u = (struct seek_flag_offset_t *)user;
if (u->is_next) {
if (fi->offset < *u->next && fi->offset > u->offset) {
*u->next = fi->offset;
}
} else {
if (fi->offset > *u->next && fi->offset < u->offset) {
*u->next = fi->offset;
}
}
return true;
}
R_API void r_core_seek_next(RCore *core, const char *type) {
RListIter *iter;
ut64 next = UT64_MAX;
@ -3106,21 +3173,11 @@ R_API void r_core_seek_next(RCore *core, const char *type) {
}
} else if (strstr (type, "hit")) {
const char *pfx = r_config_get (core->config, "search.prefix");
RFlagItem *flag;
r_list_foreach (core->flags->flags, iter, flag) {
if (!strncmp (flag->name, pfx, strlen (pfx))) {
if (flag->offset < next && flag->offset > core->offset) {
next = flag->offset;
}
}
}
struct seek_flag_offset_t u = { .offset = core->offset, .next = &next, .is_next = true };
r_flag_foreach_prefix (core->flags, pfx, -1, seek_flag_offset, &u);
} else { // flags
RFlagItem *flag;
r_list_foreach (core->flags->flags, iter, flag) {
if (flag->offset < next && flag->offset > core->offset) {
next = flag->offset;
}
}
struct seek_flag_offset_t u = { .offset = core->offset, .next = &next, .is_next = true };
r_flag_foreach (core->flags, seek_flag_offset, &u);
}
if (next != UT64_MAX) {
r_core_seek (core, next, 1);
@ -3142,22 +3199,12 @@ R_API void r_core_seek_previous (RCore *core, const char *type) {
}
} else
if (strstr (type, "hit")) {
RFlagItem *flag;
const char *pfx = r_config_get (core->config, "search.prefix");
r_list_foreach (core->flags->flags, iter, flag) {
if (!strncmp (flag->name, pfx, strlen (pfx))) {
if (flag->offset > next && flag->offset < core->offset) {
next = flag->offset;
}
}
}
struct seek_flag_offset_t u = { .offset = core->offset, .next = &next, .is_next = false };
r_flag_foreach_prefix (core->flags, pfx, -1, seek_flag_offset, &u);
} else { // flags
RFlagItem *flag;
r_list_foreach (core->flags->flags, iter, flag) {
if (flag->offset > next && flag->offset < core->offset) {
next = flag->offset;
}
}
struct seek_flag_offset_t u = { .offset = core->offset, .next = &next, .is_next = false };
r_flag_foreach (core->flags, seek_flag_offset, &u);
}
if (next != 0) {
r_core_seek (core, next, 1);

View File

@ -2,6 +2,6 @@ include ../config.mk
NAME=r_flag
DEPS=r_util
OBJS=flag.o sort.o spaces.o zones.o tags.o
OBJS=flag.o spaces.o zones.o tags.o
include ../rules.mk

View File

@ -7,8 +7,8 @@
R_LIB_VERSION(r_flag);
#define ISNULLSTR(x) (!(x) || !*(x))
#define IS_IN_SPACE(f, i) ((f)->space_idx != -1 && (i)->space != (f)->space_idx)
#define IS_FI_NOTIN_SPACE(f, i) ((f)->space_idx != -1 && (i)->space != (f)->space_idx)
#define IS_FI_IN_SPACE(fi, spidx) ((spidx) == -1 || (fi)->space == (spidx))
static const char *str_callback(RNum *user, ut64 off, int *ok) {
RFlag *f = (RFlag*)user;
@ -101,7 +101,12 @@ static bool set_name(RFlagItem *item, const char *name) {
return true;
}
R_API RFlag * r_flag_new() {
static void ht_free_flag(HtPPKv *kv) {
free (kv->key);
r_flag_item_free (kv->value);
}
R_API RFlag *r_flag_new() {
int i;
RFlag *f = R_NEW0 (RFlag);
if (!f) {
@ -120,19 +125,13 @@ R_API RFlag * r_flag_new() {
f->zones = NULL;
#endif
f->tags = sdb_new0 ();
f->flags = r_list_new ();
if (!f->flags) {
r_flag_free (f);
return NULL;
}
f->flags->free = (RListFree) r_flag_item_free;
f->space_idx = -1;
f->spacestack = r_list_newf (NULL);
if (!f->spacestack) {
r_flag_free (f);
return NULL;
}
f->ht_name = ht_pp_new0 ();
f->ht_name = ht_pp_new (NULL, ht_free_flag, NULL);
f->by_off = r_skiplist_new (flag_skiplist_free, flag_skiplist_cmp);
#if R_FLAG_ZONE_USE_SDB
sdb_free (f->zones);
@ -187,7 +186,6 @@ R_API RFlag *r_flag_free(RFlag *f) {
r_skiplist_free (f->by_off);
ht_pp_free (f->ht_name);
r_list_free (f->flags);
sdb_free (f->tags);
r_list_free (f->spacestack);
r_num_free (f->num);
@ -195,14 +193,93 @@ R_API RFlag *r_flag_free(RFlag *f) {
return NULL;
}
static bool print_flag_name(RFlagItem *fi, void *user) {
RFlag *flag = (RFlag *)user;
flag->cb_printf ("%s\n", fi->name);
return true;
}
struct print_flag_t {
RFlag *f;
bool in_range;
ut64 range_from;
ut64 range_to;
int fs;
bool first;
bool real;
const char *pfx;
};
static bool print_flag_json(RFlagItem *flag, void *user) {
struct print_flag_t *u = (struct print_flag_t *)user;
if (u->in_range && (flag->offset < u->range_from || flag->offset >= u->range_to)) {
return true;
}
u->f->cb_printf ("%s{\"name\":\"%s\",\"size\":%" PFMT64d ",",
u->first? "": ",", flag->name, flag->size);
if (flag->alias) {
u->f->cb_printf ("\"alias\":\"%s\"", flag->alias);
} else {
u->f->cb_printf ("\"offset\":%"PFMT64d, flag->offset);
}
if (flag->comment) {
u->f->cb_printf (",\"comment\":\"}");
} else {
u->f->cb_printf ("}");
}
u->first = false;
return true;
}
static bool print_flag_rad(RFlagItem *flag, void *user) {
struct print_flag_t *u = (struct print_flag_t *)user;
if (u->in_range && (flag->offset < u->range_from || flag->offset >= u->range_to)) {
return true;
}
if (u->fs == -1 || flag->space != u->fs) {
u->fs = flag->space;
const char *flagspace = r_flag_space_get_i (u->f, u->fs);
if (!flagspace || !*flagspace) {
flagspace = "*";
}
u->f->cb_printf ("fs %s\n", flagspace);
}
if (flag->alias) {
u->f->cb_printf ("fa %s %s\n", flag->name, flag->alias);
if (flag->comment && *flag->comment) {
u->f->cb_printf ("\"fC %s %s\"\n",
flag->name, flag->comment);
}
} else {
u->f->cb_printf ("f %s %"PFMT64d" 0x%08"PFMT64x"%s%s %s\n",
flag->name, flag->size, flag->offset,
u->pfx? "+": "", u->pfx? u->pfx: "",
flag->comment? flag->comment:"");
}
return true;
}
static bool print_flag_orig_name(RFlagItem *flag, void *user) {
struct print_flag_t *u = (struct print_flag_t *)user;
if (u->in_range && (flag->offset < u->range_from || flag->offset >= u->range_to)) {
return true;
}
if (flag->alias) {
const char *n = u->real? flag->realname: flag->name;
u->f->cb_printf ("%s %"PFMT64d" %s\n", flag->alias, flag->size, n);
} else {
const char *n = u->real? flag->realname: (u->f->realnames? flag->realname: flag->name);
u->f->cb_printf ("0x%08"PFMT64x" %"PFMT64d" %s\n", flag->offset, flag->size, n);
}
return true;
}
/* print with r_cons the flag items in the flag f, given as a parameter */
R_API void r_flag_list(RFlag *f, int rad, const char *pfx) {
bool in_range = false;
ut64 range_from = UT64_MAX;
ut64 range_to = UT64_MAX;
int fs = -1;
RListIter *iter;
RFlagItem *flag;
if (rad == 'i') {
char *sp, *arg = strdup (pfx + 1);
sp = strchr (arg, ' ');
@ -227,106 +304,47 @@ R_API void r_flag_list(RFlag *f, int rad, const char *pfx) {
switch (rad) {
case 'q':
r_list_foreach (f->flags, iter, flag) {
if (IS_IN_SPACE (f, flag)) {
continue;
}
f->cb_printf ("%s\n", flag->name);
}
r_flag_foreach_space (f, f->space_idx, print_flag_name, f);
break;
case 'j': {
int first = 1;
f->cb_printf ("[");
r_list_foreach (f->flags, iter, flag) {
if (IS_IN_SPACE (f, flag)) {
continue;
}
if (in_range && (flag->offset < range_from || flag->offset >= range_to)) {
continue;
}
f->cb_printf ("%s{\"name\":\"%s\",\"size\":%"PFMT64d",",
first?"":",", flag->name, flag->size);
if (flag->alias) {
f->cb_printf ("\"alias\":\"%s\"", flag->alias);
} else {
f->cb_printf ("\"offset\":%"PFMT64d, flag->offset);
}
if (flag->comment) {
f->cb_printf (",\"comment\":\"}");
} else {
f->cb_printf ("}");
}
first = 0;
}
struct print_flag_t u = {
.f = f,
.in_range = in_range,
.range_from = range_from,
.range_to = range_to,
.first = true
};
r_flag_foreach_space (f, f->space_idx, print_flag_json, &u);
f->cb_printf ("]\n");
}
break;
}
case 1:
case '*':
r_list_foreach (f->flags, iter, flag) {
if (IS_IN_SPACE (f, flag)) {
continue;
}
if (in_range && (flag->offset < range_from || flag->offset >= range_to)) {
continue;
}
if (fs == -1 || flag->space != fs) {
fs = flag->space;
const char *flagspace = r_flag_space_get_i (f, fs);
if (!flagspace || !*flagspace) {
flagspace = "*";
}
f->cb_printf ("fs %s\n", flagspace);
}
if (flag->alias) {
f->cb_printf ("fa %s %s\n", flag->name, flag->alias);
if (flag->comment && *flag->comment) {
f->cb_printf ("\"fC %s %s\"\n",
flag->name, flag->comment);
}
} else {
f->cb_printf ("f %s %"PFMT64d" 0x%08"PFMT64x"%s%s %s\n",
flag->name, flag->size, flag->offset,
pfx?"+":"", pfx?pfx:"",
flag->comment? flag->comment:"");
}
}
break;
case 'n': // show original name
r_list_foreach (f->flags, iter, flag) {
if (IS_IN_SPACE (f, flag)) {
continue;
}
if (in_range && (flag->offset < range_from || flag->offset >= range_to)) {
continue;
}
if (flag->alias) {
f->cb_printf ("%s %"PFMT64d" %s\n",
flag->alias, flag->size, flag->realname);
} else {
f->cb_printf ("0x%08"PFMT64x" %"PFMT64d" %s\n",
flag->offset, flag->size, flag->realname);
}
}
case '*': {
struct print_flag_t u = {
.f = f,
.in_range = in_range,
.range_from = range_from,
.range_to = range_to,
.fs = fs,
.pfx = pfx
};
r_flag_foreach_space (f, f->space_idx, print_flag_rad, &u);
break;
}
default:
r_list_foreach (f->flags, iter, flag) {
if (IS_IN_SPACE (f, flag)) {
continue;
}
if (in_range && (flag->offset < range_from || flag->offset >= range_to)) {
continue;
}
if (flag->alias) {
f->cb_printf ("%s %"PFMT64d" %s\n",
flag->alias, flag->size, flag->name);
} else {
f->cb_printf ("0x%08"PFMT64x" %"PFMT64d" %s\n",
flag->offset, flag->size, f->realnames ? flag->realname : flag->name);
}
}
case 'n': { // show original name
struct print_flag_t u = {
.f = f,
.in_range = in_range,
.range_from = range_from,
.range_to = range_to,
.real = (rad == 'n')
};
r_flag_foreach_space (f, f->space_idx, print_flag_orig_name, &u);
break;
}
}
}
static RFlagItem *evalFlag(RFlag *f, RFlagItem *item) {
@ -453,7 +471,7 @@ R_API RFlagItem *r_flag_get_at(RFlag *f, ut64 off, bool closest) {
}
while (!nice && flags_at) {
r_list_foreach (flags_at->flags, iter, item) {
if (f->space_strict && IS_IN_SPACE (f, item)) {
if (f->space_strict && IS_FI_NOTIN_SPACE (f, item)) {
continue;
}
if (item->offset == off) {
@ -472,6 +490,20 @@ R_API RFlagItem *r_flag_get_at(RFlag *f, ut64 off, bool closest) {
return nice? evalFlag (f, nice): NULL;
}
static bool append_to_list(void *user, const void *k, const void *v) {
RList *ret = (RList *)user;
r_list_append (ret, (RFlagItem *)v);
return true;
}
R_API RList *r_flag_all_list(RFlag *f) {
RList *ret = r_list_new ();
if (ret) {
ht_pp_foreach (f->ht_name, append_to_list, ret);
}
return ret;
}
/* return the list of flag items that are associated with a given offset */
R_API const RList* /*<RFlagItem*>*/ r_flag_get_list(RFlag *f, ut64 off) {
const RFlagsAtOffset *item = r_flag_get_nearest_list (f, off, 0);
@ -535,10 +567,7 @@ R_API RFlagItem *r_flag_set(RFlag *f, const char *name, ut64 off, ut32 size) {
r_flag_item_free (item);
return NULL;
}
//item share ownership prone to uaf, that is why only
//f->flags has set up free pointer
ht_pp_insert (f->ht_name, item->name, item);
r_list_append (f->flags, item);
}
item->space = f->space_idx;
@ -571,14 +600,14 @@ R_API RFlagItem *r_flag_set(RFlag *f, const char *name, ut64 off, ut32 size) {
R_API void r_flag_item_set_alias(RFlagItem *item, const char *alias) {
r_return_if_fail (item);
free (item->alias);
item->alias = ISNULLSTR (alias)? NULL: strdup (alias);
item->alias = R_STR_ISEMPTY (alias)? NULL: strdup (alias);
}
/* add/replace/remove the comment of a flag item */
R_API void r_flag_item_set_comment(RFlagItem *item, const char *comment) {
r_return_if_fail (item);
free (item->comment);
item->comment = ISNULLSTR (comment) ? NULL : strdup (comment);
item->comment = R_STR_ISEMPTY (comment) ? NULL : strdup (comment);
}
/* add/replace/remove the realname of a flag item */
@ -587,7 +616,7 @@ R_API void r_flag_item_set_realname(RFlagItem *item, const char *realname) {
if (item->name != item->realname) {
free (item->realname);
}
item->realname = ISNULLSTR (realname) ? NULL : strdup (realname);
item->realname = R_STR_ISEMPTY (realname)? NULL: strdup (realname);
}
/* change the name of a flag item, if the new name is available.
@ -595,7 +624,11 @@ R_API void r_flag_item_set_realname(RFlagItem *item, const char *realname) {
R_API int r_flag_rename(RFlag *f, RFlagItem *item, const char *name) {
r_return_val_if_fail (f && item && name && *name, false);
// TODO: add API in ht to update the key of an existing element
HtPPKvFreeFunc ofreefn = f->ht_name->opt.freefn;
f->ht_name->opt.freefn = NULL;
ht_pp_delete (f->ht_name, item->name);
f->ht_name->opt.freefn = ofreefn;
if (!set_name (item, name)) {
return false;
}
@ -611,7 +644,6 @@ R_API bool r_flag_unset(RFlag *f, RFlagItem *item) {
r_return_val_if_fail (f && item, false);
remove_offsetmap (f, item);
ht_pp_delete (f->ht_name, item->name);
r_list_delete_data (f->flags, item);
return true;
}
@ -626,26 +658,30 @@ R_API bool r_flag_unset_off(RFlag *f, ut64 off) {
return false;
}
struct unset_foreach_t {
RFlag *f;
int n;
};
static bool unset_foreach(RFlagItem *fi, void *user) {
struct unset_foreach_t *u = (struct unset_foreach_t *)user;
if (IS_FI_NOTIN_SPACE (u->f, fi)) {
return true;
}
r_flag_unset (u->f, fi);
u->n++;
return true;
}
/* unset all the flag items that satisfy the given glob.
* return the number of unset items. -1 on error */
// XXX This is O(n^n) because unset_globa iterates all flags and unset too.
R_API int r_flag_unset_glob(RFlag *f, const char *glob) {
r_return_val_if_fail (f, -1);
RListIter *iter, *iter2;
RFlagItem *flag;
int n = 0;
r_list_foreach_safe (f->flags, iter, iter2, flag) {
if (IS_IN_SPACE (f, flag)) {
continue;
}
if (r_str_glob (flag->name, glob)) {
r_flag_unset (f, flag);
n++;
}
}
return n;
struct unset_foreach_t u = { .f = f, .n = 0 };
r_flag_foreach_glob (f, glob, unset_foreach, &u);
return u.n;
}
/* unset the flag item with the given name.
@ -660,33 +696,45 @@ R_API bool r_flag_unset_name(RFlag *f, const char *name) {
R_API void r_flag_unset_all(RFlag *f) {
r_return_if_fail (f);
f->space_idx = -1;
r_list_free (f->flags);
f->flags = r_list_newf ((RListFree)r_flag_item_free);
ht_pp_free (f->ht_name);
//don't set free since f->flags will free up items when needed avoiding uaf
f->ht_name = ht_pp_new0 ();
f->ht_name = ht_pp_new (NULL, ht_free_flag, NULL);
r_skiplist_purge (f->by_off);
r_flag_space_unset (f, NULL);
}
struct flag_relocate_t {
ut64 off;
ut64 off_mask;
ut64 neg_mask;
ut64 to;
int n;
};
static bool flag_relocate_foreach(RFlagItem *fi, void *user) {
struct flag_relocate_t *u = (struct flag_relocate_t *)user;
ut64 fn = fi->offset & u->neg_mask;
ut64 on = u->off & u->neg_mask;
if (fn == on) {
ut64 fm = fi->offset & u->off_mask;
ut64 om = u->to & u->off_mask;
fi->offset = (u->to & u->neg_mask) + fm + om;
u->n++;
}
return true;
}
R_API int r_flag_relocate(RFlag *f, ut64 off, ut64 off_mask, ut64 to) {
r_return_val_if_fail (f, -1);
ut64 neg_mask = ~(off_mask);
RFlagItem *item;
RListIter *iter;
int n = 0;
struct flag_relocate_t u = {
.off = off,
.off_mask = off_mask,
.neg_mask = ~(off_mask),
.to = to,
.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_flag_foreach (f, flag_relocate_foreach, &u);
return u.n;
}
R_API bool r_flag_move(RFlag *f, ut64 at, ut64 to) {
@ -725,15 +773,52 @@ R_API void r_flag_bind(RFlag *f, RFlagBind *fb) {
fb->pop_fs = r_flag_space_pop;
}
static bool flag_count_foreach(RFlagItem *fi, void *user) {
int *count = (int *)user;
(*count)++;
return true;
}
R_API int r_flag_count(RFlag *f, const char *glob) {
int count = 0;
RFlagItem *flag;
RListIter *iter;
r_return_val_if_fail (f, -1);
r_list_foreach (f->flags, iter, flag) {
if (r_str_glob (flag->name, glob)) {
count++;
}
}
r_flag_foreach_glob (f, glob, flag_count_foreach, &count);
return count;
}
#define FOREACH_BODY(condition) \
RSkipListNode *it, *tmp; \
RFlagsAtOffset *flags_at; \
RListIter *it2, *tmp2; \
RFlagItem *fi; \
r_skiplist_foreach_safe (f->by_off, it, tmp, flags_at) { \
r_list_foreach_safe (flags_at->flags, it2, tmp2, fi) { \
if (condition) { \
if (!cb (fi, user)) { \
return; \
} \
} \
} \
}
R_API void r_flag_foreach(RFlag *f, RFlagItemCb cb, void *user) {
FOREACH_BODY (true);
}
R_API void r_flag_foreach_prefix(RFlag *f, const char *pfx, int pfx_len, RFlagItemCb cb, void *user) {
pfx_len = pfx_len < 0? strlen (pfx): pfx_len;
FOREACH_BODY (!strncmp (fi->name, pfx, pfx_len));
}
R_API void r_flag_foreach_range(RFlag *f, ut64 from, ut64 to, RFlagItemCb cb, void *user) {
FOREACH_BODY (fi->offset >= from && fi->offset < to);
}
R_API void r_flag_foreach_glob(RFlag *f, const char *glob, RFlagItemCb cb, void *user) {
FOREACH_BODY (!glob || r_str_glob (fi->name, glob));
}
R_API void r_flag_foreach_space(RFlag *f, int space, RFlagItemCb cb, void *user) {
FOREACH_BODY (IS_FI_IN_SPACE (fi, space));
}

View File

@ -1,6 +1,5 @@
r_flag_sources = [
'flag.c',
'sort.c',
'tags.c',
'spaces.c',
'zones.c'

View File

@ -1,58 +0,0 @@
/* radare - LGPL - Copyright 2007-2018 pancake */
#include <r_flag.h>
/* compare names */
static int ncmp(const void *a, const void *b) {
RFlagItem *fa = (RFlagItem *)a;
RFlagItem *fb = (RFlagItem *)b;
return strcmp (fa->name, fb->name);
}
/* compare offsets */
static int cmp(const void *a, const void *b) {
RFlagItem *fa = (RFlagItem *)a;
RFlagItem *fb = (RFlagItem *)b;
if (fa->offset > fb->offset) {
return 1;
}
if (fa->offset < fb->offset) {
return -1;
}
return 0;
}
R_API bool r_flag_sort(RFlag *f, int namesort) {
r_return_val_if_fail (f, false);
bool ret = false;
bool changes = false;
RFlagItem *flag, *fi = NULL;
RListIter *iter, *it_elem;
RList *tmp = r_list_new ();
// find bigger ones after this
if (!tmp) {
return false;
}
do {
changes = false;
fi = NULL;
r_list_foreach (f->flags, iter, flag) {
if (!fi || ((namesort)? ncmp (fi, flag): cmp (fi, flag)) > 0) {
fi = flag;
it_elem = iter;
changes = true;
}
}
if (fi && changes) {
ret = true;
r_list_split_iter (f->flags, it_elem);
free (it_elem);
r_list_append (tmp, fi);
}
} while (changes);
free (f->flags);
f->flags = tmp;
f->flags->free = free;
return ret;
}

View File

@ -90,9 +90,12 @@ R_API int r_flag_space_set(RFlag *f, const char *name) {
return f->space_idx;
}
static bool unset_space(RFlagItem *fi, void *user) {
fi->space = -1;
return true;
}
R_API int r_flag_space_unset(RFlag *f, const char *fs) {
RListIter *iter;
RFlagItem *fi;
r_return_val_if_fail (f, false);
int i, count = 0;
for (i = 0; i < R_FLAG_SPACES_MAX; i++) {
@ -105,27 +108,23 @@ R_API int r_flag_space_unset(RFlag *f, const char *fs) {
}
R_FREE (f->spaces[i]);
// remove all flags space references
r_list_foreach (f->flags, iter, fi) {
if (fi->space == i) {
fi->space = -1;
}
}
r_flag_foreach_space (f, i, unset_space, NULL);
count++;
}
}
return count;
}
static bool space_count(RFlagItem *fi, void *user) {
int *count = (int *)user;
(*count)++;
return true;
}
static int r_flag_space_count(RFlag *f, int n) {
RListIter *iter;
int count = 0;
RFlagItem *fi;
if (n != -1) {
r_list_foreach (f->flags, iter, fi) {
if (fi->space == n) {
count++;
}
}
r_flag_foreach_space (f, n, space_count, &count);
}
return count;
}

View File

@ -32,22 +32,32 @@ R_API void r_flag_tags_reset(RFlag *f, const char *name) {
sdb_reset (f->tags);
}
struct iter_glob_flag_t {
RList *res;
RList *words;
};
static bool iter_glob_flag(RFlagItem *fi, void *user) {
struct iter_glob_flag_t *u = (struct iter_glob_flag_t *)user;
RListIter *iter;
const char *word;
r_list_foreach (u->words, iter, word) {
if (r_str_glob (fi->name, word)) {
r_list_append (u->res, fi);
}
}
return true;
}
R_API RList *r_flag_tags_get(RFlag *f, const char *name) {
r_return_val_if_fail (f && name, NULL);
const char *k = sdb_fmt ("tag.%s", name);
RListIter *iter, *iter2;
const char *word;
RFlagItem *flag;
char *words = sdb_get (f->tags, k, NULL);
RList *res = r_list_newf (NULL);
RList *list = r_str_split_list (words, " ");
r_list_foreach (f->flags, iter2, flag) {
r_list_foreach (list, iter, word) {
if (r_str_glob (flag->name, word)) {
r_list_append (res, flag);
}
}
}
struct iter_glob_flag_t u = { .res = res, .words = list };
r_flag_foreach (f, iter_glob_flag, &u);
r_list_free (list);
return res;
}

View File

@ -58,7 +58,6 @@ typedef struct r_flag_t {
RNum *num;
RSkipList *by_off; /* flags sorted by offset, value=RFlagsAtOffset */
HtPP *ht_name; /* hashmap key=item name, value=RList of items */
RList *flags; /* list of RFlagItem contained in the flag */
RList *spacestack;
PrintfCallback cb_printf;
#if R_FLAG_ZONE_USE_SDB
@ -81,6 +80,8 @@ typedef int (*RFlagSetSpace)(RFlag *f, const char *name);
typedef bool (*RFlagPopSpace)(RFlag *f);
typedef bool (*RFlagPushSpace)(RFlag *f, const char *name);
typedef bool (*RFlagItemCb)(RFlagItem *fi, void *user);
typedef struct r_flag_bind_t {
int init;
RFlag *f;
@ -108,6 +109,7 @@ R_API RFlagItem *r_flag_get(RFlag *f, const char *name);
R_API RFlagItem *r_flag_get_i(RFlag *f, ut64 off);
R_API RFlagItem *r_flag_get_i2(RFlag *f, ut64 off);
R_API RFlagItem *r_flag_get_at(RFlag *f, ut64 off, bool closest);
R_API RList *r_flag_all_list(RFlag *f);
R_API const RList* /*<RFlagItem*>*/ r_flag_get_list(RFlag *f, ut64 off);
R_API char *r_flag_get_liststr(RFlag *f, ut64 off);
R_API bool r_flag_unset(RFlag *f, RFlagItem *item);
@ -116,7 +118,6 @@ R_API bool r_flag_unset_off(RFlag *f, ut64 addr);
R_API void r_flag_unset_all (RFlag *f);
R_API RFlagItem *r_flag_set(RFlag *fo, const char *name, ut64 addr, ut32 size);
R_API RFlagItem *r_flag_set_next(RFlag *fo, const char *name, ut64 addr, ut32 size);
R_API bool r_flag_sort(RFlag *f, int namesort);
R_API void r_flag_item_set_alias(RFlagItem *item, const char *alias);
R_API void r_flag_item_free (RFlagItem *item);
R_API void r_flag_item_set_comment(RFlagItem *item, const char *comment);
@ -127,6 +128,11 @@ R_API int r_flag_rename(RFlag *f, RFlagItem *item, const char *name);
R_API int r_flag_relocate(RFlag *f, ut64 off, ut64 off_mask, ut64 to);
R_API bool r_flag_move (RFlag *f, ut64 at, ut64 to);
R_API const char *r_flag_color(RFlag *f, RFlagItem *it, const char *color);
R_API void r_flag_foreach(RFlag *f, RFlagItemCb cb, void *user);
R_API void r_flag_foreach_prefix(RFlag *f, const char *pfx, int pfx_len, RFlagItemCb cb, void *user);
R_API void r_flag_foreach_range(RFlag *f, ut64 from, ut64 to, RFlagItemCb cb, void *user);
R_API void r_flag_foreach_glob(RFlag *f, const char *glob, RFlagItemCb cb, void *user);
R_API void r_flag_foreach_space(RFlag *f, int space, RFlagItemCb cb, void *user);
/* spaces */
R_API int r_flag_space_get(RFlag *f, const char *name);