1 /* radare - LGPL - Copyright 2009-2020 - pancake */
2
3 #include <r_core.h>
4 #include <r_cons.h>
5
6 #define NPF 5
7 #define PIDX (R_ABS (core->printidx % NPF))
8
9 static void visual_refresh(RCore *core);
10
11 static int obs = 0;
12 static int blocksize = 0;
13 static bool autoblocksize = true;
14 static int disMode = 0;
15 static int hexMode = 0;
16 static int printMode = 0;
17 static bool snowMode = false;
18 static RList *snows = NULL;
19 static int color = 1;
20 static int debug = 1;
21 static int zoom = 0;
22
23 typedef struct {
24 int x;
25 int y;
26 } Snow;
27
28 #define KEY_ALTQ 0xc5
29
30 static const char *printfmtSingle[NPF] = {
31 "xc", // HEXDUMP
32 "pd $r", // ASSEMBLY
33 "pxw 64@r:SP;dr=;pd $r", // DEBUGGER
34 "prc", // OVERVIEW
35 "pss", // PC// copypasteable views
36 };
37
38 static const char *printfmtColumns[NPF] = {
39 "pCx", // HEXDUMP // + pCw
40 "pCd $r-1", // ASSEMBLY
41 "pCD", // DEBUGGER
42 "pCA", // OVERVIEW
43 "pCc", // PC// copypasteable views
44 };
45
46 // to print the stack in the debugger view
47 #define PRINT_HEX_FORMATS 10
48 #define PRINT_3_FORMATS 2
49 #define PRINT_4_FORMATS 9
50 #define PRINT_5_FORMATS 8
51
52 static int currentFormat = 0;
53 static int current0format = 0;
54 static const char *printHexFormats[PRINT_HEX_FORMATS] = {
55 "px", "pxa", "pxr", "prx", "pxb", "pxh", "pxw", "pxq", "pxd", "pxr",
56 };
57 static int current3format = 0;
58 static const char *print3Formats[PRINT_3_FORMATS] = { // not used at all. its handled by the pd format
59 "pxw 64@r:SP;dr=;pd $r", // DEBUGGER
60 "pCD"
61 };
62 static int current4format = 0;
63 static const char *print4Formats[PRINT_4_FORMATS] = {
64 "prc", "p2", "prc=a", "pxAv", "pxx", "p=e $r-2", "pq 64", "pk 64", "pri",
65 };
66 static int current5format = 0;
67 static const char *print5Formats[PRINT_5_FORMATS] = {
68 "pca", "pcA", "p8", "pcc", "pss", "pcp", "pcd", "pcj"
69 };
70
r_core_visual_applyHexMode(RCore * core,int hexMode)71 R_API void r_core_visual_applyHexMode(RCore *core, int hexMode) {
72 currentFormat = R_ABS(hexMode) % PRINT_HEX_FORMATS;
73 switch (currentFormat) {
74 case 0: /* px */
75 case 3: /* prx */
76 case 6: /* pxw */
77 case 9: /* pxr */
78 r_config_set (core->config, "hex.compact", "false");
79 r_config_set (core->config, "hex.comments", "true");
80 break;
81 case 1: /* pxa */
82 case 4: /* pxb */
83 case 7: /* pxq */
84 r_config_set (core->config, "hex.compact", "true");
85 r_config_set (core->config, "hex.comments", "true");
86 break;
87 case 2: /* pxr */
88 case 5: /* pxh */
89 case 8: /* pxd */
90 r_config_set (core->config, "hex.compact", "false");
91 r_config_set (core->config, "hex.comments", "false");
92 break;
93 }
94 }
95
r_core_visual_toggle_decompiler_disasm(RCore * core,bool for_graph,bool reset)96 R_API void r_core_visual_toggle_decompiler_disasm(RCore *core, bool for_graph, bool reset) {
97 static RConfigHold *hold = NULL; // should be a tab-specific var
98 if (hold) {
99 r_config_hold_restore (hold);
100 r_config_hold_free (hold);
101 hold = NULL;
102 return;
103 }
104 if (reset) {
105 return;
106 }
107 hold = r_config_hold_new (core->config);
108 r_config_hold (hold, "asm.hint.pos", "asm.cmt.col", "asm.offset", "asm.lines",
109 "asm.indent", "asm.bytes", "asm.comments", "asm.dwarf", "asm.usercomments", "asm.instr", NULL);
110 if (for_graph) {
111 r_config_set (core->config, "asm.hint.pos", "-2");
112 r_config_set (core->config, "asm.lines", "false");
113 r_config_set (core->config, "asm.indent", "false");
114 } else {
115 r_config_set (core->config, "asm.hint.pos", "0");
116 r_config_set (core->config, "asm.indent", "true");
117 r_config_set (core->config, "asm.lines", "true");
118 }
119 r_config_set (core->config, "asm.cmt.col", "0");
120 r_config_set (core->config, "asm.offset", "false");
121 r_config_set (core->config, "asm.dwarf", "true");
122 r_config_set (core->config, "asm.bytes", "false");
123 r_config_set (core->config, "asm.comments", "false");
124 r_config_set (core->config, "asm.usercomments", "true");
125 r_config_set (core->config, "asm.instr", "false");
126 }
127
setcursor(RCore * core,bool cur)128 static void setcursor(RCore *core, bool cur) {
129 int flags = core->print->flags; // wtf
130 if (core->print->cur_enabled) {
131 flags |= R_PRINT_FLAGS_CURSOR;
132 } else {
133 flags &= ~(R_PRINT_FLAGS_CURSOR);
134 }
135 core->print->cur_enabled = cur;
136 if (core->print->cur == -1) {
137 core->print->cur = 0;
138 }
139 r_print_set_flags (core->print, flags);
140 core->print->col = core->print->cur_enabled? 1: 0;
141 }
142
r_core_visual_applyDisMode(RCore * core,int disMode)143 R_API void r_core_visual_applyDisMode(RCore *core, int disMode) {
144 currentFormat = R_ABS(disMode) % 5;
145 switch (currentFormat) {
146 case 0:
147 r_config_set (core->config, "asm.pseudo", "false");
148 r_config_set (core->config, "asm.bytes", "true");
149 r_config_set (core->config, "asm.esil", "false");
150 r_config_set (core->config, "emu.str", "false");
151 r_config_set (core->config, "asm.emu", "false");
152 break;
153 case 1:
154 r_config_set (core->config, "asm.pseudo", "false");
155 r_config_set (core->config, "asm.bytes", "true");
156 r_config_set (core->config, "asm.esil", "false");
157 r_config_set (core->config, "asm.emu", "false");
158 r_config_set (core->config, "emu.str", "true");
159 break;
160 case 2:
161 r_config_set (core->config, "asm.pseudo", "true");
162 r_config_set (core->config, "asm.bytes", "true");
163 r_config_set (core->config, "asm.esil", "true");
164 r_config_set (core->config, "emu.str", "true");
165 r_config_set (core->config, "asm.emu", "true");
166 break;
167 case 3:
168 r_config_set (core->config, "asm.pseudo", "false");
169 r_config_set (core->config, "asm.bytes", "false");
170 r_config_set (core->config, "asm.esil", "false");
171 r_config_set (core->config, "asm.emu", "false");
172 r_config_set (core->config, "emu.str", "true");
173 break;
174 case 4:
175 r_config_set (core->config, "asm.pseudo", "true");
176 r_config_set (core->config, "asm.bytes", "false");
177 r_config_set (core->config, "asm.esil", "false");
178 r_config_set (core->config, "asm.emu", "false");
179 r_config_set (core->config, "emu.str", "true");
180 break;
181 }
182 }
183
nextPrintCommand(void)184 static void nextPrintCommand(void) {
185 current0format++;
186 current0format %= PRINT_HEX_FORMATS;
187 currentFormat = current0format;
188 }
189
prevPrintCommand(void)190 static void prevPrintCommand(void) {
191 current0format--;
192 if (current0format < 0) {
193 current0format = 0;
194 }
195 currentFormat = current0format;
196 }
197
stackPrintCommand(RCore * core)198 static const char *stackPrintCommand(RCore *core) {
199 if (current0format == 0) {
200 if (r_config_get_i (core->config, "dbg.slow")) {
201 return "pxr";
202 }
203 if (r_config_get_i (core->config, "stack.bytes")) {
204 return "px";
205 }
206 switch (core->rasm->bits) {
207 case 64: return "pxq"; break;
208 case 32: return "pxw"; break;
209 }
210 return "px";
211 }
212 return printHexFormats[current0format % PRINT_HEX_FORMATS];
213 }
214
__core_visual_print_command(RCore * core)215 static const char *__core_visual_print_command(RCore *core) {
216 if (core->visual.tabs) {
217 RCoreVisualTab *tab = r_list_get_n (core->visual.tabs, core->visual.tab);
218 if (tab && tab->name[0] == ':') {
219 return tab->name + 1;
220 }
221 }
222 if (r_config_get_i (core->config, "scr.dumpcols")) {
223 free (core->stkcmd);
224 core->stkcmd = r_str_new (stackPrintCommand (core));
225 return printfmtColumns[PIDX];
226 }
227 return printfmtSingle[PIDX];
228 }
229
__core_visual_gogo(RCore * core,int ch)230 static bool __core_visual_gogo(RCore *core, int ch) {
231 RIOMap *map;
232 int ret = -1;
233 switch (ch) {
234 case 'g':
235 if (core->io->va) {
236 RIOMap *map = r_io_map_get (core->io, core->offset);
237 if (!map && !r_pvector_empty (&core->io->maps)) {
238 map = r_pvector_at (&core->io->maps, r_pvector_len (&core->io->maps) - 1);
239 }
240 if (map) {
241 r_core_seek (core, r_io_map_begin (map), true);
242 }
243 } else {
244 r_core_seek (core, 0, true);
245 }
246 r_io_sundo_push (core->io, core->offset, r_print_get_cursor (core->print));
247 return true;
248 case 'G':
249 map = r_io_map_get (core->io, core->offset);
250 if (!map && !r_pvector_empty (&core->io->maps)) {
251 map = r_pvector_at (&core->io->maps, 0);
252 }
253 if (map) {
254 RPrint *p = core->print;
255 int scr_rows;
256 if (!p->consbind.get_size) {
257 break;
258 }
259 (void)p->consbind.get_size (&scr_rows);
260 ut64 scols = r_config_get_i (core->config, "hex.cols");
261 ret = r_core_seek (core, r_io_map_end (map) - (scr_rows - 2) * scols, true);
262 }
263 if (ret != -1) {
264 r_io_sundo_push (core->io, core->offset, r_print_get_cursor (core->print));
265 }
266 return true;
267 }
268 return false;
269 }
270
271 static const char *help_visual[] = {
272 "?", "full help",
273 "!", "enter panels",
274 "a", "code analysis",
275 "c", "toggle cursor",
276 "d", "debugger / emulator",
277 "e", "toggle configurations",
278 "i", "insert / write",
279 "m", "moving around (seeking)",
280 "p", "print commands and modes",
281 "v", "view management",
282 NULL
283 };
284
285 static const char *help_msg_visual[] = {
286 "?", "show visual mode help (short)",
287 "??", "show visual mode help (full)",
288 "$", "set the program counter to the current offset + cursor",
289 "&", "rotate asm.bits between 8, 16, 32 and 64 applying hints",
290 "%", "in cursor mode finds matching pair, otherwise toggle autoblocksz",
291 "^", "seek to the beginning of the function",
292 "!", "swap into visual panels mode",
293 "TAB", "switch to the next print mode (or element in cursor mode)",
294 "_", "enter the flag/comment/functions/.. hud (same as VF_)",
295 "=", "set cmd.vprompt (top row)",
296 "|", "set cmd.cprompt (right column)",
297 ".", "seek to program counter",
298 "#", "toggle decompiler comments in disasm (see pdd* from r2dec)",
299 "\\", "toggle visual split mode",
300 "\"", "toggle the column mode (uses pC..)",
301 "/", "in cursor mode search in current block",
302 "(", "toggle snow",
303 ")", "toggle emu.str",
304 ":cmd", "run radare command",
305 ";[-]cmt", "add/remove comment",
306 "0", "seek to beginning of current function",
307 "[1-9]", "follow jmp/call identified by shortcut (like ;[1])",
308 ",file", "add a link to the text file",
309 "/*+-[]", "change block size, [] = resize hex.cols",
310 "<,>", "seek aligned to block size (in cursor slurp or dump files)",
311 "a/A", "(a)ssemble code, visual (A)ssembler",
312 "b", "browse evals, symbols, flags, mountpoints, evals, classes, ...",
313 "B", "toggle breakpoint",
314 "c/C", "toggle (c)ursor and (C)olors",
315 "d[f?]", "define function, data, code, ..",
316 "D", "enter visual diff mode (set diff.from/to)",
317 "f/F", "set/unset or browse flags. f- to unset, F to browse, ..",
318 "hjkl", "move around (or HJKL) (left-down-up-right)",
319 "i", "insert hex or string (in hexdump) use tab to toggle",
320 "I", "insert hexpair block ",
321 "mK/'K", "mark/go to Key (any key)",
322 "n/N", "seek next/prev function/flag/hit (scr.nkey)",
323 "g", "go/seek to given offset (g[g/G]<enter> to seek begin/end of file)",
324 "O", "toggle asm.pseudo and asm.esil",
325 "p/P", "rotate print modes (hex, disasm, debug, words, buf)",
326 "q", "back to radare shell",
327 "r", "toggle callhints/jmphints/leahints",
328 "R", "randomize color palette (ecr)",
329 "sS", "step / step over",
330 "tT", "tt new tab, t[1-9] switch to nth tab, t= name tab, t- close tab",
331 "uU", "undo/redo seek",
332 "v", "visual function/vars code analysis mode",
333 "V", "(V)iew interactive ascii art graph (agfv)",
334 "wW", "seek cursor to next/prev word",
335 "xX", "show xrefs/refs of current function from/to data/code",
336 "yY", "copy and paste selection",
337 "z", "fold/unfold comments in disassembly",
338 "Z", "shift-tab rotate print modes", // ctoggle zoom mode",
339 "Enter", "follow address of jump/call",
340 NULL
341 };
342
343 static const char *help_msg_visual_fn[] = {
344 "F2", "toggle breakpoint",
345 "F4", "run to cursor",
346 "F7", "single step",
347 "F8", "step over",
348 "F9", "continue",
349 NULL
350 };
351
352 static bool splitView = false;
353 static ut64 splitPtr = UT64_MAX;
354
355 #undef USE_THREADS
356 #define USE_THREADS 1
357
358 #if USE_THREADS
359
printSnow(RCore * core)360 static void printSnow(RCore *core) {
361 if (!snows) {
362 snows = r_list_newf (free);
363 }
364 int i, h, w = r_cons_get_size (&h);
365 int amount = r_num_rand (4);
366 if (amount > 0) {
367 for (i = 0; i < amount; i++) {
368 Snow *snow = R_NEW (Snow);
369 snow->x = r_num_rand (w);
370 snow->y = 0;
371 r_list_append (snows, snow);
372 }
373 }
374 RListIter *iter, *iter2;
375 Snow *snow;
376 r_list_foreach_safe (snows, iter, iter2, snow) {
377 int pos = (r_num_rand (3)) - 1;
378 snow->x += pos;
379 snow->y++;
380 if (snow->x >= w) {
381 r_list_delete (snows, iter);
382 continue;
383 }
384 if (snow->y > h) {
385 r_list_delete (snows, iter);
386 continue;
387 }
388 r_cons_gotoxy (snow->x, snow->y);
389 r_cons_printf ("*");
390 }
391 // r_cons_gotoxy (10 , 10);
392 r_cons_flush ();
393 }
394 #endif
395
rotateAsmBits(RCore * core)396 static void rotateAsmBits(RCore *core) {
397 RAnalHint *hint = r_anal_hint_get (core->anal, core->offset);
398 int bits = hint? hint->bits : r_config_get_i (core->config, "asm.bits");
399 int retries = 4;
400 while (retries > 0) {
401 int nb = bits == 64 ? 8:
402 bits == 32 ? 64:
403 bits == 16 ? 32:
404 bits == 8 ? 16: bits;
405 if ((core->rasm->cur->bits & nb) == nb) {
406 r_core_cmdf (core, "ahb %d", nb);
407 break;
408 }
409 bits = nb;
410 retries--;
411 }
412 r_anal_hint_free (hint);
413 }
414
rotateAsmemu(RCore * core)415 static const char *rotateAsmemu(RCore *core) {
416 const bool isEmuStr = r_config_get_i (core->config, "emu.str");
417 const bool isEmu = r_config_get_i (core->config, "asm.emu");
418 if (isEmu) {
419 if (isEmuStr) {
420 r_config_set (core->config, "emu.str", "false");
421 } else {
422 r_config_set (core->config, "asm.emu", "false");
423 }
424 } else {
425 r_config_set (core->config, "emu.str", "true");
426 }
427 return "pd";
428 }
429
r_core_visual_showcursor(RCore * core,int x)430 R_API void r_core_visual_showcursor(RCore *core, int x) {
431 if (core && core->vmode) {
432 r_cons_show_cursor (x);
433 r_cons_enable_mouse (r_config_get_i (core->config, "scr.wheel"));
434 } else {
435 r_cons_enable_mouse (false);
436 }
437 r_cons_flush ();
438 }
439
printFormat(RCore * core,const int next)440 static void printFormat(RCore *core, const int next) {
441 switch (core->printidx) {
442 case R_CORE_VISUAL_MODE_PX: // 0 // xc
443 hexMode += next;
444 r_core_visual_applyHexMode (core, hexMode);
445 printfmtSingle[0] = printHexFormats[R_ABS(hexMode) % PRINT_HEX_FORMATS];
446 break;
447 case R_CORE_VISUAL_MODE_PD: // pd
448 disMode += next;
449 r_core_visual_applyDisMode (core, disMode);
450 printfmtSingle[1] = rotateAsmemu (core);
451 break;
452 case R_CORE_VISUAL_MODE_DB: // debugger
453 disMode += next;
454 r_core_visual_applyDisMode (core, disMode);
455 printfmtSingle[1] = rotateAsmemu (core);
456 current3format += next;
457 currentFormat = R_ABS (current3format) % PRINT_3_FORMATS;
458 printfmtSingle[2] = print3Formats[currentFormat];
459 break;
460 case R_CORE_VISUAL_MODE_OV: // overview
461 current4format += next;
462 currentFormat = R_ABS (current4format) % PRINT_4_FORMATS;
463 printfmtSingle[3] = print4Formats[currentFormat];
464 break;
465 case R_CORE_VISUAL_MODE_CD: // code
466 current5format += next;
467 currentFormat = R_ABS (current5format) % PRINT_5_FORMATS;
468 printfmtSingle[4] = print5Formats[currentFormat];
469 break;
470 }
471 }
472
nextPrintFormat(RCore * core)473 static inline void nextPrintFormat(RCore *core) {
474 printFormat (core, 1);
475 }
476
prevPrintFormat(RCore * core)477 static inline void prevPrintFormat(RCore *core) {
478 printFormat (core, -1);
479 }
480
r_core_visual_hud(RCore * core)481 R_API int r_core_visual_hud(RCore *core) {
482 const char *c = r_config_get (core->config, "hud.path");
483 char *f = r_str_newf (R_JOIN_3_PATHS ("%s", R2_HUD, "main"),
484 r_sys_prefix (NULL));
485 int use_color = core->print->flags & R_PRINT_FLAGS_COLOR;
486 char *homehud = r_str_home (R2_HOME_HUD);
487 char *res = NULL;
488 char *p = 0;
489 r_cons_singleton ()->context->color_mode = use_color;
490
491 r_core_visual_showcursor (core, true);
492 if (c && *c && r_file_exists (c)) {
493 res = r_cons_hud_file (c);
494 }
495 if (!res && homehud) {
496 res = r_cons_hud_file (homehud);
497 }
498 if (!res && r_file_exists (f)) {
499 res = r_cons_hud_file (f);
500 }
501 if (!res) {
502 r_cons_message ("Cannot find hud file");
503 }
504
505 r_cons_clear ();
506 if (res) {
507 p = strchr (res, ';');
508 r_cons_println (res);
509 r_cons_flush ();
510 if (p) {
511 r_core_cmd0 (core, p + 1);
512 }
513 free (res);
514 }
515 r_core_visual_showcursor (core, false);
516 r_cons_flush ();
517 free (homehud);
518 free (f);
519 return (int) (size_t) p;
520 }
521
r_core_visual_jump(RCore * core,ut8 ch)522 R_API void r_core_visual_jump(RCore *core, ut8 ch) {
523 char chbuf[2];
524 ut64 off;
525 chbuf[0] = ch;
526 chbuf[1] = '\0';
527 off = r_core_get_asmqjmps (core, chbuf);
528 if (off != UT64_MAX) {
529 int delta = R_ABS ((st64) off - (st64) core->offset);
530 r_io_sundo_push (core->io, core->offset, r_print_get_cursor (core->print));
531 if (core->print->cur_enabled && delta < 100) {
532 core->print->cur = delta;
533 } else {
534 r_core_visual_seek_animation (core, off);
535 core->print->cur = 0;
536 }
537 r_core_block_read (core);
538 }
539 }
540
541 // TODO: merge with r_cons_cmd_help
r_core_visual_append_help(RStrBuf * p,const char * title,const char ** help)542 R_API void r_core_visual_append_help(RStrBuf *p, const char *title, const char **help) {
543 RCons *cons = r_cons_singleton ();
544 bool use_color = cons->context->color_mode;
545 const char
546 *pal_input_color = use_color ? cons->context->pal.input : "",
547 *pal_args_color = use_color ? cons->context->pal.args : "",
548 *pal_help_color = use_color ? cons->context->pal.help : "",
549 *pal_reset = use_color ? cons->context->pal.reset : "";
550 int i, max_length = 0, padding = 0;
551 const char *help_cmd = NULL, *help_desc = NULL;
552
553 // calculate padding for description text in advance
554 for (i = 0; help[i]; i += 2) {
555 max_length = R_MAX (max_length, strlen (help[i]));
556 }
557
558 /* Usage header */
559 r_strbuf_appendf (p, "%s%s%s\n",
560 pal_args_color, title, pal_reset);
561
562 /* Body of help text, indented */
563 for (i = 0; help[i]; i += 2) {
564 help_cmd = help[i + 0];
565 help_desc = help[i + 1];
566
567 padding = max_length - (strlen (help[i]));
568 r_strbuf_appendf (p, "| %s%s%*s %s%s%s\n",
569 pal_input_color, help_cmd,
570 padding, "",
571 pal_help_color, help_desc, pal_reset);
572 }
573 }
574
visual_help(RCore * core)575 static int visual_help(RCore *core) {
576 int ret = 0;
577 RStrBuf *p, *q;
578 repeat:
579 p = r_strbuf_new (NULL);
580 q = r_strbuf_new (NULL);
581 if (!p) {
582 return 0;
583 }
584 r_cons_clear00 ();
585 r_core_visual_append_help (q, "Visual Mode Help (short)", help_visual);
586 r_cons_printf ("%s", r_strbuf_get (q));
587 r_cons_flush ();
588 switch (r_cons_readchar ()) {
589 case 'q':
590 r_strbuf_free (p);
591 r_strbuf_free (q);
592 return ret;
593 case '!':
594 r_core_panels_root (core, core->panels_root);
595 break;
596 case '?':
597 r_core_visual_append_help (p, "Visual Mode Help (full)", help_msg_visual);
598 r_core_visual_append_help (p, "Function Keys Defaults # Use `e key.` to owerwrite", help_msg_visual_fn);
599 ret = r_cons_less_str (r_strbuf_get (p), "?");
600 break;
601 case 'v':
602 r_strbuf_appendf (p, "Visual Views:\n\n");
603 r_strbuf_appendf (p,
604 " \\ toggle horizonal split mode\n"
605 " tt create a new tab (same as t+)\n"
606 " t= give a name to the current tab\n"
607 " t- close current tab\n"
608 " th select previous tab (same as tj)\n"
609 " tl select next tab (same as tk)\n"
610 " t[1-9] select nth tab\n"
611 " C -> rotate scr.color=0,1,2,3\n"
612 " R -> rotate color theme with ecr command which honors scr.randpal\n"
613 );
614 ret = r_cons_less_str (r_strbuf_get (p), "?");
615 break;
616 case 'p':
617 r_strbuf_appendf (p, "Visual Print Modes:\n\n");
618 r_strbuf_appendf (p,
619 " pP -> change to the next/previous print mode (hex, dis, ..)\n"
620 " TAB -> rotate between all the configurations for the current print mode\n"
621 );
622 ret = r_cons_less_str (r_strbuf_get (p), "?");
623 break;
624 case 'e':
625 r_strbuf_appendf (p, "Visual Evals:\n\n");
626 r_strbuf_appendf (p,
627 " E toggle asm.leahints\n"
628 " & rotate asm.bits=16,32,64\n"
629 );
630 ret = r_cons_less_str (r_strbuf_get (p), "?");
631 break;
632 case 'c':
633 setcursor (core, !core->print->cur_enabled);
634 r_strbuf_free (p);
635 return ret;
636 case 'i':
637 r_strbuf_appendf (p, "Visual Insertion Help:\n\n");
638 r_strbuf_appendf (p,
639 " i -> insert bits, bytes or text depending on view\n"
640 " a -> assemble instruction and write the bytes in the current offset\n"
641 " A -> visual assembler\n"
642 " + -> increment value of byte\n"
643 " - -> decrement value of byte\n"
644 );
645 ret = r_cons_less_str (r_strbuf_get (p), "?");
646 break;
647 case 'd':
648 r_strbuf_appendf (p, "Visual Debugger Help:\n\n");
649 r_strbuf_appendf (p,
650 " $ -> set the program counter (PC register)\n"
651 " s -> step in\n"
652 " S -> step over\n"
653 " B -> toggle breakpoint\n"
654 " :dc -> continue\n"
655 );
656 ret = r_cons_less_str (r_strbuf_get (p), "?");
657 break;
658 case 'm':
659 r_strbuf_appendf (p, "Visual Moving Around:\n\n");
660 r_strbuf_appendf (p,
661 " g type flag/offset/register name to seek\n"
662 " hl seek to the next/previous byte\n"
663 " jk seek to the next row (core.offset += hex.cols)\n"
664 " JK seek one page down\n"
665 " ^ seek to the beginning of the current map\n"
666 " $ seek to the end of the current map\n"
667 " c toggle cursor mode (use hjkl to move and HJKL to select a range)\n"
668 " mK/'K mark/go to Key (any key)\n"
669 );
670 ret = r_cons_less_str (r_strbuf_get (p), "?");
671 break;
672 case 'a':
673 r_strbuf_appendf (p, "Visual Analysis:\n\n");
674 r_strbuf_appendf (p,
675 " df -> define function\n"
676 " du -> undefine function\n"
677 " dc -> define as code\n"
678 " dw -> define as dword (32bit)\n"
679 " dw -> define as qword (64bit)\n"
680 " dd -> define current block or selected bytes as data\n"
681 " V -> view graph (same as press the 'space' key)\n"
682 );
683 ret = r_cons_less_str (r_strbuf_get (p), "?");
684 break;
685 }
686 r_strbuf_free (p);
687 r_strbuf_free (q);
688 goto repeat;
689 }
690
prompt_read(const char * p,char * buf,int buflen)691 static void prompt_read(const char *p, char *buf, int buflen) {
692 if (!buf || buflen < 1) {
693 return;
694 }
695 *buf = 0;
696 r_line_set_prompt (p);
697 r_core_visual_showcursor (NULL, true);
698 r_cons_fgets (buf, buflen, 0, NULL);
699 r_core_visual_showcursor (NULL, false);
700 }
701
reset_print_cur(RPrint * p)702 static void reset_print_cur(RPrint *p) {
703 p->cur = 0;
704 p->ocur = -1;
705 }
706
__holdMouseState(RCore * core)707 static bool __holdMouseState(RCore *core) {
708 bool m = r_cons_singleton ()->mouse;
709 r_cons_enable_mouse (false);
710 return m;
711 }
712
backup_current_addr(RCore * core,ut64 * addr,ut64 * bsze,ut64 * newaddr)713 static void backup_current_addr(RCore *core, ut64 *addr, ut64 *bsze, ut64 *newaddr) {
714 *addr = core->offset;
715 *bsze = core->blocksize;
716 if (core->print->cur_enabled) {
717 if (core->print->ocur != -1) {
718 int newsz = core->print->cur - core->print->ocur;
719 *newaddr = core->offset + core->print->ocur;
720 r_core_block_size (core, newsz);
721 } else {
722 *newaddr = core->offset + core->print->cur;
723 }
724 r_core_seek (core, *newaddr, true);
725 }
726 }
727
restore_current_addr(RCore * core,ut64 addr,ut64 bsze,ut64 newaddr)728 static void restore_current_addr(RCore *core, ut64 addr, ut64 bsze, ut64 newaddr) {
729 bool restore_seek = true;
730 if (core->offset != newaddr) {
731 bool cursor_moved = false;
732 // when new address is in the screen bounds, just move
733 // the cursor if enabled and restore seek
734 if (core->print->cur != -1 && core->print->screen_bounds > 1) {
735 if (core->offset >= addr &&
736 core->offset < core->print->screen_bounds) {
737 core->print->ocur = -1;
738 core->print->cur = core->offset - addr;
739 cursor_moved = true;
740 }
741 }
742
743 if (!cursor_moved) {
744 restore_seek = false;
745 reset_print_cur (core->print);
746 }
747 }
748
749 if (core->print->cur_enabled) {
750 if (restore_seek) {
751 r_core_seek (core, addr, true);
752 r_core_block_size (core, bsze);
753 }
754 }
755 }
756
r_core_visual_prompt_input(RCore * core)757 R_API void r_core_visual_prompt_input(RCore *core) {
758 ut64 addr, bsze, newaddr = 0LL;
759 int ret, h;
760 (void) r_cons_get_size (&h);
761 bool mouse_state = __holdMouseState(core);
762 r_cons_gotoxy (0, h);
763 r_cons_reset_colors ();
764 //r_cons_printf ("\nPress <enter> to return to Visual mode.\n");
765 r_cons_show_cursor (true);
766 core->vmode = false;
767
768 backup_current_addr (core, &addr, &bsze, &newaddr);
769 do {
770 ret = r_core_visual_prompt (core);
771 } while (ret);
772 restore_current_addr (core, addr, bsze, newaddr);
773
774 r_cons_show_cursor (false);
775 core->vmode = true;
776 r_cons_enable_mouse (mouse_state && r_config_get_i (core->config, "scr.wheel"));
777 r_cons_show_cursor (true);
778 }
779
r_core_visual_prompt(RCore * core)780 R_API int r_core_visual_prompt(RCore *core) {
781 char buf[1024];
782 int ret;
783 if (PIDX != 2) {
784 core->seltab = 0;
785 }
786 #if __UNIX__
787 r_line_set_prompt (Color_RESET ":> ");
788 #else
789 r_line_set_prompt (":> ");
790 #endif
791 r_core_visual_showcursor (core, true);
792 r_cons_fgets (buf, sizeof (buf), 0, NULL);
793 if (!strcmp (buf, "q")) {
794 ret = false;
795 } else if (*buf) {
796 r_line_hist_add (buf);
797 r_core_cmd (core, buf, 0);
798 r_cons_echo (NULL);
799 r_cons_flush ();
800 ret = true;
801 if (r_config_get_i (core->config, "cfg.debug")) {
802 r_core_cmd (core, ".dr*", 0);
803 }
804 } else {
805 ret = false;
806 //r_cons_any_key (NULL);
807 r_cons_clear00 ();
808 r_core_visual_showcursor (core, false);
809 }
810 return ret;
811 }
812
visual_single_step_in(RCore * core)813 static void visual_single_step_in(RCore *core) {
814 if (r_config_get_i (core->config, "cfg.debug")) {
815 if (core->print->cur_enabled) {
816 // dcu 0xaddr
817 r_core_cmdf (core, "dcu 0x%08"PFMT64x, core->offset + core->print->cur);
818 core->print->cur_enabled = 0;
819 } else {
820 r_core_cmd (core, "ds", 0);
821 r_core_cmd (core, ".dr*", 0);
822 }
823 } else {
824 r_core_cmd (core, "aes", 0);
825 r_core_cmd (core, ".ar*", 0);
826 }
827 }
828
__core_visual_step_over(RCore * core)829 static void __core_visual_step_over(RCore *core) {
830 bool io_cache = r_config_get_i (core->config, "io.cache");
831 r_config_set_i (core->config, "io.cache", false);
832 if (r_config_get_i (core->config, "cfg.debug")) {
833 if (core->print->cur_enabled) {
834 r_core_cmd (core, "dcr", 0);
835 core->print->cur_enabled = 0;
836 } else {
837 r_core_cmd (core, "dso", 0);
838 r_core_cmd (core, ".dr*", 0);
839 }
840 } else {
841 r_core_cmd (core, "aeso", 0);
842 r_core_cmd (core, ".ar*", 0);
843 }
844 r_config_set_i (core->config, "io.cache", io_cache);
845 }
846
visual_breakpoint(RCore * core)847 static void visual_breakpoint(RCore *core) {
848 r_core_cmd (core, "dbs $$", 0);
849 }
850
visual_continue(RCore * core)851 static void visual_continue(RCore *core) {
852 if (r_config_get_i (core->config, "cfg.debug")) {
853 r_core_cmd (core, "dc", 0);
854 } else {
855 r_core_cmd (core, "aec;.ar*", 0);
856 }
857 }
858
visual_nkey(RCore * core,int ch)859 static int visual_nkey(RCore *core, int ch) {
860 const char *cmd;
861 ut64 oseek = UT64_MAX;
862 if (core->print->ocur == -1) {
863 oseek = core->offset;
864 r_core_seek (core, core->offset + core->print->cur, false);
865 }
866
867 switch (ch) {
868 case R_CONS_KEY_F1:
869 cmd = r_config_get (core->config, "key.f1");
870 if (cmd && *cmd) {
871 ch = r_core_cmd0 (core, cmd);
872 } else {
873 visual_help (core);
874 }
875 break;
876 case R_CONS_KEY_F2:
877 cmd = r_config_get (core->config, "key.f2");
878 if (cmd && *cmd) {
879 ch = r_core_cmd0 (core, cmd);
880 } else {
881 visual_breakpoint (core);
882 }
883 break;
884 case R_CONS_KEY_F3:
885 cmd = r_config_get (core->config, "key.f3");
886 if (cmd && *cmd) {
887 ch = r_core_cmd0 (core, cmd);
888 }
889 break;
890 case R_CONS_KEY_F4:
891 cmd = r_config_get (core->config, "key.f4");
892 if (cmd && *cmd) {
893 ch = r_core_cmd0 (core, cmd);
894 } else {
895 if (core->print->cur_enabled) {
896 // dcu 0xaddr
897 r_core_cmdf (core, "dcu 0x%08"PFMT64x, core->offset + core->print->cur);
898 core->print->cur_enabled = 0;
899 }
900 }
901 break;
902 case R_CONS_KEY_F5:
903 cmd = r_config_get (core->config, "key.f5");
904 if (cmd && *cmd) {
905 ch = r_core_cmd0 (core, cmd);
906 }
907 break;
908 case R_CONS_KEY_F6:
909 cmd = r_config_get (core->config, "key.f6");
910 if (cmd && *cmd) {
911 ch = r_core_cmd0 (core, cmd);
912 }
913 break;
914 case R_CONS_KEY_F7:
915 cmd = r_config_get (core->config, "key.f7");
916 if (cmd && *cmd) {
917 ch = r_core_cmd0 (core, cmd);
918 } else {
919 visual_single_step_in (core);
920 }
921 break;
922 case R_CONS_KEY_F8:
923 cmd = r_config_get (core->config, "key.f8");
924 if (cmd && *cmd) {
925 ch = r_core_cmd0 (core, cmd);
926 } else {
927 __core_visual_step_over (core);
928 }
929 break;
930 case R_CONS_KEY_F9:
931 cmd = r_config_get (core->config, "key.f9");
932 if (cmd && *cmd) {
933 ch = r_core_cmd0 (core, cmd);
934 } else {
935 visual_continue (core);
936 }
937 break;
938 case R_CONS_KEY_F10:
939 cmd = r_config_get (core->config, "key.f10");
940 if (cmd && *cmd) {
941 ch = r_core_cmd0 (core, cmd);
942 }
943 break;
944 case R_CONS_KEY_F11:
945 cmd = r_config_get (core->config, "key.f11");
946 if (cmd && *cmd) {
947 ch = r_core_cmd0 (core, cmd);
948 }
949 break;
950 case R_CONS_KEY_F12:
951 cmd = r_config_get (core->config, "key.f12");
952 if (cmd && *cmd) {
953 ch = r_core_cmd0 (core, cmd);
954 }
955 break;
956 }
957 if (oseek != UT64_MAX) {
958 r_core_seek (core, oseek, false);
959 }
960 return ch;
961 }
962
setdiff(RCore * core)963 static void setdiff(RCore *core) {
964 char from[64], to[64];
965 prompt_read ("diff from: ", from, sizeof (from));
966 r_config_set (core->config, "diff.from", from);
967 prompt_read ("diff to: ", to, sizeof (to));
968 r_config_set (core->config, "diff.to", to);
969 }
970
findPair(RCore * core)971 static void findPair(RCore *core) {
972 ut8 buf[256];
973 int i, len, d = core->print->cur + 1;
974 int delta = 0;
975 const ut8 *p, *q = NULL;
976 const char *keys = "{}[]()<>";
977 ut8 ch = core->block[core->print->cur];
978
979 p = (const ut8 *) strchr (keys, ch);
980 if (p) {
981 char p_1 = 0;
982 if ((const char *) p > keys) {
983 p_1 = p[-1];
984 }
985 delta = (size_t) (p - (const ut8 *) keys);
986 ch = (delta % 2 && p != (const ut8 *) keys)? p_1: p[1];
987 }
988 len = 1;
989 buf[0] = ch;
990
991 if (p && (delta % 2)) {
992 for (i = d - 1; i >= 0; i--) {
993 if (core->block[i] == ch) {
994 q = core->block + i;
995 break;
996 }
997 }
998 } else {
999 q = r_mem_mem (core->block + d, core->blocksize - d,
1000 (const ut8 *) buf, len);
1001 if (!q) {
1002 q = r_mem_mem (core->block, R_MIN (core->blocksize, d),
1003 (const ut8 *) buf, len);
1004 }
1005 }
1006 if (q) {
1007 core->print->cur = (int) (size_t) (q - core->block);
1008 core->print->ocur = -1;
1009 r_core_visual_showcursor (core, true);
1010 }
1011 }
1012
findNextWord(RCore * core)1013 static void findNextWord(RCore *core) {
1014 int i, d = core->print->cur_enabled? core->print->cur: 0;
1015 for (i = d + 1; i < core->blocksize; i++) {
1016 switch (core->block[i]) {
1017 case ' ':
1018 case '.':
1019 case '\t':
1020 case '\n':
1021 if (core->print->cur_enabled) {
1022 core->print->cur = i + 1;
1023 core->print->ocur = -1;
1024 r_core_visual_showcursor (core, true);
1025 } else {
1026 r_core_seek (core, core->offset + i + 1, true);
1027 }
1028 return;
1029 }
1030 }
1031 }
1032
isSpace(char ch)1033 static int isSpace(char ch) {
1034 switch (ch) {
1035 case ' ':
1036 case '.':
1037 case ',':
1038 case '\t':
1039 case '\n':
1040 return 1;
1041 }
1042 return 0;
1043 }
1044
findPrevWord(RCore * core)1045 static void findPrevWord(RCore *core) {
1046 int i = core->print->cur_enabled? core->print->cur: 0;
1047 while (i > 1) {
1048 if (isSpace (core->block[i])) {
1049 i--;
1050 } else if (isSpace (core->block[i - 1])) {
1051 i -= 2;
1052 } else {
1053 break;
1054 }
1055 }
1056 for (; i >= 0; i--) {
1057 if (isSpace (core->block[i])) {
1058 if (core->print->cur_enabled) {
1059 core->print->cur = i + 1;
1060 core->print->ocur = -1;
1061 r_core_visual_showcursor (core, true);
1062 }
1063 break;
1064 }
1065 }
1066 }
1067
1068 // TODO: integrate in '/' command with search.inblock ?
visual_search(RCore * core)1069 static void visual_search(RCore *core) {
1070 const ut8 *p;
1071 int len, d = core->print->cur;
1072 char str[128], buf[sizeof (str) * 2 + 1];
1073
1074 r_line_set_prompt ("search byte/string in block: ");
1075 r_cons_fgets (str, sizeof (str), 0, NULL);
1076 len = r_hex_str2bin (str, (ut8 *) buf);
1077 if (*str == '"') {
1078 r_str_ncpy (buf, str + 1, sizeof (buf));
1079 len = strlen (buf);
1080 char *e = buf + len - 1;
1081 if (e > buf && *e == '"') {
1082 *e = 0;
1083 len--;
1084 }
1085 } else if (len < 1) {
1086 r_str_ncpy (buf, str, sizeof (buf));
1087 len = strlen (buf);
1088 }
1089 p = r_mem_mem (core->block + d, core->blocksize - d,
1090 (const ut8 *) buf, len);
1091 if (p) {
1092 core->print->cur = (int) (size_t) (p - core->block);
1093 if (len > 1) {
1094 core->print->ocur = core->print->cur + len - 1;
1095 } else {
1096 core->print->ocur = -1;
1097 }
1098 r_core_visual_showcursor (core, true);
1099 eprintf ("Found in offset 0x%08"PFMT64x" + %d\n", core->offset, core->print->cur);
1100 r_cons_any_key (NULL);
1101 } else {
1102 eprintf ("Cannot find bytes.\n");
1103 r_cons_any_key (NULL);
1104 r_cons_clear00 ();
1105 }
1106 }
1107
r_core_visual_show_char(RCore * core,char ch)1108 R_API void r_core_visual_show_char(RCore *core, char ch) {
1109 if (r_config_get_i (core->config, "scr.feedback") < 2) {
1110 return;
1111 }
1112 if (!IS_PRINTABLE (ch)) {
1113 return;
1114 }
1115 r_cons_gotoxy (1, 2);
1116 r_cons_printf (".---.\n");
1117 r_cons_printf ("| %c |\n", ch);
1118 r_cons_printf ("'---'\n");
1119 r_cons_flush ();
1120 r_sys_sleep (1);
1121 }
1122
r_core_visual_seek_animation(RCore * core,ut64 addr)1123 R_API void r_core_visual_seek_animation(RCore *core, ut64 addr) {
1124 r_core_seek (core, addr, true);
1125 if (r_config_get_i (core->config, "scr.feedback") < 1) {
1126 return;
1127 }
1128 if (core->offset == addr) {
1129 return;
1130 }
1131 r_cons_gotoxy (1, 2);
1132 if (addr > core->offset) {
1133 r_cons_printf (".----.\n");
1134 r_cons_printf ("| \\/ |\n");
1135 r_cons_printf ("'----'\n");
1136 } else {
1137 r_cons_printf (".----.\n");
1138 r_cons_printf ("| /\\ |\n");
1139 r_cons_printf ("'----'\n");
1140 }
1141 r_cons_flush ();
1142 r_sys_usleep (90000);
1143 }
1144
setprintmode(RCore * core,int n)1145 static void setprintmode(RCore *core, int n) {
1146 RAsmOp op;
1147
1148 if (n > 0) {
1149 core->printidx = R_ABS ((core->printidx + 1) % NPF);
1150 } else {
1151 if (core->printidx) {
1152 core->printidx--;
1153 } else {
1154 core->printidx = NPF - 1;
1155 }
1156 }
1157 switch (core->printidx) {
1158 case R_CORE_VISUAL_MODE_PD:
1159 case R_CORE_VISUAL_MODE_DB:
1160 r_asm_op_init (&op);
1161 r_asm_disassemble (core->rasm, &op, core->block, R_MIN (32, core->blocksize));
1162 r_asm_op_fini (&op);
1163 break;
1164 default:
1165 break;
1166 }
1167 }
1168
1169 #define OPDELTA 32
prevop_addr(RCore * core,ut64 addr)1170 static ut64 prevop_addr(RCore *core, ut64 addr) {
1171 ut8 buf[OPDELTA * 2];
1172 ut64 target, base;
1173 RAnalBlock *bb;
1174 RAnalOp op;
1175 int len, ret, i;
1176 int minop = r_anal_archinfo (core->anal, R_ANAL_ARCHINFO_MIN_OP_SIZE);
1177 int maxop = r_anal_archinfo (core->anal, R_ANAL_ARCHINFO_MAX_OP_SIZE);
1178
1179 if (minop == maxop) {
1180 if (minop == -1) {
1181 return addr - 4;
1182 }
1183 return addr - minop;
1184 }
1185
1186 // let's see if we can use anal info to get the previous instruction
1187 // TODO: look in the current basicblock, then in the current function
1188 // and search in all functions only as a last chance, to try to speed
1189 // up the process.
1190 bb = r_anal_bb_from_offset (core->anal, addr - minop);
1191 if (bb) {
1192 ut64 res = r_anal_bb_opaddr_at (bb, addr - minop);
1193 if (res != UT64_MAX) {
1194 return res;
1195 }
1196 }
1197 // if we anal info didn't help then fallback to the dumb solution.
1198 int midflags = r_config_get_i (core->config, "asm.flags.middle");
1199 target = addr;
1200 base = target > OPDELTA ? target - OPDELTA : 0;
1201 r_io_read_at (core->io, base, buf, sizeof (buf));
1202 for (i = 0; i < sizeof (buf); i++) {
1203 ret = r_anal_op (core->anal, &op, base + i,
1204 buf + i, sizeof (buf) - i, R_ANAL_OP_MASK_BASIC);
1205 if (ret) {
1206 len = op.size;
1207 if (len < 1) {
1208 len = 1;
1209 }
1210 r_anal_op_fini (&op); // XXX
1211 if (midflags >= R_MIDFLAGS_REALIGN) {
1212 int skip_bytes = r_core_flag_in_middle (core, base + i, len, &midflags);
1213 if (skip_bytes && base + i + skip_bytes < target) {
1214 i += skip_bytes - 1;
1215 continue;
1216 }
1217 }
1218 } else {
1219 len = 1;
1220 }
1221 if (target <= base + i + len) {
1222 return base + i;
1223 }
1224 i += len - 1;
1225 }
1226 return target > 4 ? target - 4 : 0;
1227 }
1228
1229 // Returns true if we can use analysis to find the previous operation address,
1230 // sets prev_addr to the value of the instruction numinstrs back.
1231 // If we can't use the anal, then set prev_addr to UT64_MAX and return false;
r_core_prevop_addr(RCore * core,ut64 start_addr,int numinstrs,ut64 * prev_addr)1232 R_API bool r_core_prevop_addr(RCore *core, ut64 start_addr, int numinstrs, ut64 *prev_addr) {
1233 RAnalBlock *bb;
1234 int i;
1235 // Check that we're in a bb, otherwise this prevop stuff won't work.
1236 bb = r_anal_bb_from_offset (core->anal, start_addr);
1237 if (bb) {
1238 if (r_anal_bb_opaddr_at (bb, start_addr) != UT64_MAX) {
1239 // Do some anal looping.
1240 for (i = 0; i < numinstrs; i++) {
1241 *prev_addr = prevop_addr (core, start_addr);
1242 start_addr = *prev_addr;
1243 }
1244 return true;
1245 }
1246 }
1247 // Dang! not in a bb, return false and fallback to other methods.
1248 *prev_addr = UT64_MAX;
1249 return false;
1250 }
1251
1252 // Like r_core_prevop_addr(), but also uses fallback from prevop_addr() if
1253 // no anal info is available.
r_core_prevop_addr_force(RCore * core,ut64 start_addr,int numinstrs)1254 R_API ut64 r_core_prevop_addr_force(RCore *core, ut64 start_addr, int numinstrs) {
1255 int i;
1256 for (i = 0; i < numinstrs; i++) {
1257 start_addr = prevop_addr (core, start_addr);
1258 }
1259 return start_addr;
1260 }
1261
r_line_hist_offset_up(RLine * line)1262 R_API int r_line_hist_offset_up(RLine *line) {
1263 RCore *core = line->user;
1264 RIOUndo *undo = &core->io->undo;
1265 if (line->offset_hist_index <= -undo->undos) {
1266 return false;
1267 }
1268 line->offset_hist_index--;
1269 ut64 off = undo->seek[undo->idx + line->offset_hist_index].off;
1270 RFlagItem *f = r_flag_get_at (core->flags, off, false);
1271 char *command;
1272 if (f && f->offset == off && f->offset > 0) {
1273 command = r_str_newf ("%s", f->name);
1274 } else {
1275 command = r_str_newf ("0x%"PFMT64x, off);
1276 }
1277 strncpy (line->buffer.data, command, R_LINE_BUFSIZE - 1);
1278 line->buffer.index = line->buffer.length = strlen (line->buffer.data);
1279 free (command);
1280 return true;
1281 }
1282
r_line_hist_offset_down(RLine * line)1283 R_API int r_line_hist_offset_down(RLine *line) {
1284 RCore *core = line->user;
1285 RIOUndo *undo = &core->io->undo;
1286 if (line->offset_hist_index >= undo->redos) {
1287 return false;
1288 }
1289 line->offset_hist_index++;
1290 if (line->offset_hist_index == undo->redos) {
1291 line->buffer.data[0] = '\0';
1292 line->buffer.index = line->buffer.length = 0;
1293 return false;
1294 }
1295 ut64 off = undo->seek[undo->idx + line->offset_hist_index].off;
1296 RFlagItem *f = r_flag_get_at (core->flags, off, false);
1297 char *command;
1298 if (f && f->offset == off && f->offset > 0) {
1299 command = r_str_newf ("%s", f->name);
1300 } else {
1301 command = r_str_newf ("0x%"PFMT64x, off);
1302 }
1303 strncpy (line->buffer.data, command, R_LINE_BUFSIZE - 1);
1304 line->buffer.index = line->buffer.length = strlen (line->buffer.data);
1305 free (command);
1306 return true;
1307 }
1308
r_core_visual_offset(RCore * core)1309 R_API void r_core_visual_offset(RCore *core) {
1310 ut64 addr, bsze, newaddr = 0LL;
1311 char buf[256];
1312
1313 backup_current_addr (core, &addr, &bsze, &newaddr);
1314 core->cons->line->prompt_type = R_LINE_PROMPT_OFFSET;
1315 r_line_set_hist_callback (core->cons->line,
1316 &r_line_hist_offset_up,
1317 &r_line_hist_offset_down);
1318 r_line_set_prompt ("[offset]> ");
1319 strcpy (buf, "s ");
1320 if (r_cons_fgets (buf + 2, sizeof (buf) - 2, 0, NULL) > 0) {
1321 if (!strcmp (buf + 2, "g") || !strcmp (buf + 2, "G")) {
1322 __core_visual_gogo (core, buf[2]);
1323 } else {
1324 if (buf[2] == '.') {
1325 buf[1] = '.';
1326 }
1327 r_core_cmd0 (core, buf);
1328 restore_current_addr (core, addr, bsze, newaddr);
1329 }
1330 }
1331 r_line_set_hist_callback (core->cons->line, &r_line_hist_cmd_up, &r_line_hist_cmd_down);
1332 core->cons->line->prompt_type = R_LINE_PROMPT_DEFAULT;
1333 }
1334
r_core_visual_prevopsz(RCore * core,ut64 addr)1335 R_API int r_core_visual_prevopsz(RCore *core, ut64 addr) {
1336 ut64 prev_addr = prevop_addr (core, addr);
1337 return addr - prev_addr;
1338 }
1339
addComment(RCore * core,ut64 addr)1340 static void addComment(RCore *core, ut64 addr) {
1341 char buf[1024];
1342 r_cons_printf ("Enter comment for reference:\n");
1343 r_core_visual_showcursor (core, true);
1344 r_cons_flush ();
1345 r_cons_set_raw (false);
1346 r_line_set_prompt (":> ");
1347 r_cons_enable_mouse (false);
1348 if (r_cons_fgets (buf, sizeof (buf), 0, NULL) < 0) {
1349 buf[0] = '\0';
1350 }
1351 r_core_cmdf (core, "\"CC %s\"@0x%08"PFMT64x, buf, addr);
1352 r_core_visual_showcursor (core, false);
1353 r_cons_set_raw (true);
1354 }
1355
follow_ref(RCore * core,RList * xrefs,int choice,int xref)1356 static int follow_ref(RCore *core, RList *xrefs, int choice, int xref) {
1357 RAnalRef *refi = r_list_get_n (xrefs, choice);
1358 if (refi) {
1359 if (core->print->cur_enabled) {
1360 core->print->cur = 0;
1361 }
1362 ut64 addr = refi->addr;
1363 r_io_sundo_push (core->io, core->offset, -1);
1364 r_core_seek (core, addr, true);
1365 return 1;
1366 }
1367 return 0;
1368 }
1369
1370 static const char *help_msg_visual_xref[] = {
1371 "j/k", "select next or previous item (use arrows)",
1372 "J/K", "scroll by 10 refs",
1373 "g/G", "scroll to top / bottom",
1374 "p/P", "rotate between various print modes",
1375 ":", "run r2 command",
1376 "/", "highlight given word",
1377 "?", "show this help message",
1378 "x/<", "show xrefs",
1379 "X/>", "show refs",
1380 "l/Space/Enter", "seek to ref or xref",
1381 "Tab", "toggle between address and function references",
1382 "h/q/Q", "quit xref mode",
1383 NULL
1384 };
1385
r_core_visual_refs(RCore * core,bool xref,bool fcnInsteadOfAddr)1386 R_API int r_core_visual_refs(RCore *core, bool xref, bool fcnInsteadOfAddr) {
1387 ut64 cur_ref_addr = UT64_MAX;
1388 int ret = 0;
1389 char ch;
1390 int count = 0;
1391 RList *xrefs = NULL;
1392 RAnalRef *refi;
1393 RListIter *iter;
1394 int skip = 0;
1395 int idx = 0;
1396 char cstr[32];
1397 ut64 addr = core->offset;
1398 bool xrefsMode = fcnInsteadOfAddr;
1399 int lastPrintMode = 3;
1400 if (core->print->cur_enabled) {
1401 addr += core->print->cur;
1402 }
1403 repeat:
1404 r_list_free (xrefs);
1405 if (xrefsMode) {
1406 RAnalFunction *fun = r_anal_get_fcn_in (core->anal, addr, R_ANAL_FCN_TYPE_NULL);
1407 if (fun) {
1408 if (xref) { // function xrefs
1409 xrefs = r_anal_xrefs_get (core->anal, addr);
1410 //XXX xrefs = r_anal_fcn_get_xrefs (core->anal, fun);
1411 // this function is buggy so we must get the xrefs of the addr
1412 } else { // functon refs
1413 xrefs = r_anal_function_get_refs (fun);
1414 }
1415 } else {
1416 xrefs = NULL;
1417 }
1418 } else {
1419 if (xref) { // address xrefs
1420 xrefs = r_anal_xrefs_get (core->anal, addr);
1421 } else { // address refs
1422 xrefs = r_anal_refs_get (core->anal, addr);
1423 }
1424 }
1425
1426 r_cons_clear00 ();
1427 r_cons_gotoxy (1, 1);
1428 {
1429 char *address = (core->dbg->bits & R_SYS_BITS_64)
1430 ? r_str_newf ("0x%016"PFMT64x, addr)
1431 : r_str_newf ("0x%08"PFMT64x, addr);
1432 r_cons_printf ("[%s%srefs]> %s # (TAB/jk/q/?) ",
1433 xrefsMode? "fcn.": "addr.", xref ? "x": "", address);
1434 free (address);
1435 }
1436 if (!xrefs || r_list_empty (xrefs)) {
1437 r_list_free (xrefs);
1438 xrefs = NULL;
1439 r_cons_printf ("\n\n(no %srefs)\n", xref ? "x": "");
1440 } else {
1441 int h, w = r_cons_get_size (&h);
1442 bool asm_bytes = r_config_get_i (core->config, "asm.bytes");
1443 r_config_set_i (core->config, "asm.bytes", false);
1444 r_core_cmd0 (core, "fd");
1445
1446 int maxcount = 9;
1447 int rows, cols = r_cons_get_size (&rows);
1448 count = 0;
1449 char *dis = NULL;
1450 rows -= 4;
1451 idx = 0;
1452 ut64 curat = UT64_MAX;
1453 r_list_foreach (xrefs, iter, refi) {
1454 if (idx - skip > maxcount) {
1455 r_cons_printf ("...");
1456 break;
1457 }
1458 if (!iter->n && idx < skip) {
1459 skip = idx;
1460 }
1461 if (idx >= skip) {
1462 if (count > maxcount) {
1463 strcpy (cstr, "?");
1464 } else {
1465 snprintf (cstr, sizeof (cstr), "%d", count);
1466 }
1467 if (idx == skip) {
1468 cur_ref_addr = refi->addr;
1469 }
1470 RAnalFunction *fun = r_anal_get_fcn_in (core->anal, refi->addr, R_ANAL_FCN_TYPE_NULL);
1471 char *name;
1472 if (fun) {
1473 name = strdup (fun->name);
1474 } else {
1475 RFlagItem *f = r_flag_get_at (core->flags, refi->addr, true);
1476 if (f) {
1477 name = r_str_newf ("%s + %" PFMT64d, f->name, refi->addr - f->offset);
1478 } else {
1479 name = strdup ("unk");
1480 }
1481 }
1482 if (w > 45) {
1483 if (strlen (name) > w -45) {
1484 name[w - 45] = 0;
1485 }
1486 } else {
1487 name[0] = 0;
1488 }
1489 char *cmt = r_core_cmd_strf (core, "CC.@0x%08"PFMT64x, refi->addr);
1490 r_str_trim (cmt);
1491 r_cons_printf (" %d [%s] 0x%08"PFMT64x" 0x%08"PFMT64x " %s %sref (%s) ; %s\n",
1492 idx, cstr, refi->at, refi->addr,
1493 r_anal_xrefs_type_tostring (refi->type),
1494 xref ? "x":"", name, cmt);
1495 free (cmt);
1496 free (name);
1497 if (idx == skip) {
1498 free (dis);
1499 curat = refi->addr;
1500 char *res = r_core_cmd_strf (core, "pd 4 @ 0x%08"PFMT64x"@e:asm.flags.limit=1", refi->at);
1501 // TODO: show disasm with context. not seek addr
1502 // dis = r_core_cmd_strf (core, "pd $r-4 @ 0x%08"PFMT64x, refi->addr);
1503 dis = NULL;
1504 res = r_str_appendf (res, "; ---------------------------\n");
1505 switch (printMode) {
1506 case 0:
1507 dis = r_core_cmd_strf (core, "pd $r-4 @ 0x%08"PFMT64x, refi->addr);
1508 break;
1509 case 1:
1510 dis = r_core_cmd_strf (core, "pd @ 0x%08"PFMT64x"-32", refi->addr);
1511 break;
1512 case 2:
1513 dis = r_core_cmd_strf (core, "px @ 0x%08"PFMT64x, refi->addr);
1514 break;
1515 case 3:
1516 dis = r_core_cmd_strf (core, "pds @ 0x%08"PFMT64x, refi->addr);
1517 break;
1518 }
1519 if (dis) {
1520 res = r_str_append (res, dis);
1521 free (dis);
1522 }
1523 dis = res;
1524 }
1525 if (++count >= rows) {
1526 r_cons_printf ("...");
1527 break;
1528 }
1529 }
1530 idx++;
1531 }
1532 if (dis) {
1533 if (count < rows) {
1534 r_cons_newline ();
1535 }
1536 int i = count;
1537 for (; i < 9; i++) {
1538 r_cons_newline ();
1539 }
1540 /* prepare highlight */
1541 char *cmd = strdup (r_config_get (core->config, "scr.highlight"));
1542 char *ats = r_str_newf ("%"PFMT64x, curat);
1543 if (ats && !*cmd) {
1544 (void) r_config_set (core->config, "scr.highlight", ats);
1545 }
1546 /* print disasm */
1547 char *d = r_str_ansi_crop (dis, 0, 0, cols, rows - 9);
1548 if (d) {
1549 r_cons_printf ("%s", d);
1550 free (d);
1551 }
1552 /* flush and restore highlight */
1553 r_cons_flush ();
1554 r_config_set (core->config, "scr.highlight", cmd);
1555 free (ats);
1556 free (cmd);
1557 free (dis);
1558 dis = NULL;
1559 }
1560 r_config_set_i (core->config, "asm.bytes", asm_bytes);
1561 }
1562 r_cons_flush ();
1563 r_cons_enable_mouse (r_config_get_i (core->config, "scr.wheel"));
1564 ch = r_cons_readchar ();
1565 ch = r_cons_arrow_to_hjkl (ch);
1566 if (ch == ':') {
1567 r_core_visual_prompt_input (core);
1568 goto repeat;
1569 } else if (ch == '?') {
1570 r_cons_clear00 ();
1571 RStrBuf *rsb = r_strbuf_new ("");
1572 r_core_visual_append_help (rsb, "Xrefs Visual Analysis Mode (Vv + x) Help", help_msg_visual_xref);
1573 ret = r_cons_less_str (r_strbuf_get (rsb), "?");
1574 r_strbuf_free (rsb);
1575 goto repeat;
1576 } else if (ch == 9) { // TAB
1577 xrefsMode = !xrefsMode;
1578 r_core_visual_toggle_decompiler_disasm (core, false, true);
1579 goto repeat;
1580 } else if (ch == 'p') {
1581 r_core_visual_toggle_decompiler_disasm (core, false, true);
1582 printMode++;
1583 if (printMode > lastPrintMode) {
1584 printMode = 0;
1585 }
1586 goto repeat;
1587 } else if (ch == 'P') {
1588 r_core_visual_toggle_decompiler_disasm (core, false, true);
1589 printMode--;
1590 if (printMode < 0) {
1591 printMode = lastPrintMode;
1592 }
1593 goto repeat;
1594 } else if (ch == '/') {
1595 r_core_cmd0 (core, "?i highlight;e scr.highlight=`yp`");
1596 goto repeat;
1597 } else if (ch == 'x' || ch == '<') {
1598 xref = true;
1599 xrefsMode = !xrefsMode;
1600 goto repeat;
1601 } else if (ch == 'X' || ch == '>') {
1602 xref = false;
1603 xrefsMode = !xrefsMode;
1604 goto repeat;
1605 } else if (ch == 'g') {
1606 skip = 0;
1607 goto repeat;
1608 } else if (ch == 'G') {
1609 skip = 9999;
1610 goto repeat;
1611 } else if (ch == ';') {
1612 addComment (core, cur_ref_addr);
1613 goto repeat;
1614 } else if (ch == '.') {
1615 skip = 0;
1616 goto repeat;
1617 } else if (ch == 'j') {
1618 skip++;
1619 goto repeat;
1620 } else if (ch == 'J') {
1621 skip += 10;
1622 goto repeat;
1623 } else if (ch == 'k') {
1624 skip--;
1625 if (skip < 0) {
1626 skip = 0;
1627 }
1628 goto repeat;
1629 } else if (ch == 'K') {
1630 skip = (skip < 10) ? 0: skip - 10;
1631 goto repeat;
1632 } else if (ch == ' ' || ch == '\n' || ch == '\r' || ch == 'l') {
1633 ret = follow_ref (core, xrefs, skip, xref);
1634 } else if (IS_DIGIT (ch)) {
1635 ret = follow_ref (core, xrefs, ch - 0x30, xref);
1636 } else if (ch != 'q' && ch != 'Q' && ch != 'h') {
1637 goto repeat;
1638 }
1639 r_list_free (xrefs);
1640
1641 return ret;
1642 }
1643
1644 #if __WINDOWS__
SetWindow(int Width,int Height)1645 void SetWindow(int Width, int Height) {
1646 COORD coord;
1647 coord.X = Width;
1648 coord.Y = Height;
1649
1650 SMALL_RECT Rect;
1651 Rect.Top = 0;
1652 Rect.Left = 0;
1653 Rect.Bottom = Height - 1;
1654 Rect.Right = Width - 1;
1655
1656 HANDLE Handle = GetStdHandle (STD_OUTPUT_HANDLE);
1657 SetConsoleScreenBufferSize (Handle, coord);
1658 SetConsoleWindowInfo (Handle, TRUE, &Rect);
1659 }
1660 #endif
1661
1662 // unnecesarily public
getcommapath(RCore * core)1663 char *getcommapath(RCore *core) {
1664 char *cwd;
1665 const char *dir = r_config_get (core->config, "dir.projects");
1666 const char *prj = r_config_get (core->config, "prj.name");
1667 if (dir && *dir && prj && *prj) {
1668 char *abspath = r_file_abspath (dir);
1669 /* use prjdir as base directory for comma-ent files */
1670 cwd = r_str_newf ("%s"R_SYS_DIR "%s.d", abspath, prj);
1671 free (abspath);
1672 } else {
1673 /* use cwd as base directory for comma-ent files */
1674 cwd = r_sys_getdir ();
1675 }
1676 return cwd;
1677 }
1678
visual_comma(RCore * core)1679 static void visual_comma(RCore *core) {
1680 bool mouse_state = __holdMouseState (core);
1681 ut64 addr = core->offset + (core->print->cur_enabled? core->print->cur: 0);
1682 char *comment, *cwd, *cmtfile;
1683 const char *prev_cmt = r_meta_get_string (core->anal, R_META_TYPE_COMMENT, addr);
1684 comment = prev_cmt ? strdup (prev_cmt) : NULL;
1685 cmtfile = r_str_between (comment, ",(", ")");
1686 cwd = getcommapath (core);
1687 if (!cmtfile) {
1688 char *fn;
1689 fn = r_cons_input ("<comment-file> ");
1690 if (fn && *fn) {
1691 cmtfile = strdup (fn);
1692 if (!comment || !*comment) {
1693 comment = r_str_newf (",(%s)", fn);
1694 r_meta_set_string (core->anal, R_META_TYPE_COMMENT, addr, comment);
1695 } else {
1696 // append filename in current comment
1697 char *nc = r_str_newf ("%s ,(%s)", comment, fn);
1698 r_meta_set_string (core->anal, R_META_TYPE_COMMENT, addr, nc);
1699 free (nc);
1700 }
1701 }
1702 free (fn);
1703 }
1704 if (cmtfile) {
1705 char *cwf = r_str_newf ("%s"R_SYS_DIR "%s", cwd, cmtfile);
1706 char *odata = r_file_slurp (cwf, NULL);
1707 if (!odata) {
1708 eprintf ("Could not open '%s'.\n", cwf);
1709 free (cwf);
1710 goto beach;
1711 }
1712 char *data = r_core_editor (core, NULL, odata);
1713 r_file_dump (cwf, (const ut8 *) data, -1, 0);
1714 free (data);
1715 free (odata);
1716 free (cwf);
1717 } else {
1718 eprintf ("No commafile found.\n");
1719 }
1720 beach:
1721 free (comment);
1722 r_cons_enable_mouse (mouse_state && r_config_get_i (core->config, "scr.wheel"));
1723 }
1724
isDisasmPrint(int mode)1725 static bool isDisasmPrint(int mode) {
1726 return (mode == R_CORE_VISUAL_MODE_PD || mode == R_CORE_VISUAL_MODE_DB);
1727 }
1728
cursor_ocur(RCore * core,bool use_ocur)1729 static void cursor_ocur(RCore *core, bool use_ocur) {
1730 RPrint *p = core->print;
1731 if (use_ocur && p->ocur == -1) {
1732 p->ocur = p->cur;
1733 } else if (!use_ocur) {
1734 p->ocur = -1;
1735 }
1736 }
1737
nextOpcode(RCore * core)1738 static void nextOpcode(RCore *core) {
1739 RAnalOp *aop = r_core_anal_op (core, core->offset + core->print->cur, R_ANAL_OP_MASK_BASIC);
1740 RPrint *p = core->print;
1741 if (aop) {
1742 p->cur += aop->size;
1743 r_anal_op_free (aop);
1744 } else {
1745 p->cur += 4;
1746 }
1747 }
1748
prevOpcode(RCore * core)1749 static void prevOpcode(RCore *core) {
1750 RPrint *p = core->print;
1751 ut64 addr, oaddr = core->offset + core->print->cur;
1752 if (r_core_prevop_addr (core, oaddr, 1, &addr)) {
1753 const int delta = oaddr - addr;
1754 p->cur -= delta;
1755 } else {
1756 p->cur -= 4;
1757 }
1758 }
1759
cursor_nextrow(RCore * core,bool use_ocur)1760 static void cursor_nextrow(RCore *core, bool use_ocur) {
1761 RPrint *p = core->print;
1762 ut32 roff, next_roff;
1763 int row, sz, delta;
1764 RAsmOp op;
1765
1766 cursor_ocur (core, use_ocur);
1767 if (PIDX == 1) { // DISASM
1768 nextOpcode (core);
1769 return;
1770 }
1771
1772 if (PIDX == 7 || !strcmp ("prc", r_config_get (core->config, "cmd.visual"))) {
1773 p->cur += r_config_get_i (core->config, "hex.cols");
1774 return;
1775 }
1776 if (splitView) {
1777 int w = r_config_get_i (core->config, "hex.cols");
1778 if (w < 1) {
1779 w = 16;
1780 }
1781 if (core->seltab == 0) {
1782 splitPtr += w;
1783 } else {
1784 core->offset += w;
1785 }
1786 return;
1787 }
1788 if (PIDX == R_CORE_VISUAL_MODE_DB) {
1789 const int cols = core->dbg->regcols;
1790 int w = r_config_get_i (core->config, "hex.cols");
1791 switch (core->seltab) {
1792 case 0:
1793 if (w < 1) {
1794 w = 16;
1795 }
1796 r_config_set_i (core->config, "stack.delta",
1797 r_config_get_i (core->config, "stack.delta") - w);
1798 return;
1799 case 1:
1800 p->cur += cols > 0? cols: 3;
1801 return;
1802 default:
1803 nextOpcode (core);
1804 return;
1805 }
1806 }
1807 if (p->row_offsets) {
1808 // FIXME: cache the current row
1809 row = r_print_row_at_off (p, p->cur);
1810 roff = r_print_rowoff (p, row);
1811 if (roff == -1) {
1812 p->cur++;
1813 return;
1814 }
1815 next_roff = r_print_rowoff (p, row + 1);
1816 if (next_roff == UT32_MAX) {
1817 p->cur++;
1818 return;
1819 }
1820 if (next_roff > core->blocksize) {
1821 p->cur += 32; // XXX workaround to "fix" cursor nextrow far away scrolling issue
1822 return;
1823 }
1824 if (next_roff + 32 < core->blocksize) {
1825 sz = r_asm_disassemble (core->rasm, &op,
1826 core->block + next_roff, 32);
1827 if (sz < 1) {
1828 sz = 1;
1829 }
1830 } else {
1831 sz = 1;
1832 }
1833 delta = p->cur - roff;
1834 p->cur = next_roff + R_MIN (delta, sz - 1);
1835 } else {
1836 p->cur += R_MAX (1, p->cols);
1837 }
1838 }
1839
cursor_prevrow(RCore * core,bool use_ocur)1840 static void cursor_prevrow(RCore *core, bool use_ocur) {
1841 RPrint *p = core->print;
1842 ut32 roff, prev_roff;
1843 int row;
1844
1845 cursor_ocur (core, use_ocur);
1846 if (PIDX == 1) { // DISASM
1847 prevOpcode (core);
1848 return;
1849 }
1850
1851 if (PIDX == 7 || !strcmp ("prc", r_config_get (core->config, "cmd.visual"))) {
1852 int cols = r_config_get_i (core->config, "hex.cols");
1853 p->cur -= R_MAX (cols, 0);
1854 return;
1855 }
1856
1857 if (splitView) {
1858 int w = r_config_get_i (core->config, "hex.cols");
1859 if (w < 1) {
1860 w = 16;
1861 }
1862 if (core->seltab == 0) {
1863 splitPtr -= w;
1864 } else {
1865 core->offset -= w;
1866 }
1867 return;
1868 }
1869 if (PIDX == R_CORE_VISUAL_MODE_DB) {
1870 switch (core->seltab) {
1871 case 0:
1872 {
1873 int w = r_config_get_i (core->config, "hex.cols");
1874 if (w < 1) {
1875 w = 16;
1876 }
1877 r_config_set_i (core->config, "stack.delta",
1878 r_config_get_i (core->config, "stack.delta") + w);
1879 }
1880 return;
1881 case 1:
1882 {
1883 const int cols = core->dbg->regcols;
1884 p->cur -= cols > 0? cols: 4;
1885 return;
1886 }
1887 default:
1888 prevOpcode (core);
1889 return;
1890 }
1891 }
1892 if (p->row_offsets) {
1893 int delta, prev_sz;
1894
1895 // FIXME: cache the current row
1896 row = r_print_row_at_off (p, p->cur);
1897 roff = r_print_rowoff (p, row);
1898 if (roff == UT32_MAX) {
1899 p->cur--;
1900 return;
1901 }
1902 prev_roff = row > 0? r_print_rowoff (p, row - 1): UT32_MAX;
1903 delta = p->cur - roff;
1904 if (prev_roff == UT32_MAX) {
1905 ut64 prev_addr = prevop_addr (core, core->offset + roff);
1906 if (prev_addr > core->offset) {
1907 prev_roff = 0;
1908 prev_sz = 1;
1909 } else {
1910 RAsmOp op;
1911 prev_roff = 0;
1912 r_core_seek (core, prev_addr, true);
1913 prev_sz = r_asm_disassemble (core->rasm, &op,
1914 core->block, 32);
1915 }
1916 } else {
1917 prev_sz = roff - prev_roff;
1918 }
1919 int res = R_MIN (delta, prev_sz - 1);
1920 ut64 cur = prev_roff + res;
1921 if (cur == p->cur) {
1922 if (p->cur > 0) {
1923 p->cur--;
1924 }
1925 } else {
1926 p->cur = prev_roff + delta; //res;
1927 }
1928 } else {
1929 p->cur -= p->cols;
1930 }
1931 }
1932
cursor_left(RCore * core,bool use_ocur)1933 static void cursor_left(RCore *core, bool use_ocur) {
1934 if (PIDX == 2) {
1935 if (core->seltab == 1) {
1936 core->print->cur--;
1937 return;
1938 }
1939 }
1940 cursor_ocur (core, use_ocur);
1941 core->print->cur--;
1942 }
1943
cursor_right(RCore * core,bool use_ocur)1944 static void cursor_right(RCore *core, bool use_ocur) {
1945 if (PIDX == 2) {
1946 if (core->seltab == 1) {
1947 core->print->cur++;
1948 return;
1949 }
1950 }
1951 cursor_ocur (core, use_ocur);
1952 core->print->cur++;
1953 }
1954
fix_cursor(RCore * core)1955 static bool fix_cursor(RCore *core) {
1956 RPrint *p = core->print;
1957 int offscreen = (core->cons->rows - 3) * p->cols;
1958 bool res = false;
1959
1960 if (!core->print->cur_enabled) {
1961 return false;
1962 }
1963 if (core->print->screen_bounds > 1) {
1964 bool off_is_visible = core->offset < core->print->screen_bounds;
1965 bool cur_is_visible = core->offset + p->cur < core->print->screen_bounds;
1966 bool is_close = core->offset + p->cur < core->print->screen_bounds + 32;
1967
1968 if ((!cur_is_visible && !is_close) || (!cur_is_visible && p->cur == 0)) {
1969 // when the cursor is not visible and it's far from the
1970 // last visible byte, just seek there.
1971 r_core_seek_delta (core, p->cur);
1972 reset_print_cur (p);
1973 } else if ((!cur_is_visible && is_close) || !off_is_visible) {
1974 RAsmOp op;
1975 int sz = r_asm_disassemble (core->rasm,
1976 &op, core->block, 32);
1977 if (sz < 1) {
1978 sz = 1;
1979 }
1980 r_core_seek_delta (core, sz);
1981 p->cur = R_MAX (p->cur - sz, 0);
1982 if (p->ocur != -1) {
1983 p->ocur = R_MAX (p->ocur - sz, 0);
1984 }
1985 res |= off_is_visible;
1986 }
1987 } else if (core->print->cur >= offscreen) {
1988 r_core_seek (core, core->offset + p->cols, true);
1989 p->cur -= p->cols;
1990 if (p->ocur != -1) {
1991 p->ocur -= p->cols;
1992 }
1993 }
1994
1995 if (p->cur < 0) {
1996 int sz = p->cols;
1997 if (isDisasmPrint (core->printidx)) {
1998 sz = r_core_visual_prevopsz (core, core->offset + p->cur);
1999 if (sz < 1) {
2000 sz = 1;
2001 }
2002 }
2003 r_core_seek_delta (core, -sz);
2004 p->cur += sz;
2005 if (p->ocur != -1) {
2006 p->ocur += sz;
2007 }
2008 }
2009 return res;
2010 }
2011
2012 static bool __ime = false;
2013 static int __nib = -1;
2014
insert_mode_enabled(RCore * core)2015 static bool insert_mode_enabled(RCore *core) {
2016 if (!__ime) {
2017 return false;
2018 }
2019 char ch = (ut8)r_cons_readchar ();
2020 if ((ut8)ch == KEY_ALTQ) {
2021 (void)r_cons_readchar ();
2022 __ime = false;
2023 return true;
2024 }
2025 char arrows = r_cons_arrow_to_hjkl (ch);
2026 switch (ch) {
2027 case 127:
2028 core->print->cur = R_MAX (0, core->print->cur - 1);
2029 return true;
2030 case 9: // tab "tab" TAB
2031 core->print->col = core->print->col == 1? 2: 1;
2032 break;
2033 }
2034 if (ch != 'h' && arrows == 'h') {
2035 core->print->cur = R_MAX (0, core->print->cur - 1);
2036 return true;
2037 } else if (ch != 'l' && arrows == 'l') {
2038 core->print->cur = core->print->cur + 1;
2039 return true;
2040 } else if (ch != 'j' && arrows == 'j') {
2041 cursor_nextrow (core, false);
2042 return true;
2043 } else if (ch != 'k' && arrows == 'k') {
2044 cursor_prevrow (core, false);
2045 return true;
2046 }
2047 if (core->print->col == 2) {
2048 /* ascii column */
2049 if (IS_PRINTABLE (ch)) {
2050 r_core_cmdf (core, "\"w %c\" @ $$+%d", ch, core->print->cur);
2051 core->print->cur++;
2052 }
2053 return true;
2054 }
2055 ch = arrows;
2056 /* hex column */
2057 switch (ch) {
2058 case '0':
2059 case '1':
2060 case '2':
2061 case '3':
2062 case '4':
2063 case '5':
2064 case '6':
2065 case '7':
2066 case '8':
2067 case '9':
2068 case 'a':
2069 case 'b':
2070 case 'c':
2071 case 'd':
2072 case 'e':
2073 case 'f':
2074 if (__nib != -1) {
2075 r_core_cmdf (core, "wx %c%c @ $$+%d", __nib, ch, core->print->cur);
2076 core->print->cur++;
2077 __nib = -1;
2078 } else {
2079 r_core_cmdf (core, "wx %c. @ $$+%d", ch, core->print->cur);
2080 __nib = ch;
2081 }
2082 break;
2083 case 'r':
2084 r_core_cmdf (core, "r-1 @ 0x%08"PFMT64x, core->offset + core->print->cur);
2085 break;
2086 case 'R':
2087 r_core_cmdf (core, "r+1 @ 0x%08"PFMT64x, core->offset + core->print->cur);
2088 break;
2089 case 'h':
2090 core->print->cur = R_MAX (0, core->print->cur - 1);
2091 break;
2092 case 'l':
2093 core->print->cur = core->print->cur + 1;
2094 break;
2095 case 'j':
2096 cursor_nextrow (core, false);
2097 break;
2098 case 'k':
2099 cursor_prevrow (core, false);
2100 break;
2101 case 'Q':
2102 case 'q':
2103 __ime = false;
2104 break;
2105 case '?':
2106 r_cons_less_str ("\nVisual Insert Mode:\n\n"
2107 " tab - toggle between ascii and hex columns\n"
2108 " q (or alt-q) - quit insert mode\n"
2109 "\nHex column:\n"
2110 " r - remove byte in cursor\n"
2111 " R - insert byte in cursor\n"
2112 " [0-9a-f] - insert hexpairs in hex column\n"
2113 " hjkl - move around\n"
2114 "\nAscii column:\n"
2115 " arrows - move around\n"
2116 " alt-q - quit insert mode\n"
2117 , "?");
2118 break;
2119 }
2120 return true;
2121 }
2122
r_core_visual_browse(RCore * core,const char * input)2123 R_API void r_core_visual_browse(RCore *core, const char *input) {
2124 const char *browsemsg = \
2125 "Browse stuff:\n"
2126 "-------------\n"
2127 " _ hud mode (V_)\n"
2128 " 1 bit editor (vd1)\n"
2129 " b blocks\n"
2130 " a anal classes\n"
2131 " c classes\n"
2132 " C comments\n"
2133 " d debug traces\n"
2134 " e eval var configurations\n"
2135 " E esil debugger mode\n"
2136 " f flags\n"
2137 " F functions\n"
2138 " g graph\n"
2139 " h history\n"
2140 " i imports\n"
2141 " l chat logs (previously VT)\n"
2142 " m maps\n"
2143 " M mountpoints\n"
2144 " p pids/threads\n"
2145 " q quit\n"
2146 " r ROP gadgets\n"
2147 " s symbols\n"
2148 " t types\n"
2149 " T themes\n"
2150 " v vars\n"
2151 " x xrefs\n"
2152 " X refs\n"
2153 " z browse function zignatures\n"
2154 " : run command\n"
2155 ;
2156 for (;;) {
2157 r_cons_clear00 ();
2158 r_cons_printf ("%s\n", browsemsg);
2159 r_cons_flush ();
2160 char ch = 0;
2161 if (input && *input) {
2162 ch = *input;
2163 input++;
2164 } else {
2165 ch = r_cons_readchar ();
2166 }
2167 ch = r_cons_arrow_to_hjkl (ch);
2168 switch (ch) {
2169 case '1':
2170 r_core_visual_bit_editor (core);
2171 break;
2172 case 'M':
2173 if (!r_list_empty (core->fs->roots)) {
2174 r_core_visual_mounts (core);
2175 }
2176 break;
2177 case 'z': // "vbz"
2178 if (r_core_visual_view_zigns (core)) {
2179 return;
2180 }
2181 break;
2182 case 'g': // "vbg"
2183 if (r_core_visual_view_graph (core)) {
2184 return;
2185 }
2186 break;
2187 case 'r': // "vbr"
2188 r_core_visual_view_rop (core);
2189 break;
2190 case 'f': // "vbf"
2191 r_core_visual_trackflags (core);
2192 break;
2193 case 'F': // "vbF"
2194 r_core_visual_anal (core, NULL);
2195 // r_core_cmd0 (core, "s $(afl~...)");
2196 break;
2197 case 'd': // "vbd"
2198 r_core_visual_debugtraces (core, NULL);
2199 break;
2200 case 'v': // "vbv"
2201 r_core_visual_anal (core, "v");
2202 break;
2203 case 'e': // "vbe"
2204 r_core_visual_config (core);
2205 break;
2206 case 'E': // "vbe"
2207 r_core_visual_esil (core);
2208 break;
2209 case 'c': // "vbc"
2210 r_core_visual_classes (core);
2211 break;
2212 case 'a': // "vba"
2213 r_core_visual_anal_classes (core);
2214 break;
2215 case 'C': // "vbC"
2216 r_core_visual_comments (core);
2217 //r_core_cmd0 (core, "s $(CC~...)");
2218 break;
2219 case 't': // "vbt"
2220 r_core_visual_types (core);
2221 break;
2222 case 'T': // "vbT"
2223 r_core_cmd0 (core, "eco $(eco~...)");
2224 break;
2225 case 'l': // previously VT
2226 if (r_sandbox_enable (0)) {
2227 eprintf ("sandbox not enabled\n");
2228 } else {
2229 if (r_cons_is_interactive ()) {
2230 r_core_cmd0 (core, "TT");
2231 }
2232 }
2233 break;
2234 case 'p':
2235 r_core_cmd0 (core, "dpt=$(dpt~[1-])");
2236 break;
2237 case 'b':
2238 r_core_cmd0 (core, "s $(afb~...)");
2239 break;
2240 case 'i':
2241 // XXX ii shows index first and iiq shows no offset :(
2242 r_core_cmd0 (core, "s $(ii~...)");
2243 break;
2244 case 's':
2245 r_core_cmd0 (core, "s $(isq~...)");
2246 break;
2247 case 'm':
2248 r_core_cmd0 (core, "s $(dm~...)");
2249 break;
2250 case 'x':
2251 r_core_visual_refs (core, true, true);
2252 break;
2253 case 'X':
2254 r_core_visual_refs (core, false, true);
2255 break;
2256 case 'h': // seek history
2257 r_core_cmdf (core, "s!~...");
2258 break;
2259 case '_':
2260 r_core_visual_hudstuff (core);
2261 break;
2262 case ':':
2263 r_core_visual_prompt_input (core);
2264 break;
2265 case 127: // backspace
2266 case 'q':
2267 return;
2268 }
2269 }
2270 }
2271
2272 #include "visual_tabs.inc"
2273
isNumber(RCore * core,int ch)2274 static bool isNumber(RCore *core, int ch) {
2275 if (ch > '0' && ch <= '9') {
2276 return true;
2277 }
2278 if (core->print->cur_enabled) {
2279 return ch == '0';
2280 }
2281 return false;
2282 }
2283
2284 static char numbuf[32] = {0};
2285 static int numbuf_i = 0;
2286
numbuf_append(int ch)2287 static void numbuf_append(int ch) {
2288 if (numbuf_i >= sizeof (numbuf) - 1) {
2289 numbuf_i = 0;
2290 }
2291 numbuf[numbuf_i++] = ch;
2292 numbuf[numbuf_i] = 0;
2293 }
2294
numbuf_pull(void)2295 static int numbuf_pull(void) {
2296 int distance = 1;
2297 if (numbuf_i) {
2298 numbuf[numbuf_i] = 0;
2299 distance = atoi (numbuf);
2300 if (!distance) {
2301 distance = 1;
2302 }
2303 numbuf_i = 0;
2304 }
2305 return distance;
2306 }
2307
canWrite(RCore * core,ut64 addr)2308 static bool canWrite(RCore *core, ut64 addr) {
2309 if (r_config_get_i (core->config, "io.cache")) {
2310 return true;
2311 }
2312 RIOMap *map = r_io_map_get (core->io, addr);
2313 return (map && (map->perm & R_PERM_W));
2314 }
2315
toggle_bb(RCore * core,ut64 addr)2316 static bool toggle_bb(RCore *core, ut64 addr) {
2317 RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, addr, R_ANAL_FCN_TYPE_NULL);
2318 if (fcn) {
2319 RAnalBlock *bb = r_anal_fcn_bbget_in (core->anal, fcn, addr);
2320 if (bb) {
2321 bb->folded = !bb->folded;
2322 } else {
2323 r_warn_if_reached ();
2324 }
2325 return true;
2326 }
2327 return false;
2328 }
2329
process_get_click(RCore * core,int ch)2330 static int process_get_click(RCore *core, int ch) {
2331 int x, y;
2332 if (r_cons_get_click (&x, &y)) {
2333 if (y == 1) {
2334 if (x < 13) {
2335 ch = '_';
2336 } else if (x < 20) {
2337 ch = 'p';
2338 } else if (x < 24) {
2339 ch = 9;
2340 }
2341 } else if (y == 2) {
2342 if (x < 2) {
2343 visual_closetab (core);
2344 } else if (x < 5) {
2345 visual_newtab (core);
2346 } else {
2347 visual_nexttab (core);
2348 }
2349 return 0;
2350 } else {
2351 ch = 0; //'c';
2352 }
2353 }
2354 return ch;
2355 }
2356
r_core_visual_cmd(RCore * core,const char * arg)2357 R_API int r_core_visual_cmd(RCore *core, const char *arg) {
2358 ut8 och = arg[0];
2359 RAsmOp op;
2360 ut64 offset = core->offset;
2361 char buf[4096];
2362 const char *key_s;
2363 int i, cols = core->print->cols;
2364 int wheelspeed;
2365 int ch = och;
2366 if ((ut8)ch == KEY_ALTQ) {
2367 r_cons_readchar ();
2368 ch = 'q';
2369 }
2370 ch = r_cons_arrow_to_hjkl (ch);
2371 ch = visual_nkey (core, ch);
2372 if (ch < 2) {
2373 ch = process_get_click (core, ch);
2374 if (!ch) {
2375 return 1;
2376 }
2377 }
2378 if (r_cons_singleton ()->mouse_event) {
2379 wheelspeed = r_config_get_i (core->config, "scr.wheel.speed");
2380 } else {
2381 wheelspeed = 1;
2382 }
2383
2384 if (ch == 'l' && och == 6) {
2385 ch = 'J';
2386 } else if (ch == 'h' && och == 2) {
2387 ch = 'K';
2388 }
2389
2390 // do we need hotkeys for data references? not only calls?
2391 // '0' is handled to seek at the beginning of the function
2392 // unless the cursor is set, then, the 0 is captured here
2393 if (isNumber (core, ch)) {
2394 // only in disasm and debug prints..
2395 if (isDisasmPrint (core->printidx)) {
2396 if (r_config_get_i (core->config, "asm.hints") && (r_config_get_i (core->config, "asm.hint.jmp")
2397 || r_config_get_i (core->config, "asm.hint.lea") || r_config_get_i (core->config, "asm.hint.emu")
2398 || r_config_get_i (core->config, "asm.hint.call"))) {
2399 r_core_visual_jump (core, ch);
2400 } else {
2401 numbuf_append (ch);
2402 }
2403 } else {
2404 numbuf_append (ch);
2405 }
2406 } else {
2407 switch (ch) {
2408 #if __WINDOWS__
2409 case 0xf5:
2410 SetWindow (81, 25);
2411 break;
2412 case 0xcf5:
2413 SetWindow (81, 40);
2414 break;
2415 #endif
2416 case 0x0d: // "enter" "\\n" "newline"
2417 if (r_config_get_i (core->config, "scr.cursor")) {
2418 r_cons_set_click (core->cons->cpos.x, core->cons->cpos.y);
2419 char buf[10];
2420 int ch = process_get_click (core, 0);
2421 buf[0] = ch;
2422 buf[1] = 0;
2423 r_core_visual_cmd(core, buf);
2424 } else {
2425 RAnalOp *op;
2426 int wheel = r_config_get_i (core->config, "scr.wheel");
2427 if (wheel) {
2428 r_cons_enable_mouse (true);
2429 }
2430 do {
2431 op = r_core_anal_op (core, core->offset + core->print->cur, R_ANAL_OP_MASK_BASIC);
2432 if (op) {
2433 if (op->type == R_ANAL_OP_TYPE_JMP ||
2434 op->type == R_ANAL_OP_TYPE_CJMP ||
2435 op->type == R_ANAL_OP_TYPE_CALL ||
2436 op->type == R_ANAL_OP_TYPE_CCALL) {
2437 if (core->print->cur_enabled) {
2438 int delta = R_ABS ((st64) op->jump - (st64) offset);
2439 if (op->jump < core->offset || op->jump >= core->print->screen_bounds) {
2440 r_io_sundo_push (core->io, offset, r_print_get_cursor (core->print));
2441 r_core_visual_seek_animation (core, op->jump);
2442 core->print->cur = 0;
2443 } else {
2444 r_io_sundo_push (core->io, offset, r_print_get_cursor (core->print));
2445 core->print->cur = delta;
2446 }
2447 } else {
2448 r_io_sundo_push (core->io, offset, 0);
2449 r_core_visual_seek_animation (core, op->jump);
2450 }
2451 }
2452 }
2453 r_anal_op_free (op);
2454 } while (--wheelspeed > 0);
2455 }
2456 break;
2457 case 'o': // tab TAB
2458 nextPrintFormat (core);
2459 break;
2460 case 'O': // tab TAB
2461 case 9: // tab TAB
2462 r_core_visual_toggle_decompiler_disasm (core, false, true);
2463 if (splitView) {
2464 // this split view is kind of useless imho, we should kill it or merge it into tabs
2465 core->print->cur = 0;
2466 core->curtab = 0;
2467 core->seltab++;
2468 if (core->seltab > 1) {
2469 core->seltab = 0;
2470 }
2471 } else {
2472 if (core->print->cur_enabled) {
2473 core->curtab = 0;
2474 if (core->printidx == R_CORE_VISUAL_MODE_DB) {
2475 core->print->cur = 0;
2476 core->seltab++;
2477 if (core->seltab > 2) {
2478 core->seltab = 0;
2479 }
2480 } else {
2481 core->seltab = 0;
2482 ut64 f = r_config_get_i (core->config, "diff.from");
2483 ut64 t = r_config_get_i (core->config, "diff.to");
2484 if (f == t && f == 0) {
2485 core->print->col = core->print->col == 1? 2: 1;
2486 }
2487 }
2488 } else {
2489 prevPrintFormat (core);
2490 }
2491 }
2492 break;
2493 case '&':
2494 rotateAsmBits (core);
2495 break;
2496 case 'a':
2497 {
2498 {
2499 ut64 addr = core->offset;
2500 if (PIDX == 2) {
2501 if (core->seltab == 0) {
2502 addr = r_debug_reg_get (core->dbg, "SP");
2503 }
2504 }
2505 if (!canWrite (core, addr)) {
2506 r_cons_printf ("\nFile has been opened in read-only mode. Use -w flag, oo+ or e io.cache=true\n");
2507 r_cons_any_key (NULL);
2508 return true;
2509 }
2510 }
2511 r_cons_printf ("Enter assembler opcodes separated with ';':\n");
2512 r_core_visual_showcursor (core, true);
2513 r_cons_flush ();
2514 r_cons_set_raw (false);
2515 strcpy (buf, "\"wa ");
2516 r_line_set_prompt (":> ");
2517 r_cons_enable_mouse (false);
2518 if (r_cons_fgets (buf + 4, sizeof (buf) - 4, 0, NULL) < 0) {
2519 buf[0] = '\0';
2520 }
2521 strcat (buf, "\"");
2522 int wheel = r_config_get_i (core->config, "scr.wheel");
2523 if (wheel) {
2524 r_cons_enable_mouse (true);
2525 }
2526 if (*buf) {
2527 if (core->print->cur_enabled) {
2528 int t = core->offset + core->print->cur;
2529 r_core_seek (core, t, false);
2530 }
2531 r_core_cmd (core, buf, true);
2532 if (core->print->cur_enabled) {
2533 int t = core->offset - core->print->cur;
2534 r_core_seek (core, t, true);
2535 }
2536 }
2537 r_core_visual_showcursor (core, false);
2538 r_cons_set_raw (true);
2539 }
2540 break;
2541 case '=':
2542 { // TODO: edit
2543 r_core_visual_showcursor (core, true);
2544 const char *buf = NULL;
2545 #define I core->cons
2546 const char *cmd = r_config_get (core->config, "cmd.vprompt");
2547 r_line_set_prompt ("cmd.vprompt> ");
2548 I->line->contents = strdup (cmd);
2549 buf = r_line_readline ();
2550 I->line->contents = NULL;
2551 (void)r_config_set (core->config, "cmd.vprompt", buf);
2552 r_core_visual_showcursor (core, false);
2553 }
2554 break;
2555 case '|':
2556 { // TODO: edit
2557 r_core_visual_showcursor (core, true);
2558 const char *buf = NULL;
2559 #define I core->cons
2560 const char *cmd = r_config_get (core->config, "cmd.cprompt");
2561 r_line_set_prompt ("cmd.cprompt> ");
2562 I->line->contents = strdup (cmd);
2563 buf = r_line_readline ();
2564 if (buf && !strcmp (buf, "|")) {
2565 R_FREE (I->line->contents);
2566 core->print->cur_enabled = true;
2567 core->print->cur = 0;
2568 (void)r_config_set (core->config, "cmd.cprompt", "p=e $r-2");
2569 } else {
2570 R_FREE (I->line->contents);
2571 (void)r_config_set (core->config, "cmd.cprompt", r_str_get (buf));
2572 }
2573 r_core_visual_showcursor (core, false);
2574 }
2575 break;
2576 case '!':
2577 r_core_panels_root (core, core->panels_root);
2578 break;
2579 case 'g':
2580 r_core_visual_showcursor (core, true);
2581 r_core_visual_offset (core);
2582 r_core_visual_showcursor (core, false);
2583 break;
2584 case 'G':
2585 __core_visual_gogo (core, 'G');
2586 break;
2587 case 'A':
2588 {
2589 const int oce = core->print->cur_enabled;
2590 const int oco = core->print->ocur;
2591 const int occ = core->print->cur;
2592 ut64 off = oce? core->offset + core->print->cur: core->offset;
2593 core->print->cur_enabled = 0;
2594 r_cons_enable_mouse (false);
2595 r_core_visual_asm (core, off);
2596 core->print->cur_enabled = oce;
2597 core->print->cur = occ;
2598 core->print->ocur = oco;
2599 if (r_config_get_i (core->config, "scr.wheel")) {
2600 r_cons_enable_mouse (true);
2601 }
2602 }
2603 break;
2604 case '\\':
2605 if (splitPtr == UT64_MAX) {
2606 splitPtr = core->offset;
2607 }
2608 splitView = !splitView;
2609 setcursor (core, splitView);
2610 break;
2611 case 'c':
2612 setcursor (core, !core->print->cur_enabled);
2613 break;
2614 case '$':
2615 if (core->print->cur_enabled) {
2616 r_core_cmdf (core, "dr PC=$$+%d", core->print->cur);
2617 } else {
2618 r_core_cmd0 (core, "dr PC=$$");
2619 }
2620 break;
2621 case '@':
2622 if (core->print->cur_enabled) {
2623 char buf[128];
2624 prompt_read ("cursor at:", buf, sizeof (buf));
2625 core->print->cur = (st64) r_num_math (core->num, buf);
2626 }
2627 break;
2628 case 'C':
2629 if (++color > 2) {
2630 color = 0;
2631 }
2632 r_config_set_i (core->config, "scr.color", color);
2633 break;
2634 case 'd': {
2635 bool mouse_state = __holdMouseState (core);
2636 r_core_visual_showcursor (core, true);
2637 int distance = numbuf_pull ();
2638 r_core_visual_define (core, arg + 1, distance - 1);
2639 r_core_visual_showcursor (core, false);
2640 r_cons_enable_mouse (mouse_state && r_config_get_i(core->config, "scr.wheel"));
2641 }
2642 break;
2643 case 'D':
2644 setdiff (core);
2645 break;
2646 case 'f':
2647 {
2648 bool mouse_state = __holdMouseState (core);
2649 int range, min, max;
2650 char name[256], *n;
2651 r_line_set_prompt ("flag name: ");
2652 r_core_visual_showcursor (core, true);
2653 if (r_cons_fgets (name, sizeof (name), 0, NULL) >= 0 && *name) {
2654 n = name;
2655 r_str_trim (n);
2656 if (core->print->ocur != -1) {
2657 min = R_MIN (core->print->cur, core->print->ocur);
2658 max = R_MAX (core->print->cur, core->print->ocur);
2659 } else {
2660 min = max = core->print->cur;
2661 }
2662 range = max - min + 1;
2663 if (!strcmp (n, "-")) {
2664 r_flag_unset_off (core->flags, core->offset + core->print->cur);
2665 } else if (*n == '.') {
2666 if (n[1] == '-') {
2667 //unset
2668 r_core_cmdf (core, "f.-%s@0x%"PFMT64x, n + 1, core->offset + min);
2669 } else {
2670 r_core_cmdf (core, "f.%s@0x%"PFMT64x, n + 1, core->offset + min);
2671 }
2672 } else if (*n == '-') {
2673 if (*n) {
2674 r_flag_unset_name (core->flags, n + 1);
2675 }
2676 } else {
2677 if (range < 1) {
2678 range = 1;
2679 }
2680 if (*n) {
2681 r_flag_set (core->flags, n,
2682 core->offset + min, range);
2683 }
2684 }
2685 }
2686 r_cons_enable_mouse (mouse_state && r_config_get_i(core->config, "scr.wheel"));
2687 }
2688 r_core_visual_showcursor (core, false);
2689 break;
2690 case ',':
2691 visual_comma (core);
2692 break;
2693 case 't':
2694 {
2695 r_cons_gotoxy (0, 0);
2696 if (core->visual.tabs) {
2697 r_cons_printf ("[tnp:=+-] ");
2698 } else {
2699 r_cons_printf ("[t] ");
2700 }
2701 r_cons_flush();
2702 int ch = r_cons_readchar ();
2703 if (isdigit (ch)) {
2704 visual_nthtab (core, ch - '0' - 1);
2705 }
2706 switch (ch) {
2707 case 'h':
2708 case 'k':
2709 case 'p':
2710 visual_prevtab (core);
2711 break;
2712 case 9: // t-TAB
2713 case 'l':
2714 case 'j':
2715 case 'n':
2716 visual_nexttab (core);
2717 break;
2718 case '=':
2719 visual_tabname (core);
2720 break;
2721 case '-':
2722 visual_closetab (core);
2723 break;
2724 case ':':
2725 {
2726 RCoreVisualTab *tab = visual_newtab (core);
2727 if (tab) {
2728 tab->name[0] = ':';
2729 r_cons_fgets (tab->name + 1, sizeof (tab->name) - 1, 0, NULL);
2730 }
2731 }
2732 break;
2733 case '+':
2734 case 't':
2735 case 'a':
2736 visual_newtab (core);
2737 break;
2738 }
2739 }
2740 break;
2741 case 'T':
2742 visual_closetab (core);
2743 break;
2744 case 'n':
2745 r_core_seek_next (core, r_config_get (core->config, "scr.nkey"));
2746 break;
2747 case 'N':
2748 r_core_seek_previous (core, r_config_get (core->config, "scr.nkey"));
2749 break;
2750 case 'i':
2751 case 'I':
2752 {
2753 ut64 oaddr = core->offset;
2754 int delta = (core->print->ocur != -1)? R_MIN (core->print->cur, core->print->ocur): core->print->cur;
2755 ut64 addr = core->offset + delta;
2756 if (PIDX == 0) {
2757 if (strstr (printfmtSingle[0], "pxb")) {
2758 r_core_visual_define (core, "1", 1);
2759 return true;
2760 }
2761 if (core->print->ocur == -1) {
2762 __ime = true;
2763 core->print->cur_enabled = true;
2764 return true;
2765 }
2766 } else if (PIDX == 2) {
2767 if (core->seltab == 0) {
2768 addr = r_debug_reg_get (core->dbg, "SP") + delta;
2769 } else if (core->seltab == 1) {
2770 char buf[128];
2771 prompt_read ("new-reg-value> ", buf, sizeof (buf));
2772 if (*buf) {
2773 const char *creg = core->dbg->creg;
2774 if (creg) {
2775 r_core_cmdf (core, "dr %s = %s\n", creg, buf);
2776 }
2777 }
2778 return true;
2779 }
2780 }
2781 if (!canWrite (core, addr)) {
2782 r_cons_printf ("\nFile has been opened in read-only mode. Use -w flag, oo+ or e io.cache=true\n");
2783 r_cons_any_key (NULL);
2784 return true;
2785 }
2786 r_core_visual_showcursor (core, true);
2787 r_cons_flush ();
2788 r_cons_set_raw (0);
2789 if (ch == 'I') {
2790 strcpy (buf, "wow ");
2791 r_line_set_prompt ("insert hexpair block: ");
2792 if (r_cons_fgets (buf + 4, sizeof (buf) - 4, 0, NULL) < 0) {
2793 buf[0] = '\0';
2794 }
2795 char *p = strdup (buf);
2796 int cur = core->print->cur;
2797 if (cur >= core->blocksize) {
2798 cur = core->print->cur - 1;
2799 }
2800 snprintf (buf, sizeof (buf), "%s @ $$0!%i", p,
2801 core->blocksize - cur);
2802 r_core_cmd (core, buf, 0);
2803 free (p);
2804 break;
2805 }
2806 if (core->print->col == 2) {
2807 strcpy (buf, "\"w ");
2808 r_line_set_prompt ("insert string: ");
2809 if (r_cons_fgets (buf + 3, sizeof (buf) - 3, 0, NULL) < 0) {
2810 buf[0] = '\0';
2811 }
2812 strcat (buf, "\"");
2813 } else {
2814 r_line_set_prompt ("insert hex: ");
2815 if (core->print->ocur != -1) {
2816 int bs = R_ABS (core->print->cur - core->print->ocur) + 1;
2817 core->blocksize = bs;
2818 strcpy (buf, "wow ");
2819 } else {
2820 strcpy (buf, "wx ");
2821 }
2822 if (r_cons_fgets (buf + strlen (buf), sizeof (buf) - strlen (buf), 0, NULL) < 0) {
2823 buf[0] = '\0';
2824 }
2825 }
2826 if (core->print->cur_enabled) {
2827 r_core_seek (core, addr, false);
2828 }
2829 r_core_cmd (core, buf, 1);
2830 if (core->print->cur_enabled) {
2831 r_core_seek (core, addr, true);
2832 }
2833 r_cons_set_raw (1);
2834 r_core_visual_showcursor (core, false);
2835 r_core_seek (core, oaddr, true);
2836 }
2837 break;
2838 case 'R':
2839 if (r_config_get_i (core->config, "scr.randpal")) {
2840 r_core_cmd0 (core, "ecr");
2841 } else {
2842 r_core_cmd0 (core, "ecn");
2843 }
2844 break;
2845 case 'e':
2846 r_core_visual_config (core);
2847 break;
2848 case '^':
2849 {
2850 RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset, 0);
2851 if (fcn) {
2852 r_core_seek (core, fcn->addr, false);
2853 } else {
2854 __core_visual_gogo (core, 'g');
2855 }
2856 }
2857 break;
2858 case 'E':
2859 r_core_visual_colors (core);
2860 break;
2861 case 'x':
2862 r_core_visual_refs (core, true, false);
2863 break;
2864 case 'X':
2865 r_core_visual_refs (core, false, false);
2866 break;
2867 case 'r':
2868 // TODO: toggle shortcut hotkeys
2869 if (r_config_get_i (core->config, "asm.hint.call")) {
2870 r_core_cmd0 (core, "e!asm.hint.call");
2871 r_core_cmd0 (core, "e asm.hint.jmp=true");
2872 } else if (r_config_get_i (core->config, "asm.hint.jmp")) {
2873 r_core_cmd0 (core, "e!asm.hint.jmp");
2874 r_core_cmd0 (core, "e asm.hint.emu=true");
2875 } else if (r_config_get_i (core->config, "asm.hint.emu")) {
2876 r_core_cmd0 (core, "e!asm.hint.emu");
2877 r_core_cmd0 (core, "e asm.hint.lea=true");
2878 } else if (r_config_get_i (core->config, "asm.hint.lea")) {
2879 r_core_cmd0 (core, "e!asm.hint.lea");
2880 r_core_cmd0 (core, "e asm.hint.call=true");
2881 } else {
2882 r_core_cmd0 (core, "e asm.hint.call=true");
2883 }
2884 visual_refresh (core);
2885 break;
2886 case ' ':
2887 case 'V':
2888 if (r_config_get_i (core->config, "graph.web")) {
2889 r_core_cmd0 (core, "agv $$");
2890 } else {
2891 RAnalFunction *fun = r_anal_get_fcn_in (core->anal, core->offset, R_ANAL_FCN_TYPE_NULL);
2892 int ocolor = r_config_get_i (core->config, "scr.color");
2893 if (!fun) {
2894 r_cons_message ("Not in a function. Type 'df' to define it here");
2895 break;
2896 } else if (r_list_empty (fun->bbs)) {
2897 r_cons_message ("No basic blocks in this function. You may want to use 'afb+'.");
2898 break;
2899 }
2900 reset_print_cur (core->print);
2901 eprintf ("\rRendering graph...");
2902 r_core_visual_graph (core, NULL, NULL, true);
2903 r_config_set_i (core->config, "scr.color", ocolor);
2904 }
2905 break;
2906 case 'v':
2907 r_core_visual_anal (core, NULL);
2908 break;
2909 case 'h':
2910 case 'l':
2911 if (r_config_get_i (core->config, "scr.cursor")) {
2912 core->cons->cpos.x += ch == 'h'? -1: 1;
2913 if (core->cons->cpos.x < 1) {
2914 core->cons->cpos.x = 0;
2915 }
2916 int h, w = r_cons_get_size (&h);
2917 if (core->cons->cpos.x >= w) {
2918 core->cons->cpos.x = w;
2919 }
2920 } else {
2921 int distance = numbuf_pull ();
2922 if (core->print->cur_enabled) {
2923 if (ch == 'h') {
2924 for (i = 0; i < distance; i++) {
2925 cursor_left (core, false);
2926 }
2927 } else {
2928 for (i = 0; i < distance; i++) {
2929 cursor_right (core, false);
2930 }
2931 }
2932 } else {
2933 if (ch == 'h') {
2934 distance = -distance;
2935 }
2936 r_core_seek_delta (core, distance);
2937 }
2938 }
2939 break;
2940 case 'L':
2941 case 'H':
2942 if (r_config_get_i (core->config, "scr.cursor")) {
2943 int distance = 8; // numbuf_pull ();
2944 core->cons->cpos.x += (ch == 'h' || ch == 'H')? -distance: distance;
2945 if (core->cons->cpos.x < 1) {
2946 core->cons->cpos.x = 0;
2947 }
2948 int h, w = r_cons_get_size (&h);
2949 if (core->cons->cpos.x >= w) {
2950 core->cons->cpos.x = w;
2951 }
2952 } else {
2953 int distance = numbuf_pull ();
2954 if (core->print->cur_enabled) {
2955 if (ch == 'H') {
2956 for (i = 0; i < distance; i++) {
2957 cursor_left (core, true);
2958 }
2959 } else {
2960 for (i = 0; i < distance; i++) {
2961 cursor_right (core, true);
2962 }
2963 }
2964 } else {
2965 if (ch == 'H') {
2966 distance = -distance;
2967 }
2968 r_core_seek_delta (core, distance * 2);
2969 }
2970 }
2971 break;
2972 case 'j':
2973 if (r_config_get_i (core->config, "scr.cursor")) {
2974 core->cons->cpos.y++;
2975 int h;
2976 (void)r_cons_get_size (&h);
2977 if (core->cons->cpos.y >= h) {
2978 core->cons->cpos.y = h;
2979 }
2980 } else if (core->print->cur_enabled) {
2981 int distance = numbuf_pull ();
2982 for (i = 0; i < distance; i++) {
2983 cursor_nextrow (core, false);
2984 }
2985 } else {
2986 if (r_config_get_i (core->config, "scr.wheel.nkey")) {
2987 int i, distance = numbuf_pull ();
2988 if (distance < 1) {
2989 distance = 1;
2990 }
2991 for (i = 0; i < distance; i++) {
2992 r_core_cmd0 (core, "sn");
2993 }
2994 } else {
2995 int times = R_MAX (1, wheelspeed);
2996 // Check if we have a data annotation.
2997 ut64 amisize;
2998 RAnalMetaItem *ami = r_meta_get_at (core->anal, core->offset, R_META_TYPE_DATA, &amisize);
2999 if (!ami) {
3000 ami = r_meta_get_at (core->anal, core->offset, R_META_TYPE_STRING, &amisize);
3001 }
3002 if (ami) {
3003 r_core_seek_delta (core, amisize);
3004 } else {
3005 int distance = numbuf_pull ();
3006 if (distance > 1) {
3007 times = distance;
3008 }
3009 while (times--) {
3010 if (isDisasmPrint (core->printidx)) {
3011 r_core_visual_disasm_down (core, &op, &cols);
3012 } else if (!strcmp (__core_visual_print_command (core),
3013 "prc")) {
3014 cols = r_config_get_i (core->config, "hex.cols");
3015 }
3016 r_core_seek (core, core->offset + cols, true);
3017 }
3018 }
3019 }
3020 }
3021 break;
3022 case 'J':
3023 if (r_config_get_i (core->config, "scr.cursor")) {
3024 int distance = 4;// numbuf_pull ();
3025 core->cons->cpos.y += distance;
3026 int h;
3027 (void)r_cons_get_size (&h);
3028 if (core->cons->cpos.y >= h) {
3029 core->cons->cpos.y = h;
3030 }
3031 } else if (core->print->cur_enabled) {
3032 int distance = numbuf_pull ();
3033 for (i = 0; i < distance; i++) {
3034 cursor_nextrow (core, true);
3035 }
3036 } else {
3037 if (core->print->screen_bounds > 1 && core->print->screen_bounds >= core->offset) {
3038 ut64 addr = UT64_MAX;
3039 if (isDisasmPrint (core->printidx)) {
3040 if (core->print->screen_bounds == core->offset) {
3041 r_asm_disassemble (core->rasm, &op, core->block, 32);
3042 }
3043 if (addr == core->offset || addr == UT64_MAX) {
3044 addr = core->offset + 48;
3045 }
3046 } else {
3047 int h;
3048 int hexCols = r_config_get_i (core->config, "hex.cols");
3049 if (hexCols < 1) {
3050 hexCols = 16;
3051 }
3052 (void)r_cons_get_size (&h);
3053 int delta = hexCols * (h / 4);
3054 addr = core->offset + delta;
3055 }
3056 r_core_seek (core, addr, true);
3057 } else {
3058 r_core_seek (core, core->offset + obs, true);
3059 }
3060 }
3061 break;
3062 case 'k':
3063 if (r_config_get_i (core->config, "scr.cursor")) {
3064 core->cons->cpos.y--;
3065 if (core->cons->cpos.y < 1) {
3066 core->cons->cpos.y = 0;
3067 }
3068 } else if (core->print->cur_enabled) {
3069 int distance = numbuf_pull ();
3070 for (i = 0; i < distance; i++) {
3071 cursor_prevrow (core, false);
3072 }
3073 } else {
3074 if (r_config_get_i (core->config, "scr.wheel.nkey")) {
3075 int i, distance = numbuf_pull ();
3076 if (distance < 1) {
3077 distance = 1;
3078 }
3079 for (i = 0; i < distance; i++) {
3080 r_core_cmd0 (core, "sp");
3081 }
3082 } else {
3083 int times = wheelspeed;
3084 if (times < 1) {
3085 times = 1;
3086 }
3087 int distance = numbuf_pull ();
3088 if (distance > 1) {
3089 times = distance;
3090 }
3091 while (times--) {
3092 if (isDisasmPrint (core->printidx)) {
3093 r_core_visual_disasm_up (core, &cols);
3094 } else if (!strcmp (__core_visual_print_command (core), "prc")) {
3095 cols = r_config_get_i (core->config, "hex.cols");
3096 }
3097 r_core_seek_delta (core, -cols);
3098 }
3099 }
3100 }
3101 break;
3102 case 'K':
3103 if (r_config_get_i (core->config, "scr.cursor")) {
3104 int distance = 4;// numbuf_pull ();
3105 core->cons->cpos.y -= distance;
3106 if (core->cons->cpos.y < 1) {
3107 core->cons->cpos.y = 0;
3108 }
3109 } else if (core->print->cur_enabled) {
3110 int distance = numbuf_pull ();
3111 for (i = 0; i < distance; i++) {
3112 cursor_prevrow (core, true);
3113 }
3114 } else {
3115 if (core->print->screen_bounds > 1 && core->print->screen_bounds > core->offset) {
3116 int delta = (core->print->screen_bounds - core->offset);
3117 if (core->offset >= delta) {
3118 r_core_seek (core, core->offset - delta, true);
3119 } else {
3120 r_core_seek (core, 0, true);
3121 }
3122 } else {
3123 ut64 at = (core->offset > obs)? core->offset - obs: 0;
3124 if (core->offset > obs) {
3125 r_core_seek (core, at, true);
3126 } else {
3127 r_core_seek (core, 0, true);
3128 }
3129 }
3130 }
3131 break;
3132 case '[':
3133 // comments column
3134 if (core->print->cur_enabled &&
3135 (core->printidx == R_CORE_VISUAL_MODE_PD ||
3136 (core->printidx == R_CORE_VISUAL_MODE_DB && core->seltab == 2))) {
3137 int cmtcol = r_config_get_i (core->config, "asm.cmt.col");
3138 if (cmtcol > 2) {
3139 r_config_set_i (core->config, "asm.cmt.col", cmtcol - 2);
3140 }
3141 }
3142 // hex column
3143 if ((core->printidx != R_CORE_VISUAL_MODE_PD && core->printidx != R_CORE_VISUAL_MODE_DB) ||
3144 (core->printidx == R_CORE_VISUAL_MODE_DB && core->seltab != 2)) {
3145 int scrcols = r_config_get_i (core->config, "hex.cols");
3146 if (scrcols > 1) {
3147 r_config_set_i (core->config, "hex.cols", scrcols - 1);
3148 }
3149 }
3150 break;
3151 case ']':
3152 // comments column
3153 if (core->print->cur_enabled &&
3154 (core->printidx == R_CORE_VISUAL_MODE_PD ||
3155 (core->printidx == R_CORE_VISUAL_MODE_DB && core->seltab == 2))) {
3156 int cmtcol = r_config_get_i (core->config, "asm.cmt.col");
3157 r_config_set_i (core->config, "asm.cmt.col", cmtcol + 2);
3158 }
3159 // hex column
3160 if ((core->printidx != R_CORE_VISUAL_MODE_PD && core->printidx != R_CORE_VISUAL_MODE_DB) ||
3161 (core->printidx == R_CORE_VISUAL_MODE_DB && core->seltab != 2)) {
3162 int scrcols = r_config_get_i (core->config, "hex.cols");
3163 r_config_set_i (core->config, "hex.cols", scrcols + 1);
3164 }
3165 break;
3166 #if 0
3167 case 'I':
3168 r_core_cmd (core, "dsp", 0);
3169 r_core_cmd (core, ".dr*", 0);
3170 break;
3171 #endif
3172 case 's':
3173 key_s = r_config_get (core->config, "key.s");
3174 if (key_s && *key_s) {
3175 r_core_cmd0 (core, key_s);
3176 } else {
3177 visual_single_step_in (core);
3178 }
3179 break;
3180 case 'S':
3181 key_s = r_config_get (core->config, "key.S");
3182 if (key_s && *key_s) {
3183 r_core_cmd0 (core, key_s);
3184 } else {
3185 __core_visual_step_over (core);
3186 }
3187 break;
3188 case '"':
3189 r_config_toggle (core->config, "scr.dumpcols");
3190 break;
3191 case 'p':
3192 r_core_visual_toggle_decompiler_disasm (core, false, true);
3193 if (core->printidx == R_CORE_VISUAL_MODE_DB && core->print->cur_enabled) {
3194 nextPrintCommand ();
3195 } else {
3196 setprintmode (core, 1);
3197 }
3198 break;
3199 case 'P':
3200 if (core->printidx == R_CORE_VISUAL_MODE_DB && core->print->cur_enabled) {
3201 prevPrintCommand ();
3202 } else {
3203 setprintmode (core, -1);
3204 }
3205 break;
3206 case '%':
3207 if (core->print->cur_enabled) {
3208 findPair (core);
3209 } else {
3210 /* do nothing? */
3211 autoblocksize = !autoblocksize;
3212 if (autoblocksize) {
3213 obs = core->blocksize;
3214 } else {
3215 r_core_block_size (core, obs);
3216 }
3217 r_cons_clear ();
3218 }
3219 break;
3220 case 'w':
3221 findNextWord (core);
3222 break;
3223 case 'W':
3224 findPrevWord (core);
3225 //r_core_cmd0 (core, "=H");
3226 break;
3227 case 'm':
3228 {
3229 r_cons_gotoxy (0, 0);
3230 r_cons_printf (R_CONS_CLEAR_LINE"Set shortcut key for 0x%"PFMT64x"\n", core->offset);
3231 r_cons_flush ();
3232 int ch = r_cons_readchar ();
3233 r_core_visual_mark (core, ch);
3234 }
3235 break;
3236 case 'M':
3237 {
3238 r_cons_gotoxy (0, 0);
3239 if (r_core_visual_mark_dump (core)) {
3240 r_cons_printf (R_CONS_CLEAR_LINE"Remove a shortcut key from the list\n");
3241 r_cons_flush ();
3242 int ch = r_cons_readchar ();
3243 r_core_visual_mark_del (core, ch);
3244 }
3245 }
3246 break;
3247 case '\'':
3248 {
3249 r_cons_gotoxy (0, 0);
3250 if (r_core_visual_mark_dump (core)) {
3251 r_cons_flush ();
3252 int ch = r_cons_readchar ();
3253 r_core_visual_mark_seek (core, ch);
3254 }
3255 }
3256 break;
3257 case 'y':
3258 if (core->print->ocur == -1) {
3259 r_core_yank (core, core->offset + core->print->cur, 1);
3260 } else {
3261 r_core_yank (core, core->offset + ((core->print->ocur < core->print->cur) ?
3262 core->print->ocur: core->print->cur), R_ABS (core->print->cur - core->print->ocur) + 1);
3263 }
3264 break;
3265 case 'Y':
3266 if (!core->yank_buf) {
3267 r_cons_strcat ("Cannot paste, clipboard is empty.\n");
3268 r_cons_flush ();
3269 r_cons_any_key (NULL);
3270 r_cons_clear00 ();
3271 } else {
3272 r_core_yank_paste (core, core->offset + core->print->cur, 0);
3273 }
3274 break;
3275 case '0':
3276 {
3277 RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset, R_ANAL_FCN_TYPE_NULL);
3278 if (fcn) {
3279 r_core_seek (core, fcn->addr, true);
3280 }
3281 }
3282 break;
3283 case '-':
3284 if (core->print->cur_enabled) {
3285 if (core->seltab < 2 && core->printidx == R_CORE_VISUAL_MODE_DB) {
3286 if (core->seltab) {
3287 const char *creg = core->dbg->creg;
3288 if (creg) {
3289 r_core_cmdf (core, "dr %s = %s-1\n", creg, creg);
3290 }
3291 } else {
3292 int w = r_config_get_i (core->config, "hex.cols");
3293 r_config_set_i (core->config, "stack.size",
3294 r_config_get_i (core->config, "stack.size") - w);
3295 }
3296 } else {
3297 if (core->print->ocur == -1) {
3298 sprintf (buf, "wos 01 @ $$+%i!1",core->print->cur);
3299 } else {
3300 sprintf (buf, "wos 01 @ $$+%i!%i", core->print->cur < core->print->ocur
3301 ? core->print->cur
3302 : core->print->ocur,
3303 R_ABS (core->print->ocur - core->print->cur) + 1);
3304 }
3305 r_core_cmd (core, buf, 0);
3306 }
3307 } else {
3308 if (!autoblocksize) {
3309 r_core_block_size (core, core->blocksize - 1);
3310 }
3311 }
3312 break;
3313 case '+':
3314 if (core->print->cur_enabled) {
3315 if (core->seltab < 2 && core->printidx == R_CORE_VISUAL_MODE_DB) {
3316 if (core->seltab) {
3317 const char *creg = core->dbg->creg;
3318 if (creg) {
3319 r_core_cmdf (core, "dr %s = %s+1\n", creg, creg);
3320 }
3321 } else {
3322 int w = r_config_get_i (core->config, "hex.cols");
3323 r_config_set_i (core->config, "stack.size",
3324 r_config_get_i (core->config, "stack.size") + w);
3325 }
3326 } else {
3327 if (core->print->ocur == -1) {
3328 sprintf (buf, "woa 01 @ $$+%i!1", core->print->cur);
3329 } else {
3330 sprintf (buf, "woa 01 @ $$+%i!%i", core->print->cur < core->print->ocur
3331 ? core->print->cur
3332 : core->print->ocur,
3333 R_ABS (core->print->ocur - core->print->cur) + 1);
3334 }
3335 r_core_cmd (core, buf, 0);
3336 }
3337 } else {
3338 if (!autoblocksize) {
3339 r_core_block_size (core, core->blocksize + 1);
3340 }
3341 }
3342 break;
3343 case '/': {
3344 bool mouse_state = __holdMouseState (core);
3345 if (core->print->cur_enabled) {
3346 if (core->seltab < 2 && core->printidx == R_CORE_VISUAL_MODE_DB) {
3347 if (core->seltab) {
3348 const char *creg = core->dbg->creg;
3349 if (creg) {
3350 int delta = core->rasm->bits / 8;
3351 r_core_cmdf (core, "dr %s = %s-%d\n", creg, creg, delta);
3352 }
3353 } else {
3354 int w = r_config_get_i (core->config, "hex.cols");
3355 r_config_set_i (core->config, "stack.size",
3356 r_config_get_i (core->config, "stack.size") - w);
3357 }
3358 } else {
3359 visual_search (core);
3360 }
3361 } else {
3362 if (autoblocksize) {
3363 r_core_cmd0 (core, "?i highlight;e scr.highlight=`yp`");
3364 } else {
3365 r_core_block_size (core, core->blocksize - cols);
3366 }
3367 }
3368 r_cons_enable_mouse (mouse_state && r_config_get_i (core->config, "scr.wheel"));
3369 } break;
3370 case '(':
3371 snowMode = !snowMode;
3372 if (!snowMode) {
3373 r_list_free (snows);
3374 snows = NULL;
3375 }
3376 break;
3377 case ')':
3378 rotateAsmemu (core);
3379 break;
3380 case '#':
3381 if (core->printidx == 1) {
3382 r_core_visual_toggle_decompiler_disasm (core, false, false);
3383 } else {
3384 // do nothing for now :?, px vs pxa?
3385 }
3386 break;
3387 case '*':
3388 if (core->print->cur_enabled) {
3389 if (core->seltab < 2 && core->printidx == R_CORE_VISUAL_MODE_DB) {
3390 if (core->seltab) {
3391 const char *creg = core->dbg->creg;
3392 if (creg) {
3393 int delta = core->rasm->bits / 8;
3394 r_core_cmdf (core, "dr %s = %s+%d\n", creg, creg, delta);
3395 }
3396 } else {
3397 int w = r_config_get_i (core->config, "hex.cols");
3398 r_config_set_i (core->config, "stack.size",
3399 r_config_get_i (core->config, "stack.size") + w);
3400 }
3401 } else {
3402 r_core_cmdf (core, "dr PC=0x%08"PFMT64x, core->offset + core->print->cur);
3403 }
3404 } else if (!autoblocksize) {
3405 r_core_block_size (core, core->blocksize + cols);
3406 }
3407 break;
3408 case '>':
3409 if (core->print->cur_enabled) {
3410 if (core->print->ocur == -1) {
3411 eprintf ("No range selected. Use HJKL.\n");
3412 r_cons_any_key (NULL);
3413 break;
3414 }
3415 char buf[128];
3416 // TODO autocomplete filenames
3417 prompt_read ("dump to file: ", buf, sizeof (buf));
3418 if (buf[0]) {
3419 ut64 from = core->offset + core->print->ocur;
3420 ut64 size = R_ABS (core->print->cur - core->print->ocur) + 1;
3421 r_core_dump (core, buf, from, size, false);
3422 }
3423 } else {
3424 r_core_seek (core, core->offset + core->blocksize, false);
3425 r_io_sundo_push (core->io, core->offset, r_print_get_cursor (core->print));
3426 }
3427 break;
3428 case '<': // "V<"
3429 if (core->print->cur_enabled) {
3430 char buf[128];
3431 // TODO autocomplete filenames
3432 prompt_read ("load from file: ", buf, sizeof (buf));
3433 if (buf[0]) {
3434 size_t sz;
3435 char *data = r_file_slurp (buf, &sz);
3436 if (data) {
3437 int cur;
3438 if (core->print->ocur != -1) {
3439 cur = R_MIN (core->print->cur, core->print->ocur);
3440 } else {
3441 cur = core->print->cur;
3442 }
3443 ut64 from = core->offset + cur;
3444 ut64 size = R_ABS (core->print->cur - core->print->ocur) + 1;
3445 ut64 s = R_MIN (size, (ut64)sz);
3446 r_io_write_at (core->io, from, (const ut8*)data, s);
3447 }
3448 }
3449 } else {
3450 r_core_seek (core, core->offset - core->blocksize, false);
3451 r_io_sundo_push (core->io, core->offset, r_print_get_cursor (core->print));
3452 }
3453 break;
3454 case '.': // "V."
3455 r_io_sundo_push (core->io, core->offset, r_print_get_cursor (core->print));
3456 if (core->print->cur_enabled) {
3457 r_config_set_i (core->config, "stack.delta", 0);
3458 r_core_seek (core, core->offset + core->print->cur, true);
3459 core->print->cur = 0;
3460 } else {
3461 ut64 addr = r_debug_reg_get (core->dbg, "PC");
3462 if (addr && addr != UT64_MAX) {
3463 r_core_seek (core, addr, true);
3464 r_core_cmdf (core, "ar `arn PC`=0x%"PFMT64x, addr);
3465 } else {
3466 ut64 entry = r_num_get (core->num, "entry0");
3467 if (!entry || entry == UT64_MAX) {
3468 RBinObject *o = r_bin_cur_object (core->bin);
3469 RBinSection *s = o? r_bin_get_section_at (o, addr, core->io->va): NULL;
3470 if (s) {
3471 entry = s->vaddr;
3472 } else {
3473 RIOMap *map = r_pvector_pop (&core->io->maps);
3474 if (map) {
3475 entry = r_io_map_begin (map);
3476 } else {
3477 entry = r_config_get_i (core->config, "bin.baddr");
3478 }
3479 r_pvector_push_front (&core->io->maps, map);
3480 }
3481 }
3482 if (entry != UT64_MAX) {
3483 r_core_seek (core, entry, true);
3484 }
3485 }
3486 }
3487 break;
3488 #if 0
3489 case 'n': r_core_seek_delta (core, core->blocksize); break;
3490 case 'N': r_core_seek_delta (core, 0 - (int) core->blocksize); break;
3491 #endif
3492 case ':':
3493 r_core_visual_prompt_input (core);
3494 break;
3495 case '_':
3496 r_core_visual_hudstuff (core);
3497 break;
3498 case ';':
3499 r_cons_enable_mouse (false);
3500 r_cons_gotoxy (0, 0);
3501 r_cons_printf ("Enter a comment: ('-' to remove, '!' to use $EDITOR)\n");
3502 r_core_visual_showcursor (core, true);
3503 r_cons_flush ();
3504 r_cons_set_raw (false);
3505 r_line_set_prompt ("comment: ");
3506 strcpy (buf, "\"CC ");
3507 i = strlen (buf);
3508 if (r_cons_fgets (buf + i, sizeof (buf) - i, 0, NULL) > 0) {
3509 ut64 addr, orig;
3510 addr = orig = core->offset;
3511 if (core->print->cur_enabled) {
3512 addr += core->print->cur;
3513 r_core_seek (core, addr, false);
3514 r_core_cmdf (core, "s 0x%"PFMT64x, addr);
3515 }
3516 if (!strcmp (buf + i, "-")) {
3517 strcpy (buf, "CC-");
3518 } else {
3519 switch (buf[i]) {
3520 case '-':
3521 memcpy (buf, "\"CC-\x00", 5);
3522 break;
3523 case '!':
3524 memcpy (buf, "\"CC!\x00", 5);
3525 break;
3526 default:
3527 memcpy (buf, "\"CC ", 4);
3528 break;
3529 }
3530 strcat (buf, "\"");
3531 }
3532 if (buf[3] == ' ') {
3533 // have to escape any quotes.
3534 int j, len = strlen (buf);
3535 char *duped = strdup (buf);
3536 for (i = 4, j = 4; i < len; i++, j++) {
3537 char c = duped[i];
3538 if (c == '"' && i != (len - 1)) {
3539 buf[j] = '\\';
3540 j++;
3541 buf[j] = '"';
3542 } else {
3543 buf[j] = c;
3544 }
3545 }
3546 buf[j] = 0;
3547 free (duped);
3548 }
3549 r_core_cmd (core, buf, 1);
3550 if (core->print->cur_enabled) {
3551 r_core_seek (core, orig, true);
3552 }
3553 }
3554 r_cons_set_raw (true);
3555 r_core_visual_showcursor (core, false);
3556 break;
3557 case 'b':
3558 r_core_visual_browse (core, arg + 1);
3559 break;
3560 case 'B':
3561 {
3562 ut64 addr = core->print->cur_enabled? core->offset + core->print->cur: core->offset;
3563 r_core_cmdf (core, "dbs 0x%08"PFMT64x, addr);
3564 }
3565 break;
3566 case 'u':
3567 {
3568 RIOUndos *undo = r_io_sundo (core->io, core->offset);
3569 if (undo) {
3570 r_core_visual_seek_animation (core, undo->off);
3571 core->print->cur = undo->cursor;
3572 } else {
3573 eprintf ("Cannot undo\n");
3574 }
3575 }
3576 break;
3577 case 'U':
3578 {
3579 RIOUndos *undo = r_io_sundo_redo (core->io);
3580 if (undo) {
3581 r_core_visual_seek_animation (core, undo->off);
3582 reset_print_cur (core->print);
3583 }
3584 }
3585 break;
3586 case 'z':
3587 {
3588 RAnalFunction *fcn;
3589 if (core->print->cur_enabled) {
3590 fcn = r_anal_get_fcn_in (core->anal,
3591 core->offset + core->print->cur, R_ANAL_FCN_TYPE_NULL);
3592 } else {
3593 fcn = r_anal_get_fcn_in (core->anal,
3594 core->offset, R_ANAL_FCN_TYPE_NULL);
3595 }
3596 if (fcn) {
3597 fcn->folded = !fcn->folded;
3598 } else {
3599 r_config_toggle (core->config, "asm.cmt.fold");
3600 }
3601 }
3602 break;
3603 case 'Z': // shift-tab SHIFT-TAB
3604 if (och == 27) { // shift-tab
3605 if (core->print->cur_enabled && core->printidx == R_CORE_VISUAL_MODE_DB) {
3606 core->print->cur = 0;
3607 core->seltab--;
3608 if (core->seltab < 0) {
3609 core->seltab = 2;
3610 }
3611 } else {
3612 prevPrintFormat (core);
3613 }
3614 } else { // "Z"
3615 ut64 addr = core->print->cur_enabled? core->offset + core->print->cur: core->offset;
3616 toggle_bb (core, addr);
3617 }
3618 break;
3619 case '?':
3620 if (visual_help (core) == '?') {
3621 r_core_visual_hud (core);
3622 }
3623 break;
3624 case 0x1b:
3625 case 'q':
3626 case 'Q':
3627 setcursor (core, false);
3628 return false;
3629 }
3630 numbuf_i = 0;
3631 }
3632 r_core_block_read (core);
3633 return true;
3634 }
3635
r_core_visual_title(RCore * core,int color)3636 R_API void r_core_visual_title(RCore *core, int color) {
3637 bool showDelta = r_config_get_i (core->config, "scr.slow");
3638 static ut64 oldpc = 0;
3639 const char *BEGIN = core->cons->context->pal.prompt;
3640 const char *filename;
3641 char pos[512], bar[512], pcs[32];
3642 if (!oldpc) {
3643 oldpc = r_debug_reg_get (core->dbg, "PC");
3644 }
3645 /* automatic block size */
3646 int pc, hexcols = r_config_get_i (core->config, "hex.cols");
3647 if (autoblocksize) {
3648 switch (core->printidx) {
3649 #if 0
3650 case R_CORE_VISUAL_MODE_PXR: // prc
3651 case R_CORE_VISUAL_MODE_PRC: // prc
3652 r_core_block_size (core, (int)(core->cons->rows * hexcols * 3.5));
3653 break;
3654 case R_CORE_VISUAL_MODE_PXa: // pxa
3655 case R_CORE_VISUAL_MODE_PW: // XXX pw
3656 r_core_block_size (core, (int)(core->cons->rows * hexcols));
3657 break;
3658 case R_CORE_VISUAL_MODE_PC: // XXX pc
3659 r_core_block_size (core, (int)(core->cons->rows * hexcols * 4));
3660 break;
3661 case R_CORE_VISUAL_MODE_PXA: // pxA
3662 r_core_block_size (core, hexcols * core->cons->rows * 8);
3663 break;
3664 #endif
3665 case R_CORE_VISUAL_MODE_PX: // x
3666 if (currentFormat == 3 || currentFormat == 9 || currentFormat == 5) { // prx
3667 r_core_block_size (core, (int)(core->cons->rows * hexcols * 4));
3668 } else if ((R_ABS (hexMode) % 3) == 0) { // prx
3669 r_core_block_size (core, (int)(core->cons->rows * hexcols));
3670 } else {
3671 r_core_block_size (core, (int)(core->cons->rows * hexcols * 2));
3672 }
3673 break;
3674 case R_CORE_VISUAL_MODE_OV:
3675 case R_CORE_VISUAL_MODE_CD:
3676 r_core_block_size (core, (int)(core->cons->rows * hexcols * 2));
3677 break;
3678 case R_CORE_VISUAL_MODE_PD: // pd
3679 case R_CORE_VISUAL_MODE_DB: // pd+dbg
3680 {
3681 int bsize = core->cons->rows * 5;
3682
3683 if (core->print->screen_bounds > 1) {
3684 // estimate new blocksize with the size of the last
3685 // printed instructions
3686 int new_sz = core->print->screen_bounds - core->offset + 32;
3687 new_sz = R_MIN (new_sz, 16 * 1024);
3688 if (new_sz > bsize) {
3689 bsize = new_sz;
3690 }
3691 }
3692 r_core_block_size (core, bsize);
3693 break;
3694 }
3695 }
3696 }
3697 if (r_config_get_i (core->config, "scr.scrollbar") == 2) {
3698 r_core_cmd (core, "fz:", 0);
3699 }
3700 if (r_config_get_i (core->config, "cfg.debug")) {
3701 ut64 curpc = r_debug_reg_get (core->dbg, "PC");
3702 if (curpc && curpc != UT64_MAX && curpc != oldpc) {
3703 // check dbg.follow here
3704 int follow = (int) (st64) r_config_get_i (core->config, "dbg.follow");
3705 if (follow > 0) {
3706 if ((curpc < core->offset) || (curpc > (core->offset + follow))) {
3707 r_core_seek (core, curpc, true);
3708 }
3709 } else if (follow < 0) {
3710 r_core_seek (core, curpc + follow, true);
3711 }
3712 oldpc = curpc;
3713 }
3714 }
3715 RIOMap *map = r_io_map_get (core->io, core->offset);
3716 RIODesc *desc = map ? r_io_desc_get (core->io, map->fd) : core->io->desc;
3717 filename = desc? desc->name: "";
3718
3719 { /* get flag with delta */
3720 ut64 addr = core->offset + (core->print->cur_enabled? core->print->cur: 0);
3721 /* TODO: we need a helper into r_flags to do that */
3722 RFlagItem *f = NULL;
3723 if (r_flag_space_push (core->flags, R_FLAGS_FS_SYMBOLS)) {
3724 f = r_flag_get_at (core->flags, addr, showDelta);
3725 r_flag_space_pop (core->flags);
3726 }
3727 if (!f) {
3728 f = r_flag_get_at (core->flags, addr, showDelta);
3729 }
3730 if (f) {
3731 if (f->offset == addr || !f->offset) {
3732 snprintf (pos, sizeof (pos), "@ %s", f->name);
3733 } else {
3734 snprintf (pos, sizeof (pos), "@ %s+%d # 0x%"PFMT64x,
3735 f->name, (int) (addr - f->offset), addr);
3736 }
3737 } else {
3738 RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, addr, 0);
3739 if (fcn) {
3740 int delta = addr - fcn->addr;
3741 if (delta > 0) {
3742 snprintf (pos, sizeof (pos), "@ %s+%d", fcn->name, delta);
3743 } else if (delta < 0) {
3744 snprintf (pos, sizeof (pos), "@ %s%d", fcn->name, delta);
3745 } else {
3746 snprintf (pos, sizeof (pos), "@ %s", fcn->name);
3747 }
3748 } else {
3749 pos[0] = 0;
3750 }
3751 }
3752 }
3753
3754 if (core->print->cur < 0) {
3755 core->print->cur = 0;
3756 }
3757
3758 if (color) {
3759 r_cons_strcat (BEGIN);
3760 }
3761 const char *cmd_visual = r_config_get (core->config, "cmd.visual");
3762 if (cmd_visual && *cmd_visual) {
3763 r_str_ncpy (bar, cmd_visual, sizeof (bar) - 1);
3764 bar[10] = '.'; // chop cmdfmt
3765 bar[11] = '.'; // chop cmdfmt
3766 bar[12] = 0; // chop cmdfmt
3767 } else {
3768 const char *cmd = __core_visual_print_command (core);
3769 if (cmd) {
3770 r_str_ncpy (bar, cmd, sizeof (bar) - 1);
3771 bar[10] = '.'; // chop cmdfmt
3772 bar[11] = '.'; // chop cmdfmt
3773 bar[12] = 0; // chop cmdfmt
3774 }
3775 }
3776 {
3777 ut64 sz = r_io_size (core->io);
3778 ut64 pa = core->offset;
3779 {
3780 RIOMap *map = r_io_map_get (core->io, core->offset);
3781 if (map) {
3782 pa = map->delta;
3783 }
3784 }
3785 if (sz == UT64_MAX) {
3786 pcs[0] = 0;
3787 } else {
3788 if (!sz || pa > sz) {
3789 pc = 0;
3790 } else {
3791 pc = (pa * 100) / sz;
3792 }
3793 sprintf (pcs, "%d%% ", pc);
3794 }
3795 }
3796 {
3797 char *title;
3798 char *address = (core->print->wide_offsets && core->dbg->bits & R_SYS_BITS_64)
3799 ? r_str_newf ("0x%016"PFMT64x, core->offset)
3800 : r_str_newf ("0x%08"PFMT64x, core->offset);
3801 if (__ime) {
3802 title = r_str_newf ("[%s + %d> * INSERT MODE *\n",
3803 address, core->print->cur);
3804 } else {
3805 char pm[32] = "[XADVC]";
3806 int i;
3807 for(i=0;i<6;i++) {
3808 if (core->printidx == i) {
3809 pm[i + 1] = toupper((unsigned char)pm[i + 1]);
3810 } else {
3811 pm[i + 1] = tolower((unsigned char)pm[i + 1]);
3812 }
3813 }
3814 if (core->print->cur_enabled) {
3815 if (core->print->ocur == -1) {
3816 title = r_str_newf ("[%s *0x%08"PFMT64x" %s%d ($$+0x%x)]> %s %s\n",
3817 address, core->offset + core->print->cur,
3818 pm, currentFormat, core->print->cur,
3819 bar, pos);
3820 } else {
3821 title = r_str_newf ("[%s 0x%08"PFMT64x" %s%d [0x%x..0x%x] %d]> %s %s\n",
3822 address, core->offset + core->print->cur,
3823 pm, currentFormat, core->print->ocur, core->print->cur,
3824 R_ABS (core->print->cur - core->print->ocur) + 1,
3825 bar, pos);
3826 }
3827 } else {
3828 title = r_str_newf ("[%s %s%d %s%d %s]> %s %s\n",
3829 address, pm, currentFormat, pcs, core->blocksize, filename, bar, pos);
3830 }
3831 }
3832 const int tabsCount = __core_visual_tab_count (core);
3833 if (tabsCount > 0) {
3834 const char *kolor = core->cons->context->pal.prompt;
3835 char *tabstring = __core_visual_tab_string (core, kolor);
3836 if (tabstring) {
3837 title = r_str_append (title, tabstring);
3838 free (tabstring);
3839 }
3840 #if 0
3841 // TODO: add an option to show this tab mode instead?
3842 const int curTab = core->visual.tab;
3843 r_cons_printf ("[");
3844 int i;
3845 for (i = 0; i < tabsCount; i++) {
3846 if (i == curTab) {
3847 r_cons_printf ("%d", curTab + 1);
3848 } else {
3849 r_cons_printf (".");
3850 }
3851 }
3852 r_cons_printf ("]");
3853 r_cons_printf ("[tab:%d/%d]", core->visual.tab, tabsCount);
3854 #endif
3855 }
3856 r_cons_print (title);
3857 free (title);
3858 free (address);
3859 }
3860 if (color) {
3861 r_cons_strcat (Color_RESET);
3862 }
3863 }
3864
visual_responsive(RCore * core)3865 static int visual_responsive(RCore *core) {
3866 int h, w = r_cons_get_size (&h);
3867 if (r_config_get_i (core->config, "scr.responsive")) {
3868 if (w < 110) {
3869 r_config_set_i (core->config, "asm.cmt.right", 0);
3870 } else {
3871 r_config_set_i (core->config, "asm.cmt.right", 1);
3872 }
3873 if (w < 68) {
3874 r_config_set_i (core->config, "hex.cols", (int)(w / 5.2));
3875 } else {
3876 r_config_set_i (core->config, "hex.cols", 16);
3877 }
3878 if (w < 25) {
3879 r_config_set_i (core->config, "asm.offset", 0);
3880 } else {
3881 r_config_set_i (core->config, "asm.offset", 1);
3882 }
3883 if (w > 80) {
3884 r_config_set_i (core->config, "asm.lines.width", 14);
3885 r_config_set_i (core->config, "asm.lines.width", w - (int)(w / 1.2));
3886 r_config_set_i (core->config, "asm.cmt.col", w - (int)(w / 2.5));
3887 } else {
3888 r_config_set_i (core->config, "asm.lines.width", 7);
3889 }
3890 if (w < 70) {
3891 r_config_set_i (core->config, "asm.lines.width", 1);
3892 r_config_set_i (core->config, "asm.bytes", 0);
3893 } else {
3894 r_config_set_i (core->config, "asm.bytes", 1);
3895 }
3896 }
3897 return w;
3898 }
3899
3900 // TODO: use colors
3901 // TODO: find better name
r_core_print_scrollbar(RCore * core)3902 R_API void r_core_print_scrollbar(RCore *core) {
3903 int i, h, w = r_cons_get_size (&h);
3904
3905 int scrollbar = r_config_get_i (core->config, "scr.scrollbar");
3906 if (scrollbar == 2) {
3907 // already handled by r_core_cmd("zf:") in visual.c
3908 return;
3909 }
3910 if (scrollbar > 2) {
3911 r_core_print_scrollbar_bottom (core);
3912 return;
3913 }
3914
3915 if (w < 10 || h < 3) {
3916 return;
3917 }
3918 ut64 from = 0;
3919 ut64 to = UT64_MAX;
3920 if (r_config_get_i (core->config, "cfg.debug")) {
3921 from = r_num_math (core->num, "$D");
3922 to = r_num_math (core->num, "$D+$DD");
3923 } else if (r_config_get_i (core->config, "io.va")) {
3924 from = r_num_math (core->num, "$S");
3925 to = r_num_math (core->num, "$S+$SS");
3926 } else {
3927 to = r_num_math (core->num, "$s");
3928 }
3929 char *s = r_str_newf ("[0x%08"PFMT64x"]", from);
3930 r_cons_gotoxy (w - strlen (s) + 1, 2);
3931 r_cons_strcat (s);
3932 free (s);
3933
3934 ut64 block = (to - from) / h;
3935
3936 RList *words = r_flag_zone_barlist (core->flags, from, block, h);
3937
3938 bool hadMatch = false;
3939 for (i = 0; i < h ; i++) {
3940 const char *word = r_list_pop_head (words);
3941 if (word && *word) {
3942 r_cons_gotoxy (w - strlen (word) - 1, i + 3);
3943 r_cons_printf ("%s>", word);
3944 }
3945 r_cons_gotoxy (w, i + 3);
3946 if (hadMatch) {
3947 r_cons_printf ("|");
3948 } else {
3949 ut64 cur = from + (block * i);
3950 ut64 nex = from + (block * (i + 1));
3951 if (R_BETWEEN (cur, core->offset, nex)) {
3952 r_cons_printf (Color_INVERT"|"Color_RESET);
3953 hadMatch = true;
3954 } else {
3955 r_cons_printf ("|");
3956 }
3957 }
3958 }
3959 s = r_str_newf ("[0x%08"PFMT64x"]", to);
3960 if (s) {
3961 r_cons_gotoxy (w - strlen (s) + 1, h + 1);
3962 r_cons_strcat (s);
3963 free (s);
3964 }
3965 r_list_free (words);
3966 r_cons_flush ();
3967 }
3968
r_core_print_scrollbar_bottom(RCore * core)3969 R_API void r_core_print_scrollbar_bottom(RCore *core) {
3970 int i, h, w = r_cons_get_size (&h);
3971
3972 if (w < 10 || h < 4) {
3973 return;
3974 }
3975 ut64 from = 0;
3976 ut64 to = UT64_MAX;
3977 if (r_config_get_i (core->config, "cfg.debug")) {
3978 from = r_num_math (core->num, "$D");
3979 to = r_num_math (core->num, "$D+$DD");
3980 } else if (r_config_get_i (core->config, "io.va")) {
3981 from = r_num_math (core->num, "$S");
3982 to = r_num_math (core->num, "$S+$SS");
3983 } else {
3984 to = r_num_math (core->num, "$s");
3985 }
3986 char *s = r_str_newf ("[0x%08"PFMT64x"]", from);
3987 int slen = strlen (s) + 1;
3988 r_cons_gotoxy (0, h + 1);
3989 r_cons_strcat (s);
3990 free (s);
3991
3992 int linew = (w - (slen * 2)) + 1;
3993 ut64 block = (to - from) / linew;
3994
3995 RList *words = r_flag_zone_barlist (core->flags, from, block, h);
3996
3997 bool hadMatch = false;
3998 for (i = 0; i < linew + 1; i++) {
3999 r_cons_gotoxy (i + slen, h + 1);
4000 if (hadMatch) {
4001 r_cons_strcat ("-");
4002 } else {
4003 ut64 cur = from + (block * i);
4004 ut64 nex = from + (block * (i + 2));
4005 if (R_BETWEEN (cur, core->offset, nex)) {
4006 r_cons_strcat (Color_INVERT"-"Color_RESET);
4007 hadMatch = true;
4008 } else {
4009 r_cons_strcat ("-");
4010 }
4011 }
4012 }
4013 for (i = 0; i < linew; i++) {
4014 const char *word = r_list_pop_head (words);
4015 if (word && *word) {
4016 ut64 cur = from + (block * i);
4017 ut64 nex = from + (block * (i + strlen (word) + 1));
4018 r_cons_gotoxy (i + slen - 1, h);
4019 if (R_BETWEEN (cur, core->offset, nex)) {
4020 r_cons_printf (Color_INVERT"{%s}"Color_RESET, word);
4021 } else {
4022 r_cons_printf ("{%s}", word);
4023 }
4024 }
4025 }
4026 s = r_str_newf ("[0x%08"PFMT64x"]", to);
4027 if (s) {
4028 r_cons_gotoxy (linew + slen + 1, h + 1);
4029 r_cons_strcat (s);
4030 free (s);
4031 }
4032 r_list_free (words);
4033 r_cons_flush ();
4034 }
4035
show_cursor(RCore * core)4036 static void show_cursor(RCore *core) {
4037 const bool keyCursor = r_config_get_i (core->config, "scr.cursor");
4038 if (keyCursor) {
4039 r_cons_gotoxy (core->cons->cpos.x, core->cons->cpos.y);
4040 r_cons_show_cursor (1);
4041 //r_cons_invert (1, 1);
4042 //r_cons_print ("#");
4043 r_cons_flush ();
4044 }
4045 }
4046
visual_refresh(RCore * core)4047 static void visual_refresh(RCore *core) {
4048 static ut64 oseek = UT64_MAX;
4049 const char *vi, *vcmd, *cmd_str;
4050 if (!core) {
4051 return;
4052 }
4053 r_print_set_cursor (core->print, core->print->cur_enabled, core->print->ocur, core->print->cur);
4054 core->cons->blankline = true;
4055
4056 int w = visual_responsive (core);
4057
4058 if (autoblocksize) {
4059 r_cons_gotoxy (0, 0);
4060 } else {
4061 r_cons_clear ();
4062 }
4063 r_cons_flush ();
4064 r_cons_print_clear ();
4065
4066 int hex_cols = r_config_get_i (core->config, "hex.cols");
4067 int split_w = 12 + 4 + hex_cols + (hex_cols * 3);
4068 bool ce = core->print->cur_enabled;
4069
4070 vi = r_config_get (core->config, "cmd.cprompt");
4071 bool vsplit = (vi && *vi);
4072
4073 if (vsplit) {
4074 // XXX: slow
4075 core->cons->blankline = false;
4076 {
4077 int hex_cols = r_config_get_i (core->config, "hex.cols");
4078 int split_w = 12 + 4 + hex_cols + (hex_cols * 3);
4079 if (split_w > w) {
4080 // do not show column contents
4081 } else {
4082 r_cons_printf ("[cmd.cprompt=%s]\n", vi);
4083 if (oseek != UT64_MAX) {
4084 r_core_seek (core, oseek, true);
4085 }
4086 r_core_cmd0 (core, vi);
4087 r_cons_column (split_w);
4088 if (!strncmp (vi, "p=", 2) && core->print->cur_enabled) {
4089 oseek = core->offset;
4090 core->print->cur_enabled = false;
4091 r_core_seek (core, core->num->value, true);
4092 } else {
4093 oseek = UT64_MAX;
4094 }
4095 }
4096 }
4097 r_cons_gotoxy (0, 0);
4098 }
4099 vi = r_config_get (core->config, "cmd.vprompt");
4100 if (vi && *vi) {
4101 r_core_cmd0 (core, vi);
4102 #if 0
4103 char *output = r_core_cmd_str (core, vi);
4104 r_cons_strcat_at (output, 10, 5, 20, 20);
4105 free (output);
4106 #endif
4107 }
4108 r_core_visual_title (core, color);
4109 vcmd = r_config_get (core->config, "cmd.visual");
4110 if (vcmd && *vcmd) {
4111 // disable screen bounds when it's a user-defined command
4112 // because it can cause some issues
4113 core->print->screen_bounds = 0;
4114 cmd_str = vcmd;
4115 } else {
4116 if (splitView) {
4117 static char debugstr[512];
4118 const char *pxw = NULL;
4119 int h = r_num_get (core->num, "$r");
4120 int size = (h * 16) / 2;
4121 switch (core->printidx) {
4122 case 1:
4123 size = (h - 2) / 2;
4124 pxw = "pd";
4125 break;
4126 default:
4127 pxw = stackPrintCommand (core);
4128 break;
4129 }
4130 snprintf (debugstr, sizeof (debugstr),
4131 "?t0;%s %d @ %"PFMT64d";cl;"
4132 "?t1;%s %d @ %"PFMT64d";",
4133 pxw, size, splitPtr,
4134 pxw, size, core->offset);
4135 core->print->screen_bounds = 1LL;
4136 cmd_str = debugstr;
4137 } else {
4138 core->print->screen_bounds = 1LL;
4139 cmd_str = (zoom ? "pz" : __core_visual_print_command (core));
4140 }
4141 }
4142 if (cmd_str && *cmd_str) {
4143 if (vsplit) {
4144 char *cmd_result = r_core_cmd_str (core, cmd_str);
4145 cmd_result = r_str_ansi_crop (cmd_result, 0, 0, split_w, -1);
4146 r_cons_strcat (cmd_result);
4147 } else {
4148 r_core_cmd0 (core, cmd_str);
4149 }
4150 }
4151 core->print->cur_enabled = ce;
4152 #if 0
4153 if (core->print->screen_bounds != 1LL) {
4154 r_cons_printf ("[0x%08"PFMT64x "..0x%08"PFMT64x "]\n",
4155 core->offset, core->print->screen_bounds);
4156 }
4157 #endif
4158 blocksize = core->num->value? core->num->value: core->blocksize;
4159
4160 /* this is why there's flickering */
4161 if (core->print->vflush) {
4162 r_cons_visual_flush ();
4163 } else {
4164 r_cons_reset ();
4165 }
4166 if (core->scr_gadgets) {
4167 r_core_cmd0 (core, "pg");
4168 r_cons_flush ();
4169 }
4170 core->cons->blankline = false;
4171 core->cons->blankline = true;
4172 core->curtab = 0; // which command are we focusing
4173 //core->seltab = 0; // user selected tab
4174
4175 if (snowMode) {
4176 printSnow (core);
4177 }
4178 if (r_config_get_i (core->config, "scr.scrollbar")) {
4179 r_core_print_scrollbar (core);
4180 }
4181 show_cursor (core);
4182 }
4183
visual_refresh_oneshot(RCore * core)4184 static void visual_refresh_oneshot(RCore *core) {
4185 r_core_task_enqueue_oneshot (&core->tasks, (RCoreTaskOneShot) visual_refresh, core);
4186 }
4187
r_core_visual_disasm_up(RCore * core,int * cols)4188 R_API void r_core_visual_disasm_up(RCore *core, int *cols) {
4189 RAnalFunction *f = r_anal_get_fcn_in (core->anal, core->offset, R_ANAL_FCN_TYPE_NULL);
4190 if (f && f->folded) {
4191 *cols = core->offset - f->addr; // + f->size;
4192 if (*cols < 1) {
4193 *cols = 4;
4194 }
4195 } else {
4196 *cols = r_core_visual_prevopsz (core, core->offset);
4197 }
4198 }
4199
r_core_visual_disasm_down(RCore * core,RAsmOp * op,int * cols)4200 R_API void r_core_visual_disasm_down(RCore *core, RAsmOp *op, int *cols) {
4201 int midflags = r_config_get_i (core->config, "asm.flags.middle");
4202 const bool midbb = r_config_get_i (core->config, "asm.bb.middle");
4203 RAnalFunction *f = NULL;
4204 f = r_anal_get_fcn_in (core->anal, core->offset, 0);
4205 op->size = 1;
4206 if (f && f->folded) {
4207 *cols = core->offset - r_anal_function_max_addr (f);
4208 } else {
4209 r_asm_set_pc (core->rasm, core->offset);
4210 *cols = r_asm_disassemble (core->rasm,
4211 op, core->block, 32);
4212 if (midflags || midbb) {
4213 int skip_bytes_flag = 0, skip_bytes_bb = 0;
4214 if (midflags >= R_MIDFLAGS_REALIGN) {
4215 skip_bytes_flag = r_core_flag_in_middle (core, core->offset, *cols, &midflags);
4216 }
4217 if (midbb) {
4218 skip_bytes_bb = r_core_bb_starts_in_middle (core, core->offset, *cols);
4219 }
4220 if (skip_bytes_flag) {
4221 *cols = skip_bytes_flag;
4222 }
4223 if (skip_bytes_bb && skip_bytes_bb < *cols) {
4224 *cols = skip_bytes_bb;
4225 }
4226 }
4227 }
4228 if (*cols < 1) {
4229 *cols = op->size > 1 ? op->size : 1;
4230 }
4231 }
4232
4233 #ifdef __WINDOWS__
4234
is_mintty(RCons * cons)4235 static bool is_mintty(RCons *cons) {
4236 return cons->term_xterm;
4237 }
4238
flush_stdin(void)4239 static void flush_stdin(void) {
4240 while (r_cons_readchar_timeout (1) != -1) ;
4241 }
4242
4243 #else
4244
is_mintty(RCons * cons)4245 static bool is_mintty(RCons *cons) {
4246 return false;
4247 }
4248
flush_stdin(void)4249 static void flush_stdin(void) {
4250 tcflush (STDIN_FILENO, TCIFLUSH);
4251 }
4252
4253 #endif
4254
r_core_visual(RCore * core,const char * input)4255 R_API int r_core_visual(RCore *core, const char *input) {
4256 const char *teefile;
4257 ut64 scrseek;
4258 int flags, ch;
4259 bool skip;
4260 char arg[2] = {
4261 input[0], 0
4262 };
4263
4264 splitPtr = UT64_MAX;
4265
4266 if (r_cons_get_size (&ch) < 1 || ch < 1) {
4267 eprintf ("Cannot create Visual context. Use scr.fix_{columns|rows}\n");
4268 return 0;
4269 }
4270
4271 obs = core->blocksize;
4272 //r_cons_set_cup (true);
4273
4274 core->vmode = false;
4275 /* honor vim */
4276 if (!strncmp (input, "im", 2)) {
4277 char *cmd = r_str_newf ("!v%s", input);
4278 int ret = r_core_cmd0 (core, cmd);
4279 free (cmd);
4280 return ret;
4281 }
4282 while (*input) {
4283 int len = *input == 'd'? 2: 1;
4284 if (!r_core_visual_cmd (core, input)) {
4285 return 0;
4286 }
4287 input += len;
4288 }
4289 core->vmode = true;
4290
4291 // disable tee in cons
4292 teefile = r_cons_singleton ()->teefile;
4293 r_cons_singleton ()->teefile = "";
4294
4295 static char debugstr[512];
4296 core->print->flags |= R_PRINT_FLAGS_ADDRMOD;
4297 do {
4298 dodo:
4299 r_core_visual_tab_update (core);
4300 // update the cursor when it's not visible anymore
4301 skip = fix_cursor (core);
4302 r_cons_show_cursor (false);
4303 r_cons_set_raw (1);
4304 const int ref = r_config_get_i (core->config, "dbg.slow");
4305 #if 1
4306 // This is why multiple debug views dont work
4307 if (core->printidx == R_CORE_VISUAL_MODE_DB) {
4308 const int pxa = r_config_get_i (core->config, "stack.anotated"); // stack.anotated
4309 const char *reg = r_config_get (core->config, "stack.reg");
4310 const int size = r_config_get_i (core->config, "stack.size");
4311 const int delta = r_config_get_i (core->config, "stack.delta");
4312 const char *cmdvhex = r_config_get (core->config, "cmd.stack");
4313
4314 if (cmdvhex && *cmdvhex) {
4315 snprintf (debugstr, sizeof (debugstr),
4316 "?t0;f tmp;ssr %s;%s;?1;%s;?1;"
4317 "ss tmp;f-tmp;pd $r", reg, cmdvhex,
4318 ref? "drr": "dr=");
4319 debugstr[sizeof (debugstr) - 1] = 0;
4320 } else {
4321 const char *pxw = stackPrintCommand (core);
4322 const char sign = (delta < 0)? '+': '-';
4323 const int absdelta = R_ABS (delta);
4324 snprintf (debugstr, sizeof (debugstr),
4325 "diq;?0;f tmp;ssr %s;%s %d@$$%c%d;"
4326 "?t1;%s;"
4327 "?t1;ss tmp;f-tmp;afal;pd $r",
4328 reg, pxa? "pxa": pxw, size, sign, absdelta,
4329 ref? "drr": "dr=");
4330 }
4331 printfmtSingle[2] = debugstr;
4332 }
4333 #endif
4334 r_cons_show_cursor (false);
4335 r_cons_enable_mouse (r_config_get_i (core->config, "scr.wheel"));
4336 core->cons->event_resize = NULL; // avoid running old event with new data
4337 core->cons->event_data = core;
4338 core->cons->event_resize = (RConsEvent) visual_refresh_oneshot;
4339 flags = core->print->flags;
4340 color = r_config_get_i (core->config, "scr.color");
4341 if (color) {
4342 flags |= R_PRINT_FLAGS_COLOR;
4343 }
4344 debug = r_config_get_i (core->config, "cfg.debug");
4345 flags |= R_PRINT_FLAGS_ADDRMOD | R_PRINT_FLAGS_HEADER;
4346 r_print_set_flags (core->print, flags);
4347 scrseek = r_num_math (core->num,
4348 r_config_get (core->config, "scr.seek"));
4349 if (scrseek != 0LL) {
4350 r_core_seek (core, scrseek, true);
4351 }
4352 if (debug) {
4353 r_core_cmd (core, ".dr*", 0);
4354 }
4355 #if 0
4356 cmdprompt = r_config_get (core->config, "cmd.vprompt");
4357 if (cmdprompt && *cmdprompt) {
4358 r_core_cmd (core, cmdprompt, 0);
4359 }
4360 #endif
4361 core->print->vflush = !skip;
4362 visual_refresh (core);
4363 if (insert_mode_enabled (core)) {
4364 goto dodo;
4365 }
4366 if (!skip) {
4367 if (snowMode) {
4368 ch = r_cons_readchar_timeout (300);
4369 if (ch == -1) {
4370 skip = 1;
4371 continue;
4372 }
4373 } else {
4374 ch = r_cons_readchar ();
4375 }
4376 if (I->vtmode == 2 && !is_mintty (core->cons)) {
4377 // Prevent runaway scrolling
4378 if (IS_PRINTABLE (ch) || ch == '\t' || ch == '\n') {
4379 flush_stdin ();
4380 } else if (ch == 0x1b) {
4381 char chrs[2];
4382 int chrs_read = 1;
4383 chrs[0] = r_cons_readchar ();
4384 if (chrs[0] == '[') {
4385 chrs[1] = r_cons_readchar ();
4386 chrs_read++;
4387 if (chrs[1] >= 'A' && chrs[1] <= 'D') { // arrow keys
4388 flush_stdin ();
4389 #ifndef __WINDOWS__
4390 // Following seems to fix an issue where scrolling slows
4391 // down to a crawl for some terminals after some time
4392 // mashing the up and down arrow keys
4393 r_cons_set_raw (false);
4394 r_cons_set_raw (true);
4395 #endif
4396 }
4397 }
4398 (void)r_cons_readpush (chrs, chrs_read);
4399 }
4400 }
4401 if (r_cons_is_breaked()) {
4402 break;
4403 }
4404 r_core_visual_show_char (core, ch);
4405 if (ch == -1 || ch == 4) {
4406 break; // error or eof
4407 }
4408 arg[0] = ch;
4409 arg[1] = 0;
4410 }
4411 } while (skip || (*arg && r_core_visual_cmd (core, arg)));
4412
4413 r_cons_enable_mouse (false);
4414 if (color) {
4415 r_cons_strcat (Color_RESET);
4416 }
4417 r_config_set_i (core->config, "scr.color", color);
4418 core->print->cur_enabled = false;
4419 if (autoblocksize) {
4420 r_core_block_size (core, obs);
4421 }
4422 r_cons_singleton ()->teefile = teefile;
4423 r_cons_set_cup (false);
4424 r_cons_clear00 ();
4425 core->vmode = false;
4426 core->cons->event_resize = NULL;
4427 core->cons->event_data = NULL;
4428 r_cons_show_cursor (true);
4429 return 0;
4430 }
4431
r_listinfo_new(const char * name,RInterval pitv,RInterval vitv,int perm,const char * extra)4432 R_API RListInfo *r_listinfo_new(const char *name, RInterval pitv, RInterval vitv, int perm, const char *extra) {
4433 RListInfo *info = R_NEW (RListInfo);
4434 if (info) {
4435 info->name = name ? strdup (name) : NULL;
4436 info->pitv = pitv;
4437 info->vitv = vitv;
4438 info->perm = perm;
4439 info->extra = extra ? strdup (extra) : NULL;
4440 }
4441 return info;
4442 }
4443
r_listinfo_free(RListInfo * info)4444 R_API void r_listinfo_free (RListInfo *info) {
4445 if (!info) {
4446 return;
4447 }
4448 free (info->name);
4449 free (info->extra);
4450 free (info);
4451 }
4452