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