1 /* radare - LGPL - Copyright 2009-2020 - pancake, oddcoder, Anton Kochkov, Jody Frankowski */
2
3 #include <string.h>
4 #include "r_anal.h"
5 #include "r_cons.h"
6 #include "r_core.h"
7 #include <sdb.h>
8
9 static const char *help_msg_t[] = {
10 "Usage: t", "", "# cparse types commands",
11 "t", "", "List all loaded types",
12 "tj", "", "List all loaded types as json",
13 "t", " <type>", "Show type in 'pf' syntax",
14 "t*", "", "List types info in r2 commands",
15 "t-", " <name>", "Delete types by its name",
16 "t-*", "", "Remove all types",
17 "tail", " [filename]", "Output the last part of files",
18 "tc", " [type.name]", "List all/given types in C output format",
19 "te", "[?]", "List all loaded enums",
20 "td", "[?] <string>", "Load types from string",
21 "tf", "", "List all loaded functions signatures",
22 "tk", " <sdb-query>", "Perform sdb query",
23 "tl", "[?]", "Show/Link type to an address",
24 "tn", "[?] [-][addr]", "manage noreturn function attributes and marks",
25 "to", " -", "Open cfg.editor to load types",
26 "to", " <path>", "Load types from C header file",
27 "toe", " [type.name]", "Open cfg.editor to edit types",
28 "tos", " <path>", "Load types from parsed Sdb database",
29 "touch", " <file>", "Create or update timestamp in file",
30 "tp", " <type> [addr|varname]", "cast data at <address> to <type> and print it (XXX: type can contain spaces)",
31 "tpv", " <type> @ [value]", "Show offset formatted for given type",
32 "tpx", " <type> <hexpairs>", "Show value for type with specified byte sequence (XXX: type can contain spaces)",
33 "ts", "[?]", "Print loaded struct types",
34 "tu", "[?]", "Print loaded union types",
35 "tx", "[f?]", "Type xrefs",
36 "tt", "[?]", "List all loaded typedefs",
37 NULL
38 };
39
40 static const char *help_msg_tcc[] = {
41 "Usage: tcc", "[-name]", "# type function calling conventions (see also afc? and arcc)",
42 "tcc", "", "List all calling convcentions",
43 "tcc", " r0 pascal(r0,r1,r2)", "Define signature for pascall cc (see also arcc)",
44 "tcc", "-pascal", "Remove the pascal cc",
45 "tcc-*", "", "Unregister all the calling conventions",
46 "tcck", "", "List calling conventions in k=v",
47 "tccl", "", "List cc signatures (return ccname (arg0, arg1, ..) err;)",
48 "tccj", "", "List them in JSON",
49 "tcc*", "", "List them as r2 commands",
50 NULL
51 };
52
53 static const char *help_msg_t_minus[] = {
54 "Usage: t-", " <type>", "Delete type by its name",
55 NULL
56 };
57
58 static const char *help_msg_tf[] = {
59 "Usage: tf[...]", "", "",
60 "tf", "", "List all function definitions loaded",
61 "tf", " <name>", "Show function signature",
62 "tfc", " <name>", "Show function signature in C syntax",
63 "tfcj", " <name>", "Same as above but in JSON",
64 "tfj", "", "List all function definitions in JSON",
65 "tfj", " <name>", "Show function signature in JSON",
66 NULL
67 };
68
69 static const char *help_msg_to[] = {
70 "Usage: to[...]", "", "",
71 "to", " -", "Open cfg.editor to load types",
72 "to", " <path>", "Load types from C header file",
73 "tos", " <path>", "Load types from parsed Sdb database",
74 "touch", " <file>", "Create or update timestamp in file",
75 NULL
76 };
77
78 static const char *help_msg_tp[] = {
79 "Usage: tp[...]", "", "",
80 "tp", " <type> [addr|varname]", "cast data at <address> to <type> and print it (XXX: type can contain spaces)",
81 "tpv", " <type> @ [value]", "Show offset formatted for given type",
82 "tpx", " <type> <hexpairs>", "Show value for type with specified byte sequence (XXX: type can contain spaces)",
83 NULL
84 };
85
86 static const char *help_msg_tc[] = {
87 "Usage: tc[...]", " [cctype]", "",
88 "tc", " [type.name]", "List all/given loaded types in C output format with newlines",
89 "tcd", "", "List all loaded types in C output format without newlines",
90 "tcc", "?", "Manage calling conventions types",
91 "tc?", "", "show this help",
92 NULL
93 };
94
95 static const char *help_msg_td[] = {
96 "Usage:", "\"td [...]\"", "",
97 "td", "[string]", "Load types from string",
98 NULL
99 };
100
101 static const char *help_msg_te[] = {
102 "Usage: te[...]", "", "",
103 "te", "", "List all loaded enums",
104 "te", " <enum>", "Print all values of enum for given name",
105 "tej", "", "List all loaded enums in json",
106 "tej", " <enum>", "Show enum in json",
107 "te", " <enum> <value>", "Show name for given enum number",
108 "teb", " <enum> <name>", "Show matching enum bitfield for given name",
109 "tec", "<name>", "List all/given loaded enums in C output format with newlines",
110 "ted", "", "List all loaded enums in C output format without newlines",
111 "te?", "", "show this help",
112 NULL
113 };
114
115 static const char *help_msg_tt[] = {
116 "Usage: tt[...]", "", "",
117 "tt", "", "List all loaded typedefs",
118 "tt", " <typename>", "Show name for given type alias",
119 "ttj", "", "Show typename and type alias in json",
120 "ttc", "<name>", "Show typename and type alias in C output format",
121 "tt?", "", "show this help",
122 NULL
123 };
124
125 static const char *help_msg_tl[] = {
126 "Usage: tl[...]", "[typename] [[=] address]", "# Type link commands",
127 "tl", "", "list all links.",
128 "tll", "", "list all links in readable format.",
129 "tllj", "", "list all links in readable JSON format.",
130 "tl", " [typename]", "link a type to current address.",
131 "tl", " [typename] = [address]", "link type to given address.",
132 "tls", " [address]", "show link at given address.",
133 "tl-*", "", "delete all links.",
134 "tl-", " [address]", "delete link at given address.",
135 "tl*", "", "list all links in radare2 command format.",
136 "tlj", "", "list all links in JSON format.",
137 NULL
138 };
139
140 static const char *help_msg_tn[] = {
141 "Usage:", "tn [-][0xaddr|symname]", " manage no-return marks",
142 "tn[a]", " 0x3000", "stop function analysis if call/jmp to this address",
143 "tn[n]", " sym.imp.exit", "same as above but for flag/fcn names",
144 "tn-", " 0x3000 sym.imp.exit ...", "remove some no-return references",
145 "tn-*", "", "remove all no-return references",
146 "tn", "", "list them all",
147 NULL
148 };
149
150 static const char *help_msg_ts[] = {
151 "Usage: ts[...]", " [type]", "",
152 "ts", "", "List all loaded structs",
153 "ts", " [type]", "Show pf format string for given struct",
154 "tsj", "", "List all loaded structs in json",
155 "tsj", " [type]", "Show pf format string for given struct in json",
156 "ts*", "", "Show pf.<name> format string for all loaded structs",
157 "ts*", " [type]", "Show pf.<name> format string for given struct",
158 "tsc", "<name>", "List all/given loaded structs in C output format with newlines",
159 "tsd", "", "List all loaded structs in C output format without newlines",
160 "tss", " [type]", "Display size of struct",
161 "ts?", "", "show this help",
162 NULL
163 };
164
165 static const char *help_msg_tu[] = {
166 "Usage: tu[...]", "", "",
167 "tu", "", "List all loaded unions",
168 "tu", " [type]", "Show pf format string for given union",
169 "tuj", "", "List all loaded unions in json",
170 "tuj", " [type]", "Show pf format string for given union in json",
171 "tu*", "", "Show pf.<name> format string for all loaded unions",
172 "tu*", " [type]", "Show pf.<name> format string for given union",
173 "tuc", "<name>", "List all/given loaded unions in C output format with newlines",
174 "tud", "", "List all loaded unions in C output format without newlines",
175 "tu?", "", "show this help",
176 NULL
177 };
178
cmd_type_init(RCore * core,RCmdDesc * parent)179 static void cmd_type_init(RCore *core, RCmdDesc *parent) {
180 DEFINE_CMD_DESCRIPTOR (core, t);
181 DEFINE_CMD_DESCRIPTOR_SPECIAL (core, t-, t_minus);
182 DEFINE_CMD_DESCRIPTOR (core, tc);
183 DEFINE_CMD_DESCRIPTOR (core, td);
184 DEFINE_CMD_DESCRIPTOR (core, te);
185 DEFINE_CMD_DESCRIPTOR (core, tl);
186 DEFINE_CMD_DESCRIPTOR (core, tn);
187 DEFINE_CMD_DESCRIPTOR (core, ts);
188 DEFINE_CMD_DESCRIPTOR (core, tu);
189 DEFINE_CMD_DESCRIPTOR (core, tt);
190 }
191
show_help(RCore * core)192 static void show_help(RCore *core) {
193 r_core_cmd_help (core, help_msg_t);
194 }
195
cc_cb(void * p,const char * k,const char * v)196 static bool cc_cb(void *p, const char *k, const char *v) {
197 if (!strcmp (v, "cc")) {
198 RList *list = (RList*)p;
199 r_list_append (list, (void*)k);
200 }
201 return true;
202 }
203
cmd_afcl(RCore * core,const char * input)204 static void cmd_afcl(RCore *core, const char *input) {
205 int mode = 0;
206 PJ *pj = NULL;
207 if (input) {
208 mode = *input;
209 if (*input == 'j') {
210 pj = r_core_pj_new (core);
211 pj_o (pj);
212 }
213 }
214 RList *list = r_list_newf (NULL);
215 sdb_foreach (core->anal->sdb_cc, cc_cb, list);
216 char *cc;
217 RListIter *iter;
218 r_list_sort (list, (RListComparator)strcmp);
219 r_list_foreach (list, iter, cc) {
220 if (pj) {
221 pj_ko (pj, cc);
222 r_anal_cc_get_json (core->anal, pj, cc);
223 pj_end (pj);
224 } else if (mode == 'l') {
225 char *sig = r_anal_cc_get (core->anal, cc);
226 r_cons_println (sig);
227 free (sig);
228 } else if (mode == '*') {
229 char *ccexpr = r_anal_cc_get (core->anal, cc);
230 r_cons_printf ("tcc %s\n", ccexpr);
231 free (ccexpr);
232 } else {
233 r_cons_println (cc);
234 }
235 }
236 r_list_free (list);
237 if (pj) {
238 pj_end (pj);
239 char *j = pj_drain (pj);
240 r_cons_println (j);
241 free (j);
242 }
243 }
244
cmd_afck(RCore * core,const char * c)245 static void cmd_afck(RCore *core, const char *c) {
246 const char *s = "anal/cc/*";
247 char *out = sdb_querys (core->sdb, NULL, 0, s);
248 if (out) {
249 r_cons_print (out);
250 }
251 free (out);
252 }
253
cmd_tcc(RCore * core,const char * input)254 static void cmd_tcc(RCore *core, const char *input) {
255 switch (*input) {
256 case '?':
257 r_core_cmd_help (core, help_msg_tcc);
258 break;
259 case '-':
260 if (input[1] == '*') {
261 sdb_reset (core->anal->sdb_cc);
262 } else {
263 r_anal_cc_del (core->anal, r_str_trim_head_ro (input + 1));
264 }
265 break;
266 case 0:
267 cmd_afcl (core, "");
268 break;
269 case 'l':
270 cmd_afcl (core, "l");
271 break;
272 case 'j':
273 cmd_afcl (core, "j");
274 break;
275 break;
276 case '*':
277 cmd_afcl (core, "*");
278 break;
279 case 'k':
280 cmd_afck (core, NULL);
281 break;
282 case ' ':
283 if (strchr (input, '(')) {
284 if (!r_anal_cc_set (core->anal, input + 1)) {
285 eprintf ("Invalid syntax in cc signature.");
286 }
287 } else {
288 const char *ccname = r_str_trim_head_ro (input + 1);
289 char *cc = r_anal_cc_get (core->anal, ccname);
290 if (cc) {
291 r_cons_printf ("%s\n", cc);
292 free (cc);
293 }
294 }
295 break;
296 }
297 }
298
showFormat(RCore * core,const char * name,int mode)299 static void showFormat(RCore *core, const char *name, int mode) {
300 const char *isenum = sdb_const_get (core->anal->sdb_types, name, 0);
301 if (isenum && !strcmp (isenum, "enum")) {
302 eprintf ("IS ENUM\n");
303 } else {
304 char *fmt = r_type_format (core->anal->sdb_types, name);
305 if (fmt) {
306 r_str_trim (fmt);
307 if (mode == 'j') {
308 PJ *pj = pj_new ();
309 if (!pj) {
310 return;
311 }
312 pj_o (pj);
313 pj_ks (pj, "name", name);
314 pj_ks (pj, "format", fmt);
315 pj_end (pj);
316 r_cons_printf ("%s", pj_string (pj));
317 pj_free (pj);
318 } else {
319 if (mode) {
320 r_cons_printf ("pf.%s %s\n", name, fmt);
321 } else {
322 r_cons_printf ("pf %s\n", fmt);
323 }
324 }
325 free (fmt);
326 } else {
327 eprintf ("Cannot find '%s' type\n", name);
328 }
329 }
330 }
331
cmd_tail(void * data,const char * _input)332 static int cmd_tail(void *data, const char *_input) { // "tail"
333 char *input = strdup (_input);
334 RCore *core = (RCore *)data;
335 int lines = 5;
336 char *arg = strchr (input, ' ');
337 char *tmp, *count;
338 if (arg) {
339 arg = (char *)r_str_trim_head_ro (arg + 1); // contains "count filename"
340 count = strchr (arg, ' ');
341 if (count) {
342 *count = 0; // split the count and file name
343 tmp = (char *)r_str_trim_head_ro (count + 1);
344 lines = atoi (arg);
345 arg = tmp;
346 }
347 }
348 switch (*input) {
349 case '?': // "tail?"
350 eprintf ("Usage: tail [file] # to list last n lines in file\n");
351 break;
352 default: // "tail"
353 if (!arg) {
354 arg = "";
355 }
356 if (r_fs_check (core->fs, arg)) {
357 r_core_cmdf (core, "md %s", arg);
358 } else {
359 char *res = r_syscmd_tail (arg, lines);
360 if (res) {
361 r_cons_print (res);
362 free (res);
363 }
364 }
365 break;
366 }
367 free (input);
368 return 0;
369 }
370
cmd_type_noreturn(RCore * core,const char * input)371 static void cmd_type_noreturn(RCore *core, const char *input) {
372 switch (input[0]) {
373 case '-': // "tn-"
374 if (input[1] == '*') {
375 r_core_cmd0 (core, "tn- `tn`");
376 } else {
377 char *s = strdup (r_str_trim_head_ro (input + 1));
378 RListIter *iter;
379 char *k;
380 RList *list = r_str_split_list (s, " ", 0);
381 r_list_foreach (list, iter, k) {
382 r_anal_noreturn_drop (core->anal, k);
383 }
384 r_list_free (list);
385 free (s);
386 }
387 break;
388 case ' ': // "tn"
389 {
390 const char *arg = r_str_trim_head_ro (input + 1);
391 ut64 n = r_num_math (core->num, arg);
392 if (n) {
393 r_anal_noreturn_add (core->anal, arg, n);
394 } else {
395 r_anal_noreturn_add (core->anal, arg, UT64_MAX);
396 }
397 }
398 break;
399 case 'a': // "tna"
400 if (input[1] == ' ') {
401 r_anal_noreturn_add (core->anal, NULL,
402 r_num_math (core->num, input + 1));
403 } else {
404 r_core_cmd_help (core, help_msg_tn);
405 }
406 break;
407 case 'n': // "tnn"
408 if (input[1] == ' ') {
409 /* do nothing? */
410 r_anal_noreturn_add (core->anal, r_str_trim_head_ro (input + 2), UT64_MAX);
411 } else {
412 r_core_cmd_help (core, help_msg_tn);
413 }
414 break;
415 case '*':
416 case 'r': // "tn*"
417 r_anal_noreturn_list (core->anal, 1);
418 break;
419 case 0: // "tn"
420 r_anal_noreturn_list (core->anal, 0);
421 break;
422 default:
423 case '?':
424 r_core_cmd_help (core, help_msg_tn);
425 break;
426 }
427 }
428
429 static Sdb *TDB_ = NULL; // HACK
430
stdifstruct(void * user,const char * k,const char * v)431 static bool stdifstruct(void *user, const char *k, const char *v) {
432 r_return_val_if_fail (TDB_, false);
433 if (!strcmp (v, "struct") && !r_str_startswith (k, "typedef")) {
434 return true;
435 }
436 if (!strcmp (v, "typedef")) {
437 const char *typedef_key = sdb_fmt ("typedef.%s", k);
438 const char *type = sdb_const_get (TDB_, typedef_key, NULL);
439 if (type && r_str_startswith (type, "struct")) {
440 return true;
441 }
442 }
443 return false;
444 }
445
446 /*!
447 * \brief print the data types details in JSON format
448 * \param TDB pointer to the sdb for types
449 * \param filter a callback function for the filtering
450 * \return 1 if success, 0 if failure
451 */
print_struct_union_list_json(Sdb * TDB,SdbForeachCallback filter)452 static int print_struct_union_list_json(Sdb *TDB, SdbForeachCallback filter) {
453 PJ *pj = pj_new ();
454 if (!pj) {
455 return 0;
456 }
457 SdbList *l = sdb_foreach_list_filter (TDB, filter, true);
458 SdbListIter *it;
459 SdbKv *kv;
460
461 pj_a (pj); // [
462 ls_foreach (l, it, kv) {
463 const char *k = sdbkv_key (kv);
464 if (!k || !*k) {
465 continue;
466 }
467 pj_o (pj); // {
468 pj_ks (pj, "type", k); // key value pair of string and string
469 pj_end (pj); // }
470 }
471 pj_end (pj); // ]
472
473 r_cons_println (pj_string (pj));
474 pj_free (pj);
475 ls_free (l);
476 return 1;
477 }
478
print_struct_union_in_c_format(Sdb * TDB,SdbForeachCallback filter,const char * arg,bool multiline)479 static void print_struct_union_in_c_format(Sdb *TDB, SdbForeachCallback filter, const char *arg, bool multiline) {
480 char *name = NULL;
481 SdbKv *kv;
482 SdbListIter *iter;
483 SdbList *l = sdb_foreach_list_filter (TDB, filter, true);
484 const char *space = "";
485 bool match = false;
486
487 ls_foreach (l, iter, kv) {
488 if (name && !strcmp (sdbkv_value (kv), name)) {
489 continue;
490 }
491 free (name);
492 int n;
493 name = strdup (sdbkv_key (kv));
494 if (name && (arg && *arg)) {
495 if (!strcmp (arg, name)) {
496 match = true;
497 } else {
498 continue;
499 }
500 }
501 r_cons_printf ("%s %s {%s", sdbkv_value (kv), name, multiline? "\n": "");
502 char *p, *var = r_str_newf ("%s.%s", sdbkv_value (kv), name);
503 for (n = 0; (p = sdb_array_get (TDB, var, n, NULL)); n++) {
504 char *var2 = r_str_newf ("%s.%s", var, p);
505 if (var2) {
506 char *val = sdb_array_get (TDB, var2, 0, NULL);
507 if (val) {
508 char *arr = sdb_array_get (TDB, var2, 2, NULL);
509 int arrnum = atoi (arr);
510 free (arr);
511 if (multiline) {
512 r_cons_printf ("\t%s", val);
513 if (p && p[0] != '\0') {
514 r_cons_printf ("%s%s", strstr (val, " *")? "": " ", p);
515 if (arrnum) {
516 r_cons_printf ("[%d]", arrnum);
517 }
518 }
519 r_cons_println (";");
520 } else {
521 r_cons_printf ("%s%s %s", space, val, p);
522 if (arrnum) {
523 r_cons_printf ("[%d]", arrnum);
524 }
525 r_cons_print (";");
526 space = " ";
527 }
528 free (val);
529 }
530 free (var2);
531 }
532 free (p);
533 }
534 free (var);
535 r_cons_println ("};");
536 space = "";
537 if (match) {
538 break;
539 }
540 }
541 free (name);
542 ls_free (l);
543 }
544
print_enum_in_c_format(Sdb * TDB,const char * arg,bool multiline)545 static void print_enum_in_c_format(Sdb *TDB, const char *arg, bool multiline) {
546 char *name = NULL;
547 SdbKv *kv;
548 SdbListIter *iter;
549 SdbList *l = sdb_foreach_list (TDB, true);
550 const char *separator = "";
551 bool match = false;
552 ls_foreach (l, iter, kv) {
553 if (!strcmp (sdbkv_value (kv), "enum")) {
554 if (!name || strcmp (sdbkv_value (kv), name)) {
555 free (name);
556 name = strdup (sdbkv_key (kv));
557 if (name && (arg && *arg)) {
558 if (!strcmp (arg, name)) {
559 match = true;
560 } else {
561 continue;
562 }
563 }
564 r_cons_printf ("%s %s {%s", sdbkv_value (kv), name, multiline? "\n": "");
565 {
566 RList *list = r_type_get_enum (TDB, name);
567 if (list && !r_list_empty (list)) {
568 RListIter *iter;
569 RTypeEnum *member;
570 separator = multiline? "\t": "";
571 r_list_foreach (list, iter, member) {
572 r_cons_printf ("%s%s = %" PFMT64u, separator, member->name, r_num_math (NULL, member->val));
573 separator = multiline? ",\n\t": ", ";
574 }
575 }
576 r_list_free (list);
577 }
578 r_cons_println (multiline? "\n};": "};");
579 if (match) {
580 break;
581 }
582 }
583 }
584 }
585 free (name);
586 ls_free (l);
587 }
588
printkey_cb(void * user,const char * k,const char * v)589 static bool printkey_cb(void *user, const char *k, const char *v) {
590 r_cons_println (k);
591 return true;
592 }
593
594 // maybe dupe?. should return char *instead of print for reusability
printFunctionTypeC(RCore * core,const char * input)595 static void printFunctionTypeC(RCore *core, const char *input) {
596 Sdb *TDB = core->anal->sdb_types;
597 char *res = sdb_querys (TDB, NULL, -1, sdb_fmt ("func.%s.args", input));
598 const char *name = r_str_trim_head_ro (input);
599 int i, args = sdb_num_get (TDB, sdb_fmt ("func.%s.args", name), 0);
600 const char *ret = sdb_const_get (TDB, sdb_fmt ("func.%s.ret", name), 0);
601 if (!ret) {
602 ret = "void";
603 }
604 if (!ret || !name) {
605 // missing function name specified
606 return;
607 }
608
609 r_cons_printf ("%s %s (", ret, name);
610 for (i = 0; i < args; i++) {
611 char *type = sdb_get (TDB, sdb_fmt ("func.%s.arg.%d", name, i), 0);
612 char *name = strchr (type, ',');
613 if (name) {
614 *name++ = 0;
615 }
616 r_cons_printf ("%s%s %s", i==0? "": ", ", type, name);
617 }
618 r_cons_printf (");\n");
619 free (res);
620 }
621
printFunctionType(RCore * core,const char * input)622 static void printFunctionType(RCore *core, const char *input) {
623 Sdb *TDB = core->anal->sdb_types;
624 PJ *pj = pj_new ();
625 if (!pj) {
626 return;
627 }
628 pj_o (pj);
629 char *res = sdb_querys (TDB, NULL, -1, sdb_fmt ("func.%s.args", input));
630 const char *name = r_str_trim_head_ro (input);
631 int i, args = sdb_num_get (TDB, sdb_fmt ("func.%s.args", name), 0);
632 pj_ks (pj, "name", name);
633 const char *ret_type = sdb_const_get (TDB, sdb_fmt ("func.%s.ret", name), 0);
634 pj_ks (pj, "ret", r_str_get_fail (ret_type, "void"));
635 pj_k (pj, "args");
636 pj_a (pj);
637 for (i = 0; i < args; i++) {
638 char *type = sdb_get (TDB, sdb_fmt ("func.%s.arg.%d", name, i), 0);
639 if (!type) {
640 continue;
641 }
642 char *name = strchr (type, ',');
643 if (name) {
644 *name++ = 0;
645 }
646 pj_o (pj);
647 pj_ks (pj, "type", type);
648 if (name) {
649 pj_ks (pj, "name", name);
650 } else {
651 pj_ks (pj, "name", "(null)");
652 }
653 pj_end (pj);
654 }
655 pj_end (pj);
656 pj_end (pj);
657 r_cons_printf ("%s", pj_string (pj));
658 pj_free (pj);
659 free (res);
660 }
661
printfunc_json_cb(void * user,const char * k,const char * v)662 static bool printfunc_json_cb(void *user, const char *k, const char *v) {
663 printFunctionType ((RCore *)user, k);
664 return true;
665 }
666
stdiffunc(void * p,const char * k,const char * v)667 static bool stdiffunc(void *p, const char *k, const char *v) {
668 return !strncmp (v, "func", strlen ("func") + 1);
669 }
670
stdifunion(void * p,const char * k,const char * v)671 static bool stdifunion(void *p, const char *k, const char *v) {
672 return !strncmp (v, "union", strlen ("union") + 1);
673 }
674
sdbdeletelink(void * p,const char * k,const char * v)675 static bool sdbdeletelink(void *p, const char *k, const char *v) {
676 RCore *core = (RCore *)p;
677 if (!strncmp (k, "link.", strlen ("link."))) {
678 r_type_del (core->anal->sdb_types, k);
679 }
680 return true;
681 }
682
stdiflink(void * p,const char * k,const char * v)683 static bool stdiflink(void *p, const char *k, const char *v) {
684 return !strncmp (k, "link.", strlen ("link."));
685 }
686
print_link_cb(void * p,const char * k,const char * v)687 static bool print_link_cb(void *p, const char *k, const char *v) {
688 r_cons_printf ("0x%s = %s\n", k + strlen ("link."), v);
689 return true;
690 }
691
692 //TODO PJ
print_link_json_cb(void * p,const char * k,const char * v)693 static bool print_link_json_cb(void *p, const char *k, const char *v) {
694 r_cons_printf ("{\"0x%s\":\"%s\"}", k + strlen ("link."), v);
695 return true;
696 }
697
print_link_r_cb(void * p,const char * k,const char * v)698 static bool print_link_r_cb(void *p, const char *k, const char *v) {
699 r_cons_printf ("tl %s = 0x%s\n", v, k + strlen ("link."));
700 return true;
701 }
702
print_link_readable_cb(void * p,const char * k,const char * v)703 static bool print_link_readable_cb(void *p, const char *k, const char *v) {
704 RCore *core = (RCore *)p;
705 char *fmt = r_type_format (core->anal->sdb_types, v);
706 if (!fmt) {
707 eprintf ("Can't fint type %s", v);
708 return 1;
709 }
710 r_cons_printf ("(%s)\n", v);
711 r_core_cmdf (core, "pf %s @ 0x%s\n", fmt, k + strlen ("link."));
712 return true;
713 }
714
715 //TODO PJ
print_link_readable_json_cb(void * p,const char * k,const char * v)716 static bool print_link_readable_json_cb(void *p, const char *k, const char *v) {
717 RCore *core = (RCore *)p;
718 char *fmt = r_type_format (core->anal->sdb_types, v);
719 if (!fmt) {
720 eprintf ("Can't fint type %s", v);
721 return true;
722 }
723 r_cons_printf ("{\"%s\":", v);
724 r_core_cmdf (core, "pfj %s @ 0x%s\n", fmt, k + strlen ("link."));
725 r_cons_printf ("}");
726 return true;
727 }
728
stdiftype(void * p,const char * k,const char * v)729 static bool stdiftype(void *p, const char *k, const char *v) {
730 return !strncmp (v, "type", strlen ("type") + 1);
731 }
732
print_typelist_r_cb(void * p,const char * k,const char * v)733 static bool print_typelist_r_cb(void *p, const char *k, const char *v) {
734 r_cons_printf ("tk %s=%s\n", k, v);
735 return true;
736 }
737
print_typelist_json_cb(void * p,const char * k,const char * v)738 static bool print_typelist_json_cb(void *p, const char *k, const char *v) {
739 RCore *core = (RCore *)p;
740 PJ *pj = pj_new ();
741 pj_o (pj);
742 Sdb *sdb = core->anal->sdb_types;
743 char *sizecmd = r_str_newf ("type.%s.size", k);
744 char *size_s = sdb_querys (sdb, NULL, -1, sizecmd);
745 char *formatcmd = r_str_newf ("type.%s", k);
746 char *format_s = sdb_querys (sdb, NULL, -1, formatcmd);
747 r_str_trim (format_s);
748 pj_ks (pj, "type", k);
749 pj_ki (pj, "size", size_s ? atoi (size_s) : -1);
750 pj_ks (pj, "format", format_s);
751 pj_end (pj);
752 r_cons_printf ("%s", pj_string (pj));
753 pj_free (pj);
754 free (size_s);
755 free (format_s);
756 free (sizecmd);
757 free (formatcmd);
758 return true;
759 }
760
print_keys(Sdb * TDB,RCore * core,SdbForeachCallback filter,SdbForeachCallback printfn_cb,bool json)761 static void print_keys(Sdb *TDB, RCore *core, SdbForeachCallback filter, SdbForeachCallback printfn_cb, bool json) {
762 SdbList *l = sdb_foreach_list_filter (TDB, filter, true);
763 SdbListIter *it;
764 SdbKv *kv;
765 const char *comma = "";
766
767 if (json) {
768 r_cons_printf ("[");
769 }
770 ls_foreach (l, it, kv) {
771 const char *k = sdbkv_key (kv);
772 if (!k || !*k) {
773 continue;
774 }
775 if (json) {
776 r_cons_printf ("%s", comma);
777 comma = ",";
778 }
779 printfn_cb (core, sdbkv_key (kv), sdbkv_value (kv));
780 }
781 if (json) {
782 r_cons_printf ("]\n");
783 }
784 ls_free (l);
785 }
786
typesList(RCore * core,int mode)787 static void typesList(RCore *core, int mode) {
788 switch (mode) {
789 case 1:
790 case '*':
791 print_keys (core->anal->sdb_types, core, NULL, print_typelist_r_cb, false);
792 break;
793 case 'j':
794 print_keys (core->anal->sdb_types, core, stdiftype, print_typelist_json_cb, true);
795 break;
796 default:
797 print_keys (core->anal->sdb_types, core, stdiftype, printkey_cb, false);
798 break;
799 }
800 }
801
set_offset_hint(RCore * core,RAnalOp * op,const char * type,ut64 laddr,ut64 at,int offimm)802 static void set_offset_hint(RCore *core, RAnalOp *op, const char *type, ut64 laddr, ut64 at, int offimm) {
803 char *res = r_type_get_struct_memb (core->anal->sdb_types, type, offimm);
804 const char *cmt = ((offimm == 0) && res)? res: type;
805 if (offimm > 0) {
806 // set hint only if link is present
807 char* query = sdb_fmt ("link.%08"PFMT64x, laddr);
808 if (res && sdb_const_get (core->anal->sdb_types, query, 0)) {
809 r_anal_hint_set_offset (core->anal, at, res);
810 }
811 } else if (cmt && r_anal_op_ismemref (op->type)) {
812 r_meta_set_string (core->anal, R_META_TYPE_VARTYPE, at, cmt);
813 }
814 }
815
r_core_get_stacksz(RCore * core,ut64 from,ut64 to)816 R_API int r_core_get_stacksz(RCore *core, ut64 from, ut64 to) {
817 int stack = 0, maxstack = 0;
818 ut64 at = from;
819
820 if (from >= to) {
821 return 0;
822 }
823 const int mininstrsz = r_anal_archinfo (core->anal, R_ANAL_ARCHINFO_MIN_OP_SIZE);
824 const int minopcode = R_MAX (1, mininstrsz);
825 while (at < to) {
826 RAnalOp *op = r_core_anal_op (core, at, R_ANAL_OP_MASK_BASIC);
827 if (!op || op->size <= 0) {
828 at += minopcode;
829 continue;
830 }
831 if ((op->stackop == R_ANAL_STACK_INC) && R_ABS (op->stackptr) < 8096) {
832 stack += op->stackptr;
833 if (stack > maxstack) {
834 maxstack = stack;
835 }
836 }
837 at += op->size;
838 r_anal_op_free (op);
839 }
840 return maxstack;
841 }
842
set_retval(RCore * core,ut64 at)843 static void set_retval(RCore *core, ut64 at) {
844 RAnal *anal = core->anal;
845 RAnalHint *hint = r_anal_hint_get (anal, at);
846 RAnalFunction *fcn = r_anal_get_fcn_in (anal, at, 0);
847
848 if (!hint || !fcn || !fcn->name) {
849 goto beach;
850 }
851 if (hint->ret == UT64_MAX) {
852 goto beach;
853 }
854 const char *cc = r_anal_cc_func (core->anal, fcn->name);
855 const char *regname = r_anal_cc_ret (anal, cc);
856 if (regname) {
857 RRegItem *reg = r_reg_get (anal->reg, regname, -1);
858 if (reg) {
859 r_reg_set_value (anal->reg, reg, hint->ret);
860 }
861 }
862 beach:
863 r_anal_hint_free (hint);
864 return;
865 }
866
r_core_link_stroff(RCore * core,RAnalFunction * fcn)867 R_API void r_core_link_stroff(RCore *core, RAnalFunction *fcn) {
868 RAnalBlock *bb;
869 RListIter *it;
870 RAnalOp aop = {0};
871 bool ioCache = r_config_get_i (core->config, "io.cache");
872 bool stack_set = false;
873 bool resolved = false;
874 const char *varpfx;
875 int dbg_follow = r_config_get_i (core->config, "dbg.follow");
876 Sdb *TDB = core->anal->sdb_types;
877 RAnalEsil *esil;
878 int iotrap = r_config_get_i (core->config, "esil.iotrap");
879 int stacksize = r_config_get_i (core->config, "esil.stack.depth");
880 unsigned int addrsize = r_config_get_i (core->config, "esil.addr.size");
881 const char *pc_name = r_reg_get_name (core->anal->reg, R_REG_NAME_PC);
882 const char *sp_name = r_reg_get_name (core->anal->reg, R_REG_NAME_SP);
883 RRegItem *pc = r_reg_get (core->anal->reg, pc_name, -1);
884
885 if (!fcn) {
886 return;
887 }
888 if (!(esil = r_anal_esil_new (stacksize, iotrap, addrsize))) {
889 return;
890 }
891 r_anal_esil_setup (esil, core->anal, 0, 0, 0);
892 int i, ret, bsize = R_MAX (64, core->blocksize);
893 const int mininstrsz = r_anal_archinfo (core->anal, R_ANAL_ARCHINFO_MIN_OP_SIZE);
894 const int maxinstrsz = r_anal_archinfo (core->anal, R_ANAL_ARCHINFO_MAX_OP_SIZE);
895 const int minopcode = R_MAX (1, mininstrsz);
896 ut8 *buf = malloc (bsize);
897 if (!buf) {
898 free (buf);
899 r_anal_esil_free (esil);
900 return;
901 }
902 r_reg_arena_push (core->anal->reg);
903 r_debug_reg_sync (core->dbg, R_REG_TYPE_ALL, true);
904 ut64 spval = r_reg_getv (esil->anal->reg, sp_name);
905 if (spval) {
906 // reset stack pointer to initial value
907 RRegItem *sp = r_reg_get (esil->anal->reg, sp_name, -1);
908 ut64 curpc = r_reg_getv (esil->anal->reg, pc_name);
909 int stacksz = r_core_get_stacksz (core, fcn->addr, curpc);
910 if (stacksz > 0) {
911 r_reg_arena_zero (esil->anal->reg); // clear prev reg values
912 r_reg_set_value (esil->anal->reg, sp, spval + stacksz);
913 }
914 } else {
915 // initialize stack
916 r_core_cmd0 (core, "aeim");
917 stack_set = true;
918 }
919 r_config_set_i (core->config, "io.cache", 1);
920 r_config_set_i (core->config, "dbg.follow", 0);
921 ut64 oldoff = core->offset;
922 r_cons_break_push (NULL, NULL);
923 // TODO: The algorithm can be more accurate if blocks are followed by their jmp/fail, not just by address
924 r_list_sort (fcn->bbs, bb_cmpaddr);
925 r_list_foreach (fcn->bbs, it, bb) {
926 ut64 at = bb->addr;
927 ut64 to = bb->addr + bb->size;
928 r_reg_set_value (esil->anal->reg, pc, at);
929 for (i = 0; at < to; i++) {
930 if (r_cons_is_breaked ()) {
931 goto beach;
932 }
933 if (at < bb->addr) {
934 break;
935 }
936 if (i >= (bsize - maxinstrsz)) {
937 i = 0;
938 }
939 if (!i) {
940 r_io_read_at (core->io, at, buf, bsize);
941 }
942 ret = r_anal_op (core->anal, &aop, at, buf + i, bsize - i, R_ANAL_OP_MASK_VAL);
943 if (ret <= 0) {
944 i += minopcode;
945 at += minopcode;
946 r_anal_op_fini (&aop);
947 continue;
948 }
949 i += ret - 1;
950 at += ret;
951 int index = 0;
952 if (aop.ireg) {
953 index = r_reg_getv (esil->anal->reg, aop.ireg) * aop.scale;
954 }
955 int j, src_imm = -1, dst_imm = -1;
956 ut64 src_addr = UT64_MAX;
957 ut64 dst_addr = UT64_MAX;
958 for (j = 0; j < 3; j++) {
959 if (aop.src[j] && aop.src[j]->reg && aop.src[j]->reg->name) {
960 src_addr = r_reg_getv (esil->anal->reg, aop.src[j]->reg->name) + index;
961 src_imm = aop.src[j]->delta;
962 }
963 }
964 if (aop.dst && aop.dst->reg && aop.dst->reg->name) {
965 dst_addr = r_reg_getv (esil->anal->reg, aop.dst->reg->name) + index;
966 dst_imm = aop.dst->delta;
967 }
968 RAnalVar *var = r_anal_get_used_function_var (core->anal, aop.addr);
969 if (false) { // src_addr != UT64_MAX || dst_addr != UT64_MAX) {
970 // if (src_addr == UT64_MAX && dst_addr == UT64_MAX) {
971 r_anal_op_fini (&aop);
972 continue;
973 }
974 char *slink = r_type_link_at (TDB, src_addr);
975 char *vlink = r_type_link_at (TDB, src_addr + src_imm);
976 char *dlink = r_type_link_at (TDB, dst_addr);
977 //TODO: Handle register based arg for struct offset propgation
978 if (vlink && var && var->kind != 'r') {
979 if (r_type_kind (TDB, vlink) == R_TYPE_UNION) {
980 varpfx = "union";
981 } else {
982 varpfx = "struct";
983 }
984 // if a var addr matches with struct , change it's type and name
985 // var int local_e0h --> var struct foo
986 if (strcmp (var->name , vlink) && !resolved) {
987 resolved = true;
988 r_anal_var_set_type (var, varpfx);
989 r_anal_var_rename (var, vlink, false);
990 }
991 } else if (slink) {
992 set_offset_hint (core, &aop, slink, src_addr, at - ret, src_imm);
993 } else if (dlink) {
994 set_offset_hint (core, &aop, dlink, dst_addr, at - ret, dst_imm);
995 }
996 if (r_anal_op_nonlinear (aop.type)) {
997 r_reg_set_value (esil->anal->reg, pc, at);
998 set_retval (core, at - ret);
999 } else {
1000 r_core_esil_step (core, UT64_MAX, NULL, NULL, false);
1001 }
1002 free (dlink);
1003 free (vlink);
1004 free (slink);
1005 r_anal_op_fini (&aop);
1006 }
1007 }
1008 beach:
1009 r_core_cmd0 (core, "wc-*"); // drop cache writes
1010 r_config_set_i (core->config, "io.cache", ioCache);
1011 r_config_set_i (core->config, "dbg.follow", dbg_follow);
1012 if (stack_set) {
1013 r_core_cmd0 (core, "aeim-");
1014 }
1015 r_core_seek (core, oldoff, true);
1016 r_anal_esil_free (esil);
1017 r_reg_arena_pop (core->anal->reg);
1018 r_core_cmd0 (core, ".ar*");
1019 r_cons_break_pop ();
1020 free (buf);
1021 }
1022
cmd_type(void * data,const char * input)1023 static int cmd_type(void *data, const char *input) {
1024 RCore *core = (RCore *)data;
1025 Sdb *TDB = core->anal->sdb_types;
1026 char *res;
1027 TDB_ = TDB; // HACK
1028
1029 switch (input[0]) {
1030 case 'n': // "tn"
1031 cmd_type_noreturn (core, input + 1);
1032 break;
1033 // t [typename] - show given type in C syntax
1034 case 'u': { // "tu"
1035 switch (input[1]) {
1036 case '?':
1037 r_core_cmd_help (core, help_msg_tu);
1038 break;
1039 case '*':
1040 if (input[2] == ' ') {
1041 showFormat (core, r_str_trim_head_ro (input + 2), 1);
1042 } else {
1043 SdbList *l = sdb_foreach_list_filter (TDB, stdifunion, true);
1044 SdbListIter *it;
1045 SdbKv *kv;
1046 ls_foreach (l, it, kv) {
1047 showFormat (core, sdbkv_key (kv), 1);
1048 }
1049 ls_free (l);
1050 }
1051 break;
1052 case 'j': // "tuj"
1053 if (input[2]) {
1054 showFormat (core, r_str_trim_head_ro (input + 2), 'j');
1055 r_cons_newline ();
1056 } else {
1057 print_struct_union_list_json (TDB, stdifunion);
1058 }
1059 break;
1060 case 'c':
1061 print_struct_union_in_c_format (TDB, stdifunion, r_str_trim_head_ro (input + 2), true);
1062 break;
1063 case 'd':
1064 print_struct_union_in_c_format (TDB, stdifunion, r_str_trim_head_ro (input + 2), false);
1065 break;
1066 case ' ':
1067 showFormat (core, r_str_trim_head_ro (input + 1), 0);
1068 break;
1069 case 0:
1070 print_keys (TDB, core, stdifunion, printkey_cb, false);
1071 break;
1072 }
1073 break;
1074 }
1075 case 'k': // "tk"
1076 res = (input[1] == ' ')
1077 ? sdb_querys (TDB, NULL, -1, input + 2)
1078 : sdb_querys (TDB, NULL, -1, "*");
1079 if (res) {
1080 r_cons_print (res);
1081 free (res);
1082 }
1083 break;
1084 case 'c': // "tc"
1085 switch (input[1]) {
1086 case 'c': // "tcc" -- calling conventions
1087 cmd_tcc (core, input + 2);
1088 break;
1089 case '?': //"tc?"
1090 r_core_cmd_help (core, help_msg_tc);
1091 break;
1092 case ' ': { // "tcc "
1093 const char *type = r_str_trim_head_ro (input + 1);
1094 const char *name = type ? strchr (type, '.') : NULL;
1095 if (name && type) {
1096 name++; // skip the '.'
1097 if (r_str_startswith (type, "struct")) {
1098 r_core_cmdf (core, "tsc %s", name);
1099 } else if (r_str_startswith (type, "union")) {
1100 r_core_cmdf (core, "tuc %s", name);
1101 } else if (r_str_startswith (type, "enum")) {
1102 r_core_cmdf (core, "tec %s", name);
1103 } else if (r_str_startswith (type, "typedef")) {
1104 r_core_cmdf (core, "ttc %s", name);
1105 } else if (r_str_startswith (type, "func")) {
1106 r_core_cmdf (core, "tfc %s", name);
1107 } else {
1108 eprintf ("unk\n");
1109 }
1110 }
1111 break;
1112 }
1113 case '*': // "tc*"
1114 r_core_cmd0 (core, "ts*");
1115 break;
1116 case 0: // "tc"
1117 r_core_cmd0 (core, "tfc;tuc;tsc;ttc;tec");
1118 break;
1119 case 'd': // "tcd"
1120 r_core_cmd0 (core, "tud;tsd;ttc;ted");
1121 break;
1122 default:
1123 r_core_cmd_help (core, help_msg_tc);
1124 break;
1125 }
1126 break;
1127 case 's': { // "ts"
1128 switch (input[1]) {
1129 case '?':
1130 r_core_cmd_help (core, help_msg_ts);
1131 break;
1132 case '*':
1133 if (input[2] == ' ') {
1134 showFormat (core, r_str_trim_head_ro (input + 2), 1);
1135 } else {
1136 SdbList *l = sdb_foreach_list_filter (TDB, stdifstruct, true);
1137 SdbListIter *it;
1138 SdbKv *kv;
1139
1140 ls_foreach (l, it, kv) {
1141 showFormat (core, sdbkv_key (kv), 1);
1142 }
1143 ls_free (l);
1144 }
1145 break;
1146 case ' ':
1147 showFormat (core, r_str_trim_head_ro (input + 1), 0);
1148 break;
1149 case 's':
1150 if (input[2] == ' ') {
1151 r_cons_printf ("%" PFMT64u "\n", (r_type_get_bitsize (TDB, input + 3) / 8));
1152 } else {
1153 r_core_cmd_help (core, help_msg_ts);
1154 }
1155 break;
1156 case 0:
1157 print_keys (TDB, core, stdifstruct, printkey_cb, false);
1158 break;
1159 case 'c': // "tsc"
1160 print_struct_union_in_c_format (TDB, stdifstruct, r_str_trim_head_ro (input + 2), true);
1161 break;
1162 case 'd': // "tsd"
1163 print_struct_union_in_c_format (TDB, stdifstruct, r_str_trim_head_ro (input + 2), false);
1164 break;
1165 case 'j': // "tsj"
1166 // TODO: current output is a bit poor, will be good to improve
1167 if (input[2]) {
1168 showFormat (core, r_str_trim_head_ro (input + 2), 'j');
1169 r_cons_newline ();
1170 } else {
1171 print_struct_union_list_json (TDB, stdifstruct);
1172 }
1173 break;
1174 } // end of switch (input[1])
1175 break;
1176 }
1177 case 'e': { // "te"
1178 char *res = NULL, *temp = strchr (input, ' ');
1179 Sdb *TDB = core->anal->sdb_types;
1180 char *name = temp ? strdup (temp + 1): NULL;
1181 char *member_name = name ? strchr (name, ' '): NULL;
1182
1183 if (member_name) {
1184 *member_name++ = 0;
1185 }
1186 if (name && (r_type_kind (TDB, name) != R_TYPE_ENUM)) {
1187 eprintf ("%s is not an enum\n", name);
1188 free (name);
1189 break;
1190 }
1191 switch (input[1]) {
1192 case '?':
1193 r_core_cmd_help (core, help_msg_te);
1194 break;
1195 case 'j': // "tej"
1196 if (input[2] == 0) { // "tej"
1197 char *name = NULL;
1198 SdbKv *kv;
1199 SdbListIter *iter;
1200 SdbList *l = sdb_foreach_list (TDB, true);
1201 PJ *pj = pj_new ();
1202 pj_o (pj);
1203 ls_foreach (l, iter, kv) {
1204 if (!strcmp (sdbkv_value (kv), "enum")) {
1205 if (!name || strcmp (sdbkv_value (kv), name)) {
1206 free (name);
1207 name = strdup (sdbkv_key (kv));
1208 pj_k (pj, name);
1209 {
1210 RList *list = r_type_get_enum (TDB, name);
1211 if (list && !r_list_empty (list)) {
1212 pj_o (pj);
1213 RListIter *iter;
1214 RTypeEnum *member;
1215 r_list_foreach (list, iter, member) {
1216 pj_kn (pj, member->name, r_num_math (NULL, member->val));
1217 }
1218 pj_end (pj);
1219 }
1220 r_list_free (list);
1221 }
1222 }
1223 }
1224 }
1225 pj_end (pj);
1226 r_cons_printf ("%s\n", pj_string (pj));
1227 pj_free (pj);
1228 free (name);
1229 ls_free (l);
1230 } else { // "tej ENUM"
1231 RListIter *iter;
1232 PJ *pj = pj_new ();
1233 RTypeEnum *member;
1234 pj_o (pj);
1235 if (member_name) {
1236 res = r_type_enum_member (TDB, name, NULL, r_num_math (core->num, member_name));
1237 // NEVER REACHED
1238 } else {
1239 RList *list = r_type_get_enum (TDB, name);
1240 if (list && !r_list_empty (list)) {
1241 pj_ks (pj, "name", name);
1242 pj_k (pj, "values");
1243 pj_o (pj);
1244 r_list_foreach (list, iter, member) {
1245 pj_kn (pj, member->name, r_num_math (NULL, member->val));
1246 }
1247 pj_end (pj);
1248 pj_end (pj);
1249 }
1250 r_cons_printf ("%s\n", pj_string (pj));
1251 pj_free (pj);
1252 r_list_free (list);
1253 }
1254 }
1255 break;
1256 case 'b': // "teb"
1257 res = r_type_enum_member (TDB, name, member_name, 0);
1258 break;
1259 case 'c': // "tec"
1260 print_enum_in_c_format(TDB, r_str_trim_head_ro (input + 2), true);
1261 break;
1262 case 'd':
1263 print_enum_in_c_format(TDB, r_str_trim_head_ro (input + 2), false);
1264 break;
1265 case ' ':
1266 if (member_name) {
1267 res = r_type_enum_member (TDB, name, NULL, r_num_math (core->num, member_name));
1268 } else {
1269 RList *list = r_type_get_enum (TDB, name);
1270 RListIter *iter;
1271 RTypeEnum *member;
1272 r_list_foreach (list, iter, member) {
1273 r_cons_printf ("%s = %s\n", member->name, member->val);
1274 }
1275 r_list_free (list);
1276 }
1277 break;
1278 case '\0': {
1279 char *name = NULL;
1280 SdbKv *kv;
1281 SdbListIter *iter;
1282 SdbList *l = sdb_foreach_list (TDB, true);
1283 ls_foreach (l, iter, kv) {
1284 if (!strcmp (sdbkv_value (kv), "enum")) {
1285 if (!name || strcmp (sdbkv_value (kv), name)) {
1286 free (name);
1287 name = strdup (sdbkv_key (kv));
1288 r_cons_println (name);
1289 }
1290 }
1291 }
1292 free (name);
1293 ls_free (l);
1294 break;
1295 }
1296 } // end of switch (input[1])
1297 free (name);
1298 if (res) {
1299 r_cons_println (res);
1300 } else if (member_name) {
1301 eprintf ("Invalid enum member\n");
1302 }
1303 break;
1304 }
1305 case ' ':
1306 showFormat (core, input + 1, 0);
1307 break;
1308 // t* - list all types in 'pf' syntax
1309 case 'j': // "tj"
1310 case '*': // "t*"
1311 case 0: // "t"
1312 typesList (core, input[0]);
1313 break;
1314 case 'o': // "to"
1315 if (input[1] == '?') {
1316 r_core_cmd_help (core, help_msg_to);
1317 } else if (!r_sandbox_enable (0)) {
1318 if (input[1] == ' ') {
1319 const char *dir = r_config_get (core->config, "dir.types");
1320 const char *filename = input + 2;
1321 char *homefile = NULL;
1322 if (*filename == '~') {
1323 if (filename[1] && filename[2]) {
1324 homefile = r_str_home (filename + 2);
1325 filename = homefile;
1326 }
1327 }
1328 if (!strcmp (filename, "-")) {
1329 char *tmp = r_core_editor (core, "*.h", "");
1330 if (tmp) {
1331 char *error_msg = NULL;
1332 char *out = r_parse_c_string (core->anal, tmp, &error_msg);
1333 if (out) {
1334 // r_cons_strcat (out);
1335 r_anal_save_parsed_type (core->anal, out);
1336 free (out);
1337 }
1338 if (error_msg) {
1339 fprintf (stderr, "%s", error_msg);
1340 free (error_msg);
1341 }
1342 free (tmp);
1343 }
1344 } else {
1345 char *error_msg = NULL;
1346 char *out = r_parse_c_file (core->anal, filename, dir, &error_msg);
1347 if (out) {
1348 //r_cons_strcat (out);
1349 r_anal_save_parsed_type (core->anal, out);
1350 free (out);
1351 }
1352 if (error_msg) {
1353 fprintf (stderr, "%s", error_msg);
1354 free (error_msg);
1355 }
1356 }
1357 free (homefile);
1358 } else if (input[1] == 'u') {
1359 // "tou" "touch"
1360 char *arg = strchr (input, ' ');
1361 if (arg) {
1362 r_file_touch (arg + 1);
1363 } else {
1364 eprintf ("Usage: touch [filename]");
1365 }
1366 } else if (input[1] == 's') {
1367 const char *dbpath = input + 3;
1368 if (r_file_exists (dbpath)) {
1369 Sdb *db_tmp = sdb_new (0, dbpath, 0);
1370 sdb_merge (TDB, db_tmp);
1371 sdb_close (db_tmp);
1372 sdb_free (db_tmp);
1373 }
1374 } else if (input[1] == 'e') { // "toe"
1375 char *str = r_core_cmd_strf (core , "tc %s", input + 2);
1376 char *tmp = r_core_editor (core, "*.h", str);
1377 if (tmp) {
1378 char *error_msg = NULL;
1379 char *out = r_parse_c_string (core->anal, tmp, &error_msg);
1380 if (out) {
1381 // remove previous types and save new edited types
1382 sdb_reset (TDB);
1383 r_parse_c_reset (core->parser);
1384 r_anal_save_parsed_type (core->anal, out);
1385 free (out);
1386 }
1387 if (error_msg) {
1388 eprintf ("%s\n", error_msg);
1389 free (error_msg);
1390 }
1391 free (tmp);
1392 }
1393 free (str);
1394 }
1395 } else {
1396 eprintf ("Sandbox: system call disabled\n");
1397 }
1398 break;
1399 // td - parse string with cparse engine and load types from it
1400 case 'd': // "td"
1401 if (input[1] == '?') {
1402 // TODO #7967 help refactor: move to detail
1403 r_core_cmd_help (core, help_msg_td);
1404 r_cons_printf ("Note: The td command should be put between double quotes\n"
1405 "Example: \"td struct foo {int bar;int cow;};\""
1406 "\nt");
1407
1408 } else if (input[1] == ' ') {
1409 char *tmp = r_str_newf ("%s;", input + 2);
1410 if (!tmp) {
1411 break;
1412 }
1413 char *error_msg = NULL;
1414 char *out = r_parse_c_string (core->anal, tmp, &error_msg);
1415 free (tmp);
1416 if (out) {
1417 r_anal_save_parsed_type (core->anal, out);
1418 free (out);
1419 }
1420 if (error_msg) {
1421 eprintf ("%s", error_msg);
1422 free (error_msg);
1423 }
1424 } else {
1425 eprintf ("Invalid use of td. See td? for help\n");
1426 }
1427 break;
1428 case 'x': {
1429 char *type, *type2;
1430 RListIter *iter, *iter2;
1431 RAnalFunction *fcn;
1432 switch (input[1]) {
1433 case '.': // "tx." type xrefs
1434 case 'f': // "txf" type xrefs
1435 {
1436 ut64 addr = core->offset;
1437 if (input[2] == ' ') {
1438 addr = r_num_math (core->num, input + 2);
1439 }
1440 fcn = r_anal_get_function_at (core->anal, addr);
1441 if (fcn) {
1442 RList *uniq = r_anal_types_from_fcn (core->anal, fcn);
1443 r_list_foreach (uniq , iter , type) {
1444 r_cons_println (type);
1445 }
1446 r_list_free (uniq);
1447 } else {
1448 eprintf ("cannot find function at 0x%08"PFMT64x"\n", addr);
1449 }
1450 }
1451 break;
1452 case 0: // "tx"
1453 r_list_foreach (core->anal->fcns, iter, fcn) {
1454 RList *uniq = r_anal_types_from_fcn (core->anal, fcn);
1455 if (r_list_length (uniq)) {
1456 r_cons_printf ("%s: ", fcn->name);
1457 }
1458 r_list_foreach (uniq , iter2, type) {
1459 r_cons_printf ("%s%s", type, iter2->n ? ",":"\n");
1460 }
1461 }
1462 break;
1463 case 'g': // "txg"
1464 {
1465 r_list_foreach (core->anal->fcns, iter, fcn) {
1466 RList *uniq = r_anal_types_from_fcn (core->anal, fcn);
1467 if (r_list_length (uniq)) {
1468 r_cons_printf ("agn %s\n", fcn->name);
1469 }
1470 r_list_foreach (uniq , iter2, type) {
1471 char *myType = strdup (type);
1472 r_str_replace_ch (myType, ' ', '_', true);
1473 r_cons_printf ("agn %s\n", myType);
1474 r_cons_printf ("age %s %s\n", myType, fcn->name);
1475 free (myType);
1476 }
1477 }
1478 }
1479 break;
1480 case 'l': // "txl"
1481 {
1482 RList *uniqList = r_list_newf (free);
1483 r_list_foreach (core->anal->fcns, iter, fcn) {
1484 RList *uniq = r_anal_types_from_fcn (core->anal, fcn);
1485 r_list_foreach (uniq , iter2, type) {
1486 if (!r_list_find (uniqList, type, (RListComparator)strcmp)) {
1487 r_list_push (uniqList, strdup (type));
1488 }
1489 }
1490 }
1491 r_list_sort (uniqList, (RListComparator)strcmp);
1492 r_list_foreach (uniqList, iter, type) {
1493 r_cons_printf ("%s\n", type);
1494 }
1495 r_list_free (uniqList);
1496 }
1497 break;
1498 case 't':
1499 case ' ': // "tx " -- show which function use given type
1500 type = (char *)r_str_trim_head_ro (input + 2);
1501 r_list_foreach (core->anal->fcns, iter, fcn) {
1502 RList *uniq = r_anal_types_from_fcn (core->anal, fcn);
1503 r_list_foreach (uniq , iter2, type2) {
1504 if (!strcmp (type2, type)) {
1505 r_cons_printf ("%s\n", fcn->name);
1506 break;
1507 }
1508 }
1509 }
1510 break;
1511 default:
1512 eprintf ("Usage: tx[flg] [...]\n");
1513 eprintf (" txf | tx. list all types used in this function\n");
1514 eprintf (" txf 0xaddr list all types used in function at 0xaddr\n");
1515 eprintf (" txl list all types used by any function\n");
1516 eprintf (" txg render the type xrefs graph (usage .txg;aggv)\n");
1517 eprintf (" tx int32_t list functions names using this type\n");
1518 eprintf (" txt int32_t same as 'tx type'\n");
1519 eprintf (" tx list functions and the types they use\n");
1520 break;
1521 }
1522 break;
1523 }
1524 // ta: moved to anal hints (aht)- just for tail, at the moment
1525 case 'a': // "ta"
1526 switch (input[1]) {
1527 case 'i': { // "tai"
1528 if (input[2] == 'l') {
1529 cmd_tail (core, input);
1530 } else {
1531 eprintf ("Usage: tail [number] [file]\n");
1532 }
1533 break;
1534 }
1535 default:
1536 eprintf ("[WARNING] \"ta\" is deprecated. Use \"aht\" instead.\n");
1537 }
1538 break;
1539 // tl - link a type to an address
1540 case 'l': // "tl"
1541 switch (input[1]) {
1542 case '?':
1543 r_core_cmd_help (core, help_msg_tl);
1544 break;
1545 case ' ': {
1546 char *type = strdup (input + 2);
1547 char *ptr = strchr (type, '=');
1548 ut64 addr = core->offset;
1549
1550 if (ptr) {
1551 *ptr++ = 0;
1552 r_str_trim (ptr);
1553 if (ptr && *ptr) {
1554 addr = r_num_math (core->num, ptr);
1555 } else {
1556 eprintf ("tl: Address is unvalid\n");
1557 free (type);
1558 break;
1559 }
1560 }
1561 r_str_trim (type);
1562 char *tmp = sdb_get (TDB, type, 0);
1563 if (tmp && *tmp) {
1564 r_type_set_link (TDB, type, addr);
1565 RList *fcns = r_anal_get_functions_in (core->anal, core->offset);
1566 if (r_list_length (fcns) > 1) {
1567 eprintf ("Multiple functions found in here.\n");
1568 } else if (r_list_length (fcns) == 1) {
1569 RAnalFunction *fcn = r_list_first (fcns);
1570 r_core_link_stroff (core, fcn);
1571 } else {
1572 eprintf ("Cannot find any function here\n");
1573 }
1574 r_list_free (fcns);
1575 free (tmp);
1576 } else {
1577 eprintf ("unknown type %s\n", type);
1578 }
1579 free (type);
1580 break;
1581 }
1582 case 's': {
1583 char *ptr = r_str_trim_dup (input + 2);
1584 ut64 addr = r_num_math (NULL, ptr);
1585 const char *query = sdb_fmt ("link.%08" PFMT64x, addr);
1586 const char *link = sdb_const_get (TDB, query, 0);
1587 if (link) {
1588 print_link_readable_cb (core, query, link);
1589 }
1590 free (ptr);
1591 break;
1592 }
1593 case '-':
1594 switch (input[2]) {
1595 case '*':
1596 sdb_foreach (TDB, sdbdeletelink, core);
1597 break;
1598 case ' ': {
1599 const char *ptr = input + 3;
1600 ut64 addr = r_num_math (core->num, ptr);
1601 r_type_unlink (TDB, addr);
1602 break;
1603 }
1604 }
1605 break;
1606 case '*':
1607 print_keys (TDB, core, stdiflink, print_link_r_cb, false);
1608 break;
1609 case 'l':
1610 switch (input[2]) {
1611 case 'j':
1612 print_keys (TDB, core, stdiflink, print_link_readable_json_cb, true);
1613 break;
1614 default:
1615 print_keys (TDB, core, stdiflink, print_link_readable_cb, false);
1616 break;
1617 }
1618 break;
1619 case 'j':
1620 print_keys (TDB, core, stdiflink, print_link_json_cb, true);
1621 break;
1622 case '\0':
1623 print_keys (TDB, core, stdiflink, print_link_cb, false);
1624 break;
1625 }
1626 break;
1627 case 'p': // "tp"
1628 if (input[1] == '?') { // "tp?"
1629 r_core_cmd_help (core, help_msg_tp);
1630 } else if (input[1] == 'v') { // "tpv"
1631 const char *type_name = r_str_trim_head_ro (input + 2);
1632 char *fmt = r_type_format (TDB, type_name);
1633 if (fmt && *fmt) {
1634 ut64 val = core->offset;
1635 r_core_cmdf (core, "pf %s @v:0x%08" PFMT64x "\n", fmt, val);
1636 } else {
1637 eprintf ("Usage: tpv [type] @ [value]\n");
1638 }
1639 } else if (input[1] == ' ' || input[1] == 'x' || !input[1]) {
1640 char *tmp = strdup (input);
1641 char *type_begin = strchr (tmp, ' ');
1642 if (type_begin) {
1643 r_str_trim (type_begin);
1644 const char *type_end = r_str_rchr (type_begin, NULL, ' ');
1645 int type_len = (type_end)
1646 ? (int)(type_end - type_begin)
1647 : strlen (type_begin);
1648 char *type = strdup (type_begin);
1649 if (!type) {
1650 free (tmp);
1651 break;
1652 }
1653 snprintf (type, type_len + 1, "%s", type_begin);
1654 const char *arg = (type_end) ? type_end + 1 : NULL;
1655 char *fmt = r_type_format (TDB, type);
1656 if (!fmt) {
1657 eprintf ("Cannot find '%s' type\n", type);
1658 free (tmp);
1659 free (type);
1660 break;
1661 }
1662 if (input[1] == 'x' && arg) { // "tpx"
1663 r_core_cmdf (core, "pf %s @x:%s", fmt, arg);
1664 // eprintf ("pf %s @x:%s", fmt, arg);
1665 } else {
1666 ut64 addr = arg ? r_num_math (core->num, arg): core->offset;
1667 ut64 original_addr = addr;
1668 if (!addr && arg) {
1669 RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset, -1);
1670 if (fcn) {
1671 RAnalVar *var = r_anal_function_get_var_byname (fcn, arg);
1672 if (var) {
1673 addr = r_anal_var_addr (var);
1674 }
1675 }
1676 }
1677 if (addr != UT64_MAX) {
1678 r_core_cmdf (core, "pf %s @ 0x%08" PFMT64x, fmt, addr);
1679 } else if (original_addr == 0) {
1680 r_core_cmdf (core, "pf %s @ 0x%08" PFMT64x, fmt, original_addr);
1681 }
1682 }
1683 free (fmt);
1684 free (type);
1685 } else {
1686 eprintf ("Usage: tp?\n");
1687 }
1688 free (tmp);
1689 } else { // "tp"
1690 eprintf ("Usage: tp?\n");
1691 }
1692 break;
1693 case '-': // "t-"
1694 if (input[1] == '?') {
1695 r_core_cmd_help (core, help_msg_t_minus);
1696 } else if (input[1] == '*') {
1697 sdb_reset (TDB);
1698 r_parse_c_reset (core->parser);
1699 } else {
1700 const char *name = r_str_trim_head_ro (input + 1);
1701 if (*name) {
1702 r_anal_remove_parsed_type (core->anal, name);
1703 } else {
1704 eprintf ("Invalid use of t- . See t-? for help.\n");
1705 }
1706 }
1707 break;
1708 // tv - get/set type value linked to a given address
1709 case 'f': // "tf"
1710 switch (input[1]) {
1711 case 0: // "tf"
1712 print_keys (TDB, core, stdiffunc, printkey_cb, false);
1713 break;
1714 case 'c': // "tfc"
1715 if (input[2] == ' ') {
1716 printFunctionTypeC (core, input + 3);
1717 }
1718 break;
1719 case 'j': // "tfj"
1720 if (input[2] == ' ') {
1721 printFunctionType (core, input + 2);
1722 r_cons_newline ();
1723 } else {
1724 print_keys (TDB, core, stdiffunc, printfunc_json_cb, true);
1725 }
1726 break;
1727 case ' ': {
1728 char *res = sdb_querys (TDB, NULL, -1, sdb_fmt ("~~func.%s", input + 2));
1729 if (res) {
1730 r_cons_printf ("%s", res);
1731 free (res);
1732 }
1733 break;
1734 }
1735 default:
1736 r_core_cmd_help (core, help_msg_tf);
1737 break;
1738 }
1739 break;
1740 case 't': {
1741 if (!input[1] || input[1] == 'j') {
1742 PJ *pj = NULL;
1743 if (input[1] == 'j') {
1744 pj = pj_new ();
1745 pj_o (pj);
1746 }
1747 char *name = NULL;
1748 SdbKv *kv;
1749 SdbListIter *iter;
1750 SdbList *l = sdb_foreach_list (TDB, true);
1751 ls_foreach (l, iter, kv) {
1752 if (!strcmp (sdbkv_value (kv), "typedef")) {
1753 if (!name || strcmp (sdbkv_value (kv), name)) {
1754 free (name);
1755 name = strdup (sdbkv_key (kv));
1756 if (!input[1]) {
1757 r_cons_println (name);
1758 } else {
1759 const char *q = sdb_fmt ("typedef.%s", name);
1760 const char *res = sdb_const_get (TDB, q, 0);
1761 pj_ks (pj, name, res);
1762 }
1763 }
1764 }
1765 }
1766 if (input[1] == 'j') {
1767 pj_end (pj);
1768 }
1769 if (pj) {
1770 r_cons_printf ("%s\n", pj_string (pj));
1771 pj_free (pj);
1772 }
1773 free (name);
1774 ls_free (l);
1775 break;
1776 }
1777 if (input[1] == 'c') {
1778 char *name = NULL;
1779 SdbKv *kv;
1780 SdbListIter *iter;
1781 SdbList *l = sdb_foreach_list (TDB, true);
1782 const char *arg = r_str_trim_head_ro (input + 2);
1783 bool match = false;
1784 ls_foreach (l, iter, kv) {
1785 if (!strcmp (sdbkv_value (kv), "typedef")) {
1786 if (!name || strcmp (sdbkv_value (kv), name)) {
1787 free (name);
1788 name = strdup (sdbkv_key (kv));
1789 if (name && (arg && *arg)) {
1790 if (!strcmp (arg, name)) {
1791 match = true;
1792 } else {
1793 continue;
1794 }
1795 }
1796 const char *q = sdb_fmt ("typedef.%s", name);
1797 const char *res = sdb_const_get (TDB, q, 0);
1798 if (res) {
1799 r_cons_printf ("%s %s %s;\n", sdbkv_value (kv), res, name);
1800 }
1801 if (match) {
1802 break;
1803 }
1804 }
1805 }
1806 }
1807 free (name);
1808 ls_free (l);
1809 break;
1810 }
1811 if (input[1] == '?') {
1812 r_core_cmd_help (core, help_msg_tt);
1813 break;
1814 }
1815 char *s = strdup (input + 2);
1816 const char *istypedef;
1817 istypedef = sdb_const_get (TDB, s, 0);
1818 if (istypedef && !strncmp (istypedef, "typedef", 7)) {
1819 const char *q = sdb_fmt ("typedef.%s", s);
1820 const char *res = sdb_const_get (TDB, q, 0);
1821 if (res) {
1822 r_cons_println (res);
1823 }
1824 } else {
1825 eprintf ("This is not an typedef\n");
1826 }
1827 free (s);
1828 break;
1829 }
1830 case '?':
1831 show_help (core);
1832 break;
1833 }
1834 return true;
1835 }
1836