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