1 /* radare - LGPL - Copyright 2007-2020 - pancake, ret2libc */
2
3 #include <r_flag.h>
4 #include <r_util.h>
5 #include <r_cons.h>
6 #include <stdio.h>
7
8 R_LIB_VERSION(r_flag);
9
10 #define IS_FI_NOTIN_SPACE(f, i) (r_flag_space_cur (f) && (i)->space != r_flag_space_cur (f))
11 #define IS_FI_IN_SPACE(fi, sp) (!(sp) || (fi)->space == (sp))
12 #define STRDUP_OR_NULL(s) (!R_STR_ISEMPTY (s)? strdup (s): NULL)
13
str_callback(RNum * user,ut64 off,int * ok)14 static const char *str_callback(RNum *user, ut64 off, int *ok) {
15 RFlag *f = (RFlag*)user;
16 if (ok) {
17 *ok = 0;
18 }
19 if (f) {
20 const RList *list = r_flag_get_list (f, off);
21 RFlagItem *item = r_list_get_top (list);
22 if (item) {
23 if (ok) {
24 *ok = true;
25 }
26 return item->name;
27 }
28 }
29 return NULL;
30 }
31
flag_skiplist_free(void * data)32 static void flag_skiplist_free(void *data) {
33 RFlagsAtOffset *item = (RFlagsAtOffset *)data;
34 r_list_free (item->flags);
35 free (data);
36 }
37
flag_skiplist_cmp(const void * va,const void * vb)38 static int flag_skiplist_cmp(const void *va, const void *vb) {
39 const RFlagsAtOffset *a = (RFlagsAtOffset *)va, *b = (RFlagsAtOffset *)vb;
40 if (a->off == b->off) {
41 return 0;
42 }
43 return a->off < b->off? -1: 1;
44 }
45
num_callback(RNum * user,const char * name,int * ok)46 static ut64 num_callback(RNum *user, const char *name, int *ok) {
47 RFlag *f = (RFlag *)user;
48 if (ok) {
49 *ok = 0;
50 }
51 RFlagItem *item = ht_pp_find (f->ht_name, name, NULL);
52 if (item) {
53 // NOTE: to avoid warning infinite loop here we avoid recursivity
54 if (item->alias) {
55 return 0LL;
56 }
57 if (ok) {
58 *ok = 1;
59 }
60 return item->offset;
61 }
62 return 0LL;
63 }
64
free_item_realname(RFlagItem * item)65 static void free_item_realname(RFlagItem *item) {
66 if (item->name != item->realname) {
67 free (item->realname);
68 }
69 }
70
free_item_name(RFlagItem * item)71 static void free_item_name(RFlagItem *item) {
72 if (item->name != item->realname) {
73 free (item->name);
74 }
75 }
76
77 /* return the list of flag at the nearest position.
78 dir == -1 -> result <= off
79 dir == 0 -> result == off
80 dir == 1 -> result >= off*/
r_flag_get_nearest_list(RFlag * f,ut64 off,int dir)81 static RFlagsAtOffset *r_flag_get_nearest_list(RFlag *f, ut64 off, int dir) {
82 RFlagsAtOffset key = { .off = off };
83 RFlagsAtOffset *flags = (dir >= 0)
84 ? r_skiplist_get_geq (f->by_off, &key)
85 : r_skiplist_get_leq (f->by_off, &key);
86 return (dir == 0 && flags && flags->off != off)? NULL: flags;
87 }
88
remove_offsetmap(RFlag * f,RFlagItem * item)89 static void remove_offsetmap(RFlag *f, RFlagItem *item) {
90 r_return_if_fail (f && item);
91 RFlagsAtOffset *flags = r_flag_get_nearest_list (f, item->offset, 0);
92 if (flags) {
93 r_list_delete_data (flags->flags, item);
94 if (r_list_empty (flags->flags)) {
95 r_skiplist_delete (f->by_off, flags);
96 }
97 }
98 }
99
flags_at_offset(RFlag * f,ut64 off)100 static RFlagsAtOffset *flags_at_offset(RFlag *f, ut64 off) {
101 RFlagsAtOffset *res = r_flag_get_nearest_list (f, off, 0);
102 if (res) {
103 return res;
104 }
105
106 // there is no existing flagsAtOffset, we create one now
107 res = R_NEW (RFlagsAtOffset);
108 if (!res) {
109 return NULL;
110 }
111
112 res->flags = r_list_new ();
113 if (!res->flags) {
114 free (res);
115 return NULL;
116 }
117
118 res->off = off;
119 r_skiplist_insert (f->by_off, res);
120 return res;
121 }
122
filter_item_name(const char * name)123 static char *filter_item_name(const char *name) {
124 char *res = strdup (name);
125 if (!res) {
126 return NULL;
127 }
128
129 r_str_trim (res);
130 r_name_filter (res, 0);
131 return res;
132 }
133
set_name(RFlagItem * item,char * name)134 static void set_name(RFlagItem *item, char *name) {
135 free_item_name (item);
136 item->name = name;
137 free_item_realname (item);
138 item->realname = item->name;
139 }
140
update_flag_item_offset(RFlag * f,RFlagItem * item,ut64 newoff,bool is_new,bool force)141 static bool update_flag_item_offset(RFlag *f, RFlagItem *item, ut64 newoff, bool is_new, bool force) {
142 if (item->offset != newoff || force) {
143 if (!is_new) {
144 remove_offsetmap (f, item);
145 }
146 item->offset = newoff;
147
148 RFlagsAtOffset *flagsAtOffset = flags_at_offset (f, newoff);
149 if (!flagsAtOffset) {
150 return false;
151 }
152
153 r_list_append (flagsAtOffset->flags, item);
154 return true;
155 }
156
157 return false;
158 }
159
update_flag_item_name(RFlag * f,RFlagItem * item,const char * newname,bool force)160 static bool update_flag_item_name(RFlag *f, RFlagItem *item, const char *newname, bool force) {
161 if (!f || !item || !newname) {
162 return false;
163 }
164 if (!force && (item->name == newname || (item->name && !strcmp (item->name, newname)))) {
165 return false;
166 }
167 char *fname = filter_item_name (newname);
168 if (!fname) {
169 return false;
170 }
171 bool res = (item->name)
172 ? ht_pp_update_key (f->ht_name, item->name, fname)
173 : ht_pp_insert (f->ht_name, fname, item);
174 if (res) {
175 set_name (item, fname);
176 return true;
177 }
178 free (fname);
179 return false;
180 }
181
ht_free_flag(HtPPKv * kv)182 static void ht_free_flag(HtPPKv *kv) {
183 free (kv->key);
184 r_flag_item_free (kv->value);
185 }
186
count_flags(RFlagItem * fi,void * user)187 static bool count_flags(RFlagItem *fi, void *user) {
188 int *count = (int *)user;
189 (*count)++;
190 return true;
191 }
192
unset_flags_space(RFlagItem * fi,void * user)193 static bool unset_flags_space(RFlagItem *fi, void *user) {
194 fi->space = NULL;
195 return true;
196 }
197
count_flags_in_space(REvent * ev,int type,void * user,void * data)198 static void count_flags_in_space(REvent *ev, int type, void *user, void *data) {
199 RSpaces *sp = (RSpaces *)ev->user;
200 RFlag *f = container_of (sp, RFlag, spaces);
201 RSpaceEvent *spe = (RSpaceEvent *)data;
202 r_flag_foreach_space (f, spe->data.count.space, count_flags, &spe->res);
203 }
204
unset_flagspace(REvent * ev,int type,void * user,void * data)205 static void unset_flagspace(REvent *ev, int type, void *user, void *data) {
206 RSpaces *sp = (RSpaces *)ev->user;
207 RFlag *f = container_of (sp, RFlag, spaces);
208 const RSpaceEvent *spe = (const RSpaceEvent *)data;
209 r_flag_foreach_space (f, spe->data.unset.space, unset_flags_space, NULL);
210 }
211
new_spaces(RFlag * f)212 static void new_spaces(RFlag *f) {
213 r_spaces_init (&f->spaces, "fs");
214 r_event_hook (f->spaces.event, R_SPACE_EVENT_COUNT, count_flags_in_space, NULL);
215 r_event_hook (f->spaces.event, R_SPACE_EVENT_UNSET, unset_flagspace, NULL);
216 }
217
r_flag_new(void)218 R_API RFlag *r_flag_new(void) {
219 RFlag *f = R_NEW0 (RFlag);
220 if (!f) {
221 return NULL;
222 }
223 f->num = r_num_new (&num_callback, &str_callback, f);
224 if (!f->num) {
225 r_flag_free (f);
226 return NULL;
227 }
228 f->base = 0;
229 f->cb_printf = (PrintfCallback)printf;
230 #if R_FLAG_ZONE_USE_SDB
231 f->zones = sdb_new0 ();
232 #else
233 f->zones = NULL;
234 #endif
235 f->tags = sdb_new0 ();
236 f->ht_name = ht_pp_new (NULL, ht_free_flag, NULL);
237 f->by_off = r_skiplist_new (flag_skiplist_free, flag_skiplist_cmp);
238 #if R_FLAG_ZONE_USE_SDB
239 sdb_free (f->zones);
240 #else
241 r_list_free (f->zones);
242 #endif
243 new_spaces(f);
244 return f;
245 }
246
r_flag_item_clone(RFlagItem * item)247 R_API RFlagItem *r_flag_item_clone(RFlagItem *item) {
248 r_return_val_if_fail (item, NULL);
249
250 RFlagItem *n = R_NEW0 (RFlagItem);
251 if (!n) {
252 return NULL;
253 }
254 n->color = STRDUP_OR_NULL (item->color);
255 n->comment = STRDUP_OR_NULL (item->comment);
256 n->alias = STRDUP_OR_NULL (item->alias);
257 n->name = STRDUP_OR_NULL (item->name);
258 n->realname = STRDUP_OR_NULL (item->realname);
259 n->offset = item->offset;
260 n->size = item->size;
261 n->space = item->space;
262 return n;
263 }
264
r_flag_item_free(RFlagItem * item)265 R_API void r_flag_item_free(RFlagItem *item) {
266 if (!item) {
267 return;
268 }
269 free (item->color);
270 free (item->comment);
271 free (item->alias);
272 /* release only one of the two pointers if they are the same */
273 free_item_name (item);
274 free (item->realname);
275 free (item);
276 }
277
r_flag_free(RFlag * f)278 R_API RFlag *r_flag_free(RFlag *f) {
279 r_return_val_if_fail (f, NULL);
280 r_skiplist_free (f->by_off);
281 ht_pp_free (f->ht_name);
282 sdb_free (f->tags);
283 r_spaces_fini (&f->spaces);
284 r_num_free (f->num);
285 r_list_free (f->zones);
286 free (f);
287 return NULL;
288 }
289
print_flag_name(RFlagItem * fi,void * user)290 static bool print_flag_name(RFlagItem *fi, void *user) {
291 RFlag *flag = (RFlag *)user;
292 flag->cb_printf ("%s\n", fi->name);
293 return true;
294 }
295
296 struct print_flag_t {
297 RFlag *f;
298 PJ *pj;
299 bool in_range;
300 ut64 range_from;
301 ut64 range_to;
302 RSpace *fs;
303 bool real;
304 const char *pfx;
305 };
306
print_flag_json(RFlagItem * flag,void * user)307 static bool print_flag_json(RFlagItem *flag, void *user) {
308 struct print_flag_t *u = (struct print_flag_t *)user;
309 if (u->in_range && (flag->offset < u->range_from || flag->offset >= u->range_to)) {
310 return true;
311 }
312 pj_o (u->pj);
313 pj_ks (u->pj, "name", flag->name);
314 if (flag->name != flag->realname) {
315 pj_ks (u->pj, "realname", flag->realname);
316 }
317 pj_ki (u->pj, "size", flag->size);
318 if (flag->alias) {
319 pj_ks (u->pj, "alias", flag->alias);
320 } else {
321 pj_kn (u->pj, "offset", flag->offset);
322 }
323 if (flag->comment) {
324 pj_ks (u->pj, "comment", flag->comment);
325 }
326 pj_end (u->pj);
327 return true;
328 }
329
print_flag_rad(RFlagItem * flag,void * user)330 static bool print_flag_rad(RFlagItem *flag, void *user) {
331 struct print_flag_t *u = (struct print_flag_t *)user;
332 char *comment_b64 = NULL, *tmp = NULL;
333 if (u->in_range && (flag->offset < u->range_from || flag->offset >= u->range_to)) {
334 return true;
335 }
336 if (!u->fs || flag->space != u->fs) {
337 u->fs = flag->space;
338 u->f->cb_printf ("fs %s\n", u->fs? u->fs->name: "*");
339 }
340 if (flag->comment && *flag->comment) {
341 comment_b64 = r_base64_encode_dyn (flag->comment, -1);
342 // prefix the armored string with "base64:"
343 if (comment_b64) {
344 tmp = r_str_newf ("base64:%s", comment_b64);
345 free (comment_b64);
346 comment_b64 = tmp;
347 }
348 }
349 if (flag->alias) {
350 u->f->cb_printf ("fa %s %s\n", flag->name, flag->alias);
351 if (comment_b64) {
352 u->f->cb_printf ("\"fC %s %s\"\n",
353 flag->name, r_str_get (comment_b64));
354 }
355 } else {
356 u->f->cb_printf ("f %s %" PFMT64d " 0x%08" PFMT64x "%s%s %s\n",
357 flag->name, flag->size, flag->offset,
358 u->pfx? "+": "", r_str_get (u->pfx),
359 r_str_get (comment_b64));
360 }
361
362 free (comment_b64);
363 return true;
364 }
365
print_flag_orig_name(RFlagItem * flag,void * user)366 static bool print_flag_orig_name(RFlagItem *flag, void *user) {
367 struct print_flag_t *u = (struct print_flag_t *)user;
368 if (u->in_range && (flag->offset < u->range_from || flag->offset >= u->range_to)) {
369 return true;
370 }
371 if (flag->alias) {
372 const char *n = u->real? flag->realname: flag->name;
373 u->f->cb_printf ("%s %"PFMT64d" %s\n", flag->alias, flag->size, n);
374 } else {
375 const char *n = u->real? flag->realname: (u->f->realnames? flag->realname: flag->name);
376 u->f->cb_printf ("0x%08" PFMT64x " %" PFMT64d " %s\n", flag->offset, flag->size, n);
377 }
378 return true;
379 }
380
381 /* print with r_cons the flag items in the flag f, given as a parameter */
r_flag_list(RFlag * f,int rad,const char * pfx)382 R_API void r_flag_list(RFlag *f, int rad, const char *pfx) {
383 r_return_if_fail (f);
384 bool in_range = false;
385 ut64 range_from = UT64_MAX;
386 ut64 range_to = UT64_MAX;
387 if (rad == 'i') {
388 char *sp, *arg = strdup (pfx + 1);
389 sp = strchr (arg, ' ');
390 if (sp) {
391 *sp++ = 0;
392 range_from = r_num_math (f->num, arg);
393 range_to = r_num_math (f->num, sp);
394 } else {
395 const int bsize = 4096;
396 range_from = r_num_math (f->num, arg);
397 range_to = range_from + bsize;
398 }
399 in_range = true;
400 free (arg);
401 rad = pfx[0];
402 pfx = NULL;
403 }
404
405 if (pfx && !*pfx) {
406 pfx = NULL;
407 }
408
409 switch (rad) {
410 case 'q':
411 r_flag_foreach_space (f, r_flag_space_cur (f), print_flag_name, f);
412 break;
413 case 'j': {
414 PJ *pj = pj_new ();
415 struct print_flag_t u = {
416 .f = f,
417 .pj = pj,
418 .in_range = in_range,
419 .range_from = range_from,
420 .range_to = range_to,
421 .real = false
422 };
423 pj_a (pj);
424 r_flag_foreach_space (f, r_flag_space_cur (f), print_flag_json, &u);
425 pj_end (pj);
426 f->cb_printf ("%s\n", pj_string (pj));
427 pj_free (pj);
428 break;
429 }
430 case 1:
431 case '*': {
432 struct print_flag_t u = {
433 .f = f,
434 .in_range = in_range,
435 .range_from = range_from,
436 .range_to = range_to,
437 .fs = NULL,
438 .pfx = pfx
439 };
440 r_flag_foreach_space (f, r_flag_space_cur (f), print_flag_rad, &u);
441 break;
442 }
443 default:
444 case 'n': {
445 if (!pfx || pfx[0] != 'j') {// show original name
446 struct print_flag_t u = {
447 .f = f,
448 .in_range = in_range,
449 .range_from = range_from,
450 .range_to = range_to,
451 .real = (rad == 'n')
452 };
453 r_flag_foreach_space (f, r_flag_space_cur (f), print_flag_orig_name, &u);
454 } else {
455 PJ *pj = pj_new ();
456 struct print_flag_t u = {
457 .f = f,
458 .pj = pj,
459 .in_range = in_range,
460 .range_from = range_from,
461 .range_to = range_to,
462 .real = true
463 };
464 pj_a (pj);
465 r_flag_foreach_space (f, r_flag_space_cur (f), print_flag_json, &u);
466 pj_end (pj);
467 f->cb_printf ("%s\n", pj_string (pj));
468 pj_free (pj);
469 }
470 break;
471 }
472 }
473 }
474
evalFlag(RFlag * f,RFlagItem * item)475 static RFlagItem *evalFlag(RFlag *f, RFlagItem *item) {
476 r_return_val_if_fail (f && item, NULL);
477 if (item->alias) {
478 item->offset = r_num_math (f->num, item->alias);
479 }
480 return item;
481 }
482
483 /* return true if flag.* exist at offset. Otherwise, false is returned.
484 * For example (f, "sym", 3, 0x1000)*/
r_flag_exist_at(RFlag * f,const char * flag_prefix,ut16 fp_size,ut64 off)485 R_API bool r_flag_exist_at(RFlag *f, const char *flag_prefix, ut16 fp_size, ut64 off) {
486 r_return_val_if_fail (f && flag_prefix, NULL);
487 RListIter *iter = NULL;
488 RFlagItem *item = NULL;
489 const RList *list = r_flag_get_list (f, off);
490 if (list) {
491 r_list_foreach (list, iter, item) {
492 if (item->name && !strncmp (item->name, flag_prefix, fp_size)) {
493 return true;
494 }
495 }
496 }
497 return false;
498 }
499
500 /* return the flag item with name "name" in the RFlag "f", if it exists.
501 * Otherwise, NULL is returned. */
r_flag_get(RFlag * f,const char * name)502 R_API RFlagItem *r_flag_get(RFlag *f, const char *name) {
503 r_return_val_if_fail (f, NULL);
504 RFlagItem *r = ht_pp_find (f->ht_name, name, NULL);
505 return r? evalFlag (f, r): NULL;
506 }
507
508 /* return the first flag item that can be found at offset "off", or NULL otherwise */
r_flag_get_i(RFlag * f,ut64 off)509 R_API RFlagItem *r_flag_get_i(RFlag *f, ut64 off) {
510 r_return_val_if_fail (f, NULL);
511 const RList *list = r_flag_get_list (f, off);
512 return list? evalFlag (f, r_list_get_top (list)): NULL;
513 }
514
515 /* return the first flag that matches an offset ordered by the order of
516 * operands to the function.
517 * Pass in the name of each space, in order, followed by a NULL */
r_flag_get_by_spaces(RFlag * f,ut64 off,...)518 R_API RFlagItem *r_flag_get_by_spaces(RFlag *f, ut64 off, ...) {
519 r_return_val_if_fail (f, NULL);
520
521 const RList *list = r_flag_get_list (f, off);
522 RFlagItem *ret = NULL;
523 const char *spacename;
524 RSpace **spaces;
525 RListIter *iter;
526 RFlagItem *flg;
527 va_list ap, aq;
528 size_t n_spaces = 0, i;
529
530 va_start (ap, off);
531 // some quick checks for common cases
532 if (r_list_empty (list)) {
533 goto beach;
534 }
535 if (r_list_length (list) == 1) {
536 ret = r_list_get_top (list);
537 goto beach;
538 }
539
540 // count spaces in the vaarg
541 va_copy (aq, ap);
542 spacename = va_arg (aq, const char *);
543 while (spacename) {
544 n_spaces++;
545 spacename = va_arg (aq, const char *);
546 }
547 va_end (aq);
548
549 // get RSpaces from the names
550 i = 0;
551 spaces = R_NEWS (RSpace *, n_spaces);
552 spacename = va_arg (ap, const char *);
553 while (spacename) {
554 RSpace *space = r_flag_space_get (f, spacename);
555 if (space) {
556 spaces[i++] = space;
557 }
558 spacename = va_arg (ap, const char *);
559 }
560 n_spaces = i;
561
562 ut64 min_space_i = n_spaces + 1;
563 r_list_foreach (list, iter, flg) {
564 // get the "priority" of the flag flagspace and
565 // check if better than what we found so far
566 for (i = 0; i < n_spaces; i++) {
567 if (flg->space == spaces[i]) {
568 break;
569 }
570 if (i >= min_space_i) {
571 break;
572 }
573 }
574
575 if (i < min_space_i) {
576 min_space_i = i;
577 ret = flg;
578 }
579 if (!min_space_i) {
580 // this is the best flag we can find, let's stop immediately
581 break;
582 }
583 }
584 free (spaces);
585 beach:
586 va_end (ap);
587 return ret? evalFlag (f, ret): NULL;
588 }
589
isFunctionFlag(const char * n)590 static bool isFunctionFlag(const char *n) {
591 return (!strncmp (n, "sym.func.", 9)
592 || !strncmp (n, "method.", 7)
593 || !strncmp (n, "sym.", 4)
594 || !strncmp (n, "func.", 5)
595 || !strncmp (n, "fcn.0", 5));
596 }
597
598 /* returns the last flag item defined before or at the given offset.
599 * NULL is returned if such a item is not found. */
r_flag_get_at(RFlag * f,ut64 off,bool closest)600 R_API RFlagItem *r_flag_get_at(RFlag *f, ut64 off, bool closest) {
601 r_return_val_if_fail (f, NULL);
602
603 RFlagItem *nice = NULL;
604 RListIter *iter;
605 const RFlagsAtOffset *flags_at = r_flag_get_nearest_list (f, off, -1);
606 if (!flags_at) {
607 return NULL;
608 }
609 if (flags_at->off == off) {
610 RFlagItem *item;
611 r_list_foreach (flags_at->flags, iter, item) {
612 if (IS_FI_NOTIN_SPACE (f, item)) {
613 continue;
614 }
615 if (nice) {
616 if (isFunctionFlag (nice->name)) {
617 nice = item;
618 }
619 } else {
620 nice = item;
621 }
622 }
623 if (nice) {
624 return evalFlag (f, nice);
625 }
626 }
627
628 if (!closest) {
629 return NULL;
630 }
631 while (!nice && flags_at) {
632 RFlagItem *item;
633 r_list_foreach (flags_at->flags, iter, item) {
634 if (IS_FI_NOTIN_SPACE (f, item)) {
635 continue;
636 }
637 if (item->offset == off) {
638 eprintf ("XXX Should never happend\n");
639 return evalFlag (f, item);
640 }
641 nice = item;
642 break;
643 }
644 if (!nice && flags_at->off) {
645 flags_at = r_flag_get_nearest_list (f, flags_at->off - 1, -1);
646 } else {
647 flags_at = NULL;
648 }
649 }
650 return nice? evalFlag (f, nice): NULL;
651 }
652
append_to_list(RFlagItem * fi,void * user)653 static bool append_to_list(RFlagItem *fi, void *user) {
654 RList *ret = (RList *)user;
655 r_list_append (ret, fi);
656 return true;
657 }
658
r_flag_all_list(RFlag * f,bool by_space)659 R_API RList *r_flag_all_list(RFlag *f, bool by_space) {
660 RList *ret = r_list_new ();
661 if (!ret) {
662 return NULL;
663 }
664
665 RSpace *cur = by_space? r_flag_space_cur (f): NULL;
666 r_flag_foreach_space (f, cur, append_to_list, ret);
667 return ret;
668 }
669
670 /* return the list of flag items that are associated with a given offset */
r_flag_get_list(RFlag * f,ut64 off)671 R_API const RList* /*<RFlagItem*>*/ r_flag_get_list(RFlag *f, ut64 off) {
672 const RFlagsAtOffset *item = r_flag_get_nearest_list (f, off, 0);
673 return item ? item->flags : NULL;
674 }
675
r_flag_get_liststr(RFlag * f,ut64 off)676 R_API char *r_flag_get_liststr(RFlag *f, ut64 off) {
677 RFlagItem *fi;
678 RListIter *iter;
679 const RList *list = r_flag_get_list (f, off);
680 char *p = NULL;
681 r_list_foreach (list, iter, fi) {
682 p = r_str_appendf (p, "%s%s",
683 fi->realname, iter->n? ",": "");
684 }
685 return p;
686 }
687
688 // Set a new flag named `name` at offset `off`. If there's already a flag with
689 // the same name, slightly change the name by appending ".%d" as suffix
r_flag_set_next(RFlag * f,const char * name,ut64 off,ut32 size)690 R_API RFlagItem *r_flag_set_next(RFlag *f, const char *name, ut64 off, ut32 size) {
691 r_return_val_if_fail (f && name, NULL);
692 if (!r_flag_get (f, name)) {
693 return r_flag_set (f, name, off, size);
694 }
695 int i, newNameSize = strlen (name);
696 char *newName = malloc (newNameSize + 16);
697 if (!newName) {
698 return NULL;
699 }
700 strcpy (newName, name);
701 for (i = 0; ; i++) {
702 snprintf (newName + newNameSize, 15, ".%d", i);
703 if (!r_flag_get (f, newName)) {
704 RFlagItem *fi = r_flag_set (f, newName, off, size);
705 if (fi) {
706 free (newName);
707 return fi;
708 }
709 }
710 }
711 return NULL;
712 }
713
714 /* create or modify an existing flag item with the given name and parameters.
715 * The realname of the item will be the same as the name.
716 * NULL is returned in case of any errors during the process. */
r_flag_set(RFlag * f,const char * name,ut64 off,ut32 size)717 R_API RFlagItem *r_flag_set(RFlag *f, const char *name, ut64 off, ut32 size) {
718 r_return_val_if_fail (f && name && *name, NULL);
719
720 bool is_new = false;
721 char *itemname = filter_item_name (name);
722 if (!itemname) {
723 return NULL;
724 }
725 // this should never happen because the name is filtered before..
726 if (!r_name_check (itemname)) {
727 eprintf ("Invalid flag name '%s'\n", name);
728 return NULL;
729 }
730
731 RFlagItem *item = r_flag_get (f, itemname);
732 free (itemname);
733 if (item && item->offset == off) {
734 item->size = size;
735 return item;
736 }
737
738 if (!item) {
739 item = R_NEW0 (RFlagItem);
740 if (!item) {
741 goto err;
742 }
743 is_new = true;
744 }
745
746 item->space = r_flag_space_cur (f);
747 item->size = size;
748
749 update_flag_item_offset (f, item, off + f->base, is_new, true);
750 update_flag_item_name (f, item, name, true);
751 return item;
752 err:
753 r_flag_item_free (item);
754 return NULL;
755 }
756
757 /* add/replace/remove the alias of a flag item */
r_flag_item_set_alias(RFlagItem * item,const char * alias)758 R_API void r_flag_item_set_alias(RFlagItem *item, const char *alias) {
759 r_return_if_fail (item);
760 free (item->alias);
761 item->alias = R_STR_ISEMPTY (alias)? NULL: strdup (alias);
762 }
763
764 /* add/replace/remove the comment of a flag item */
r_flag_item_set_comment(RFlagItem * item,const char * comment)765 R_API void r_flag_item_set_comment(RFlagItem *item, const char *comment) {
766 r_return_if_fail (item);
767 free (item->comment);
768 item->comment = R_STR_ISEMPTY (comment)? NULL: strdup (comment);
769 }
770
771 /* add/replace/remove the realname of a flag item */
r_flag_item_set_realname(RFlagItem * item,const char * realname)772 R_API void r_flag_item_set_realname(RFlagItem *item, const char *realname) {
773 r_return_if_fail (item);
774 free_item_realname (item);
775 item->realname = R_STR_ISEMPTY (realname)? NULL: strdup (realname);
776 }
777
778 /* add/replace/remove the color of a flag item */
r_flag_item_set_color(RFlagItem * item,const char * color)779 R_API const char *r_flag_item_set_color(RFlagItem *item, const char *color) {
780 r_return_val_if_fail (item, NULL);
781 free (item->color);
782 item->color = (color && *color) ? strdup (color) : NULL;
783 return item->color;
784 }
785
786 /* change the name of a flag item, if the new name is available.
787 * true is returned if everything works well, false otherwise */
r_flag_rename(RFlag * f,RFlagItem * item,const char * name)788 R_API int r_flag_rename(RFlag *f, RFlagItem *item, const char *name) {
789 r_return_val_if_fail (f && item && name && *name, false);
790 return update_flag_item_name (f, item, name, false);
791 }
792
793 /* unset the given flag item.
794 * returns true if the item is successfully unset, false otherwise.
795 *
796 * NOTE: the item is freed. */
r_flag_unset(RFlag * f,RFlagItem * item)797 R_API bool r_flag_unset(RFlag *f, RFlagItem *item) {
798 r_return_val_if_fail (f && item, false);
799 remove_offsetmap (f, item);
800 ht_pp_delete (f->ht_name, item->name);
801 return true;
802 }
803
804 /* unset the first flag item found at offset off.
805 * return true if such a flag is found and unset, false otherwise. */
r_flag_unset_off(RFlag * f,ut64 off)806 R_API bool r_flag_unset_off(RFlag *f, ut64 off) {
807 r_return_val_if_fail (f, false);
808 RFlagItem *item = r_flag_get_i (f, off);
809 if (item && r_flag_unset (f, item)) {
810 return true;
811 }
812 return false;
813 }
814
815 struct unset_foreach_t {
816 RFlag *f;
817 int n;
818 };
819
unset_foreach(RFlagItem * fi,void * user)820 static bool unset_foreach(RFlagItem *fi, void *user) {
821 struct unset_foreach_t *u = (struct unset_foreach_t *)user;
822 if (IS_FI_NOTIN_SPACE (u->f, fi)) {
823 return true;
824 }
825 r_flag_unset (u->f, fi);
826 u->n++;
827 return true;
828 }
829
830 /* unset all the flag items that satisfy the given glob.
831 * return the number of unset items. -1 on error */
832 // XXX This is O(n^n) because unset_globa iterates all flags and unset too.
r_flag_unset_glob(RFlag * f,const char * glob)833 R_API int r_flag_unset_glob(RFlag *f, const char *glob) {
834 r_return_val_if_fail (f, -1);
835
836 struct unset_foreach_t u = { .f = f, .n = 0 };
837 r_flag_foreach_glob (f, glob, unset_foreach, &u);
838 return u.n;
839 }
840
841 /* unset the flag item with the given name.
842 * returns true if the item is found and unset, false otherwise. */
r_flag_unset_name(RFlag * f,const char * name)843 R_API bool r_flag_unset_name(RFlag *f, const char *name) {
844 r_return_val_if_fail (f, false);
845 RFlagItem *item = ht_pp_find (f->ht_name, name, NULL);
846 return item && r_flag_unset (f, item);
847 }
848
849 /* unset all flag items in the RFlag f */
r_flag_unset_all(RFlag * f)850 R_API void r_flag_unset_all(RFlag *f) {
851 r_return_if_fail (f);
852 ht_pp_free (f->ht_name);
853 f->ht_name = ht_pp_new (NULL, ht_free_flag, NULL);
854 r_skiplist_purge (f->by_off);
855 r_spaces_fini (&f->spaces);
856 new_spaces (f);
857 }
858
859 struct flag_relocate_t {
860 RFlag *f;
861 ut64 off;
862 ut64 off_mask;
863 ut64 neg_mask;
864 ut64 to;
865 int n;
866 };
867
flag_relocate_foreach(RFlagItem * fi,void * user)868 static bool flag_relocate_foreach(RFlagItem *fi, void *user) {
869 struct flag_relocate_t *u = (struct flag_relocate_t *)user;
870 ut64 fn = fi->offset & u->neg_mask;
871 ut64 on = u->off & u->neg_mask;
872 if (fn == on) {
873 ut64 fm = fi->offset & u->off_mask;
874 ut64 om = u->to & u->off_mask;
875 update_flag_item_offset (u->f, fi, (u->to & u->neg_mask) + fm + om, false, false);
876 u->n++;
877 }
878 return true;
879 }
880
r_flag_relocate(RFlag * f,ut64 off,ut64 off_mask,ut64 to)881 R_API int r_flag_relocate(RFlag *f, ut64 off, ut64 off_mask, ut64 to) {
882 r_return_val_if_fail (f, -1);
883 struct flag_relocate_t u = {
884 .f = f,
885 .off = off,
886 .off_mask = off_mask,
887 .neg_mask = ~(off_mask),
888 .to = to,
889 .n = 0
890 };
891
892 r_flag_foreach (f, flag_relocate_foreach, &u);
893 return u.n;
894 }
895
r_flag_move(RFlag * f,ut64 at,ut64 to)896 R_API bool r_flag_move(RFlag *f, ut64 at, ut64 to) {
897 r_return_val_if_fail (f, false);
898 RFlagItem *item = r_flag_get_i (f, at);
899 if (item) {
900 r_flag_set (f, item->name, to, item->size);
901 return true;
902 }
903 return false;
904 }
905
906 // BIND
r_flag_bind(RFlag * f,RFlagBind * fb)907 R_API void r_flag_bind(RFlag *f, RFlagBind *fb) {
908 r_return_if_fail (f && fb);
909 fb->f = f;
910 fb->exist_at = r_flag_exist_at;
911 fb->get = r_flag_get;
912 fb->get_at = r_flag_get_at;
913 fb->get_list = r_flag_get_list;
914 fb->set = r_flag_set;
915 fb->unset = r_flag_unset;
916 fb->unset_name = r_flag_unset_name;
917 fb->unset_off = r_flag_unset_off;
918 fb->set_fs = r_flag_space_set;
919 fb->push_fs = r_flag_space_push;
920 fb->pop_fs = r_flag_space_pop;
921 }
922
flag_count_foreach(RFlagItem * fi,void * user)923 static bool flag_count_foreach(RFlagItem *fi, void *user) {
924 int *count = (int *)user;
925 (*count)++;
926 return true;
927 }
928
r_flag_count(RFlag * f,const char * glob)929 R_API int r_flag_count(RFlag *f, const char *glob) {
930 int count = 0;
931 r_return_val_if_fail (f, -1);
932 r_flag_foreach_glob (f, glob, flag_count_foreach, &count);
933 return count;
934 }
935
936 #define FOREACH_BODY(condition) \
937 RSkipListNode *it, *tmp; \
938 RFlagsAtOffset *flags_at; \
939 RListIter *it2, *tmp2; \
940 RFlagItem *fi; \
941 r_skiplist_foreach_safe (f->by_off, it, tmp, flags_at) { \
942 if (flags_at) { \
943 r_list_foreach_safe (flags_at->flags, it2, tmp2, fi) { \
944 if (condition) { \
945 if (!cb (fi, user)) { \
946 return; \
947 } \
948 } \
949 } \
950 } \
951 }
952
r_flag_foreach(RFlag * f,RFlagItemCb cb,void * user)953 R_API void r_flag_foreach(RFlag *f, RFlagItemCb cb, void *user) {
954 FOREACH_BODY (true);
955 }
956
r_flag_foreach_prefix(RFlag * f,const char * pfx,int pfx_len,RFlagItemCb cb,void * user)957 R_API void r_flag_foreach_prefix(RFlag *f, const char *pfx, int pfx_len, RFlagItemCb cb, void *user) {
958 pfx_len = pfx_len < 0? strlen (pfx): pfx_len;
959 FOREACH_BODY (!strncmp (fi->name, pfx, pfx_len));
960 }
961
r_flag_foreach_range(RFlag * f,ut64 from,ut64 to,RFlagItemCb cb,void * user)962 R_API void r_flag_foreach_range(RFlag *f, ut64 from, ut64 to, RFlagItemCb cb, void *user) {
963 FOREACH_BODY (fi->offset >= from && fi->offset < to);
964 }
965
r_flag_foreach_glob(RFlag * f,const char * glob,RFlagItemCb cb,void * user)966 R_API void r_flag_foreach_glob(RFlag *f, const char *glob, RFlagItemCb cb, void *user) {
967 FOREACH_BODY (!glob || r_str_glob (fi->name, glob));
968 }
969
r_flag_foreach_space_glob(RFlag * f,const char * glob,const RSpace * space,RFlagItemCb cb,void * user)970 R_API void r_flag_foreach_space_glob(RFlag *f, const char *glob, const RSpace *space, RFlagItemCb cb, void *user) {
971 FOREACH_BODY (IS_FI_IN_SPACE (fi, space) && (!glob || r_str_glob (fi->name, glob)));
972 }
973
r_flag_foreach_space(RFlag * f,const RSpace * space,RFlagItemCb cb,void * user)974 R_API void r_flag_foreach_space(RFlag *f, const RSpace *space, RFlagItemCb cb, void *user) {
975 FOREACH_BODY (IS_FI_IN_SPACE (fi, space));
976 }
977