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