1 /* radare - LGPL - Copyright 2009-2021 - pancake */
2 
3 #include <stddef.h>
4 #include "r_cons.h"
5 #include "r_core.h"
6 
7 static const char *help_msg_f[] = {
8 	"Usage: f","[?] [flagname]", " # Manage offset-name flags",
9 	"f","","list flags (will only list flags from selected flagspaces)",
10 	"f?","flagname","check if flag exists or not, See ?? and ?!",
11 	"f."," [*[*]]","list local per-function flags (*) as r2 commands",
12 	"f.","blah=$$+12","set local function label named 'blah'",
13 	"f."," fname","list all local labels for the given function",
14 	"f,","","table output for flags",
15 	"f*","","list flags in r commands",
16 	"f"," name 12 @ 33","set flag 'name' with length 12 at offset 33",
17 	"f"," name = 33","alias for 'f name @ 33' or 'f name 1 33'",
18 	"f"," name 12 33 [cmt]","same as above + optional comment",
19 	"f-",".blah@fcn.foo","delete local label from function at current seek (also f.-)",
20 	"f--","","delete all flags and flagspaces (deinit)",
21 	"f+","name 12 @ 33","like above but creates new one if doesnt exist",
22 	"f-","name","remove flag 'name'",
23 	"f-","@addr","remove flag at address expression",
24 	"f="," [glob]","list range bars graphics with flag offsets and sizes",
25 	"fa"," [name] [alias]","alias a flag to evaluate an expression",
26 	"fb"," [addr]","set base address for new flags",
27 	"fb"," [addr] [flag*]","move flags matching 'flag' to relative addr",
28 	"fc","[?][name] [color]","set color for given flag",
29 	"fC"," [name] [cmt]","set comment for given flag",
30 	"fd","[?] addr","return flag+delta",
31 	"fe-","","resets the enumerator counter",
32 	"fe"," [name]","create flag name.#num# enumerated flag. See fe?",
33 	"ff"," ([glob])","distance in bytes to reach the next flag (see sn/sp)",
34 	"fi"," [size] | [from] [to]","show flags in current block or range",
35 	"fg","[*] ([prefix])","construct a graph with the flag names",
36 	"fj","","list flags in JSON format",
37 	"fl"," (@[flag]) [size]","show or set flag length (size)",
38 	"fla"," [glob]","automatically compute the size of all flags matching glob",
39 	"fm"," addr","move flag at current offset to new address",
40 	"fn","","list flags displaying the real name (demangled)",
41 	"fnj","","list flags displaying the real name (demangled) in JSON format",
42 	"fN","","show real name of flag at current address",
43 	"fN"," [[name]] [realname]","set flag real name (if no flag name current seek one is used)",
44 	"fo","","show fortunes",
45 	"fO", " [glob]", "flag as ordinals (sym.* func.* method.*)",
46 	//" fc [name] [cmt]  ; set execution command for a specific flag"
47 	"fr"," [[old]] [new]","rename flag (if no new flag current seek one is used)",
48 	"fR","[?] [f] [t] [m]","relocate all flags matching f&~m 'f'rom, 't'o, 'm'ask",
49 	"fs","[?]+-*","manage flagspaces",
50 	"ft","[?]*","flag tags, useful to find all flags matching some words",
51 	"fV","[*-] [nkey] [offset]","dump/restore visual marks (mK/'K)",
52 	"fx","[d]","show hexdump (or disasm) of flag:flagsize",
53 	"fq","","list flags in quiet mode",
54 	"fz","[?][name]","add named flag zone -name to delete. see fz?[name]",
55 	NULL
56 };
57 
58 static const char *help_msg_fc[] = {
59 	"Usage: fc", "<flagname> [color]", " # List colors with 'ecs'",
60 	"fc", " flagname", "Get current color for given flagname",
61 	"fc", " flagname color", "Set color to a flag",
62 	NULL
63 };
64 static const char *help_msg_fd[] = {
65 	"Usage: fd[d]", " [offset|flag|expression]", " # Describe flags",
66 	"fd", " $$" , "# describe flag + delta for given offset",
67  	"fd.", " $$", "# check flags in current address (no delta)",
68 	"fdd", " $$", "# describe flag without space restrictions",
69 	"fdw", " [string]", "# filter closest flag by string for current offset",
70 	NULL
71 };
72 
73 static const char *help_msg_fs[] = {
74 	"Usage: fs","[*] [+-][flagspace|addr]", " # Manage flagspaces",
75 	"fs","","display flagspaces",
76 	"fs*","","display flagspaces as r2 commands",
77 	"fsj","","display flagspaces in JSON",
78 	"fs"," *","select all flagspaces",
79 	"fs"," flagspace","select flagspace or create if it doesn't exist",
80 	"fs","-flagspace","remove flagspace",
81 	"fs","-*","remove all flagspaces",
82 	"fs","+foo","push previous flagspace and set",
83 	"fs","-","pop to the previous flagspace",
84 	"fs","-.","remove the current flagspace",
85 	"fsq","", "list flagspaces in quiet mode",
86 	"fsm"," [addr]","move flags at given address to the current flagspace",
87 	"fss","","display flagspaces stack",
88 	"fss*","","display flagspaces stack in r2 commands",
89 	"fssj","","display flagspaces stack in JSON",
90 	"fsr"," newname","rename selected flagspace",
91 	NULL
92 };
93 
94 static const char *help_msg_fz[] = {
95 	"Usage: f", "[?|-name| name] [@addr]", " # Manage flagzones",
96 	" fz", " math", "add new flagzone named 'math'",
97 	" fz-", "math", "remove the math flagzone",
98 	" fz-", "*", "remove all flagzones",
99 	" fz.", "", "show around flagzone context",
100 	" fz:", "", "show what's in scr.flagzone for visual",
101 	" fz*", "", "dump into r2 commands, for projects",
102 	NULL
103 };
104 
cmd_flag_init(RCore * core,RCmdDesc * parent)105 static void cmd_flag_init(RCore *core, RCmdDesc *parent) {
106 	DEFINE_CMD_DESCRIPTOR (core, f);
107 	DEFINE_CMD_DESCRIPTOR (core, fc);
108 	DEFINE_CMD_DESCRIPTOR (core, fd);
109 	DEFINE_CMD_DESCRIPTOR (core, fs);
110 	DEFINE_CMD_DESCRIPTOR (core, fz);
111 }
112 
listFlag(RFlagItem * flag,void * user)113 static bool listFlag(RFlagItem *flag, void *user) {
114 	r_list_append (user, flag);
115 	return true;
116 }
117 
countMatching(const char * a,const char * b)118 static size_t countMatching (const char *a, const char *b) {
119 	size_t matches = 0;
120 	for (; *a && *b; a++, b++) {
121 		if (*a != *b) {
122 			break;
123 		}
124 		matches++;
125 	}
126 	return matches;
127 }
128 
__isOnlySon(RCore * core,RList * flags,const char * kw)129 static const char *__isOnlySon(RCore *core, RList *flags, const char *kw) {
130         RListIter *iter;
131         RFlagItem *f;
132 
133         size_t count = 0;
134         char *fname = NULL;
135         r_list_foreach (flags, iter, f) {
136                 if (!strncmp (f->name, kw, strlen (kw))) {
137                         count++;
138                         if (count > 1) {
139                                 return NULL;
140                         }
141                         fname = f->name;
142                 }
143         }
144         return fname;
145 }
146 
__childrenFlagsOf(RCore * core,RList * flags,const char * prefix)147 static RList *__childrenFlagsOf(RCore *core, RList *flags, const char *prefix) {
148 	RList *list = r_list_newf (free);
149 	RListIter *iter, *iter2;
150 	RFlagItem *f, *f2;
151 	char *fn;
152 
153 	const size_t prefix_len = strlen (prefix);
154 	r_list_foreach (flags, iter, f) {
155 		if (prefix_len > 0 && strncmp (f->name, prefix, prefix_len)) {
156 			continue;
157 		}
158 		if (prefix_len > strlen (f->name)) {
159 			continue;
160 		}
161 		if (r_cons_is_breaked ()) {
162 			break;
163 		}
164 		const char *name = f->name;
165 		int name_len = strlen (name);
166 		r_list_foreach (flags, iter2, f2) {
167 			if (prefix_len > strlen (f2->name)) {
168 				continue;
169 			}
170 			if (prefix_len > 0 && strncmp (f2->name, prefix, prefix_len)) {
171 				continue;
172 			}
173 			int matching = countMatching (name, f2->name);
174 			if (matching < prefix_len || matching == name_len) {
175 				continue;
176 			}
177 			if (matching > name_len) {
178 				break;
179 			}
180 			if (matching < name_len) {
181 				name_len = matching;
182 			}
183 		}
184 		char *kw = r_str_ndup (name, name_len + 1);
185 		const int kw_len = strlen (kw);
186 		const char *only = __isOnlySon (core, flags, kw);
187 		if (only) {
188 			free (kw);
189 			kw = strdup (only);
190 		} else {
191 			const char *fname = NULL;
192 			size_t fname_len = 0;
193 			r_list_foreach (flags, iter2, f2) {
194 				if (strncmp (f2->name, kw, kw_len)) {
195 					continue;
196 				}
197 				if (fname) {
198 					int matching = countMatching (fname, f2->name);
199 					if (fname_len) {
200 						if (matching < fname_len) {
201 							fname_len = matching;
202 						}
203 					} else {
204 						fname_len = matching;
205 					}
206 				} else {
207 					fname = f2->name;
208 				}
209 			}
210 			if (fname_len > 0) {
211 				free (kw);
212 				kw = r_str_ndup (fname, fname_len);
213 			}
214 		}
215 
216 		bool found = false;
217 		r_list_foreach (list, iter2, fn) {
218 			if (!strcmp (fn, kw)) {
219 				found = true;
220 				break;
221 			}
222 		}
223 		if (found) {
224 			free (kw);
225 		} else {
226 			if (strcmp (prefix, kw)) {
227 				r_list_append (list, kw);
228 			} else {
229 				free (kw);
230 			}
231 		}
232 	}
233 	return list;
234 }
235 
236 static void __printRecursive (RCore *core, RList *list, const char *prefix, int mode, int depth);
237 
__printRecursive(RCore * core,RList * flags,const char * prefix,int mode,int depth)238 static void __printRecursive (RCore *core, RList *flags, const char *prefix, int mode, int depth) {
239 	char *fn;
240 	RListIter *iter;
241 	const int prefix_len = strlen (prefix);
242 	// eprintf ("# fg %s\n", prefix);
243 	if (mode == '*' && !*prefix) {
244 		r_cons_printf ("agn root\n");
245 	}
246 	if (r_flag_get (core->flags, prefix)) {
247 		return;
248 	}
249 	RList *children = __childrenFlagsOf (core, flags, prefix);
250 	r_list_foreach (children, iter, fn) {
251 		if (!strcmp (fn, prefix)) {
252 			continue;
253 		}
254 		if (mode == '*') {
255 			r_cons_printf ("agn %s %s\n", fn, fn + prefix_len);
256 			r_cons_printf ("age %s %s\n", *prefix ? prefix : "root", fn);
257 		} else {
258 			r_cons_printf ("%s %s\n", r_str_pad (' ', prefix_len), fn + prefix_len);
259 		}
260 		//r_cons_printf (".fg %s\n", fn);
261 		__printRecursive (core, flags, fn, mode, depth+1);
262 	}
263 	r_list_free (children);
264 }
265 
__flag_graph(RCore * core,const char * input,int mode)266 static void __flag_graph (RCore *core, const char *input, int mode) {
267 	RList *flags = r_list_newf (NULL);
268 	r_flag_foreach_space (core->flags, r_flag_space_cur (core->flags), listFlag, flags);
269 	__printRecursive (core, flags, input, mode, 0);
270 	r_list_free (flags);
271 }
272 
spaces_list(RSpaces * sp,int mode)273 static void spaces_list(RSpaces *sp, int mode) {
274 	RSpaceIter it;
275 	RSpace *s;
276 	const RSpace *cur = r_spaces_current (sp);
277 	PJ *pj = NULL;
278 	if (mode == 'j') {
279 		pj = pj_new ();
280 		pj_a (pj);
281 	}
282 	r_spaces_foreach (sp, it, s) {
283 		int count = r_spaces_count (sp, s->name);
284 		if (mode == 'j') {
285 			pj_o (pj);
286 			pj_ks (pj, "name", s->name);
287 			pj_ki (pj, "count", count);
288 			pj_kb (pj, "selected", cur == s);
289 			pj_end (pj);
290 		} else if (mode == 'q') {
291 			r_cons_printf ("%s\n", s->name);
292 		} else if (mode == '*') {
293 			r_cons_printf ("%s %s\n", sp->name, s->name);
294 		} else {
295 			r_cons_printf ("%5d %c %s\n", count, (!cur || cur == s)? '*': '.',
296 				s->name);
297 		}
298 	}
299 	if (mode == '*' && r_spaces_current (sp)) {
300 		r_cons_printf ("%s %s # current\n", sp->name, r_spaces_current_name (sp));
301 	}
302 	if (mode == 'j') {
303 		pj_end (pj);
304 		r_cons_printf ("%s\n", pj_string (pj));
305 		pj_free (pj);
306 	}
307 }
308 
cmd_fz(RCore * core,const char * input)309 static void cmd_fz(RCore *core, const char *input) {
310 	switch (*input) {
311 	case '?': // "fz?"
312 		r_core_cmd_help (core, help_msg_fz);
313 		break;
314 	case '.': // "fz."
315 		{
316 			const char *a = NULL, *b = NULL;
317 			r_flag_zone_around (core->flags, core->offset, &a, &b);
318 			r_cons_printf ("%s %s\n", r_str_get_fail (a, "~"), r_str_get_fail (b, "~"));
319 		}
320 		break;
321 	case ':': // "fz:"
322 		{
323 			const char *a, *b;
324 			int a_len = 0;
325 			int w = r_cons_get_size (NULL);
326 			r_flag_zone_around (core->flags, core->offset, &a, &b);
327 			if (a) {
328 				r_cons_printf ("[<< %s]", a);
329 				a_len = strlen (a) + 4;
330 			}
331 			int padsize = (w / 2)  - a_len;
332 			int title_size = 12;
333 			if (a || b) {
334 				char *title = r_str_newf ("[ 0x%08"PFMT64x" ]", core->offset);
335 				title_size = strlen (title);
336 				padsize -= strlen (title) / 2;
337 				const char *halfpad = r_str_pad (' ', padsize);
338 				r_cons_printf ("%s%s", halfpad, title);
339 				free (title);
340 			}
341 			if (b) {
342 				padsize = (w / 2) - title_size - strlen (b) - 4;
343 				const char *halfpad = padsize > 1? r_str_pad (' ', padsize): "";
344 				r_cons_printf ("%s[%s >>]", halfpad, b);
345 			}
346 			if (a || b) {
347 				r_cons_newline();
348 			}
349 		}
350 		break;
351 	case ' ':
352 		r_flag_zone_add (core->flags, r_str_trim_head_ro (input + 1), core->offset);
353 		break;
354 	case '-':
355 		if (input[1] == '*') {
356 			r_flag_zone_reset (core->flags);
357 		} else {
358 			r_flag_zone_del (core->flags, input + 1);
359 		}
360 		break;
361 	case '*':
362 		r_flag_zone_list (core->flags, '*');
363 		break;
364 	case 0:
365 		r_flag_zone_list (core->flags, 0);
366 		break;
367 	}
368 }
369 
370 struct flagbar_t {
371 	RCore *core;
372 	int cols;
373 };
374 
flagbar_foreach(RFlagItem * fi,void * user)375 static bool flagbar_foreach(RFlagItem *fi, void *user) {
376 	struct flagbar_t *u = (struct flagbar_t *)user;
377 	ut64 min = 0, max = r_io_size (u->core->io);
378 	RIOMap *m = r_io_map_get (u->core->io, fi->offset);
379 	if (m) {
380 		min = m->itv.addr;
381 		max = m->itv.addr + m->itv.size;
382 	}
383 	r_cons_printf ("0x%08"PFMT64x" ", fi->offset);
384 	r_print_rangebar (u->core->print, fi->offset, fi->offset + fi->size, min, max, u->cols);
385 	r_cons_printf ("  %s\n", fi->name);
386 	return true;
387 }
388 
flagbars(RCore * core,const char * glob)389 static void flagbars(RCore *core, const char *glob) {
390 	int cols = r_cons_get_size (NULL);
391 	cols -= 80;
392 	if (cols < 0) {
393 		cols += 80;
394 	}
395 
396 	struct flagbar_t u = { .core = core, .cols = cols };
397 	r_flag_foreach_space_glob (core->flags, glob, r_flag_space_cur (core->flags), flagbar_foreach, &u);
398 }
399 
400 struct flag_to_flag_t {
401 	ut64 next;
402 	ut64 offset;
403 };
404 
flag_to_flag_foreach(RFlagItem * fi,void * user)405 static bool flag_to_flag_foreach(RFlagItem *fi, void *user) {
406 	struct flag_to_flag_t *u = (struct flag_to_flag_t *)user;
407 	if (fi->offset < u->next && fi->offset > u->offset) {
408 		u->next = fi->offset;
409 	}
410 	return true;
411 }
412 
flag_to_flag(RCore * core,const char * glob)413 static int flag_to_flag(RCore *core, const char *glob) {
414 	r_return_val_if_fail (glob, 0);
415 	glob = r_str_trim_head_ro (glob);
416 	struct flag_to_flag_t u = { .next = UT64_MAX, .offset = core->offset };
417 	r_flag_foreach_glob (core->flags, glob, flag_to_flag_foreach, &u);
418 	if (u.next != UT64_MAX && u.next > core->offset) {
419 		return u.next - core->offset;
420 	}
421 	return 0;
422 }
423 
424 typedef struct {
425 	RTable *t;
426 } FlagTableData;
427 
__tableItemCallback(RFlagItem * flag,void * user)428 static bool __tableItemCallback(RFlagItem *flag, void *user) {
429 	FlagTableData *ftd = user;
430 	if (!R_STR_ISEMPTY (flag->name)) {
431 		RTable *t = ftd->t;
432 		const char *spaceName = (flag->space && flag->space->name)? flag->space->name: "";
433 		const char *addr = sdb_fmt ("0x%08"PFMT64x, flag->offset);
434 		r_table_add_row (t, addr, sdb_fmt ("%"PFMT64d, flag->size), spaceName, flag->name, NULL);
435 	}
436 	return true;
437 }
438 
cmd_flag_table(RCore * core,const char * input)439 static void cmd_flag_table(RCore *core, const char *input) {
440 	const char fmt = *input++;
441 	const char *q = input;
442 	FlagTableData ftd = {0};
443 	RTable *t = r_core_table (core, "flags");
444 	ftd.t = t;
445 	RTableColumnType *typeString = r_table_type ("string");
446 	RTableColumnType *typeNumber = r_table_type ("number");
447 	r_table_add_column (t, typeNumber, "addr", 0);
448 	r_table_add_column (t, typeNumber, "size", 0);
449 	r_table_add_column (t, typeString, "space", 0);
450 	r_table_add_column (t, typeString, "name", 0);
451 
452 	RSpace *curSpace = r_flag_space_cur (core->flags);
453 	r_flag_foreach_space (core->flags, curSpace, __tableItemCallback, &ftd);
454 	if (r_table_query (t, q)) {
455 		char *s = (fmt == 'j')
456 			? r_table_tojson (t)
457 			: r_table_tostring (t);
458 		r_cons_printf ("%s\n", s);
459 		free (s);
460 	}
461 	r_table_free (t);
462 }
463 
cmd_flag_tags(RCore * core,const char * input)464 static void cmd_flag_tags(RCore *core, const char *input) {
465 	char mode = input[1];
466 	for (; *input && !IS_WHITESPACE (*input); input++) {}
467 	char *inp = strdup (input);
468 	char *arg = inp;
469 	r_str_trim (arg);
470 	if (!*arg && !mode) {
471 		const char *tag;
472 		RListIter *iter;
473 		RList *list = r_flag_tags_list (core->flags, NULL);
474 		r_list_foreach (list, iter, tag) {
475 			r_cons_printf ("%s\n", tag);
476 		}
477 		r_list_free (list);
478 		free (inp);
479 		return;
480 	}
481 	if (mode == '?') {
482 		eprintf ("Usage: ft[?ln] [k] [v ...]\n");
483 		eprintf (" ft tag strcpy strlen ... # set words for the 'string' tag\n");
484 		eprintf (" ft tag                   # get offsets of all matching flags\n");
485 		eprintf (" ft                       # list all tags\n");
486 		eprintf (" ftn tag                  # get matching flagnames fot given tag\n");
487 		eprintf (" ftw                      # flag tags within this file\n");
488 		eprintf (" ftj                      # list all flagtags in JSON format\n");
489 		eprintf (" ft*                      # list all flagtags in r2 commands\n");
490 		free (inp);
491 		return;
492 	}
493 	if (mode == 'w') { // "ftw"
494 		const char *tag;
495 		RListIter *iter;
496 		RList *list = r_flag_tags_list (core->flags, NULL);
497 		r_list_foreach (list, iter, tag) {
498 			r_cons_printf ("%s:\n", tag);
499 			r_core_cmdf (core, "ftn %s", tag);
500 		}
501 		r_list_free (list);
502 		free (inp);
503 		return;
504 	}
505 	if (mode == '*') {
506 		RListIter *iter;
507 		const char *tag;
508 		RList *list = r_flag_tags_list (core->flags, NULL);
509 		r_list_foreach (list, iter, tag) {
510 			const char *flags = sdb_get (core->flags->tags, sdb_fmt ("tag.%s", tag), NULL);
511 			r_cons_printf ("ft %s %s\n", tag, flags);
512 		}
513 		r_list_free (list);
514 		free (inp);
515 		return;
516 	}
517 	if (mode == 'j') { // "ftj"
518 		RListIter *iter, *iter2;
519 		const char *tag, *flg;
520 		PJ *pj = pj_new ();
521 		pj_o (pj);
522 		RList *list = r_flag_tags_list (core->flags, NULL);
523 		r_list_foreach (list, iter, tag) {
524 			pj_k (pj, tag);
525 			pj_a (pj);
526 			RList *flags = r_flag_tags_list (core->flags, tag);
527 			r_list_foreach (flags, iter2, flg) {
528 				pj_s (pj, flg);
529 			}
530 			pj_end (pj);
531 			r_list_free (flags);
532 		}
533 		pj_end (pj);
534 		r_list_free (list);
535 		free (inp);
536 		r_cons_printf ("%s\n", pj_string (pj));
537 		pj_free (pj);
538 		return;
539 	}
540 	char *arg1 = strchr (arg, ' ');
541 	if (arg1) {
542 		*arg1 = 0;
543 		const char *a1 = r_str_trim_head_ro (arg1 + 1);
544 		r_flag_tags_set (core->flags, arg, a1);
545 	} else {
546 		RListIter *iter;
547 		RFlagItem *flag;
548 		RList *flags = r_flag_tags_get (core->flags, arg);
549 		switch (mode) {
550 		case 'n':
551 			r_list_foreach (flags, iter, flag) {
552 				// r_cons_printf ("0x%08"PFMT64x"\n", flag->offset);
553 				r_cons_printf ("0x%08"PFMT64x"  %s\n", flag->offset, flag->name);
554 			}
555 			break;
556 		default:
557 			r_list_foreach (flags, iter, flag) {
558 				r_cons_printf ("0x%08"PFMT64x"\n", flag->offset);
559 			}
560 			break;
561 		}
562 	}
563 	free (inp);
564 }
565 
566 struct rename_flag_t {
567 	RCore *core;
568 	const char *pfx;
569 	int count;
570 };
571 
rename_flag_ordinal(RFlagItem * fi,void * user)572 static bool rename_flag_ordinal(RFlagItem *fi, void *user) {
573 	struct rename_flag_t *u = (struct rename_flag_t *)user;
574 	char *newName = r_str_newf ("%s%d", u->pfx, u->count++);
575 	if (!newName) {
576 		return false;
577 	}
578 	r_flag_rename (u->core->flags, fi, newName);
579 	free (newName);
580 	return true;
581 }
582 
flag_ordinals(RCore * core,const char * str)583 static void flag_ordinals(RCore *core, const char *str) {
584 	const char *glob = r_str_trim_head_ro (str);
585 	char *pfx = strdup (glob);
586 	char *p = strchr (pfx, '*');
587 	if (p) {
588 		*p = 0;
589 	}
590 
591 	struct rename_flag_t u = { .core = core, .pfx = pfx, .count = 0 };
592 	r_flag_foreach_glob (core->flags, glob, rename_flag_ordinal, &u);
593 	free (pfx);
594 }
595 
cmpflag(const void * _a,const void * _b)596 static int cmpflag(const void *_a, const void *_b) {
597 	const RFlagItem *flag1 = _a , *flag2 = _b;
598 	return (flag1->offset - flag2->offset);
599 }
600 
601 struct find_flag_t {
602 	RFlagItem *win;
603 	ut64 at;
604 };
605 
find_flag_after(RFlagItem * flag,void * user)606 static bool find_flag_after(RFlagItem *flag, void *user) {
607 	struct find_flag_t *u = (struct find_flag_t *)user;
608 	if (flag->offset > u->at && (!u->win || flag->offset < u->win->offset)) {
609 		u->win = flag;
610 	}
611 	return true;
612 }
613 
find_flag_after_foreach(RFlagItem * flag,void * user)614 static bool find_flag_after_foreach(RFlagItem *flag, void *user) {
615 	if (flag->size != 0) {
616 		return true;
617 	}
618 
619 	RFlag *flags = (RFlag *)user;
620 	struct find_flag_t u = { .win = NULL, .at = flag->offset };
621 	r_flag_foreach (flags, find_flag_after, &u);
622 	if (u.win) {
623 		flag->size = u.win->offset - flag->offset;
624 	}
625 	return true;
626 }
627 
adjust_offset(RFlagItem * flag,void * user)628 static bool adjust_offset(RFlagItem *flag, void *user) {
629 	st64 base = *(st64 *)user;
630 	flag->offset += base;
631 	return true;
632 }
633 
print_space_stack(RFlag * f,int ordinal,const char * name,bool selected,PJ * pj,int mode)634 static void print_space_stack(RFlag *f, int ordinal, const char *name, bool selected, PJ *pj, int mode) {
635 	bool first = ordinal == 0;
636 	switch (mode) {
637 	case 'j': {
638 		char *ename = r_str_escape (name);
639 		if (!ename) {
640 			return;
641 		}
642 
643 		pj_o (pj);
644 		pj_ki (pj, "ordinal", ordinal);
645 		pj_ks (pj, "name", ename);
646 		pj_kb (pj, "selected", selected);
647 		pj_end (pj);
648 		free (ename);
649 		break;
650 	}
651 	case '*': {
652 		const char *fmt = first? "fs %s\n": "fs+%s\n";
653 		r_cons_printf (fmt, name);
654 		break;
655 	}
656 	default:
657 		r_cons_printf ("%-2d %s%s\n", ordinal, name, selected? " (selected)": "");
658 		break;
659 	}
660 }
661 
flag_space_stack_list(RFlag * f,int mode)662 static int flag_space_stack_list(RFlag *f, int mode) {
663 	RListIter *iter;
664 	char *space;
665 	int i = 0;
666 	PJ *pj = NULL;
667 	if (mode == 'j') {
668 		pj = pj_new ();
669 		pj_a (pj);
670 	}
671 	r_list_foreach (f->spaces.spacestack, iter, space) {
672 		print_space_stack (f, i++, space, false, pj, mode);
673 	}
674 	const char *cur_name = r_flag_space_cur_name (f);
675 	print_space_stack (f, i++, cur_name, true, pj, mode);
676 	if (mode == 'j') {
677 		pj_end (pj);
678 		r_cons_printf ("%s\n", pj_string (pj));
679 		pj_free (pj);
680 	}
681 	return i;
682 }
683 
684 typedef struct {
685 	int rad;
686 	PJ *pj;
687 	RAnalFunction *fcn;
688 } PrintFcnLabelsCtx;
689 
print_function_labels_cb(void * user,const ut64 addr,const void * v)690 static bool print_function_labels_cb(void *user, const ut64 addr, const void *v) {
691 	const PrintFcnLabelsCtx *ctx = user;
692 	const char *name = v;
693 	switch (ctx->rad) {
694 	case '*':
695 	case 1:
696 		r_cons_printf ("f.%s@0x%08"PFMT64x"\n", name, addr);
697 		break;
698 	case 'j':
699 		pj_kn (ctx->pj, name, addr);
700 		break;
701 	default:
702 		r_cons_printf ("0x%08"PFMT64x" %s   [%s + %"PFMT64d"]\n",
703 			addr,
704 			name, ctx->fcn->name,
705 			addr - ctx->fcn->addr);
706 	}
707 	return true;
708 }
709 
710 
print_function_labels_for(RAnalFunction * fcn,int rad,PJ * pj)711 static void print_function_labels_for(RAnalFunction *fcn, int rad, PJ *pj) {
712 	r_return_if_fail (fcn && (rad != 'j' || pj));
713 	bool json = rad == 'j';
714 	if (json) {
715 		pj_o (pj);
716 	}
717 	PrintFcnLabelsCtx ctx = { rad, pj, fcn };
718 	ht_up_foreach (fcn->labels, print_function_labels_cb, &ctx);
719 	if (json) {
720 		pj_end (pj);
721 	}
722 }
723 
print_function_labels(RAnal * anal,RAnalFunction * fcn,int rad)724 static void print_function_labels(RAnal *anal, RAnalFunction *fcn, int rad) {
725 	r_return_if_fail (anal || fcn);
726 	PJ *pj = NULL;
727 	bool json = rad == 'j';
728 	if (json) {
729 		pj = pj_new ();
730 	}
731 	if (fcn) {
732 		print_function_labels_for (fcn, rad, pj);
733 	} else {
734 		if (json) {
735 			pj_o (pj);
736 		}
737 		RAnalFunction *f;
738 		RListIter *iter;
739 		r_list_foreach (anal->fcns, iter, f) {
740 			if (!f->labels->count) {
741 				continue;
742 			}
743 			if (json) {
744 				pj_k (pj, f->name);
745 			}
746 			print_function_labels_for (f, rad, pj);
747 		}
748 		if (json) {
749 			pj_end (pj);
750 		}
751 	}
752 	if (json) {
753 		r_cons_println (pj_string (pj));
754 		pj_free (pj);
755 	}
756 }
757 
cmd_flag(void * data,const char * input)758 static int cmd_flag(void *data, const char *input) {
759 	static int flagenum = 0;
760 	RCore *core = (RCore *)data;
761 	ut64 off = core->offset;
762 	char *ptr, *str = NULL;
763 	RFlagItem *item;
764 	char *name = NULL;
765 	st64 base;
766 
767 	// TODO: off+=cursor
768 	if (*input) {
769 		str = strdup (input + 1);
770 	}
771 rep:
772 	switch (*input) {
773 	case 'f': // "ff"
774 		if (input[1] == 's') { // "ffs"
775 			int delta = flag_to_flag (core, input + 2);
776 			if (delta > 0) {
777 				r_cons_printf ("0x%08"PFMT64x"\n", core->offset + delta);
778 			}
779 		} else {
780 			r_cons_printf ("%d\n", flag_to_flag (core, input + 1));
781 		}
782 		break;
783 	case 'e': // "fe"
784 		switch (input[1]) {
785 		case ' ':
786 			ptr = r_str_newf ("%s.%d", input + 2, flagenum);
787 			(void)r_flag_set (core->flags, ptr, core->offset, 1);
788 			flagenum++;
789 			free (ptr);
790 			break;
791 		case '-':
792 			flagenum = 0;
793 			break;
794 		default:
795 			eprintf ("|Usage: fe[-| name] @@= 1 2 3 4\n");
796 			break;
797 		}
798 		break;
799 	case '=': // "f="
800 		switch (input[1]) {
801 		case ' ':
802 			flagbars (core, input + 2);
803 			break;
804 		case 0:
805 			flagbars (core, NULL);
806 			break;
807 		default:
808 		case '?':
809 			eprintf ("Usage: f= [glob] to grep for matching flag names\n");
810 			break;
811 		}
812 		break;
813 	case 'a':
814 		if (input[1] == ' ') {
815 			RFlagItem *fi;
816 			R_FREE (str);
817 			str = strdup (input+2);
818 			ptr = strchr (str, '=');
819 			if (!ptr) {
820 				ptr = strchr (str, ' ');
821 			}
822 			if (ptr) {
823 				*ptr++ = 0;
824 			}
825 			name = (char *)r_str_trim_head_ro (str);
826 			ptr = (char *)r_str_trim_head_ro (ptr);
827 			fi = r_flag_get (core->flags, name);
828 			if (!fi) {
829 				fi = r_flag_set (core->flags, name,
830 					core->offset, 1);
831 			}
832 			if (fi) {
833 				r_flag_item_set_alias (fi, ptr);
834 			} else {
835 				eprintf ("Cannot find flag '%s'\n", name);
836 			}
837 		} else {
838 			eprintf ("Usage: fa flagname flagalias\n");
839 		}
840 		break;
841 	case 'V': // visual marks
842 		switch (input[1]) {
843 		case '-':
844 			r_core_visual_mark_reset (core);
845 			break;
846 		case ' ':
847 			{
848 				int n = atoi (input + 1);
849 				if (n + ASCII_MAX + 1 < UT8_MAX) {
850 					const char *arg = strchr (input + 2, ' ');
851 					ut64 addr = arg? r_num_math (core->num, arg): core->offset;
852 					r_core_visual_mark_set (core, n + ASCII_MAX + 1, addr);
853 				}
854 			}
855 			break;
856 		case '?':
857 			eprintf ("Usage: fV[*-] [nkey] [offset]\n");
858 			eprintf ("Dump/Restore visual marks (mK/'K)\n");
859 			break;
860 		default:
861 			r_core_visual_mark_dump (core);
862 			break;
863 		}
864 		break;
865 	case 'm': // "fm"
866 		r_flag_move (core->flags, core->offset, r_num_math (core->num, input+1));
867 		break;
868 	case 'R': // "fR"
869 		switch(*str) {
870 		case '\0':
871 			eprintf ("Usage: fR [from] [to] ([mask])\n");
872 			eprintf ("Example to relocate PIE flags on debugger:\n"
873 				" > fR entry0 `dm~:1[1]`\n");
874 			break;
875 		case '?':
876 			r_cons_println ("Usage: fR [from] [to] ([mask])");
877 			r_cons_println ("Example to relocate PIE flags on debugger:\n"
878 				" > fR entry0 `dm~:1[1]`");
879 			break;
880 		default:
881             {
882 				char *p = strchr (str+1, ' ');
883 				ut64 from, to, mask = 0xffff;
884 				int ret;
885 				if (p) {
886 					char *q = strchr (p + 1, ' ');
887 					*p = 0;
888 					if (q) {
889 						*q = 0;
890 						mask = r_num_math (core->num, q+1);
891 					}
892 					from = r_num_math (core->num, str+1);
893 					to = r_num_math (core->num, p+1);
894 					ret = r_flag_relocate (core->flags, from, mask, to);
895 					eprintf ("Relocated %d flags\n", ret);
896 				} else {
897 					eprintf ("Usage: fR [from] [to] ([mask])\n");
898 					eprintf ("Example to relocate PIE flags on debugger:\n"
899 						" > fR entry0 `dm~:1[1]`\n");
900 				}
901 			}
902 		}
903 		break;
904 	case 'b': // "fb"
905 		switch (input[1]) {
906 		case ' ':
907 			free (str);
908 			str = strdup (input + 2);
909 			ptr = strchr (str, ' ');
910 			if (ptr) {
911 				RFlag *f = core->flags;
912 				*ptr = 0;
913 				base = r_num_math (core->num, str);
914 				r_flag_foreach_glob (f, ptr + 1, adjust_offset, &base);
915 			} else {
916 				core->flags->base = r_num_math (core->num, input+1);
917 			}
918 			R_FREE (str);
919 			break;
920 		case '\0':
921 			r_cons_printf ("%"PFMT64d" 0x%"PFMT64x"\n",
922 				core->flags->base,
923 				core->flags->base);
924 			break;
925 		default:
926 			eprintf ("Usage: fb [addr] [[flags*]]\n");
927 			break;
928 		}
929 		break;
930 	case '+': // "f+'
931 	case ' ': {
932 		const char *cstr = r_str_trim_head_ro (str);
933 		char* eq = strchr (cstr, '=');
934 		char* b64 = strstr (cstr, "base64:");
935 		char* s = strchr (cstr, ' ');
936 		char* s2 = NULL, *s3 = NULL;
937 		char* comment = NULL;
938 		bool comment_needs_free = false;
939 		ut32 bsze = 1; //core->blocksize;
940 		int eqdir = 0;
941 
942 		if (eq && eq > cstr) {
943 			char *prech = eq - 1;
944 			if (*prech == '+') {
945 				eqdir = 1;
946 				*prech = 0;
947 			} else if (*prech == '-') {
948 				eqdir = -1;
949 				*prech = 0;
950 			}
951 		}
952 
953 		// Get outta here as fast as we can so we can make sure that the comment
954 		// buffer used on later code can be freed properly if necessary.
955 		if (*cstr == '.') {
956 			input++;
957 			goto rep;
958 		}
959 		// Check base64 padding
960 		if (eq && !(b64 && eq > b64 && (eq[1] == '\0' || (eq[1] == '=' && eq[2] == '\0')))) {
961 			*eq = 0;
962 			ut64 arg = r_num_math (core->num, eq + 1);
963 			RFlagItem *item = r_flag_get (core->flags, cstr);
964 			if (eqdir && item) {
965 				off = item->offset + (arg * eqdir);
966 			} else {
967 				off = arg;
968 			}
969 		}
970 		if (s) {
971 			*s = '\0';
972 			s2 = strchr (s + 1, ' ');
973 			if (s2) {
974 				*s2 = '\0';
975 				if (s2[1] && s2[2]) {
976 					off = r_num_math (core->num, s2 + 1);
977 				}
978 				s3 = strchr (s2 + 1, ' ');
979 				if (s3) {
980 					*s3 = '\0';
981 					if (!strncmp (s3 + 1, "base64:", 7)) {
982 						comment = (char *) r_base64_decode_dyn (s3 + 8, -1);
983 						comment_needs_free = true;
984 					} else if (s3[1]) {
985 						comment = s3 + 1;
986 					}
987 				}
988 			}
989 			bsze = (s[1] == '=') ? 1 : r_num_math (core->num, s + 1);
990 		}
991 
992 		bool addFlag = true;
993 		if (input[0] == '+') {
994 			if ((item = r_flag_get_at (core->flags, off, false))) {
995 				addFlag = false;
996 			}
997 		}
998 		if (addFlag) {
999 			if (!r_name_check (cstr)) {
1000 				eprintf ("Invalid flag name '%s'.\n", cstr);
1001 				return false;
1002 			}
1003 			item = r_flag_set (core->flags, cstr, off, bsze);
1004 		}
1005 		if (item && comment) {
1006 			r_flag_item_set_comment (item, comment);
1007 			if (comment_needs_free) {
1008 				free (comment);
1009 			}
1010 		}
1011 		}
1012 		break;
1013 	case '-':
1014 		if (input[1] == '-') {
1015 			r_flag_unset_all (core->flags);
1016 		} else if (input[1]) {
1017 			const char *flagname = r_str_trim_head_ro (input + 1);
1018 			while (*flagname==' ') {
1019 				flagname++;
1020 			}
1021 			if (*flagname == '.') {
1022 				RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, off, 0);
1023 				if (fcn) {
1024 					r_anal_function_delete_label_at (fcn, off);
1025 				} else {
1026 					eprintf ("Cannot find function at 0x%08"PFMT64x"\n", off);
1027 				}
1028 			} else {
1029 				if (strchr (flagname, '*')) {
1030 					r_flag_unset_glob (core->flags, flagname);
1031 				} else {
1032 					r_flag_unset_name (core->flags, flagname);
1033 				}
1034 			}
1035 		} else {
1036 			r_flag_unset_off (core->flags, off);
1037 		}
1038 		break;
1039 	case '.': // "f."
1040 		input = r_str_trim_head_ro (input + 1) - 1;
1041 		if (input[1]) {
1042 			if (input[1] == '*' || input[1] == 'j') {
1043 				if (input[2] == '*') {
1044 					print_function_labels (core->anal, NULL, input[1]);
1045 				} else {
1046 					RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, off, 0);
1047 					if (fcn) {
1048 						print_function_labels (core->anal, fcn, input[1]);
1049 					} else {
1050 						eprintf ("Cannot find function at 0x%08"PFMT64x"\n", off);
1051 					}
1052 				}
1053 			} else {
1054 				char *name = strdup (input + ((input[2] == ' ')? 2: 1));
1055 				RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, off, 0);
1056 				if (name) {
1057 					char *eq = strchr (name, '=');
1058 					if (eq) {
1059 						*eq = 0;
1060 						off = r_num_math (core->num, eq + 1);
1061 					}
1062 					r_str_trim (name);
1063 					if (fcn) {
1064 						if (*name=='-') {
1065 							r_anal_function_delete_label (fcn, name + 1);
1066 						} else {
1067 							r_anal_function_set_label (fcn, name, off);
1068 						}
1069 					} else {
1070 						eprintf ("Cannot find function at 0x%08"PFMT64x"\n", off);
1071 					}
1072 					free (name);
1073 				}
1074 			}
1075 		} else {
1076 			RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, off, 0);
1077 			if (fcn) {
1078 				print_function_labels (core->anal, fcn, 0);
1079 			} else {
1080 				eprintf ("Local flags require a function to work.");
1081 			}
1082 		}
1083 		break;
1084 	case 'l': // "fl"
1085 		if (input[1] == '?') { // "fl?"
1086 			eprintf ("Usage: fl[a] [flagname] [flagsize]\n");
1087 		} else if (input[1] == 'a') { // "fla"
1088 			// TODO: we can optimize this if core->flags->flags is sorted by flagitem->offset
1089 			char *glob = strchr (input, ' ');
1090 			if (glob) {
1091 				glob++;
1092 			}
1093 			r_flag_foreach_glob (core->flags, glob, find_flag_after_foreach, core->flags);
1094 		} else if (input[1] == ' ') { // "fl ..."
1095 			char *p, *arg = strdup (input + 2);
1096 			r_str_trim (arg);
1097 			p = strchr (arg, ' ');
1098 			if (p) {
1099 				*p++ = 0;
1100 				item = r_flag_get_i (core->flags,
1101 					r_num_math (core->num, arg));
1102 				if (item)
1103 					item->size = r_num_math (core->num, p);
1104 			} else {
1105 				if (*arg) {
1106 					item = r_flag_get_i (core->flags, core->offset);
1107 					if (item) {
1108 						item->size = r_num_math (core->num, arg);
1109 					}
1110 				} else {
1111 					item = r_flag_get_i (core->flags, r_num_math (core->num, arg));
1112 					if (item) {
1113 						r_cons_printf ("0x%08"PFMT64x"\n", item->size);
1114 					}
1115 				}
1116 			}
1117 			free (arg);
1118 		} else { // "fl"
1119 			item = r_flag_get_i (core->flags, core->offset);
1120 			if (item)
1121 				r_cons_printf ("0x%08"PFMT64x"\n", item->size);
1122 		}
1123 		break;
1124 #if 0
1125 	case 'd':
1126 		if (input[1] == ' ') {
1127 			char cmd[128];
1128 			RFlagItem *item = r_flag_get_i (core->flags,
1129 				r_num_math (core->num, input+2));
1130 			if (item) {
1131 				r_cons_printf ("0x%08"PFMT64x"\n", item->offset);
1132 				snprintf (cmd, sizeof (cmd), "pD@%"PFMT64d":%"PFMT64d,
1133 					 item->offset, item->size);
1134 				r_core_cmd0 (core, cmd);
1135 			}
1136 		} else eprintf ("Missing arguments\n");
1137 		break;
1138 #endif
1139 	case 'z': // "fz"
1140 		cmd_fz (core, input + 1);
1141 		break;
1142 	case 'x':
1143 		if (input[1] == ' ') {
1144 			char cmd[128];
1145 			RFlagItem *item = r_flag_get_i (core->flags,
1146 				r_num_math (core->num, input+2));
1147 			if (item) {
1148 				r_cons_printf ("0x%08"PFMT64x"\n", item->offset);
1149 				snprintf (cmd, sizeof (cmd), "px@%"PFMT64d":%"PFMT64d,
1150 					 item->offset, item->size);
1151 				r_core_cmd0 (core, cmd);
1152 			}
1153 		} else {
1154 			eprintf ("Missing arguments\n");
1155 		}
1156 		break;
1157 	case ',': // "f,"
1158 		cmd_flag_table (core, input);
1159 		break;
1160 	case 't': // "ft"
1161 		cmd_flag_tags (core, input);
1162 		break;
1163 	case 's': // "fs"
1164 		switch (input[1]) {
1165 		case '?':
1166 			r_core_cmd_help (core, help_msg_fs);
1167 			break;
1168 		case '+': // "fs+"
1169 			r_flag_space_push (core->flags, r_str_trim_head_ro (input + 2));
1170 			break;
1171 		case 'r':
1172 			if (input[2] == ' ') {
1173 				char *newname = r_str_trim_dup (input + 3);
1174 				r_str_trim (newname);
1175 				r_flag_space_rename (core->flags, NULL, newname);
1176 				free (newname);
1177 			} else {
1178 				eprintf ("Usage: fsr [newname]\n");
1179 			}
1180 			break;
1181 		case 's':
1182 			flag_space_stack_list (core->flags, input[2]);
1183 			break;
1184 		case '-':
1185 			switch (input[2]) {
1186 			case '*':
1187 				r_flag_space_unset (core->flags, NULL);
1188 				break;
1189 			case '.': {
1190 				const RSpace *sp = r_flag_space_cur (core->flags);
1191 				if (sp) {
1192 					r_flag_space_unset (core->flags, sp->name);
1193 				}
1194 				break;
1195 			}
1196 			case 0:
1197 				r_flag_space_pop (core->flags);
1198 				break;
1199 			default:
1200 				r_flag_space_unset (core->flags, r_str_trim_head_ro (input + 2));
1201 				break;
1202 			}
1203 			break;
1204 		case ' ':
1205 		{
1206 			char *name = r_str_trim_dup (input + 2);
1207 			r_str_trim (name);
1208 			r_flag_space_set (core->flags, name);
1209 			free (name);
1210 			break;
1211 		}
1212 		case 'm':
1213 			{ RFlagItem *f;
1214 			ut64 off = core->offset;
1215 			if (input[2] == ' ') {
1216 				off = r_num_math (core->num, input+2);
1217 			}
1218 			f = r_flag_get_i (core->flags, off);
1219 			if (f) {
1220 				f->space = r_flag_space_cur (core->flags);
1221 			} else {
1222 				eprintf ("Cannot find any flag at 0x%"PFMT64x".\n", off);
1223 			}
1224 			}
1225 			break;
1226 		case 'j':
1227 		case '\0':
1228 		case '*':
1229 		case 'q':
1230 			spaces_list (&core->flags->spaces, input[1]);
1231 			break;
1232 		default:
1233 			spaces_list (&core->flags->spaces, 0);
1234 			break;
1235 		}
1236 		break;
1237 	case 'g': // "fg"
1238 		switch (input[1]) {
1239 		case '*':
1240 			__flag_graph (core, r_str_trim_head_ro (input + 2), '*');
1241 			break;
1242 		case ' ':
1243 			__flag_graph (core, r_str_trim_head_ro (input + 2), ' ');
1244 			break;
1245 		case 0:
1246 			__flag_graph (core, r_str_trim_head_ro (input + 1), 0);
1247 			break;
1248 		default:
1249 			eprintf ("Usage: fg[*] ([prefix])\n");
1250 			break;
1251 		}
1252 		break;
1253 	case 'c': // "fc"
1254 		if (input[1]=='?' || input[1] != ' ') {
1255 			r_core_cmd_help (core, help_msg_fc);
1256 		} else {
1257 			RFlagItem *fi;
1258 			const char *ret;
1259 			char *arg = r_str_trim_dup (input + 2);
1260 			char *color = strchr (arg, ' ');
1261 			if (color && color[1]) {
1262 				*color++ = 0;
1263 			}
1264 			fi = r_flag_get (core->flags, arg);
1265 			if (fi) {
1266 				ret = r_flag_item_set_color (fi, color);
1267 				if (!color && ret)
1268 					r_cons_println (ret);
1269 			} else {
1270 				eprintf ("Unknown flag '%s'\n", arg);
1271 			}
1272 			free (arg);
1273 		}
1274 		break;
1275 	case 'C': // "fC"
1276 		if (input[1] == ' ') {
1277 			RFlagItem *item;
1278 			char *q, *p = strdup (input + 2), *dec = NULL;
1279 			q = strchr (p, ' ');
1280 			if (q) {
1281 				*q = 0;
1282 				item = r_flag_get (core->flags, p);
1283 				if (item) {
1284 					if (!strncmp (q + 1, "base64:", 7)) {
1285 						dec = (char *) r_base64_decode_dyn (q + 8, -1);
1286 						if (dec) {
1287 							r_flag_item_set_comment (item, dec);
1288 							free (dec);
1289 						} else {
1290 							eprintf ("Failed to decode base64-encoded string\n");
1291 						}
1292 					} else {
1293 						r_flag_item_set_comment (item, q + 1);
1294 					}
1295 				} else {
1296 					eprintf ("Cannot find flag with name '%s'\n", p);
1297 				}
1298 			} else {
1299 				item = r_flag_get_i (core->flags, r_num_math (core->num, p));
1300 				if (item && item->comment) {
1301 					r_cons_println (item->comment);
1302 				} else {
1303 					eprintf ("Cannot find item\n");
1304 				}
1305 			}
1306 			free (p);
1307 		} else eprintf ("Usage: fC [name] [comment]\n");
1308 		break;
1309 	case 'o': // "fo"
1310 		r_core_fortune_print_random (core);
1311 		break;
1312 	case 'O': // "fO"
1313 		flag_ordinals (core, input + 1);
1314 		break;
1315 	case 'r':
1316 		if (input[1] == ' ' && input[2]) {
1317 			RFlagItem *item;
1318 			char *old = str + 1;
1319 			char *new = strchr (old, ' ');
1320 			if (new) {
1321 				*new = 0;
1322 				new++;
1323 				item = r_flag_get (core->flags, old);
1324 				if (!item && !strncmp (old, "fcn.", 4)) {
1325 					item = r_flag_get (core->flags, old+4);
1326 				}
1327 			} else {
1328 				new = old;
1329 				item = r_flag_get_i (core->flags, core->offset);
1330 			}
1331 			if (item) {
1332 				if (!r_flag_rename (core->flags, item, new)) {
1333 					eprintf ("Invalid name\n");
1334 				}
1335 			} else {
1336 				eprintf ("Usage: fr [[old]] [new]\n");
1337 			}
1338 		}
1339 		break;
1340 	case 'N':
1341 		if (!input[1]) {
1342 			RFlagItem *item = r_flag_get_i (core->flags, core->offset);
1343 			if (item) {
1344 				r_cons_printf ("%s\n", item->realname);
1345 			}
1346 			break;
1347 		} else if (input[1] == ' ' && input[2]) {
1348 			RFlagItem *item;
1349 			char *name = str + 1;
1350 			char *realname = strchr (name, ' ');
1351 			if (realname) {
1352 				*realname = 0;
1353 				realname++;
1354 				item = r_flag_get (core->flags, name);
1355 				if (!item && !strncmp (name, "fcn.", 4)) {
1356 					item = r_flag_get (core->flags, name+4);
1357 				}
1358 			} else {
1359 				realname = name;
1360 				item = r_flag_get_i (core->flags, core->offset);
1361 			}
1362 			if (item) {
1363 				r_flag_item_set_realname (item, realname);
1364 			}
1365 			break;
1366 		}
1367 		eprintf ("Usage: fN [[name]] [[realname]]\n");
1368 		break;
1369 	case '\0':
1370 	case 'n': // "fn" "fnj"
1371 	case '*': // "f*"
1372 	case 'j': // "fj"
1373 	case 'q': // "fq"
1374 		if (input[0]) {
1375 			switch (input[1]) {
1376 			case 'j':
1377 			case 'q':
1378 			case 'n':
1379 			case '*':
1380 				input++;
1381 				break;
1382 			}
1383 		}
1384 		if (input[0] && input[1] == '.') {
1385 			const int mode = input[2];
1386 			const RList *list = r_flag_get_list (core->flags, core->offset);
1387 			PJ *pj = NULL;
1388 			if (mode == 'j') {
1389 				pj = pj_new ();
1390 				pj_a (pj);
1391 			}
1392 			RListIter *iter;
1393 			RFlagItem *item;
1394 			r_list_foreach (list, iter, item) {
1395 				switch (mode) {
1396 				case '*':
1397 					r_cons_printf ("f %s = 0x%08"PFMT64x"\n", item->name, item->offset);
1398 					break;
1399 				case 'j':
1400 					{
1401 						pj_o (pj);
1402 						pj_ks (pj, "name", item->name);
1403 						pj_ks (pj, "realname", item->realname);
1404 						pj_kn (pj, "offset", item->offset);
1405 						pj_kn (pj, "size", item->size);
1406 						pj_end (pj);
1407 					}
1408 					break;
1409 				default:
1410 					r_cons_printf ("%s\n", item->name);
1411 					break;
1412 				}
1413 			}
1414 			if (mode == 'j') {
1415 				pj_end (pj);
1416 				char *s = pj_drain (pj);
1417 				r_cons_printf ("%s\n", s);
1418 				free (s);
1419 			}
1420 		} else {
1421 			r_flag_list (core->flags, *input, input[0]? input + 1: "");
1422 		}
1423 		break;
1424 	case 'i': // "fi"
1425 		if (input[1] == ' ' || (input[1] && input[2] == ' ')) {
1426 			char *arg = strdup (r_str_trim_head_ro (input + 2));
1427 			if (*arg) {
1428 				arg = strdup (r_str_trim_head_ro (input + 2));
1429 				char *sp = strchr (arg, ' ');
1430 				if (!sp) {
1431 					char *newarg = r_str_newf ("%c0x%"PFMT64x" %s+0x%"PFMT64x,
1432 						input[1], core->offset, arg, core->offset);
1433 					free (arg);
1434 					arg = newarg;
1435 				} else {
1436 					char *newarg = r_str_newf ("%c%s", input[1], arg);
1437 					free (arg);
1438 					arg = newarg;
1439 				}
1440 			} else {
1441 				free (arg);
1442 				arg = r_str_newf (" 0x%"PFMT64x" 0x%"PFMT64x,
1443 					core->offset, core->offset + core->blocksize);
1444 			}
1445 			r_flag_list (core->flags, 'i', arg);
1446 			free (arg);
1447 		} else {
1448 			// XXX dupe for prev case
1449 			char *arg = r_str_newf (" 0x%"PFMT64x" 0x%"PFMT64x,
1450 				core->offset, core->offset + core->blocksize);
1451 			r_flag_list (core->flags, 'i', arg);
1452 			free (arg);
1453 		}
1454 		break;
1455 	case 'd': // "fd"
1456 		{
1457 			ut64 addr = core->offset;
1458 			char *arg = NULL;
1459 			RFlagItem *f = NULL;
1460 			bool strict_offset = false;
1461 			switch (input[1]) {
1462 			case '?':
1463 				r_core_cmd_help (core, help_msg_fd);
1464 				if (str) {
1465 					free (str);
1466 				}
1467 				return false;
1468 			case '\0':
1469 				addr = core->offset;
1470 				break;
1471 			case 'd':
1472 				arg = strchr (input, ' ');
1473 				if (arg) {
1474 					addr = r_num_math (core->num, arg + 1);
1475 				}
1476 				break;
1477 			case '.': // "fd." list all flags at given offset
1478 				{
1479 				RFlagItem *flag;
1480 				RListIter *iter;
1481 				bool isJson = false;
1482 				const RList *flaglist;
1483 				arg = strchr (input, ' ');
1484 				if (arg) {
1485 					addr = r_num_math (core->num, arg + 1);
1486 				}
1487 				flaglist = r_flag_get_list (core->flags, addr);
1488 				isJson = strchr (input, 'j');
1489 				PJ *pj = pj_new ();
1490 				if (isJson) {
1491 					pj_a (pj);
1492 				}
1493 
1494 				// Sometime an address has multiple flags assigned to, show them all
1495 				r_list_foreach (flaglist, iter, flag) {
1496 					if (flag) {
1497 						if (isJson) {
1498 							pj_o (pj);
1499 							pj_ks (pj, "name", flag->name);
1500 							if (flag->realname) {
1501 								pj_ks (pj, "realname", flag->realname);
1502 							}
1503 							pj_end (pj);
1504 
1505 						} else {
1506 							// Print realname if exists and asm.flags.real is enabled
1507 							if (core->flags->realnames && flag->realname) {
1508 								r_cons_println (flag->realname);
1509 							} else {
1510 								r_cons_println (flag->name);
1511 							}
1512 						}
1513 					}
1514 				}
1515 
1516 				if (isJson) {
1517 					pj_end (pj);
1518 					r_cons_println (pj_string (pj));
1519 				}
1520 
1521 				if (pj) {
1522 					pj_free (pj);
1523 				}
1524 
1525 				return 0;
1526 				}
1527 			case 'w': {
1528 				arg = strchr (input, ' ');
1529 				if (!arg) {
1530 					return 0;
1531 				}
1532 				arg++;
1533 				if (!*arg) {
1534 					return 0;
1535 				}
1536 
1537 				RFlag *f = core->flags;
1538 				RList *temp = r_flag_all_list (f, true);
1539 				ut64 loff = 0;
1540 				ut64 uoff = 0;
1541 				ut64 curseek = core->offset;
1542 				char *lmatch = NULL , *umatch = NULL;
1543 				RFlagItem *flag;
1544 				RListIter *iter;
1545 				r_list_sort (temp, &cmpflag);
1546 				r_list_foreach (temp, iter, flag) {
1547 					if (strstr (flag->name , arg) != NULL) {
1548 						if (flag->offset < core->offset) {
1549 							loff = flag->offset;
1550 							lmatch = flag->name;
1551 							continue;
1552 						}
1553 						uoff = flag->offset;
1554 						umatch = flag->name;
1555 						break;
1556 					}
1557 				}
1558 				char *match = (curseek - loff) < (uoff - curseek) ? lmatch : umatch ;
1559 				if (match) {
1560 					if (*match) {
1561 						r_cons_println (match);
1562 					}
1563 				}
1564 				r_list_free (temp);
1565 				return 0;
1566 			}
1567 			default:
1568 				arg = strchr (input, ' ');
1569 				if (arg) {
1570 					addr = r_num_math (core->num, arg + 1);
1571 				}
1572 				break;
1573 			}
1574 			f = r_flag_get_at (core->flags, addr, !strict_offset);
1575 			if (f) {
1576 				if (f->offset != addr) {
1577 					// if input contains 'j' print json
1578 					if (strchr (input, 'j')) {
1579 						PJ *pj = pj_new ();
1580 						pj_o (pj);
1581 						pj_kn (pj, "offset", f->offset);
1582 						pj_ks (pj, "name", f->name);
1583 						// Print flag's real name if defined
1584 						if (f->realname) {
1585 							pj_ks (pj, "realname", f->realname);
1586 						}
1587 						pj_end (pj);
1588 						r_cons_println (pj_string (pj));
1589 						if (pj) {
1590 							pj_free (pj);
1591 						}
1592 					} else {
1593 						// Print realname if exists and asm.flags.real is enabled
1594 						if (core->flags->realnames && f->realname) {
1595 							r_cons_printf ("%s + %d\n", f->realname,
1596 									   (int)(addr - f->offset));
1597 						} else {
1598 							r_cons_printf ("%s + %d\n", f->name,
1599 									   (int)(addr - f->offset));
1600 						}
1601 					}
1602 				} else {
1603 					if (strchr (input, 'j')) {
1604 						PJ *pj = pj_new ();
1605 						pj_o (pj);
1606 						pj_ks (pj, "name", f->name);
1607 						// Print flag's real name if defined
1608 						if (f->realname) {
1609 							pj_ks (pj, "realname", f->realname);
1610 						}
1611 						pj_end (pj);
1612 						r_cons_println (pj_string (pj));
1613 						pj_free (pj);
1614 					} else {
1615 						// Print realname if exists and asm.flags.real is enabled
1616 						if (core->flags->realnames && f->realname) {
1617 							r_cons_println (f->realname);
1618 						} else {
1619 							r_cons_println (f->name);
1620 						}
1621 					}
1622 				}
1623 			}
1624 		}
1625 		break;
1626 	case '?':
1627 	default:
1628 		if (input[1]) {
1629 			const char *arg = r_str_trim_head_ro (input + 1);
1630 			RFlagItem *fi = r_flag_get (core->flags, arg);
1631 			core->num->value = fi? 1: 0;
1632 		} else {
1633 			r_core_cmd_help (core, help_msg_f);
1634 			break;
1635 		}
1636 	}
1637 	free (str);
1638 	return 0;
1639 }
1640