1 /* radare - LGPL - Copyright 2009-2021 - nibble, pancake */
2
3 #define INTERACTIVE_MAX_REP 1024
4
5 #include <r_core.h>
6 #include <r_anal.h>
7 #include <r_cons.h>
8 #include <r_cmd.h>
9 #include <stdint.h>
10 #include <sys/types.h>
11 #include <ctype.h>
12 #include <stdarg.h>
13 #include "cmd_helps.h"
14 #if __UNIX__
15 #include <sys/utsname.h>
16 #endif
17
18 #include <tree_sitter/api.h>
19 TSLanguage *tree_sitter_r2cmd ();
20
21 // NOTE: this should be in sync with SPECIAL_CHARACTERS in
22 // radare2-shell-parser grammar, except for ", ' and
23 // whitespaces, because we let cmd_substitution_arg create
24 // new arguments
25 static const char *SPECIAL_CHARS_REGULAR = "@;~$#|`\"'()<>";
26 static const char *SPECIAL_CHARS_PF = "@;~$#|`\"'<>";
27 static const char *SPECIAL_CHARS_DOUBLE_QUOTED = "\"";
28 static const char *SPECIAL_CHARS_SINGLE_QUOTED = "'";
29
cmd_descriptor(const char * cmd,const char * help[])30 static RCmdDescriptor *cmd_descriptor(const char *cmd, const char *help[]) {
31 RCmdDescriptor *d = R_NEW0 (RCmdDescriptor);
32 if (d) {
33 d->cmd = cmd;
34 d->help_msg = help;
35 }
36 return d;
37 }
38
39 #define DEFINE_CMD_DESCRIPTOR(core, cmd_) \
40 { \
41 RCmdDescriptor *d = cmd_descriptor (#cmd_, help_msg_##cmd_); \
42 if (d) { \
43 r_list_append ((core)->cmd_descriptors, d); \
44 } \
45 }
46
47 #define DEFINE_CMD_DESCRIPTOR_WITH_DETAIL(core, cmd_) \
48 { \
49 RCmdDescriptor *d = cmd_descriptor (#cmd_, help_msg##cmd_); \
50 if (d) { \
51 d->help_detail = help_detail_##cmd_; \
52 r_list_append ((core)->cmd_descriptors, d); \
53 } \
54 }
55
56 #define DEFINE_CMD_DESCRIPTOR_WITH_DETAIL2(core, cmd_) \
57 { \
58 RCmdDescriptor *d = cmd_descriptor (#cmd_, help_msg_##cmd_); \
59 if (d) { \
60 d->help_detail = help_detail_##cmd_; \
61 d->help_detail2 = help_detail2_##cmd_; \
62 r_list_append ((core)->cmd_descriptors, d); \
63 } \
64 }
65
66 #define DEFINE_CMD_DESCRIPTOR_SPECIAL(core, cmd_, named_cmd) \
67 { \
68 RCmdDescriptor *d = R_NEW0 (RCmdDescriptor); \
69 if (d) { \
70 d->cmd = #cmd_; \
71 d->help_msg = help_msg_##named_cmd; \
72 r_list_append ((core)->cmd_descriptors, d); \
73 } \
74 }
75
76 static int r_core_cmd_subst_i(RCore *core, char *cmd, char* colon, bool *tmpseek);
77
bb_cmpaddr(const void * _a,const void * _b)78 static int bb_cmpaddr(const void *_a, const void *_b) {
79 const RAnalBlock *a = _a, *b = _b;
80 return a->addr > b->addr ? 1 : (a->addr < b->addr ? -1 : 0);
81 }
82
83 static void cmd_debug_reg(RCore *core, const char *str);
84
85 #include "cmd_quit.c"
86 #include "cmd_hash.c"
87 #include "cmd_debug.c"
88 #include "cmd_log.c"
89 #include "cmd_flag.c"
90 #include "cmd_zign.c"
91 #include "cmd_project.c"
92 #include "cmd_write.c"
93 #include "cmd_cmp.c"
94 #include "cmd_eval.c"
95 #include "cmd_type.c"
96 #include "cmd_anal.c"
97 #include "cmd_open.c"
98 #include "cmd_meta.c"
99 #include "cmd_egg.c"
100 #include "cmd_info.c"
101 #include "cmd_macro.c"
102 #include "cmd_magic.c"
103 #include "cmd_mount.c"
104 #include "cmd_seek.c"
105 #include "cmd_search.c" // defines incDigitBuffer... used by cmd_print
106 #include "cmd_print.c"
107 #include "cmd_help.c"
108 #include "cmd_colon.c"
109
110 static const char *help_msg_dollar[] = {
111 "Usage:", "$alias[=cmd] [args...]", "Alias commands and strings (See ?$? for help on $variables)",
112 "$", "", "list all defined aliases",
113 "$*", "", "list all the aliases as r2 commands in base64",
114 "$**", "", "same as above, but using plain text",
115 "$", "foo:=123", "alias for 'f foo=123'",
116 "$", "foo-=4", "alias for 'f foo-=4'",
117 "$", "foo+=4", "alias for 'f foo+=4'",
118 "$", "foo", "alias for 's foo' (note that command aliases can override flag resolution)",
119 "$", "dis=base64:AAA==", "alias this base64 encoded text to be printed when $dis is called",
120 "$", "dis=$hello world", "alias this text to be printed when $dis is called",
121 "$", "dis=-", "open cfg.editor to set the new value for dis alias",
122 "$", "dis=af;pdf", "create command - analyze to show function",
123 "$", "test=#!pipe node /tmp/test.js", "create command - rlangpipe script",
124 "$", "dis=", "undefine alias",
125 "$", "dis", "execute the previously defined alias",
126 "$", "dis?", "show commands aliased by $dis",
127 "$", "dis?n", "show commands aliased by $dis, without a new line",
128 NULL
129 };
130
131 static const char *help_msg_star[] = {
132 "Usage:", "*<addr>[=[0x]value]", "Pointer read/write data/values",
133 "*", "entry0=cc", "write trap in entrypoint",
134 "*", "entry0+10=0x804800", "write value in delta address",
135 "*", "entry0", "read byte at given address",
136 "*", "/", "end multiline comment. (use '/*' to start mulitiline comment",
137 "TODO: last command should honor asm.bits", "", "",
138 NULL
139 };
140
141 static const char *cmd_table_help[] = {
142 "Usage:", ",[,.-/*jhr] [file]", "# load table data",
143 ",", "", "display table",
144 ", ", "[table-query]", "filter and print table. See ,? for more details",
145 ",.", " file.csv", "load table from CSV file (comma dot)",
146 ",,", "", "print table in csv format (comma comma)",
147 ",-", "", "reset table",
148 ",/", "?", "query/filter current table (non-destructive)",
149 ",*", ">$foo", "print table as r2 commands",
150 ",j", "", "print table in json format",
151 ",h", " xxd foo bar cow", "define header column names and types",
152 ",r", " 1 2 foo", "adds a row using the given format string",
153 NULL
154 };
155
156 static const char *help_msg_dot[] = {
157 "Usage:", ".[r2cmd] | [file] | [!command] | [(macro)]", "# define macro or interpret r2, r_lang,\n"
158 " cparse, d, es6, exe, go, js, lsp, pl, py, rb, sh, vala or zig file",
159 ".", "", "repeat last command backward",
160 ".", "r2cmd", "interpret the output of the command as r2 commands",
161 "..", " [file]", "run the output of the execution of a script as r2 commands",
162 "...", "", "repeat last command forward (same as \\n)",
163 ".:", "8080", "listen for commands on given tcp port",
164 ".--", "", "terminate tcp server for remote commands",
165 ".", " foo.r2", "interpret script",
166 ".-", "", "open cfg.editor and interpret tmp file",
167 ".*", " file ...", "same as #!pipe open cfg.editor and interpret tmp file",
168 ".!", "rabin -ri $FILE", "interpret output of command",
169 ".", "(foo 1 2 3)", "run macro 'foo' with args 1, 2, 3",
170 "./", " ELF", "interpret output of command /m ELF as r. commands",
171 NULL
172 };
173
174 static const char *help_msg_equal[] = {
175 "Usage:", " =[:!+-=ghH] [...]", " # connect with other instances of r2",
176 "\nremote commands:", "", "",
177 "=", "", "list all open connections",
178 "=<", "[fd] cmd", "send output of local command to remote fd", // XXX may not be a special char
179 "=", "[fd] cmd", "exec cmd at remote 'fd' (last open is default one)",
180 "=!", " cmd", "run command via r_io_system",
181 "=+", " [proto://]host:port", "connect to remote host:port (*rap://, raps://, tcp://, udp://, http://)",
182 "=-", "[fd]", "remove all hosts or host 'fd'",
183 "==", "[fd]", "open remote session with host 'fd', 'q' to quit",
184 "=!=", "", "disable remote cmd mode",
185 "!=!", "", "enable remote cmd mode",
186 "\nservers:","","",
187 ".:", "9000", "start the tcp server (echo x|nc ::1 9090 or curl ::1:9090/cmd/x)",
188 "=:", "port", "start the rap server (o rap://9999)",
189 "=g", "[?]", "start the gdbserver",
190 "=h", "[?]", "start the http webserver",
191 "=H", "[?]", "start the http webserver (and launch the web browser)",
192 "\nother:","","",
193 "=&", ":port", "start rap server in background (same as '&_=h')",
194 "=", ":host:port cmd", "run 'cmd' command on remote server",
195 "\nexamples:","","",
196 "=+", "tcp://localhost:9090/", "connect to: r2 -c.:9090 ./bin",
197 // "=+", "udp://localhost:9090/", "connect to: r2 -c.:9090 ./bin",
198 "=+", "rap://localhost:9090/", "connect to: r2 rap://:9090",
199 "=+", "http://localhost:9090/cmd/", "connect to: r2 -c'=h 9090' bin",
200 "o ", "rap://:9090/", "start the rap server on tcp port 9090",
201 NULL
202 };
203
204 static const char *help_msg_equalh[] = {
205 "Usage:", " =[hH] [...]", " # http server",
206 "http server:", "", "",
207 "=h", " port", "listen for http connections (r2 -qc=H /bin/ls)",
208 "=h-", "", "stop background webserver",
209 "=h--", "", "stop foreground webserver",
210 "=h*", "", "restart current webserver",
211 "=h&", " port", "start http server in background",
212 "=H", " port", "launch browser and listen for http",
213 "=H&", " port", "launch browser and listen for http in background",
214 NULL
215 };
216
217 static const char *help_msg_equalg[] = {
218 "Usage:", " =[g] [...]", " # gdb server",
219 "gdbserver:", "", "",
220 "=g", " port file [args]", "listen on 'port' debugging 'file' using gdbserver",
221 "=g!", " port file [args]", "same as above, but debug protocol messages (like gdbserver --remote-debug)",
222 NULL
223 };
224
225 static const char *help_msg_b[] = {
226 "Usage:", "b[f] [arg]\n", "Get/Set block size",
227 "b", " 33", "set block size to 33",
228 "b", " eip+4", "numeric argument can be an expression",
229 "b", "", "display current block size",
230 "b", "+3", "increase blocksize by 3",
231 "b", "-16", "decrease blocksize by 16",
232 "b*", "", "display current block size in r2 command",
233 "bf", " foo", "set block size to flag size",
234 "bj", "", "display block size information in JSON",
235 "bm", " 1M", "set max block size",
236 NULL
237 };
238
239 static const char *help_msg_k[] = {
240 "Usage:", "k[s] [key[=value]]", "Sdb Query",
241 "k", " anal/**", "list namespaces under anal",
242 "k", " anal/meta/*", "list kv from anal > meta namespaces",
243 "k", " anal/meta/meta.0x80404", "get value for meta.0x80404 key",
244 "k", " foo", "show value",
245 "k", " foo=bar", "set value",
246 "k", "", "list keys",
247 "kd", " [file.sdb] [ns]", "dump namespace to disk",
248 "kj", "", "List all namespaces and sdb databases in JSON format",
249 "ko", " [file.sdb] [ns]", "open file into namespace",
250 "ks", " [ns]", "enter the sdb query shell",
251 //"kl", " ha.sdb", "load keyvalue from ha.sdb",
252 //"ks", " ha.sdb", "save keyvalue to ha.sdb",
253 NULL,
254 };
255
256 static const char *help_msg_r[] = {
257 "Usage:", "r[+-][ size]", "Resize file",
258 "r", "", "display file size",
259 "rj", "", "display the file size in JSON format",
260 "r", " size", "expand or truncate file to given size",
261 "r-", "num", "remove num bytes, move following data down",
262 "r+", "num", "insert num bytes, move following data up",
263 "rb", "oldbase @ newbase", "rebase all flags, bin.info, breakpoints and analysis",
264 "rm" ," [file]", "remove file",
265 "rh" ,"", "show size in human format",
266 "r2" ," [file]", "launch r2 (same for rax2, rasm2, ...)",
267 "reset" ,"", "reset console settings (clear --hard)",
268 NULL
269 };
270
271 static const char *help_msg_u[] = {
272 "Usage:", "u", "uname or undo write/seek",
273 "u", "", "show system uname",
274 "uw", "", "alias for wc (requires: e io.cache=true)",
275 "us", "", "alias for s- (seek history)",
276 "uc", "[?]", "undo core commands (uc?, ucl, uc*, ..)",
277 "uniq", "", "filter rows to avoid duplicates",
278 "uname", "", "uname - show system information",
279 NULL
280 };
281
282 static const char *help_msg_uc[] = {
283 "Usage:", "uc [cmd] [revert-cmd]", "undo core commands",
284 "uc", "", "list all core undos",
285 "uc*", "", "list all core undos as r2 commands",
286 "uc-", "", "undo last action",
287 "uc.", "", "list all reverts in current",
288 NULL
289 };
290
291 static const char *help_msg_y[] = {
292 "Usage:", "y[ptxy] [len] [[@]addr]", " # See wd? for memcpy, same as 'yf'.",
293 "y!", "", "open cfg.editor to edit the clipboard",
294 "y", " 16 @ 0x200", "copy 16 bytes into clipboard from 0x200",
295 "y", " 16 0x200", "copy 16 bytes into clipboard from 0x200",
296 "y", " 16", "copy 16 bytes into clipboard",
297 "y", "", "show yank buffer information (origin len bytes)",
298 "y*", "", "print in r2 commands what's been yanked",
299 "yf", " 64 0x200", "copy file 64 bytes from 0x200 from file",
300 "yfa", " file copy", "copy all bytes from file (opens w/ io)",
301 "yfx", " 10203040", "yank from hexpairs (same as ywx)",
302 "yj", "", "print in JSON commands what's been yanked",
303 "yp", "", "print contents of clipboard",
304 "yq", "", "print contents of clipboard in hexpairs",
305 "ys", "", "print contents of clipboard as string",
306 "yt", " 64 0x200", "copy 64 bytes from current seek to 0x200",
307 "ytf", " file", "dump the clipboard to given file",
308 "yw", " hello world", "yank from string",
309 "ywx", " 10203040", "yank from hexpairs (same as yfx)",
310 "yx", "", "print contents of clipboard in hexadecimal",
311 "yy", " @ 0x3344", "paste contents of clipboard to 0x3344",
312 "yy", " 0x3344", "paste contents of clipboard to 0x3344",
313 "yy", "", "paste contents of clipboard at current seek",
314 "yz", " [len]", "copy nul-terminated string (up to blocksize) into clipboard",
315 NULL
316 };
317
318 static const char *help_msg_triple_exclamation[] = {
319 "Usage:", "!!![-*][cmd] [arg|$type...]", " # user-defined autocompletion for commands",
320 "!!!", "", "list all autocompletions",
321 "!!!?", "", "show this help",
322 "!!!", "-*", "remove all user-defined autocompletions",
323 "!!!", "-\\*", "remove autocompletions matching this glob expression",
324 "!!!", "-foo", "remove autocompletion named 'foo'",
325 "!!!", "foo", "add 'foo' for autocompletion",
326 "!!!", "bar $flag", "add 'bar' for autocompletion with $flag as argument",
327 "Types:", "", "",
328 NULL
329 };
330
331 static const char *help_msg_vertical_bar[] = {
332 "Usage:", "[cmd] | [program|H|T|.|]", "",
333 "", "[cmd] |?", "show this help",
334 "", "[cmd] |", "disable scr.html and scr.color",
335 "", "[cmd] |H", "enable scr.html, respect scr.color",
336 "", "[cmd] |T", "use scr.tts to speak out the stdout",
337 "", "[cmd] | [program]", "pipe output of command to program",
338 "", "[cmd] |.", "alias for .[cmd]",
339 NULL
340 };
341
342 static const char *help_msg_v[] = {
343 "Usage:", "v[*i]", "",
344 "v", "", "open visual panels",
345 "v", " test", "load saved layout with name test",
346 "v=", " test", "save current layout with name test",
347 "vi", " test", "open the file test in 'cfg.editor'",
348 NULL
349 };
350
r_core_cmd_help(const RCore * core,const char * help[])351 R_API void r_core_cmd_help(const RCore *core, const char *help[]) {
352 r_cons_cmd_help (help, core->print->flags & R_PRINT_FLAGS_COLOR);
353 }
354
355 struct duplicate_flag_t {
356 RList *ret;
357 const char *word;
358 };
359
duplicate_flag(RFlagItem * flag,void * u)360 static bool duplicate_flag(RFlagItem *flag, void *u) {
361 struct duplicate_flag_t *user = (struct duplicate_flag_t *)u;
362 /* filter per flag spaces */
363 if (r_str_glob (flag->name, user->word)) {
364 RFlagItem *cloned_item = r_flag_item_clone (flag);
365 if (!cloned_item) {
366 return false;
367 }
368 r_list_append (user->ret, cloned_item);
369 }
370 return true;
371 }
372
recursive_help_go(RCore * core,int detail,RCmdDescriptor * desc)373 static void recursive_help_go(RCore *core, int detail, RCmdDescriptor *desc) {
374 int i;
375 if (desc->help_msg) {
376 r_core_cmd_help (core, desc->help_msg);
377 }
378 if (detail >= 1) {
379 if (desc->help_detail) {
380 r_core_cmd_help (core, desc->help_detail);
381 }
382 if (detail >= 2 && desc->help_detail2) {
383 r_core_cmd_help (core, desc->help_detail2);
384 }
385 }
386 for (i = 32; i < R_ARRAY_SIZE (desc->sub); i++) {
387 if (desc->sub[i]) {
388 recursive_help_go (core, detail, desc->sub[i]);
389 }
390 }
391 }
392
recursive_help(RCore * core,int detail,const char * cmd_prefix)393 static void recursive_help(RCore *core, int detail, const char *cmd_prefix) {
394 const ut8 *p;
395 RCmdDescriptor *desc = &core->root_cmd_descriptor;
396 for (p = (const ut8 *)cmd_prefix; *p && *p < R_ARRAY_SIZE (desc->sub); p++) {
397 if (!(desc = desc->sub[*p])) {
398 return;
399 }
400 }
401 recursive_help_go (core, detail, desc);
402 }
403
lastcmd_repeat(RCore * core,int next)404 static bool lastcmd_repeat(RCore *core, int next) {
405 int res = -1;
406 // Fix for backtickbug px`~`
407 if (!core->lastcmd || core->cons->context->cmd_depth < 1) {
408 return false;
409 }
410 switch (*core->lastcmd) {
411 case '.':
412 if (core->lastcmd[1] == '(') { // macro call
413 res = r_core_cmd0 (core, core->lastcmd);
414 }
415 break;
416 case 'd': // debug
417 res = r_core_cmd0 (core, core->lastcmd);
418 switch (core->lastcmd[1]) {
419 case 's':
420 case 'c':
421 r_core_cmd0 (core, "sr PC;pd 1");
422 }
423 break;
424 case 'p': // print
425 case 'x':
426 case '$':
427 if (!strncmp (core->lastcmd, "pd", 2)) {
428 if (core->lastcmd[2]== ' ') {
429 r_core_cmdf (core, "so %s", core->lastcmd + 3);
430 } else {
431 r_core_cmd0 (core, "so `pi~?`");
432 }
433 } else {
434 if (next) {
435 r_core_seek (core, core->offset + core->blocksize, true);
436 } else {
437 if (core->blocksize > core->offset) {
438 r_core_seek (core, 0, true);
439 } else {
440 r_core_seek (core, core->offset - core->blocksize, true);
441 }
442 }
443 }
444 res = r_core_cmd0 (core, core->lastcmd);
445 break;
446 }
447 return res != -1;
448 }
449
r_core_cmd_nullcallback(void * data)450 static int r_core_cmd_nullcallback(void *data) {
451 RCore *core = (RCore*) data;
452 if (core->cons->context->breaked) {
453 core->cons->context->breaked = false;
454 return 0;
455 }
456 if (!core->cmdrepeat) {
457 return 0;
458 }
459 lastcmd_repeat (core, true);
460 return 1;
461 }
462
cmd_uname(void * data,const char * input)463 static int cmd_uname(void *data, const char *input) { // "uniq"
464 RSysInfo *si = r_sys_info();
465 if (si) {
466 r_cons_printf ("%s", si->sysname);
467 if (strstr (input, "-r")) {
468 r_cons_printf (" %s", si->release);
469 }
470 r_cons_newline ();
471 r_sys_info_free (si);
472 }
473 return 0;
474 }
475
cmd_uniq(void * data,const char * input)476 static int cmd_uniq(void *data, const char *input) { // "uniq"
477 RCore *core = (RCore *)data;
478 const char *arg = strchr (input, ' ');
479 if (arg) {
480 arg = r_str_trim_head_ro (arg + 1);
481 }
482 switch (*input) {
483 case '?': // "uniq?"
484 eprintf ("Usage: uniq # uniq to list unique strings in file\n");
485 break;
486 default: // "uniq"
487 if (!arg) {
488 arg = "";
489 }
490 if (r_fs_check (core->fs, arg)) {
491 r_core_cmdf (core, "md %s", arg);
492 } else {
493 char *res = r_syscmd_uniq (arg);
494 if (res) {
495 r_cons_print (res);
496 free (res);
497 }
498 }
499 break;
500 }
501 return 0;
502 }
503
cmd_head(void * data,const char * _input)504 static int cmd_head (void *data, const char *_input) { // "head"
505 RCore *core = (RCore *)data;
506 int lines = 5;
507 char *input = strdup (_input);
508 char *arg = strchr (input, ' ');
509 char *tmp, *count;
510 if (arg) {
511 arg = (char *)r_str_trim_head_ro (arg + 1); // contains "count filename"
512 count = strchr (arg, ' ');
513 if (count) {
514 *count = 0; // split the count and file name
515 tmp = (char *)r_str_trim_head_ro (count + 1);
516 lines = atoi (arg);
517 arg = tmp;
518 }
519 }
520 switch (*input) {
521 case '?': // "head?"
522 eprintf ("Usage: head [file] # to list first n lines in file\n");
523 break;
524 default: // "head"
525 if (!arg) {
526 arg = "";
527 }
528 if (r_fs_check (core->fs, arg)) {
529 r_core_cmdf (core, "md %s", arg);
530 } else {
531 char *res = r_syscmd_head (arg, lines);
532 if (res) {
533 r_cons_print (res);
534 free (res);
535 }
536 }
537 break;
538 }
539 free (input);
540 return 0;
541 }
542
cmd_undo(void * data,const char * input)543 static int cmd_undo(void *data, const char *input) {
544 RCore *core = (RCore *)data;
545 switch (input[0]) {
546 case '?': // "u?"
547 r_core_cmd_help (data, help_msg_u);
548 return 1;
549 case 'c': // "uc"
550 switch (input[1]) {
551 case ' ': {
552 char *cmd = strdup (input + 2);
553 char *rcmd = strchr (cmd, ',');
554 if (rcmd) {
555 *rcmd++ = 0;
556 RCoreUndo *undo = r_core_undo_new (core->offset, cmd, rcmd);
557 r_core_undo_push (core, undo);
558 } else {
559 eprintf ("Usage: uc [cmd] [revert-cmd]");
560 }
561 free (cmd);
562 }
563 break;
564 case '?': // "uc?"
565 r_core_cmd_help (core, help_msg_uc);
566 break;
567 case '.': { // "uc."
568 RCoreUndoCondition cond = {
569 .addr = core->offset,
570 .minstamp = 0,
571 .glob = NULL
572 };
573 r_core_undo_print (core, 1, &cond);
574 break;
575 }
576 case '*': // "uc*"
577 r_core_undo_print (core, 1, NULL);
578 break;
579 case '-': // "uc-"
580 r_core_undo_pop (core);
581 break;
582 default:
583 r_core_undo_print (core, 0, NULL);
584 break;
585 }
586 return 1;
587 case 's': // "us"
588 r_core_cmdf (data, "s-%s", input + 1);
589 return 1;
590 case 'w': // "uw"
591 r_core_cmdf (data, "wc%s", input + 1);
592 return 1;
593 case 'n': // "un"
594 if (input[1] == 'a') { // "uname"
595 (void)cmd_uname (core, input);
596 } else if (input[1] == 'i' && input[2] == 'q') {
597 (void)cmd_uniq (core, input);
598 }
599 return 1;
600 }
601 #if __UNIX__
602 struct utsname un;
603 uname (&un);
604 r_cons_printf ("%s %s %s %s\n", un.sysname,
605 un.nodename, un.release, un.machine);
606 #elif __WINDOWS__
607 r_cons_printf ("windows\n");
608 #else
609 r_cons_printf ("unknown\n");
610 #endif
611 return 0;
612 }
613
cmd_alias(void * data,const char * input)614 static int cmd_alias(void *data, const char *input) {
615 RCore *core = (RCore *)data;
616 if (*input == '?') {
617 r_core_cmd_help (core, help_msg_dollar);
618 return 0;
619 }
620 int i = strlen (input);
621 char *buf = malloc (i + 2);
622 if (!buf) {
623 return 0;
624 }
625 *buf = '$'; // prefix aliases with a dollar
626 memcpy (buf + 1, input, i + 1);
627 char *q = strchr (buf, ' ');
628 char *def = strchr (buf, '=');
629 char *desc = strchr (buf, '?');
630 char *nonl = strchr (buf, 'n');
631
632 int defmode = 0;
633 if (def && def > buf) {
634 char *prev = def - 1;
635 switch (*prev) {
636 case ':':
637 defmode = *prev;
638 *prev = 0;
639 break;
640 case '+':
641 defmode = *prev;
642 *prev = 0;
643 break;
644 case '-':
645 defmode = *prev;
646 *prev = 0;
647 break;
648 }
649 }
650
651 /* create alias */
652 if ((def && q && (def < q)) || (def && !q)) {
653 *def++ = 0;
654 size_t len = strlen (def);
655 if (defmode) {
656 ut64 at = r_num_math (core->num, def);
657 switch (defmode) {
658 case ':':
659 r_flag_set (core->flags, buf + 1, at, 1);
660 return 1;
661 case '+':
662 at = r_num_get (core->num, buf + 1) + at;
663 r_flag_set (core->flags, buf + 1, at, 1);
664 return 1;
665 case '-':
666 at = r_num_get (core->num, buf + 1) - at;
667 r_flag_set (core->flags, buf + 1, at, 1);
668 return 1;
669 }
670 }
671 /* Remove quotes */
672 if (len > 0 && (def[0] == '\'') && (def[len - 1] == '\'')) {
673 def[len - 1] = 0x00;
674 def++;
675 }
676 if (!q || (q && q > def)) {
677 if (*def) {
678 if (!strcmp (def, "-")) {
679 const char *v = r_cmd_alias_get (core->rcmd, buf, 0);
680 char *n = r_cons_editor (NULL, v);
681 if (n) {
682 r_cmd_alias_set (core->rcmd, buf, n, 0);
683 free (n);
684 }
685 } else {
686 r_cmd_alias_set (core->rcmd, buf, def, 0);
687 }
688 } else {
689 r_cmd_alias_del (core->rcmd, buf);
690 }
691 }
692 /* Show command for alias */
693 } else if (desc && !q) {
694 *desc = 0;
695 const char *v = r_cmd_alias_get (core->rcmd, buf, 0);
696 if (v) {
697 if (nonl == desc + 1) {
698 r_cons_print (v);
699 } else {
700 r_cons_println (v);
701 }
702 free (buf);
703 return 1;
704 } else {
705 eprintf ("unknown key '%s'\n", buf);
706 }
707 } else if (buf[1] == '*') {
708 /* Show aliases */
709 int i, count = 0;
710 char **keys = r_cmd_alias_keys (core->rcmd, &count);
711 for (i = 0; i < count; i++) {
712 const char *v = r_cmd_alias_get (core->rcmd, keys[i], 0);
713 char *q = r_base64_encode_dyn (v, -1);
714 if (buf[2] == '*') {
715 r_cons_printf ("%s=%s\n", keys[i], v);
716 } else {
717 r_cons_printf ("%s=base64:%s\n", keys[i], q);
718 }
719 free (q);
720 }
721 } else if (!buf[1]) {
722 int i, count = 0;
723 char **keys = r_cmd_alias_keys (core->rcmd, &count);
724 for (i = 0; i < count; i++) {
725 r_cons_println (keys[i]);
726 }
727 } else {
728 /* Execute alias */
729 if (q) {
730 *q = 0;
731 }
732 const char *v = r_cmd_alias_get (core->rcmd, buf, 0);
733 if (v) {
734 if (*v == '$') {
735 r_cons_strcat (v + 1);
736 r_cons_newline ();
737 } else if (q) {
738 char *out = r_str_newf ("%s %s", v, q + 1);
739 r_core_cmd0 (core, out);
740 free (out);
741 } else {
742 r_core_cmd0 (core, v);
743 }
744 } else {
745 ut64 at = r_num_get (core->num, buf + 1);
746 if (at != UT64_MAX) {
747 r_core_seek (core, at, true);
748 } else {
749 eprintf ("Unknown alias '%s'\n", buf + 1);
750 }
751 }
752 }
753 free (buf);
754 return 0;
755 }
756
getArg(char ch,int def)757 static int getArg(char ch, int def) {
758 switch (ch) {
759 case '&':
760 case '-':
761 return ch;
762 }
763 return def;
764 }
765
766 // wtf dupe for local vs remote?
aliascmd(RCore * core,const char * str)767 static void aliascmd(RCore *core, const char *str) {
768 switch (str[0]) {
769 case '\0': // "=$"
770 r_core_cmd0 (core, "$");
771 break;
772 case '-': // "=$-"
773 if (str[1]) {
774 r_cmd_alias_del (core->rcmd, str + 2);
775 } else {
776 r_cmd_alias_del (core->rcmd, NULL);
777 // r_cmd_alias_reset (core->rcmd);
778 }
779 break;
780 case '?': // "=$?"
781 eprintf ("Usage: =$[-][remotecmd] # remote command alias\n");
782 eprintf (" =$dr # makes 'dr' alias for =!dr\n");
783 eprintf (" =$-dr # unset 'dr' alias\n");
784 break;
785 default:
786 r_cmd_alias_set (core->rcmd, str, "", 1);
787 break;
788 }
789 }
790
cmd_remote(RCore * core,const char * input,bool retry)791 static void cmd_remote(RCore *core, const char *input, bool retry) {
792 if (!*input) {
793 return;
794 }
795 if (*input == '?') {
796 r_cons_printf ("Usage: =r localhost:9999\n");
797 return;
798 }
799 char *host = strdup (input);
800 char *port = strchr (host, ':');
801 if (port) {
802 *port++ = 0;
803 }
804 RSocket *s = r_socket_new (false);
805 repeat:
806 if (r_socket_connect (s, host, port, R_SOCKET_PROTO_TCP, 1500)) {
807 char buf[1024];
808 void *bed = r_cons_sleep_begin ();
809 r_cons_break_push (NULL, NULL);
810 for (;;) {
811 if (r_cons_is_breaked ()) {
812 break;
813 }
814 r_socket_printf (s, "[0x%08"PFMT64x"]> ", core->offset);
815 r_socket_flush (s);
816 memset (buf, 0, sizeof (buf));
817 r_socket_block_time (s, true, 99999, 0);
818 if (r_socket_read (s, (ut8*)buf, sizeof (buf) - 1) < 1) {
819 break;
820 }
821 if (*buf == 'q') {
822 break;
823 }
824 const bool orig = r_config_get_b (core->config, "scr.interactive");
825 r_config_set_b (core->config, "scr.interactive", false);
826 char *res = r_core_cmd_str (core, buf);
827 r_config_set_b (core->config, "scr.interactive", orig);
828 r_socket_printf (s, "%s\n", res);
829 r_socket_flush (s);
830 free (res);
831 }
832 r_cons_break_pop ();
833 r_cons_sleep_end (bed);
834 } else {
835 if (retry) {
836 r_sys_sleep (1);
837 goto repeat;
838 }
839 }
840 r_socket_close (s);
841 r_socket_free (s);
842 free (host);
843 }
844
cmd_rap(void * data,const char * input)845 static int cmd_rap(void *data, const char *input) {
846 RCore *core = (RCore *)data;
847 switch (*input) {
848 case '\0': // "="
849 r_core_rtr_list (core);
850 break;
851 case 'r': // "=r"
852 cmd_remote (core, r_str_trim_head_ro (input + 1), false);
853 break;
854 case 'R': // "=R"
855 cmd_remote (core, r_str_trim_head_ro (input + 1), true);
856 break;
857 case 'j': // "=j"
858 eprintf ("TODO: list connections in json\n");
859 break;
860 case '!': // "=!"
861 if (input[1] == 'q') {
862 R_FREE (core->cmdremote);
863 } else if (input[1] == '=') { // =!=0 or =!= for iosystem
864 R_FREE (core->cmdremote);
865 core->cmdremote = r_str_trim_dup (input + 2);
866 } else {
867 char *res = r_io_system (core->io, input + 1);
868 if (res) {
869 r_cons_printf ("%s\n", res);
870 free (res);
871 }
872 }
873 break;
874 case '$': // "=$"
875 // XXX deprecate?
876 aliascmd (core, input + 1);
877 break;
878 case '+': // "=+"
879 r_core_rtr_add (core, input + 1);
880 break;
881 case '-': // "=-"
882 r_core_rtr_remove (core, input + 1);
883 break;
884 //case ':': r_core_rtr_cmds (core, input + 1); break;
885 case '<': // "=<"
886 r_core_rtr_pushout (core, input + 1);
887 break;
888 case '=': // "=="
889 r_core_rtr_session (core, input + 1);
890 break;
891 case 'g': // "=g"
892 if (input[1] == '?') {
893 r_core_cmd_help (core, help_msg_equalg);
894 } else {
895 r_core_rtr_gdb (core, getArg (input[1], 'g'), input + 1);
896 }
897 break;
898 case 'h': // "=h"
899 if (input[1] == '?') {
900 r_core_cmd_help (core, help_msg_equalh);
901 } else {
902 r_core_rtr_http (core, getArg (input[1], 'h'), 'h', input + 1);
903 }
904 break;
905 case 'H': // "=H"
906 if (input[1] == '?') {
907 r_core_cmd_help (core, help_msg_equalh);
908 } else {
909 const char *arg = r_str_trim_head_ro (input + 1);
910 r_core_rtr_http (core, getArg (input[1], 'H'), 'H', arg);
911 }
912 break;
913 case '?': // "=?"
914 r_core_cmd_help (core, help_msg_equal);
915 break;
916 default:
917 r_core_rtr_cmd (core, input);
918 break;
919 }
920 return 0;
921 }
922
cmd_rap_run(void * data,const char * input)923 static int cmd_rap_run(void *data, const char *input) {
924 RCore *core = (RCore *)data;
925 char *res = r_io_system (core->io, input);
926 if (res) {
927 int ret = atoi (res);
928 free (res);
929 return ret;
930 }
931 return false;
932 }
933
cmd_yank(void * data,const char * input)934 static int cmd_yank(void *data, const char *input) {
935 ut64 n;
936 RCore *core = (RCore *)data;
937 switch (input[0]) {
938 case ' ': // "y "
939 r_core_yank (core, core->offset, r_num_math (core->num, input + 1));
940 break;
941 case 'l': // "yl"
942 core->num->value = r_buf_size (core->yank_buf);
943 break;
944 case 'y': // "yy"
945 while (input[1] == ' ') {
946 input++;
947 }
948 n = input[1]? r_num_math (core->num, input + 1): core->offset;
949 r_core_yank_paste (core, n, 0);
950 break;
951 case 'x': // "yx"
952 r_core_yank_hexdump (core, r_num_math (core->num, input + 1));
953 break;
954 case 'z': // "yz"
955 r_core_yank_string (core, core->offset, r_num_math (core->num, input + 1));
956 break;
957 case 'w': // "yw" ... we have yf which makes more sense than 'w'
958 switch (input[1]) {
959 case ' ':
960 r_core_yank_set (core, 0, (const ut8*)input + 2, strlen (input + 2));
961 break;
962 case 'x':
963 if (input[2] == ' ') {
964 char *out = strdup (input + 3);
965 int len = r_hex_str2bin (input + 3, (ut8*)out);
966 if (len > 0) {
967 r_core_yank_set (core, core->offset, (const ut8*)out, len);
968 } else {
969 eprintf ("Invalid length\n");
970 }
971 free (out);
972 } else {
973 eprintf ("Usage: ywx [hexpairs]\n");
974 }
975 // r_core_yank_write_hex (core, input + 2);
976 break;
977 default:
978 eprintf ("Usage: ywx [hexpairs]\n");
979 break;
980 }
981 break;
982 case 'p': // "yp"
983 r_core_yank_cat (core, r_num_math (core->num, input + 1));
984 break;
985 case 's': // "ys"
986 r_core_yank_cat_string (core, r_num_math (core->num, input + 1));
987 break;
988 case 't': // "wt"
989 if (input[1] == 'f') { // "wtf"
990 ut64 tmpsz;
991 const char *file = r_str_trim_head_ro (input + 2);
992 const ut8 *tmp = r_buf_data (core->yank_buf, &tmpsz);
993 if (!r_file_dump (file, tmp, tmpsz, false)) {
994 eprintf ("Cannot dump to '%s'\n", file);
995 }
996 } else if (input[1] == ' ') {
997 r_core_yank_to (core, input + 1);
998 } else {
999 eprintf ("Usage: wt[f] [arg] ..\n");
1000 }
1001 break;
1002 case 'f': // "yf"
1003 switch (input[1]) {
1004 case ' ': // "yf"
1005 r_core_yank_file_ex (core, input + 1);
1006 break;
1007 case 'x': // "yfx"
1008 r_core_yank_hexpair (core, input + 2);
1009 break;
1010 case 'a': // "yfa"
1011 r_core_yank_file_all (core, input + 2);
1012 break;
1013 default:
1014 eprintf ("Usage: yf[xa] [arg]\n");
1015 eprintf ("yf [file] - copy blocksize from file into the clipboard\n");
1016 eprintf ("yfa [path] - yank the whole file\n");
1017 eprintf ("yfx [hexpair] - yank from hexpair string\n");
1018 break;
1019 }
1020 break;
1021 case '!': // "y!"
1022 {
1023 char *sig = r_core_cmd_str (core, "y*");
1024 if (!sig || !*sig) {
1025 free (sig);
1026 sig = strdup ("wx 10203040");
1027 }
1028 char *data = r_core_editor (core, NULL, sig);
1029 (void) strtok (data, ";\n");
1030 r_core_cmdf (core, "y%s", data);
1031 free (sig);
1032 free (data);
1033 }
1034 break;
1035 case '*': // "y*"
1036 case 'j': // "yj"
1037 case 'q': // "yq"
1038 case '\0': // "y"
1039 r_core_yank_dump (core, 0, input[0]);
1040 break;
1041 default:
1042 r_core_cmd_help (core, help_msg_y);
1043 break;
1044 }
1045 return true;
1046 }
1047
lang_run_file(RCore * core,RLang * lang,const char * file)1048 static int lang_run_file(RCore *core, RLang *lang, const char *file) {
1049 r_core_sysenv_begin (core, NULL);
1050 return r_lang_run_file (core->lang, file);
1051 }
1052
langFromHashbang(RCore * core,const char * file)1053 static char *langFromHashbang(RCore *core, const char *file) {
1054 int fd = r_sandbox_open (file, O_RDONLY, 0);
1055 if (fd != -1) {
1056 char firstLine[128] = {0};
1057 int len = r_sandbox_read (fd, (ut8*)firstLine, sizeof (firstLine) - 1);
1058 firstLine[len] = 0;
1059 if (!strncmp (firstLine, "#!/", 3)) {
1060 // I CAN HAS A HASHBANG
1061 char *nl = strchr (firstLine, '\n');
1062 if (nl) {
1063 *nl = 0;
1064 }
1065 nl = strchr (firstLine, ' ');
1066 if (nl) {
1067 *nl = 0;
1068 }
1069 nl = strdup (firstLine + 2);
1070 r_sandbox_close (fd);
1071 return nl;
1072 }
1073 r_sandbox_close (fd);
1074 }
1075 return NULL;
1076 }
1077
r_core_run_script(RCore * core,const char * file)1078 R_API bool r_core_run_script(RCore *core, const char *file) {
1079 bool ret = false;
1080 RListIter *iter;
1081 RLangPlugin *p;
1082 char *name;
1083
1084 r_list_foreach (core->scriptstack, iter, name) {
1085 if (!strcmp (file, name)) {
1086 eprintf ("WARNING: ignored nested source: %s\n", file);
1087 return false;
1088 }
1089 }
1090 r_list_push (core->scriptstack, strdup (file));
1091
1092 if (!strcmp (file, "-")) {
1093 char *out = r_core_editor (core, NULL, NULL);
1094 if (out) {
1095 ret = r_core_cmd_lines (core, out);
1096 free (out);
1097 }
1098 } else if (r_str_endswith (file, ".html")) {
1099 const bool httpSandbox = r_config_get_i (core->config, "http.sandbox");
1100 char *httpIndex = strdup (r_config_get (core->config, "http.index"));
1101 r_config_set_b (core->config, "http.sandbox", false);
1102 char *absfile = r_file_abspath (file);
1103 r_config_set (core->config, "http.index", absfile);
1104 free (absfile);
1105 r_core_cmdf (core, "=H");
1106 r_config_set_b (core->config, "http.sandbox", httpSandbox);
1107 r_config_set (core->config, "http.index", httpIndex);
1108 free (httpIndex);
1109 ret = true;
1110 } else if (r_str_endswith (file, ".c")) {
1111 r_core_cmd_strf (core, "#!c %s", file);
1112 ret = true;
1113 } else if (r_file_is_c (file)) {
1114 const char *dir = r_config_get (core->config, "dir.types");
1115 char *out = r_parse_c_file (core->anal, file, dir, NULL);
1116 if (out) {
1117 r_cons_strcat (out);
1118 sdb_query_lines (core->anal->sdb_types, out);
1119 free (out);
1120 }
1121 ret = out != NULL;
1122 } else {
1123 p = r_lang_get_by_extension (core->lang, file);
1124 if (p) {
1125 r_lang_use (core->lang, p->name);
1126 ret = lang_run_file (core, core->lang, file);
1127 } else {
1128 // XXX this is an ugly hack, we need to use execve here and specify args properly
1129 #if __WINDOWS__
1130 #define cmdstr(x) r_str_newf (x" %s", file);
1131 #else
1132 #define cmdstr(x) r_str_newf (x" '%s'", file);
1133 #endif
1134 const char *p = r_str_lchr (file, '.');
1135 if (p) {
1136 const char *ext = p + 1;
1137 /* TODO: handle this inside r_lang_pipe with new APIs */
1138 if (!strcmp (ext, "js")) {
1139 char *cmd = cmdstr ("node");
1140 r_lang_use (core->lang, "pipe");
1141 lang_run_file (core, core->lang, cmd);
1142 free (cmd);
1143 ret = 1;
1144 } else if (!strcmp (ext, "exe")) {
1145 #if __WINDOWS__
1146 char *cmd = r_str_newf ("%s", file);
1147 #else
1148 char *cmd = cmdstr ("wine");
1149 #endif
1150 r_lang_use (core->lang, "pipe");
1151 lang_run_file (core, core->lang, cmd);
1152 free (cmd);
1153 ret = 1;
1154 } else if (!strcmp (ext, "zig")) {
1155 char *cmd = cmdstr ("zig run");
1156 r_lang_use (core->lang, "pipe");
1157 lang_run_file (core, core->lang, cmd);
1158 free (cmd);
1159 ret = 1;
1160 } else if (!strcmp (ext, "d")) {
1161 char *cmd = cmdstr ("dmd -run");
1162 r_lang_use (core->lang, "pipe");
1163 lang_run_file (core, core->lang, cmd);
1164 free (cmd);
1165 ret = 1;
1166 } else if (!strcmp (ext, "lsp")) {
1167 char *cmd = cmdstr ("newlisp -n");
1168 r_lang_use (core->lang, "pipe");
1169 lang_run_file (core, core->lang, cmd);
1170 free (cmd);
1171 ret = 1;
1172 } else if (!strcmp (ext, "go")) {
1173 char *cmd = cmdstr ("go run");
1174 r_lang_use (core->lang, "pipe");
1175 lang_run_file (core, core->lang, cmd);
1176 free (cmd);
1177 ret = 1;
1178 } else if (!strcmp (ext, "es6")) {
1179 char *cmd = cmdstr ("babel-node");
1180 r_lang_use (core->lang, "pipe");
1181 lang_run_file (core, core->lang, cmd);
1182 free (cmd);
1183 ret = 1;
1184 } else if (!strcmp (ext, "rb")) {
1185 char *cmd = cmdstr ("ruby");
1186 r_lang_use (core->lang, "pipe");
1187 lang_run_file (core, core->lang, cmd);
1188 free (cmd);
1189 ret = 1;
1190 } else if (!strcmp (ext, "vala")) {
1191 r_lang_use (core->lang, "vala");
1192 lang_run_file (core, core->lang, file);
1193 ret = 1;
1194 } else if (!strcmp (ext, "sh")) {
1195 char *shell = r_sys_getenv ("SHELL");
1196 if (!shell) {
1197 shell = strdup ("sh");
1198 }
1199 if (shell) {
1200 r_lang_use (core->lang, "pipe");
1201 char *cmd = r_str_newf ("%s '%s'", shell, file);
1202 if (cmd) {
1203 lang_run_file (core, core->lang, cmd);
1204 free (cmd);
1205 }
1206 free (shell);
1207 }
1208 ret = 1;
1209 } else if (!strcmp (ext, "pl")) {
1210 char *cmd = cmdstr ("perl");
1211 r_lang_use (core->lang, "pipe");
1212 lang_run_file (core, core->lang, cmd);
1213 free (cmd);
1214 ret = 1;
1215 } else if (!strcmp (ext, "py")) {
1216 char *cmd = cmdstr ("python");
1217 r_lang_use (core->lang, "pipe");
1218 lang_run_file (core, core->lang, cmd);
1219 free (cmd);
1220 ret = 1;
1221 }
1222 } else {
1223 char *abspath = r_file_path (file);
1224 char *lang = langFromHashbang (core, file);
1225 if (lang) {
1226 r_lang_use (core->lang, "pipe");
1227 char *cmd = r_str_newf ("%s '%s'", lang, file);
1228 lang_run_file (core, core->lang, cmd);
1229 free (lang);
1230 free (cmd);
1231 ret = 1;
1232 }
1233 free (abspath);
1234 }
1235 if (!ret) {
1236 ret = r_core_cmd_file (core, file);
1237 }
1238 }
1239 }
1240 free (r_list_pop (core->scriptstack));
1241 return ret;
1242 }
1243
cmd_ls(void * data,const char * input)1244 static int cmd_ls(void *data, const char *input) { // "ls"
1245 RCore *core = (RCore *)data;
1246 const char *arg = strchr (input, ' ');
1247 if (arg) {
1248 arg = r_str_trim_head_ro (arg + 1);
1249 }
1250 switch (*input) {
1251 case '?': // "l?"
1252 eprintf ("Usage: l[es] # ls to list files, le[ss] to less a file\n");
1253 break;
1254 case 'e': // "le"
1255 if (arg) {
1256 r_core_cmdf (core, "cat %s~..", arg);
1257 } else {
1258 eprintf ("Usage: less [file]\n");
1259 }
1260 break;
1261 default: // "ls"
1262 if (!arg) {
1263 arg = "";
1264 }
1265 if (r_fs_check (core->fs, arg)) {
1266 r_core_cmdf (core, "md %s", arg);
1267 } else {
1268 char *res = r_syscmd_ls (arg);
1269 if (res) {
1270 r_cons_print (res);
1271 free (res);
1272 }
1273 }
1274 break;
1275 }
1276 return 0;
1277 }
1278
cmd_join(void * data,const char * input)1279 static int cmd_join(void *data, const char *input) { // "join"
1280 RCore *core = (RCore *)data;
1281 char *tmp = strdup (input);
1282 const char *arg1 = strchr (tmp, ' ');
1283 if (!arg1) {
1284 goto beach;
1285 }
1286 arg1 = r_str_trim_head_ro (arg1);
1287 if (!arg1) {
1288 goto beach;
1289 }
1290 char *end = strchr (arg1, ' ');
1291 if (!end) {
1292 goto beach;
1293 }
1294 *end = '\0';
1295 const char *arg2 = end+1;
1296 if (!arg2) {
1297 goto beach;
1298 }
1299 arg2 = r_str_trim_head_ro (arg2);
1300 switch (*input) {
1301 case '?': // "join?"
1302 goto beach;
1303 default: // "join"
1304 if (!arg1) {
1305 arg1 = "";
1306 }
1307 if (!arg2) {
1308 arg2 = "";
1309 }
1310 if (!r_fs_check (core->fs, arg1) && !r_fs_check (core->fs, arg2)) {
1311 char *res = r_syscmd_join (arg1, arg2);
1312 if (res) {
1313 r_cons_print (res);
1314 free (res);
1315 }
1316 }
1317 break;
1318 }
1319 free (tmp);
1320 return 0;
1321 beach:
1322 eprintf ("Usage: join [file1] [file2] # join the contents of the two files\n");
1323 free (tmp);
1324 return 0;
1325 }
1326
cmd_stdin(void * data,const char * input)1327 static int cmd_stdin(void *data, const char *input) {
1328 RCore *core = (RCore *)data;
1329 if (input[0] == '?') {
1330 r_cons_printf ("Usage: '-' '.-' '. -' do the same\n");
1331 return false;
1332 }
1333 return r_core_run_script (core, "-");
1334 }
1335
load_table_json(RCore * core,RTable * t,char * data)1336 static void load_table_json(RCore *core, RTable *t, char *data) {
1337 // parse json file and iterate over all the entries
1338 // RTableRow *row = r_table_row_new (items);
1339 // r_list_append (t->rows, row);
1340 eprintf ("TODO: Loading tables from JSON is not yet implemented\n");
1341 }
1342
get_type_string(const char * s)1343 static const char *get_type_string(const char *s) {
1344 if (!strncmp (s, "0x", 2)) {
1345 return "x";
1346 }
1347 if (*s == '0' || atoi (s)) {
1348 return "d";
1349 }
1350 return "s";
1351 }
1352
load_table_csv(RCore * core,RTable * t,RList * lines)1353 static void load_table_csv(RCore *core, RTable *t, RList *lines) {
1354 RListIter *iter;
1355 char *line;
1356 int row = 0;
1357
1358 RList *cols = NULL;
1359 r_list_foreach (lines, iter, line) {
1360 char *word;
1361 RListIter *iter2;
1362 RList *words = r_str_split_list (line, ",", 0);
1363 if (r_list_length (words) > 0) {
1364 switch (row) {
1365 case 0:
1366 cols = words;
1367 words = NULL;
1368 break;
1369 case 1:
1370 {
1371 RStrBuf *b = r_strbuf_new (",h ");
1372 RStrBuf *args = r_strbuf_new ("");
1373 r_list_foreach (words, iter2, word) {
1374 const char *type = get_type_string (word);
1375 r_strbuf_append (b, type);
1376 }
1377 r_list_foreach (cols, iter2, word) {
1378 r_strbuf_append (b , " ");
1379 r_strbuf_append (b, word);
1380 }
1381 r_core_cmd0 (core, r_strbuf_get (b));
1382 r_strbuf_free (args);
1383 r_strbuf_free (b);
1384 }
1385 /* fallthrough */
1386 default:
1387 {
1388 RStrBuf *b = r_strbuf_new (",r ");
1389 r_list_foreach (words, iter2, word) {
1390 r_strbuf_append (b, " ");
1391 r_strbuf_append (b, word);
1392 }
1393 r_core_cmd0 (core, r_strbuf_get (b));
1394 r_strbuf_free (b);
1395 }
1396 break;
1397 }
1398 }
1399 r_list_free (words);
1400 row++;
1401 }
1402 }
1403
load_table_asciiart(RCore * core,RTable * t,RList * lines)1404 static void load_table_asciiart(RCore *core, RTable *t, RList *lines) {
1405 RListIter *iter;
1406 char *line;
1407 const char *separator = "|";
1408 int ncols = 0;
1409 bool expect_header = false;
1410 bool expect_rows = false;
1411 r_list_foreach (lines, iter, line) {
1412 if (!expect_rows) {
1413 if (r_str_startswith (line, ".--")) {
1414 expect_header = true;
1415 separator = "|";
1416 continue;
1417 }
1418 if (r_str_startswith (line, "┌")) {
1419 expect_header = true;
1420 separator = "│";
1421 continue;
1422 }
1423 if (r_str_startswith (line, ")-")) {
1424 expect_rows = true;
1425 separator = "|";
1426 continue;
1427 }
1428 if (r_str_startswith (line, "│─")) {
1429 expect_rows = true;
1430 separator = "│";
1431 continue;
1432 }
1433 }
1434
1435 RTableColumnType *typeString = r_table_type ("string");
1436 RTableColumnType *typeNumber = r_table_type ("number");
1437 if (expect_header) {
1438 char *arg;
1439 RList *args = r_str_split_list (line + strlen (separator), separator, 0);
1440 RListIter *iter2;
1441 ncols = 0;
1442 if (r_list_length (t->cols) > 0) {
1443 eprintf ("Warning: Not re-adding headers. Use ,- to reset the table.\n");
1444 continue;
1445 }
1446 r_list_foreach (args, iter2, arg) {
1447 char *s = strchr (arg, ' ');
1448 char *ss = r_str_trim_dup (s? s + 1: arg);
1449 if (!*ss) {
1450 free (ss);
1451 continue;
1452 }
1453 r_table_add_column (t, typeString, ss, 0);
1454 ncols ++;
1455 }
1456 expect_header = false;
1457 } else if (expect_rows) {
1458 char *arg;
1459 size_t line_len = strlen (line);
1460 size_t separator_len = strlen (separator);
1461 size_t pos = (line_len < separator_len)? line_len: separator_len;
1462 RList *args = r_str_split_list (line + pos, separator, 0);
1463 RList *items = r_list_newf (free);
1464 RListIter *iter2;
1465 if (r_list_length (args) < ncols) {
1466 // dowarn?
1467 continue;
1468 }
1469 r_list_foreach (args, iter2, arg) {
1470 char *ss = r_str_trim_dup (arg);
1471 if (!*ss) {
1472 free (ss);
1473 continue;
1474 }
1475 if (isdigit ((unsigned char)*ss)) {
1476 int col = r_list_length (items);
1477 RTableColumn *c = r_list_get_n (t->cols, col);
1478 if (c) {
1479 c->type = typeNumber;
1480 }
1481 }
1482 r_list_append (items, ss);
1483 }
1484 RTableRow *row = r_table_row_new (items);
1485 r_list_append (t->rows, row);
1486 }
1487 }
1488 }
1489
load_table(RCore * core,RTable * t,char * data)1490 static void load_table(RCore *core, RTable *t, char *data) {
1491 r_return_if_fail (core && t && data);
1492 if (*data == '[') {
1493 load_table_json (core, t, data);
1494 } else {
1495 RList *lines = r_str_split_list (data, "\n", 0);
1496 if (strchr (data, ',')) {
1497 load_table_csv (core, t, lines);
1498 } else {
1499 load_table_asciiart (core, t, lines);
1500 }
1501 r_list_free (lines);
1502 }
1503 free (data);
1504 }
1505
display_table(char * ts)1506 static void display_table(char *ts) {
1507 if (ts) {
1508 r_cons_printf ("%s\n", ts);
1509 free (ts);
1510 }
1511 }
1512
cmd_table_header(RCore * core,char * s)1513 static void cmd_table_header(RCore *core, char *s) {
1514 RList *list = r_str_split_list (s, " ", 0); // owns *s
1515 RListIter *iter;
1516 char *format = r_list_pop_head (list);
1517 if (!format) {
1518 return;
1519 }
1520 if (!core->table) {
1521 core->table = r_core_table (core, "header");
1522 }
1523 size_t i = 0;
1524 r_list_foreach (list, iter, s) {
1525 const char type_char = format[i];
1526 if (!type_char) {
1527 break;
1528 }
1529 const char *type_name = (type_char == 's')
1530 ? "string": "number";
1531 RTableColumnType *typeString = r_table_type (type_name);
1532 r_table_add_column (core->table, typeString, s, 0);
1533 i++;
1534 }
1535 r_list_free (list);
1536 free (format);
1537 }
1538
display_table_filter(RCore * core,const char * input)1539 static bool display_table_filter(RCore *core, const char *input) {
1540 r_return_val_if_fail (core && input, false);
1541 if (!core->table) {
1542 return false;
1543 }
1544 int skip = (*input == ' ')? 1: (*input&&input[1])? 2: 0;
1545 if (skip) {
1546 const char *q = r_str_trim_head_ro (input + skip);
1547 return r_table_query (core->table, q);
1548 }
1549 return true;
1550 }
1551
cmd_table(void * data,const char * input)1552 static int cmd_table(void *data, const char *input) {
1553 RCore *core = (RCore*)data;
1554 if (!core->table) {
1555 core->table = r_table_new ("table");
1556 }
1557 switch (*input) {
1558 case 'h': // table header columns
1559 case 'c': // table columns
1560 cmd_table_header (core, r_str_trim_dup (input + 1));
1561 break;
1562 case 'r': // add row
1563 {
1564 if (!core->table) {
1565 core->table = r_table_new ("table");
1566 }
1567 char *args = r_str_trim_dup (input + 1);
1568 if (*args) {
1569 RList *list = r_str_split_list (args, " ", 0);
1570 if (list) {
1571 r_table_add_row_list (core->table, list);
1572 }
1573 }
1574 }
1575 break;
1576 case '-':
1577 r_table_free (core->table);
1578 core->table = r_table_new ("table");
1579 break;
1580 case '/':
1581 // query here
1582 {
1583 RTable *ot = r_table_clone (core->table);
1584 if (display_table_filter (core, input)) {
1585 display_table (r_table_tostring (core->table));
1586 }
1587 r_table_free (core->table);
1588 core->table = ot;
1589 }
1590 break;
1591 case '.': // ",."
1592 if (R_STR_ISEMPTY (input + 1)) {
1593 eprintf ("Usage: ,. [file | $alias]\n");
1594 } else {
1595 const char *file = r_str_trim_head_ro (input + 1);
1596 if (*file == '$') {
1597 const char *file_data = r_cmd_alias_get (core->rcmd, file, 1);
1598 if (file_data) {
1599 load_table (core, core->table, strdup (file_data + 1));
1600 }
1601 } else {
1602 char *file_data = r_file_slurp (file, NULL);
1603 if (file_data) {
1604 load_table (core, core->table, file_data);
1605 } else {
1606 eprintf ("Cannot open file.\n");
1607 }
1608 }
1609 }
1610 break;
1611 case ' ':
1612 if (display_table_filter (core, input)) {
1613 display_table (r_table_tostring (core->table));
1614 }
1615 break;
1616 case ',':
1617 if (display_table_filter (core, input)) {
1618 display_table (r_table_tocsv (core->table));
1619 }
1620 break;
1621 case '*':
1622 if (display_table_filter (core, input)) {
1623 display_table (r_table_tor2cmds (core->table));
1624 }
1625 break;
1626 case 'j':
1627 if (display_table_filter (core, input)) {
1628 display_table (r_table_tojson (core->table));
1629 }
1630 break;
1631 case 0:
1632 if (core->table) {
1633 display_table (r_table_tofancystring (core->table));
1634 }
1635 break;
1636 case '?':
1637 r_core_cmd_help (core, cmd_table_help);
1638 r_cons_printf ("%s\n", r_table_help ());
1639 break;
1640 default:
1641 r_core_cmd_help (core, cmd_table_help);
1642 break;
1643 }
1644 return 0;
1645 }
1646
cmd_interpret(void * data,const char * input)1647 static int cmd_interpret(void *data, const char *input) {
1648 char *str, *ptr, *eol, *rbuf, *filter, *inp;
1649 const char *host, *port, *cmd;
1650 RCore *core = (RCore *)data;
1651
1652 if (!strcmp (input, "?")) {
1653 r_core_cmd_help (core, help_msg_dot);
1654 return 0;
1655 }
1656 switch (*input) {
1657 case '\0': // "."
1658 lastcmd_repeat (core, 0);
1659 break;
1660 case ':': // ".:"
1661 if ((ptr = strchr (input + 1, ' '))) {
1662 /* .:port cmd */
1663 /* .:host:port cmd */
1664 cmd = ptr + 1;
1665 *ptr = 0;
1666 eol = strchr (input + 1, ':');
1667 if (eol) {
1668 *eol = 0;
1669 host = input + 1;
1670 port = eol + 1;
1671 } else {
1672 host = "localhost";
1673 port = input + ((input[1] == ':')? 2: 1);
1674 }
1675 rbuf = r_core_rtr_cmds_query (core, host, port, cmd);
1676 if (rbuf) {
1677 r_cons_print (rbuf);
1678 free (rbuf);
1679 }
1680 } else {
1681 r_core_rtr_cmds (core, input + 1);
1682 }
1683 break;
1684 case '.': // ".." same as \n
1685 if (input[1] == '.') { // "..." run the last command repeated
1686 // same as \n with e cmd.repeat=true
1687 lastcmd_repeat (core, 1);
1688 } else if (input[1]) {
1689 char *str = r_core_cmd_str_pipe (core, r_str_trim_head_ro (input));
1690 if (str) {
1691 r_core_cmd (core, str, 0);
1692 free (str);
1693 }
1694 } else {
1695 eprintf ("Usage: .. ([file])\n");
1696 }
1697 break;
1698 case '*': // ".*"
1699 {
1700 const char *a = r_str_trim_head_ro (input + 1);
1701 char *s = strdup (a);
1702 char *sp = strchr (s, ' ');
1703 if (sp) {
1704 *sp = 0;
1705 }
1706 if (R_STR_ISNOTEMPTY (s)) {
1707 r_core_run_script (core, s);
1708 }
1709 free (s);
1710 }
1711 break;
1712 case '-': // ".-"
1713 if (input[1] == '?') {
1714 r_cons_printf ("Usage: '-' '.-' '. -' do the same\n");
1715 } else {
1716 r_core_run_script (core, "-");
1717 }
1718 break;
1719 case ' ': // ". "
1720 {
1721 const char *script_file = r_str_trim_head_ro (input + 1);
1722 if (*script_file == '$') {
1723 const char *oldText = r_cmd_alias_get (core->rcmd, script_file, 1);
1724 r_core_cmd0 (core, oldText); // script_file);
1725 } else {
1726 if (!r_core_run_script (core, script_file)) {
1727 eprintf ("Cannot find script '%s'\n", script_file);
1728 core->num->value = 1;
1729 } else {
1730 core->num->value = 0;
1731 }
1732 }
1733 }
1734 break;
1735 case '!': // ".!"
1736 /* from command */
1737 r_core_cmd_command (core, input + 1);
1738 break;
1739 case '(': // ".("
1740 r_cmd_macro_call (&core->rcmd->macro, input + 1);
1741 break;
1742 default:
1743 if (*input >= 0 && *input <= 9) {
1744 eprintf ("|ERROR| No .[0..9] to avoid infinite loops\n");
1745 break;
1746 }
1747 inp = strdup (input);
1748 filter = strchr (inp, '~');
1749 if (filter) {
1750 *filter = 0;
1751 }
1752 int tmp_html = r_cons_singleton ()->is_html;
1753 r_cons_singleton ()->is_html = false;
1754 ptr = str = r_core_cmd_str (core, inp);
1755 r_cons_singleton ()->is_html = tmp_html;
1756
1757 if (filter) {
1758 *filter = '~';
1759 }
1760 r_cons_break_push (NULL, NULL);
1761 if (ptr) {
1762 for (;;) {
1763 if (r_cons_is_breaked ()) {
1764 break;
1765 }
1766 eol = strchr (ptr, '\n');
1767 if (eol) {
1768 *eol = '\0';
1769 }
1770 if (*ptr) {
1771 char *p = r_str_append (strdup (ptr), filter);
1772 r_core_cmd0 (core, p);
1773 free (p);
1774 }
1775 if (!eol) {
1776 break;
1777 }
1778 ptr = eol + 1;
1779 }
1780 }
1781 r_cons_break_pop ();
1782 free (str);
1783 free (inp);
1784 break;
1785 }
1786 return 0;
1787 }
1788
callback_foreach_kv(void * user,const char * k,const char * v)1789 static bool callback_foreach_kv(void *user, const char *k, const char *v) {
1790 r_cons_printf ("%s=%s\n", k, v);
1791 return true;
1792 }
1793
r_line_hist_sdb_up(RLine * line)1794 R_API int r_line_hist_sdb_up(RLine *line) {
1795 if (!line->sdbshell_hist_iter || !line->sdbshell_hist_iter->n) {
1796 return false;
1797 }
1798 line->sdbshell_hist_iter = line->sdbshell_hist_iter->n;
1799 strncpy (line->buffer.data, line->sdbshell_hist_iter->data, R_LINE_BUFSIZE - 1);
1800 line->buffer.index = line->buffer.length = strlen (line->buffer.data);
1801 return true;
1802 }
1803
r_line_hist_sdb_down(RLine * line)1804 R_API int r_line_hist_sdb_down(RLine *line) {
1805 if (!line->sdbshell_hist_iter || !line->sdbshell_hist_iter->p) {
1806 return false;
1807 }
1808 line->sdbshell_hist_iter = line->sdbshell_hist_iter->p;
1809 strncpy (line->buffer.data, line->sdbshell_hist_iter->data, R_LINE_BUFSIZE - 1);
1810 line->buffer.index = line->buffer.length = strlen (line->buffer.data);
1811 return true;
1812 }
1813
cmd_kuery(void * data,const char * input)1814 static int cmd_kuery(void *data, const char *input) {
1815 char buf[1024], *out;
1816 RCore *core = (RCore*)data;
1817 const char *sp, *p = "[sdb]> ";
1818 Sdb *s = core->sdb;
1819
1820 char *cur_pos = NULL, *cur_cmd = NULL, *next_cmd = NULL;
1821 char *temp_pos = NULL, *temp_cmd = NULL;
1822
1823 switch (input[0]) {
1824 case 'j':
1825 out = sdb_querys (s, NULL, 0, "anal/**");
1826 if (!out) {
1827 r_cons_println ("No Output from sdb");
1828 break;
1829 }
1830 PJ * pj = pj_new ();
1831 if (!pj) {
1832 free (out);
1833 break;
1834 }
1835 pj_o (pj);
1836 pj_ko (pj, "anal");
1837 pj_ka (pj, "cur_cmd");
1838
1839 while (*out) {
1840 cur_pos = strchr (out, '\n');
1841 if (!cur_pos) {
1842 break;
1843 }
1844 cur_cmd = r_str_ndup (out, cur_pos - out);
1845 pj_s (pj, cur_cmd);
1846
1847 free (next_cmd);
1848 next_cmd = r_str_newf ("anal/%s/*", cur_cmd);
1849 char *query_result = sdb_querys (s, NULL, 0, next_cmd);
1850
1851 if (!query_result) {
1852 out = cur_pos + 1;
1853 continue;
1854 }
1855
1856 char *temp = query_result;
1857 while (*temp) {
1858 temp_pos = strchr (temp, '\n');
1859 if (!temp_pos) {
1860 break;
1861 }
1862 temp_cmd = r_str_ndup (temp, temp_pos - temp);
1863 pj_s (pj, temp_cmd);
1864 temp = temp_pos + 1;
1865 }
1866 out = cur_pos + 1;
1867 free (query_result);
1868 }
1869 pj_end (pj);
1870 pj_end (pj);
1871 pj_end (pj);
1872 r_cons_println (pj_string (pj));
1873 pj_free (pj);
1874 R_FREE (next_cmd);
1875 free (next_cmd);
1876 free (cur_cmd);
1877 break;
1878 case ' ':
1879 if (s) {
1880 out = sdb_querys (s, NULL, 0, input + 1);
1881 if (out) {
1882 r_cons_print (out);
1883 }
1884 R_FREE (out);
1885 }
1886 break;
1887 //case 's': r_pair_save (s, input + 3); break;
1888 //case 'l': r_pair_load (sdb, input + 3); break;
1889 case '\0':
1890 sdb_foreach (s, callback_foreach_kv, NULL);
1891 break;
1892 // TODO: add command to list all namespaces // sdb_ns_foreach ?
1893 case 's': // "ks"
1894 if (core->http_up) {
1895 return false;
1896 }
1897 if (!r_cons_is_interactive ()) {
1898 return false;
1899 }
1900 if (input[1] == ' ') {
1901 char *n, *o, *p = strdup (input + 2);
1902 // TODO: slash split here? or inside sdb_ns ?
1903 for (n = o = p; n; o = n) {
1904 n = strchr (o, '/'); // SDB_NS_SEPARATOR NAMESPACE
1905 if (n) {
1906 *n++ = 0;
1907 }
1908 s = sdb_ns (s, o, 1);
1909 }
1910 free (p);
1911 }
1912 if (!s) {
1913 s = core->sdb;
1914 }
1915 RLine *line = core->cons->line;
1916 if (!line->sdbshell_hist) {
1917 line->sdbshell_hist = r_list_newf (free);
1918 r_list_append (line->sdbshell_hist, r_str_new ("\0"));
1919 }
1920 RList *sdb_hist = line->sdbshell_hist;
1921 r_line_set_hist_callback (line, &r_line_hist_sdb_up, &r_line_hist_sdb_down);
1922 for (;;) {
1923 r_line_set_prompt (p);
1924 if (r_cons_fgets (buf, sizeof (buf), 0, NULL) < 1) {
1925 break;
1926 }
1927 if (!*buf) {
1928 break;
1929 }
1930 if (sdb_hist) {
1931 if ((r_list_length (sdb_hist) == 1) || (r_list_length (sdb_hist) > 1 && strcmp (r_list_get_n (sdb_hist, 1), buf))) {
1932 r_list_insert (sdb_hist, 1, strdup (buf));
1933 }
1934 line->sdbshell_hist_iter = sdb_hist->head;
1935 }
1936 out = sdb_querys (s, NULL, 0, buf);
1937 if (out) {
1938 r_cons_println (out);
1939 r_cons_flush ();
1940 }
1941 }
1942 r_line_set_hist_callback (core->cons->line, &r_line_hist_cmd_up, &r_line_hist_cmd_down);
1943 break;
1944 case 'o': // "ko"
1945 if (r_sandbox_enable (0)) {
1946 eprintf ("This command is disabled in sandbox mode\n");
1947 return 0;
1948 }
1949 if (input[1] == ' ') {
1950 char *fn = strdup (input + 2);
1951 if (!fn) {
1952 eprintf("Unable to allocate memory\n");
1953 return 0;
1954 }
1955 char *ns = strchr (fn, ' ');
1956 if (ns) {
1957 Sdb *db;
1958 *ns++ = 0;
1959 if (r_file_exists (fn)) {
1960 db = sdb_ns_path (core->sdb, ns, 1);
1961 if (db) {
1962 Sdb *newdb = sdb_new (NULL, fn, 0);
1963 if (newdb) {
1964 sdb_drain (db, newdb);
1965 } else {
1966 eprintf ("Cannot open sdb '%s'\n", fn);
1967 }
1968 } else {
1969 eprintf ("Cannot find sdb '%s'\n", ns);
1970 }
1971 } else {
1972 eprintf ("Cannot open file\n");
1973 }
1974 } else {
1975 eprintf ("Missing sdb namespace\n");
1976 }
1977 free (fn);
1978 } else {
1979 eprintf ("Usage: ko [file] [namespace]\n");
1980 }
1981 break;
1982 case 'd': // "kd"
1983 if (r_sandbox_enable (0)) {
1984 eprintf ("This command is disabled in sandbox mode\n");
1985 return 0;
1986 }
1987 if (input[1] == ' ') {
1988 char *fn = strdup (input + 2);
1989 char *ns = strchr (fn, ' ');
1990 if (ns) {
1991 *ns++ = 0;
1992 Sdb *db = sdb_ns_path (core->sdb, ns, 0);
1993 if (db) {
1994 sdb_file (db, fn);
1995 sdb_sync (db);
1996 } else {
1997 eprintf ("Cannot find sdb '%s'\n", ns);
1998 }
1999 } else {
2000 eprintf ("Missing sdb namespace\n");
2001 }
2002 free (fn);
2003 } else {
2004 eprintf ("Usage: kd [file] [namespace]\n");
2005 }
2006 break;
2007 case '?':
2008 r_core_cmd_help (core, help_msg_k);
2009 break;
2010 }
2011
2012 if (input[0] == '\0') {
2013 /* nothing more to do, the command has been parsed. */
2014 return 0;
2015 }
2016
2017 sp = strchr (input + 1, ' ');
2018 if (sp) {
2019 char *inp = strdup (input);
2020 inp [(size_t)(sp - input)] = 0;
2021 s = sdb_ns (core->sdb, inp + 1, 1);
2022 out = sdb_querys (s, NULL, 0, sp + 1);
2023 if (out) {
2024 r_cons_println (out);
2025 free (out);
2026 }
2027 free (inp);
2028 return 0;
2029 }
2030 return 0;
2031 }
2032
cmd_bsize(void * data,const char * input)2033 static int cmd_bsize(void *data, const char *input) {
2034 ut64 n;
2035 RFlagItem *flag;
2036 RCore *core = (RCore *)data;
2037 switch (input[0]) {
2038 case 'm': // "bm"
2039 n = r_num_math (core->num, input + 1);
2040 if (n > 1) {
2041 core->blocksize_max = n;
2042 } else {
2043 r_cons_printf ("0x%x\n", (ut32)core->blocksize_max);
2044 }
2045 break;
2046 case '+': // "b+"
2047 n = r_num_math (core->num, input + 1);
2048 r_core_block_size (core, core->blocksize + n);
2049 break;
2050 case '-': // "b-"
2051 n = r_num_math (core->num, input + 1);
2052 r_core_block_size (core, core->blocksize - n);
2053 break;
2054 case 'f': // "bf"
2055 if (input[1] == ' ') {
2056 flag = r_flag_get (core->flags, input + 2);
2057 if (flag) {
2058 r_core_block_size (core, flag->size);
2059 } else {
2060 eprintf ("bf: cannot find flag named '%s'\n", input + 2);
2061 }
2062 } else {
2063 eprintf ("Usage: bf [flagname]\n");
2064 }
2065 break;
2066 case 'j': { // "bj"
2067 PJ * pj = pj_new ();
2068 if (!pj) {
2069 break;
2070 }
2071 pj_o (pj);
2072 pj_ki (pj, "blocksize", core->blocksize);
2073 pj_ki (pj, "blocksize_limit", core->blocksize_max);
2074 pj_end (pj);
2075 r_cons_println (pj_string (pj));
2076 pj_free (pj);
2077 break;
2078 }
2079 case '*': // "b*"
2080 r_cons_printf ("b 0x%x\n", core->blocksize);
2081 break;
2082 case '\0': // "b"
2083 r_cons_printf ("0x%x\n", core->blocksize);
2084 break;
2085 case ' ':
2086 r_core_block_size (core, r_num_math (core->num, input));
2087 break;
2088 default:
2089 case '?': // "b?"
2090 r_core_cmd_help (core, help_msg_b);
2091 break;
2092 }
2093 return 0;
2094 }
2095
__runMain(RMainCallback cb,const char * arg)2096 static int __runMain(RMainCallback cb, const char *arg) {
2097 char *a = r_str_trim_dup (arg);
2098 int argc = 0;
2099 char **args = r_str_argv (a, &argc);
2100 int res = cb (argc, (const char **)args);
2101 free (args);
2102 free (a);
2103 return res;
2104 }
2105
cmd_r2cmd(RCore * core,const char * _input)2106 static bool cmd_r2cmd(RCore *core, const char *_input) {
2107 char *input = r_str_newf ("r%s", _input);
2108 int rc = 0;
2109 if (r_str_startswith (input, "rax2")) {
2110 rc = __runMain (core->r_main_rax2, input);
2111 } else if (r_str_startswith (input, "r2")) {
2112 r_sys_cmdf ("%s", input);
2113 // rc = __runMain (core->r_main_radare2, input);
2114 } else if (r_str_startswith (input, "radare2")) {
2115 r_sys_cmdf ("%s", input);
2116 // rc = __runMain (core->r_main_radare2, input);
2117 } else if (r_str_startswith (input, "rasm2")) {
2118 r_sys_cmdf ("%s", input);
2119 // rc = __runMain (core->r_main_rasm2, input);
2120 } else if (r_str_startswith (input, "rabin2")) {
2121 r_sys_cmdf ("%s", input);
2122 // rc = __runMain (core->r_main_rabin2, input);
2123 } else if (r_str_startswith (input, "ragg2")) {
2124 r_sys_cmdf ("%s", input);
2125 // rc = __runMain (core->r_main_ragg2, input);
2126 } else if (r_str_startswith (input, "r2pm")) {
2127 r_sys_cmdf ("%s", input);
2128 // rc = __runMain (core->r_main_r2pm, input);
2129 } else if (r_str_startswith (input, "radiff2")) {
2130 rc = __runMain (core->r_main_radiff2, input);
2131 } else {
2132 const char *r2cmds[] = {
2133 "rax2", "r2pm", "rasm2", "rabin2", "rahash2", "rafind2", "rarun2", "ragg2", "radare2", "r2", NULL
2134 };
2135 int i;
2136 for (i = 0; r2cmds[i]; i++) {
2137 if (r_str_startswith (input, r2cmds[i])) {
2138 free (input);
2139 return true;
2140 }
2141 }
2142 free (input);
2143 return false;
2144 }
2145 free (input);
2146 core->num->value = rc;
2147 return true;
2148 }
2149
cmd_rebase(RCore * core,const char * input)2150 static int cmd_rebase(RCore *core, const char *input) {
2151 ut64 addr = r_num_math (core->num, input);
2152 if (!addr) {
2153 r_cons_printf ("Usage: rb oldbase @ newbase\n");
2154 return 0;
2155 }
2156 // old base = addr
2157 // new base = core->offset
2158 r_debug_bp_rebase (core->dbg, addr, core->offset);
2159 r_bin_set_baddr (core->bin, core->offset);
2160 r_flag_move (core->flags, addr, core->offset);
2161 r_core_cmd0 (core, ".is*");
2162 r_core_cmd0 (core, ".iM*");
2163 r_core_cmd0 (core, ".ii*");
2164 r_core_cmd0 (core, ".iz*");
2165 // TODO: r_anal_move :??
2166 // TODO: differentiate analysis by map ranges (associated with files or memory maps)
2167 return 0;
2168 }
2169
cmd_resize(void * data,const char * input)2170 static int cmd_resize(void *data, const char *input) {
2171 RCore *core = (RCore *)data;
2172 ut64 newsize = 0;
2173 st64 delta = 0;
2174 int grow, ret;
2175
2176 if (cmd_r2cmd (core, input)) {
2177 return true;
2178 }
2179
2180 ut64 oldsize = (core->io->desc) ? r_io_fd_size (core->io, core->io->desc->fd): 0;
2181 switch (*input) {
2182 case 'a': // "r..."
2183 if (r_str_startswith (input, "adare2")) {
2184 __runMain (core->r_main_radare2, input - 1);
2185 }
2186 return true;
2187 case 'b': // "rb" rebase
2188 return cmd_rebase (core, input + 1);
2189 case '2': // "r2" // XXX should be handled already in cmd_r2cmd()
2190 // TODO: use argv[0] instead of 'radare2'
2191 // TODO: { char **argv = { "r2", NULL }; r_main_radare2 (1, argv); }
2192 r_sys_cmdf ("radare%s", input);
2193 return true;
2194 case 'm': // "rm"
2195 if (input[1] == ' ') {
2196 const char *file = r_str_trim_head_ro (input + 2);
2197 if (*file == '$') {
2198 r_cmd_alias_del (core->rcmd, file);
2199 } else {
2200 r_file_rm (file);
2201 }
2202 } else {
2203 eprintf ("Usage: rm [file] # removes a file\n");
2204 }
2205 return true;
2206 case '\0':
2207 if (core->io->desc) {
2208 if (oldsize != -1) {
2209 r_cons_printf ("%"PFMT64d"\n", oldsize);
2210 }
2211 }
2212 return true;
2213 case 'j': { // "rj"
2214 PJ * pj = pj_new ();
2215 pj_o (pj);
2216 if (oldsize != -1) {
2217 pj_kn (pj, "size", oldsize);
2218 }
2219 pj_end (pj);
2220 char *s = pj_drain (pj);
2221 r_cons_println (s);
2222 free (s);
2223 return true;
2224 }
2225 case 'h':
2226 if (core->io->desc) {
2227 if (oldsize != -1) {
2228 char humansz[8];
2229 r_num_units (humansz, sizeof (humansz), oldsize);
2230 r_cons_printf ("%s\n", humansz);
2231 }
2232 }
2233 return true;
2234 case '+': // "r+"
2235 case '-': // "r-"
2236 delta = (st64)r_num_math (core->num, input);
2237 newsize = oldsize + delta;
2238 break;
2239 case ' ': // "r "
2240 newsize = r_num_math (core->num, input + 1);
2241 if (newsize == 0) {
2242 if (input[1] == '0') {
2243 eprintf ("Invalid size\n");
2244 }
2245 return false;
2246 }
2247 break;
2248 case 'e':
2249 {
2250 int rc = write (1, Color_RESET_TERMINAL, strlen (Color_RESET_TERMINAL));
2251 if (rc == -1) {
2252 return false;
2253 }
2254 }
2255 return true;
2256 case '?': // "r?"
2257 default:
2258 r_core_cmd_help (core, help_msg_r);
2259 return true;
2260 }
2261
2262 grow = (newsize > oldsize);
2263 if (grow) {
2264 ret = r_io_resize (core->io, newsize);
2265 if (ret < 1) {
2266 eprintf ("r_io_resize: cannot resize\n");
2267 }
2268 }
2269 if (delta && core->offset < newsize) {
2270 r_io_shift (core->io, core->offset, grow?newsize:oldsize, delta);
2271 }
2272 if (!grow) {
2273 ret = r_io_resize (core->io, newsize);
2274 if (ret < 1) {
2275 eprintf ("r_io_resize: cannot resize\n");
2276 }
2277 }
2278 if (newsize < core->offset+core->blocksize || oldsize < core->offset + core->blocksize) {
2279 r_core_block_read (core);
2280 }
2281 return true;
2282 }
2283
cmd_panels(void * data,const char * input)2284 static int cmd_panels(void *data, const char *input) {
2285 RCore *core = (RCore*) data;
2286 if (core->vmode) {
2287 return false;
2288 }
2289 if (*input == '?') {
2290 r_core_cmd_help (core, help_msg_v);
2291 return false;
2292 }
2293 if (!r_cons_is_interactive ()) {
2294 eprintf ("Panel mode requires scr.interactive=true.\n");
2295 return false;
2296 }
2297 if (*input == ' ') {
2298 if (core->panels) {
2299 r_core_panels_load (core, input + 1);
2300 }
2301 r_config_set (core->config, "scr.layout", input + 1);
2302 return true;
2303 }
2304 if (*input == '=') {
2305 r_core_panels_save (core, input + 1);
2306 r_config_set (core->config, "scr.layout", input + 1);
2307 return true;
2308 }
2309 if (*input == 'i') {
2310 char *sp = strchr (input, ' ');
2311 if (sp) {
2312 char *r = r_core_editor (core, sp + 1, NULL);
2313 if (r) {
2314 free (r);
2315 } else {
2316 eprintf ("Cannot open file (%s)\n", sp + 1);
2317 }
2318 }
2319 ////r_sys_cmdf ("v%s", input);
2320 return false;
2321 }
2322 r_core_panels_root (core, core->panels_root);
2323 return true;
2324 }
2325
cmd_visual(void * data,const char * input)2326 static int cmd_visual(void *data, const char *input) {
2327 RCore *core = (RCore*) data;
2328 if (core->http_up) {
2329 return false;
2330 }
2331 if (!r_cons_is_interactive ()) {
2332 eprintf ("Visual mode requires scr.interactive=true.\n");
2333 return false;
2334 }
2335 return r_core_visual ((RCore *)data, input);
2336 }
2337
cmd_pipein(void * user,const char * input)2338 static int cmd_pipein(void *user, const char *input) {
2339 char *buf = strdup (input);
2340 int len = r_str_unescape (buf);
2341 r_cons_readpush (buf, len);
2342 free (buf);
2343 return 0;
2344 }
2345
cmd_tasks(void * data,const char * input)2346 static int cmd_tasks(void *data, const char *input) {
2347 RCore *core = (RCore*) data;
2348 switch (input[0]) {
2349 case '\0': // "&"
2350 case 'j': // "&j"
2351 r_core_task_list (core, *input);
2352 break;
2353 case 'b': { // "&b"
2354 if (r_sandbox_enable (0)) {
2355 eprintf ("This command is disabled in sandbox mode\n");
2356 return 0;
2357 }
2358 int tid = r_num_math (core->num, input + 1);
2359 if (tid) {
2360 r_core_task_break (&core->tasks, tid);
2361 }
2362 break;
2363 }
2364 case '&': { // "&&"
2365 if (r_sandbox_enable (0)) {
2366 eprintf ("This command is disabled in sandbox mode\n");
2367 return 0;
2368 }
2369 int tid = r_num_math (core->num, input + 1);
2370 r_core_task_join (&core->tasks, core->tasks.current_task, tid ? tid : -1);
2371 break;
2372 }
2373 case '=': { // "&="
2374 // r_core_task_list (core, '=');
2375 int tid = r_num_math (core->num, input + 1);
2376 if (tid) {
2377 RCoreTask *task = r_core_task_get_incref (&core->tasks, tid);
2378 if (task) {
2379 if (task->res) {
2380 r_cons_println (task->res);
2381 }
2382 r_core_task_decref (task);
2383 } else {
2384 eprintf ("Cannot find task\n");
2385 }
2386 }
2387 break;
2388 }
2389 case '-': // "&-"
2390 if (r_sandbox_enable (0)) {
2391 eprintf ("This command is disabled in sandbox mode\n");
2392 return 0;
2393 }
2394 if (input[1] == '*') {
2395 r_core_task_del_all_done (&core->tasks);
2396 } else {
2397 r_core_task_del (&core->tasks, r_num_math (core->num, input + 1));
2398 }
2399 break;
2400 case '?': // "&?"
2401 default:
2402 helpCmdTasks (core);
2403 break;
2404 case ' ': // "& "
2405 case '_': // "&_"
2406 case 't': { // "&t"
2407 if (r_sandbox_enable (0)) {
2408 eprintf ("This command is disabled in sandbox mode\n");
2409 return 0;
2410 }
2411 RCoreTask *task = r_core_task_new (core, true, input + 1, NULL, core);
2412 if (!task) {
2413 break;
2414 }
2415 task->transient = input[0] == 't';
2416 r_core_task_enqueue (&core->tasks, task);
2417 break;
2418 }
2419 }
2420 return 0;
2421 }
2422
cmd_pointer(void * data,const char * input)2423 static int cmd_pointer(void *data, const char *input) {
2424 RCore *core = (RCore*) data;
2425 int ret = true;
2426 char *str, *eq;
2427 input = r_str_trim_head_ro (input);
2428 while (*input == ' ') {
2429 input++;
2430 }
2431 if (!*input || *input == '?') {
2432 r_core_cmd_help (core, help_msg_star);
2433 return ret;
2434 }
2435 str = strdup (input);
2436 eq = strchr (str, '=');
2437 if (eq) {
2438 *eq++ = 0;
2439 if (!strncmp (eq, "0x", 2)) {
2440 ret = r_core_cmdf (core, "wv %s@%s", eq, str);
2441 } else {
2442 ret = r_core_cmdf (core, "wx %s@%s", eq, str);
2443 }
2444 } else {
2445 ret = r_core_cmdf (core, "?v [%s]", input);
2446 }
2447 free (str);
2448 return ret;
2449 }
2450
cmd_env(void * data,const char * input)2451 static int cmd_env(void *data, const char *input) {
2452 RCore *core = (RCore*)data;
2453 int ret = true;
2454 switch (*input) {
2455 case '?':
2456 cmd_help_percent (core);
2457 break;
2458 default:
2459 ret = r_core_cmdf (core, "env %s", input);
2460 }
2461 return ret;
2462 }
2463
2464 static struct autocomplete_flag_map_t {
2465 const char* name;
2466 const char* desc;
2467 int type;
2468 } autocomplete_flags [] = {
2469 { "$dflt", "default autocomplete flag", R_CORE_AUTOCMPLT_DFLT },
2470 { "$flag", "shows known flag hints", R_CORE_AUTOCMPLT_FLAG },
2471 { "$flsp", "shows known flag-spaces hints", R_CORE_AUTOCMPLT_FLSP },
2472 { "$seek", "shows the seek hints", R_CORE_AUTOCMPLT_SEEK },
2473 { "$fcn", "shows the functions hints", R_CORE_AUTOCMPLT_FCN },
2474 { "$zign", "shows known zignatures hints", R_CORE_AUTOCMPLT_ZIGN },
2475 { "$eval", "shows known evals hints", R_CORE_AUTOCMPLT_EVAL },
2476 { "$prjt", "shows known projects hints", R_CORE_AUTOCMPLT_PRJT },
2477 { "$mins", NULL, R_CORE_AUTOCMPLT_MINS },
2478 { "$brkp", "shows known breakpoints hints", R_CORE_AUTOCMPLT_BRKP },
2479 { "$macro", NULL, R_CORE_AUTOCMPLT_MACR },
2480 { "$file", "hints file paths", R_CORE_AUTOCMPLT_FILE },
2481 { "$thme", "shows known themes hints", R_CORE_AUTOCMPLT_THME },
2482 { "$optn", "allows the selection for multiple options", R_CORE_AUTOCMPLT_OPTN },
2483 { "$ms", "shows mount hints", R_CORE_AUTOCMPLT_MS},
2484 { "$sdb", "shows sdb hints", R_CORE_AUTOCMPLT_SDB},
2485 { NULL, NULL, 0 }
2486 };
2487
print_dict(RCoreAutocomplete * a,int sub)2488 static inline void print_dict(RCoreAutocomplete* a, int sub) {
2489 if (!a) {
2490 return;
2491 }
2492 int i, j;
2493 const char* name = "unknown";
2494 for (i = 0; i < a->n_subcmds; i++) {
2495 RCoreAutocomplete* b = a->subcmds[i];
2496 if (b->locked) {
2497 continue;
2498 }
2499 for (j = 0; j < R_CORE_AUTOCMPLT_END; j++) {
2500 if (b->type == autocomplete_flags[j].type) {
2501 name = autocomplete_flags[j].name;
2502 break;
2503 }
2504 }
2505 eprintf ("[%3d] %s: '%s'\n", sub, name, b->cmd);
2506 print_dict (a->subcmds[i], sub + 1);
2507 }
2508 }
2509
autocomplete_type(const char * strflag)2510 static int autocomplete_type(const char* strflag) {
2511 int i;
2512 for (i = 0; i < R_CORE_AUTOCMPLT_END; i++) {
2513 if (autocomplete_flags[i].desc && !strncmp (strflag, autocomplete_flags[i].name, 5)) {
2514 return autocomplete_flags[i].type;
2515 }
2516 }
2517 eprintf ("Invalid flag '%s'\n", strflag);
2518 return R_CORE_AUTOCMPLT_END;
2519 }
2520
cmd_autocomplete_help(RCore * core)2521 static void cmd_autocomplete_help(RCore *core) {
2522 r_core_cmd_help (core, help_msg_triple_exclamation);
2523 // non-zero-cost survival without iterators 101
2524 const char **help = calloc (R_CORE_AUTOCMPLT_END + 1, 3 * sizeof (char *));
2525 int i;
2526 size_t n;
2527 for (i = 0, n = 0; i < R_CORE_AUTOCMPLT_END; i++) {
2528 if (autocomplete_flags[i].desc) {
2529 // highlight "$" as cmd and the rest of the name as args
2530 help[n + 0] = "$";
2531 help[n + 1] = autocomplete_flags[i].name + 1;
2532 help[n + 2] = autocomplete_flags[i].desc;
2533 n += 3;
2534 }
2535 }
2536 r_core_cmd_help (core, help);
2537 free (help);
2538 }
2539
cmd_autocomplete(RCore * core,const char * input)2540 static void cmd_autocomplete(RCore *core, const char *input) {
2541 RCoreAutocomplete* b = core->autocomplete;
2542 input = r_str_trim_head_ro (input);
2543 char arg[256];
2544 if (!*input) {
2545 print_dict (core->autocomplete, 0);
2546 return;
2547 }
2548 if (*input == '?') {
2549 cmd_autocomplete_help (core);
2550 return;
2551 }
2552 if (*input == '-') {
2553 const char *arg = input + 1;
2554 if (!*input) {
2555 eprintf ("Use !!!-* or !!!-<cmd>\n");
2556 return;
2557 }
2558 r_core_autocomplete_remove (b, arg);
2559 return;
2560 }
2561 while (b) {
2562 const char* end = r_str_trim_head_wp (input);
2563 if (!end) {
2564 break;
2565 }
2566 if ((end - input) >= sizeof (arg)) {
2567 // wtf?
2568 eprintf ("Exceeded the max arg length (255).\n");
2569 return;
2570 }
2571 if (end == input) {
2572 break;
2573 }
2574 memcpy (arg, input, end - input);
2575 arg[end - input] = 0;
2576 RCoreAutocomplete* a = r_core_autocomplete_find (b, arg, true);
2577 input = r_str_trim_head_ro (end);
2578 if (input && *input && !a) {
2579 if (b->type == R_CORE_AUTOCMPLT_DFLT && !(b = r_core_autocomplete_add (b, arg, R_CORE_AUTOCMPLT_DFLT, false))) {
2580 eprintf ("ENOMEM\n");
2581 return;
2582 } else if (b->type != R_CORE_AUTOCMPLT_DFLT) {
2583 eprintf ("Cannot add autocomplete to '%s'. type not $dflt\n", b->cmd);
2584 return;
2585 }
2586 } else if ((!input || !*input) && !a) {
2587 if (arg[0] == '$') {
2588 int type = autocomplete_type (arg);
2589 if (type != R_CORE_AUTOCMPLT_END && !b->locked && !b->n_subcmds) {
2590 b->type = type;
2591 } else if (b->locked || b->n_subcmds) {
2592 if (!b->cmd) {
2593 return;
2594 }
2595 eprintf ("Changing type of '%s' is forbidden.\n", b->cmd);
2596 }
2597 } else {
2598 if (!r_core_autocomplete_add (b, arg, R_CORE_AUTOCMPLT_DFLT, false)) {
2599 eprintf ("ENOMEM\n");
2600 return;
2601 }
2602 }
2603 return;
2604 } else if ((!input || !*input) && a) {
2605 // eprintf ("Cannot add '%s'. Already exists.\n", arg);
2606 return;
2607 } else {
2608 b = a;
2609 }
2610 }
2611 eprintf ("Invalid usage of !!!\n");
2612 }
2613
cmd_last(void * data,const char * input)2614 static int cmd_last(void *data, const char *input) {
2615 switch (*input) {
2616 case 0:
2617 r_cons_last ();
2618 break;
2619 default:
2620 eprintf ("Usage: _ print last output\n");
2621 }
2622 return 0;
2623 }
2624
cmd_system(void * data,const char * input)2625 static int cmd_system(void *data, const char *input) {
2626 RCore *core = (RCore*)data;
2627 ut64 n;
2628 int ret = 0;
2629 switch (*input) {
2630 case '-': //!-
2631 if (input[1]) {
2632 r_line_hist_free();
2633 r_line_hist_save (R2_HOME_HISTORY);
2634 } else {
2635 r_line_hist_free();
2636 }
2637 break;
2638 case '=': //!=
2639 if (input[1] == '?') {
2640 r_cons_printf ("Usage: !=[!] - enable/disable remote commands\n");
2641 } else {
2642 if (!r_sandbox_enable (0)) {
2643 R_FREE (core->cmdremote);
2644 }
2645 }
2646 break;
2647 case '!': //!!
2648 if (input[1] == '!') { // !!! & !!!-
2649 cmd_autocomplete (core, input + 2);
2650 } else if (input[1] == '?') {
2651 cmd_help_exclamation (core);
2652 } else if (input[1] == '*') {
2653 char *cmd = r_str_trim_dup (input + 1);
2654 (void)r_core_cmdf (core, "\"#!pipe %s\"", cmd);
2655 free (cmd);
2656 } else {
2657 if (r_sandbox_enable (0)) {
2658 eprintf ("This command is disabled in sandbox mode\n");
2659 return 0;
2660 }
2661 if (input[1]) {
2662 int olen;
2663 char *out = NULL;
2664 char *cmd = r_core_sysenv_begin (core, input);
2665 if (cmd) {
2666 void *bed = r_cons_sleep_begin ();
2667 ret = r_sys_cmd_str_full (cmd + 1, NULL, &out, &olen, NULL);
2668 r_cons_sleep_end (bed);
2669 r_core_sysenv_end (core, input);
2670 r_cons_memcat (out, olen);
2671 free (out);
2672 free (cmd);
2673 } //else eprintf ("Error setting up system environment\n");
2674 } else {
2675 eprintf ("History saved to "R2_HOME_HISTORY"\n");
2676 r_line_hist_save (R2_HOME_HISTORY);
2677 }
2678 }
2679 break;
2680 case '\0':
2681 r_line_hist_list ();
2682 break;
2683 case '?': //!?
2684 cmd_help_exclamation (core);
2685 break;
2686 case '*':
2687 // TODO: use the api
2688 {
2689 char *cmd = r_str_trim_dup (input + 1);
2690 cmd = r_str_replace (cmd, " ", "\\ ", true);
2691 cmd = r_str_replace (cmd, "\\ ", " ", false);
2692 cmd = r_str_replace (cmd, "\"", "'", false);
2693 ret = r_core_cmdf (core, "\"#!pipe %s\"", cmd);
2694 free (cmd);
2695 }
2696 break;
2697 default:
2698 n = atoi (input);
2699 if (*input == '0' || n > 0) {
2700 const char *cmd = r_line_hist_get (n);
2701 if (cmd) {
2702 r_core_cmd0 (core, cmd);
2703 }
2704 //else eprintf ("Error setting up system environment\n");
2705 } else {
2706 char *cmd = r_core_sysenv_begin (core, input);
2707 if (cmd) {
2708 void *bed = r_cons_sleep_begin ();
2709 ret = r_sys_cmd (cmd);
2710 r_cons_sleep_end (bed);
2711 r_core_sysenv_end (core, input);
2712 free (cmd);
2713 } else {
2714 eprintf ("Error setting up system environment\n");
2715 }
2716 }
2717 break;
2718 }
2719 return ret;
2720 }
2721
unescape_special_chars(const char * s,const char * special_chars)2722 static char *unescape_special_chars(const char *s, const char *special_chars) {
2723 char *dst = R_NEWS (char, strlen (s) + 1);
2724 int i, j = 0;
2725
2726 for (i = 0; s[i]; i++) {
2727 if (s[i] != '\\' || !strchr (special_chars, s[i + 1])) {
2728 dst[j++] = s[i];
2729 continue;
2730 }
2731 dst[j++] = s[i + 1];
2732 i++;
2733 }
2734 dst[j++] = '\0';
2735 return dst;
2736 }
2737
2738 #if __WINDOWS__
2739 #include <tchar.h>
2740 #define __CLOSE_DUPPED_PIPES() \
2741 close (1); \
2742 close (fd_out); \
2743 fd_out = -1;
2744
r_w32_cmd_pipe(RCore * core,char * radare_cmd,char * shell_cmd)2745 static void r_w32_cmd_pipe(RCore *core, char *radare_cmd, char *shell_cmd) {
2746 STARTUPINFO si = {0};
2747 PROCESS_INFORMATION pi = {0};
2748 SECURITY_ATTRIBUTES sa;
2749 HANDLE pipe[2] = {NULL, NULL};
2750 int fd_out = -1, cons_out = -1;
2751 char *_shell_cmd = NULL;
2752 LPTSTR _shell_cmd_ = NULL;
2753 DWORD mode;
2754 TCHAR *systemdir = NULL;
2755 GetConsoleMode (GetStdHandle (STD_OUTPUT_HANDLE), &mode);
2756
2757 sa.nLength = sizeof (SECURITY_ATTRIBUTES);
2758 sa.bInheritHandle = TRUE;
2759 sa.lpSecurityDescriptor = NULL;
2760 if (!CreatePipe (&pipe[0], &pipe[1], &sa, 0)) {
2761 r_sys_perror ("r_w32_cmd_pipe/CreatePipe");
2762 goto err_r_w32_cmd_pipe;
2763 }
2764 if (!SetHandleInformation (pipe[1], HANDLE_FLAG_INHERIT, 0)) {
2765 r_sys_perror ("r_w32_cmd_pipe/SetHandleInformation");
2766 goto err_r_w32_cmd_pipe;
2767 }
2768 si.hStdError = GetStdHandle (STD_ERROR_HANDLE);
2769 si.hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE);
2770 si.hStdInput = pipe[0];
2771 si.dwFlags |= STARTF_USESTDHANDLES;
2772 si.cb = sizeof (si);
2773 _shell_cmd = shell_cmd;
2774 while (*_shell_cmd && isspace ((ut8)*_shell_cmd)) {
2775 _shell_cmd++;
2776 }
2777 char *tmp = r_str_newf ("/Q /c \"%s\"", _shell_cmd);
2778 if (!tmp) {
2779 goto err_r_w32_cmd_pipe;
2780 }
2781 _shell_cmd = tmp;
2782 _shell_cmd_ = r_sys_conv_utf8_to_win (_shell_cmd);
2783 free (tmp);
2784 if (!_shell_cmd_) {
2785 goto err_r_w32_cmd_pipe;
2786 }
2787 systemdir = calloc (MAX_PATH, sizeof (TCHAR));
2788 if (!systemdir) {
2789 goto err_r_w32_cmd_pipe;
2790 }
2791 int ret = GetSystemDirectory (systemdir, MAX_PATH);
2792 if (!ret) {
2793 r_sys_perror ("r_w32_cmd_pipe/systemdir");
2794 goto err_r_w32_cmd_pipe;
2795 }
2796 _tcscat_s (systemdir, MAX_PATH, TEXT("\\cmd.exe"));
2797 // exec windows process
2798 if (!CreateProcess (systemdir, _shell_cmd_, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) {
2799 r_sys_perror ("r_w32_cmd_pipe/CreateProcess");
2800 goto err_r_w32_cmd_pipe;
2801 }
2802 fd_out = _open_osfhandle ((intptr_t)pipe[1], _O_WRONLY|_O_TEXT);
2803 if (fd_out == -1) {
2804 perror ("_open_osfhandle");
2805 goto err_r_w32_cmd_pipe;
2806 }
2807 cons_out = dup (1);
2808 dup2 (fd_out, 1);
2809 // exec radare command
2810 r_core_cmd (core, radare_cmd, 0);
2811
2812 HANDLE th = CreateThread (NULL, 0,(LPTHREAD_START_ROUTINE) r_cons_flush, NULL, 0, NULL);
2813 if (!th) {
2814 __CLOSE_DUPPED_PIPES ();
2815 goto err_r_w32_cmd_pipe;
2816 }
2817 while (true) {
2818 int ret = WaitForSingleObject (th, 50);
2819 if (!ret) {
2820 // Successfully written everything to pipe
2821 __CLOSE_DUPPED_PIPES ();
2822 WaitForSingleObject (pi.hProcess, INFINITE);
2823 break;
2824 }
2825 ret = WaitForSingleObject (pi.hProcess, 50);
2826 if (!ret) {
2827 // Process exited before we finished writing to pipe
2828 DWORD exit;
2829 if (GetExitCodeThread (th, &exit) && exit == STILL_ACTIVE) {
2830 CancelSynchronousIo (th);
2831 }
2832 WaitForSingleObject (th, INFINITE);
2833 __CLOSE_DUPPED_PIPES ();
2834 break;
2835 }
2836 }
2837 CloseHandle (th);
2838 err_r_w32_cmd_pipe:
2839 if (pi.hProcess) {
2840 CloseHandle (pi.hProcess);
2841 }
2842 if (pi.hThread) {
2843 CloseHandle (pi.hThread);
2844 }
2845 if (pipe[0]) {
2846 CloseHandle (pipe[0]);
2847 }
2848 if (fd_out != -1) {
2849 close (fd_out);
2850 }
2851 if (cons_out != -1) {
2852 dup2 (cons_out, 1);
2853 close (cons_out);
2854 }
2855 free (systemdir);
2856 free (_shell_cmd_);
2857 SetConsoleMode (GetStdHandle (STD_OUTPUT_HANDLE), mode);
2858 }
2859 #undef __CLOSE_DUPPED_PIPES
2860 #endif
2861
r_core_cmd_pipe(RCore * core,char * radare_cmd,char * shell_cmd)2862 R_API int r_core_cmd_pipe(RCore *core, char *radare_cmd, char *shell_cmd) {
2863 #if __UNIX__
2864 int stdout_fd, fds[2];
2865 int child;
2866 #endif
2867 int si, olen, ret = -1, pipecolor = -1;
2868 char *str, *out = NULL;
2869
2870 if (r_sandbox_enable (0)) {
2871 eprintf ("Pipes are not allowed in sandbox mode\n");
2872 return -1;
2873 }
2874 si = r_cons_is_interactive ();
2875 r_config_set_b (core->config, "scr.interactive", false);
2876 if (!r_config_get_i (core->config, "scr.color.pipe")) {
2877 pipecolor = r_config_get_i (core->config, "scr.color");
2878 r_config_set_i (core->config, "scr.color", COLOR_MODE_DISABLED);
2879 }
2880 if (*shell_cmd=='!') {
2881 r_cons_grep_parsecmd (shell_cmd, "\"");
2882 olen = 0;
2883 out = NULL;
2884 // TODO: implement foo
2885 str = r_core_cmd_str (core, radare_cmd);
2886 r_sys_cmd_str_full (shell_cmd + 1, str, &out, &olen, NULL);
2887 free (str);
2888 r_cons_memcat (out, olen);
2889 free (out);
2890 ret = 0;
2891 }
2892 #if __UNIX__
2893 r_str_trim_head (radare_cmd);
2894 r_str_trim_head (shell_cmd);
2895
2896 r_sys_signal (SIGPIPE, SIG_IGN);
2897 stdout_fd = dup (1);
2898 if (stdout_fd != -1) {
2899 if (pipe (fds) == 0) {
2900 child = r_sys_fork ();
2901 if (child == -1) {
2902 eprintf ("Cannot fork\n");
2903 close (stdout_fd);
2904 } else if (child) {
2905 dup2 (fds[1], 1);
2906 close (fds[1]);
2907 close (fds[0]);
2908 r_core_cmd (core, radare_cmd, 0);
2909 r_cons_flush ();
2910 close (1);
2911 wait (&ret);
2912 dup2 (stdout_fd, 1);
2913 close (stdout_fd);
2914 } else {
2915 close (fds[1]);
2916 dup2 (fds[0], 0);
2917 //dup2 (1, 2); // stderr goes to stdout
2918 r_sandbox_system (shell_cmd, 0);
2919 close (stdout_fd);
2920 }
2921 } else {
2922 eprintf ("r_core_cmd_pipe: Could not pipe\n");
2923 }
2924 }
2925 #elif __WINDOWS__
2926 r_w32_cmd_pipe (core, radare_cmd, shell_cmd);
2927 #else
2928 #ifdef _MSC_VER
2929 #pragma message ("r_core_cmd_pipe UNIMPLEMENTED FOR THIS PLATFORM")
2930 #else
2931 #warning r_core_cmd_pipe UNIMPLEMENTED FOR THIS PLATFORM
2932 #endif
2933 eprintf ("r_core_cmd_pipe: unimplemented for this platform\n");
2934 #endif
2935 if (pipecolor != -1) {
2936 r_config_set_i (core->config, "scr.color", pipecolor);
2937 }
2938 r_config_set_i (core->config, "scr.interactive", si);
2939 return ret;
2940 }
2941
parse_tmp_evals(RCore * core,const char * str)2942 static char *parse_tmp_evals(RCore *core, const char *str) {
2943 char *s = strdup (str);
2944 int i, argc = r_str_split (s, ',');
2945 char *res = strdup ("");
2946 if (!s || !res) {
2947 free (s);
2948 free (res);
2949 return NULL;
2950 }
2951 for (i = 0; i < argc; i++) {
2952 char *eq, *kv = (char *)r_str_word_get0 (s, i);
2953 if (!kv) {
2954 break;
2955 }
2956 eq = strchr (kv, '=');
2957 if (eq) {
2958 *eq = 0;
2959 const char *ov = r_config_get (core->config, kv);
2960 if (!ov) {
2961 continue;
2962 }
2963 char *cmd = r_str_newf ("e %s=%s;", kv, ov);
2964 if (!cmd) {
2965 free (s);
2966 free (res);
2967 return NULL;
2968 }
2969 res = r_str_prepend (res, cmd);
2970 free (cmd);
2971 r_config_set (core->config, kv, eq + 1);
2972 *eq = '=';
2973 } else {
2974 eprintf ("Missing '=' in e: expression (%s)\n", kv);
2975 }
2976 }
2977 free (s);
2978 return res;
2979 }
2980
is_macro_command(const char * ptr)2981 static bool is_macro_command(const char *ptr) {
2982 ptr = r_str_trim_head_ro (ptr);
2983 while (IS_DIGIT (*ptr)) {
2984 ptr++;
2985 }
2986 return *ptr == '(';
2987 }
2988
find_ch_after_macro(char * ptr,char ch)2989 static char *find_ch_after_macro(char *ptr, char ch) {
2990 int depth = 0;
2991 while (*ptr) {
2992 if (depth == 0 && *ptr == ch) {
2993 return ptr;
2994 }
2995 if (*ptr == '(') {
2996 depth++;
2997 } else if (*ptr == ')') {
2998 depth--;
2999 }
3000 ptr++;
3001 }
3002 return NULL;
3003 }
3004
r_core_cmd_subst(RCore * core,char * cmd)3005 static int r_core_cmd_subst(RCore *core, char *cmd) {
3006 ut64 rep = strtoull (cmd, NULL, 10);
3007 int ret = 0, orep;
3008 char *colon = NULL, *icmd = NULL;
3009 bool tmpseek = false;
3010 bool original_tmpseek = core->tmpseek;
3011
3012 if (r_str_startswith (cmd, "GET /cmd/")) {
3013 memmove (cmd, cmd + 9, strlen (cmd + 9) + 1);
3014 char *http = strstr (cmd, "HTTP");
3015 if (http) {
3016 *http = 0;
3017 http--;
3018 if (*http == ' ') {
3019 *http = 0;
3020 }
3021 }
3022 r_cons_printf ("HTTP/1.0 %d %s\r\n%s"
3023 "Connection: close\r\nContent-Length: %d\r\n\r\n",
3024 200, "OK", "", -1);
3025 return r_core_cmd0 (core, cmd);
3026 }
3027
3028 /* must store a local orig_offset because there can be
3029 * nested call of this function */
3030 ut64 orig_offset = core->offset;
3031 icmd = strdup (cmd);
3032 if (!icmd) {
3033 goto beach;
3034 }
3035
3036 if (core->max_cmd_depth - core->cons->context->cmd_depth == 1) {
3037 core->prompt_offset = core->offset;
3038 }
3039 cmd = (char *)r_str_trim_head_ro (icmd);
3040 r_str_trim_tail (cmd);
3041 // lines starting with # are ignored (never reach cmd_hash()), except #! and #?
3042 if (!*cmd) {
3043 if (core->cmdrepeat > 0) {
3044 lastcmd_repeat (core, true);
3045 ret = r_core_cmd_nullcallback (core);
3046 }
3047 goto beach;
3048 }
3049 if (!icmd || (cmd[0] == '#' && cmd[1] != '!' && cmd[1] != '?')) {
3050 goto beach;
3051 }
3052 if (*icmd && !strchr (icmd, '"')) {
3053 char *hash;
3054 for (hash = icmd + 1; *hash; hash++) {
3055 if (*hash == '\\') {
3056 hash++;
3057 if (*hash == '#') {
3058 continue;
3059 } else if (!*hash) {
3060 break;
3061 }
3062 }
3063 if (*hash == '#') {
3064 break;
3065 }
3066 }
3067 if (hash && *hash) {
3068 *hash = 0;
3069 r_str_trim_tail (icmd);
3070 }
3071 }
3072 if (*cmd != '"') {
3073 if (!strchr (cmd, '\'')) { // allow | awk '{foo;bar}' // ignore ; if there's a single quote
3074 if (is_macro_command (cmd)) {
3075 colon = find_ch_after_macro (cmd, ';');
3076 } else {
3077 colon = strchr (cmd, ';');
3078 }
3079 if (colon) {
3080 *colon = 0;
3081 }
3082 }
3083 } else {
3084 colon = NULL;
3085 }
3086 if (rep > 0) {
3087 while (IS_DIGIT (*cmd)) {
3088 cmd++;
3089 }
3090 // do not repeat null cmd
3091 if (!*cmd) {
3092 goto beach;
3093 }
3094 }
3095 if (rep < 1) {
3096 rep = 1;
3097 }
3098 // XXX if output is a pipe then we don't want to be interactive
3099 if (rep > 1 && r_sandbox_enable (0)) {
3100 eprintf ("Command repeat sugar disabled in sandbox mode (%s)\n", cmd);
3101 goto beach;
3102 } else {
3103 if (rep > INTERACTIVE_MAX_REP) {
3104 if (r_cons_is_interactive ()) {
3105 if (!r_cons_yesno ('n', "Are you sure to repeat this %"PFMT64d" times? (y/N)", rep)) {
3106 goto beach;
3107 }
3108 }
3109 }
3110 }
3111 // TODO: store in core->cmdtimes to speedup ?
3112 const char *cmdrep = r_str_get (core->cmdtimes);
3113 orep = rep;
3114
3115 r_cons_break_push (NULL, NULL);
3116
3117 int ocur_enabled = core->print && core->print->cur_enabled;
3118 while (rep-- && *cmd) {
3119 if (core->print) {
3120 core->print->cur_enabled = false;
3121 if (ocur_enabled && core->seltab >= 0) {
3122 if (core->seltab == core->curtab) {
3123 core->print->cur_enabled = true;
3124 }
3125 }
3126 }
3127 if (r_cons_is_breaked ()) {
3128 break;
3129 }
3130 char *cr = strdup (cmdrep);
3131 core->break_loop = false;
3132 ret = r_core_cmd_subst_i (core, cmd, colon, (rep == orep - 1) ? &tmpseek : NULL);
3133 if (*cmd == 's') {
3134 // do not restore tmpseek if the command executed is the 's'eek
3135 tmpseek = false;
3136 }
3137 if (ret && *cmd == 'q') {
3138 free (cr);
3139 goto beach;
3140 }
3141 if (core->break_loop) {
3142 free (cr);
3143 break;
3144 }
3145 if (cr && *cr && orep > 1) {
3146 // XXX: do not flush here, we need r_cons_push () and r_cons_pop()
3147 r_cons_flush ();
3148 // XXX: we must import register flags in C
3149 (void)r_core_cmd0 (core, ".dr*");
3150 (void)r_core_cmd0 (core, cr);
3151 }
3152 free (cr);
3153 }
3154
3155 r_cons_break_pop ();
3156
3157 if (tmpseek) {
3158 r_core_seek (core, orig_offset, true);
3159 core->tmpseek = original_tmpseek;
3160 }
3161 if (core->print) {
3162 core->print->cur_enabled = ocur_enabled;
3163 }
3164 if (colon && colon[1]) {
3165 for (++colon; *colon == ';'; colon++) {
3166 ;
3167 }
3168 r_core_cmd_subst (core, colon);
3169 } else {
3170 if (!*icmd) {
3171 r_core_cmd_nullcallback (core);
3172 }
3173 }
3174 beach:
3175 free (icmd);
3176 return ret;
3177 }
3178
find_eoq(char * p)3179 static char *find_eoq(char *p) {
3180 for (; *p; p++) {
3181 if (*p == '"') {
3182 break;
3183 }
3184 if (*p == '\\' && p[1] == '"') {
3185 p++;
3186 }
3187 }
3188 return p;
3189 }
3190
findSeparator(char * p)3191 static char* findSeparator(char *p) {
3192 char *q = strchr (p, '+');
3193 if (q) {
3194 return q;
3195 }
3196 return strchr (p, '-');
3197 }
3198
tmpenvs_free(void * item)3199 static void tmpenvs_free(void *item) {
3200 r_sys_setenv (item, NULL);
3201 free (item);
3202 }
3203
set_tmp_arch(RCore * core,char * arch,char ** tmparch)3204 static bool set_tmp_arch(RCore *core, char *arch, char **tmparch) {
3205 r_return_val_if_fail (tmparch, false);
3206 *tmparch = strdup (r_config_get (core->config, "asm.arch"));
3207 r_config_set (core->config, "asm.arch", arch);
3208 core->fixedarch = true;
3209 return true;
3210 }
3211
set_tmp_bits(RCore * core,int bits,char ** tmpbits,int * cmd_ignbithints)3212 static bool set_tmp_bits(RCore *core, int bits, char **tmpbits, int *cmd_ignbithints) {
3213 r_return_val_if_fail (tmpbits, false);
3214 *tmpbits = strdup (r_config_get (core->config, "asm.bits"));
3215 r_config_set_i (core->config, "asm.bits", bits);
3216 core->fixedbits = true;
3217 // XXX: why?
3218 *cmd_ignbithints = r_config_get_i (core->config, "anal.ignbithints");
3219 r_config_set_b (core->config, "anal.ignbithints", true);
3220 return true;
3221 }
3222
r_core_cmd_subst_i(RCore * core,char * cmd,char * colon,bool * tmpseek)3223 static int r_core_cmd_subst_i(RCore *core, char *cmd, char *colon, bool *tmpseek) {
3224 RList *tmpenvs = r_list_newf (tmpenvs_free);
3225 const char *quotestr = "`";
3226 const char *tick = NULL;
3227 char *ptr, *ptr2, *str;
3228 char *arroba = NULL;
3229 char *grep = NULL;
3230 RIODesc *tmpdesc = NULL;
3231 int pamode = !core->io->va;
3232 int i, ret = 0, pipefd;
3233 bool usemyblock = false;
3234 int scr_html = -1;
3235 int scr_color = -1;
3236 bool eos = false;
3237 bool haveQuote = false;
3238 bool oldfixedarch = core->fixedarch;
3239 bool oldfixedbits = core->fixedbits;
3240 bool cmd_tmpseek = false;
3241 ut64 tmpbsz = core->blocksize;
3242 int cmd_ignbithints = -1;
3243
3244 if (!cmd) {
3245 r_list_free (tmpenvs);
3246 return 0;
3247 }
3248 r_str_trim (cmd);
3249
3250 char *$0 = strstr (cmd, "$(");
3251 if ($0) {
3252 char *$1 = strchr ($0 + 2, ')');
3253 if ($1) {
3254 *$0 = '`';
3255 *$1 = '`';
3256 memmove ($0 + 1, $0 + 2, strlen ($0 + 2) + 1);
3257 } else {
3258 eprintf ("Unterminated $() block\n");
3259 }
3260 }
3261
3262 /* quoted / raw command */
3263 switch (*cmd) {
3264 case '.':
3265 if (cmd[1] == '"') { /* interpret */
3266 r_list_free (tmpenvs);
3267 return r_cmd_call (core->rcmd, cmd);
3268 }
3269 break;
3270 case '"':
3271 for (; *cmd; ) {
3272 int pipefd = -1;
3273 ut64 oseek = UT64_MAX;
3274 char *line, *p;
3275 haveQuote = *cmd == '"';
3276 if (haveQuote) {
3277 cmd++;
3278 p = *cmd ? find_eoq (cmd) : NULL;
3279 if (!p || !*p) {
3280 eprintf ("Missing \" in (%s).", cmd);
3281 r_list_free (tmpenvs);
3282 return false;
3283 }
3284 *p++ = 0;
3285 if (!*p) {
3286 eos = true;
3287 }
3288 } else {
3289 char *sc = strchr (cmd, ';');
3290 if (sc) {
3291 *sc = 0;
3292 }
3293 r_core_cmd0 (core, cmd);
3294 if (!sc) {
3295 break;
3296 }
3297 cmd = sc + 1;
3298 continue;
3299 }
3300 char op0 = 0;
3301 if (*p) {
3302 // workaround :D
3303 if (p[0] == '@') {
3304 p--;
3305 }
3306 while (p[1] == ';' || IS_WHITESPACE (p[1])) {
3307 p++;
3308 }
3309 if (p[1] == '@' || (p[1] && p[2] == '@')) {
3310 char *q = strchr (p + 1, '"');
3311 if (q) {
3312 op0 = *q;
3313 *q = 0;
3314 }
3315 haveQuote = q != NULL;
3316 oseek = core->offset;
3317 r_core_seek (core, r_num_math (core->num, p + 2), true);
3318 if (q) {
3319 *p = '"';
3320 p = q;
3321 } else {
3322 p = strchr (p + 1, ';');
3323 }
3324 }
3325 if (p && *p && p[1] == '>') {
3326 str = p + 2;
3327 while (*str == '>') {
3328 str++;
3329 }
3330 str = (char *)r_str_trim_head_ro (str);
3331 r_cons_flush ();
3332 const bool append = p[2] == '>';
3333 pipefd = r_cons_pipe_open (str, 1, append);
3334 }
3335 }
3336 line = strdup (cmd);
3337 line = r_str_replace (line, "\\\"", "\"", true);
3338 if (p && *p && p[1] == '|') {
3339 str = (char *)r_str_trim_head_ro (p + 2);
3340 r_core_cmd_pipe (core, cmd, str);
3341 } else {
3342 r_cmd_call (core->rcmd, line);
3343 }
3344 free (line);
3345 if (oseek != UT64_MAX) {
3346 r_core_seek (core, oseek, true);
3347 }
3348 if (pipefd != -1) {
3349 r_cons_flush ();
3350 r_cons_pipe_close (pipefd);
3351 }
3352 if (!p) {
3353 break;
3354 }
3355 if (eos) {
3356 break;
3357 }
3358 if (haveQuote) {
3359 if (*p == ';') {
3360 cmd = p + 1;
3361 } else {
3362 if (*p == '"') {
3363 cmd = p;
3364 } else {
3365 *p = op0;
3366 cmd = p;
3367 }
3368 }
3369 } else {
3370 cmd = p + 1;
3371 }
3372 }
3373 r_list_free (tmpenvs);
3374 return true;
3375 case '(':
3376 if (cmd[1] != '*' && !strstr (cmd, ")()")) {
3377 r_list_free (tmpenvs);
3378 return r_cmd_call (core->rcmd, cmd);
3379 }
3380 break;
3381 case '?':
3382 if (cmd[1] == '>') {
3383 r_core_cmd_help (core, help_msg_greater_sign);
3384 r_list_free (tmpenvs);
3385 return true;
3386 }
3387 }
3388
3389 // TODO must honor `
3390 /* comments */
3391 if (*cmd != '#') {
3392 ptr = (char *)r_str_firstbut (cmd, '#', "`\""); // TODO: use quotestr here
3393 if (ptr && (ptr[1] == ' ' || ptr[1] == '\t')) {
3394 *ptr = '\0';
3395 }
3396 }
3397
3398 /* multiple commands */
3399 // TODO: must honor " and ` boundaries
3400 //ptr = strrchr (cmd, ';');
3401 if (*cmd != '#') {
3402 if (is_macro_command (cmd)) {
3403 ptr = find_ch_after_macro (cmd, ';');
3404 } else {
3405 ptr = (char *)r_str_lastbut (cmd, ';', quotestr);
3406 }
3407 if (colon && ptr) {
3408 int ret ;
3409 *ptr = '\0';
3410 if (r_core_cmd_subst (core, cmd) == -1) {
3411 r_list_free (tmpenvs);
3412 return -1;
3413 }
3414 cmd = ptr + 1;
3415 ret = r_core_cmd_subst (core, cmd);
3416 *ptr = ';';
3417 r_list_free (tmpenvs);
3418 return ret;
3419 //r_cons_flush ();
3420 }
3421 }
3422
3423 // TODO must honor " and `
3424 /* pipe console to shell process */
3425 //ptr = strchr (cmd, '|');
3426 ptr = (char *)r_str_lastbut (cmd, '|', quotestr);
3427 if (ptr) {
3428 if (ptr > cmd) {
3429 char *ch = ptr - 1;
3430 if (*ch == '\\') {
3431 memmove (ch, ptr, strlen (ptr) + 1);
3432 goto escape_pipe;
3433 }
3434 }
3435 char *ptr2 = strchr (cmd, '`');
3436 if (!ptr2 || (ptr2 && ptr2 > ptr)) {
3437 if (!tick || (tick && tick > ptr)) {
3438 *ptr = '\0';
3439 cmd = r_str_trim_nc (cmd);
3440 if (!strcmp (ptr + 1, "?")) { // "|?"
3441 r_core_cmd_help (core, help_msg_vertical_bar);
3442 r_list_free (tmpenvs);
3443 return ret;
3444 } else if (!strncmp (ptr + 1, "H", 1)) { // "|H"
3445 scr_html = r_config_get_b (core->config, "scr.html");
3446 r_config_set_b (core->config, "scr.html", true);
3447 } else if (!strcmp (ptr + 1, "T")) { // "|T"
3448 scr_color = r_config_get_i (core->config, "scr.color");
3449 r_config_set_i (core->config, "scr.color", COLOR_MODE_DISABLED);
3450 core->cons->use_tts = true;
3451 } else if (!strcmp (ptr + 1, ".")) { // "|."
3452 ret = *cmd ? r_core_cmdf (core, ".%s", cmd) : 0;
3453 r_list_free (tmpenvs);
3454 return ret;
3455 } else if (ptr[1]) { // "| grep .."
3456 int value = core->num->value;
3457 if (*cmd) {
3458 r_core_cmd_pipe (core, cmd, ptr + 1);
3459 } else {
3460 char *res = r_io_system (core->io, ptr + 1);
3461 if (res) {
3462 r_cons_printf ("%s\n", res);
3463 free (res);
3464 }
3465 }
3466 core->num->value = value;
3467 r_list_free (tmpenvs);
3468 return 0;
3469 } else { // "|"
3470 scr_html = r_config_get_b (core->config, "scr.html");
3471 r_config_set_b (core->config, "scr.html", false);
3472 scr_color = r_config_get_i (core->config, "scr.color");
3473 r_config_set_i (core->config, "scr.color", COLOR_MODE_DISABLED);
3474 }
3475 }
3476 }
3477 }
3478 escape_pipe:
3479
3480 // TODO must honor " and `
3481 /* bool conditions */
3482 ptr = (char *)r_str_lastbut (cmd, '&', quotestr);
3483 //ptr = strchr (cmd, '&');
3484 while (ptr && *ptr && ptr[1] == '&') {
3485 *ptr = '\0';
3486 ret = r_cmd_call (core->rcmd, cmd);
3487 if (ret == -1) {
3488 eprintf ("command error(%s)\n", cmd);
3489 if (scr_html != -1) {
3490 r_config_set_b (core->config, "scr.html", scr_html);
3491 }
3492 if (scr_color != -1) {
3493 r_config_set_i (core->config, "scr.color", scr_color);
3494 }
3495 r_list_free (tmpenvs);
3496 return ret;
3497 }
3498 for (cmd = ptr + 2; cmd && *cmd == ' '; cmd++) {
3499 ;
3500 }
3501 ptr = strchr (cmd, '&');
3502 }
3503
3504 ptr = strstr (cmd, "?*");
3505 if (ptr && (ptr == cmd || ptr[-1] != '~')) {
3506 ptr[0] = 0;
3507 if (*cmd != '#') {
3508 int detail = 0;
3509 if (cmd < ptr && ptr[-1] == '?') {
3510 detail++;
3511 if (cmd < ptr - 1 && ptr[-2] == '?') {
3512 detail++;
3513 }
3514 }
3515 r_cons_break_push (NULL, NULL);
3516 recursive_help (core, detail, cmd);
3517 r_cons_break_pop ();
3518 r_cons_grep_parsecmd (ptr + 2, "`");
3519 if (scr_html != -1) {
3520 r_config_set_b (core->config, "scr.html", scr_html);
3521 }
3522 if (scr_color != -1) {
3523 r_config_set_i (core->config, "scr.color", scr_color);
3524 }
3525 r_list_free (tmpenvs);
3526 return 0;
3527 }
3528 }
3529
3530 /* pipe console to file */
3531 ptr = (char *)r_str_firstbut (cmd, '>', "\"");
3532 // TODO honor `
3533 if (ptr) {
3534 if (ptr > cmd) {
3535 char *ch = ptr - 1;
3536 if (*ch == '\\') {
3537 memmove (ch, ptr, strlen (ptr) + 1);
3538 goto escape_redir;
3539 }
3540 }
3541 if (ptr[0] && ptr[1] == '?') {
3542 r_core_cmd_help (core, help_msg_greater_sign);
3543 r_list_free (tmpenvs);
3544 return true;
3545 }
3546 int fdn = 1;
3547 int pipecolor = r_config_get_i (core->config, "scr.color.pipe");
3548 int use_editor = false;
3549 int ocolor = r_config_get_i (core->config, "scr.color");
3550 *ptr = '\0';
3551 str = ptr + 1 + (ptr[1] == '>');
3552 r_str_trim (str);
3553 if (!*str) {
3554 eprintf ("No output?\n");
3555 goto next2;
3556 }
3557 /* r_cons_flush() handles interactive output (to the terminal)
3558 * differently (e.g. asking about too long output). This conflicts
3559 * with piping to a file. Disable it while piping. */
3560 if (ptr > (cmd + 1) && IS_WHITECHAR (ptr[-2])) {
3561 char *fdnum = ptr - 1;
3562 if (*fdnum == 'H') { // "H>"
3563 scr_html = r_config_get_i (core->config, "scr.html");
3564 r_config_set_i (core->config, "scr.html", true);
3565 pipecolor = true;
3566 *fdnum = 0;
3567 } else {
3568 if (IS_DIGIT (*fdnum)) {
3569 fdn = *fdnum - '0';
3570 }
3571 *fdnum = 0;
3572 }
3573 }
3574 r_cons_set_interactive (false);
3575 if (!strcmp (str, "-")) {
3576 use_editor = true;
3577 str = r_file_temp ("dumpedit");
3578 r_config_set_i (core->config, "scr.color", COLOR_MODE_DISABLED);
3579 }
3580 const bool appendResult = (ptr[1] == '>');
3581 if (*str == '$') {
3582 // pipe to alias variable
3583 // register output of command as an alias
3584 char *o = r_core_cmd_str (core, cmd);
3585 if (appendResult) {
3586 const char *oldText = r_cmd_alias_get (core->rcmd, str, 1);
3587 if (oldText) {
3588 char *two = r_str_newf ("%s%s", oldText, o);
3589 if (two) {
3590 r_cmd_alias_set (core->rcmd, str, two, 1);
3591 free (two);
3592 }
3593 } else {
3594 char *n = r_str_newf ("$%s", o);
3595 r_cmd_alias_set (core->rcmd, str, n, 1);
3596 free (n);
3597 }
3598 } else {
3599 char *n = r_str_newf ("$%s", o);
3600 r_cmd_alias_set (core->rcmd, str, n, 1);
3601 free (n);
3602 }
3603 ret = 0;
3604 free (o);
3605 } else if (fdn > 0) {
3606 // pipe to file (or append)
3607 pipefd = r_cons_pipe_open (str, fdn, appendResult);
3608 if (pipefd != -1) {
3609 if (!pipecolor) {
3610 r_config_set_i (core->config, "scr.color", COLOR_MODE_DISABLED);
3611 }
3612 ret = r_core_cmd_subst (core, cmd);
3613 r_cons_flush ();
3614 r_cons_pipe_close (pipefd);
3615 }
3616 }
3617 r_cons_set_last_interactive ();
3618 if (!pipecolor) {
3619 r_config_set_i (core->config, "scr.color", ocolor);
3620 }
3621 if (use_editor) {
3622 const char *editor = r_config_get (core->config, "cfg.editor");
3623 if (editor && *editor) {
3624 r_sys_cmdf ("%s '%s'", editor, str);
3625 r_file_rm (str);
3626 } else {
3627 eprintf ("No cfg.editor configured\n");
3628 }
3629 r_config_set_i (core->config, "scr.color", ocolor);
3630 free (str);
3631 }
3632 if (scr_html != -1) {
3633 r_config_set_i (core->config, "scr.html", scr_html);
3634 }
3635 if (scr_color != -1) {
3636 r_config_set_i (core->config, "scr.color", scr_color);
3637 }
3638 core->cons->use_tts = false;
3639 r_list_free (tmpenvs);
3640 return ret;
3641 }
3642 escape_redir:
3643 next2:
3644 /* sub commands */
3645 ptr = strchr (cmd, '`');
3646 if (ptr) {
3647 if (ptr > cmd) {
3648 char *ch = ptr - 1;
3649 if (*ch == '\\') {
3650 memmove (ch, ptr, strlen (ptr) + 1);
3651 goto escape_backtick;
3652 }
3653 }
3654 bool empty = false;
3655 int oneline = 1;
3656 if (ptr[1] == '`') {
3657 memmove (ptr, ptr + 1, strlen (ptr));
3658 oneline = 0;
3659 empty = true;
3660 }
3661 ptr2 = strchr (ptr + 1, '`');
3662 if (empty) {
3663 /* do nothing */
3664 } else if (!ptr2) {
3665 eprintf ("parse: Missing backtick in expression.\n");
3666 goto fail;
3667 } else {
3668 int value = core->num->value;
3669 *ptr = '\0';
3670 *ptr2 = '\0';
3671 if (ptr[1] == '!') {
3672 str = r_core_cmd_str_pipe (core, ptr + 1);
3673 } else {
3674 // Color disabled when doing backticks ?e `pi 1`
3675 int ocolor = r_config_get_i (core->config, "scr.color");
3676 r_config_set_i (core->config, "scr.color", 0);
3677 core->cmd_in_backticks = true;
3678 str = r_core_cmd_str (core, ptr + 1);
3679 core->cmd_in_backticks = false;
3680 r_config_set_i (core->config, "scr.color", ocolor);
3681 }
3682 if (!str) {
3683 goto fail;
3684 }
3685 // ignore contents if first char is pipe or comment
3686 if (*str == '|' || *str == '*') {
3687 eprintf ("r_core_cmd_subst_i: invalid backticked command\n");
3688 free (str);
3689 goto fail;
3690 }
3691 if (oneline && str) {
3692 for (i = 0; str[i]; i++) {
3693 if (str[i] == '\n') {
3694 str[i] = ' ';
3695 }
3696 }
3697 }
3698 str = r_str_append (str, ptr2 + 1);
3699 cmd = r_str_append (strdup (cmd), str);
3700 core->num->value = value;
3701 ret = r_core_cmd_subst (core, cmd);
3702 free (cmd);
3703 if (scr_html != -1) {
3704 r_config_set_i (core->config, "scr.html", scr_html);
3705 }
3706 free (str);
3707 r_list_free (tmpenvs);
3708 return ret;
3709 }
3710 }
3711 escape_backtick:
3712 // TODO must honor " and `
3713 if (*cmd != '"' && *cmd) {
3714 const char *s = strstr (cmd, "~?");
3715 if (s) {
3716 bool showHelp = false;
3717 if (cmd == s) {
3718 // ~?
3719 // ~??
3720 showHelp = true;
3721 } else {
3722 // pd~?
3723 // pd~??
3724 if (!strcmp (s, "~??")) {
3725 showHelp = true;
3726 }
3727 }
3728 if (showHelp) {
3729 r_cons_grep_help ();
3730 r_list_free (tmpenvs);
3731 return true;
3732 }
3733 }
3734 }
3735 if (*cmd != '.') {
3736 grep = r_cons_grep_strip (cmd, quotestr);
3737 }
3738
3739 /* temporary seek commands */
3740 // if (*cmd != '(' && *cmd != '"')
3741 if (*cmd != '"') {
3742 ptr = strchr (cmd, '@');
3743 if (ptr == cmd + 1 && *cmd == '?') {
3744 ptr = NULL;
3745 }
3746 } else {
3747 ptr = NULL;
3748 }
3749
3750 cmd_tmpseek = core->tmpseek = ptr != NULL;
3751 int rc = 0;
3752 if (ptr) {
3753 char *f, *ptr2 = strchr (ptr + 1, '!');
3754 ut64 addr = core->offset;
3755 bool addr_is_set = false;
3756 char *tmpbits = NULL;
3757 const char *offstr = NULL;
3758 bool is_bits_set = false;
3759 bool is_arch_set = false;
3760 char *tmpeval = NULL;
3761 char *tmpasm = NULL;
3762 bool flgspc_changed = false;
3763 int tmpfd = -1;
3764 size_t sz;
3765 int len;
3766 ut8 *buf;
3767
3768 *ptr++ = '\0';
3769 repeat_arroba:
3770 arroba = (ptr[0] && ptr[1] && ptr[2])?
3771 strchr (ptr + 2, '@'): NULL;
3772 if (arroba) {
3773 *arroba = 0;
3774 }
3775
3776 for (; *ptr == ' '; ptr++) {
3777 //nothing to see here
3778 }
3779 if (*ptr && ptr[1] == ':') {
3780 /* do nothing here */
3781 } else {
3782 ptr--;
3783 }
3784
3785 r_str_trim_tail (ptr);
3786
3787 if (ptr[1] == '?') {
3788 r_core_cmd_help (core, help_msg_at);
3789 } else if (ptr[1] == '%') { // "@%"
3790 char *k = strdup (ptr + 2);
3791 char *v = strchr (k, '=');
3792 if (v) {
3793 *v++ = 0;
3794 r_sys_setenv (k, v);
3795 r_list_append (tmpenvs, k);
3796 } else {
3797 free (k);
3798 }
3799 } else if (ptr[1] == '.') { // "@."
3800 if (ptr[2] == '.') { // "@.."
3801 if (ptr[3] == '.') { // "@..."
3802 ut64 addr = r_num_tail (core->num, core->offset, ptr + 4);
3803 r_core_block_size (core, R_ABS ((st64)addr - (st64)core->offset));
3804 goto fuji;
3805 } else {
3806 addr = r_num_tail (core->num, core->offset, ptr + 3);
3807 r_core_seek (core, addr, true);
3808 cmd_tmpseek = core->tmpseek = true;
3809 goto fuji;
3810 }
3811 } else {
3812 // WAT DU
3813 eprintf ("TODO: what do you expect for @. import offset from file maybe?\n");
3814 }
3815 } else if (ptr[0] && ptr[1] == ':' && ptr[2]) {
3816 switch (ptr[0]) {
3817 case 'F': // "@F:" // temporary flag space
3818 flgspc_changed = r_flag_space_push (core->flags, ptr + 2);
3819 break;
3820 case 'B': // "@B:#" // seek to the last instruction in current bb
3821 {
3822 int index = (int)r_num_math (core->num, ptr + 2);
3823 RAnalBlock *bb = r_anal_bb_from_offset (core->anal, core->offset);
3824 if (bb) {
3825 // handle negative indices
3826 if (index < 0) {
3827 index = bb->ninstr + index;
3828 }
3829
3830 if (index >= 0 && index < bb->ninstr) {
3831 ut16 inst_off = r_anal_bb_offset_inst (bb, index);
3832 r_core_seek (core, bb->addr + inst_off, true);
3833 cmd_tmpseek = core->tmpseek = true;
3834 } else {
3835 eprintf ("The current basic block has %d instructions\n", bb->ninstr);
3836 }
3837 } else {
3838 eprintf ("Can't find a basic block for 0x%08"PFMT64x"\n", core->offset);
3839 }
3840 break;
3841 }
3842 break;
3843 case 'f': // "@f:" // slurp file in block
3844 f = r_file_slurp (ptr + 2, &sz);
3845 if (f) {
3846 {
3847 RBuffer *b = r_buf_new_with_bytes ((const ut8*)f, (ut64)sz);
3848 RIODesc *d = r_io_open_buffer (core->io, b, R_PERM_RWX, 0);
3849 if (d) {
3850 if (tmpdesc) {
3851 r_io_desc_close (tmpdesc);
3852 }
3853 tmpdesc = d;
3854 if (pamode) {
3855 r_config_set_i (core->config, "io.va", 1);
3856 }
3857 r_io_map_new (core->io, d->fd, d->perm, 0, core->offset, r_buf_size (b));
3858 }
3859 }
3860 } else {
3861 eprintf ("cannot open '%s'\n", ptr + 3);
3862 }
3863 break;
3864 case 'r': // "@r:" // regname
3865 if (ptr[1] == ':') {
3866 ut64 regval;
3867 char *mander = strdup (ptr + 2);
3868 char *sep = findSeparator (mander);
3869 if (sep) {
3870 char ch = *sep;
3871 *sep = 0;
3872 regval = r_debug_reg_get (core->dbg, mander);
3873 *sep = ch;
3874 char *numexpr = r_str_newf ("0x%"PFMT64x"%s", regval, sep);
3875 regval = r_num_math (core->num, numexpr);
3876 free (numexpr);
3877 } else {
3878 regval = r_debug_reg_get (core->dbg, ptr + 2);
3879 }
3880 r_core_seek (core, regval, true);
3881 cmd_tmpseek = core->tmpseek = true;
3882 free (mander);
3883 }
3884 break;
3885 case 'b': // "@b:" // bits
3886 is_bits_set = set_tmp_bits (core, r_num_math (core->num, ptr + 2), &tmpbits, &cmd_ignbithints);
3887 break;
3888 case 'i': // "@i:"
3889 {
3890 ut64 addr = r_num_math (core->num, ptr + 2);
3891 if (addr) {
3892 r_core_cmdf (core, "so %s", ptr + 2);
3893 cmd_tmpseek = core->tmpseek = true;
3894 }
3895 }
3896 break;
3897 case 'e': // "@e:"
3898 {
3899 char *cmd = parse_tmp_evals (core, ptr + 2);
3900 if (!tmpeval) {
3901 tmpeval = cmd;
3902 } else {
3903 tmpeval = r_str_prepend (tmpeval, cmd);
3904 free (cmd);
3905 }
3906 }
3907 break;
3908 case 'v': // "@v:" // value (honors asm.bits and cfg.bigendian)
3909 if (ptr[1] == ':') {
3910 ut8 buf[8] = {0};
3911 ut64 v = r_num_math (core->num, ptr + 2);
3912 int be = r_config_get_i (core->config, "cfg.bigendian");
3913 int bi = r_config_get_i (core->config, "asm.bits");
3914 if (bi == 64) {
3915 r_write_ble64 (buf, v, be);
3916 len = 8;
3917 } else {
3918 r_write_ble32 (buf, v, be);
3919 len = 4;
3920 }
3921 tmpfd = r_io_fd_get_current(core->io);
3922 r_core_block_size (core, R_ABS (len));
3923 RBuffer *b = r_buf_new_with_bytes (buf, len);
3924 RIODesc *d = r_io_open_buffer (core->io, b, R_PERM_RWX, 0);
3925 if (d) {
3926 if (tmpdesc) {
3927 r_io_desc_close (tmpdesc);
3928 }
3929 tmpdesc = d;
3930 if (pamode) {
3931 r_config_set_i (core->config, "io.va", 1);
3932 }
3933 r_io_map_new (core->io, d->fd, d->perm, 0, core->offset, r_buf_size (b));
3934 r_core_block_size (core, len);
3935 r_core_block_read (core);
3936 }
3937 } else {
3938 eprintf ("Invalid @v: syntax\n");
3939 }
3940 break;
3941 case 'x': // "@x:" // hexpairs
3942 if (ptr[1] == ':') {
3943 buf = malloc (strlen (ptr + 2) + 1);
3944 if (buf) {
3945 len = r_hex_str2bin (ptr + 2, buf);
3946 r_core_block_size (core, R_ABS (len));
3947 if (len > 0) {
3948 RBuffer *b = r_buf_new_with_bytes (buf, len);
3949 RIODesc *d = r_io_open_buffer (core->io, b, R_PERM_RWX, 0);
3950 if (d) {
3951 if (tmpdesc) {
3952 r_io_desc_close (tmpdesc);
3953 }
3954 tmpdesc = d;
3955 if (pamode) {
3956 r_config_set_i (core->config, "io.va", 1);
3957 }
3958 r_io_map_new (core->io, d->fd, d->perm, 0, core->offset, r_buf_size (b));
3959 r_core_block_size (core, len);
3960 r_core_block_read (core);
3961 }
3962 } else {
3963 eprintf ("Error: Invalid hexpairs for @x:\n");
3964 }
3965 free (buf);
3966 } else {
3967 eprintf ("cannot allocate\n");
3968 }
3969 } else {
3970 eprintf ("Invalid @x: syntax\n");
3971 }
3972 break;
3973 case 'k': // "@k"
3974 {
3975 char *out = sdb_querys (core->sdb, NULL, 0, ptr + ((ptr[1])? 2: 1));
3976 if (out) {
3977 r_core_seek (core, r_num_math (core->num, out), true);
3978 free (out);
3979 usemyblock = true;
3980 }
3981 }
3982 break;
3983 case 'o': // "@o:3"
3984 if (ptr[1] == ':') {
3985 tmpfd = core->io->desc ? core->io->desc->fd : -1;
3986 r_io_use_fd (core->io, atoi (ptr + 2));
3987 }
3988 break;
3989 case 'a': // "@a:"
3990 if (ptr[1] == ':') {
3991 char *q = strchr (ptr + 2, ':');
3992 if (q) {
3993 *q++ = 0;
3994 int bits = r_num_math (core->num, q);
3995 is_bits_set = set_tmp_bits (core, bits, &tmpbits, &cmd_ignbithints);
3996 }
3997 is_arch_set = set_tmp_arch (core, ptr + 2, &tmpasm);
3998 } else {
3999 eprintf ("Usage: pd 10 @a:arm:32\n");
4000 }
4001 break;
4002 case 's': // "@s:" // wtf syntax
4003 {
4004 len = strlen (ptr + 2);
4005 r_core_block_size (core, len);
4006 const ut8 *buf = (const ut8*)r_str_trim_head_ro (ptr + 2);
4007
4008 if (len > 0) {
4009 RBuffer *b = r_buf_new_with_bytes (buf, len);
4010 RIODesc *d = r_io_open_buffer (core->io, b, R_PERM_RWX, 0);
4011 if (!core->io->va) {
4012 r_config_set_i (core->config, "io.va", 1);
4013 }
4014 if (d) {
4015 if (tmpdesc) {
4016 r_io_desc_close (tmpdesc);
4017 }
4018 tmpdesc = d;
4019 if (pamode) {
4020 r_config_set_i (core->config, "io.va", 1);
4021 }
4022 r_io_map_new (core->io, d->fd, d->perm, 0, core->offset, r_buf_size (b));
4023 r_core_block_size (core, len);
4024 // r_core_block_read (core);
4025 }
4026 }
4027 }
4028 break;
4029 default:
4030 goto ignore;
4031 }
4032 *ptr = '@';
4033 /* trim whitespaces before the @ */
4034 /* Fixes pd @x:9090 */
4035 char *trim = ptr - 2;
4036 while (trim > cmd) {
4037 if (!IS_WHITESPACE (*trim)) {
4038 break;
4039 }
4040 *trim = 0;
4041 trim--;
4042 }
4043 goto next_arroba;
4044 }
4045 ignore:
4046 r_str_trim_head (ptr + 1);
4047 cmd = r_str_trim_nc (cmd);
4048 if (ptr2) {
4049 if (strlen (ptr + 1) == 13 && strlen (ptr2 + 1) == 6 &&
4050 !memcmp (ptr + 1, "0x", 2) &&
4051 !memcmp (ptr2 + 1, "0x", 2)) {
4052 /* 0xXXXX:0xYYYY */
4053 } else if (strlen (ptr + 1) == 9 && strlen (ptr2 + 1) == 4) {
4054 /* XXXX:YYYY */
4055 } else {
4056 *ptr2 = '\0';
4057 if (!ptr2[1]) {
4058 goto fail;
4059 }
4060 r_core_block_size (
4061 core, r_num_math (core->num, ptr2 + 1));
4062 }
4063 }
4064
4065 r_str_trim_head (ptr + 1);
4066 offstr = ptr + 1;
4067
4068 addr = (*offstr == '{')? core->offset: r_num_math (core->num, offstr);
4069 addr_is_set = true;
4070
4071 if (isalpha ((ut8)ptr[1]) && !addr) {
4072 if (!r_flag_get (core->flags, ptr + 1)) {
4073 eprintf ("Invalid address (%s)\n", ptr + 1);
4074 goto fail;
4075 }
4076 } else {
4077 char ch = *offstr;
4078 if (ch == '-' || ch == '+') {
4079 addr = core->offset + addr;
4080 }
4081 }
4082 // remap thhe tmpdesc if any
4083 if (addr) {
4084 RIODesc *d = tmpdesc;
4085 if (d) {
4086 r_io_map_new (core->io, d->fd, d->perm, 0, addr, r_io_desc_size (d));
4087 }
4088 }
4089 next_arroba:
4090 if (arroba) {
4091 ptr = arroba + 1;
4092 *arroba = '@';
4093 arroba = NULL;
4094 goto repeat_arroba;
4095 }
4096 core->fixedblock = !!tmpdesc;
4097 if (core->fixedblock) {
4098 r_core_block_read (core);
4099 }
4100 if (ptr[1] == '@') {
4101 if (ptr[2] == '@') {
4102 char *rule = ptr + 3;
4103 while (*rule && *rule == ' ') {
4104 rule++;
4105 }
4106 ret = r_core_cmd_foreach3 (core, cmd, rule);
4107 } else {
4108 ret = r_core_cmd_foreach (core, cmd, ptr + 2);
4109 }
4110 } else {
4111 bool tmpseek = false;
4112 const char *fromvars[] = { "anal.from", "diff.from", "graph.from", "search.from", "zoom.from", NULL };
4113 const char *tovars[] = { "anal.to", "diff.to", "graph.to", "search.to", "zoom.to", NULL };
4114 ut64 curfrom[R_ARRAY_SIZE (fromvars) - 1], curto[R_ARRAY_SIZE (tovars) - 1];
4115
4116 // "@{A B}"
4117 if (ptr[1] == '{') {
4118 char *range = ptr + 2;
4119 char *p = strchr (range, ' ');
4120 if (!p) {
4121 eprintf ("Usage: / ABCD @{0x1000 0x3000}\n");
4122 eprintf ("Run command and define the following vars:\n");
4123 eprintf (" (anal|diff|graph|search|zoom).{from,to}\n");
4124 free (tmpeval);
4125 free (tmpasm);
4126 free (tmpbits);
4127 goto fail;
4128 }
4129 char *arg = p + 1;
4130 int arg_len = strlen (arg);
4131 if (arg_len > 0) {
4132 arg[arg_len - 1] = 0;
4133 }
4134 *p = '\x00';
4135 ut64 from = r_num_math (core->num, range);
4136 ut64 to = r_num_math (core->num, arg);
4137 // save current ranges
4138 for (i = 0; fromvars[i]; i++) {
4139 curfrom[i] = r_config_get_i (core->config, fromvars[i]);
4140 }
4141 for (i = 0; tovars[i]; i++) {
4142 curto[i] = r_config_get_i (core->config, tovars[i]);
4143 }
4144 // set new ranges
4145 for (i = 0; fromvars[i]; i++) {
4146 r_config_set_i (core->config, fromvars[i], from);
4147 }
4148 for (i = 0; tovars[i]; i++) {
4149 r_config_set_i (core->config, tovars[i], to);
4150 }
4151 tmpseek = true;
4152 }
4153 if (usemyblock) {
4154 if (addr_is_set) {
4155 core->offset = addr;
4156 }
4157 ret = r_cmd_call (core->rcmd, r_str_trim_head_ro (cmd));
4158 } else {
4159 if (addr_is_set) {
4160 if (ptr[1]) {
4161 r_core_seek (core, addr, true);
4162 r_core_block_read (core);
4163 }
4164 }
4165 ret = r_cmd_call (core->rcmd, r_str_trim_head_ro (cmd));
4166
4167 }
4168 if (tmpseek) {
4169 // restore ranges
4170 for (i = 0; fromvars[i]; i++) {
4171 r_config_set_i (core->config, fromvars[i], curfrom[i]);
4172 }
4173 for (i = 0; tovars[i]; i++) {
4174 r_config_set_i (core->config, tovars[i], curto[i]);
4175 }
4176 }
4177 }
4178 if (ptr2) {
4179 *ptr2 = '!';
4180 r_core_block_size (core, tmpbsz);
4181 }
4182 if (is_arch_set) {
4183 core->fixedarch = oldfixedarch;
4184 r_config_set (core->config, "asm.arch", tmpasm);
4185 R_FREE (tmpasm);
4186 }
4187 if (tmpdesc) {
4188 if (pamode) {
4189 r_config_set_i (core->config, "io.va", 0);
4190 }
4191 r_io_desc_close (tmpdesc);
4192 tmpdesc = NULL;
4193 }
4194 if (tmpfd != -1) {
4195 // TODO: reuse tmpfd instead of
4196 r_io_use_fd (core->io, tmpfd);
4197 tmpfd = -1;
4198 }
4199 if (is_bits_set) {
4200 r_config_set (core->config, "asm.bits", tmpbits);
4201 core->fixedbits = oldfixedbits;
4202 }
4203 if (tmpbsz != core->blocksize) {
4204 r_core_block_size (core, tmpbsz);
4205 }
4206 if (tmpeval) {
4207 r_core_cmd0 (core, tmpeval);
4208 R_FREE (tmpeval);
4209 }
4210 if (flgspc_changed) {
4211 r_flag_space_pop (core->flags);
4212 }
4213 *ptr = '@';
4214 rc = ret;
4215 goto beach;
4216 }
4217 fuji:
4218 if (cmd) {
4219 r_str_trim_head (cmd);
4220 rc = r_cmd_call (core->rcmd, cmd);
4221 } else {
4222 rc = false;
4223 }
4224 beach:
4225 if (grep) {
4226 char *old_grep = grep;
4227 grep = unescape_special_chars (old_grep, SPECIAL_CHARS_REGULAR);
4228 free (old_grep);
4229 }
4230 r_cons_grep_process (grep);
4231 if (scr_html != -1) {
4232 r_cons_flush ();
4233 r_config_set_i (core->config, "scr.html", scr_html);
4234 }
4235 if (scr_color != -1) {
4236 r_config_set_i (core->config, "scr.color", scr_color);
4237 }
4238 r_list_free (tmpenvs);
4239 if (tmpdesc) {
4240 r_io_desc_close (tmpdesc);
4241 tmpdesc = NULL;
4242 }
4243 core->fixedarch = oldfixedarch;
4244 core->fixedbits = oldfixedbits;
4245 if (tmpseek) {
4246 *tmpseek = cmd_tmpseek;
4247 }
4248 if (cmd_ignbithints != -1) {
4249 r_config_set_i (core->config, "anal.ignbithints", cmd_ignbithints);
4250 }
4251 return rc;
4252 fail:
4253 rc = -1;
4254 goto beach;
4255 }
4256
4257 struct exec_command_t {
4258 RCore *core;
4259 const char *cmd;
4260 };
4261
copy_into_flagitem_list(RFlagItem * flg,void * u)4262 static bool copy_into_flagitem_list(RFlagItem *flg, void *u) {
4263 RFlagItem *fi = r_mem_dup (flg, sizeof (RFlagItem));
4264 r_list_append (u, fi);
4265 return true;
4266 }
4267
foreach_pairs(RCore * core,const char * cmd,const char * each)4268 static void foreach_pairs(RCore *core, const char *cmd, const char *each) {
4269 const char *arg;
4270 int pair = 0;
4271 for (arg = each ; ; ) {
4272 char *next = strchr (arg, ' ');
4273 if (next) {
4274 *next = 0;
4275 }
4276 if (arg && *arg) {
4277 ut64 n = r_num_get (NULL, arg);
4278 if (pair%2) {
4279 r_core_block_size (core, n);
4280 r_core_cmd0 (core, cmd);
4281 } else {
4282 r_core_seek (core, n, true);
4283 }
4284 pair++;
4285 }
4286 if (!next) {
4287 break;
4288 }
4289 arg = next + 1;
4290 }
4291 }
4292
r_core_cmd_foreach3(RCore * core,const char * cmd,char * each)4293 R_API int r_core_cmd_foreach3(RCore *core, const char *cmd, char *each) { // "@@@"
4294 RDebug *dbg = core->dbg;
4295 RList *list, *head;
4296 RListIter *iter;
4297 int i;
4298 const char *filter = NULL;
4299
4300 if (each[0] && each[1] == ':') {
4301 filter = each + 2;
4302 }
4303
4304 switch (each[0]) {
4305 case '=':
4306 foreach_pairs (core, cmd, each + 1);
4307 break;
4308 case '?':
4309 r_core_cmd_help (core, help_msg_at_at_at);
4310 break;
4311 case 'c':
4312 if (filter) {
4313 char *arg = r_core_cmd_str (core, filter);
4314 foreach_pairs (core, cmd, arg);
4315 free (arg);
4316 } else {
4317 eprintf ("Usage: @@@c:command # same as @@@=`command`\n");
4318 }
4319 break;
4320 case 'C': {
4321 char *glob = filter ? r_str_trim_dup (filter): NULL;
4322 RIntervalTreeIter it;
4323 RAnalMetaItem *meta;
4324 r_interval_tree_foreach (&core->anal->meta, it, meta) {
4325 if (meta->type != R_META_TYPE_COMMENT) {
4326 continue;
4327 }
4328 if (!glob || (meta->str && r_str_glob (meta->str, glob))) {
4329 r_core_seek (core, r_interval_tree_iter_get (&it)->start, true);
4330 r_core_cmd0 (core, cmd);
4331 }
4332 }
4333 free (glob);
4334 break;
4335 }
4336 case 'm':
4337 {
4338 int fd = r_io_fd_get_current (core->io);
4339 // only iterate maps of current fd
4340 RList *maps = r_io_map_get_for_fd (core->io, fd);
4341 RIOMap *map;
4342 if (maps) {
4343 RListIter *iter;
4344 r_list_foreach (maps, iter, map) {
4345 r_core_seek (core, r_io_map_begin (map), true);
4346 r_core_block_size (core, r_io_map_size (map));
4347 r_core_cmd0 (core, cmd);
4348 }
4349 r_list_free (maps);
4350 }
4351 }
4352 break;
4353 case 'M':
4354 if (dbg && dbg->h && dbg->maps) {
4355 RDebugMap *map;
4356 r_list_foreach (dbg->maps, iter, map) {
4357 r_core_seek (core, map->addr, true);
4358 //r_core_block_size (core, map->size);
4359 r_core_cmd0 (core, cmd);
4360 }
4361 }
4362 break;
4363 case 't':
4364 // iterate over all threads
4365 if (dbg && dbg->h && dbg->h->threads) {
4366 int origpid = dbg->pid;
4367 RDebugPid *p;
4368 list = dbg->h->threads (dbg, dbg->pid);
4369 if (!list) {
4370 return false;
4371 }
4372 r_list_foreach (list, iter, p) {
4373 r_core_cmdf (core, "dp %d", p->pid);
4374 r_cons_printf ("PID %d\n", p->pid);
4375 r_core_cmd0 (core, cmd);
4376 }
4377 r_core_cmdf (core, "dp %d", origpid);
4378 r_list_free (list);
4379 }
4380 break;
4381 case 'r': // @@@r
4382 {
4383 ut64 offorig = core->offset;
4384 for (i = 0; i < R_REG_TYPE_LAST; i++) {
4385 RRegItem *item;
4386 ut64 value;
4387 head = r_reg_get_list (core->dbg->reg, i);
4388 if (!head) {
4389 continue;
4390 }
4391 RList *list = r_list_newf (free);
4392 r_list_foreach (head, iter, item) {
4393 if (item->size != core->anal->bits) {
4394 continue;
4395 }
4396 if (item->type != i) {
4397 continue;
4398 }
4399 r_list_append (list, strdup (item->name));
4400 }
4401 const char *item_name;
4402 r_list_foreach (list, iter, item_name) {
4403 value = r_reg_getv (core->dbg->reg, item_name);
4404 r_core_seek (core, value, true);
4405 r_cons_printf ("%s: ", item_name);
4406 r_core_cmd0 (core, cmd);
4407 }
4408 r_list_free (list);
4409 }
4410 r_core_seek (core, offorig, true);
4411 }
4412 break;
4413 case 'i': // @@@i
4414 {
4415 RBinImport *imp;
4416 ut64 offorig = core->offset;
4417 list = r_bin_get_imports (core->bin);
4418 RList *lost = r_list_newf (free);
4419 r_list_foreach (list, iter, imp) {
4420 char *impflag = r_str_newf ("sym.imp.%s", imp->name);
4421 ut64 addr = r_num_math (core->num, impflag);
4422 ut64 *n = R_NEW (ut64);
4423 *n = addr;
4424 r_list_append (lost, n);
4425 free (impflag);
4426 }
4427 ut64 *naddr;
4428 r_list_foreach (lost, iter, naddr) {
4429 ut64 addr = *naddr;
4430 if (addr && addr != UT64_MAX) {
4431 r_core_seek (core, addr, true);
4432 r_core_cmd0 (core, cmd);
4433 }
4434 }
4435 r_core_seek (core, offorig, true);
4436 r_list_free (lost);
4437 }
4438 break;
4439 case 'S': // "@@@S"
4440 {
4441 RBinObject *obj = r_bin_cur_object (core->bin);
4442 if (obj) {
4443 ut64 offorig = core->offset;
4444 ut64 bszorig = core->blocksize;
4445 RBinSection *sec;
4446 RListIter *iter;
4447 r_list_foreach (obj->sections, iter, sec) {
4448 r_core_seek (core, sec->vaddr, true);
4449 r_core_block_size (core, sec->vsize);
4450 r_core_cmd0 (core, cmd);
4451 }
4452 r_core_block_size (core, bszorig);
4453 r_core_seek (core, offorig, true);
4454 }
4455 }
4456 #if ATTIC
4457 if (each[1] == 'S') {
4458 RListIter *it;
4459 RBinSection *sec;
4460 RBinObject *obj = r_bin_cur_object (core->bin);
4461 int cbsz = core->blocksize;
4462 r_list_foreach (obj->sections, it, sec){
4463 ut64 addr = sec->vaddr;
4464 ut64 size = sec->vsize;
4465 // TODO:
4466 //if (R_BIN_SCN_EXECUTABLE & sec->perm) {
4467 // continue;
4468 //}
4469 r_core_seek_size (core, addr, size);
4470 r_core_cmd (core, cmd, 0);
4471 }
4472 r_core_block_size (core, cbsz);
4473 }
4474 #endif
4475 break;
4476 case 's':
4477 if (each[1] == 't') { // strings
4478 list = r_bin_get_strings (core->bin);
4479 if (list) {
4480 ut64 offorig = core->offset;
4481 ut64 obs = core->blocksize;
4482 RBinString *s;
4483 RList *lost = r_list_newf (free);
4484 r_list_foreach (list, iter, s) {
4485 RBinString *bs = r_mem_dup (s, sizeof (RBinString));
4486 r_list_append (lost, bs);
4487 }
4488 r_list_foreach (lost, iter, s) {
4489 r_core_block_size (core, s->size);
4490 r_core_seek (core, s->vaddr, true);
4491 r_core_cmd0 (core, cmd);
4492 }
4493 r_core_block_size (core, obs);
4494 r_core_seek (core, offorig, true);
4495 r_list_free (lost);
4496 }
4497 } else {
4498 // symbols
4499 RBinSymbol *sym;
4500 ut64 offorig = core->offset;
4501 ut64 obs = core->blocksize;
4502 list = r_bin_get_symbols (core->bin);
4503 r_cons_break_push (NULL, NULL);
4504 RList *lost = r_list_newf (free);
4505 r_list_foreach (list, iter, sym) {
4506 RBinSymbol *bs = r_mem_dup (sym, sizeof (RBinSymbol));
4507 r_list_append (lost, bs);
4508 }
4509 r_list_foreach (lost, iter, sym) {
4510 if (r_cons_is_breaked ()) {
4511 break;
4512 }
4513 r_core_block_size (core, sym->size);
4514 r_core_seek (core, sym->vaddr, true);
4515 r_core_cmd0 (core, cmd);
4516 }
4517 r_cons_break_pop ();
4518 r_list_free (lost);
4519 r_core_block_size (core, obs);
4520 r_core_seek (core, offorig, true);
4521 }
4522 break;
4523 case 'f': // flags
4524 {
4525 // TODO: honor ^C
4526 char *glob = filter? r_str_trim_dup (filter): NULL;
4527 ut64 off = core->offset;
4528 ut64 obs = core->blocksize;
4529 RList *flags = r_list_newf (free);
4530 r_flag_foreach_glob (core->flags, glob, copy_into_flagitem_list, flags);
4531 RListIter *iter;
4532 RFlagItem *f;
4533 r_list_foreach (flags, iter, f) {
4534 r_core_block_size (core, f->size);
4535 r_core_seek (core, f->offset, true);
4536 r_core_cmd0 (core, cmd);
4537 }
4538 r_core_seek (core, off, false);
4539 r_core_block_size (core, obs);
4540 free (glob);
4541 }
4542 break;
4543 case 'F': // functions
4544 {
4545 ut64 obs = core->blocksize;
4546 ut64 offorig = core->offset;
4547 RAnalFunction *fcn;
4548 list = core->anal->fcns;
4549 r_cons_break_push (NULL, NULL);
4550 r_list_foreach (list, iter, fcn) {
4551 if (r_cons_is_breaked ()) {
4552 break;
4553 }
4554 if (!filter || r_str_glob (fcn->name, filter)) {
4555 r_core_seek (core, fcn->addr, true);
4556 r_core_block_size (core, r_anal_function_linear_size (fcn));
4557 r_core_cmd0 (core, cmd);
4558 }
4559 }
4560 r_cons_break_pop ();
4561 r_core_block_size (core, obs);
4562 r_core_seek (core, offorig, true);
4563 }
4564 break;
4565 case 'b':
4566 {
4567 RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset, 0);
4568 ut64 offorig = core->offset;
4569 ut64 obs = core->blocksize;
4570 if (fcn) {
4571 RListIter *iter;
4572 RAnalBlock *bb;
4573 r_list_foreach (fcn->bbs, iter, bb) {
4574 r_core_seek (core, bb->addr, true);
4575 r_core_block_size (core, bb->size);
4576 r_core_cmd0 (core, cmd);
4577 }
4578 r_core_block_size (core, obs);
4579 r_core_seek (core, offorig, true);
4580 }
4581 }
4582 break;
4583 }
4584 return 0;
4585 }
4586
foreachOffset(RCore * core,const char * _cmd,const char * each)4587 static void foreachOffset(RCore *core, const char *_cmd, const char *each) {
4588 char *cmd = strdup (_cmd);
4589 char *nextLine = NULL;
4590 ut64 addr;
4591 /* foreach list of items */
4592 while (each) {
4593 // skip spaces
4594 while (*each == ' ') {
4595 each++;
4596 }
4597 // stahp if empty string
4598 if (!*each) {
4599 break;
4600 }
4601 // find newline
4602 char *nl = strchr (each, '\n');
4603 if (nl) {
4604 *nl = 0;
4605 nextLine = nl + 1;
4606 } else {
4607 nextLine = NULL;
4608 }
4609 // chop comment in line
4610 nl = strchr (each, '#');
4611 if (nl) {
4612 *nl = 0;
4613 }
4614 // space separated numbers
4615 while (each && *each) {
4616 // find spaces
4617 while (*each == ' ') {
4618 each++;
4619 }
4620 char *str = strchr (each, ' ');
4621 if (str) {
4622 *str = '\0';
4623 addr = r_num_math (core->num, each);
4624 *str = ' ';
4625 each = str + 1;
4626 } else {
4627 if (!*each) {
4628 break;
4629 }
4630 addr = r_num_math (core->num, each);
4631 each = NULL;
4632 }
4633 r_core_seek (core, addr, true);
4634 r_core_cmd (core, cmd, 0);
4635 r_cons_flush ();
4636 }
4637 each = nextLine;
4638 }
4639 free (cmd);
4640 }
4641
r_core_cmd_foreach(RCore * core,const char * cmd,char * each)4642 R_API int r_core_cmd_foreach(RCore *core, const char *cmd, char *each) {
4643 int i, j;
4644 char ch;
4645 char *word = NULL;
4646 char *str, *ostr = NULL;
4647 RListIter *iter;
4648 RFlagItem *flag;
4649 ut64 oseek, addr;
4650
4651 for (; *cmd == ' '; cmd++) {
4652 ;
4653 }
4654
4655 oseek = core->offset;
4656 ostr = str = strdup (each);
4657 r_cons_break_push (NULL, NULL); //pop on return
4658 switch (each[0]) {
4659 case '/': // "@@/"
4660 {
4661 char *cmdhit = strdup (r_config_get (core->config, "cmd.hit"));
4662 r_config_set (core->config, "cmd.hit", cmd);
4663 r_core_cmd0 (core, each);
4664 r_config_set (core->config, "cmd.hit", cmdhit);
4665 free (cmdhit);
4666 }
4667 free (ostr);
4668 return 0;
4669 case '?': // "@@?"
4670 r_core_cmd_help (core, help_msg_at_at);
4671 break;
4672 case 'b': // "@@b" - function basic blocks
4673 {
4674 RListIter *iter;
4675 RAnalBlock *bb;
4676 RAnalFunction *fcn = r_anal_get_function_at (core->anal, core->offset);
4677 int bs = core->blocksize;
4678 if (fcn) {
4679 r_list_sort (fcn->bbs, bb_cmp);
4680 r_list_foreach (fcn->bbs, iter, bb) {
4681 r_core_block_size (core, bb->size);
4682 r_core_seek (core, bb->addr, true);
4683 r_core_cmd (core, cmd, 0);
4684 if (r_cons_is_breaked ()) {
4685 break;
4686 }
4687 }
4688 }
4689 r_core_block_size (core, bs);
4690 goto out_finish;
4691 }
4692 break;
4693 case 's': // "@@s" - sequence
4694 {
4695 char *str = each + 1;
4696 if (*str == ':' || *str == ' ') {
4697 str++;
4698 }
4699 int count = r_str_split (str, ' ');
4700 if (count == 3) {
4701 ut64 cur;
4702 ut64 from = r_num_math (core->num, r_str_word_get0 (str, 0));
4703 ut64 to = r_num_math (core->num, r_str_word_get0 (str, 1));
4704 ut64 step = r_num_math (core->num, r_str_word_get0 (str, 2));
4705 for (cur = from; cur <= to; cur += step) {
4706 (void) r_core_seek (core, cur, true);
4707 r_core_cmd (core, cmd, 0);
4708 if (r_cons_is_breaked ()) {
4709 break;
4710 }
4711 }
4712 } else {
4713 eprintf ("Usage: cmd @@s:from to step\n");
4714 }
4715 goto out_finish;
4716 }
4717 break;
4718 case 'i': // "@@i" - function instructions
4719 {
4720 RListIter *iter;
4721 RAnalBlock *bb;
4722 int i;
4723 RAnalFunction *fcn = r_anal_get_function_at (core->anal, core->offset);
4724 if (fcn) {
4725 r_list_sort (fcn->bbs, bb_cmp);
4726 r_list_foreach (fcn->bbs, iter, bb) {
4727 for (i = 0; i < bb->op_pos_size; i++) {
4728 ut64 addr = bb->addr + bb->op_pos[i];
4729 r_core_seek (core, addr, true);
4730 r_core_cmd (core, cmd, 0);
4731 if (r_cons_is_breaked ()) {
4732 break;
4733 }
4734 }
4735 }
4736 }
4737 goto out_finish;
4738 }
4739 break;
4740 case 'f': // "@@f"
4741 if (each[1] == ':') {
4742 RAnalFunction *fcn;
4743 RListIter *iter;
4744 if (core->anal) {
4745 r_list_foreach (core->anal->fcns, iter, fcn) {
4746 if (each[2] && strstr (fcn->name, each + 2)) {
4747 r_core_seek (core, fcn->addr, true);
4748 r_core_cmd (core, cmd, 0);
4749 if (r_cons_is_breaked ()) {
4750 break;
4751 }
4752 }
4753 }
4754 }
4755 goto out_finish;
4756 } else {
4757 RAnalFunction *fcn;
4758 RListIter *iter;
4759 if (core->anal) {
4760 RConsGrep grep = core->cons->context->grep;
4761 r_list_foreach (core->anal->fcns, iter, fcn) {
4762 char *buf;
4763 r_core_seek (core, fcn->addr, true);
4764 r_cons_push ();
4765 r_core_cmd (core, cmd, 0);
4766 buf = (char *)r_cons_get_buffer ();
4767 if (buf) {
4768 buf = strdup (buf);
4769 }
4770 r_cons_pop ();
4771 r_cons_strcat (buf);
4772 free (buf);
4773 if (r_cons_is_breaked ()) {
4774 break;
4775 }
4776 }
4777 core->cons->context->grep = grep;
4778 }
4779 goto out_finish;
4780 }
4781 break;
4782 case 't': // "@@t"
4783 {
4784 RDebugPid *p;
4785 int pid = core->dbg->pid;
4786 if (core->dbg->h && core->dbg->h->pids) {
4787 RList *list = core->dbg->h->pids (core->dbg, R_MAX (0, pid));
4788 r_list_foreach (list, iter, p) {
4789 r_cons_printf ("# PID %d\n", p->pid);
4790 r_debug_select (core->dbg, p->pid, p->pid);
4791 r_core_cmd (core, cmd, 0);
4792 r_cons_newline ();
4793 }
4794 r_list_free (list);
4795 }
4796 r_debug_select (core->dbg, pid, pid);
4797 goto out_finish;
4798 }
4799 break;
4800 case 'c': // "@@c:"
4801 if (each[1] == ':') {
4802 char *arg = r_core_cmd_str (core, each + 2);
4803 if (arg) {
4804 foreachOffset (core, cmd, arg);
4805 free (arg);
4806 }
4807 }
4808 break;
4809 case '=': // "@@="
4810 foreachOffset (core, cmd, str + 1);
4811 break;
4812 case 'd': // "@@d"
4813 if (each[1] == 'b' && each[2] == 't') {
4814 ut64 oseek = core->offset;
4815 RDebugFrame *frame;
4816 RListIter *iter;
4817 RList *list;
4818 list = r_debug_frames (core->dbg, UT64_MAX);
4819 i = 0;
4820 r_list_foreach (list, iter, frame) {
4821 switch (each[3]) {
4822 case 'b':
4823 r_core_seek (core, frame->bp, true);
4824 break;
4825 case 's':
4826 r_core_seek (core, frame->sp, true);
4827 break;
4828 default:
4829 case 'a':
4830 r_core_seek (core, frame->addr, true);
4831 break;
4832 }
4833 r_core_cmd (core, cmd, 0);
4834 r_cons_newline ();
4835 i++;
4836 }
4837 r_core_seek (core, oseek, false);
4838 r_list_free (list);
4839 } else {
4840 eprintf("Invalid for-each statement. Use @@=dbt[abs]\n");
4841 }
4842 break;
4843 case 'k': // "@@k"
4844 /* foreach list of items */
4845 {
4846 char *out = sdb_querys (core->sdb, NULL, 0, str + ((str[1])? 2: 1));
4847 if (out) {
4848 each = out;
4849 do {
4850 while (*each == ' ') {
4851 each++;
4852 }
4853 if (!*each) {
4854 break;
4855 }
4856 str = strchr (each, ' ');
4857 if (str) {
4858 *str = '\0';
4859 addr = r_num_math (core->num, each);
4860 *str = ' ';
4861 } else {
4862 addr = r_num_math (core->num, each);
4863 }
4864 //eprintf ("; 0x%08"PFMT64x":\n", addr);
4865 each = str + 1;
4866 r_core_seek (core, addr, true);
4867 r_core_cmd (core, cmd, 0);
4868 r_cons_flush ();
4869 } while (str != NULL);
4870 free (out);
4871 }
4872 }
4873 break;
4874 case '.': // "@@."
4875 if (each[1] == '(') {
4876 char cmd2[1024];
4877 // XXX what's this 999 ?
4878 i = 0;
4879 for (core->rcmd->macro.counter = 0; i < 999; core->rcmd->macro.counter++) {
4880 if (r_cons_is_breaked ()) {
4881 break;
4882 }
4883 r_cmd_macro_call (&core->rcmd->macro, each + 2);
4884 if (!core->rcmd->macro.brk_value) {
4885 break;
4886 }
4887 addr = core->rcmd->macro._brk_value;
4888 sprintf (cmd2, "%s @ 0x%08"PFMT64x"", cmd, addr);
4889 eprintf ("0x%08"PFMT64x" (%s)\n", addr, cmd2);
4890 r_core_seek (core, addr, true);
4891 r_core_cmd (core, cmd2, 0);
4892 i++;
4893 }
4894 } else {
4895 char buf[1024];
4896 char cmd2[1024];
4897 FILE *fd = r_sandbox_fopen (each + 1, "r");
4898 if (fd) {
4899 core->rcmd->macro.counter = 0;
4900 while (!feof (fd)) {
4901 buf[0] = '\0';
4902 if (!fgets (buf, sizeof (buf), fd)) {
4903 break;
4904 }
4905 addr = r_num_math (core->num, buf);
4906 eprintf ("0x%08"PFMT64x": %s\n", addr, cmd);
4907 sprintf (cmd2, "%s @ 0x%08"PFMT64x"", cmd, addr);
4908 r_core_seek (core, addr, true); // XXX
4909 r_core_cmd (core, cmd2, 0);
4910 core->rcmd->macro.counter++;
4911 }
4912 fclose (fd);
4913 } else {
4914 eprintf ("cannot open file '%s' to read offsets\n", each + 1);
4915 }
4916 }
4917 break;
4918 default:
4919 core->rcmd->macro.counter = 0;
4920 for (; *each == ' '; each++) {
4921 ;
4922 }
4923 i = 0;
4924 while (str[i]) {
4925 j = i;
4926 for (; str[j] && str[j] == ' '; j++) {
4927 ; // skip spaces
4928 }
4929 for (i = j; str[i] && str[i] != ' '; i++) {
4930 ; // find EOS
4931 }
4932 ch = str[i];
4933 str[i] = '\0';
4934 word = strdup (str + j);
4935 if (!word) {
4936 break;
4937 }
4938 str[i] = ch;
4939 {
4940 const RSpace *flagspace = r_flag_space_cur (core->flags);
4941 RList *match_flag_items = r_list_newf ((RListFree)r_flag_item_free);
4942 if (!match_flag_items) {
4943 break;
4944 }
4945
4946 /* duplicate flags that match word, to be sure
4947 the command is going to be executed on flags
4948 values at the moment the command is called
4949 (without side effects) */
4950 struct duplicate_flag_t u = {
4951 .ret = match_flag_items,
4952 .word = word,
4953 };
4954 r_flag_foreach_space (core->flags, flagspace, duplicate_flag, &u);
4955
4956 /* for all flags that match */
4957 r_list_foreach (match_flag_items, iter, flag) {
4958 if (r_cons_is_breaked ()) {
4959 break;
4960 }
4961
4962 char *buf = NULL;
4963 const char *tmp = NULL;
4964 r_core_seek (core, flag->offset, true);
4965 r_cons_push ();
4966 r_core_cmd (core, cmd, 0);
4967 tmp = r_cons_get_buffer ();
4968 buf = tmp? strdup (tmp): NULL;
4969 r_cons_pop ();
4970 r_cons_strcat (buf);
4971 free (buf);
4972 r_core_task_yield (&core->tasks);
4973 }
4974
4975 r_list_free (match_flag_items);
4976 core->rcmd->macro.counter++ ;
4977 R_FREE (word);
4978 }
4979 }
4980 }
4981 r_cons_break_pop ();
4982 // XXX: use r_core_seek here
4983 core->offset = oseek;
4984
4985 free (word);
4986 free (ostr);
4987 return true;
4988 out_finish:
4989 free (ostr);
4990 r_cons_break_pop ();
4991 return false;
4992 }
4993
4994 static int run_cmd_depth(RCore *core, char *cmd);
4995
4996 struct tsr2cmd_state {
4997 TSParser *parser;
4998 RCore *core;
4999 char *input;
5000 char *saved_input;
5001 TSTree *tree;
5002 TSTree *saved_tree;
5003 bool log;
5004 bool split_lines;
5005 bool is_last_cmd;
5006 TSNode substitute_cmd;
5007 };
5008
5009 struct tsr2cmd_edit {
5010 char *new_text;
5011 char *old_text;
5012 ut32 start;
5013 ut32 end;
5014 TSPoint start_point;
5015 TSPoint end_point;
5016 };
5017
5018 typedef RCmdStatus (*ts_handler)(struct tsr2cmd_state *state, TSNode node);
5019
5020 struct ts_data_symbol_map {
5021 const char *name;
5022 void *data;
5023 };
5024
5025 #define TS_START_END(node, start, end) do { \
5026 start = ts_node_start_byte (node); \
5027 end = ts_node_end_byte (node); \
5028 } while (0)
5029
ts_node_sub_string(TSNode node,const char * cstr)5030 static char *ts_node_sub_string(TSNode node, const char *cstr) {
5031 ut32 start, end;
5032 TS_START_END (node, start, end);
5033 return r_str_newf ("%.*s", end - start, cstr + start);
5034 }
5035
ts_node_sub_parent_string(TSNode parent,TSNode node,const char * cstr)5036 static char *ts_node_sub_parent_string(TSNode parent, TSNode node, const char *cstr) {
5037 ut32 start, end;
5038 TS_START_END (node, start, end);
5039 ut32 parent_start = ts_node_start_byte (parent);
5040 start -= parent_start;
5041 end -= parent_start;
5042 return r_str_newf ("%.*s", end - start, cstr + start);
5043 }
5044
5045 #define DEFINE_SYMBOL_TS_FCN(name) TSSymbol ts_##name##_symbol
5046
5047 #define DEFINE_IS_TS_FCN(name) \
5048 static inline bool is_ts_##name(TSNode node) { \
5049 return ts_node_symbol (node) == ts_##name##_symbol; \
5050 }
5051
5052 #define DEFINE_IS_TS_FCN_AND_SYMBOL(name) \
5053 DEFINE_SYMBOL_TS_FCN (name); \
5054 DEFINE_IS_TS_FCN (name)
5055
5056 #define DEFINE_HANDLE_TS_FCN(name) \
5057 static RCmdStatus handle_ts_##name##_internal(struct tsr2cmd_state *state, TSNode node, char *node_string); \
5058 static RCmdStatus handle_ts_##name(struct tsr2cmd_state *state, TSNode node) { \
5059 char *node_string = ts_node_sub_string (node, state->input); \
5060 R_LOG_DEBUG (#name ": '%s'\n", node_string); \
5061 RCmdStatus res = handle_ts_##name##_internal (state, node, node_string); \
5062 free (node_string); \
5063 return res; \
5064 } \
5065 static RCmdStatus handle_ts_##name##_internal(struct tsr2cmd_state *state, TSNode node, char *node_string)
5066
5067 #define DEFINE_HANDLE_TS_FCN_AND_SYMBOL(name) \
5068 DEFINE_SYMBOL_TS_FCN (name); \
5069 DEFINE_HANDLE_TS_FCN (name)
5070
5071 #define UPDATE_CMD_STATUS_RES(res, cmd_res, label) \
5072 if ((cmd_res) != R_CMD_STATUS_OK) { \
5073 res = (cmd_res); \
5074 goto label; \
5075 }
5076
5077 static RCmdStatus handle_ts_command(struct tsr2cmd_state *state, TSNode node);
5078 static RCmdStatus handle_ts_command_tmpseek(struct tsr2cmd_state *state, TSNode node);
5079 static RCmdStatus core_cmd_tsr2cmd(RCore *core, const char *cstr, bool split_lines, bool log);
5080
5081 DEFINE_IS_TS_FCN_AND_SYMBOL(fdn_redirect_operator)
DEFINE_IS_TS_FCN_AND_SYMBOL(fdn_append_operator)5082 DEFINE_IS_TS_FCN_AND_SYMBOL(fdn_append_operator)
5083 DEFINE_IS_TS_FCN_AND_SYMBOL(html_redirect_operator)
5084 DEFINE_IS_TS_FCN_AND_SYMBOL(html_append_operator)
5085 DEFINE_IS_TS_FCN_AND_SYMBOL(cmd_substitution_arg)
5086 DEFINE_IS_TS_FCN_AND_SYMBOL(args)
5087 DEFINE_IS_TS_FCN_AND_SYMBOL(arg)
5088 DEFINE_IS_TS_FCN_AND_SYMBOL(arg_identifier)
5089 DEFINE_IS_TS_FCN_AND_SYMBOL(pf_arg)
5090 DEFINE_IS_TS_FCN_AND_SYMBOL(pf_args)
5091 DEFINE_IS_TS_FCN_AND_SYMBOL(pf_dot_cmd_args)
5092 DEFINE_IS_TS_FCN_AND_SYMBOL(pf_new_args)
5093 DEFINE_IS_TS_FCN_AND_SYMBOL(pf_concatenation)
5094 DEFINE_IS_TS_FCN_AND_SYMBOL(double_quoted_arg)
5095 DEFINE_IS_TS_FCN_AND_SYMBOL(single_quoted_arg)
5096 DEFINE_IS_TS_FCN_AND_SYMBOL(concatenation)
5097 DEFINE_IS_TS_FCN_AND_SYMBOL(grep_specifier)
5098 DEFINE_IS_TS_FCN_AND_SYMBOL(commands)
5099
5100 static struct tsr2cmd_edit *create_cmd_edit(struct tsr2cmd_state *state, TSNode arg, char *new_text) {
5101 struct tsr2cmd_edit *e = R_NEW0 (struct tsr2cmd_edit);
5102 ut32 command_start = ts_node_start_byte (state->substitute_cmd);
5103 TSPoint command_point = ts_node_start_point (state->substitute_cmd);
5104 e->new_text = new_text;
5105 e->old_text = ts_node_sub_parent_string (state->substitute_cmd, arg, state->input);
5106 e->start = ts_node_start_byte (arg) - command_start;
5107 e->end = ts_node_end_byte (arg) - command_start;
5108 e->start_point = ts_node_start_point (arg);
5109 e->end_point = ts_node_end_point (arg);
5110 if (e->start_point.row == command_point.row) {
5111 e->start_point.column -= command_point.column;
5112 }
5113 if (e->end_point.row == command_point.row) {
5114 e->end_point.column -= command_point.column;
5115 }
5116 e->start_point.row -= command_point.row;
5117 e->end_point.row -= command_point.row;
5118 return e;
5119 }
5120
replace_whitespaces(char * s,char ch)5121 static void replace_whitespaces(char *s, char ch) {
5122 while (*s) {
5123 if (*s == '#') {
5124 while (*s && *s != '\r' && *s != '\n') {
5125 *s = ch;
5126 s++;
5127 }
5128 }
5129 if (isspace ((unsigned char)*s)) {
5130 *s = ch;
5131 }
5132 s++;
5133 }
5134 }
5135
escape_special_chars(char * s,const char * special_chars)5136 static char *escape_special_chars(char *s, const char *special_chars) {
5137 size_t s_len = strlen (s);
5138 char *d = R_NEWS (char, s_len * 2 + 1);
5139 int i, j = 0;
5140 for (i = 0; i < s_len; i++) {
5141 if (strchr (special_chars, s[i])) {
5142 d[j++] = '\\';
5143 }
5144 d[j++] = s[i];
5145 }
5146 d[j++] = '\0';
5147 free (s);
5148 return d;
5149 }
5150
free_tsr2cmd_edit(struct tsr2cmd_edit * edit)5151 void free_tsr2cmd_edit(struct tsr2cmd_edit *edit) {
5152 free (edit->new_text);
5153 free (edit->old_text);
5154 free (edit);
5155 }
5156
do_handle_substitution_cmd(struct tsr2cmd_state * state,TSNode inn_cmd)5157 static char *do_handle_substitution_cmd(struct tsr2cmd_state *state, TSNode inn_cmd) {
5158 RCore *core = state->core;
5159 int value = core->num->value;
5160 char *inn_str = ts_node_sub_parent_string (state->substitute_cmd, inn_cmd, state->input);
5161
5162 // save current color and disable it
5163 int ocolor = r_config_get_i (core->config, "scr.color");
5164 r_config_set_i (core->config, "scr.color", 0);
5165 core->cmd_in_backticks = true;
5166
5167 // execute the sub command
5168 char *o_out = inn_str[0] == '!'?
5169 r_core_cmd_str_pipe (core, inn_str):
5170 r_core_cmd_str (core, inn_str);
5171
5172 // restore color and cmd_in_backticks
5173 core->num->value = value;
5174 core->cmd_in_backticks = false;
5175 r_config_set_i (core->config, "scr.color", ocolor);
5176 free (inn_str);
5177
5178 // replace the output of the sub command with the current argument
5179 char *out = strdup (o_out);
5180 r_str_trim (out);
5181 R_LOG_DEBUG ("output of inner command: '%s'\n", out);
5182 free (o_out);
5183
5184 // replace newlines and similar with spaces
5185 replace_whitespaces (out, ' ');
5186 return out;
5187 }
5188
handle_cmd_substitution_arg(struct tsr2cmd_state * state,TSNode arg,RList * edits)5189 static void handle_cmd_substitution_arg(struct tsr2cmd_state *state, TSNode arg, RList *edits) {
5190 TSNode inn_cmd = ts_node_child (arg, 1);
5191 r_return_if_fail (!ts_node_is_null (inn_cmd));
5192 char *out = do_handle_substitution_cmd (state, inn_cmd);
5193 // escape special chars to prevent creation of new tokens when parsing again
5194 const char *special_chars;
5195 if (is_ts_double_quoted_arg (ts_node_parent (arg))) {
5196 special_chars = SPECIAL_CHARS_DOUBLE_QUOTED;
5197 } else if (is_ts_pf_arg (ts_node_parent (arg))) {
5198 special_chars = SPECIAL_CHARS_PF;
5199 } else {
5200 special_chars = SPECIAL_CHARS_REGULAR;
5201 }
5202 out = escape_special_chars (out, special_chars);
5203 struct tsr2cmd_edit *e = create_cmd_edit (state, arg, out);
5204 r_list_append (edits, e);
5205 }
5206
is_group_of_args(TSNode args)5207 static bool is_group_of_args(TSNode args) {
5208 return is_ts_args (args) || is_ts_concatenation (args) ||
5209 is_ts_double_quoted_arg (args) ||
5210 is_ts_pf_concatenation (args) || is_ts_pf_args (args) ||
5211 is_ts_pf_dot_cmd_args (args) || is_ts_pf_new_args (args) ||
5212 is_ts_grep_specifier (args);
5213 }
5214
is_arg(TSNode args)5215 static bool is_arg(TSNode args) {
5216 return is_ts_arg (args) || is_ts_pf_arg (args);
5217 }
5218
is_handled_args(TSNode args)5219 static bool is_handled_args(TSNode args) {
5220 return is_group_of_args (args) || is_arg (args) ||
5221 is_ts_cmd_substitution_arg (args) || is_ts_grep_specifier (args);
5222 }
5223
handle_substitution_args(struct tsr2cmd_state * state,TSNode args,RList * edits)5224 static void handle_substitution_args(struct tsr2cmd_state *state, TSNode args, RList *edits) {
5225 if (is_group_of_args (args)) {
5226 uint32_t n_children = ts_node_named_child_count (args);
5227 uint32_t i;
5228 for (i = 0; i < n_children; i++) {
5229 TSNode arg = ts_node_named_child (args, i);
5230 handle_substitution_args (state, arg, edits);
5231 }
5232 } else if (is_ts_cmd_substitution_arg (args)) {
5233 handle_cmd_substitution_arg (state, args, edits);
5234 } else if (is_arg (args)) {
5235 TSNode arg = ts_node_named_child (args, 0);
5236 handle_substitution_args (state, arg, edits);
5237 }
5238 }
5239
unescape_arg_str(struct tsr2cmd_state * state,const char * arg_str,const char * special_chars)5240 static char *unescape_arg_str(struct tsr2cmd_state *state, const char *arg_str, const char *special_chars) {
5241 char *unescaped_arg = unescape_special_chars (arg_str, special_chars);
5242 R_LOG_DEBUG ("original arg = '%s', unescaped arg = '%s'\n", arg_str, unescaped_arg);
5243 return unescaped_arg;
5244 }
5245
unescape_arg(struct tsr2cmd_state * state,TSNode arg,const char * special_chars)5246 static char *unescape_arg(struct tsr2cmd_state *state, TSNode arg, const char *special_chars) {
5247 char *arg_str = ts_node_sub_string (arg, state->input);
5248 char *unescaped_arg = unescape_arg_str (state, arg_str, special_chars);
5249 free (arg_str);
5250 return unescaped_arg;
5251 }
5252
do_handle_ts_unescape_arg(struct tsr2cmd_state * state,TSNode arg,bool do_unwrap)5253 static char *do_handle_ts_unescape_arg(struct tsr2cmd_state *state, TSNode arg, bool do_unwrap) {
5254 if (is_ts_arg (arg)) {
5255 return do_handle_ts_unescape_arg (state, ts_node_named_child (arg, 0), do_unwrap);
5256 } else if (is_ts_arg_identifier (arg)) {
5257 return unescape_arg (state, arg, SPECIAL_CHARS_REGULAR);
5258 } else if (is_ts_single_quoted_arg (arg) || is_ts_double_quoted_arg (arg)) {
5259 const char *special = is_ts_single_quoted_arg (arg)? SPECIAL_CHARS_SINGLE_QUOTED: SPECIAL_CHARS_DOUBLE_QUOTED;
5260 char *o_arg_str = ts_node_sub_string (arg, state->input);
5261 char *arg_str = o_arg_str;
5262 if (do_unwrap) {
5263 // remove quotes
5264 arg_str[strlen (arg_str) - 1] = '\0';
5265 arg_str++;
5266 }
5267 char *res = unescape_arg_str (state, arg_str, special);
5268 free (o_arg_str);
5269 return res;
5270 } else if (is_ts_concatenation (arg)) {
5271 uint32_t i, n_children = ts_node_named_child_count (arg);
5272 RStrBuf *sb = r_strbuf_new (NULL);
5273 for (i = 0; i < n_children; i++) {
5274 TSNode sub_arg = ts_node_named_child (arg, i);
5275 char *s = do_handle_ts_unescape_arg (state, sub_arg, do_unwrap);
5276 r_strbuf_append (sb, s);
5277 }
5278 return r_strbuf_drain (sb);
5279 } else {
5280 return ts_node_sub_string (arg, state->input);
5281 }
5282 }
5283
parse_args(struct tsr2cmd_state * state,TSNode args,bool do_unwrap)5284 static RCmdParsedArgs *parse_args(struct tsr2cmd_state *state, TSNode args, bool do_unwrap) {
5285 if (ts_node_is_null (args)) {
5286 return r_cmd_parsed_args_newargs (0, NULL);
5287 } else if (is_ts_args (args)) {
5288 uint32_t n_children = ts_node_named_child_count (args);
5289 uint32_t i;
5290 char **unescaped_args = R_NEWS0 (char *, n_children);
5291 for (i = 0; i < n_children; i++) {
5292 TSNode arg = ts_node_named_child (args, i);
5293 unescaped_args[i] = do_handle_ts_unescape_arg (state, arg, do_unwrap);
5294 }
5295 RCmdParsedArgs *res = r_cmd_parsed_args_newargs (n_children, unescaped_args);
5296 for (i = 0; i < n_children; i++) {
5297 free (unescaped_args[i]);
5298 }
5299 free (unescaped_args);
5300 return res;
5301 } else {
5302 char *unescaped_args[] = { do_handle_ts_unescape_arg (state, args, do_unwrap) };
5303 RCmdParsedArgs *res = r_cmd_parsed_args_newargs (1, unescaped_args);
5304 free (unescaped_args[0]);
5305 return res;
5306 }
5307 }
5308
apply_edits(struct tsr2cmd_state * state,RList * edits)5309 static TSTree *apply_edits(struct tsr2cmd_state *state, RList *edits) {
5310 struct tsr2cmd_edit *edit;
5311 RListIter *it;
5312
5313 R_LOG_DEBUG ("old input = '%s'\n", state->input);
5314 r_list_foreach (edits, it, edit) {
5315 R_LOG_DEBUG ("apply_edits: about to replace '%s' with '%s'\n", edit->old_text, edit->new_text);
5316 state->input = r_str_replace (state->input, edit->old_text, edit->new_text, 0);
5317 }
5318 R_LOG_DEBUG ("new input = '%s'\n", state->input);
5319 return ts_parser_parse_string (state->parser, NULL, state->input, strlen (state->input));
5320 }
5321
substitute_args_fini(struct tsr2cmd_state * state)5322 static void substitute_args_fini(struct tsr2cmd_state *state) {
5323 if (state->tree != state->saved_tree) {
5324 ts_tree_delete (state->tree);
5325 }
5326 state->tree = state->saved_tree;
5327 state->saved_tree = NULL;
5328 if (state->input != state->saved_input) {
5329 free (state->input);
5330 }
5331 state->input = state->saved_input;
5332 state->saved_input = NULL;
5333 }
5334
substitute_args_init(struct tsr2cmd_state * state,TSNode command)5335 static void substitute_args_init(struct tsr2cmd_state *state, TSNode command) {
5336 state->saved_input = state->input;
5337 state->saved_tree = state->tree;
5338 state->substitute_cmd = command;
5339 state->input = ts_node_sub_string (state->substitute_cmd, state->input);
5340 R_LOG_DEBUG ("Shrinking input to '%s'\n", state->input);
5341 }
5342
substitute_args_do(struct tsr2cmd_state * state,RList * edits,TSNode * new_command)5343 static bool substitute_args_do(struct tsr2cmd_state *state, RList *edits, TSNode *new_command) {
5344 TSTree *new_tree = apply_edits (state, edits);
5345 if (!new_tree) {
5346 return false;
5347 }
5348
5349 TSNode root = ts_tree_root_node (new_tree);
5350 if (ts_node_has_error (root)) {
5351 ts_tree_delete (new_tree);
5352 return false;
5353 }
5354 *new_command = ts_node_named_child (root, 0);
5355 state->tree = new_tree;
5356 return true;
5357 }
5358
substitute_args(struct tsr2cmd_state * state,TSNode args,TSNode * new_command)5359 static bool substitute_args(struct tsr2cmd_state *state, TSNode args, TSNode *new_command) {
5360 RList *edits = r_list_newf ((RListFree)free_tsr2cmd_edit);
5361
5362 if (is_handled_args (args)) {
5363 handle_substitution_args (state, args, edits);
5364 }
5365
5366 bool res = substitute_args_do (state, edits, new_command);
5367 r_list_free (edits);
5368 return res;
5369 }
5370
ts_node_handle_arg_prargs(struct tsr2cmd_state * state,TSNode command,TSNode arg,uint32_t child_idx,bool do_unwrap)5371 static RCmdParsedArgs *ts_node_handle_arg_prargs(struct tsr2cmd_state *state, TSNode command, TSNode arg, uint32_t child_idx, bool do_unwrap) {
5372 RCmdParsedArgs *res = NULL;
5373 TSNode new_command;
5374 substitute_args_init (state, command);
5375 bool ok = substitute_args (state, arg, &new_command);
5376 if (!ok) {
5377 R_LOG_ERROR ("Error while substituting arguments\n");
5378 goto err;
5379 }
5380
5381 arg = ts_node_named_child (new_command, child_idx);
5382 res = parse_args (state, arg, do_unwrap);
5383 if (res == NULL) {
5384 R_LOG_ERROR ("Cannot parse arg\n");
5385 goto err;
5386 }
5387 err:
5388 substitute_args_fini (state);
5389 return res;
5390 }
5391
ts_node_handle_arg(struct tsr2cmd_state * state,TSNode command,TSNode arg,uint32_t child_idx)5392 static char *ts_node_handle_arg(struct tsr2cmd_state *state, TSNode command, TSNode arg, uint32_t child_idx) {
5393 RCmdParsedArgs *a = ts_node_handle_arg_prargs (state, command, arg, child_idx, true);
5394 char *str = r_cmd_parsed_args_argstr (a);
5395 r_cmd_parsed_args_free (a);
5396 return str;
5397 }
5398
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(arged_command)5399 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(arged_command) {
5400 TSNode command = ts_node_child_by_field_name (node, "command", strlen ("command"));
5401 r_return_val_if_fail (!ts_node_is_null (command), false);
5402 char *command_str = ts_node_sub_string (command, state->input);
5403 R_LOG_DEBUG ("arged_command command: '%s'\n", command_str);
5404 TSNode args = ts_node_child_by_field_name (node, "args", strlen ("args"));
5405 RCmdStatus res = R_CMD_STATUS_INVALID;
5406
5407 // FIXME: this special handling should be removed once we have a proper
5408 // command tree
5409 if (!strcmp (command_str, "|.")) {
5410 char *cmd_str = ts_node_sub_string (args, state->input);
5411 char *exec_string = r_str_newf (".%s", cmd_str);
5412 free (cmd_str);
5413 free (command_str);
5414 res = core_cmd_tsr2cmd (state->core, exec_string, state->split_lines, false);
5415 free (exec_string);
5416 return res;
5417 }
5418
5419 RCmdParsedArgs *pr_args = NULL;
5420 if (!ts_node_is_null (args)) {
5421 RCmdDesc *cd = r_cmd_get_desc (state->core->rcmd, command_str);
5422 bool do_unwrap = cd && cd->type != R_CMD_DESC_TYPE_OLDINPUT;
5423 pr_args = ts_node_handle_arg_prargs (state, node, args, 1, do_unwrap);
5424 if (!pr_args) {
5425 goto err;
5426 }
5427 r_cmd_parsed_args_setcmd (pr_args, command_str);
5428 } else {
5429 pr_args = r_cmd_parsed_args_newcmd (command_str);
5430 if (!pr_args) {
5431 goto err;
5432 }
5433 }
5434
5435 int i;
5436 const char *s;
5437 r_cmd_parsed_args_foreach_arg (pr_args, i, s) {
5438 R_LOG_DEBUG ("parsed_arg %d: '%s'\n", i, s);
5439 }
5440
5441 pr_args->has_space_after_cmd = !ts_node_is_null (args) && ts_node_end_byte (command) < ts_node_start_byte (args);
5442 res = r_cmd_call_parsed_args (state->core->rcmd, pr_args);
5443 if (res == R_CMD_STATUS_WRONG_ARGS) {
5444 const char *cmdname = r_cmd_parsed_args_cmd (pr_args);
5445 eprintf ("Wrong number of arguments passed to `%s`, see its help with `%s?`\n", cmdname, cmdname);
5446 } else if (res == R_CMD_STATUS_ERROR) {
5447 const char *cmdname = r_cmd_parsed_args_cmd (pr_args);
5448 R_LOG_DEBUG ("Something wrong during the execution of `%s` command.\n", cmdname);
5449 }
5450
5451 err:
5452 r_cmd_parsed_args_free (pr_args);
5453 free (command_str);
5454 return res;
5455 }
5456
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(legacy_quoted_command)5457 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(legacy_quoted_command) {
5458 return r_cmd_int2status(run_cmd_depth (state->core, node_string));
5459 }
5460
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(repeat_command)5461 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(repeat_command) {
5462 TSNode number = ts_node_child_by_field_name (node, "arg", strlen ("arg"));
5463 char *number_str = ts_node_sub_string (number, state->input);
5464 int rep = atoi (number_str);
5465 free (number_str);
5466
5467 TSNode command = ts_node_child_by_field_name (node, "command", strlen ("command"));
5468 if (rep > 1 && r_sandbox_enable (0)) {
5469 eprintf ("Command repeat sugar disabled in sandbox mode (%s)\n", node_string);
5470 return R_CMD_STATUS_INVALID;
5471 }
5472 if (rep > INTERACTIVE_MAX_REP && r_cons_is_interactive ()) {
5473 if (!r_cons_yesno ('n', "Are you sure to repeat this %d times? (y/N)", rep)) {
5474 return R_CMD_STATUS_INVALID;
5475 }
5476 }
5477
5478 RCmdStatus res = R_CMD_STATUS_OK;
5479 size_t i;
5480 for (i = 0; i < rep; i++) {
5481 RCmdStatus cmd_res = handle_ts_command (state, command);
5482 UPDATE_CMD_STATUS_RES (res, cmd_res, err);
5483 }
5484 err:
5485 return res;
5486 }
5487
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(redirect_command)5488 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(redirect_command) {
5489 int pipecolor = r_config_get_i (state->core->config, "scr.color.pipe");
5490 int ocolor = r_config_get_i (state->core->config, "scr.color");
5491 int scr_html = -1;
5492 RCmdStatus res = R_CMD_STATUS_INVALID, is_append = false, is_html = false;
5493 int fdn = 1;
5494
5495 TSNode redirect_op = ts_node_child_by_field_name (node, "redirect_operator", strlen ("redirect_operator"));
5496 if (is_ts_fdn_redirect_operator (redirect_op)) {
5497 // this is the default operation, no html and no append
5498 } else if (is_ts_fdn_append_operator (redirect_op)) {
5499 is_append = true;
5500 } else if (is_ts_html_redirect_operator (redirect_op)) {
5501 is_html = true;
5502 } else if (is_ts_html_append_operator (redirect_op)) {
5503 is_html = true;
5504 is_append = true;
5505 } else {
5506 R_LOG_ERROR ("This should never happen, redirect_operator is no known type");
5507 r_warn_if_reached ();
5508 }
5509
5510 if (is_html) {
5511 scr_html = r_config_get_i (state->core->config, "scr.html");
5512 r_config_set_i (state->core->config, "scr.html", true);
5513 pipecolor = true;
5514 } else {
5515 TSNode fd_desc = ts_node_named_child (redirect_op, 0);
5516 if (!ts_node_is_null (fd_desc)) {
5517 char *fd_str = ts_node_sub_string (fd_desc, state->input);
5518 fdn = atoi (fd_str);
5519 free (fd_str);
5520 }
5521 }
5522
5523 r_cons_set_interactive (false);
5524 // TODO: allow to use editor as the old behaviour
5525
5526 // extract the string of the filename we need to write to
5527 TSNode arg = ts_node_child_by_field_name (node, "arg", strlen ("arg"));
5528 char *arg_str = ts_node_sub_string (arg, state->input);
5529
5530 if (arg_str[0] == '$') {
5531 // redirect output of command to an alias variable
5532 R_LOG_DEBUG ("redirect_command: alias = '%s'\n", arg_str);
5533 TSNode command = ts_node_child_by_field_name (node, "command", strlen ("command"));
5534 char *command_str = ts_node_sub_string (command, state->input);
5535
5536 char *output = r_core_cmd_str (state->core, command_str);
5537 const char *old_alias_value = r_cmd_alias_get (state->core->rcmd, arg_str, 1);
5538 char *new_alias_value;
5539 const char *start_char = "$";
5540 if (is_append && old_alias_value) {
5541 start_char = "";
5542 } else {
5543 old_alias_value = "";
5544 }
5545 new_alias_value = r_str_newf ("%s%s%s", start_char, old_alias_value, output);
5546 r_cmd_alias_set (state->core->rcmd, arg_str, new_alias_value, 1);
5547 free (new_alias_value);
5548 free (command_str);
5549 res = R_CMD_STATUS_OK;
5550 } else {
5551 r_cons_flush ();
5552 R_LOG_DEBUG ("redirect_command: fdn = %d, is_append = %d\n", fdn, is_append);
5553 int pipefd = r_cons_pipe_open (arg_str, fdn, is_append);
5554 if (pipefd != -1) {
5555 if (!pipecolor) {
5556 r_config_set_i (state->core->config, "scr.color", COLOR_MODE_DISABLED);
5557 }
5558 TSNode command = ts_node_child_by_field_name (node, "command", strlen ("command"));
5559 res = handle_ts_command (state, command);
5560 r_cons_flush ();
5561 r_cons_pipe_close (pipefd);
5562 } else {
5563 R_LOG_WARN ("Could not open pipe to %d", fdn);
5564 }
5565 }
5566 free (arg_str);
5567 r_cons_set_last_interactive ();
5568 if (!pipecolor) {
5569 r_config_set_i (state->core->config, "scr.color", ocolor);
5570 }
5571 if (scr_html != -1) {
5572 r_config_set_i (state->core->config, "scr.html", scr_html);
5573 }
5574 state->core->cons->use_tts = false;
5575 return res;
5576 }
5577
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(help_command)5578 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(help_command) {
5579 // TODO: traverse command tree to print help
5580 // FIXME: once we have a command tree, this special handling should be removed
5581 size_t node_str_len = strlen (node_string);
5582 if (!strcmp (node_string, "@?")) {
5583 r_core_cmd_help (state->core, help_msg_at);
5584 } else if (!strcmp (node_string, "@@?")) {
5585 r_core_cmd_help (state->core, help_msg_at_at);
5586 } else if (!strcmp (node_string, "@@@?")) {
5587 r_core_cmd_help (state->core, help_msg_at_at_at);
5588 } else if (!strcmp (node_string, "|?")) {
5589 r_core_cmd_help (state->core, help_msg_vertical_bar);
5590 } else if (!strcmp (node_string, "~?")) {
5591 r_cons_grep_help ();
5592 } else if (!strcmp (node_string, ">?")) {
5593 r_core_cmd_help (state->core, help_msg_greater_sign);
5594 } else if (node_str_len >= 2 && !strcmp (node_string + node_str_len - 2, "?*")) {
5595 int detail = 0;
5596 if (node_str_len > 3 && node_string[node_str_len - 3] == '?') {
5597 detail++;
5598 if (node_str_len > 4 && node_string[node_str_len - 4] == '?') {
5599 detail++;
5600 }
5601 }
5602 node_string[node_str_len - 2 - detail] = '\0';
5603 recursive_help (state->core, detail, node_string);
5604 return R_CMD_STATUS_OK;
5605 } else {
5606 TSNode command = ts_node_child_by_field_name (node, "command", strlen ("command"));
5607 char *command_str = ts_node_sub_string (command, state->input);
5608 TSNode args = ts_node_child_by_field_name (node, "args", strlen ("args"));
5609 RCmdParsedArgs *pr_args = NULL;
5610 RCmdStatus res = R_CMD_STATUS_INVALID;
5611 if (!ts_node_is_null (args)) {
5612 RCmdDesc *cd = r_cmd_get_desc (state->core->rcmd, command_str);
5613 bool do_unwrap = cd && cd->type != R_CMD_DESC_TYPE_OLDINPUT;
5614 pr_args = ts_node_handle_arg_prargs (state, node, args, 1, do_unwrap);
5615 if (!pr_args) {
5616 goto err_else;
5617 }
5618 r_cmd_parsed_args_setcmd (pr_args, command_str);
5619 } else {
5620 pr_args = r_cmd_parsed_args_newcmd (command_str);
5621 if (!pr_args) {
5622 goto err_else;
5623 }
5624 }
5625
5626 // let's try first with the new auto-generated help, if
5627 // something fails fallback to old behaviour
5628 char *help_msg = r_cmd_get_help (state->core->rcmd, pr_args, state->core->print->flags & R_PRINT_FLAGS_COLOR);
5629 if (help_msg) {
5630 r_cons_printf ("%s", help_msg);
5631 free (help_msg);
5632 res = R_CMD_STATUS_OK;
5633 } else {
5634 res = r_cmd_call_parsed_args (state->core->rcmd, pr_args);
5635 }
5636 err_else:
5637 r_cmd_parsed_args_free (pr_args);
5638 free (command_str);
5639 return res;
5640 }
5641 return R_CMD_STATUS_OK;
5642 }
5643
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_seek_command)5644 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_seek_command) {
5645 TSNode command = ts_node_named_child (node, 0);
5646 TSNode offset = ts_node_named_child (node, 1);
5647 char *offset_string = ts_node_handle_arg (state, node, offset, 1);
5648 ut64 offset_val = r_num_math (state->core->num, offset_string);
5649 ut64 orig_offset = state->core->offset;
5650 if (!offset_val && isalpha ((int)offset_string[0])) {
5651 if (!r_flag_get (state->core->flags, offset_string)) {
5652 eprintf ("Invalid address (%s)\n", offset_string);
5653 free (offset_string);
5654 return R_CMD_STATUS_INVALID;
5655 }
5656 }
5657 if (offset_string[0] == '-' || offset_string[0] == '+') {
5658 offset_val += state->core->offset;
5659 }
5660 R_LOG_DEBUG ("tmp_seek_command, changing offset to %" PFMT64x "\n", offset_val);
5661 r_core_seek (state->core, offset_val, true);
5662 RCmdStatus res = handle_ts_command_tmpseek (state, command);
5663 r_core_seek (state->core, orig_offset, true);
5664 free (offset_string);
5665 return res;
5666 }
5667
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_blksz_command)5668 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_blksz_command) {
5669 TSNode command = ts_node_named_child (node, 0);
5670 TSNode blksz = ts_node_named_child (node, 1);
5671 char *blksz_string = ts_node_handle_arg (state, node, blksz, 1);
5672 ut64 orig_blksz = state->core->blocksize;
5673 R_LOG_DEBUG ("tmp_blksz_command, changing blksz to %s\n", blksz_string);
5674 r_core_block_size (state->core, r_num_math (state->core->num, blksz_string));
5675 RCmdStatus res = handle_ts_command (state, command);
5676 r_core_block_size (state->core, orig_blksz);
5677 free (blksz_string);
5678 return res;
5679 }
5680
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_fromto_command)5681 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_fromto_command) {
5682 RCore *core = state->core;
5683 TSNode command = ts_node_named_child (node, 0);
5684 TSNode from = ts_node_named_child (node, 1);
5685 TSNode to = ts_node_named_child (node, 2);
5686 char *from_str = ts_node_handle_arg (state, node, from, 1);
5687 char *to_str = ts_node_handle_arg (state, node, to, 2);
5688
5689 const char *fromvars[] = { "anal.from", "diff.from", "graph.from",
5690 "io.buffer.from", "lines.from", "search.from", "zoom.from", NULL };
5691 const char *tovars[] = { "anal.to", "diff.to", "graph.to",
5692 "io.buffer.to", "lines.to", "search.to", "zoom.to", NULL };
5693 ut64 from_val = r_num_math (core->num, from_str);
5694 ut64 to_val = r_num_math (core->num, to_str);
5695 R_LOG_DEBUG ("tmp_fromto_command, changing fromto to (%" PFMT64x ", %" PFMT64x ")\n", from_val, to_val);
5696
5697 RConfigHold *hc = r_config_hold_new (core->config);
5698 int i;
5699 for (i = 0; fromvars[i]; i++) {
5700 r_config_hold (hc, fromvars[i], NULL);
5701 r_config_set_i (core->config, fromvars[i], from_val);
5702 }
5703 for (i = 0; tovars[i]; i++) {
5704 r_config_hold (hc, tovars[i], NULL);
5705 r_config_set_i (core->config, tovars[i], to_val);
5706 }
5707
5708 RCmdStatus res = handle_ts_command (state, command);
5709
5710 r_config_hold_restore (hc);
5711
5712 r_config_hold_free (hc);
5713 free (from_str);
5714 free (to_str);
5715 return res;
5716 }
5717
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_arch_command)5718 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_arch_command) {
5719 RCore *core = state->core;
5720 TSNode command = ts_node_named_child (node, 0);
5721 TSNode arg = ts_node_named_child (node, 1);
5722 char *arg_str = ts_node_handle_arg (state, node, arg, 1);
5723 char *tmparch, *tmpbits;
5724 bool is_arch_set = false, is_bits_set = false;
5725 bool oldfixedarch = core->fixedarch, oldfixedbits = core->fixedbits;
5726 int cmd_ignbithints = -1;
5727
5728 // change arch and bits
5729 char *q = strchr (arg_str, ':');
5730 if (q) {
5731 *q++ = '\0';
5732 int bits = r_num_math (core->num, q);
5733 is_bits_set = set_tmp_bits (core, bits, &tmpbits, &cmd_ignbithints);
5734 }
5735 is_arch_set = set_tmp_arch (core, arg_str, &tmparch);
5736
5737 // execute command with changed settings
5738 RCmdStatus res = handle_ts_command (state, command);
5739
5740 // restore original settings
5741 if (is_arch_set) {
5742 core->fixedarch = oldfixedarch;
5743 r_config_set (core->config, "asm.arch", tmparch);
5744 free (tmparch);
5745 }
5746 if (is_bits_set) {
5747 r_config_set (core->config, "asm.bits", tmpbits);
5748 core->fixedbits = oldfixedbits;
5749 free (tmpbits);
5750 }
5751 if (cmd_ignbithints != -1) {
5752 r_config_set_i (core->config, "anal.ignbithints", cmd_ignbithints);
5753 }
5754 free (arg_str);
5755 return res;
5756 }
5757
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_bits_command)5758 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_bits_command) {
5759 RCore *core = state->core;
5760 TSNode command = ts_node_named_child (node, 0);
5761 TSNode arg = ts_node_named_child (node, 1);
5762 char *arg_str = ts_node_handle_arg (state, node, arg, 1);
5763 bool oldfixedbits = core->fixedbits;
5764 char *tmpbits;
5765 int cmd_ignbithints;
5766
5767 int bits = r_num_math (core->num, arg_str);
5768 set_tmp_bits (core, bits, &tmpbits, &cmd_ignbithints);
5769
5770 RCmdStatus res = handle_ts_command (state, command);
5771
5772 r_config_set (core->config, "asm.bits", tmpbits);
5773 core->fixedbits = oldfixedbits;
5774 r_config_set_i (core->config, "anal.ignbithints", cmd_ignbithints);
5775
5776 free (tmpbits);
5777 free (arg_str);
5778 return res;
5779 }
5780
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_nthi_command)5781 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_nthi_command) {
5782 RCore *core = state->core;
5783 TSNode command = ts_node_named_child (node, 0);
5784 TSNode arg = ts_node_named_child (node, 1);
5785 char *arg_str = ts_node_handle_arg (state, node, arg, 1);
5786
5787 ut64 orig_offset = state->core->offset;
5788 int index = r_num_math (core->num, arg_str);
5789 RAnalBlock *bb = r_anal_bb_from_offset (core->anal, core->offset);
5790 if (bb) {
5791 // handle negative indices
5792 if (index < 0) {
5793 index = bb->ninstr + index;
5794 }
5795
5796 if (index >= 0 && index < bb->ninstr) {
5797 ut16 inst_off = r_anal_bb_offset_inst (bb, index);
5798 r_core_seek (core, bb->addr + inst_off, true);
5799 } else {
5800 eprintf ("The current basic block has just %d instructions\n", bb->ninstr);
5801 }
5802 } else {
5803 eprintf ("Can't find a basic block for 0x%08" PFMT64x "\n", core->offset);
5804 }
5805
5806 RCmdStatus res = handle_ts_command_tmpseek (state, command);
5807
5808 r_core_seek (core, orig_offset, true);
5809
5810 free (arg_str);
5811 return res;
5812 }
5813
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_eval_command)5814 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_eval_command) {
5815 // TODO: support cmd_substitution in tmp_eval_args
5816 RCore *core = state->core;
5817 TSNode command = ts_node_named_child (node, 0);
5818 TSNode args = ts_node_named_child (node, 1);
5819
5820 RConfigHold *hc = r_config_hold_new (core->config);
5821 uint32_t i, n_args = ts_node_named_child_count (args);
5822 for (i = 0; i < n_args; i++) {
5823 TSNode arg = ts_node_named_child (args, i);
5824 char *arg_str = ts_node_sub_string (arg, state->input);
5825 char *eq = strchr (arg_str, '=');
5826 if (eq) {
5827 *eq = 0;
5828 r_config_hold (hc, arg_str, NULL);
5829 r_config_set (core->config, arg_str, eq + 1);
5830 } else {
5831 eprintf ("Missing '=' in e: expression (%s)\n", arg_str);
5832 }
5833 free (arg_str);
5834 }
5835
5836 RCmdStatus res = handle_ts_command (state, command);
5837
5838 r_config_hold_restore (hc);
5839 r_config_hold_free (hc);
5840 return res;
5841 }
5842
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_fs_command)5843 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_fs_command) {
5844 RCore *core = state->core;
5845 TSNode command = ts_node_named_child (node, 0);
5846 TSNode arg = ts_node_named_child (node, 1);
5847 char *arg_str = ts_node_handle_arg (state, node, arg, 1);
5848 r_flag_space_push (core->flags, arg_str);
5849 RCmdStatus res = handle_ts_command (state, command);
5850 r_flag_space_pop (core->flags);
5851 free (arg_str);
5852 return res;
5853 }
5854
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_reli_command)5855 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_reli_command) {
5856 RCore *core = state->core;
5857 TSNode command = ts_node_named_child (node, 0);
5858 TSNode arg = ts_node_named_child (node, 1);
5859 char *arg_str = ts_node_handle_arg (state, node, arg, 1);
5860 ut64 orig_offset = state->core->offset;
5861 ut64 addr = r_num_math (core->num, arg_str);
5862 if (addr) {
5863 r_core_cmdf (core, "so %" PFMT64d, addr);
5864 }
5865 RCmdStatus res = handle_ts_command_tmpseek (state, command);
5866 r_core_seek (state->core, orig_offset, true);
5867 free (arg_str);
5868 return res;
5869 }
5870
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_kuery_command)5871 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_kuery_command) {
5872 RCore *core = state->core;
5873 TSNode command = ts_node_named_child (node, 0);
5874 TSNode arg = ts_node_named_child (node, 1);
5875 char *arg_str = ts_node_handle_arg (state, node, arg, 1);
5876 ut64 orig_offset = state->core->offset;
5877 char *out = sdb_querys (core->sdb, NULL, 0, arg_str);
5878 if (out) {
5879 r_core_seek (core, r_num_math (core->num, out), true);
5880 free (out);
5881 }
5882 RCmdStatus res = handle_ts_command_tmpseek (state, command);
5883 r_core_seek (state->core, orig_offset, true);
5884 free (arg_str);
5885 return res;
5886 }
5887
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_fd_command)5888 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_fd_command) {
5889 RCore *core = state->core;
5890 TSNode command = ts_node_named_child (node, 0);
5891 TSNode arg = ts_node_named_child (node, 1);
5892 char *arg_str = ts_node_handle_arg (state, node, arg, 1);
5893 int tmpfd = core->io->desc? core->io->desc->fd: -1;
5894 r_io_use_fd (core->io, atoi (arg_str));
5895 RCmdStatus res = handle_ts_command (state, command);
5896 r_io_use_fd (core->io, tmpfd);
5897 free (arg_str);
5898 return res;
5899 }
5900
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_reg_command)5901 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_reg_command) {
5902 RCore *core = state->core;
5903 TSNode command = ts_node_named_child (node, 0);
5904 TSNode arg = ts_node_named_child (node, 1);
5905 char *arg_str = ts_node_handle_arg (state, node, arg, 1);
5906 ut64 orig_offset = state->core->offset;
5907 // TODO: add support for operations (e.g. @r:PC+10)
5908 ut64 regval = r_debug_reg_get (core->dbg, arg_str);
5909 r_core_seek (core, regval, true);
5910 RCmdStatus res = handle_ts_command_tmpseek (state, command);
5911 r_core_seek (core, orig_offset, true);
5912 free (arg_str);
5913 return res;
5914 }
5915
handle_tmp_desc(struct tsr2cmd_state * state,TSNode command,const ut8 * buf,int sz)5916 static bool handle_tmp_desc(struct tsr2cmd_state *state, TSNode command, const ut8 *buf, int sz) {
5917 RCore *core = state->core;
5918 int pamode = !core->io->va;
5919 RCmdStatus res = R_CMD_STATUS_INVALID, o_fixedblock = core->fixedblock;
5920 RBuffer *b = r_buf_new_with_bytes (buf, sz);
5921 RIODesc *d = r_io_open_buffer (core->io, b, R_PERM_RWX, 0);
5922 if (!d) {
5923 eprintf ("Cannot open io buffer\n");
5924 goto out_buf;
5925 }
5926 if (pamode) {
5927 r_config_set_i (core->config, "io.va", 1);
5928 }
5929 r_io_map_new (core->io, d->fd, d->perm, 0, core->offset, r_buf_size (b));
5930 r_core_block_size (core, r_buf_size (b));
5931 core->fixedblock = true;
5932 r_core_block_read (core);
5933
5934 res = handle_ts_command (state, command);
5935
5936 core->fixedblock = o_fixedblock;
5937 if (pamode) {
5938 r_config_set_i (core->config, "io.va", 0);
5939 }
5940 r_io_desc_close (d);
5941
5942 out_buf:
5943 r_buf_free (b);
5944 return res;
5945 }
5946
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_file_command)5947 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_file_command) {
5948 TSNode command = ts_node_named_child (node, 0);
5949 TSNode arg = ts_node_named_child (node, 1);
5950 char *arg_str = ts_node_handle_arg (state, node, arg, 1);
5951 size_t sz;
5952 RCmdStatus res = R_CMD_STATUS_INVALID;
5953
5954 char *f = r_file_slurp (arg_str, &sz);
5955 if (!f) {
5956 eprintf ("Cannot open '%s'\n", arg_str);
5957 goto out;
5958 }
5959
5960 res = handle_tmp_desc (state, command, (ut8 *)f, (int)sz);
5961
5962 free (f);
5963 out:
5964 free (arg_str);
5965 return res;
5966 }
5967
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_string_command)5968 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_string_command) {
5969 TSNode command = ts_node_named_child (node, 0);
5970 TSNode arg = ts_node_named_child (node, 1);
5971 char *arg_str = ts_node_handle_arg (state, node, arg, 1);
5972 int sz;
5973
5974 sz = strlen (arg_str);
5975 const ut8 *buf = (const ut8 *)arg_str;
5976
5977 RCmdStatus res = handle_tmp_desc (state, command, buf, sz);
5978
5979 free (arg_str);
5980 return res;
5981 }
5982
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_hex_command)5983 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_hex_command) {
5984 TSNode command = ts_node_named_child (node, 0);
5985 TSNode arg = ts_node_named_child (node, 1);
5986 char *arg_str = ts_node_handle_arg (state, node, arg, 1);
5987 int sz;
5988
5989 size_t len = strlen (arg_str);
5990 ut8 *buf = R_NEWS (ut8, len + 1);
5991 sz = r_hex_str2bin (arg_str, buf);
5992
5993 RCmdStatus res = handle_tmp_desc (state, command, buf, sz);
5994
5995 free (buf);
5996 free (arg_str);
5997 return res;
5998 }
5999
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_flags_command)6000 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_flags_command) {
6001 RCore *core = state->core;
6002 TSNode command = ts_node_named_child (node, 0);
6003 TSNode arg = ts_node_named_child (node, 1);
6004 char *arg_str = ts_node_handle_arg(state, node, arg, 1);
6005 const RSpace *flagspace = r_flag_space_cur (core->flags);
6006 RFlagItem *flag;
6007 RListIter *iter;
6008 RCmdStatus ret = R_CMD_STATUS_OK;
6009 RList *match_flag_items = r_list_newf ((RListFree)r_flag_item_free);
6010 if (!match_flag_items) {
6011 return R_CMD_STATUS_OK;
6012 }
6013
6014 /* duplicate flags that match word, to be sure the command is going to
6015 be executed on flags values at the moment the command is called
6016 (without side effects) */
6017 struct duplicate_flag_t u = {
6018 .ret = match_flag_items,
6019 .word = arg_str,
6020 };
6021 r_flag_foreach_space (core->flags, flagspace, duplicate_flag, &u);
6022
6023 /* for all flags that match */
6024 r_list_foreach (match_flag_items, iter, flag) {
6025 if (r_cons_is_breaked ()) {
6026 break;
6027 }
6028
6029 char *buf = NULL;
6030 const char *tmp = NULL;
6031 R_LOG_DEBUG ("iter_flags_command: seek to %" PFMT64x "\n", flag->offset);
6032 r_core_seek (core, flag->offset, true);
6033 r_cons_push ();
6034 RCmdStatus cmd_res = handle_ts_command_tmpseek (state, command);
6035 tmp = r_cons_get_buffer ();
6036 buf = tmp? strdup (tmp): NULL;
6037 r_cons_pop ();
6038 r_cons_strcat (buf);
6039 free (buf);
6040 r_core_task_yield (&core->tasks);
6041 UPDATE_CMD_STATUS_RES (ret, cmd_res, err);
6042 }
6043
6044 err:
6045 r_list_free (match_flag_items);
6046 free (arg_str);
6047 return ret;
6048 }
6049
6050 enum dbt_commands_mode {
6051 DBT_COMMANDS_MODE_ADDR,
6052 DBT_COMMANDS_MODE_BP,
6053 DBT_COMMANDS_MODE_SP,
6054 };
6055
iter_dbt_commands(struct tsr2cmd_state * state,TSNode node,enum dbt_commands_mode mode)6056 static bool iter_dbt_commands(struct tsr2cmd_state *state, TSNode node, enum dbt_commands_mode mode) {
6057 RCore *core = state->core;
6058 TSNode command = ts_node_named_child (node, 0);
6059 RList *list = r_debug_frames (core->dbg, UT64_MAX);
6060 ut64 orig_offset = core->offset;
6061 RDebugFrame *frame;
6062 RListIter *iter;
6063 RCmdStatus res = R_CMD_STATUS_OK;
6064
6065 r_list_foreach (list, iter, frame) {
6066 switch (mode) {
6067 case DBT_COMMANDS_MODE_ADDR:
6068 r_core_seek (core, frame->addr, true);
6069 break;
6070 case DBT_COMMANDS_MODE_SP:
6071 r_core_seek (core, frame->sp, true);
6072 break;
6073 case DBT_COMMANDS_MODE_BP:
6074 r_core_seek (core, frame->bp, true);
6075 break;
6076 default:
6077 r_warn_if_reached ();
6078 return R_CMD_STATUS_INVALID;
6079 }
6080 RCmdStatus cmd_res = handle_ts_command_tmpseek (state, command);
6081 r_cons_newline ();
6082 UPDATE_CMD_STATUS_RES (res, cmd_res, err);
6083 }
6084 err:
6085 r_core_seek (core, orig_offset, true);
6086 r_list_free (list);
6087 return res;
6088 }
6089
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_dbta_command)6090 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_dbta_command) {
6091 return iter_dbt_commands (state, node, DBT_COMMANDS_MODE_ADDR);
6092 }
6093
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_dbtb_command)6094 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_dbtb_command) {
6095 return iter_dbt_commands (state, node, DBT_COMMANDS_MODE_BP);
6096 }
6097
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_dbts_command)6098 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_dbts_command) {
6099 return iter_dbt_commands (state, node, DBT_COMMANDS_MODE_SP);
6100 }
6101
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_file_lines_command)6102 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_file_lines_command) {
6103 // TODO: old implementation has some unknown check on '('
6104 RCore *core = state->core;
6105 RCmdStatus res = R_CMD_STATUS_OK;
6106 TSNode command = ts_node_named_child (node, 0);
6107 TSNode arg = ts_node_named_child (node, 1);
6108 char *arg_str = ts_node_handle_arg(state, node, arg, 1);
6109 ut64 orig_offset = core->offset;
6110 FILE *fd = r_sandbox_fopen (arg_str, "r");
6111 if (!fd) {
6112 res = R_CMD_STATUS_INVALID;
6113 goto arg_out;
6114 }
6115
6116 core->rcmd->macro.counter = 0;
6117 while (!feof (fd)) {
6118 char buf[1024];
6119 buf[0] = '\0';
6120 if (!fgets (buf, sizeof (buf), fd)) {
6121 break;
6122 }
6123 ut64 addr = r_num_math (core->num, buf);
6124 r_core_seek (core, addr, true);
6125 RCmdStatus cmd_res = handle_ts_command_tmpseek (state, command);
6126 core->rcmd->macro.counter++;
6127 UPDATE_CMD_STATUS_RES (res, cmd_res, err);
6128 }
6129 err:
6130 r_core_seek (core, orig_offset, true);
6131 fclose (fd);
6132
6133 arg_out:
6134 free (arg_str);
6135 return res;
6136 }
6137
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_offsets_command)6138 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_offsets_command) {
6139 RCore *core = state->core;
6140 RCmdStatus res = R_CMD_STATUS_OK;
6141 TSNode command = ts_node_named_child (node, 0);
6142 if (ts_node_named_child_count (node) < 2) {
6143 // no offsets provided, all's good.
6144 return R_CMD_STATUS_OK;
6145 }
6146
6147 TSNode args = ts_node_named_child (node, 1);
6148 ut64 orig_offset = core->offset;
6149
6150 RCmdParsedArgs *a = ts_node_handle_arg_prargs (state, node, args, 1, true);
6151 if (!a) {
6152 R_LOG_ERROR ("Cannot parse args\n");
6153 return R_CMD_STATUS_INVALID;
6154 }
6155
6156 const char *s;
6157 int i;
6158 r_cmd_parsed_args_foreach_arg (a, i, s) {
6159 ut64 addr = r_num_math (core->num, s);
6160 R_LOG_DEBUG ("iter_offsets_command: seek to %" PFMT64x "\n", addr);
6161 r_core_seek (core, addr, true);
6162 RCmdStatus cmd_res = handle_ts_command_tmpseek (state, command);
6163 r_cons_flush ();
6164 UPDATE_CMD_STATUS_RES (res, cmd_res, err);
6165 }
6166
6167 err:
6168 r_core_seek (core, orig_offset, true);
6169 r_cmd_parsed_args_free (a);
6170 return res;
6171 }
6172
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_sdbquery_command)6173 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_sdbquery_command) {
6174 RCore *core = state->core;
6175 TSNode command = ts_node_named_child (node, 0);
6176 TSNode arg = ts_node_named_child (node, 1);
6177 char *arg_str = ts_node_handle_arg (state, node, arg, 1);
6178 ut64 orig_offset = core->offset;
6179
6180 char *out = sdb_querys (core->sdb, NULL, 0, arg_str);
6181 if (!out) {
6182 return R_CMD_STATUS_INVALID;
6183 }
6184 char *str, *each = out;
6185 ut64 addr;
6186 RCmdStatus res = R_CMD_STATUS_OK;
6187 do {
6188 while (*each == ' ') {
6189 each++;
6190 }
6191 if (!*each) {
6192 break;
6193 }
6194 str = strchr (each, ' ');
6195 if (str) {
6196 *str = '\0';
6197 addr = r_num_math (core->num, each);
6198 *str = ' ';
6199 } else {
6200 addr = r_num_math (core->num, each);
6201 }
6202 each = str + 1;
6203 r_core_seek (core, addr, true);
6204 RCmdStatus cmd_res = handle_ts_command_tmpseek (state, command);
6205 r_cons_flush ();
6206 UPDATE_CMD_STATUS_RES (res, cmd_res, err);
6207 } while (str != NULL);
6208 err:
6209 r_core_seek (core, orig_offset, true);
6210 free (out);
6211 free (arg_str);
6212 return res;
6213 }
6214
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_threads_command)6215 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_threads_command) {
6216 RCore *core = state->core;
6217 TSNode command = ts_node_named_child (node, 0);
6218 int pid = core->dbg->pid;
6219 if (!core->dbg->h || !core->dbg->h->pids) {
6220 return R_CMD_STATUS_INVALID;
6221 }
6222
6223 RCmdStatus res = R_CMD_STATUS_OK;
6224 RList *list = core->dbg->h->pids (core->dbg, R_MAX (0, pid));
6225 RListIter *iter;
6226 RDebugPid *p;
6227 r_list_foreach (list, iter, p) {
6228 r_cons_printf ("# PID %d\n", p->pid);
6229 r_debug_select (core->dbg, p->pid, p->pid);
6230 RCmdStatus cmd_res = handle_ts_command (state, command);
6231 UPDATE_CMD_STATUS_RES (res, cmd_res, err);
6232 r_cons_newline ();
6233 }
6234 err:
6235 r_list_free (list);
6236 r_debug_select (core->dbg, pid, pid);
6237 return res;
6238 }
6239
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_bbs_command)6240 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_bbs_command) {
6241 RCore *core = state->core;
6242 TSNode command = ts_node_named_child (node, 0);
6243 RListIter *iter;
6244 RAnalBlock *bb;
6245 int bs = core->blocksize;
6246 ut64 orig_offset = core->offset;
6247 RCmdStatus res = R_CMD_STATUS_OK;
6248 RAnalFunction *fcn = r_anal_get_function_at (core->anal, core->offset);
6249 if (!fcn) {
6250 eprintf ("No function at current address\n");
6251 return R_CMD_STATUS_INVALID;
6252 }
6253 r_list_sort (fcn->bbs, bb_cmp);
6254 r_list_foreach (fcn->bbs, iter, bb) {
6255 r_core_block_size (core, bb->size);
6256 r_core_seek (core, bb->addr, true);
6257 RCmdStatus cmd_res = handle_ts_command_tmpseek (state, command);
6258 UPDATE_CMD_STATUS_RES (res, cmd_res, err);
6259 if (r_cons_is_breaked ()) {
6260 break;
6261 }
6262 }
6263 err:
6264 r_core_block_size (core, bs);
6265 r_core_seek (core, orig_offset, true);
6266 return res;
6267 }
6268
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_instrs_command)6269 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_instrs_command) {
6270 TSNode command = ts_node_named_child (node, 0);
6271 RCore *core = state->core;
6272 RListIter *iter;
6273 RAnalBlock *bb;
6274 int i;
6275 RCmdStatus res = R_CMD_STATUS_OK;
6276 ut64 orig_offset = core->offset;
6277 int bs = core->blocksize;
6278 RAnalFunction *fcn = r_anal_get_function_at (core->anal, core->offset);
6279 if (!fcn) {
6280 eprintf ("No function at current address\n");
6281 return R_CMD_STATUS_INVALID;
6282 }
6283 r_list_sort (fcn->bbs, bb_cmp);
6284 r_list_foreach (fcn->bbs, iter, bb) {
6285 for (i = 0; i < bb->ninstr; i++) {
6286 ut64 addr = bb->addr + r_anal_bb_offset_inst (bb, i);
6287 int sz = r_anal_bb_size_i (bb, i);
6288 r_core_block_size (core, sz);
6289 r_core_seek (core, addr, true);
6290 RCmdStatus cmd_res = handle_ts_command_tmpseek (state, command);
6291 UPDATE_CMD_STATUS_RES (res, cmd_res, err);
6292 if (r_cons_is_breaked ()) {
6293 break;
6294 }
6295 }
6296 }
6297
6298 err:
6299 r_core_block_size (core, bs);
6300 r_core_seek (core, orig_offset, true);
6301 return res;
6302 }
6303
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_functions_command)6304 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_functions_command) {
6305 TSNode command = ts_node_named_child (node, 0);
6306 TSNode arg = ts_node_named_child (node, 1);
6307 char *arg_str = NULL;
6308 RCore *core = state->core;
6309 RCmdStatus res = R_CMD_STATUS_OK;
6310 ut64 orig_offset = core->offset;
6311 int bs = core->blocksize;
6312 RAnalFunction *fcn;
6313 RListIter *iter;
6314
6315 if (!ts_node_is_null (arg)) {
6316 arg_str = ts_node_handle_arg (state, node, arg, 1);
6317 }
6318
6319 r_list_foreach (core->anal->fcns, iter, fcn) {
6320 if (arg_str && !strstr (fcn->name, arg_str)) {
6321 continue;
6322 }
6323 char *buf;
6324 r_core_block_size (core, r_anal_function_linear_size (fcn));
6325 r_core_seek (core, fcn->addr, true);
6326 r_cons_push ();
6327 RCmdStatus cmd_res = handle_ts_command_tmpseek (state, command);
6328 buf = (char *)r_cons_get_buffer ();
6329 if (buf) {
6330 buf = strdup (buf);
6331 }
6332 r_cons_pop ();
6333 r_cons_strcat (buf);
6334 free (buf);
6335 UPDATE_CMD_STATUS_RES (res, cmd_res, err);
6336 if (r_cons_is_breaked ()) {
6337 break;
6338 }
6339 }
6340
6341 err:
6342 r_core_block_size (core, bs);
6343 r_core_seek (core, orig_offset, true);
6344 free (arg_str);
6345 return res;
6346 }
6347
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_step_command)6348 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_step_command) {
6349 TSNode command = ts_node_named_child (node, 0);
6350 TSNode from_n = ts_node_named_child (node, 1);
6351 TSNode to_n = ts_node_named_child (node, 2);
6352 TSNode step_n = ts_node_named_child (node, 3);
6353 RCore *core = state->core;
6354 RCmdStatus res = R_CMD_STATUS_OK;
6355 ut64 orig_offset = core->offset;
6356 int bs = core->blocksize;
6357
6358 char *from_str = ts_node_handle_arg (state, node, from_n, 1);
6359 char *to_str = ts_node_handle_arg (state, node, to_n, 2);
6360 char *step_str = ts_node_handle_arg (state, node, step_n, 3);
6361 ut64 from = r_num_math (core->num, from_str);
6362 ut64 to = r_num_math (core->num, to_str);
6363 ut64 step = r_num_math (core->num, step_str);
6364 free (from_str);
6365 free (to_str);
6366 free (step_str);
6367
6368 ut64 cur;
6369 for (cur = from; cur <= to; cur += step) {
6370 r_core_seek (core, cur, true);
6371 r_core_block_size (core, step);
6372 RCmdStatus cmd_res = handle_ts_command_tmpseek (state, command);
6373 UPDATE_CMD_STATUS_RES (res, cmd_res, err);
6374 if (r_cons_is_breaked ()) {
6375 break;
6376 }
6377 }
6378
6379 err:
6380 r_core_block_size (core, bs);
6381 r_core_seek (core, orig_offset, true);
6382 return res;
6383 }
6384
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_interpret_command)6385 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_interpret_command) {
6386 RCore *core = state->core;
6387 TSNode command = ts_node_named_child (node, 0);
6388 TSNode in_cmd = ts_node_named_child (node, 1);
6389 substitute_args_init (state, node);
6390
6391 RList *edits = r_list_newf ((RListFree)free_tsr2cmd_edit);
6392
6393 char *in_cmd_out = do_handle_substitution_cmd (state, in_cmd);
6394 in_cmd_out = escape_special_chars (in_cmd_out, SPECIAL_CHARS_REGULAR);
6395 struct tsr2cmd_edit *e = create_cmd_edit (state, in_cmd, in_cmd_out);
6396 r_list_append (edits, e);
6397
6398 TSNode op = ts_node_child (node, 1);
6399 e = create_cmd_edit (state, op, strdup ("@@="));
6400 r_list_append (edits, e);
6401
6402 TSNode new_command;
6403 bool ok = substitute_args_do (state, edits, &new_command);
6404 if (!ok) {
6405 r_list_free (edits);
6406 substitute_args_fini (state);
6407 return R_CMD_STATUS_INVALID;
6408 }
6409 TSNode args = ts_node_named_child (new_command, 1);
6410
6411 RCmdParsedArgs *a = parse_args (state, args, true);
6412 if (!a) {
6413 r_list_free (edits);
6414 substitute_args_fini (state);
6415 return R_CMD_STATUS_INVALID;
6416 }
6417
6418 r_list_free (edits);
6419 substitute_args_fini (state);
6420
6421 const char *s;
6422 int i;
6423 ut64 orig_offset = core->offset;
6424 RCmdStatus res = R_CMD_STATUS_OK;
6425 r_cmd_parsed_args_foreach_arg (a, i, s) {
6426 ut64 addr = r_num_math (core->num, s);
6427 R_LOG_DEBUG ("iter_interpret_command: seek to %" PFMT64x "\n", addr);
6428 r_core_seek (core, addr, true);
6429 RCmdStatus cmd_res = handle_ts_command_tmpseek (state, command);
6430 r_cons_flush ();
6431 UPDATE_CMD_STATUS_RES (res, cmd_res, err);
6432 }
6433 err:
6434 r_core_seek (core, orig_offset, true);
6435 r_cmd_parsed_args_free (a);
6436 return res;
6437 }
6438
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_hit_command)6439 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(iter_hit_command) {
6440 RCore *core = state->core;
6441 TSNode command = ts_node_named_child (node, 0);
6442 TSNode search_cmd = ts_node_named_child (node, 1);
6443 char *command_str = ts_node_sub_string (command, state->input);
6444 char *cmdhit = strdup (r_config_get (core->config, "cmd.hit"));
6445 r_config_set (core->config, "cmd.hit", command_str);
6446 RCmdStatus res = handle_ts_command (state, search_cmd);
6447 r_config_set (core->config, "cmd.hit", cmdhit);
6448 free (command_str);
6449 return res;
6450 }
6451
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_addrsize_command)6452 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_addrsize_command) {
6453 RCore *core = state->core;
6454 TSNode command = ts_node_named_child (node, 0);
6455 uint32_t i = 1;
6456 RCmdStatus ret = R_CMD_STATUS_OK;
6457 TSNode seek_addr_node = ts_node_named_child (node, i);
6458 TSNode blk_sz_node = ts_node_named_child (node, i + 1);
6459 ut64 orig_offset = core->offset;
6460 ut64 orig_blksz = core->blocksize;
6461 while (!ts_node_is_null (seek_addr_node)) {
6462 char *seek_addr_str = ts_node_handle_arg (state, node, seek_addr_node, i);
6463 char *blk_sz_str = ts_node_handle_arg (state, node, blk_sz_node, i + 1);
6464 ut64 seek_addr_val = r_num_get (core->num, seek_addr_str);
6465 ut64 blk_sz_val = r_num_get (core->num, blk_sz_str);
6466 free (seek_addr_str);
6467 free (blk_sz_str);
6468 r_core_seek (core, seek_addr_val, true);
6469 r_core_block_size (core, blk_sz_val);
6470 RCmdStatus cmd_res = handle_ts_command_tmpseek (state, command);
6471 UPDATE_CMD_STATUS_RES (ret, cmd_res, err);
6472 i += 2;
6473 seek_addr_node = ts_node_named_child (node, i);
6474 blk_sz_node = ts_node_named_child (node, i + 1);
6475 }
6476 err:
6477 r_core_block_size (core, orig_blksz);
6478 r_core_seek (core, orig_offset, true);
6479 return ret;
6480 }
6481
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_bb_command)6482 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_bb_command) {
6483 RCore *core = state->core;
6484 TSNode command = ts_node_named_child (node, 0);
6485 RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset, 0);
6486 ut64 offorig = core->offset;
6487 ut64 obs = core->blocksize;
6488 if (!fcn) {
6489 return R_CMD_STATUS_INVALID;
6490 }
6491
6492 RListIter *iter;
6493 RAnalBlock *bb;
6494 RCmdStatus ret = R_CMD_STATUS_OK;
6495 r_list_foreach (fcn->bbs, iter, bb) {
6496 r_core_seek (core, bb->addr, true);
6497 r_core_block_size (core, bb->size);
6498 RCmdStatus cmd_res = handle_ts_command_tmpseek (state, command);
6499 UPDATE_CMD_STATUS_RES (ret, cmd_res, err);
6500 }
6501 err:
6502 r_core_block_size (core, obs);
6503 r_core_seek (core, offorig, true);
6504 return ret;
6505 }
6506
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_cmd_command)6507 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_cmd_command) {
6508 // convert @@@c: command into a @@@= one, by using the output of the
6509 // in_cmd as addr/blksz of @@@=
6510 TSNode in_cmd = ts_node_named_child (node, 1);
6511 substitute_args_init (state, node);
6512
6513 RList *edits = r_list_newf ((RListFree)free_tsr2cmd_edit);
6514 if (!edits) {
6515 substitute_args_fini (state);
6516 return R_CMD_STATUS_INVALID;
6517 }
6518
6519 char *in_cmd_out = do_handle_substitution_cmd (state, in_cmd);
6520 in_cmd_out = escape_special_chars (in_cmd_out, SPECIAL_CHARS_REGULAR);
6521 struct tsr2cmd_edit *e = create_cmd_edit (state, in_cmd, in_cmd_out);
6522 r_list_append (edits, e);
6523
6524 TSNode op = ts_node_child (node, 1);
6525 e = create_cmd_edit (state, op, strdup ("@@@="));
6526 r_list_append (edits, e);
6527
6528 TSNode new_command;
6529 if (!substitute_args_do (state, edits, &new_command)) {
6530 r_list_free (edits);
6531 substitute_args_fini (state);
6532 return R_CMD_STATUS_INVALID;
6533 }
6534 RCmdStatus res = handle_ts_command (state, new_command);
6535 r_list_free (edits);
6536 substitute_args_fini (state);
6537 return res;
6538 }
6539
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_comment_command)6540 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_comment_command) {
6541 RCore *core = state->core;
6542 TSNode command = ts_node_named_child (node, 0);
6543 TSNode filter_node = ts_node_named_child (node, 1);
6544 char *glob = !ts_node_is_null (filter_node)
6545 ? ts_node_sub_string (filter_node, state->input)
6546 : NULL;
6547 ut64 off = core->offset;
6548 RCmdStatus res = R_CMD_STATUS_OK;
6549 RIntervalTreeIter it;
6550 RAnalMetaItem *meta;
6551 r_interval_tree_foreach (&core->anal->meta, it, meta) {
6552 if (meta->type != R_META_TYPE_COMMENT) {
6553 continue;
6554 }
6555 if (!glob || (meta->str && r_str_glob (meta->str, glob))) {
6556 r_core_seek (core, r_interval_tree_iter_get (&it)->start, true);
6557 RCmdStatus cmd_res = handle_ts_command_tmpseek (state, command);
6558 UPDATE_CMD_STATUS_RES (res, cmd_res, err);
6559 }
6560 }
6561 err:
6562 r_core_seek (core, off, false);
6563 free (glob);
6564 return res;
6565 }
6566
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_import_command)6567 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_import_command) {
6568 RCore *core = state->core;
6569 TSNode command = ts_node_named_child (node, 0);
6570 RBinImport *imp;
6571 ut64 offorig = core->offset;
6572 RList *list = r_bin_get_imports (core->bin);
6573 if (!list) {
6574 return R_CMD_STATUS_OK;
6575 }
6576
6577 RList *lost = r_list_newf (free);
6578 RListIter *iter;
6579 r_list_foreach (list, iter, imp) {
6580 char *impflag = r_str_newf ("sym.imp.%s", imp->name);
6581 ut64 addr = r_num_math (core->num, impflag);
6582 ut64 *n = R_NEW (ut64);
6583 *n = addr;
6584 r_list_append (lost, n);
6585 free (impflag);
6586 }
6587 ut64 *naddr;
6588 RCmdStatus res = R_CMD_STATUS_OK;
6589 r_list_foreach (lost, iter, naddr) {
6590 ut64 addr = *naddr;
6591 if (addr && addr != UT64_MAX) {
6592 r_core_seek (core, addr, true);
6593 RCmdStatus cmd_res = handle_ts_command_tmpseek (state, command);
6594 UPDATE_CMD_STATUS_RES (res, cmd_res, err);
6595 }
6596 }
6597 err:
6598 r_core_seek (core, offorig, true);
6599 r_list_free (lost);
6600 return res;
6601 }
6602
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_register_command)6603 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_register_command) {
6604 RCore *core = state->core;
6605 TSNode command = ts_node_named_child (node, 0);
6606 ut64 offorig = core->offset;
6607 int i;
6608 RCmdStatus res = R_CMD_STATUS_OK;
6609 for (i = 0; i < R_REG_TYPE_LAST; i++) {
6610 RRegItem *item;
6611 ut64 value;
6612 RList *head = r_reg_get_list (core->dbg->reg, i);
6613 if (!head) {
6614 continue;
6615 }
6616 RList *list = r_list_newf (free);
6617 RListIter *iter;
6618 r_list_foreach (head, iter, item) {
6619 if (item->size != core->anal->bits) {
6620 continue;
6621 }
6622 if (item->type != i) {
6623 continue;
6624 }
6625 r_list_append (list, strdup (item->name));
6626 }
6627 const char *item_name;
6628 r_list_foreach (list, iter, item_name) {
6629 value = r_reg_getv (core->dbg->reg, item_name);
6630 r_core_seek (core, value, true);
6631 r_cons_printf ("%s: ", item_name);
6632 RCmdStatus cmd_res = handle_ts_command_tmpseek (state, command);
6633 UPDATE_CMD_STATUS_RES (res, cmd_res, err);
6634 }
6635 err:
6636 r_list_free (list);
6637 }
6638 r_core_seek (core, offorig, true);
6639 return res;
6640 }
6641
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_symbol_command)6642 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_symbol_command) {
6643 RCore *core = state->core;
6644 TSNode command = ts_node_named_child (node, 0);
6645 RBinSymbol *sym;
6646 ut64 offorig = core->offset;
6647 ut64 obs = core->blocksize;
6648 RList *list = r_bin_get_symbols (core->bin);
6649 RListIter *iter;
6650 r_cons_break_push (NULL, NULL);
6651 RList *lost = r_list_newf (free);
6652 r_list_foreach (list, iter, sym) {
6653 RBinSymbol *bs = r_mem_dup (sym, sizeof (RBinSymbol));
6654 r_list_append (lost, bs);
6655 }
6656 RCmdStatus res = R_CMD_STATUS_OK;
6657 r_list_foreach (lost, iter, sym) {
6658 if (r_cons_is_breaked ()) {
6659 break;
6660 }
6661 r_core_block_size (core, sym->size);
6662 r_core_seek (core, sym->vaddr, true);
6663 RCmdStatus cmd_res = handle_ts_command_tmpseek (state, command);
6664 UPDATE_CMD_STATUS_RES (res, cmd_res, err);
6665 }
6666 err:
6667 r_cons_break_pop ();
6668 r_list_free (lost);
6669 r_core_block_size (core, obs);
6670 r_core_seek (core, offorig, true);
6671 return res;
6672 }
6673
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_string_command)6674 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_string_command) {
6675 RCore *core = state->core;
6676 TSNode command = ts_node_named_child (node, 0);
6677 RList *list = r_bin_get_strings (core->bin);
6678 RCmdStatus res = R_CMD_STATUS_OK;
6679 if (list) {
6680 ut64 offorig = core->offset;
6681 ut64 obs = core->blocksize;
6682 RBinString *s;
6683 RList *lost = r_list_newf (free);
6684 RListIter *iter;
6685 r_list_foreach (list, iter, s) {
6686 RBinString *bs = r_mem_dup (s, sizeof (RBinString));
6687 r_list_append (lost, bs);
6688 }
6689 r_list_foreach (lost, iter, s) {
6690 r_core_block_size (core, s->size);
6691 r_core_seek (core, s->vaddr, true);
6692 RCmdStatus cmd_res = handle_ts_command_tmpseek (state, command);
6693 UPDATE_CMD_STATUS_RES (res, cmd_res, err);
6694 }
6695 err:
6696 r_core_block_size (core, obs);
6697 r_core_seek (core, offorig, true);
6698 r_list_free (lost);
6699 }
6700 return res;
6701 }
6702
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_section_command)6703 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_section_command) {
6704 RCore *core = state->core;
6705 TSNode command = ts_node_named_child (node, 0);
6706 RBinObject *obj = r_bin_cur_object (core->bin);
6707 if (!obj) {
6708 return false;
6709 }
6710 RCmdStatus res = R_CMD_STATUS_OK;
6711 ut64 offorig = core->offset;
6712 ut64 bszorig = core->blocksize;
6713 RBinSection *sec;
6714 RListIter *iter;
6715 r_list_foreach (obj->sections, iter, sec) {
6716 r_core_seek (core, sec->vaddr, true);
6717 r_core_block_size (core, sec->vsize);
6718 RCmdStatus cmd_res = handle_ts_command_tmpseek (state, command);
6719 UPDATE_CMD_STATUS_RES (res, cmd_res, err);
6720 }
6721 err:
6722 r_core_block_size (core, bszorig);
6723 r_core_seek (core, offorig, true);
6724 return res;
6725 }
6726
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_iomap_command)6727 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_iomap_command) {
6728 RCore *core = state->core;
6729 TSNode command = ts_node_named_child (node, 0);
6730 int fd = r_io_fd_get_current (core->io);
6731 // only iterate maps of current fd
6732 RList *maps = r_io_map_get_for_fd (core->io, fd);
6733 RIOMap *map;
6734 RCmdStatus res = R_CMD_STATUS_OK;
6735 if (maps) {
6736 RListIter *iter;
6737 r_list_foreach (maps, iter, map) {
6738 r_core_seek (core, r_io_map_begin (map), true);
6739 r_core_block_size (core, r_io_map_size (map));
6740 RCmdStatus cmd_res = handle_ts_command_tmpseek (state, command);
6741 UPDATE_CMD_STATUS_RES (res, cmd_res, err);
6742 }
6743 err:
6744 r_list_free (maps);
6745 }
6746 return res;
6747 }
6748
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_dbgmap_command)6749 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_dbgmap_command) {
6750 RCore *core = state->core;
6751 TSNode command = ts_node_named_child (node, 0);
6752 RDebug *dbg = core->dbg;
6753 RCmdStatus res = R_CMD_STATUS_OK;
6754 if (dbg && dbg->h && dbg->maps) {
6755 RDebugMap *map;
6756 RListIter *iter;
6757 r_list_foreach (dbg->maps, iter, map) {
6758 r_core_seek (core, map->addr, true);
6759 RCmdStatus cmd_res = handle_ts_command_tmpseek (state, command);
6760 UPDATE_CMD_STATUS_RES (res, cmd_res, err);
6761 }
6762 }
6763 err:
6764 return res;
6765 }
6766
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_flag_command)6767 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_flag_command) {
6768 RCore *core = state->core;
6769 TSNode command = ts_node_named_child (node, 0);
6770 TSNode filter_node = ts_node_named_child (node, 1);
6771 char *glob = NULL;
6772 if (!ts_node_is_null (filter_node)) {
6773 glob = ts_node_sub_string (filter_node, state->input);
6774 }
6775 ut64 off = core->offset;
6776 ut64 obs = core->blocksize;
6777 RList *flags = r_list_newf (free);
6778 r_flag_foreach_glob (core->flags, glob, copy_into_flagitem_list, flags);
6779 RListIter *iter;
6780 RFlagItem *f;
6781 RCmdStatus res = R_CMD_STATUS_OK;
6782 r_list_foreach (flags, iter, f) {
6783 r_core_block_size (core, f->size);
6784 r_core_seek (core, f->offset, true);
6785 RCmdStatus cmd_res = handle_ts_command_tmpseek (state, command);
6786 UPDATE_CMD_STATUS_RES (res, cmd_res, err);
6787 }
6788 err:
6789 r_core_seek (core, off, false);
6790 r_core_block_size (core, obs);
6791 free (glob);
6792 return res;
6793 }
6794
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_function_command)6795 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_function_command) {
6796 RCore *core = state->core;
6797 TSNode command = ts_node_named_child (node, 0);
6798 TSNode filter_node = ts_node_named_child (node, 1);
6799 char *filter = NULL;
6800 if (!ts_node_is_null (filter_node)) {
6801 filter = ts_node_sub_string (filter_node, state->input);
6802 }
6803 ut64 obs = core->blocksize;
6804 ut64 offorig = core->offset;
6805 RAnalFunction *fcn;
6806 RList *list = core->anal->fcns;
6807 RListIter *iter;
6808 RCmdStatus res = R_CMD_STATUS_OK;
6809 r_cons_break_push (NULL, NULL);
6810 r_list_foreach (list, iter, fcn) {
6811 if (r_cons_is_breaked ()) {
6812 break;
6813 }
6814 if (!filter || r_str_glob (fcn->name, filter)) {
6815 r_core_seek (core, fcn->addr, true);
6816 r_core_block_size (core, r_anal_function_linear_size (fcn));
6817 RCmdStatus cmd_res = handle_ts_command_tmpseek (state, command);
6818 UPDATE_CMD_STATUS_RES (res, cmd_res, err);
6819 }
6820 }
6821 err:
6822 r_cons_break_pop ();
6823 r_core_block_size (core, obs);
6824 r_core_seek (core, offorig, true);
6825 return res;
6826 }
6827
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_thread_command)6828 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(foreach_thread_command) {
6829 RCore *core = state->core;
6830 TSNode command = ts_node_named_child (node, 0);
6831 RDebug *dbg = core->dbg;
6832 RCmdStatus res = R_CMD_STATUS_OK;
6833 if (dbg && dbg->h && dbg->h->threads) {
6834 int origtid = dbg->tid;
6835 RDebugPid *p;
6836 RList *list = dbg->h->threads (dbg, dbg->pid);
6837 if (!list) {
6838 return R_CMD_STATUS_INVALID;
6839 }
6840 RListIter *iter;
6841 r_list_foreach (list, iter, p) {
6842 r_debug_select (dbg, dbg->pid, p->pid);
6843 r_cons_printf ("PID %d\n", p->pid);
6844 RCmdStatus cmd_res = handle_ts_command (state, command);
6845 UPDATE_CMD_STATUS_RES (res, cmd_res, err);
6846 }
6847 err:
6848 r_debug_select (dbg, dbg->pid, origtid);
6849 r_list_free (list);
6850 }
6851 return res;
6852 }
6853
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(last_command)6854 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(last_command) {
6855 TSNode command = ts_node_child_by_field_name (node, "command", strlen ("command"));
6856 char *command_str = ts_node_sub_string (command, state->input);
6857 RCmdStatus res = R_CMD_STATUS_INVALID;
6858 state->is_last_cmd = true;
6859 if (!strcmp (command_str, ".")) {
6860 res = lastcmd_repeat (state->core, 0);
6861 } else if (!strcmp (command_str, "...")) {
6862 res = lastcmd_repeat (state->core, 1);
6863 } else {
6864 r_warn_if_reached ();
6865 }
6866 free (command_str);
6867 return res;
6868 }
6869
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(grep_command)6870 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(grep_command) {
6871 TSNode command = ts_node_child_by_field_name (node, "command", strlen ("command"));
6872 TSNode arg = ts_node_child_by_field_name (node, "specifier", strlen ("specifier"));
6873 char *arg_str = ts_node_handle_arg (state, node, arg, 1);
6874 RCmdStatus res = handle_ts_command (state, command);
6875 R_LOG_DEBUG ("grep_command specifier: '%s'\n", arg_str);
6876 RStrBuf *sb = r_strbuf_new (arg_str);
6877 r_strbuf_prepend (sb, "~");
6878 char *specifier_str = r_cons_grep_strip (r_strbuf_get (sb), "`");
6879 r_strbuf_free (sb);
6880 specifier_str = unescape_special_chars (specifier_str, SPECIAL_CHARS_REGULAR);
6881 R_LOG_DEBUG ("grep_command processed specifier: '%s'\n", specifier_str);
6882 r_cons_grep_process (specifier_str);
6883 free (arg_str);
6884 return res;
6885 }
6886
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(html_disable_command)6887 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(html_disable_command) {
6888 TSNode command = ts_node_child_by_field_name (node, "command", strlen ("command"));
6889 int scr_html = r_config_get_i (state->core->config, "scr.html");
6890 r_config_set_i (state->core->config, "scr.html", 0);
6891 int scr_color = r_config_get_i (state->core->config, "scr.color");
6892 r_config_set_i (state->core->config, "scr.color", COLOR_MODE_DISABLED);
6893 RCmdStatus res = handle_ts_command (state, command);
6894 if (scr_html != -1) {
6895 r_cons_flush ();
6896 r_config_set_i (state->core->config, "scr.html", scr_html);
6897 }
6898 if (scr_color != -1) {
6899 r_config_set_i (state->core->config, "scr.color", scr_color);
6900 }
6901 return res;
6902 }
6903
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(html_enable_command)6904 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(html_enable_command) {
6905 TSNode command = ts_node_child_by_field_name (node, "command", strlen ("command"));
6906 int scr_html = r_config_get_i (state->core->config, "scr.html");
6907 r_config_set_i (state->core->config, "scr.html", true);
6908 RCmdStatus res = handle_ts_command (state, command);
6909 if (scr_html != -1) {
6910 r_cons_flush ();
6911 r_config_set_i (state->core->config, "scr.html", scr_html);
6912 }
6913 return res;
6914 }
6915
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(pipe_command)6916 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(pipe_command) {
6917 TSNode first_cmd = ts_node_named_child (node, 0);
6918 r_return_val_if_fail (!ts_node_is_null (first_cmd), false);
6919 TSNode second_cmd = ts_node_named_child (node, 1);
6920 r_return_val_if_fail (!ts_node_is_null (second_cmd), false);
6921 char *first_str = ts_node_sub_string (first_cmd, state->input);
6922 char *second_str = ts_node_sub_string (second_cmd, state->input);
6923 int value = state->core->num->value;
6924 RCmdStatus res = r_cmd_int2status (r_core_cmd_pipe (state->core, first_str, second_str));
6925 state->core->num->value = value;
6926 free (first_str);
6927 free (second_str);
6928 return res;
6929 }
6930
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(scr_tts_command)6931 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(scr_tts_command) {
6932 TSNode command = ts_node_child_by_field_name (node, "command", strlen ("command"));
6933 int scr_color = r_config_get_i (state->core->config, "scr.color");
6934 r_config_set_i (state->core->config, "scr.color", COLOR_MODE_DISABLED);
6935 state->core->cons->use_tts = true;
6936 RCmdStatus res = handle_ts_command (state, command);
6937 if (scr_color != -1) {
6938 r_config_set_i (state->core->config, "scr.color", scr_color);
6939 }
6940 return res;
6941 }
6942
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(task_command)6943 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(task_command) {
6944 // TODO: this should be handled differently, if the argument is a command.
6945 // For now we just treat everything as an arged_command
6946 return handle_ts_arged_command (state, node);
6947 }
6948
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(number_command)6949 DEFINE_HANDLE_TS_FCN_AND_SYMBOL(number_command) {
6950 ut64 addr = r_num_math (state->core->num, node_string);
6951 r_core_seek (state->core, addr, true);
6952 return R_CMD_STATUS_OK;
6953 }
6954
handle_ts_command(struct tsr2cmd_state * state,TSNode node)6955 static RCmdStatus handle_ts_command(struct tsr2cmd_state *state, TSNode node) {
6956 RCmdStatus ret = R_CMD_STATUS_INVALID;
6957 RCmd *cmd = state->core->rcmd;
6958
6959 TSSymbol node_symbol = ts_node_symbol (node);
6960 ts_handler handler = ht_up_find (cmd->ts_symbols_ht, node_symbol, NULL);
6961
6962 state->is_last_cmd = false;
6963 if (handler) {
6964 ret = handler (state, node);
6965 } else {
6966 R_LOG_WARN ("No handler for this kind of command `%s`\n", ts_node_type (node));
6967 }
6968 if (state->log && !state->is_last_cmd) {
6969 free (state->core->lastcmd);
6970 state->core->lastcmd = ts_node_sub_string (node, state->input);
6971 }
6972 return ret;
6973 }
6974
handle_ts_command_tmpseek(struct tsr2cmd_state * state,TSNode node)6975 static RCmdStatus handle_ts_command_tmpseek(struct tsr2cmd_state *state, TSNode node) {
6976 RCore *core = state->core;
6977 bool saved_tmpseek = core->tmpseek;
6978 core->tmpseek = true;
6979 RCmdStatus ret = handle_ts_command (state, node);
6980 core->tmpseek = saved_tmpseek;
6981 return ret;
6982 }
6983
DEFINE_HANDLE_TS_FCN(commands)6984 DEFINE_HANDLE_TS_FCN(commands) {
6985 RCore *core = state->core;
6986 RCmdStatus res = R_CMD_STATUS_OK;
6987 ut32 child_count = ts_node_named_child_count (node);
6988 int i;
6989
6990 R_LOG_DEBUG ("commands with %d childs\n", child_count);
6991 if (child_count == 0 && !*state->input) {
6992 if (core->cons->context->breaked) {
6993 core->cons->context->breaked = false;
6994 return R_CMD_STATUS_INVALID;
6995 }
6996 if (!core->cmdrepeat) {
6997 return R_CMD_STATUS_OK;
6998 }
6999 return lastcmd_repeat (core, true)? R_CMD_STATUS_OK: R_CMD_STATUS_INVALID;
7000 }
7001 if (state->split_lines) {
7002 r_cons_break_push (NULL, NULL);
7003 }
7004 for (i = 0; i < child_count; i++) {
7005 if (core->cons->context->cmd_depth < 1) {
7006 R_LOG_ERROR ("handle_ts_commands: That was too deep...\n");
7007 return R_CMD_STATUS_INVALID;
7008 }
7009 core->cons->context->cmd_depth--;
7010 if (core->max_cmd_depth - core->cons->context->cmd_depth == 1) {
7011 core->prompt_offset = core->offset;
7012 }
7013
7014 if (state->split_lines && r_cons_is_breaked ()) {
7015 r_cons_break_pop ();
7016 return res;
7017 }
7018 TSNode command = ts_node_named_child (node, i);
7019 RCmdStatus cmd_res = handle_ts_command (state, command);
7020 if (state->split_lines) {
7021 r_cons_flush ();
7022 r_core_task_yield (&core->tasks);
7023 }
7024 core->cons->context->cmd_depth++;
7025 if (cmd_res == R_CMD_STATUS_INVALID) {
7026 char *command_str = ts_node_sub_string (command, state->input);
7027 eprintf ("Error while executing command: %s\n", command_str);
7028 free (command_str);
7029 res = cmd_res;
7030 goto err;
7031 } else if (cmd_res != R_CMD_STATUS_OK) {
7032 res = cmd_res;
7033 goto err;
7034 }
7035 }
7036 err:
7037 if (state->split_lines) {
7038 r_cons_break_pop ();
7039 }
7040 return res;
7041 }
7042
7043 #define HANDLER_RULE_OP(name) { #name, handle_ts_##name },
7044 #define RULE_OP(name)
7045
7046 struct ts_data_symbol_map map_ts_command_handlers[] = {
7047 #include "r2-shell-parser-cmds.inc"
7048 { NULL, NULL },
7049 };
7050
7051 #define RULE_OP(name) { #name, &ts_##name##_symbol },
7052 #define HANDLER_RULE_OP(name) RULE_OP(name)
7053
7054 struct ts_data_symbol_map map_ts_symbols[] = {
7055 #include "r2-shell-parser-cmds.inc"
7056 { NULL, NULL },
7057 };
7058
ts_symbols_init(RCmd * cmd)7059 static void ts_symbols_init(RCmd *cmd) {
7060 if (cmd->language) {
7061 return;
7062 }
7063 TSLanguage *lang = tree_sitter_r2cmd ();
7064 cmd->language = lang;
7065 cmd->ts_symbols_ht = ht_up_new0 ();
7066 struct ts_data_symbol_map *entry = map_ts_command_handlers;
7067 while (entry->name) {
7068 TSSymbol symbol = ts_language_symbol_for_name (lang, entry->name, strlen (entry->name), true);
7069 ht_up_insert (cmd->ts_symbols_ht, symbol, entry->data);
7070 entry++;
7071 }
7072
7073 entry = map_ts_symbols;
7074 while (entry->name) {
7075 TSSymbol *sym_ptr = entry->data;
7076 *sym_ptr = ts_language_symbol_for_name (lang, entry->name, strlen (entry->name), true);
7077 entry++;
7078 }
7079 }
7080
core_cmd_tsr2cmd(RCore * core,const char * cstr,bool split_lines,bool log)7081 static RCmdStatus core_cmd_tsr2cmd(RCore *core, const char *cstr, bool split_lines, bool log) {
7082 char *input = strdup (r_str_trim_head_ro (cstr));
7083
7084 ts_symbols_init (core->rcmd);
7085
7086 TSParser *parser = ts_parser_new ();
7087 ts_parser_set_language (parser, (TSLanguage *)core->rcmd->language);
7088
7089 TSTree *tree = ts_parser_parse_string (parser, NULL, input, strlen (input));
7090 TSNode root = ts_tree_root_node (tree);
7091
7092 RCmdStatus res = R_CMD_STATUS_INVALID;
7093 struct tsr2cmd_state state;
7094 state.parser = parser;
7095 state.core = core;
7096 state.input = input;
7097 state.tree = tree;
7098 state.log = log;
7099 state.split_lines = split_lines;
7100
7101 if (state.log) {
7102 r_line_hist_add (state.input);
7103 }
7104
7105 char *ts_str = ts_node_string (root);
7106 R_LOG_DEBUG("s-expr %s\n", ts_str);
7107 free (ts_str);
7108
7109 if (is_ts_commands (root) && !ts_node_has_error (root)) {
7110 res = handle_ts_commands (&state, root);
7111 } else {
7112 // TODO: print a more meaningful error message and use the ERROR
7113 // tokens to indicate where, probably, the error is.
7114 eprintf ("Error while parsing command: `%s`\n", input);
7115 }
7116
7117 ts_tree_delete (tree);
7118 ts_parser_delete (parser);
7119 free (input);
7120 return res;
7121 }
7122
run_cmd_depth(RCore * core,char * cmd)7123 static int run_cmd_depth(RCore *core, char *cmd) {
7124 char *rcmd;
7125 int ret = false;
7126
7127 if (core->cons->context->cmd_depth < 1) {
7128 eprintf ("r_core_cmd: That was too deep (%s)...\n", cmd);
7129 return false;
7130 }
7131 core->cons->context->cmd_depth--;
7132 for (rcmd = cmd;;) {
7133 char *ptr = strchr (rcmd, '\n');
7134 if (ptr) {
7135 *ptr = '\0';
7136 }
7137 ret = r_core_cmd_subst (core, rcmd);
7138 if (ret == -1) {
7139 r_cons_eprintf ("|ERROR| Invalid command '%s' (0x%02x)\n", rcmd, *rcmd);
7140 break;
7141 }
7142 if (!ptr) {
7143 break;
7144 }
7145 rcmd = ptr + 1;
7146 }
7147 core->cons->context->cmd_depth++;
7148 return ret;
7149 }
7150
r_core_cmd(RCore * core,const char * cstr,bool log)7151 R_API int r_core_cmd(RCore *core, const char *cstr, bool log) {
7152 if (core->use_tree_sitter_r2cmd) {
7153 return r_cmd_status2int (core_cmd_tsr2cmd (core, cstr, false, log));
7154 }
7155
7156 int ret = false;
7157 size_t i;
7158 if (core->cmdfilter) {
7159 const char *invalid_chars = ";|>`@";
7160 for (i = 0; invalid_chars[i]; i++) {
7161 if (strchr (cstr, invalid_chars[i])) {
7162 ret = true;
7163 goto beach;
7164 }
7165 }
7166 if (strncmp (cstr, core->cmdfilter, strlen (core->cmdfilter))) {
7167 ret = true;
7168 goto beach;
7169 }
7170 }
7171 if (core->cmdremote) {
7172 if (*cstr == 'q') {
7173 R_FREE (core->cmdremote);
7174 goto beach; // false
7175 } else if (*cstr != '=' && strncmp (cstr, "!=", 2)) {
7176 if (core->cmdremote[0]) {
7177 char *s = r_str_newf ("%s %s", core->cmdremote, cstr);
7178 r_core_rtr_cmd (core, s);
7179 free (s);
7180 } else {
7181 char *res = r_io_system (core->io, cstr);
7182 if (res) {
7183 r_cons_printf ("%s\n", res);
7184 free (res);
7185 }
7186 }
7187 if (log) {
7188 r_line_hist_add (cstr);
7189 }
7190 goto beach; // false
7191 }
7192 }
7193
7194 if (!cstr || (*cstr == '|' && cstr[1] != '?')) {
7195 // raw comment syntax
7196 goto beach; // false;
7197 }
7198 if (!strncmp (cstr, "/*", 2)) {
7199 if (r_sandbox_enable (0)) {
7200 eprintf ("This command is disabled in sandbox mode\n");
7201 goto beach; // false
7202 }
7203 core->incomment = true;
7204 } else if (!strncmp (cstr, "*/", 2)) {
7205 core->incomment = false;
7206 goto beach; // false
7207 }
7208 if (core->incomment) {
7209 goto beach; // false
7210 }
7211 if (log && (*cstr && (*cstr != '.' || !strncmp (cstr, ".(", 2)))) {
7212 free (core->lastcmd);
7213 core->lastcmd = strdup (cstr);
7214 }
7215
7216 char *cmd = malloc (strlen (cstr) + 4096);
7217 if (!cmd) {
7218 goto beach;
7219 }
7220 r_str_cpy (cmd, cstr);
7221 if (log) {
7222 r_line_hist_add (cstr);
7223 }
7224
7225 ret = run_cmd_depth (core, cmd);
7226 free (cmd);
7227 beach:
7228 return ret;
7229 }
7230
r_core_cmd_lines(RCore * core,const char * lines)7231 R_API int r_core_cmd_lines(RCore *core, const char *lines) {
7232 if (core->use_tree_sitter_r2cmd) {
7233 RCmdStatus status = core_cmd_tsr2cmd (core, lines, true, false);
7234 return status == R_CMD_STATUS_OK;
7235 }
7236 int r, ret = true;
7237 char *nl, *data, *odata;
7238
7239 if (!lines || !*lines) {
7240 return true;
7241 }
7242 data = odata = strdup (lines);
7243 if (!odata) {
7244 return false;
7245 }
7246 size_t line_count = r_str_char_count(lines, '\n');
7247
7248 #if __UNIX__
7249 const bool istty = r_cons_isatty ();
7250 #else
7251 const bool istty = true;
7252 #endif
7253 const bool show_progress_bar = core->print->enable_progressbar && r_config_get_i (core->config, "scr.interactive") && r_config_get_i (core->config, "scr.progressbar") && istty;
7254 size_t current_line = 0;
7255 nl = strchr (odata, '\n');
7256 if (nl) {
7257 r_cons_break_push (NULL, NULL);
7258 do {
7259 if (show_progress_bar) {
7260 r_print_progressbar_with_count (core->print, current_line++, line_count, 80, true);
7261 }
7262 if (r_cons_is_breaked ()) {
7263 free (odata);
7264 r_cons_break_pop ();
7265 return ret;
7266 }
7267 *nl = '\0';
7268 r = r_core_cmd (core, data, 0);
7269 if (r < 0) {
7270 data = nl + 1;
7271 ret = -1;
7272 break;
7273 }
7274 r_cons_flush ();
7275 if (data[0] == 'q') {
7276 if (data[1] == '!') {
7277 ret = -1;
7278 } else {
7279 eprintf ("'q': quit ignored. Use 'q!'\n");
7280 }
7281 data = nl + 1;
7282 break;
7283 }
7284 data = nl + 1;
7285 r_core_task_yield (&core->tasks);
7286 } while ((nl = strchr (data, '\n')));
7287 r_cons_break_pop ();
7288 if (show_progress_bar) {
7289 r_print_progressbar_with_count (core->print, line_count, line_count, 80, true);
7290 r_cons_newline ();
7291 }
7292 }
7293 if (ret >= 0 && data && *data) {
7294 r_core_cmd (core, data, 0);
7295 r_cons_flush ();
7296 r_core_task_yield (&core->tasks);
7297 }
7298 free (odata);
7299 return ret;
7300 }
7301
r_core_cmd_file(RCore * core,const char * file)7302 R_API int r_core_cmd_file(RCore *core, const char *file) {
7303 char *data = r_file_abspath (file);
7304 if (!data) {
7305 return false;
7306 }
7307 char *odata = r_file_slurp (data, NULL);
7308 free (data);
7309 if (!odata) {
7310 return false;
7311 }
7312 if (!r_core_cmd_lines (core, odata)) {
7313 eprintf ("Failed to run script '%s'\n", file);
7314 free (odata);
7315 return false;
7316 }
7317 free (odata);
7318 return true;
7319 }
7320
r_core_cmd_command(RCore * core,const char * command)7321 R_API int r_core_cmd_command(RCore *core, const char *command) {
7322 int ret, len;
7323 char *buf, *rcmd, *ptr;
7324 char *cmd = r_core_sysenv_begin (core, command);
7325 rcmd = ptr = buf = r_sys_cmd_str (cmd, 0, &len);
7326 if (!buf) {
7327 free (cmd);
7328 return -1;
7329 }
7330 ret = r_core_cmd (core, rcmd, 0);
7331 r_core_sysenv_end (core, command);
7332 free (buf);
7333 return ret;
7334 }
7335
7336 //TODO: Fix disasm loop is mandatory
r_core_disassemble_instr(RCore * core,ut64 addr,int l)7337 R_API char *r_core_disassemble_instr(RCore *core, ut64 addr, int l) {
7338 char *cmd, *ret = NULL;
7339 cmd = r_str_newf ("pd %i @ 0x%08"PFMT64x, l, addr);
7340 if (cmd) {
7341 ret = r_core_cmd_str (core, cmd);
7342 free (cmd);
7343 }
7344 return ret;
7345 }
7346
r_core_disassemble_bytes(RCore * core,ut64 addr,int b)7347 R_API char *r_core_disassemble_bytes(RCore *core, ut64 addr, int b) {
7348 char *cmd, *ret = NULL;
7349 cmd = r_str_newf ("pD %i @ 0x%08"PFMT64x, b, addr);
7350 if (cmd) {
7351 ret = r_core_cmd_str (core, cmd);
7352 free (cmd);
7353 }
7354 return ret;
7355 }
7356
r_core_cmd_buffer(RCore * core,const char * buf)7357 R_API int r_core_cmd_buffer(RCore *core, const char *buf) {
7358 char *ptr, *optr, *str = strdup (buf);
7359 if (!str) {
7360 return false;
7361 }
7362 optr = str;
7363 ptr = strchr (str, '\n');
7364 while (ptr) {
7365 *ptr = '\0';
7366 r_core_cmd (core, optr, 0);
7367 optr = ptr + 1;
7368 ptr = strchr (str, '\n');
7369 }
7370 r_core_cmd (core, optr, 0);
7371 free (str);
7372 return true;
7373 }
7374
r_core_cmdf(RCore * core,const char * fmt,...)7375 R_API int r_core_cmdf(RCore *core, const char *fmt, ...) {
7376 char string[4096];
7377 int ret;
7378 va_list ap;
7379 va_start (ap, fmt);
7380 vsnprintf (string, sizeof (string), fmt, ap);
7381 ret = r_core_cmd (core, string, 0);
7382 va_end (ap);
7383 return ret;
7384 }
7385
r_core_cmd0(RCore * core,const char * cmd)7386 R_API int r_core_cmd0(RCore *core, const char *cmd) {
7387 return r_core_cmd (core, cmd, 0);
7388 }
7389
r_core_flush(RCore * core,const char * cmd)7390 R_API int r_core_flush(RCore *core, const char *cmd) {
7391 int ret = r_core_cmd (core, cmd, 0);
7392 r_cons_flush ();
7393 return ret;
7394 }
7395
r_core_cmd_str_pipe(RCore * core,const char * cmd)7396 R_API char *r_core_cmd_str_pipe(RCore *core, const char *cmd) {
7397 char *tmp = NULL;
7398 char *p = (*cmd != '"')? strchr (cmd, '|'): NULL;
7399 if (!p && *cmd != '!' && *cmd != '.') {
7400 return r_core_cmd_str (core, cmd);
7401 }
7402 r_cons_reset ();
7403 r_sandbox_disable (true);
7404 if (r_file_mkstemp ("cmd", &tmp) != -1) {
7405 int pipefd = r_cons_pipe_open (tmp, 1, 0);
7406 if (pipefd == -1) {
7407 r_file_rm (tmp);
7408 r_sandbox_disable (false);
7409 free (tmp);
7410 return r_core_cmd_str (core, cmd);
7411 }
7412 char *_cmd = strdup (cmd);
7413 if (core->use_tree_sitter_r2cmd) {
7414 r_core_cmd (core, _cmd, 0);
7415 } else {
7416 r_core_cmd_subst (core, _cmd);
7417 }
7418 r_cons_flush ();
7419 r_cons_pipe_close (pipefd);
7420 if (r_file_exists (tmp)) {
7421 char *s = r_file_slurp (tmp, NULL);
7422 r_file_rm (tmp);
7423 r_sandbox_disable (false);
7424 free (tmp);
7425 free (_cmd);
7426 return s? s: strdup ("");
7427 }
7428 eprintf ("slurp %s fails\n", tmp);
7429 r_file_rm (tmp);
7430 free (tmp);
7431 free (_cmd);
7432 r_sandbox_disable (false);
7433 return r_core_cmd_str (core, cmd);
7434 }
7435 r_sandbox_disable (0);
7436 return NULL;
7437 }
7438
r_core_cmd_strf(RCore * core,const char * fmt,...)7439 R_API char *r_core_cmd_strf(RCore *core, const char *fmt, ...) {
7440 char string[4096];
7441 va_list ap;
7442 va_start (ap, fmt);
7443 vsnprintf (string, sizeof (string), fmt, ap);
7444 char *ret = r_core_cmd_str (core, string);
7445 va_end (ap);
7446 return ret;
7447 }
7448
7449 /* return: pointer to a buffer with the output of the command */
r_core_cmd_str(RCore * core,const char * cmd)7450 R_API char *r_core_cmd_str(RCore *core, const char *cmd) {
7451 r_cons_push ();
7452 if (r_core_cmd (core, cmd, 0) == -1) {
7453 //eprintf ("Invalid command: %s\n", cmd);
7454 return NULL;
7455 }
7456 r_cons_filter ();
7457 const char *static_str = r_cons_get_buffer ();
7458 char *retstr = strdup (r_str_get (static_str));
7459 r_cons_pop ();
7460 r_cons_echo (NULL);
7461 return retstr;
7462 }
7463
7464 /* run cmd in the main task synchronously */
r_core_cmd_task_sync(RCore * core,const char * cmd,bool log)7465 R_API int r_core_cmd_task_sync(RCore *core, const char *cmd, bool log) {
7466 RCoreTask *task = core->tasks.main_task;
7467 char *s = strdup (cmd);
7468 if (!s) {
7469 return 0;
7470 }
7471 task->cmd = s;
7472 task->cmd_log = log;
7473 task->state = R_CORE_TASK_STATE_BEFORE_START;
7474 int res = r_core_task_run_sync (&core->tasks, task);
7475 free (s);
7476 return res;
7477 }
7478
cmd_ox(void * data,const char * input)7479 static int cmd_ox(void *data, const char *input) {
7480 return r_core_cmdf ((RCore*)data, "s 0%s", input);
7481 }
7482
compare_cmd_descriptor_name(const void * a,const void * b)7483 static int compare_cmd_descriptor_name(const void *a, const void *b) {
7484 return strcmp (((RCmdDescriptor *)a)->cmd, ((RCmdDescriptor *)b)->cmd);
7485 }
7486
cmd_descriptor_init(RCore * core)7487 static void cmd_descriptor_init(RCore *core) {
7488 const ut8 *p;
7489 RListIter *iter;
7490 RCmdDescriptor *x, *y;
7491 int n = core->cmd_descriptors->length;
7492 r_list_sort (core->cmd_descriptors, compare_cmd_descriptor_name);
7493 r_list_foreach (core->cmd_descriptors, iter, y) {
7494 if (--n < 0) {
7495 break;
7496 }
7497 x = &core->root_cmd_descriptor;
7498 for (p = (const ut8 *)y->cmd; *p; p++) {
7499 if (!x->sub[*p]) {
7500 if (p[1]) {
7501 RCmdDescriptor *d = R_NEW0 (RCmdDescriptor);
7502 r_list_append (core->cmd_descriptors, d);
7503 x->sub[*p] = d;
7504 } else {
7505 x->sub[*p] = y;
7506 }
7507 } else if (!p[1]) {
7508 eprintf ("Command '%s' is duplicated, please check\n", y->cmd);
7509 }
7510 x = x->sub[*p];
7511 }
7512 }
7513 }
7514
core_cmd0_wrapper(void * core,const char * cmd)7515 static int core_cmd0_wrapper(void *core, const char *cmd) {
7516 return r_core_cmd0 ((RCore *)core, cmd);
7517 }
7518
r_core_cmd_init(RCore * core)7519 R_API void r_core_cmd_init(RCore *core) {
7520 struct {
7521 const char *cmd;
7522 const char *description;
7523 RCmdCb cb;
7524 void (*descriptor_init)(RCore *core, RCmdDesc *parent);
7525 const RCmdDescHelp *help;
7526 const RCmdDescHelp *group_help;
7527 RCmdDescType type;
7528 RCmdArgvCb argv_cb;
7529 } cmds[] = {
7530 {"!", "run system command", cmd_system, NULL, &system_help},
7531 {"_", "print last output", cmd_last, NULL, &underscore_help},
7532 {"#", "calculate hash", cmd_hash, NULL, &hash_help},
7533 {"$", "alias", cmd_alias, NULL, &alias_help},
7534 {"%", "short version of 'env' command", cmd_env, NULL, &env_help},
7535 {"&", "tasks", cmd_tasks, NULL, &tasks_help},
7536 {"(", "macro", cmd_macro, cmd_macro_init, ¯o_help},
7537 {"*", "pointer read/write", cmd_pointer, NULL, &pointer_help},
7538 {"-", "open cfg.editor and run script", cmd_stdin, NULL, &stdin_help},
7539 {".", "interpret", cmd_interpret, NULL, &interpret_help},
7540 {",", "create and manipulate tables", cmd_table, NULL, &table_help},
7541 {"/", "search kw, pattern aes", cmd_search, cmd_search_init, &search_help},
7542 {"=", "io pipe", cmd_rap, NULL, &rap_help},
7543 {"?", "help message", cmd_help, cmd_help_init, &help_help},
7544 {"\\","alias for =!", cmd_rap_run, NULL, &rap_run_help},
7545 {"'", "alias for =!", cmd_rap_run, NULL, &rap_run_help},
7546 {"0", "alias for s 0x", cmd_ox, NULL, &zero_help},
7547 {"a", "analysis", cmd_anal, cmd_anal_init, &anal_help},
7548 {"b", "change block size", cmd_bsize, NULL, &b_help},
7549 {"c", "compare memory", cmd_cmp, cmd_cmp_init, &c_help},
7550 {"C", "code metadata", cmd_meta, cmd_meta_init, &C_help},
7551 {"d", "debugger operations", cmd_debug, cmd_debug_init, &d_help},
7552 {"e", "evaluate configuration variable", cmd_eval, cmd_eval_init, &e_help},
7553 {"f", "get/set flags", cmd_flag, cmd_flag_init, &f_help},
7554 {"g", "egg manipulation", cmd_egg, cmd_egg_init, &g_help},
7555 {"i", "get file info", cmd_info, cmd_info_init, &i_help},
7556 {"k", "perform sdb query", cmd_kuery, NULL, &k_help},
7557 {"l", "list files and directories", cmd_ls, NULL, &l_help},
7558 {"j", "join the contents of the two files", cmd_join, NULL, &j_help},
7559 {"h", "show the top n number of line in file", cmd_head, NULL, &h_help},
7560 {"L", "manage dynamically loaded plugins", cmd_plugins, NULL, &L_help},
7561 {"m", "mount filesystem", cmd_mount, cmd_mount_init, &m_help},
7562 {"o", "open or map file", cmd_open, cmd_open_init, &o_help},
7563 {"p", "print current block", cmd_print, cmd_print_init, &p_help},
7564 {"P", "project", cmd_project, cmd_project_init, &P_help},
7565 {"q", "exit program session", cmd_quit, cmd_quit_init, &q_help},
7566 {"Q", "alias for q!", cmd_Quit, NULL, &Q_help},
7567 {":", "long commands starting with :", cmd_colon, NULL, &colon_help},
7568 {"r", "change file size", cmd_resize, NULL, &r_help},
7569 {"s", "seek to an offset", cmd_seek, cmd_seek_init, &s_help},
7570 {"t", "type information (cparse)", cmd_type, cmd_type_init, &t_help},
7571 {"T", "Text log utility", cmd_log, cmd_log_init, &T_help},
7572 {"u", "uname/undo", cmd_undo, NULL, &u_help},
7573 {"<", "pipe into RCons.readChar", cmd_pipein, NULL, &pipein_help},
7574 {"V", "enter visual mode", cmd_visual, NULL, &V_help},
7575 {"v", "enter visual mode", cmd_panels, NULL, &v_help},
7576 {"w", "write bytes", cmd_write, cmd_write_init, &w_help, &w_group_help, R_CMD_DESC_TYPE_GROUP, w_handler},
7577 {"x", "alias for px", cmd_hexdump, NULL, &x_help},
7578 {"y", "yank bytes", cmd_yank, NULL, &y_help},
7579 {"z", "zignatures", cmd_zign, cmd_zign_init, &z_help},
7580 };
7581
7582 core->rcmd = r_cmd_new ();
7583 core->rcmd->macro.user = core;
7584 core->rcmd->macro.num = core->num;
7585 core->rcmd->macro.cmd = core_cmd0_wrapper;
7586 core->rcmd->nullcallback = r_core_cmd_nullcallback;
7587 core->rcmd->macro.cb_printf = (PrintfCallback)r_cons_printf;
7588 r_cmd_set_data (core->rcmd, core);
7589 core->cmd_descriptors = r_list_newf (free);
7590
7591 RCmdDesc *root = r_cmd_get_root (core->rcmd);
7592 size_t i;
7593 for (i = 0; i < R_ARRAY_SIZE (cmds); i++) {
7594 r_cmd_add (core->rcmd, cmds[i].cmd, cmds[i].cb);
7595
7596 RCmdDesc *cd = NULL;
7597 switch (cmds[i].type) {
7598 case R_CMD_DESC_TYPE_OLDINPUT:
7599 cd = r_cmd_desc_oldinput_new (core->rcmd, root, cmds[i].cmd, cmds[i].cb, cmds[i].help);
7600 break;
7601 case R_CMD_DESC_TYPE_ARGV:
7602 cd = r_cmd_desc_argv_new (core->rcmd, root, cmds[i].cmd, cmds[i].argv_cb, cmds[i].help);
7603 break;
7604 case R_CMD_DESC_TYPE_INNER:
7605 cd = r_cmd_desc_inner_new (core->rcmd, root, cmds[i].cmd, cmds[i].help);
7606 break;
7607 case R_CMD_DESC_TYPE_GROUP:
7608 cd = r_cmd_desc_group_new (core->rcmd, root, cmds[i].cmd, cmds[i].argv_cb, cmds[i].help, cmds[i].group_help);
7609 break;
7610 }
7611 if (cd && cmds[i].descriptor_init) {
7612 cmds[i].descriptor_init (core, cd);
7613 }
7614 }
7615 DEFINE_CMD_DESCRIPTOR_SPECIAL (core, $, dollar);
7616 DEFINE_CMD_DESCRIPTOR_SPECIAL (core, %, percent);
7617 DEFINE_CMD_DESCRIPTOR_SPECIAL (core, *, star);
7618 DEFINE_CMD_DESCRIPTOR_SPECIAL (core, ., dot);
7619 DEFINE_CMD_DESCRIPTOR_SPECIAL (core, =, equal);
7620
7621 DEFINE_CMD_DESCRIPTOR (core, b);
7622 DEFINE_CMD_DESCRIPTOR (core, k);
7623 DEFINE_CMD_DESCRIPTOR (core, r);
7624 DEFINE_CMD_DESCRIPTOR (core, u);
7625 DEFINE_CMD_DESCRIPTOR (core, y);
7626 cmd_descriptor_init (core);
7627 }
7628