1 /* radare - LGPL - Copyright 2009-2020 - pancake */
2
3 #include <r_core.h>
4 #include <r_util.h>
5 #include <string.h>
6
7 #define MAX_FORMAT 3
8
9 enum {
10 R_BYTE_DATA = 1,
11 R_WORD_DATA = 2,
12 R_DWORD_DATA = 4,
13 R_QWORD_DATA = 8
14 };
15
16 enum {
17 SORT_NONE,
18 SORT_NAME,
19 SORT_OFFSET
20 };
21
22 typedef struct {
23 RCore *core;
24 int t_idx;
25 int t_ctr;
26 const char *type;
27 char *curname;
28 char *curfmt;
29 const char *optword;
30 } RCoreVisualTypes;
31
32 // TODO: move this helper into r_cons
prompt(const char * str,const char * txt)33 static char *prompt(const char *str, const char *txt) {
34 char cmd[1024];
35 char *res = NULL;
36 char *oprompt = strdup (r_cons_singleton ()->line->prompt);
37 r_cons_show_cursor (true);
38 if (txt && *txt) {
39 free (r_cons_singleton ()->line->contents);
40 r_cons_singleton ()->line->contents = strdup (txt);
41 } else {
42 R_FREE (r_cons_singleton ()->line->contents);
43 }
44 *cmd = '\0';
45 r_line_set_prompt (str);
46 if (r_cons_fgets (cmd, sizeof (cmd), 0, NULL) < 0) {
47 *cmd = '\0';
48 }
49 //line[strlen(line)-1]='\0';
50 if (*cmd) {
51 res = strdup (cmd);
52 }
53 r_line_set_prompt (oprompt);
54 free (oprompt);
55 R_FREE (r_cons_singleton ()->line->contents);
56 return res;
57 }
58
getformat(RCoreVisualTypes * vt,const char * k)59 static inline char *getformat (RCoreVisualTypes *vt, const char *k) {
60 return sdb_get (vt->core->anal->sdb_types,
61 sdb_fmt ("type.%s", k), 0);
62 }
63
colorize_asm_string(RCore * core,const char * buf_asm,int optype,ut64 addr)64 static char *colorize_asm_string(RCore *core, const char *buf_asm, int optype, ut64 addr) {
65 char *tmp, *spacer = NULL;
66 char *source = (char*)buf_asm;
67 bool use_color = core->print->flags & R_PRINT_FLAGS_COLOR;
68 const char *color_num = core->cons->context->pal.num;
69 const char *color_reg = core->cons->context->pal.reg;
70 RAnalFunction* fcn = r_anal_get_fcn_in (core->anal, addr, R_ANAL_FCN_TYPE_NULL);
71
72 if (!use_color) {
73 return strdup (source);
74 }
75 // workaround dummy colorizer in case of paired commands (tms320 & friends)
76 spacer = strstr (source, "||");
77 if (spacer) {
78 char *s1 = r_str_ndup (source, spacer - source);
79 char *s2 = strdup (spacer + 2);
80 char *scol1 = r_print_colorize_opcode (core->print, s1, color_reg, color_num, false, fcn ? fcn->addr : 0);
81 char *scol2 = r_print_colorize_opcode (core->print, s2, color_reg, color_num, false, fcn ? fcn->addr : 0);
82 char *source = r_str_newf ("%s||%s", r_str_get (scol1), r_str_get (scol2));
83 free (scol1);
84 free (scol2);
85 free (s1);
86 free (s2);
87 return source;
88 }
89 char *res = strdup ("");
90 res = r_str_append (res, r_print_color_op_type (core->print, optype));
91 tmp = r_print_colorize_opcode (core->print, source, color_reg, color_num, false, fcn ? fcn->addr : 0);
92 res = r_str_append (res, tmp);
93 free (tmp);
94 return res;
95 }
96
rotate_nibble(const ut8 b,int dir)97 static int rotate_nibble (const ut8 b, int dir) {
98 if (dir > 0) {
99 bool high = b >> 7;
100 return (b << 1) | high;
101 }
102 bool lower = b & 1;
103 return (b >> 1) | (lower << 7);
104 }
105
wordpos(const char * esil,int n)106 static int wordpos(const char *esil, int n) {
107 const char *w = esil;
108 if (n < 1) {
109 n = 0;
110 }
111 while (w && n--) {
112 const char *nw = strchr (w + 1, ',');
113 if (!nw) {
114 return strlen (esil);
115 }
116 w = nw;
117 }
118 if (!w && n > 0) {
119 return strlen (esil);
120 }
121 return (size_t)(w - esil);
122 }
123
showreg(RAnalEsil * esil,const char * rn,const char * desc)124 static void showreg(RAnalEsil *esil, const char *rn, const char *desc) {
125 ut64 nm = 0;
126 int sz = 0;
127 r_cons_printf ("%s 0x%08"PFMT64x" (%d) ; %s\n", rn, nm, sz, desc);
128 }
129
r_core_visual_esil(RCore * core)130 R_API bool r_core_visual_esil(RCore *core) {
131 const int nbits = sizeof (ut64) * 8;
132 int analopType;
133 char *word = NULL;
134 int x = 0;
135 RAsmOp asmop;
136 RAnalOp analop;
137 ut8 buf[sizeof (ut64)];
138 unsigned int addrsize = r_config_get_i (core->config, "esil.addr.size");
139
140 if (core->blocksize < sizeof (ut64)) {
141 return false;
142 }
143 memcpy (buf, core->block, sizeof (ut64));
144 RAnalEsil *esil = r_anal_esil_new (20, 0, addrsize);
145 esil->anal = core->anal;
146 r_anal_esil_set_pc (esil, core->offset);
147 for (;;) {
148 r_cons_clear00 ();
149 // bool use_color = core->print->flags & R_PRINT_FLAGS_COLOR;
150 (void) r_asm_disassemble (core->rasm, &asmop, buf, sizeof (ut64));
151 analop.type = -1;
152 (void)r_anal_op (core->anal, &analop, core->offset, buf, sizeof (ut64), R_ANAL_OP_MASK_ESIL);
153 analopType = analop.type & R_ANAL_OP_TYPE_MASK;
154 r_cons_printf ("r2's esil debugger:\n\n");
155 r_cons_printf ("pos: %d\n", x);
156 {
157 char *op_hex = r_asm_op_get_hex (&asmop);
158 char *res = r_print_hexpair (core->print, op_hex, -1);
159 r_cons_printf ("hex: %s\n"Color_RESET, res);
160 free (res);
161 free (op_hex);
162 }
163 {
164 char *op = colorize_asm_string (core, r_asm_op_get_asm (&asmop), analopType, core->offset);
165 r_cons_printf (Color_RESET"asm: %s\n"Color_RESET, op);
166 free (op);
167 }
168 {
169 const char *expr = r_strbuf_get (&analop.esil);
170 r_cons_printf (Color_RESET"esil: %s\n"Color_RESET, expr);
171 int wp = wordpos (expr, x);
172 char *pas = strdup (r_str_pad (' ', wp ? wp + 1: 0));
173 int wp2 = wordpos (expr, x + 1);
174 free (word);
175 word = r_str_ndup (expr + (wp?(wp+1):0), (wp2 - wp) - (wp?1:0));
176 if (wp == wp2) {
177 // x --;
178 eprintf ("Done\n");
179 x = 0;
180 r_sys_sleep (1);
181 free (pas);
182 continue;
183 }
184 const char *pad = r_str_pad ('-', wp2 - ((wp > 0)? wp + 1: 0));
185 r_cons_printf (Color_RESET" %s%s\n"Color_RESET, pas, pad);
186 free (pas);
187 // free (pad);
188 }
189 r_cons_printf ("esil regs:\n");
190 showreg (esil, "$$", "address");
191 showreg (esil, "$z", "zero");
192 showreg (esil, "$b", "borrow");
193 showreg (esil, "$c", "carry");
194 showreg (esil, "$o", "overflow");
195 showreg (esil, "$p", "parity");
196 showreg (esil, "$r", "regsize");
197 showreg (esil, "$s", "sign");
198 showreg (esil, "$d", "delay");
199 showreg (esil, "$j", "jump");
200
201 r_cons_printf ("regs:\n");
202 char *r = r_core_cmd_str (core, "dr=");
203 if (r) {
204 r_cons_printf ("%s", r);
205 free (r);
206 }
207 r_cons_printf ("esil stack:\n");
208 r_anal_esil_dumpstack (esil);
209 r_anal_op_fini (&analop);
210 r_cons_newline ();
211 r_cons_visual_flush ();
212
213 int ch = r_cons_readchar ();
214 if (ch == -1 || ch == 4) {
215 break;
216 }
217 ch = r_cons_arrow_to_hjkl (ch); // get ESC+char, return 'hjkl' char
218 switch (ch) {
219 case 'Q':
220 case 'q':
221 goto beach;
222 case 's':
223 eprintf ("step ((%s))\n", word);
224 r_sys_usleep (500);
225 x = R_MIN (x + 1, nbits - 1);
226 r_anal_esil_runword (esil, word);
227 break;
228 case 'S':
229 eprintf ("esil step over :D\n");
230 r_sys_usleep (500);
231 break;
232 case 'r':
233 case 'h':
234 x = 0; //R_MAX (x - 1, 0);
235 break;
236 case '?':
237 r_cons_clear00 ();
238 r_cons_printf (
239 "Vd1?: Visual Bit Editor Help:\n\n"
240 " q - quit the bit editor\n"
241 " h/r - reset / go back (reinitialize esil state)\n"
242 " s - esil step in\n"
243 " j/k - toggle bit value (same as space key)\n"
244 " : - enter command\n");
245 r_cons_flush ();
246 r_cons_any_key (NULL);
247 break;
248 case ':': // TODO: move this into a separate helper function
249 {
250 char cmd[1024];
251 r_cons_show_cursor (true);
252 r_cons_set_raw (0);
253 *cmd = 0;
254 r_line_set_prompt (":> ");
255 if (r_cons_fgets (cmd, sizeof (cmd), 0, NULL) < 0) {
256 cmd[0] = '\0';
257 }
258 r_core_cmd_task_sync (core, cmd, 1);
259 r_cons_set_raw (1);
260 r_cons_show_cursor (false);
261 if (cmd[0]) {
262 r_cons_any_key (NULL);
263 }
264 r_cons_clear ();
265 }
266 break;
267 }
268 }
269 beach:
270 r_anal_esil_free (esil);
271 free (word);
272 return true;
273 }
274
r_core_visual_bit_editor(RCore * core)275 R_API bool r_core_visual_bit_editor(RCore *core) {
276 const int nbits = sizeof (ut64) * 8;
277 bool colorBits = false;
278 int analopType;
279 int i, j, x = 0;
280 RAsmOp asmop;
281 RAnalOp analop;
282 ut8 buf[sizeof (ut64)];
283 bool bitsInLine = false;
284
285 if (core->blocksize < sizeof (ut64)) {
286 return false;
287 }
288 int cur = 0;
289 if (core->print->cur != -1) {
290 cur = core->print->cur;
291 }
292 memcpy (buf, core->block + cur, sizeof (ut64));
293 for (;;) {
294 r_cons_clear00 ();
295 bool use_color = core->print->flags & R_PRINT_FLAGS_COLOR;
296 (void) r_asm_disassemble (core->rasm, &asmop, buf, sizeof (ut64));
297 analop.type = -1;
298 (void)r_anal_op (core->anal, &analop, core->offset, buf, sizeof (ut64), R_ANAL_OP_MASK_ESIL);
299 analopType = analop.type & R_ANAL_OP_TYPE_MASK;
300 r_cons_printf ("r2's bit editor:\n\n");
301 r_cons_printf ("offset: 0x%08"PFMT64x"\n"Color_RESET, core->offset + cur);
302 {
303 char *op_hex = r_asm_op_get_hex (&asmop);
304 char *res = r_print_hexpair (core->print, op_hex, -1);
305 r_cons_printf ("hex: %s\n"Color_RESET, res);
306 free (res);
307 free (op_hex);
308 }
309 r_cons_printf ("len: %d\n", asmop.size);
310 {
311 ut32 word = (x % 32);
312 r_cons_printf ("shift: >> %d << %d\n", word, (asmop.size * 8) - word - 1);
313 }
314 {
315 char *op = colorize_asm_string (core, r_asm_op_get_asm (&asmop), analopType, core->offset);
316 r_cons_printf (Color_RESET"asm: %s\n"Color_RESET, op);
317 free (op);
318 }
319 r_cons_printf (Color_RESET"esl: %s\n"Color_RESET, r_strbuf_get (&analop.esil));
320 r_anal_op_fini (&analop);
321 r_cons_printf ("chr:");
322 for (i = 0; i < 8; i++) {
323 const ut8 *byte = buf + i;
324 char ch = IS_PRINTABLE (*byte)? *byte: '?';
325 if (i == 4) {
326 r_cons_print (" |");
327 }
328 if (use_color) {
329 r_cons_printf (" %5s'%s%c"Color_RESET"'", " ", core->cons->context->pal.btext, ch);
330 } else {
331 r_cons_printf (" %5s'%c'", " ", ch);
332 }
333 }
334 r_cons_printf ("\ndec:");
335 for (i = 0; i < 8; i++) {
336 const ut8 *byte = buf + i;
337 if (i == 4) {
338 r_cons_print (" |");
339 }
340 r_cons_printf (" %8d", *byte);
341 }
342 r_cons_printf ("\nhex:");
343 for (i = 0; i < 8; i++) {
344 const ut8 *byte = buf + i;
345 if (i == 4) {
346 r_cons_print (" |");
347 }
348 r_cons_printf (" 0x%02x", *byte);
349 }
350 if (bitsInLine) {
351 r_cons_printf ("\nbit: ");
352 for (i = 0; i < 8; i++) {
353 ut8 *byte = buf + i;
354 if (i == 4) {
355 r_cons_print ("| ");
356 }
357 if (colorBits && i >= asmop.size) {
358 r_cons_print (Color_RESET);
359 colorBits = false;
360 }
361 for (j = 0; j < 8; j++) {
362 bool bit = R_BIT_CHK (byte, 7 - j);
363 r_cons_printf ("%d", bit? 1: 0);
364 }
365 r_cons_print (" ");
366 }
367 } else {
368 int set;
369 const char *ws = r_config_get_i (core->config, "scr.utf8")? "·": " ";
370 for (set = 1; set >= 0 ; set--) {
371 r_cons_printf ("\nbit: ");
372 for (i = 0; i < 8; i++) {
373 ut8 *byte = buf + i;
374 if (i == 4) {
375 r_cons_print ("| ");
376 }
377 if (colorBits && i >= asmop.size) {
378 r_cons_print (Color_RESET);
379 colorBits = false;
380 }
381 for (j = 0; j < 8; j++) {
382 bool bit = R_BIT_CHK (byte, 7 - j);
383 if (set && bit) {
384 r_cons_print ("1");
385 } else if (!set && !bit) {
386 r_cons_print ("0");
387 } else {
388 r_cons_print (ws);
389 }
390 }
391 r_cons_print (" ");
392 }
393 }
394 }
395 r_cons_newline ();
396 char str_pos[128];
397 memset (str_pos, '-', nbits + 9);
398 int pos = x;
399 if (pos > 31) {
400 pos += 2;
401 }
402 str_pos[pos + (x / 8)] = '^';
403 str_pos[nbits + 9] = 0;
404 str_pos[8] = ' ';
405 str_pos[17] = ' ';
406 str_pos[26] = ' ';
407 str_pos[35] = ' ';
408 str_pos[36] = ' ';
409 str_pos[37] = ' ';
410 str_pos[46] = ' ';
411 str_pos[55] = ' ';
412 str_pos[64] = ' ';
413 r_cons_printf ("pos: %s\n", str_pos);
414 r_cons_newline ();
415 r_cons_visual_flush ();
416
417 int ch = r_cons_readchar ();
418 if (ch == -1 || ch == 4) {
419 break;
420 }
421 if (ch != 10) {
422 ch = r_cons_arrow_to_hjkl (ch); // get ESC+char, return 'hjkl' char
423 }
424 switch (ch) {
425 case 'Q':
426 case 'q':
427 {
428 char *op_hex = r_asm_op_get_hex (&asmop);
429 char *res = r_print_hexpair (core->print, op_hex, -1);
430 r_core_cmdf (core, "wx %02x%02x%02x%02x", buf[0], buf[1], buf[2], buf[3]);
431 free (res);
432 free (op_hex);
433 }
434 return false;
435 case 'H':
436 {
437 int y = R_MAX (x - 8, 0);
438 x = y - y%8;
439 }
440 break;
441 case 'L':
442 case 9:
443 {
444 int y = R_MIN (x + 8, nbits - 8);
445 x = y - y%8;
446 }
447 break;
448 case 'j':
449 case 'k':
450 case 10:
451 case ' ':
452 //togglebit();
453 {
454 const int nbyte = x / 8;
455 const int nbit = 7 - (x - (nbyte * 8));
456 ut8 *byte = buf + nbyte;
457 bool bit = R_BIT_CHK (byte, nbit);
458 if (bit) {
459 R_BIT_UNSET (byte, nbit);
460 } else {
461 R_BIT_SET (byte, nbit);
462 }
463 }
464 break;
465 case '>':
466 buf[x/8] = rotate_nibble (buf [(x / 8)], -1);
467 break;
468 case '<':
469 buf[x/8] = rotate_nibble (buf [(x / 8)], 1);
470 break;
471 case 'i':
472 {
473 r_line_set_prompt ("> ");
474 const char *line = r_line_readline ();
475 ut64 num = r_num_math (core->num, line);
476 if (num || (!num && *line == '0')) {
477 buf[x/8] = num;
478 }
479 }
480 break;
481 case 'R':
482 if (r_config_get_i (core->config, "scr.randpal")) {
483 r_core_cmd0 (core, "ecr");
484 } else {
485 r_core_cmd0 (core, "ecn");
486 }
487 break;
488 case '+':
489 buf[(x/8)]++;
490 break;
491 case '-':
492 buf[(x/8)]--;
493 break;
494 case 'h':
495 x = R_MAX (x - 1, 0);
496 break;
497 case 'l':
498 x = R_MIN (x + 1, nbits - 1);
499 break;
500 case 'b':
501 bitsInLine = !bitsInLine;
502 break;
503 case '?':
504 r_cons_clear00 ();
505 r_cons_printf (
506 "Vd1?: Visual Bit Editor Help:\n\n"
507 " q - quit the bit editor\n"
508 " R - randomize color palette\n"
509 " b - toggle bitsInLine\n"
510 " j/k - toggle bit value (same as space key)\n"
511 " h/l - select next/previous bit\n"
512 " +/- - increment or decrement byte value\n"
513 " </> - rotate left/right byte value\n"
514 " i - insert numeric value of byte\n"
515 " : - enter command\n");
516 r_cons_flush ();
517 r_cons_any_key (NULL);
518 break;
519 case ':': // TODO: move this into a separate helper function
520 {
521 char cmd[1024];
522 r_cons_show_cursor (true);
523 r_cons_set_raw (0);
524 cmd[0]='\0';
525 r_line_set_prompt (":> ");
526 if (r_cons_fgets (cmd, sizeof (cmd), 0, NULL) < 0) {
527 cmd[0] = '\0';
528 }
529 r_core_cmd (core, cmd, 1);
530 r_cons_set_raw (1);
531 r_cons_show_cursor (false);
532 if (cmd[0]) {
533 r_cons_any_key (NULL);
534 }
535 r_cons_clear ();
536 }
537 break;
538 }
539 }
540 return true;
541 }
542
543 // belongs to r_core_visual_types
sdbforcb(void * p,const char * k,const char * v)544 static bool sdbforcb (void *p, const char *k, const char *v) {
545 const char *pre = " ";
546 RCoreVisualTypes *vt = (RCoreVisualTypes*)p;
547 bool use_color = vt->core->print->flags & R_PRINT_FLAGS_COLOR;
548 char *color_sel = vt->core->cons->context->pal.prompt;
549 if (vt->optword) {
550 if (!strcmp (vt->type, "struct")) {
551 char *s = r_str_newf ("struct.%s.", vt->optword);
552 /* enum */
553 if (!strncmp (s, k, strlen (s))) {
554 if (vt->t_idx == vt->t_ctr) {
555 free (vt->curname);
556 vt->curname = strdup (k);
557 free (vt->curfmt);
558 vt->curfmt = strdup (v);
559 pre = ">";
560 }
561 if (use_color && *pre == '>') {
562 r_cons_printf ("%s %s %s %s %10s\n", color_sel,
563 Color_RESET, pre, k+strlen (s), v);
564 } else {
565 r_cons_printf (" %s %s %10s\n",
566 pre, k + strlen (s), v);
567 }
568 vt->t_ctr ++;
569 }
570 free (s);
571 } else {
572 char *s = r_str_newf ("%s.", vt->optword);
573 /* enum */
574 if (!strncmp (s, k, strlen (s))) {
575 if (!strstr (k, ".0x")) {
576 if (vt->t_idx == vt->t_ctr) {
577 free (vt->curname);
578 vt->curname = strdup (v);
579 free (vt->curfmt);
580 vt->curfmt = strdup (v);
581 pre = ">";
582 }
583 if (use_color && *pre=='>') {
584 r_cons_printf ("%s"Color_RESET" %s %s %s\n", color_sel,
585 pre, k, v);
586 } else {
587 r_cons_printf (" %s %s %s\n",
588 pre, k, v);
589 }
590 vt->t_ctr ++;
591 }
592 }
593 free (s);
594 }
595 } else if (!strcmp (v, vt->type)) {
596 if (!strcmp (vt->type, "type")) {
597 char *fmt = getformat (vt, k);
598 if (vt->t_idx == vt->t_ctr) {
599 free (vt->curname);
600 vt->curname = strdup (k);
601 free (vt->curfmt);
602 vt->curfmt = strdup (fmt);
603 pre = ">";
604 }
605 if (use_color && *pre == '>') {
606 r_cons_printf ("%s %s pf %3s %s\n"Color_RESET,
607 color_sel, pre, fmt, k);
608 } else {
609 r_cons_printf (" %s pf %3s %s\n",
610 pre, fmt, k);
611 }
612 free (fmt);
613 } else {
614 if (vt->t_idx == vt->t_ctr) {
615 free (vt->curname);
616 vt->curname = strdup (k);
617 free (vt->curfmt);
618 vt->curfmt = strdup (v);
619 pre = ">";
620 }
621 if (use_color && *pre == '>') {
622 r_cons_printf ("%s %s %s\n"Color_RESET, color_sel,
623 (vt->t_idx == vt->t_ctr)?
624 ">":" ", k);
625 } else {
626 r_cons_printf (" %s %s\n",
627 (vt->t_idx == vt->t_ctr)?
628 ">":" ", k);
629 }
630 }
631 vt->t_ctr ++;
632 }
633 return true;
634 }
635
r_core_visual_types(RCore * core)636 R_API int r_core_visual_types(RCore *core) {
637 RCoreVisualTypes vt = {core, 0, 0};
638 int i, ch;
639 int _option = 0;
640 int option = 0;
641 char *txt;
642 char cmd[1024];
643 int menu = 0;
644 int h_opt = 0;
645 char *optword = NULL;
646 const char *opts[] = {
647 "type",
648 "enum",
649 "struct",
650 "func",
651 "union",
652 "cc",
653 NULL
654 };
655 bool use_color = core->print->flags & R_PRINT_FLAGS_COLOR;
656 if (r_flag_space_is_empty (core->flags)) {
657 menu = 1;
658 }
659 for (;;) {
660 r_cons_clear00 ();
661 for (i = 0; opts[i]; i++) {
662 if (use_color) {
663 if (h_opt == i) {
664 r_cons_printf ("%s[%s]%s ", core->cons->context->pal.call,
665 opts[i], Color_RESET);
666 } else {
667 r_cons_printf ("%s%s%s ", core->cons->context->pal.other,
668 opts[i], Color_RESET);
669 }
670 } else {
671 r_cons_printf (h_opt == i ? "[%s] " : " %s ", opts[i]);
672 }
673 }
674 r_cons_newline ();
675 if (optword) {
676 r_cons_printf (">> %s\n", optword);
677 }
678 if (!strcmp (opts[h_opt], "cc")) {
679 // XXX TODO: make this work (select with cursor, to delete, or add a new one with 'i', etc)
680 r_core_cmdf (core, "tfcl");
681 } else {
682 vt.t_idx = option;
683 vt.t_ctr = 0;
684 vt.type = opts[h_opt];
685 vt.optword = optword;
686 sdb_foreach (core->anal->sdb_types, sdbforcb, &vt);
687 }
688
689 r_cons_visual_flush ();
690 ch = r_cons_readchar ();
691 if (ch == -1 || ch == 4) {
692 return false;
693 }
694 ch = r_cons_arrow_to_hjkl (ch); // get ESC+char, return 'hjkl' char
695 switch (ch) {
696 case 'h':
697 h_opt--;
698 if (h_opt < 0) {
699 h_opt = 0;
700 }
701 option = 0;
702 R_FREE (optword);
703 break;
704 case 'l':
705 h_opt++;
706 option = 0;
707 if (!opts[h_opt]) {
708 h_opt--;
709 }
710 R_FREE (optword);
711 break;
712 case 'o':
713 {
714 char *file = prompt ("Filename: ", NULL);
715 if (file) {
716 r_core_cmdf (core, "\"to %s\"", file);
717 free (file);
718 }
719 }
720 break;
721 case 'j':
722 if (++option >= vt.t_ctr) {
723 option = vt.t_ctr - 1;
724 }
725 break;
726 case 'J':
727 option += 10;
728 if (option >= vt.t_ctr) {
729 option = vt.t_ctr-1;
730 }
731 break;
732 case 'k':
733 if (--option < 0) {
734 option = 0;
735 }
736 break;
737 case 'K':
738 option -= 10;
739 if (option < 0) {
740 option = 0;
741 }
742 break;
743 case 'b':
744 r_core_cmdf (core, "tl %s", vt.curname);
745 break;
746 case -1: // EOF
747 case 'Q':
748 case 'q':
749 if (optword) {
750 R_FREE (optword);
751 break;
752 }
753 if (menu <= 0) {
754 return true;
755 }
756 menu--;
757 option = _option;
758 if (menu==0) {
759 // if no flagspaces, just quit
760 if (r_flag_space_is_empty (core->flags)) {
761 return true;
762 }
763 }
764 break;
765 case 'a':
766 {
767 txt = prompt ("add C type: ", NULL);
768 if (txt) {
769 r_core_cmdf (core, "\"td %s\"", txt);
770 free (txt);
771 }
772 }
773 break;
774 case 'd':
775 r_core_cmdf (core, "t- %s", vt.curname);
776 break;
777 case '-':
778 r_core_cmd0 (core, "to -");
779 break;
780 case ' ':
781 case '\r':
782 case '\n':
783 case 'e':
784 if (optword) {
785 /* TODO: edit field */
786 } else {
787 switch (h_opt) {
788 case 0: { // type
789 /* TODO: do something with this data */
790 char *r = NULL;
791 r = prompt ("name: ", vt.curname);
792 free (r);
793 r = prompt ("pf: ", vt.curfmt);
794 free (r);
795 break;
796 }
797 case 1: // enum
798 case 2: // struct
799 free (optword);
800 if (vt.curname) {
801 optword = strdup (vt.curname);
802 } else {
803 optword = NULL;
804 }
805 break;
806 default:
807 break;
808 }
809 }
810 break;
811 case '?':
812 r_cons_clear00 ();
813 r_cons_printf (
814 "Vt?: Visual Types Help:\n\n"
815 " q - quit menu\n"
816 " j/k - down/up keys\n"
817 " h/l - left-right\n"
818 " a - add new type (C syntax)\n"
819 " b - bind type to current offset\n"
820 " d - delete current type\n"
821 " e - edit current type\n"
822 " o - open .h include file\n"
823 " - - Open cfg.editor to load types\n"
824 " : - enter command\n");
825 r_cons_flush ();
826 r_cons_any_key (NULL);
827 break;
828 case ':':
829 r_cons_show_cursor (true);
830 r_cons_set_raw (0);
831 cmd[0] = '\0';
832 r_line_set_prompt (":> ");
833 if (r_cons_fgets (cmd, sizeof (cmd), 0, NULL) < 0) {
834 cmd[0]='\0';
835 }
836 r_core_cmd (core, cmd, 1);
837 r_cons_set_raw (1);
838 r_cons_show_cursor (false);
839 if (cmd[0]) {
840 r_cons_any_key (NULL);
841 }
842 r_cons_clear ();
843 continue;
844 }
845 }
846 return true;
847 }
848
r_core_visual_hudclasses(RCore * core)849 R_API bool r_core_visual_hudclasses(RCore *core) {
850 RListIter *iter, *iter2;
851 RBinClass *c;
852 RBinField *f;
853 RBinSymbol *m;
854 ut64 addr;
855 char *res;
856 RList *list = r_list_new ();
857 if (!list) {
858 return false;
859 }
860 list->free = free;
861 RList *classes = r_bin_get_classes (core->bin);
862 r_list_foreach (classes, iter, c) {
863 r_list_foreach (c->fields, iter2, f) {
864 r_list_append (list, r_str_newf ("0x%08"PFMT64x" %s %s",
865 f->vaddr, c->name, f->name));
866 }
867 r_list_foreach (c->methods, iter2, m) {
868 const char *name = m->dname? m->dname: m->name;
869 r_list_append (list, r_str_newf ("0x%08"PFMT64x" %s %s",
870 m->vaddr, c->name, name));
871 }
872 }
873 res = r_cons_hud (list, NULL);
874 if (res) {
875 char *p = strchr (res, ' ');
876 if (p) {
877 *p = 0;
878 }
879 addr = r_num_get (NULL, res);
880 r_core_seek (core, addr, true);
881 free (res);
882 }
883 r_list_free (list);
884 return res != NULL;
885 }
886
hudstuff_append(RFlagItem * fi,void * user)887 static bool hudstuff_append(RFlagItem *fi, void *user) {
888 RList *list = (RList *)user;
889 char *s = r_str_newf ("0x%08"PFMT64x" %s", fi->offset, fi->name);
890 if (s) {
891 r_list_append (list, s);
892 }
893 return true;
894 }
895
r_core_visual_hudstuff(RCore * core)896 R_API bool r_core_visual_hudstuff(RCore *core) {
897 ut64 addr;
898 char *res;
899 RList *list = r_list_new ();
900 if (!list) {
901 return false;
902 }
903 list->free = free;
904 r_flag_foreach (core->flags, hudstuff_append, list);
905 RIntervalTreeIter it;
906 RAnalMetaItem *mi;
907 r_interval_tree_foreach (&core->anal->meta, it, mi) {
908 if (mi->type == R_META_TYPE_COMMENT) {
909 char *s = r_str_newf ("0x%08"PFMT64x" %s", r_interval_tree_iter_get (&it)->start, mi->str);
910 if (s) {
911 r_list_push (list, s);
912 }
913 }
914 }
915 res = r_cons_hud (list, NULL);
916 if (res) {
917 char *p = strchr (res, ' ');
918 if (p) {
919 *p = 0;
920 }
921 addr = r_num_get (NULL, res);
922 r_core_seek (core, addr, true);
923 free (res);
924 }
925 r_list_free (list);
926 return res != NULL;
927 }
928
r_core_visual_config_hud(RCore * core)929 static bool r_core_visual_config_hud(RCore *core) {
930 RListIter *iter;
931 RConfigNode *bt;
932 RList *list = r_list_new ();
933 if (!list) {
934 return false;
935 }
936 list->free = free;
937 r_list_foreach (core->config->nodes, iter, bt) {
938 r_list_append (list, r_str_newf ("%s %s", bt->name, bt->value));
939 }
940 char *res = r_cons_hud (list, NULL);
941 if (res) {
942 const char *oldvalue = NULL;
943 char cmd[512];
944 char *p = strchr (res, ' ');
945 if (p) {
946 *p = 0;
947 }
948 oldvalue = r_config_get (core->config, res);
949 r_cons_show_cursor (true);
950 r_cons_set_raw (false);
951 cmd[0] = '\0';
952 eprintf ("Set new value for %s (old=%s)\n", res, oldvalue);
953 r_line_set_prompt (":> ");
954 if (r_cons_fgets (cmd, sizeof (cmd), 0, NULL) < 0) {
955 cmd[0] = '\0';
956 }
957 r_config_set (core->config, res, cmd);
958 r_cons_set_raw (true);
959 r_cons_show_cursor (false);
960 }
961 r_list_free (list);
962 return true;
963 }
964
965 // TODO: skip N first elements
966 // TODO: show only N elements of the list
967 // TODO: wrap index when out of boundaries
968 // TODO: Add support to show class fields too
969 // Segfaults - stack overflow, because of recursion
show_class(RCore * core,int mode,int * idx,RBinClass * _c,const char * grep,RList * list)970 static void *show_class(RCore *core, int mode, int *idx, RBinClass *_c, const char *grep, RList *list) {
971 bool show_color = r_config_get_i (core->config, "scr.color");
972 RListIter *iter;
973 RBinClass *c, *cur = NULL;
974 RBinSymbol *m, *mur = NULL;
975 RBinField *f, *fur = NULL;
976 int i = 0;
977 int skip = *idx - 10;
978 bool found = false;
979
980 switch (mode) {
981 case 'c':
982 r_cons_printf ("[hjkl_/Cfm]> classes:\n\n");
983 r_list_foreach (list, iter, c) {
984 if (grep) {
985 if (!r_str_casestr (c->name, grep)) {
986 i++;
987 continue;
988 }
989 } else {
990 if (*idx > 10) {
991 skip--;
992 if (skip > 0) {
993 i++;
994 continue;
995 }
996 }
997 }
998 if (show_color) {
999 if (i == *idx) {
1000 const char *clr = Color_BLUE;
1001 r_cons_printf (Color_GREEN ">>" Color_RESET " %02d %s0x%08"
1002 PFMT64x Color_YELLOW " %s\n" Color_RESET,
1003 i, clr, c->addr, c->name);
1004 } else {
1005 r_cons_printf ("- %02d %s0x%08"PFMT64x Color_RESET" %s\n",
1006 i, core->cons->context->pal.offset, c->addr, c->name);
1007 }
1008 } else {
1009 r_cons_printf ("%s %02d 0x%08"PFMT64x" %s\n",
1010 (i==*idx)?">>":"- ", i, c->addr, c->name);
1011 }
1012 if (i++ == *idx) {
1013 cur = c;
1014 }
1015 found = true;
1016 }
1017 if (!cur) {
1018 *idx = i - 1;
1019 if (!found) {
1020 return NULL;
1021 }
1022 // r_cons_clear00 ();
1023 return NULL; // show_class (core, mode, idx, _c, "", list);
1024 }
1025 return cur;
1026 case 'f':
1027 // show fields
1028 r_cons_printf ("[hjkl_/cFm]> fields of %s:\n\n", _c->name);
1029 r_list_foreach (_c->fields, iter, f) {
1030 const char *name = f->name;
1031 if (grep) {
1032 if (!r_str_casestr (name, grep)) {
1033 i++;
1034 continue;
1035 }
1036 } else {
1037 if (*idx > 10) {
1038 skip--;
1039 if (skip > 0) {
1040 i++;
1041 continue;
1042 }
1043 }
1044 }
1045
1046 char *mflags = strdup ("");
1047
1048 if (r_str_startswith (name, _c->name)) {
1049 name += strlen (_c->name);
1050 }
1051 if (show_color) {
1052 if (i == *idx) {
1053 const char *clr = Color_BLUE;
1054 r_cons_printf (Color_GREEN ">>" Color_RESET " %02d %s0x%08"
1055 PFMT64x Color_YELLOW " %s %s\n" Color_RESET,
1056 i, clr, f->vaddr, mflags, name);
1057 } else {
1058 r_cons_printf ("- %02d %s0x%08"PFMT64x Color_RESET" %s %s\n",
1059 i, core->cons->context->pal.offset, f->vaddr, mflags, name);
1060 }
1061 } else {
1062 r_cons_printf ("%s %02d 0x%08"PFMT64x" %s %s\n",
1063 (i==*idx)? ">>": "- ", i, f->vaddr, mflags, name);
1064 }
1065
1066 R_FREE (mflags);
1067
1068 if (i++ == *idx) {
1069 fur = f;
1070 }
1071 }
1072 if (!fur) {
1073 *idx = i - 1;
1074 if (r_list_empty (_c->fields)) {
1075 return NULL;
1076 }
1077 // r_cons_clear00 ();
1078 return NULL; // show_class (core, mode, idx, _c, grep, list);
1079 }
1080 return fur;
1081 break;
1082 case 'm':
1083 // show methods
1084 if (!_c) {
1085 eprintf ("No class selected.\n");
1086 return mur;
1087 }
1088 r_cons_printf ("[hjkl_/cfM]> methods of %s\n\n", _c->name);
1089 r_list_foreach (_c->methods, iter, m) {
1090 const char *name = m->dname? m->dname: m->name;
1091 char *mflags;
1092 if (grep) {
1093 if (!r_str_casestr (name, grep)) {
1094 i++;
1095 continue;
1096 }
1097 } else {
1098 if (*idx > 10) {
1099 skip--;
1100 if (skip > 0) {
1101 i++;
1102 continue;
1103 }
1104 }
1105 }
1106
1107 mflags = r_core_bin_method_flags_str (m->method_flags, 0);
1108
1109 if (show_color) {
1110 if (r_str_startswith (name, _c->name)) {
1111 name += strlen (_c->name);
1112 }
1113 if (i == *idx) {
1114 const char *clr = Color_BLUE;
1115 r_cons_printf (Color_GREEN ">>" Color_RESET " %02d %s0x%08"
1116 PFMT64x Color_YELLOW " %s %s\n" Color_RESET,
1117 i, clr, m->vaddr, mflags, name);
1118 } else {
1119 r_cons_printf ("- %02d %s0x%08"PFMT64x Color_RESET" %s %s\n",
1120 i, core->cons->context->pal.offset, m->vaddr, mflags, name);
1121 }
1122 } else {
1123 r_cons_printf ("%s %02d 0x%08"PFMT64x" %s %s\n",
1124 (i==*idx)? ">>": "- ", i, m->vaddr, mflags, name);
1125 }
1126
1127 R_FREE (mflags);
1128
1129 if (i++ == *idx) {
1130 mur = m;
1131 }
1132 }
1133 if (!mur) {
1134 *idx = i - 1;
1135 if (r_list_empty (_c->methods)) {
1136 return NULL;
1137 }
1138 // r_cons_clear00 ();
1139 return NULL; // show_class (core, mode, idx, _c, grep, list);
1140 }
1141 return mur;
1142 }
1143 return NULL;
1144 }
1145
r_core_visual_classes(RCore * core)1146 R_API int r_core_visual_classes(RCore *core) {
1147 int ch, index = 0;
1148 char cmd[1024];
1149 int mode = 'c';
1150 RBinClass *cur = NULL;
1151 RBinSymbol *mur = NULL;
1152 RBinField *fur = NULL;
1153 void *ptr;
1154 int oldcur = 0;
1155 char *grep = NULL;
1156 bool grepmode = false;
1157 RList *list = r_bin_get_classes (core->bin);
1158 if (r_list_empty (list)) {
1159 r_cons_message ("No Classes");
1160 return false;
1161 }
1162 for (;;) {
1163 int cols;
1164 r_cons_clear00 ();
1165 if (grepmode) {
1166 r_cons_printf ("Grep: %s\n", r_str_get (grep));
1167 }
1168 ptr = show_class (core, mode, &index, cur, grep, list);
1169 switch (mode) {
1170 case 'f':
1171 fur = (RBinField*)ptr;
1172 break;
1173 case 'm':
1174 mur = (RBinSymbol*)ptr;
1175 break;
1176 case 'c':
1177 cur = (RBinClass*)ptr;
1178 break;
1179 }
1180
1181 /* update terminal size */
1182 (void) r_cons_get_size (&cols);
1183 r_cons_visual_flush ();
1184 ch = r_cons_readchar ();
1185 if (ch == -1 || ch == 4) {
1186 R_FREE (grep);
1187 return false;
1188 }
1189
1190 if (grepmode) {
1191 switch (ch) {
1192 case 127:
1193 if (grep) {
1194 int len = strlen (grep);
1195 if (len < 1) {
1196 grepmode = false;
1197 } else {
1198 grep[len - 1] = 0;
1199 }
1200 }
1201 break;
1202 case ' ':
1203 case '\r':
1204 case '\n':
1205 R_FREE (grep);
1206 grepmode = false;
1207 break;
1208 default:
1209 grep = grep
1210 ? r_str_appendf (grep, "%c", ch)
1211 : r_str_newf ("%c", ch);
1212 break;
1213 }
1214 continue;
1215 }
1216
1217 ch = r_cons_arrow_to_hjkl (ch); // get ESC+char, return 'hjkl' char
1218 switch (ch) {
1219 case 'C':
1220 r_config_toggle (core->config, "scr.color");
1221 break;
1222 case '_':
1223 if (r_core_visual_hudclasses (core)) {
1224 return true;
1225 }
1226 break;
1227 case 'J': index += 10; break;
1228 case 'j': index++; break;
1229 case 'k':
1230 if (--index < 0) {
1231 index = 0;
1232 }
1233 break;
1234 case 'K':
1235 index -= 10;
1236 if (index < 0) {
1237 index = 0;
1238 }
1239 break;
1240 case 'g':
1241 index = 0;
1242 break;
1243 case 'G':
1244 index = r_list_length (list) - 1;
1245 break;
1246 case 'i':
1247 {
1248 char *num = prompt ("Index:", NULL);
1249 if (num) {
1250 index = atoi (num);
1251 free (num);
1252 }
1253 }
1254 break;
1255 case 'p':
1256 if (mode == 'm' && mur) {
1257 r_core_seek (core, mur->vaddr, true);
1258 r_core_cmd0 (core, "af;pdf~..");
1259 }
1260 break;
1261 case 'm': // methods
1262 mode = 'm';
1263 break;
1264 case 'f': // fields
1265 mode = 'f';
1266 break;
1267 case 'h':
1268 case 127: // backspace
1269 case 'b': // back
1270 case 'Q':
1271 case 'c':
1272 case 'q':
1273 if (mode == 'c') {
1274 return true;
1275 }
1276 mode = 'c';
1277 index = oldcur;
1278 break;
1279 case '/':
1280 grepmode = true;
1281 break;
1282 case 'l':
1283 case ' ':
1284 case '\r':
1285 case '\n':
1286 if (mur && mode == 'm') {
1287 r_core_seek (core, mur->vaddr, true);
1288 return true;
1289 }
1290 if (fur) {
1291 r_core_seek (core, fur->vaddr, true);
1292 return true;
1293 }
1294 if (cur) {
1295 oldcur = index;
1296 index = 0;
1297 mode = 'm';
1298 }
1299 break;
1300 case '?':
1301 r_cons_clear00 ();
1302 r_cons_printf (
1303 "\nVF: Visual Classes help:\n\n"
1304 " q - quit menu\n"
1305 " j/k - down/up keys\n"
1306 " h/b - go back\n"
1307 " g/G - go first/last item\n"
1308 " i - specify index\n"
1309 " / - grep mode\n"
1310 " C - toggle colors\n"
1311 " f - show class fields\n"
1312 " m - show class methods\n"
1313 " l/' ' - accept current selection\n"
1314 " p - preview method disasm with less\n"
1315 " : - enter command\n");
1316 r_cons_flush ();
1317 r_cons_any_key (NULL);
1318 break;
1319 case ':':
1320 r_cons_show_cursor (true);
1321 r_cons_set_raw (0);
1322 cmd[0] = '\0';
1323 r_line_set_prompt (":> ");
1324 if (r_cons_fgets (cmd, sizeof (cmd), 0, NULL) < 0) {
1325 cmd[0]='\0';
1326 }
1327 //line[strlen(line)-1]='\0';
1328 r_core_cmd (core, cmd, 1);
1329 r_cons_set_raw (1);
1330 r_cons_show_cursor (false);
1331 if (cmd[0]) {
1332 r_cons_any_key (NULL);
1333 }
1334 //cons_gotoxy(0,0);
1335 r_cons_clear ();
1336 break;
1337 }
1338 }
1339 return true;
1340 }
1341
anal_class_print(RAnal * anal,const char * class_name)1342 static void anal_class_print(RAnal *anal, const char *class_name) {
1343 RVector *bases = r_anal_class_base_get_all (anal, class_name);
1344 RVector *vtables = r_anal_class_vtable_get_all (anal, class_name);
1345 RVector *methods = r_anal_class_method_get_all (anal, class_name);
1346
1347 r_cons_print (class_name);
1348 if (bases) {
1349 RAnalBaseClass *base;
1350 bool first = true;
1351 r_vector_foreach (bases, base) {
1352 if (first) {
1353 r_cons_print (": ");
1354 first = false;
1355 } else {
1356 r_cons_print (", ");
1357 }
1358 r_cons_print (base->class_name);
1359 }
1360 r_vector_free (bases);
1361 }
1362
1363 r_cons_print ("\n");
1364
1365
1366 if (vtables) {
1367 RAnalVTable *vtable;
1368 r_vector_foreach (vtables, vtable) {
1369 r_cons_printf (" %2s vtable 0x%"PFMT64x" @ +0x%"PFMT64x" size:+0x%"PFMT64x"\n", vtable->id, vtable->addr, vtable->offset, vtable->size);
1370 }
1371 r_vector_free (vtables);
1372 }
1373
1374 r_cons_print ("\n");
1375
1376 if (methods) {
1377 RAnalMethod *meth;
1378 r_vector_foreach (methods, meth) {
1379 r_cons_printf (" %s @ 0x%"PFMT64x, meth->name, meth->addr);
1380 if (meth->vtable_offset >= 0) {
1381 r_cons_printf (" (vtable + 0x%"PFMT64x")\n", (ut64)meth->vtable_offset);
1382 } else {
1383 r_cons_print ("\n");
1384 }
1385 }
1386 r_vector_free (methods);
1387 }
1388 }
1389
show_anal_classes(RCore * core,char mode,int * idx,SdbList * list,const char * class_name)1390 static const char *show_anal_classes(RCore *core, char mode, int *idx, SdbList *list, const char *class_name) {
1391 bool show_color = r_config_get_i (core->config, "scr.color");
1392 SdbListIter *iter;
1393 SdbKv *kv;
1394 int i = 0;
1395 int skip = *idx - 10;
1396 const char * cur_class = NULL;
1397 r_cons_printf ("[hjkl_/Cfm]> anal classes:\n\n");
1398
1399 if (mode == 'd' && class_name) {
1400 anal_class_print (core->anal, class_name);
1401 return class_name;
1402 }
1403
1404 ls_foreach (list, iter, kv) {
1405 if (*idx > 10) {
1406 skip--;
1407 if (skip > 0) {
1408 i++;
1409 continue;
1410 }
1411 }
1412 class_name = sdbkv_key (kv);
1413
1414 if (show_color) {
1415 const char *pointer = "- ";
1416 const char *txt_clr = "";
1417
1418 if (i == *idx) {
1419 pointer = Color_GREEN ">>";
1420 txt_clr = Color_YELLOW;
1421 cur_class = class_name;
1422 }
1423 r_cons_printf ("%s" Color_RESET " %02d"
1424 " %s%s\n" Color_RESET, pointer, i, txt_clr, class_name);
1425 } else {
1426 r_cons_printf ("%s %02d %s\n", (i==*idx) ? ">>" : "- ", i, class_name);
1427 }
1428
1429 i++;
1430 }
1431
1432 return cur_class;
1433 }
1434 // TODO add other commands that Vbc has
1435 // Should the classes be refreshed after command execution with :
1436 // in case new class information would be added?
1437 // Add grep?
r_core_visual_anal_classes(RCore * core)1438 R_API int r_core_visual_anal_classes(RCore *core) {
1439 int ch, index = 0;
1440 char command[1024];
1441 SdbList *list = r_anal_class_get_all (core->anal, true);
1442 int oldcur = 0;
1443 char mode = ' ';
1444 const char *class_name = "";
1445
1446 if (r_list_empty (list)) {
1447 r_cons_message ("No Classes");
1448 goto cleanup;
1449 }
1450 for (;;) {
1451 int cols;
1452 r_cons_clear00 ();
1453
1454 class_name = show_anal_classes (core, mode, &index, list, class_name);
1455
1456 /* update terminal size */
1457 (void) r_cons_get_size (&cols);
1458 r_cons_visual_flush ();
1459 ch = r_cons_readchar ();
1460 if (ch == -1 || ch == 4) {
1461 goto cleanup;
1462 }
1463
1464 ch = r_cons_arrow_to_hjkl (ch); // get ESC+char, return 'hjkl' char
1465 switch (ch) {
1466 case 'C':
1467 r_config_toggle (core->config, "scr.color");
1468 break;
1469 case 'J':
1470 index += 10;
1471 if (index >= list->length) {
1472 index = list->length -1;
1473 }
1474 break;
1475 case 'j':
1476 if (++index >= list->length) {
1477 index = 0;
1478 }
1479 break;
1480 case 'k':
1481 if (--index < 0) {
1482 index = list->length - 1;
1483 }
1484 break;
1485 case 'K':
1486 index -= 10;
1487 if (index < 0) {
1488 index = 0;
1489 }
1490 break;
1491 case 'g':
1492 index = 0;
1493 break;
1494 case 'G':
1495 index = list->length - 1;
1496 break;
1497 case 'h':
1498 case 127: // backspace
1499 case 'b': // back
1500 case 'Q':
1501 case 'c':
1502 case 'q':
1503 if (mode == ' ') {
1504 goto cleanup;
1505 }
1506 mode = ' ';
1507 index = oldcur;
1508 break;
1509 case 'l':
1510 case ' ':
1511 case '\r':
1512 case '\n':
1513 mode = 'd';
1514 break;
1515 case '?':
1516 r_cons_clear00 ();
1517 r_cons_printf (
1518 "\nVF: Visual Classes help:\n\n"
1519 " q - quit menu\n"
1520 " j/k - down/up keys\n"
1521 " h/b - go back\n"
1522 " g/G - go first/last item\n"
1523 " l/' ' - accept current selection\n"
1524 " : - enter command\n");
1525 r_cons_flush ();
1526 r_cons_any_key (NULL);
1527 break;
1528 case ':':
1529 r_cons_show_cursor (true);
1530 r_cons_set_raw (0);
1531 command[0] = '\0';
1532 r_line_set_prompt (":> ");
1533 if (r_cons_fgets (command, sizeof (command), 0, NULL) < 0) {
1534 command[0]='\0';
1535 }
1536 //line[strlen(line)-1]='\0';
1537 r_core_cmd (core, command, 1);
1538 r_cons_set_raw (1);
1539 r_cons_show_cursor (false);
1540 if (command[0]) {
1541 r_cons_any_key (NULL);
1542 }
1543 //cons_gotoxy(0,0);
1544 r_cons_clear ();
1545 break;
1546 }
1547 }
1548 cleanup:
1549 ls_free(list);
1550 return true;
1551 }
1552
flag_name_sort(const void * a,const void * b)1553 static int flag_name_sort(const void *a, const void *b) {
1554 const RFlagItem *fa = (const RFlagItem *)a;
1555 const RFlagItem *fb = (const RFlagItem *)b;
1556 return strcmp (fa->name, fb->name);
1557 }
1558
flag_offset_sort(const void * a,const void * b)1559 static int flag_offset_sort(const void *a, const void *b) {
1560 const RFlagItem *fa = (const RFlagItem *)a;
1561 const RFlagItem *fb = (const RFlagItem *)b;
1562 if (fa->offset < fb->offset) {
1563 return -1;
1564 }
1565 if (fa->offset > fb->offset) {
1566 return 1;
1567 }
1568 return 0;
1569 }
1570
sort_flags(RList * l,int sort)1571 static void sort_flags(RList *l, int sort) {
1572 switch (sort) {
1573 case SORT_NAME:
1574 r_list_sort (l, flag_name_sort);
1575 break;
1576 case SORT_OFFSET:
1577 r_list_sort (l, flag_offset_sort);
1578 break;
1579 case SORT_NONE:
1580 default:
1581 break;
1582 }
1583 }
1584
1585 // TODO: remove this statement, should be a separate .o
1586
print_rop(void * _core,void * _item,bool selected)1587 static char *print_rop(void *_core, void *_item, bool selected) {
1588 char *line = _item;
1589 // TODO: trim if too long
1590 return r_str_newf ("%c %s\n", selected?'>':' ', line);
1591 }
1592
r_core_visual_view_rop(RCore * core)1593 R_API int r_core_visual_view_rop(RCore *core) {
1594 RListIter *iter;
1595 const int rows = 7;
1596 int cur = 0;
1597
1598 r_line_set_prompt ("rop regexp: ");
1599 const char *line = r_line_readline ();
1600
1601 int scr_h, scr_w = r_cons_get_size (&scr_h);
1602
1603 if (!line || !*line) {
1604 return false;
1605 }
1606 // maybe store in RCore, so we can save it in project and use it outside visual
1607
1608 eprintf ("Searching ROP gadgets...\n");
1609 char *ropstr = r_core_cmd_strf (core, "\"/Rl %s\" @e:scr.color=0", line);
1610 RList *rops = r_str_split_list (ropstr, "\n", 0);
1611 int delta = 0;
1612 bool show_color = core->print->flags & R_PRINT_FLAGS_COLOR;
1613 bool forceaddr = false;
1614 ut64 addr = UT64_MAX;
1615 char *cursearch = strdup (line);
1616 while (true) {
1617 r_cons_clear00 ();
1618 r_cons_printf ("[0x%08"PFMT64x"]-[visual-r2rop] %s (see pdp command)\n",
1619 (addr == UT64_MAX)? 0: addr + delta, cursearch);
1620
1621 // compute chain
1622 RStrBuf *sb = r_strbuf_new ("");
1623 char *msg;
1624 r_list_foreach (core->ropchain, iter, msg) {
1625 if (core->rasm->bits == 64) {
1626 ut64 n = r_num_get (NULL, msg);
1627 n = r_read_be64 (&n);
1628 r_strbuf_appendf (sb, "%016"PFMT64x, n);
1629 } else {
1630 ut32 n = r_num_get (NULL, msg);
1631 n = r_read_be32 (&n);
1632 r_strbuf_appendf (sb, "%08x", n);
1633 }
1634 }
1635 char *chainstr = r_strbuf_drain (sb);
1636
1637 char *wlist = r_str_widget_list (core, rops, rows, cur, print_rop);
1638 r_cons_printf ("%s", wlist);
1639 free (wlist);
1640 char *curline = r_str_dup (NULL, r_str_trim_head_ro (r_str_widget_list (
1641 core, rops, rows, cur, print_rop)));
1642 if (curline) {
1643 char *sp = strchr (curline, ' ');
1644 if (sp) {
1645 *sp = 0;
1646 if (!forceaddr) {
1647 addr = r_num_math (NULL, curline);
1648 }
1649 *sp = ' ';
1650 }
1651 if (addr != UT64_MAX) {
1652 r_cons_printf ("Gadget:");
1653 // get comment
1654 char *output = r_core_cmd_strf (core, "piu 10 @ 0x%08"PFMT64x, addr + delta);
1655 if (output) {
1656 r_cons_strcat_at (output, 0, 10, scr_w, 10);
1657 free (output);
1658 }
1659 }
1660 }
1661 int count = 0;
1662 r_cons_flush ();
1663 r_cons_gotoxy (0, 20);
1664 r_cons_printf ("ROPChain:\n %s\n", r_str_get (chainstr));
1665 r_list_foreach (core->ropchain, iter, msg) {
1666 int extra = strlen (chainstr) / scr_w;
1667 r_cons_gotoxy (0, extra + 22 + count);
1668 r_cons_strcat (msg);
1669 const char *cmt = r_meta_get_string (core->anal, R_META_TYPE_COMMENT, r_num_get (NULL, msg));
1670 if (cmt) {
1671 r_cons_strcat (cmt);
1672 }
1673 count ++;
1674 }
1675 r_cons_flush ();
1676 int ch = r_cons_readchar ();
1677 if (ch == -1 || ch == 4) {
1678 free (curline);
1679 free (cursearch);
1680 R_FREE (chainstr);
1681 return false;
1682 }
1683 #define NEWTYPE(x,y) r_mem_dup (&(y), sizeof (x));
1684 ch = r_cons_arrow_to_hjkl (ch); // get ESC+char, return 'hjkl' char
1685 switch (ch) {
1686 case 127:
1687 free (r_list_pop (core->ropchain));
1688 break;
1689 case '?':
1690 r_cons_clear00 ();
1691 r_cons_printf ("[r2rop-visual] Help\n"
1692 " jk - select next/prev rop gadget\n"
1693 " JK - scroll next/prev page from list\n"
1694 " hl - increase/decrease delta offset in disasm\n"
1695 " \\n - enter key or dot will add the current offset into the chain\n"
1696 " i - enter a number to be pushed into the chain\n"
1697 " : - run r2 command\n"
1698 " ; - add comment in current offset\n"
1699 " <- - backspace - delete last gadget from the chain\n"
1700 " / - highlight given word\n"
1701 " y - yank current rop chain into the clipboard (y?)\n"
1702 " o - seek to given offset\n"
1703 " r - run /R again\n"
1704 " ? - show this help message\n"
1705 " q - quit this view\n"
1706 );
1707 r_cons_flush ();
1708 r_cons_any_key (NULL);
1709 break;
1710 case ':': // TODO: move this into a separate helper function
1711 r_cons_show_cursor (true);
1712 r_cons_set_raw (0);
1713 while (true) {
1714 char cmd[1024];
1715 cmd[0] = '\0';
1716 r_line_set_prompt (":> ");
1717 if (r_cons_fgets (cmd, sizeof (cmd), 0, NULL) < 0) {
1718 cmd[0] = '\0';
1719 }
1720 if (!*cmd || *cmd == 'q') {
1721 break;
1722 }
1723 ut64 oseek = core->offset;
1724 r_core_seek (core, addr + delta, false);
1725 r_core_cmd (core, cmd, 1);
1726 r_core_seek (core, oseek, false);
1727 r_cons_flush ();
1728 }
1729 r_cons_set_raw (1);
1730 r_cons_show_cursor (false);
1731 break;
1732 case 'y':
1733 r_core_cmdf (core, "yfx %s", chainstr);
1734 break;
1735 case 'o':
1736 {
1737 r_line_set_prompt ("offset: ");
1738 const char *line = r_line_readline ();
1739 if (line && *line) {
1740 ut64 off = r_num_math (core->num, line);
1741 r_core_seek (core, off, true);
1742 addr = off;
1743 forceaddr = true;
1744 delta = 0;
1745 }
1746 }
1747 break;
1748 case 'r':
1749 {
1750 r_line_set_prompt ("rop regexp: ");
1751 const char *line = r_line_readline ();
1752 if (line && *line) {
1753 free (cursearch);
1754 delta = 0;
1755 addr = UT64_MAX;
1756 cur = 0;
1757 cursearch = strdup (line);
1758 free (ropstr);
1759 ropstr = r_core_cmd_strf (core, "\"/Rl %s\" @e:scr.color=0", line);
1760 r_list_free (rops);
1761 rops = r_str_split_list (ropstr, "\n", 0);
1762 }
1763 }
1764 break;
1765 case '/':
1766 r_core_cmd0 (core, "?i highlight;e scr.highlight=`yp`");
1767 break;
1768 case 'i':
1769 {
1770 r_line_set_prompt ("insert value: ");
1771 const char *line = r_line_readline ();
1772 if (line && *line) {
1773 ut64 n = r_num_math (core->num, line);
1774 r_list_push (core->ropchain, r_str_newf ("0x%08"PFMT64x, n));
1775 }
1776 }
1777 break;
1778 case ';':
1779 {
1780 r_line_set_prompt ("comment: ");
1781 const char *line = r_line_readline ();
1782 if (line && *line) {
1783 // XXX code injection bug here
1784 r_core_cmdf (core, "CC %s @ 0x%08"PFMT64x, line, addr + delta);
1785 }
1786 }
1787 break;
1788 case '.':
1789 case '\n':
1790 case '\r':
1791 if (curline && *curline) {
1792 char *line = r_core_cmd_strf (core, "piuq@0x%08"PFMT64x, addr + delta);
1793 r_str_replace_char (line, '\n', ';');
1794 if (show_color) {
1795 // XXX parsing fails to read this ansi-offset
1796 // const char *offsetColor = r_cons_singleton ()->context->pal.offset; // TODO etooslow. must cache
1797 // r_list_push (core->ropchain, r_str_newf ("%s0x%08"PFMT64x""Color_RESET" %s", offsetColor, addr + delta, line));
1798 r_list_push (core->ropchain, r_str_newf ("0x%08"PFMT64x" %s", addr + delta, line));
1799 } else {
1800 r_list_push (core->ropchain, r_str_newf ("0x%08"PFMT64x" %s", addr + delta, line));
1801 }
1802 free (line);
1803 }
1804 break;
1805 case 'h':
1806 delta--;
1807 break;
1808 case 'l':
1809 delta++;
1810 break;
1811 case 'J':
1812 cur+=10;
1813 forceaddr = false;
1814 delta = 0;
1815 break;
1816 case 'K':
1817 delta = 0;
1818 forceaddr = false;
1819 if (cur > 10) {
1820 cur-=10;
1821 } else {
1822 cur = 0;
1823 }
1824 break;
1825 case '0':
1826 delta = 0;
1827 cur = 0;
1828 break;
1829 case 'j':
1830 delta = 0;
1831 cur++;
1832 forceaddr = false;
1833 break;
1834 case 'k':
1835 delta = 0;
1836 forceaddr = false;
1837 if (cur > 0) {
1838 cur--;
1839 } else {
1840 cur = 0;
1841 }
1842 break;
1843 case 'q':
1844 free (curline);
1845 free (cursearch);
1846 R_FREE (chainstr);
1847 return true;
1848 }
1849 R_FREE (chainstr);
1850 free (curline);
1851 }
1852 free (cursearch);
1853 return false;
1854 }
1855
r_core_visual_trackflags(RCore * core)1856 R_API int r_core_visual_trackflags(RCore *core) {
1857 const char *fs = NULL, *fs2 = NULL;
1858 int hit, i, j, ch;
1859 int _option = 0;
1860 int option = 0;
1861 char cmd[1024];
1862 int format = 0;
1863 int delta = 7;
1864 int menu = 0;
1865 int sort = SORT_NONE;
1866
1867 if (r_flag_space_is_empty (core->flags)) {
1868 menu = 1;
1869 }
1870 for (;;) {
1871 bool hasColor = r_config_get_i (core->config, "scr.color");
1872 r_cons_clear00 ();
1873
1874 if (menu) {
1875 r_cons_printf ("Flags in flagspace '%s'. Press '?' for help.\n\n",
1876 r_flag_space_cur_name (core->flags));
1877 hit = 0;
1878 i = j = 0;
1879 RList *l = r_flag_all_list (core->flags, true);
1880 RListIter *iter;
1881 RFlagItem *fi;
1882 sort_flags (l, sort);
1883 r_list_foreach (l, iter, fi) {
1884 if (option == i) {
1885 fs2 = fi->name;
1886 hit = 1;
1887 }
1888 if ((i>=option-delta) && ((i<option+delta)||((option<delta)&&(i<(delta<<1))))) {
1889 bool cur = option == i;
1890 if (cur && hasColor) {
1891 r_cons_printf (Color_INVERT);
1892 }
1893 r_cons_printf (" %c %03d 0x%08"PFMT64x" %4"PFMT64d" %s\n",
1894 cur?'>':' ', i, fi->offset, fi->size, fi->name);
1895 if (cur && hasColor) {
1896 r_cons_printf (Color_RESET);
1897 }
1898 j++;
1899 }
1900 i++;
1901 }
1902 r_list_free (l);
1903
1904 if (!hit && i > 0) {
1905 option = i - 1;
1906 continue;
1907 }
1908 if (fs2) {
1909 int cols, rows = r_cons_get_size (&cols);
1910 //int rows = 20;
1911 rows -= 12;
1912 r_cons_printf ("\n Selected: %s\n\n", fs2);
1913 // Honor MAX_FORMATS here
1914 switch (format) {
1915 case 0: snprintf (cmd, sizeof (cmd), "px %d @ %s!64", rows*16, fs2); core->printidx = 0; break;
1916 case 1: snprintf (cmd, sizeof (cmd), "pd %d @ %s!64", rows, fs2); core->printidx = 1; break;
1917 case 2: snprintf (cmd, sizeof (cmd), "ps @ %s!64", fs2); core->printidx = 5; break;
1918 case 3: strcpy (cmd, "f="); break;
1919 default: format = 0; continue;
1920 }
1921 if (*cmd) {
1922 r_core_cmd (core, cmd, 0);
1923 }
1924 } else {
1925 r_cons_printf ("(no flags)\n");
1926 }
1927 } else {
1928 r_cons_printf ("Flag spaces:\n\n");
1929 hit = 0;
1930 RSpaceIter it;
1931 const RSpace *s, *cur = r_flag_space_cur (core->flags);
1932 int i = 0;
1933 r_flag_space_foreach (core->flags, it, s) {
1934 if (option == i) {
1935 fs = s->name;
1936 hit = 1;
1937 }
1938 if ((i >= option - delta) && ((i < option + delta) ||
1939 ((option < delta) && (i < (delta << 1))))) {
1940 r_cons_printf (" %c %c %s\n",
1941 (option == i)? '>': ' ',
1942 (s == cur)? '*': ' ',
1943 s->name);
1944 }
1945 i++;
1946 }
1947 if (option == i) {
1948 fs = "*";
1949 hit = 1;
1950 }
1951 r_cons_printf (" %c %c %s\n", (option == i)? '>': ' ',
1952 !cur? '*': ' ', "*");
1953 i++;
1954 if (!hit && i > 0) {
1955 option = i - 1;
1956 continue;
1957 }
1958 }
1959 r_cons_visual_flush ();
1960 ch = r_cons_readchar ();
1961 if (ch == -1 || ch == 4) {
1962 return false;
1963 }
1964 ch = r_cons_arrow_to_hjkl (ch); // get ESC+char, return 'hjkl' char
1965 switch (ch) {
1966 case 'C':
1967 r_config_toggle (core->config, "scr.color");
1968 break;
1969 case '_':
1970 if (r_core_visual_hudstuff (core)) {
1971 return true;
1972 }
1973 break;
1974 case 'J': option += 10; break;
1975 case 'o': sort = SORT_OFFSET; break;
1976 case 'n': sort = SORT_NAME; break;
1977 case 'j': option++; break;
1978 case 'k':
1979 if (--option < 0) {
1980 option = 0;
1981 }
1982 break;
1983 case 'K': option-=10;
1984 if (option < 0) {
1985 option = 0;
1986 }
1987 break;
1988 case 'h':
1989 case 'b': // back
1990 case 'Q':
1991 case 'q':
1992 if (menu <= 0) {
1993 return true;
1994 }
1995 menu--;
1996 option = _option;
1997 if (menu == 0) {
1998 r_flag_space_set (core->flags, NULL);
1999 // if no flagspaces, just quit
2000 if (r_flag_space_is_empty (core->flags)) {
2001 return true;
2002 }
2003 }
2004 break;
2005 case 'a':
2006 switch (menu) {
2007 case 0: // new flag space
2008 r_cons_show_cursor (true);
2009 r_line_set_prompt ("add flagspace: ");
2010 strcpy (cmd, "fs ");
2011 if (r_cons_fgets (cmd + 3, sizeof (cmd) - 3, 0, NULL) > 0) {
2012 r_core_cmd (core, cmd, 0);
2013 r_cons_set_raw (1);
2014 r_cons_show_cursor (false);
2015 }
2016 break;
2017 case 1: // new flag
2018 r_cons_show_cursor (true);
2019 r_line_set_prompt ("add flag: ");
2020 strcpy (cmd, "f ");
2021 if (r_cons_fgets (cmd + 2, sizeof (cmd) - 2, 0, NULL) > 0) {
2022 r_core_cmd (core, cmd, 0);
2023 r_cons_set_raw (1);
2024 r_cons_show_cursor (false);
2025 }
2026 break;
2027 }
2028 break;
2029 case 'd':
2030 r_flag_unset_name (core->flags, fs2);
2031 break;
2032 case 'e':
2033 /* TODO: prompt for addr, size, name */
2034 eprintf ("TODO\n");
2035 r_sys_sleep (1);
2036 break;
2037 case '*':
2038 r_core_block_size (core, core->blocksize+16);
2039 break;
2040 case '/':
2041 r_core_block_size (core, core->blocksize-16);
2042 break;
2043 case '+':
2044 if (menu == 1) {
2045 r_core_cmdf (core, "f %s=%s+1", fs2, fs2);
2046 } else {
2047 r_core_block_size (core, core->blocksize + 1);
2048 }
2049 break;
2050 case '-':
2051 if (menu == 1) {
2052 r_core_cmdf (core, "f %s=%s-1", fs2, fs2);
2053 } else {
2054 r_core_block_size (core, core->blocksize-1);
2055 }
2056 break;
2057 case 'r': // "Vtr"
2058 if (menu == 1) {
2059 int len;
2060 r_cons_show_cursor (true);
2061 r_cons_set_raw (0);
2062 // TODO: use r_flag_rename or wtf?..fr doesnt uses this..
2063 snprintf (cmd, sizeof (cmd), "fr %s ", fs2);
2064 len = strlen (cmd);
2065 eprintf ("Rename flag '%s' as:\n", fs2);
2066 r_line_set_prompt (":> ");
2067 if (r_cons_fgets (cmd + len, sizeof (cmd) - len, 0, NULL) < 0) {
2068 cmd[0] = '\0';
2069 }
2070 r_core_cmd (core, cmd, 0);
2071 r_cons_set_raw (1);
2072 r_cons_show_cursor (false);
2073 }
2074 break;
2075 case 'R':
2076 if (menu == 1) {
2077 char line[1024];
2078 r_cons_show_cursor (true);
2079 r_cons_set_raw (0);
2080 eprintf ("Rename function '%s' as:\n", fs2);
2081 r_line_set_prompt (":> ");
2082 if (r_cons_fgets (line, sizeof (line), 0, NULL) < 0) {
2083 cmd[0] = '\0';
2084 }
2085 int res = snprintf (cmd, sizeof (cmd), "afr %s %s", line, fs2);
2086 if (res < sizeof (cmd)) {
2087 r_core_cmd (core, cmd, 0);
2088 }
2089 r_cons_set_raw (1);
2090 r_cons_show_cursor (false);
2091 }
2092 break;
2093 case 'P':
2094 if (--format < 0) {
2095 format = MAX_FORMAT;
2096 }
2097 break;
2098 // = (format<=0)? MAX_FORMAT: format-1; break;
2099 case 'p': format++; break;
2100 case 'l':
2101 case ' ':
2102 case '\r':
2103 case '\n':
2104 if (menu == 1) {
2105 sprintf (cmd, "s %s", fs2);
2106 r_core_cmd (core, cmd, 0);
2107 return true;
2108 }
2109 r_flag_space_set (core->flags, fs);
2110 menu = 1;
2111 _option = option;
2112 option = 0;
2113 break;
2114 case '?':
2115 r_cons_clear00 ();
2116 r_cons_printf (
2117 "\nVF: Visual Flags help:\n\n"
2118 " q - quit menu\n"
2119 " j/k - line down/up keys\n"
2120 " J/K - page down/up keys\n"
2121 " h/b - go back\n"
2122 " C - toggle colors\n"
2123 " l/' ' - accept current selection\n"
2124 " a/d/e - add/delete/edit flag\n"
2125 " +/- - increase/decrease block size\n"
2126 " o - sort flags by offset\n"
2127 " r/R - rename flag / Rename function\n"
2128 " n - sort flags by name\n"
2129 " p/P - rotate print format\n"
2130 " _ - hud for flags and comments\n"
2131 " : - enter command\n");
2132 r_cons_flush ();
2133 r_cons_any_key (NULL);
2134 break;
2135 case ':':
2136 r_cons_show_cursor (true);
2137 r_cons_set_raw (0);
2138 *cmd = 0;
2139 r_line_set_prompt (":> ");
2140 if (r_cons_fgets (cmd, sizeof (cmd), 0, NULL) <0) {
2141 *cmd = 0;
2142 }
2143 cmd[sizeof (cmd) - 1] = 0;
2144 r_core_cmd_task_sync (core, cmd, 1);
2145 r_cons_set_raw (1);
2146 r_cons_show_cursor (false);
2147 if (*cmd) {
2148 r_cons_any_key (NULL);
2149 }
2150 //cons_gotoxy(0,0);
2151 r_cons_clear ();
2152 continue;
2153 }
2154 }
2155 return true;
2156 }
2157
r_core_visual_comments(RCore * core)2158 R_API int r_core_visual_comments (RCore *core) {
2159 char *str;
2160 char cmd[512], *p = NULL;
2161 int ch, option = 0;
2162 int format = 0, i = 0;
2163 ut64 addr, from = 0, size = 0;
2164
2165 for (;;) {
2166 r_cons_clear00 ();
2167 r_cons_strcat ("Comments:\n");
2168 RIntervalTreeIter it;
2169 RAnalMetaItem *item;
2170 i = 0;
2171 r_interval_tree_foreach (&core->anal->meta, it, item) {
2172 if (item->type != R_META_TYPE_COMMENT) {
2173 continue;
2174 }
2175 str = item->str;
2176 addr = r_interval_tree_iter_get (&it)->start;
2177 if (option==i) {
2178 from = addr;
2179 size = 1; // XXX: remove this thing size for comments is useless d->size;
2180 free (p);
2181 p = strdup (str);
2182 r_cons_printf (" > %s\n", str);
2183 } else {
2184 r_cons_printf (" %s\n", str);
2185 }
2186 i ++;
2187 }
2188 if (!i) {
2189 if (--option < 0) {
2190 r_cons_any_key ("No comments");
2191 break;
2192 }
2193 continue;
2194 }
2195 r_cons_newline ();
2196
2197 switch (format) {
2198 case 0: sprintf (cmd, "px @ 0x%"PFMT64x":64", from); core->printidx = 0; break;
2199 case 1: sprintf (cmd, "pd 12 @ 0x%"PFMT64x":64", from); core->printidx = 1; break;
2200 case 2: sprintf (cmd, "ps @ 0x%"PFMT64x":64", from); core->printidx = 5; break;
2201 default: format = 0; continue;
2202 }
2203 if (*cmd) {
2204 r_core_cmd (core, cmd, 0);
2205 }
2206 r_cons_visual_flush ();
2207 ch = r_cons_readchar ();
2208 ch = r_cons_arrow_to_hjkl (ch); // get ESC+char, return 'hjkl' char
2209 switch (ch) {
2210 case 'a':
2211 //TODO
2212 break;
2213 case 'e':
2214 //TODO
2215 break;
2216 case 'd':
2217 if (p) {
2218 r_meta_del (core->anal, R_META_TYPE_ANY, from, size);
2219 }
2220 break;
2221 case 'P':
2222 if (--format < 0) {
2223 format = MAX_FORMAT;
2224 }
2225 break;
2226 case 'p':
2227 format++;
2228 break;
2229 case 'J':
2230 option += 10;
2231 break;
2232 case 'j':
2233 option++;
2234 break;
2235 case 'k':
2236 if (--option < 0) {
2237 option = 0;
2238 }
2239 break;
2240 case 'K':
2241 option -= 10;
2242 if (option < 0) {
2243 option = 0;
2244 }
2245 break;
2246 case 'l':
2247 case ' ':
2248 case '\r':
2249 case '\n':
2250 r_core_cmdf (core, "s 0x%"PFMT64x, from);
2251 R_FREE (p);
2252 return true;
2253 case 'Q':
2254 case 'q':
2255 R_FREE (p);
2256 return true;
2257 case '?':
2258 case 'h':
2259 r_cons_clear00 ();
2260 r_cons_printf (
2261 "\nVT: Visual Comments/Anal help:\n\n"
2262 " q - quit menu\n"
2263 " j/k - down/up keys\n"
2264 " h/b - go back\n"
2265 " l/' ' - accept current selection\n"
2266 " a/d/e - add/delete/edit comment/anal symbol\n"
2267 " p/P - rotate print format\n");
2268 r_cons_flush ();
2269 r_cons_any_key (NULL);
2270 break;
2271 }
2272 R_FREE (p);
2273 }
2274 return true;
2275 }
2276
config_visual_hit_i(RCore * core,const char * name,int delta)2277 static void config_visual_hit_i(RCore *core, const char *name, int delta) {
2278 struct r_config_node_t *node;
2279 node = r_config_node_get (core->config, name);
2280 if (node && r_config_node_is_int (node)) {
2281 int hitDelta = r_config_get_i (core->config, name) + delta;
2282 (void) r_config_set_i (core->config, name, hitDelta);
2283 }
2284 }
2285
2286 /* Visually activate the config variable */
config_visual_hit(RCore * core,const char * name,int editor)2287 static void config_visual_hit(RCore *core, const char *name, int editor) {
2288 char buf[1024];
2289 RConfigNode *node;
2290
2291 if (!(node = r_config_node_get (core->config, name))) {
2292 return;
2293 }
2294 if (r_config_node_is_bool (node)) {
2295 r_config_set_i (core->config, name, node->i_value? 0:1);
2296 } else {
2297 // XXX: must use config_set () to run callbacks!
2298 if (editor) {
2299 char * buf = r_core_editor (core, NULL, node->value);
2300 node->value = r_str_dup (node->value, buf);
2301 free (buf);
2302 } else {
2303 // FGETS AND SO
2304 r_cons_printf ("New value (old=%s): \n", node->value);
2305 r_cons_show_cursor (true);
2306 r_cons_flush ();
2307 r_cons_set_raw (0);
2308 r_line_set_prompt (":> ");
2309 r_cons_fgets (buf, sizeof (buf), 0, 0);
2310 r_cons_set_raw (1);
2311 r_cons_show_cursor (false);
2312 r_config_set (core->config, name, buf);
2313 //node->value = r_str_dup (node->value, buf);
2314 }
2315 }
2316 }
2317
show_config_options(RCore * core,const char * opt)2318 static void show_config_options(RCore *core, const char *opt) {
2319 RConfigNode *node = r_config_node_get (core->config, opt);
2320 if (node && !r_list_empty (node->options)) {
2321 int h, w = r_cons_get_size (&h);
2322 const char *item;
2323 RListIter *iter;
2324 RStrBuf *sb = r_strbuf_new (" Options: ");
2325 r_list_foreach (node->options, iter, item) {
2326 r_strbuf_appendf (sb, "%s%s", iter->p? ", ": "", item);
2327 if (r_strbuf_length (sb) + 5 >= w) {
2328 char *s = r_strbuf_drain (sb);
2329 r_cons_println (s);
2330 free (s);
2331 sb = r_strbuf_new ("");
2332 }
2333 }
2334 char *s = r_strbuf_drain (sb);
2335 r_cons_println (s);
2336 free (s);
2337 }
2338 }
2339
r_core_visual_config(RCore * core)2340 R_API void r_core_visual_config(RCore *core) {
2341 char *fs = NULL, *fs2 = NULL, *desc = NULL;
2342 int i, j, ch, hit, show;
2343 int option, _option = 0;
2344 RListIter *iter;
2345 RConfigNode *bt;
2346 char old[1024];
2347 int delta = 9;
2348 int menu = 0;
2349 old[0]='\0';
2350
2351 option = 0;
2352 for (;;) {
2353 r_cons_clear00 ();
2354 r_cons_get_size (&delta);
2355 delta /= 4;
2356
2357 switch (menu) {
2358 case 0: // flag space
2359 r_cons_printf ("[EvalSpace]\n\n");
2360 hit = j = i = 0;
2361 r_list_foreach (core->config->nodes, iter, bt) {
2362 if (option == i) {
2363 fs = bt->name;
2364 }
2365 if (!old[0]) {
2366 r_str_ccpy (old, bt->name, '.');
2367 show = 1;
2368 } else if (r_str_ccmp (old, bt->name, '.')) {
2369 r_str_ccpy (old, bt->name, '.');
2370 show = 1;
2371 } else {
2372 show = 0;
2373 }
2374 if (show) {
2375 if (option == i) {
2376 hit = 1;
2377 }
2378 if ( (i >=option-delta) && ((i<option+delta)||((option<delta)&&(i<(delta<<1))))) {
2379 r_cons_printf (" %c %s\n", (option == i)?'>':' ', old);
2380 j++;
2381 }
2382 i++;
2383 }
2384 }
2385 if (!hit && j > 0) {
2386 option--;
2387 continue;
2388 }
2389 r_cons_printf ("\n Sel: %s \n\n", fs);
2390 break;
2391 case 1: // flag selection
2392 r_cons_printf ("[EvalSpace < Variables: %s]\n\n", fs);
2393 hit = 0;
2394 j = i = 0;
2395 // TODO: cut -d '.' -f 1 | sort | uniq !!!
2396 r_list_foreach (core->config->nodes, iter, bt) {
2397 if (!r_str_ccmp (bt->name, fs, '.')) {
2398 if (option == i) {
2399 fs2 = bt->name;
2400 desc = bt->desc;
2401 hit = 1;
2402 }
2403 if ( (i>=option-delta) && ((i<option+delta)||((option<delta)&&(i<(delta<<1))))) {
2404 // TODO: Better align
2405 r_cons_printf (" %c %s = %s\n", (option==i)?'>':' ', bt->name, bt->value);
2406 j++;
2407 }
2408 i++;
2409 }
2410 }
2411 if (!hit && j > 0) {
2412 option = i - 1;
2413 continue;
2414 }
2415 if (fs2) {
2416 // TODO: Break long lines.
2417 r_cons_printf ("\n Selected: %s (%s)\n", fs2, desc);
2418 show_config_options (core, fs2);
2419 r_cons_newline ();
2420 }
2421 }
2422
2423 if (fs && !strncmp (fs, "asm.", 4)) {
2424 r_core_cmd (core, "pd $r", 0);
2425 }
2426 r_cons_visual_flush ();
2427 ch = r_cons_readchar ();
2428 if (ch == 4 || ch == -1) {
2429 return;
2430 }
2431 ch = r_cons_arrow_to_hjkl (ch); // get ESC+char, return 'hjkl' char
2432
2433 switch (ch) {
2434 case 'j': option++; break;
2435 case 'k': option = (option < 1)? 0: option - 1; break;
2436 case 'J': option += 4; break;
2437 case 'K': option = (option < 4)? 0: option - 4; break;
2438 case 'h':
2439 case 'b': // back
2440 menu = 0;
2441 option = _option;
2442 break;
2443 case '_':
2444 r_core_visual_config_hud (core);
2445 break;
2446 case 'Q':
2447 case 'q':
2448 if (menu <= 0) {
2449 return;
2450 }
2451 menu--;
2452 option = _option;
2453 break;
2454 case '$':
2455 r_core_cmd0 (core, "?$");
2456 r_cons_any_key (NULL);
2457 break;
2458 case '*':
2459 case '+':
2460 fs2 ? config_visual_hit_i (core, fs2, +1) : 0;
2461 continue;
2462 case '/':
2463 case '-':
2464 fs2 ? config_visual_hit_i (core, fs2, -1) : 0;
2465 continue;
2466 case 'l':
2467 case 'E': // edit value
2468 case 'e': // edit value
2469 case ' ':
2470 case '\r':
2471 case '\n': // never happens
2472 if (menu == 1) {
2473 fs2 ? config_visual_hit (core, fs2, (ch=='E')) : 0;
2474 } else {
2475 menu = 1;
2476 _option = option;
2477 option = 0;
2478 }
2479 break;
2480 case '?':
2481 r_cons_clear00 ();
2482 r_cons_printf ("\nVe: Visual Eval help:\n\n"
2483 " q - quit menu\n"
2484 " j/k - down/up keys\n"
2485 " h/b - go back\n"
2486 " $ - same as ?$ - show values of vars\n"
2487 " e/' ' - edit/toggle current variable\n"
2488 " E - edit variable with 'cfg.editor' (vi?)\n"
2489 " +/- - increase/decrease numeric value (* and /, too)\n"
2490 " : - enter command\n");
2491 r_cons_flush ();
2492 r_cons_any_key (NULL);
2493 break;
2494 case ':':
2495 r_cons_show_cursor (true);
2496 r_cons_set_raw (0);
2497 {
2498 char *cmd = prompt (":> ", NULL);
2499 r_core_cmd (core, cmd, 1);
2500 free (cmd);
2501 }
2502 r_cons_set_raw (1);
2503 r_cons_show_cursor (false);
2504 r_cons_any_key (NULL);
2505 r_cons_clear00 ();
2506 continue;
2507 }
2508 }
2509 }
2510
r_core_visual_mounts(RCore * core)2511 R_API void r_core_visual_mounts(RCore *core) {
2512 RList *list = NULL;
2513 RFSRoot *fsroot = NULL;
2514 RListIter *iter;
2515 RFSFile *file;
2516 RFSPartition *part;
2517 int i, ch, option, mode, partition, dir, delta = 7;
2518 char *str, path[4096], buf[1024], *root = NULL;
2519 const char *n, *p;
2520
2521 dir = partition = option = mode = 0;
2522 for (;;) {
2523 /* Clear */
2524 r_cons_clear00 ();
2525
2526 /* Show */
2527 if (mode == 0) {
2528 if (list) {
2529 r_list_free (list);
2530 list = NULL;
2531 }
2532 r_cons_printf ("Press '/' to navigate the root filesystem.\nPartitions:\n\n");
2533 n = r_fs_partition_type_get (partition);
2534 list = r_fs_partitions (core->fs, n, 0);
2535 i = 0;
2536 if (list) {
2537 r_list_foreach (list, iter, part) {
2538 if ((option-delta <= i) && (i <= option+delta)) {
2539 if (option == i) {
2540 r_cons_printf (" > ");
2541 } else {
2542 r_cons_printf (" ");
2543 }
2544 r_cons_printf ("%d %02x 0x%010"PFMT64x" 0x%010"PFMT64x"\n",
2545 part->number, part->type,
2546 part->start, part->start+part->length);
2547 }
2548 i++;
2549 }
2550 r_list_free (list);
2551 list = NULL;
2552 } else {
2553 r_cons_printf ("Cannot read partition\n");
2554 }
2555 } else if (mode == 1) {
2556 r_cons_printf ("Types:\n\n");
2557 for (i=0;;i++) {
2558 n = r_fs_partition_type_get (i);
2559 if (!n) {
2560 break;
2561 }
2562 r_cons_printf ("%s%s\n", (i==partition)?" > ":" ", n);
2563 }
2564 } else if (mode == 3) {
2565 i = 0;
2566 r_cons_printf ("Mountpoints:\n\n");
2567 r_list_foreach (core->fs->roots, iter, fsroot) {
2568 if (fsroot && (option-delta <= i) && (i <= option+delta)) {
2569 r_cons_printf ("%s %s\n", (option == i)?" > ":" ",
2570 fsroot->path);
2571 }
2572 i++;
2573 }
2574 } else {
2575 if (root) {
2576 list = r_fs_dir (core->fs, path);
2577 if (list) {
2578 r_cons_printf ("%s:\n\n", path);
2579 i = 0;
2580 r_list_foreach (list, iter, file) {
2581 if ((dir-delta <= i) && (i <= dir+delta)) {
2582 r_cons_printf ("%s%c %s\n", (dir == i)?" > ":" ",
2583 file->type, file->name);
2584 }
2585 i++;
2586 }
2587 r_cons_printf ("\n");
2588 r_list_free (list);
2589 list = NULL;
2590 } else {
2591 r_cons_printf ("Cannot open '%s' directory\n", root);
2592 }
2593 } else {
2594 r_cons_printf ("Root undefined\n");
2595 }
2596 }
2597 if (mode==2) {
2598 r_str_trim_path (path);
2599 size_t n = strlen (path);
2600 str = path + n;
2601 snprintf (str, sizeof (path) - n, "/");
2602 list = r_fs_dir (core->fs, path);
2603 file = r_list_get_n (list, dir);
2604 if (file && file->type != 'd') {
2605 r_core_cmdf (core, "px @ 0x%" PFMT64x "!64", file->off);
2606 }
2607 r_list_free (list);
2608 list = NULL;
2609 *str='\0';
2610 }
2611 r_cons_flush ();
2612
2613 /* Ask for option */
2614 ch = r_cons_readchar ();
2615 if (ch==-1||ch==4){
2616 free (root);
2617 return;
2618 }
2619 ch = r_cons_arrow_to_hjkl (ch);
2620 switch (ch) {
2621 case '/':
2622 R_FREE (root);
2623 root = strdup ("/");
2624 strncpy (path, root, sizeof (path)-1);
2625 mode = 2;
2626 break;
2627 case 'l':
2628 case '\r':
2629 case '\n':
2630 if (mode == 0) {
2631 n = r_fs_partition_type_get (partition);
2632 list = r_fs_partitions (core->fs, n, 0);
2633 if (!list) {
2634 r_cons_printf ("Unknown partition\n");
2635 r_cons_any_key (NULL);
2636 r_cons_flush ();
2637 break;
2638 }
2639 part = r_list_get_n (list, option);
2640 if (!part) {
2641 r_cons_printf ("Unknown partition\n");
2642 r_cons_any_key (NULL);
2643 r_cons_flush ();
2644 break;
2645 }
2646 p = r_fs_partition_type (n, part->type);
2647 if (p) {
2648 if (r_fs_mount (core->fs, p, "/root", part->start)) {
2649 free (root);
2650 root = strdup ("/root");
2651 strncpy (path, root, sizeof (path)-1);
2652 mode = 2;
2653 } else {
2654 r_cons_printf ("Cannot mount partition\n");
2655 r_cons_flush ();
2656 r_cons_any_key (NULL);
2657 }
2658 } else {
2659 r_cons_printf ("Unknown partition type\n");
2660 r_cons_flush ();
2661 r_cons_any_key (NULL);
2662 }
2663 r_list_free (list);
2664 list = NULL;
2665 } else if (mode == 2){
2666 r_str_trim_path (path);
2667 size_t n = strlen (path);
2668 snprintf (path + n, sizeof (path) - n, "/");
2669 list = r_fs_dir (core->fs, path);
2670 file = r_list_get_n (list, dir);
2671 if (file) {
2672 if (file->type == 'd') {
2673 n = strlen (path);
2674 snprintf (path + n, sizeof (path) - n, "%s", file->name);
2675 r_str_trim_path (path);
2676 if (root && strncmp (root, path, strlen (root) - 1)) {
2677 strncpy (path, root, sizeof (path) - 1);
2678 }
2679 } else {
2680 r_core_cmdf (core, "s 0x%"PFMT64x, file->off);
2681 r_fs_umount (core->fs, root);
2682 free (root);
2683 return;
2684 }
2685 } else {
2686 r_cons_printf ("Unknown file\n");
2687 r_cons_flush ();
2688 r_cons_any_key (NULL);
2689 }
2690
2691 } else if (mode == 3) {
2692 fsroot = r_list_get_n (core->fs->roots, option);
2693 if (fsroot) {
2694 root = strdup (fsroot->path);
2695 strncpy (path, root, sizeof (path)-1);
2696 }
2697 mode = 2;
2698 }
2699 dir = partition = option = 0;
2700 break;
2701 case 'k':
2702 if (mode == 0 || mode == 3) {
2703 if (option > 0) {
2704 option--;
2705 }
2706 } else if (mode == 1) {
2707 if (partition > 0) {
2708 partition--;
2709 }
2710 } else {
2711 if (dir > 0) {
2712 dir--;
2713 }
2714 }
2715 break;
2716 case 'j':
2717 if (mode == 0) {
2718 n = r_fs_partition_type_get (partition);
2719 list = r_fs_partitions (core->fs, n, 0);
2720 if (option < r_list_length (list) - 1) {
2721 option++;
2722 }
2723 } else if (mode == 1) {
2724 if (partition < r_fs_partition_get_size () - 1) {
2725 partition++;
2726 }
2727 } else if (mode == 3) {
2728 if (option < r_list_length (core->fs->roots) - 1) {
2729 option++;
2730 }
2731 } else {
2732 list = r_fs_dir (core->fs, path);
2733 if (dir < r_list_length (list) - 1) {
2734 dir++;
2735 }
2736 }
2737 break;
2738 case 't':
2739 mode = 1;
2740 break;
2741 case 'h':
2742 if (mode == 2) {
2743 if (!root) {
2744 mode = 0;
2745 } else
2746 if (strcmp (path, root)) {
2747 strcat (path, "/..");
2748 r_str_trim_path (path);
2749 } else {
2750 r_fs_umount (core->fs, root);
2751 mode = 0;
2752 }
2753 } else if (mode == 1) {
2754 mode = 0;
2755 } else {
2756 return;
2757 }
2758 break;
2759 case 'Q':
2760 case 'q':
2761 if (mode == 2 && root) {
2762 r_fs_umount (core->fs, root);
2763 mode = 0;
2764 } else {
2765 return;
2766 }
2767 break;
2768 case 'g':
2769 if (mode == 2) {
2770 r_str_trim_path (path);
2771 size_t n = strlen (path);
2772 str = path + n;
2773 snprintf (str, sizeof (path) - n, "/");
2774 list = r_fs_dir (core->fs, path);
2775 file = r_list_get_n (list, dir);
2776 if (file && root) {
2777 n = strlen (path);
2778 snprintf (path + n, sizeof (path) - n, "%s", file->name);
2779 r_str_trim_path (path);
2780 if (strncmp (root, path, strlen (root) - 1)) {
2781 strncpy (path, root, sizeof (path) - 1);
2782 }
2783 file = r_fs_open (core->fs, path, false);
2784 if (file) {
2785 r_fs_read (core->fs, file, 0, file->size);
2786 r_cons_show_cursor (true);
2787 r_cons_set_raw (0);
2788 r_line_set_prompt ("Dump path (ej: /tmp/file): ");
2789 r_cons_fgets (buf, sizeof (buf), 0, 0);
2790 r_cons_set_raw (1);
2791 r_cons_show_cursor (false);
2792 r_file_dump (buf, file->data, file->size, 0);
2793 r_fs_close (core->fs, file);
2794 r_cons_printf ("Done\n");
2795 } else {
2796 r_cons_printf ("Cannot dump file\n");
2797 }
2798 } else {
2799 r_cons_printf ("Cannot dump file\n");
2800 }
2801 r_cons_flush ();
2802 r_cons_any_key (NULL);
2803 *str='\0';
2804 }
2805 break;
2806 case 'm':
2807 mode = 3;
2808 option = 0;
2809 break;
2810 case '?':
2811 r_cons_clear00 ();
2812 r_cons_printf ("\nVM: Visual Mount points help:\n\n");
2813 r_cons_printf (" q - go back or quit menu\n");
2814 r_cons_printf (" j/k - down/up keys\n");
2815 r_cons_printf (" h/l - forward/go keys\n");
2816 r_cons_printf (" t - choose partition type\n");
2817 r_cons_printf (" g - dump file\n");
2818 r_cons_printf (" m - show mountpoints\n");
2819 r_cons_printf (" : - enter command\n");
2820 r_cons_printf (" ? - show this help\n");
2821 r_cons_flush ();
2822 r_cons_any_key (NULL);
2823 break;
2824 case ':':
2825 r_cons_show_cursor (true);
2826 r_cons_set_raw (0);
2827 r_line_set_prompt (":> ");
2828 r_cons_fgets (buf, sizeof (buf), 0, 0);
2829 r_cons_set_raw (1);
2830 r_cons_show_cursor (false);
2831 r_core_cmd (core, buf, 1);
2832 r_cons_any_key (NULL);
2833 break;
2834 }
2835 }
2836 }
2837
2838 // helper
function_rename(RCore * core,ut64 addr,const char * name)2839 static void function_rename(RCore *core, ut64 addr, const char *name) {
2840 RListIter *iter;
2841 RAnalFunction *fcn;
2842
2843 r_list_foreach (core->anal->fcns, iter, fcn) {
2844 if (fcn->addr == addr) {
2845 r_flag_unset_name (core->flags, fcn->name);
2846 free (fcn->name);
2847 fcn->name = strdup (name);
2848 r_flag_set (core->flags, name, addr, r_anal_function_size_from_entry (fcn));
2849 break;
2850 }
2851 }
2852 }
2853
variable_rename(RCore * core,ut64 addr,int vindex,const char * name)2854 static void variable_rename (RCore *core, ut64 addr, int vindex, const char *name) {
2855 RAnalFunction* fcn = r_anal_get_fcn_in (core->anal, addr, R_ANAL_FCN_TYPE_NULL);
2856 ut64 a_tmp = core->offset;
2857 int i = 0;
2858 RListIter *iter;
2859 RList *list = r_anal_var_all_list (core->anal, fcn);
2860 RAnalVar* var;
2861
2862 r_list_foreach (list, iter, var) {
2863 if (i == vindex) {
2864 r_core_seek (core, addr, false);
2865 r_core_cmd_strf (core, "afvn %s %s", name, var->name);
2866 r_core_seek (core, a_tmp, false);
2867 break;
2868 }
2869 ++i;
2870 }
2871 r_list_free (list);
2872 }
2873
variable_set_type(RCore * core,ut64 addr,int vindex,const char * type)2874 static void variable_set_type (RCore *core, ut64 addr, int vindex, const char *type) {
2875 RAnalFunction* fcn = r_anal_get_fcn_in (core->anal, addr, R_ANAL_FCN_TYPE_NULL);
2876 RList *list = r_anal_var_all_list (core->anal, fcn);
2877 RListIter *iter;
2878 RAnalVar* var;
2879
2880 r_list_foreach (list, iter, var) {
2881 if (vindex == 0) {
2882 r_anal_var_set_type (var, type);
2883 break;
2884 }
2885 vindex--;
2886 }
2887 r_list_free (list);
2888 }
2889
2890 // In visual mode, display function list
var_functions_show(RCore * core,int idx,int show,int cols)2891 static ut64 var_functions_show(RCore *core, int idx, int show, int cols) {
2892 int wdelta = (idx > 5)? idx - 5: 0;
2893 char *var_functions;
2894 ut64 seek = core->offset;
2895 ut64 addr = core->offset;
2896 RAnalFunction *fcn;
2897 int window, i = 0, print_full_func;
2898 RListIter *iter;
2899
2900 // Adjust the windows size automaticaly
2901 (void)r_cons_get_size (&window);
2902 window -= 8; // Size of printed things
2903 bool color = r_config_get_i (core->config, "scr.color");
2904 const char *color_addr = core->cons->context->pal.offset;
2905 const char *color_fcn = core->cons->context->pal.fname;
2906
2907 r_list_foreach (core->anal->fcns, iter, fcn) {
2908 print_full_func = true;
2909 if (i >= wdelta) {
2910 if (i > window + wdelta - 1) {
2911 r_cons_printf ("...\n");
2912 break;
2913 }
2914 if (idx == i) {
2915 addr = fcn->addr;
2916 }
2917 if (show) {
2918 char *tmp;
2919 if (color) {
2920 var_functions = r_str_newf ("%c%c %s0x%08"PFMT64x"" Color_RESET" %4"PFMT64d" %s%s"Color_RESET"",
2921 (seek == fcn->addr)?'>':' ',
2922 (idx==i)?'*':' ',
2923 color_addr, fcn->addr, r_anal_function_realsize (fcn),
2924 color_fcn, fcn->name);
2925 } else {
2926 var_functions = r_str_newf ("%c%c 0x%08"PFMT64x" %4"PFMT64d" %s",
2927 (seek == fcn->addr)?'>':' ',
2928 (idx==i)?'*':' ',
2929 fcn->addr, r_anal_function_realsize (fcn), fcn->name);
2930 }
2931 if (var_functions) {
2932 if (!r_cons_singleton ()->show_vals) {
2933 int fun_len = r_str_ansi_len (var_functions);
2934 int columns = fun_len > cols ? cols - 2 : cols;
2935 tmp = r_str_ansi_crop (var_functions, 0, 0, columns, window);
2936 if (r_str_ansi_len (tmp) < fun_len) {
2937 r_cons_printf ("%s..%s\n", tmp, Color_RESET);
2938 print_full_func = false;
2939 }
2940 r_free (tmp);
2941 }
2942 if (print_full_func) {
2943 r_cons_println (var_functions);
2944 }
2945 r_free (var_functions);
2946 }
2947 }
2948 }
2949 i++;
2950 }
2951 return addr;
2952 }
2953
2954 // In visual mode, display the variables.
var_variables_show(RCore * core,int idx,int * vindex,int show,int cols)2955 static ut64 var_variables_show(RCore* core, int idx, int *vindex, int show, int cols) {
2956 int i = 0;
2957 const ut64 addr = var_functions_show (core, idx, 0, cols);
2958 RAnalFunction* fcn = r_anal_get_fcn_in (core->anal, addr, R_ANAL_FCN_TYPE_NULL);
2959 int window;
2960 int wdelta = (idx > 5) ? idx - 5 : 0;
2961 RListIter *iter;
2962 RList *list = r_anal_var_all_list (core->anal, fcn);
2963 RAnalVar* var;
2964 // Adjust the window size automatically.
2965 (void)r_cons_get_size (&window);
2966 window -= 8; // Size of printed things.
2967
2968 // A new line so this looks reasonable.
2969 r_cons_newline ();
2970
2971 int llen = r_list_length (list);
2972 if (*vindex >= llen) {
2973 *vindex = llen - 1;
2974 }
2975
2976 r_list_foreach (list, iter, var) {
2977 if (i >= wdelta) {
2978 if (i > window + wdelta) {
2979 r_cons_printf ("...\n");
2980 break;
2981 }
2982 if (show) {
2983 switch (var->kind & 0xff) {
2984 case 'r':
2985 {
2986 RRegItem *r = r_reg_index_get (core->anal->reg, var->delta);
2987 if (!r) {
2988 eprintf ("Register not found");
2989 break;
2990 }
2991 r_cons_printf ("%sarg %s %s @ %s\n",
2992 i == *vindex ? "* ":" ",
2993 var->type, var->name,
2994 r->name);
2995 }
2996 break;
2997 case 'b':
2998 r_cons_printf ("%s%s %s %s @ %s%s0x%x\n",
2999 i == *vindex ? "* ":" ",
3000 var->delta < 0? "var": "arg",
3001 var->type, var->name,
3002 core->anal->reg->name[R_REG_NAME_BP],
3003 (var->kind == 'v')?"-":"+",
3004 var->delta);
3005 break;
3006 case 's':
3007 r_cons_printf ("%s%s %s %s @ %s%s0x%x\n",
3008 i == *vindex ? "* ":" ",
3009 var->delta < 0? "var": "arg",
3010 var->type, var->name,
3011 core->anal->reg->name[R_REG_NAME_BP],
3012 (var->kind == 'v')?"-":"+",
3013 var->delta);
3014 break;
3015 }
3016 }
3017 }
3018 ++i;
3019 }
3020 r_list_free (list);
3021 return addr;
3022 }
3023
3024 static int level = 0;
3025 static st64 delta = 0;
3026 static int option = 0;
3027 static int variable_option = 0;
3028 static int printMode = 0;
3029 static bool selectPanel = false;
3030 #define lastPrintMode 6
3031 static const char *printCmds[lastPrintMode] = {
3032 "pdf", "pd $r", "afi", "pdsf", "pdc", "pdr"
3033 };
3034
r_core_visual_anal_refresh_column(RCore * core,int colpos)3035 static void r_core_visual_anal_refresh_column (RCore *core, int colpos) {
3036 const ut64 addr = (level != 0 && level != 1)
3037 ? core->offset
3038 : var_functions_show (core, option, 0, colpos);
3039 // RAnalFunction* fcn = r_anal_get_fcn_in(core->anal, addr, R_ANAL_FCN_TYPE_NULL);
3040 int h, w = r_cons_get_size (&h);
3041 // int sz = (fcn)? R_MIN (r_anal_fcn_size (fcn), h * 15) : 16; // max instr is 15 bytes.
3042
3043 const char *cmd;
3044 if (printMode > 0 && printMode < lastPrintMode) {
3045 cmd = printCmds[printMode];
3046 } else {
3047 cmd = printCmds[printMode = 0];
3048 }
3049 char *cmdf = r_str_newf ("%s @ 0x%"PFMT64x, cmd, addr + delta);
3050 if (!cmdf) {
3051 return;
3052 }
3053 char *output = r_core_cmd_str (core, cmdf);
3054 if (output) {
3055 // 'h - 2' because we have two new lines in r_cons_printf
3056 char *out = r_str_ansi_crop (output, 0, 0, w - colpos, h - 2);
3057 r_cons_printf ("\n%s\n", out);
3058 free (out);
3059 R_FREE (output);
3060 }
3061 free (cmdf);
3062 }
3063
3064 static const char *help_fun_visual[] = {
3065 "(a)", "analyze ", "(-)", "delete ", "(x)", "xrefs ", "(X)", "refs ", "(j/k)", "next/prev\n",
3066 "(r)", "rename ", "(c)", "calls ", "(d)", "define ", "(Tab)", "disasm ", "(_)", "hud\n",
3067 "(d)", "define ", "(v)", "vars ", "(?)", " help ", "(:)", "shell " ,"(q)", "quit\n",
3068 "(s)", "edit function signature\n\n",
3069 NULL
3070 };
3071
3072 static const char *help_var_visual[] = {
3073 "(a)", "add " ,"(x)", "xrefs ", "(r)", "rename\n",
3074 "(t)", "type ", "(g)", "go ", "(-)" ,"delete\n",
3075 "(q)", "quit ", "(s)", "signature\n\n",
3076 NULL
3077 };
3078
3079 static const char *help_visual_anal_actions[] = {
3080 "functions:", "Add, Modify, Delete, Xrefs Calls Vars",
3081 "variables:", "Add, Modify, Delete",
3082 NULL
3083 };
3084
3085 static const char *help_visual_anal_keys[] = {
3086 "j/k", "select next/prev item; scroll disasm column",
3087 "J/K", "scroll next/prev by page",
3088 "b/h", "functions analysis (level 0)",
3089 "v/l", "variables analysis (level 1)",
3090 "c", "calls/xref analysis (level 2)",
3091 "q/Q", "go back one level or quit",
3092 "Space/Enter", "quit",
3093 "p/P", "switch next/prev print mode",
3094 "x/X", "see xrefs to the selected function",
3095 "Tab", "disasm column scrolling",
3096 "!", "run `afls` to sort all functions by address",
3097 ".", "seek to current function address",
3098 ":", "run r2 commands",
3099 "_", "hud mode, same as `s $(afl~...)`",
3100 NULL
3101 };
3102
r_core_vmenu_append_help(RStrBuf * p,const char ** help)3103 static void r_core_vmenu_append_help (RStrBuf *p, const char **help) {
3104 int i;
3105 RConsContext *cons_ctx = r_cons_singleton ()->context;
3106 const char *pal_args_color = cons_ctx->color_mode ? cons_ctx->pal.args : "",
3107 *pal_help_color = cons_ctx->color_mode ? cons_ctx->pal.help : "",
3108 *pal_reset = cons_ctx->color_mode ? cons_ctx->pal.reset : "";
3109
3110 for (i = 0; help[i]; i += 2) {
3111 r_strbuf_appendf (p, "%s%s %s%s%s",
3112 pal_args_color, help[i],
3113 pal_help_color, help[i + 1], pal_reset);
3114 }
3115 }
3116
r_core_visual_anal_refresh(RCore * core)3117 static ut64 r_core_visual_anal_refresh (RCore *core) {
3118 if (!core) {
3119 return 0LL;
3120 }
3121 ut64 addr;
3122 RStrBuf *buf;
3123 char old[1024];
3124 bool color = r_config_get_i (core->config, "scr.color");
3125 int h, cols = r_cons_get_size (&h);
3126 old[0] = '\0';
3127 addr = core->offset;
3128 cols -= 50;
3129 if (cols > 60) {
3130 cols = 60;
3131 }
3132
3133 r_cons_clear00 ();
3134 r_core_visual_anal_refresh_column (core, cols);
3135 if (cols > 30) {
3136 r_cons_column (cols);
3137 }
3138 switch (level) {
3139 // Show functions list help in visual mode
3140 case 0:
3141 buf = r_strbuf_new ("");
3142 if (color) {
3143 r_cons_strcat (core->cons->context->pal.prompt);
3144 }
3145 if (selectPanel) {
3146 r_cons_printf ("-- functions -----------------[ %s ]-->>", printCmds[printMode]);
3147 } else {
3148 r_cons_printf ("-[ functions ]----------------- %s ---", printCmds[printMode]);
3149 }
3150 if (color) {
3151 r_cons_strcat ("\n" Color_RESET);
3152 }
3153 r_core_vmenu_append_help (buf, help_fun_visual);
3154 r_cons_printf ("%s", r_strbuf_drain (buf));
3155 addr = var_functions_show (core, option, 1, cols);
3156 break;
3157 case 1:
3158 buf = r_strbuf_new ("");
3159 if (color) {
3160 r_cons_strcat (core->cons->context->pal.prompt);
3161 }
3162 r_cons_printf ("-[ variables ]----- 0x%08"PFMT64x"", addr);
3163 if (color) {
3164 r_cons_strcat ("\n" Color_RESET);
3165 }
3166 r_core_vmenu_append_help (buf, help_var_visual);
3167 char *drained = r_strbuf_drain (buf);
3168 r_cons_printf ("%s", drained);
3169 addr = var_variables_show (core, option, &variable_option, 1, cols);
3170 free (drained);
3171 // var_index_show (core->anal, fcn, addr, option);
3172 break;
3173 case 2:
3174 r_cons_printf ("Press 'q' to quit call refs\n");
3175 if (color) {
3176 r_cons_strcat (core->cons->context->pal.prompt);
3177 }
3178 r_cons_printf ("-[ calls ]----------------------- 0x%08"PFMT64x" (TODO)\n", addr);
3179 if (color) {
3180 r_cons_strcat ("\n" Color_RESET);
3181 }
3182 // TODO: filter only the callrefs. but we cant grep here
3183 sprintf (old, "afi @ 0x%08"PFMT64x, addr);
3184 char *output = r_core_cmd_str (core, old);
3185 if (output) {
3186 // 'h - 2' because we have two new lines in r_cons_printf
3187 if (!r_cons_singleton ()->show_vals) {
3188 char *out = r_str_ansi_crop(output, 0, 0, cols, h - 2);
3189 r_cons_printf ("\n%s\n", out);
3190 free (out);
3191 R_FREE (output);
3192 } else {
3193 r_cons_printf ("\n%s\n", output);
3194 R_FREE (output);
3195 }
3196 }
3197 break;
3198 default:
3199 // assert
3200 break;
3201 }
3202 r_cons_flush ();
3203 return addr;
3204 }
3205
r_core_visual_anal_refresh_oneshot(RCore * core)3206 static void r_core_visual_anal_refresh_oneshot (RCore *core) {
3207 r_core_task_enqueue_oneshot (&core->tasks, (RCoreTaskOneShot) r_core_visual_anal_refresh, core);
3208 }
3209
r_core_visual_debugtraces_help(RCore * core)3210 static void r_core_visual_debugtraces_help(RCore *core) {
3211 r_cons_clear00 ();
3212 r_cons_printf (
3213 "vbd: Visual Browse Debugtraces:\n\n"
3214 " q - quit the bit editor\n"
3215 " Q - Quit (jump into the disasm view)\n"
3216 " j/k - Select next/previous trace\n"
3217 " : - enter command\n");
3218 r_cons_flush ();
3219 r_cons_any_key (NULL);
3220 }
3221
r_core_visual_debugtraces(RCore * core,const char * input)3222 R_API void r_core_visual_debugtraces(RCore *core, const char *input) {
3223 int i, delta = 0;
3224 for (;;) {
3225 char *trace_addr_str = r_core_cmd_strf (core, "dtdq %d", delta);
3226 ut64 trace_addr = r_num_get (NULL, trace_addr_str);
3227 free (trace_addr_str);
3228 r_cons_printf ("[0x%08"PFMT64x"]> %d dbg.trace\n", trace_addr, delta);
3229 for (i = 0; i < delta; i++) {
3230 r_core_cmdf (core, ".dte %d", i);
3231 }
3232 r_core_cmd0 (core, "x 64@r:SP");
3233 r_core_cmd0 (core, "dri");
3234 // limit by rows here
3235 //int rows = r_cons_get_size (NULL);
3236 r_core_cmdf (core, "dtd %d", delta);
3237 r_cons_visual_flush ();
3238 char ch ;
3239 if (input && *input) {
3240 ch = *input;
3241 input++;
3242 } else {
3243 ch = r_cons_readchar ();
3244 }
3245 if (ch == 4 || ch == -1) {
3246 if (level == 0) {
3247 goto beach;
3248 }
3249 level--;
3250 continue;
3251 }
3252 ch = r_cons_arrow_to_hjkl (ch); // get ESC+char, return 'hjkl' char
3253 switch (ch) {
3254 case 'Q': // tab
3255 {
3256 ut64 oseek = core->offset;
3257 core->vmode = false;
3258 r_core_seek (core, trace_addr, true);
3259 r_core_visual (core, "");
3260 r_core_seek (core, oseek, true);
3261 }
3262 break;
3263 case 'q':
3264 goto beach;
3265 break;
3266 case ']':
3267 r_config_set_i (core->config, "hex.cols", r_config_get_i (core->config, "hex.cols") + 1);
3268 break;
3269 case '[':
3270 r_config_set_i (core->config, "hex.cols", r_config_get_i (core->config, "hex.cols") - 1);
3271 break;
3272 case 'J':
3273 delta += 10;
3274 break;
3275 case 'K':
3276 delta -= 10;
3277 if (delta < 0) {
3278 delta = 0;
3279 }
3280 case 'j':
3281 delta++;
3282 break;
3283 case 'k':
3284 delta--;
3285 if (delta < 0) {
3286 delta = 0;
3287 }
3288 break;
3289 case ':':
3290 r_core_visual_prompt (core);
3291 r_cons_any_key (NULL);
3292 break;
3293 case '?':
3294 r_core_visual_debugtraces_help (core);
3295 break;
3296 }
3297 }
3298 beach:
3299 ;
3300 }
3301
__prompt(const char * msg,void * p)3302 static char *__prompt(const char *msg, void *p) {
3303 char res[128];
3304 r_cons_show_cursor (true);
3305 r_cons_set_raw (false);
3306 r_line_set_prompt (msg);
3307 res[0] =0;
3308 if (!r_cons_fgets (res, sizeof (res), 0, NULL)) {
3309 res[0] = 0;
3310 }
3311 return strdup (res);
3312 }
3313
addVar(RCore * core,int ch,const char * msg)3314 static void addVar(RCore *core, int ch, const char *msg) {
3315 char *src = __prompt (msg, NULL);
3316 char *name = __prompt ("Variable Name: ", NULL);
3317 char *type = __prompt ("Type of Variable (int32_t): ", NULL);
3318 char *cmd = r_str_newf ("afv%c %s %s %s", ch, src, name, type);
3319 r_str_trim (cmd);
3320 r_core_cmd0 (core, cmd);
3321 free(cmd);
3322 free (src);
3323 free (name);
3324 free (type);
3325 }
3326
3327 /* Like emenu but for real */
r_core_visual_anal(RCore * core,const char * input)3328 R_API void r_core_visual_anal(RCore *core, const char *input) {
3329 char old[218];
3330 int nfcns, ch, _option = 0;
3331
3332 RConsEvent olde = core->cons->event_resize;
3333 void *olde_user = core->cons->event_data;
3334 ut64 addr = core->offset;
3335
3336 core->cons->event_resize = NULL; // avoid running old event with new data
3337 core->cons->event_data = core;
3338 core->cons->event_resize = (RConsEvent) r_core_visual_anal_refresh_oneshot;
3339
3340 level = 0;
3341
3342 int asmbytes = r_config_get_i (core->config, "asm.bytes");
3343 r_config_set_i (core->config, "asm.bytes", 0);
3344 for (;;) {
3345 nfcns = r_list_length (core->anal->fcns);
3346 addr = r_core_visual_anal_refresh (core);
3347 if (input && *input) {
3348 ch = *input;
3349 input++;
3350 } else {
3351 ch = r_cons_readchar ();
3352 }
3353 if (ch == 4 || ch == -1) {
3354 if (level == 0) {
3355 goto beach;
3356 }
3357 level--;
3358 continue;
3359 }
3360 ch = r_cons_arrow_to_hjkl (ch); // get ESC+char, return 'hjkl' char
3361 switch (ch) {
3362 case '[':
3363 r_cons_singleton ()->show_vals = true;
3364 break;
3365 case ']':
3366 r_cons_singleton ()->show_vals = false;
3367 break;
3368 case '?':
3369 r_cons_clear00 ();
3370 RStrBuf *rsb = r_strbuf_new ("");
3371 r_core_visual_append_help (rsb, "Functions/Variables Visual Analysis Mode (Vv) Help", (const char *[]){ NULL });
3372 r_core_visual_append_help (rsb, "Actions Supported", help_visual_anal_actions);
3373 r_core_visual_append_help (rsb, "Keys", help_visual_anal_keys);
3374 r_cons_less_str (r_strbuf_get (rsb), "?");
3375 r_strbuf_free (rsb);
3376 break;
3377 case 9:
3378 selectPanel = !selectPanel;
3379 if (!selectPanel) {
3380 delta = 0;
3381 printMode = 0;
3382 }
3383 break;
3384 case ':':
3385 {
3386 ut64 orig = core->offset;
3387 r_core_seek (core, addr, false);
3388 while (r_core_visual_prompt (core));
3389 r_core_seek (core, orig, false);
3390 }
3391 continue;
3392 case '/':
3393 r_core_cmd0 (core, "?i highlight;e scr.highlight=`yp`");
3394 break;
3395 case 'a':
3396 switch (level) {
3397 case 0:
3398 r_core_cmd0 (core, "af-$$;af"); // reanalize
3399 break;
3400 case 1:
3401 {
3402 eprintf ("Select variable source ('r'egister, 's'tackptr or 'b'aseptr): ");
3403 int type = r_cons_readchar ();
3404 switch (type) {
3405 case 'r':
3406 addVar (core, type, "Source Register Name: ");
3407 break;
3408 case 's':
3409 addVar (core, type, "BP Relative Delta: ");
3410 break;
3411 case 'b':
3412 addVar (core, type, "SP Relative Delta: ");
3413 break;
3414 }
3415 }
3416 break;
3417 }
3418 break;
3419 case 'r':
3420 {
3421 switch (level) {
3422 case 1:
3423 r_cons_show_cursor (true);
3424 r_cons_set_raw (false);
3425 r_line_set_prompt ("New name: ");
3426 if (r_cons_fgets (old, sizeof (old), 0, NULL)) {
3427 if (*old) {
3428 //old[strlen (old)-1] = 0;
3429 variable_rename (core, addr, variable_option, old);
3430 }
3431 }
3432 break;
3433 default:
3434 r_line_set_prompt ("New name: ");
3435 if (r_cons_fgets (old, sizeof (old), 0, NULL)) {
3436 if (*old) {
3437 //old[strlen (old)-1] = 0;
3438 function_rename (core, addr, old);
3439 }
3440 }
3441 break;
3442 }
3443 r_cons_set_raw (true);
3444 r_cons_show_cursor (false);
3445 }
3446 break;
3447 case 't':
3448 if (level == 1) {
3449 r_cons_show_cursor (true);
3450 r_cons_set_raw (false);
3451 r_line_set_prompt ("New type: ");
3452 if (r_cons_fgets (old, sizeof (old), 0, NULL)) {
3453 if (*old) {
3454 //old[strlen (old)-1] = 0;
3455 variable_set_type (core, addr, variable_option, old);
3456 }
3457 }
3458 r_cons_set_raw (true);
3459 r_cons_show_cursor (false);
3460 }
3461 break;
3462 case '.':
3463 delta = 0;
3464 break;
3465 case 'R':
3466 r_core_cmd0 (core, "ecn");
3467 break;
3468 case 'p':
3469 printMode ++;
3470 break;
3471 case 'P':
3472 if (printMode == 0) {
3473 printMode = lastPrintMode;
3474 } else {
3475 printMode --;
3476 }
3477 break;
3478 case 'd':
3479 r_core_visual_define(core, "", 0);
3480 break;
3481 case '-':
3482 switch (level) {
3483 case 0:
3484 r_core_cmdf (core, "af-0x%"PFMT64x, addr);
3485 break;
3486 }
3487 break;
3488 case 'x':
3489 r_core_visual_refs (core, false, true);
3490 break;
3491 case 'X':
3492 r_core_visual_refs (core, true, true);
3493 break;
3494 case 's':
3495 r_core_cmdf (core, "afs!@0x%08"PFMT64x, addr);
3496 break;
3497 case 'c':
3498 level = 2;
3499 break;
3500 case 'v':
3501 level = 1;
3502 variable_option = 0;
3503 break;
3504 case '_':
3505 {
3506 r_core_cmd0 (core, "s $(afl~...)");
3507 int n = 0;
3508 RListIter *iter;
3509 RAnalFunction *fcn;
3510 r_list_foreach (core->anal->fcns, iter, fcn) {
3511 if (fcn->addr == core->offset) {
3512 option = n;
3513 break;
3514 }
3515 n ++;
3516 }
3517 }
3518 break;
3519 case 'j':
3520 if (selectPanel) {
3521 printMode = 1;
3522 delta += 16;
3523 } else {
3524 delta = 0;
3525 switch (level) {
3526 case 1:
3527 variable_option++;
3528 break;
3529 default:
3530 option++;
3531 if (option >= nfcns) {
3532 --option;
3533 }
3534 break;
3535 }
3536 }
3537 break;
3538 case '!':
3539 // TODO: use aflsn/aflsb/aflss/...
3540 {
3541 static int sortMode = 0;
3542 const char *sortModes[4] = { "aflsa", "aflss", "aflsb", "aflsn" };
3543 r_core_cmd0 (core, sortModes[sortMode%4]);
3544 sortMode++;
3545 }
3546 break;
3547 case 'k':
3548 if (selectPanel) {
3549 printMode = 1;
3550 delta -= 16;
3551 } else {
3552 delta = 0;
3553 switch (level) {
3554 case 1:
3555 variable_option = (variable_option<=0)? 0: variable_option-1;
3556 break;
3557 default:
3558 option = (option<=0)? 0: option-1;
3559 break;
3560 }
3561 }
3562
3563 break;
3564 case 'J':
3565 if (selectPanel) {
3566 printMode = 1;
3567 delta += 40;
3568 } else {
3569 int rows = 0;
3570 r_cons_get_size (&rows);
3571 option += (rows - 5);
3572 if (option >= nfcns) {
3573 option = nfcns - 1;
3574 }
3575 }
3576 break;
3577 case 'K':
3578 if (selectPanel) {
3579 printMode = 1;
3580 delta -= 40;
3581 } else {
3582 int rows = 0;
3583 r_cons_get_size (&rows);
3584 option -= (rows - 5);
3585 if (option < 0) {
3586 option = 0;
3587 }
3588 }
3589 break;
3590 case 'g': {
3591 r_core_visual_showcursor (core, true);
3592 r_core_visual_offset (core); // change the seek to selected offset
3593 RListIter *iter; // change the current option to selected seek
3594 RAnalFunction *fcn;
3595 int i = 0;
3596 r_list_foreach (core->anal->fcns, iter, fcn) {
3597 if (core->offset == fcn->addr){
3598 option = i;
3599 }
3600 i++;
3601 }
3602 r_core_visual_showcursor (core, false);
3603 }
3604 break;
3605 case 'G':
3606 r_core_seek (core, addr, SEEK_SET);
3607 goto beach;
3608 case ' ':
3609 case '\r':
3610 case '\n':
3611 level = 0;
3612 r_core_seek (core, addr, SEEK_SET);
3613 goto beach;
3614 case 'l':
3615 level = 1;
3616 _option = option;
3617 break;
3618 case 'h':
3619 case 'b': // back
3620 level = 0;
3621 option = _option;
3622 break;
3623 case 'Q':
3624 case 'q':
3625 if (level == 0) {
3626 goto beach;
3627 }
3628 level--;
3629 break;
3630 }
3631 }
3632 beach:
3633 core->cons->event_resize = NULL; // avoid running old event with new data
3634 core->cons->event_data = olde_user;
3635 core->cons->event_resize = olde;
3636 level = 0;
3637 r_config_set_i (core->config, "asm.bytes", asmbytes);
3638 }
3639
3640 struct seek_flag_offset_t {
3641 ut64 offset;
3642 ut64 *next;
3643 bool is_next;
3644 };
3645
seek_flag_offset(RFlagItem * fi,void * user)3646 static bool seek_flag_offset(RFlagItem *fi, void *user) {
3647 struct seek_flag_offset_t *u = (struct seek_flag_offset_t *)user;
3648 if (u->is_next) {
3649 if (fi->offset < *u->next && fi->offset > u->offset) {
3650 *u->next = fi->offset;
3651 }
3652 } else {
3653 if (fi->offset > *u->next && fi->offset < u->offset) {
3654 *u->next = fi->offset;
3655 }
3656 }
3657 return true;
3658 }
3659
r_core_seek_next(RCore * core,const char * type)3660 R_API void r_core_seek_next(RCore *core, const char *type) {
3661 RListIter *iter;
3662 ut64 next = UT64_MAX;
3663 if (strstr (type, "opc")) {
3664 RAnalOp aop;
3665 if (r_anal_op (core->anal, &aop, core->offset, core->block, core->blocksize, R_ANAL_OP_MASK_BASIC)) {
3666 next = core->offset + aop.size;
3667 } else {
3668 eprintf ("Invalid opcode\n");
3669 }
3670 } else if (strstr (type, "fun")) {
3671 RAnalFunction *fcni;
3672 r_list_foreach (core->anal->fcns, iter, fcni) {
3673 if (fcni->addr < next && fcni->addr > core->offset) {
3674 next = fcni->addr;
3675 }
3676 }
3677 } else if (strstr (type, "hit")) {
3678 const char *pfx = r_config_get (core->config, "search.prefix");
3679 struct seek_flag_offset_t u = { .offset = core->offset, .next = &next, .is_next = true };
3680 r_flag_foreach_prefix (core->flags, pfx, -1, seek_flag_offset, &u);
3681 } else { // flags
3682 struct seek_flag_offset_t u = { .offset = core->offset, .next = &next, .is_next = true };
3683 r_flag_foreach (core->flags, seek_flag_offset, &u);
3684 }
3685 if (next != UT64_MAX) {
3686 r_core_seek (core, next, true);
3687 }
3688 }
3689
r_core_seek_previous(RCore * core,const char * type)3690 R_API void r_core_seek_previous (RCore *core, const char *type) {
3691 RListIter *iter;
3692 ut64 next = 0;
3693 if (strstr (type, "opc")) {
3694 eprintf ("TODO: r_core_seek_previous (opc)\n");
3695 } else
3696 if (strstr (type, "fun")) {
3697 RAnalFunction *fcni;
3698 r_list_foreach (core->anal->fcns, iter, fcni) {
3699 if (fcni->addr > next && fcni->addr < core->offset) {
3700 next = fcni->addr;
3701 }
3702 }
3703 } else
3704 if (strstr (type, "hit")) {
3705 const char *pfx = r_config_get (core->config, "search.prefix");
3706 struct seek_flag_offset_t u = { .offset = core->offset, .next = &next, .is_next = false };
3707 r_flag_foreach_prefix (core->flags, pfx, -1, seek_flag_offset, &u);
3708 } else { // flags
3709 struct seek_flag_offset_t u = { .offset = core->offset, .next = &next, .is_next = false };
3710 r_flag_foreach (core->flags, seek_flag_offset, &u);
3711 }
3712 if (next != 0) {
3713 r_core_seek (core, next, true);
3714 }
3715 }
3716
3717 //define the data at offset according to the type (byte, word...) n times
define_data_ntimes(RCore * core,ut64 off,int times,int type)3718 static void define_data_ntimes (RCore *core, ut64 off, int times, int type) {
3719 int i = 0;
3720 r_meta_del (core->anal, R_META_TYPE_ANY, off, core->blocksize);
3721 if (times < 0) {
3722 times = 1;
3723 }
3724 for (i = 0; i < times; i++, off += type) {
3725 r_meta_set (core->anal, R_META_TYPE_DATA, off, type, "");
3726 }
3727 }
3728
isDisasmPrint(int mode)3729 static bool isDisasmPrint(int mode) {
3730 return (mode == 1 || mode == 2);
3731 }
3732
handleHints(RCore * core)3733 static void handleHints(RCore *core) {
3734 //TODO extend for more anal hints
3735 int i = 0;
3736 char ch[64] = R_EMPTY;
3737 const char *lines[] = {"[dh]- Define anal hint:"
3738 ," b [16,32,64] set bits hint"
3739 , NULL};
3740 for (i = 0; lines[i]; i++) {
3741 r_cons_fill_line ();
3742 r_cons_printf ("\r%s\n", lines[i]);
3743 }
3744 r_cons_flush ();
3745 r_line_set_prompt ("anal hint: ");
3746 if (r_cons_fgets (ch, sizeof (ch), 0, NULL) > 0) {
3747 switch (ch[0]) {
3748 case 'b':
3749 {
3750 char *arg = ch + 1;
3751 r_str_trim (arg);
3752 int bits = atoi (arg);
3753 if (bits == 8 || bits == 16 || bits == 32 || bits == 64) {
3754 r_anal_hint_set_bits (core->anal, core->offset, bits);
3755 }
3756 }
3757 break;
3758 default:
3759 break;
3760 }
3761 }
3762 }
3763
r_core_visual_define(RCore * core,const char * args,int distance)3764 R_API void r_core_visual_define(RCore *core, const char *args, int distance) {
3765 int plen = core->blocksize;
3766 ut64 off = core->offset;
3767 int i, h = 0, n, ch, ntotal = 0;
3768 ut8 *p = core->block;
3769 int rep = -1;
3770 char *name;
3771 int delta = 0;
3772 if (core->print->cur_enabled) {
3773 int cur = core->print->cur;
3774 if (core->print->ocur != -1) {
3775 plen = R_ABS (core->print->cur - core->print->ocur) + 1;
3776 if (core->print->ocur<cur) {
3777 cur = core->print->ocur;
3778 }
3779 }
3780 off += cur;
3781 p += cur;
3782 }
3783 (void) r_cons_get_size (&h);
3784 h -= 19;
3785 if (h < 0) {
3786 h = 0;
3787 r_cons_clear00 ();
3788 } else {
3789 r_cons_gotoxy (0, 3);
3790 }
3791 const char *lines[] = { ""
3792 ,"[Vd]- Define current block as:"
3793 ," $ define flag size"
3794 ," 1 edit bits"
3795 ," a assembly"
3796 ," b as byte (1 byte)"
3797 ," B define half word (16 bit, 2 byte size)"
3798 ," c as code (unset any data / string / format) in here"
3799 ," C define flag color (fc)"
3800 ," d set as data"
3801 ," e end of function"
3802 ," f analyze function"
3803 ," F format"
3804 ," h define hint (for half-word, see 'B')"
3805 ," i (ahi) immediate base (b(in), o(ct), d(ec), h(ex), s(tr))"
3806 ," I (ahi1) immediate base (b(in), o(ct), d(ec), h(ex), s(tr))"
3807 ," j merge down (join this and next functions)"
3808 ," k merge up (join this and previous function)"
3809 ," h define anal hint"
3810 ," m manpage for current call"
3811 ," n rename flag used at cursor"
3812 ," N edit function signature (afs!)"
3813 ," o opcode string"
3814 ," r rename function"
3815 ," R find references /r"
3816 ," s set string"
3817 ," S set strings in current block"
3818 ," t set opcode type via aht hints (call, nop, jump, ...)"
3819 ," u undefine metadata here"
3820 ," v rename variable at offset that matches some hex digits"
3821 ," x find xrefs to current address (./r)"
3822 ," w set as 32bit word"
3823 ," W set as 64bit word"
3824 ," q quit menu"
3825 ," z zone flag"
3826 , NULL};
3827 for (i = 0; lines[i]; i++) {
3828 r_cons_fill_line ();
3829 r_cons_printf ("\r%s\n", lines[i]);
3830 }
3831 r_cons_flush ();
3832 int wordsize = 0;
3833 // get ESC+char, return 'hjkl' char
3834 repeat:
3835 if (*args) {
3836 ch = *args;
3837 args++;
3838 } else {
3839 ch = r_cons_arrow_to_hjkl (r_cons_readchar ());
3840 }
3841
3842 onemoretime:
3843 wordsize = 4;
3844 switch (ch) {
3845 case 'N':
3846 r_core_cmdf (core, "afs! @ 0x%08"PFMT64x, off);
3847 break;
3848 case 'F':
3849 {
3850 char cmd[128];
3851 r_cons_show_cursor (true);
3852 r_core_cmd0 (core, "pf?");
3853 r_cons_flush ();
3854 r_line_set_prompt ("format: ");
3855 strcpy (cmd, "Cf 0 ");
3856 if (r_cons_fgets (cmd + 5, sizeof (cmd) - 5, 0, NULL) > 0) {
3857 r_core_cmdf (core, "%s @ 0x%08"PFMT64x, cmd, off);
3858 r_cons_set_raw (1);
3859 r_cons_show_cursor (false);
3860 }
3861 }
3862 break;
3863 case '1':
3864 r_core_visual_bit_editor (core);
3865 break;
3866 case 't':
3867 case 'o':
3868 {
3869 char str[128];
3870 r_cons_show_cursor (true);
3871 r_line_set_prompt (ch=='t'?"type: ": "opstr: ");
3872 if (r_cons_fgets (str, sizeof (str), 0, NULL) > 0) {
3873 r_core_cmdf (core, "ah%c %s @ 0x%"PFMT64x, ch, str, off);
3874 }
3875 }
3876 break;
3877 case 'x':
3878 r_core_cmd0 (core, "/r $$");
3879 break;
3880 case 'i':
3881 {
3882 char str[128];
3883 r_cons_show_cursor (true);
3884 r_line_set_prompt ("immbase: ");
3885 if (r_cons_fgets (str, sizeof (str), 0, NULL) > 0) {
3886 r_core_cmdf (core, "ahi %s @ 0x%"PFMT64x, str, off);
3887 }
3888 }
3889 break;
3890 case 'I':
3891 {
3892 char str[128];
3893 r_cons_show_cursor (true);
3894 r_line_set_prompt ("immbase: ");
3895 if (r_cons_fgets (str, sizeof (str), 0, NULL) > 0) {
3896 r_core_cmdf (core, "ahi1 %s @ 0x%"PFMT64x, str, off);
3897 }
3898 }
3899 break;
3900 case 'a':
3901 r_core_visual_asm (core, off);
3902 break;
3903 case 'b':
3904 if (plen != core->blocksize) {
3905 rep = plen / 2;
3906 }
3907 define_data_ntimes (core, off, rep, R_BYTE_DATA);
3908 wordsize = 1;
3909 break;
3910 case 'B': // "VdB"
3911 if (plen != core->blocksize) {
3912 rep = plen / 2;
3913 }
3914 define_data_ntimes (core, off, rep, R_WORD_DATA);
3915 wordsize = 2;
3916 break;
3917 case 'w':
3918 if (plen != core->blocksize) {
3919 rep = plen / 4;
3920 }
3921 define_data_ntimes (core, off, rep, R_DWORD_DATA);
3922 wordsize = 4;
3923 break;
3924 case 'W':
3925 if (plen != core->blocksize) {
3926 rep = plen / 8;
3927 }
3928 define_data_ntimes (core, off, rep, R_QWORD_DATA);
3929 wordsize = 8;
3930 break;
3931 case 'm':
3932 {
3933 char *man = NULL;
3934 /* check for manpage */
3935 RAnalOp *op = r_core_anal_op (core, off, R_ANAL_OP_MASK_BASIC);
3936 if (op) {
3937 if (op->jump != UT64_MAX) {
3938 RFlagItem *item = r_flag_get_i (core->flags, op->jump);
3939 if (item) {
3940 const char *ptr = r_str_lchr (item->name, '.');
3941 if (ptr) {
3942 man = strdup (ptr + 1);
3943 }
3944 }
3945 }
3946 r_anal_op_free (op);
3947 }
3948 if (man) {
3949 char *p = strstr (man, "INODE");
3950 if (p) {
3951 *p = 0;
3952 }
3953 r_cons_clear ();
3954 r_cons_flush ();
3955 r_sys_cmdf ("man %s", man);
3956 free (man);
3957 }
3958 r_cons_any_key (NULL);
3959 }
3960 break;
3961 case 'n':
3962 {
3963 RAnalOp op;
3964 char *q = NULL;
3965 ut64 tgt_addr = UT64_MAX;
3966 if (!isDisasmPrint (core->printidx)) {
3967 break;
3968 }
3969 // TODO: get the aligned instruction even if the cursor is in the middle of it.
3970 r_anal_op (core->anal, &op, off,
3971 core->block + off - core->offset, 32, R_ANAL_OP_MASK_BASIC);
3972
3973 tgt_addr = op.jump != UT64_MAX ? op.jump : op.ptr;
3974 RAnalVar *var = r_anal_get_used_function_var (core->anal, op.addr);
3975 if (var) {
3976 // q = r_str_newf ("?i Rename variable %s to;afvn %s `yp`", op.var->name, op.var->name);
3977 char *newname = r_cons_input (sdb_fmt ("New variable name for '%s': ", var->name));
3978 if (newname && *newname) {
3979 r_anal_var_rename (var, newname, true);
3980 free (newname);
3981 }
3982 } else if (tgt_addr != UT64_MAX) {
3983 RAnalFunction *fcn = r_anal_get_function_at (core->anal, tgt_addr);
3984 RFlagItem *f = r_flag_get_i (core->flags, tgt_addr);
3985 if (fcn) {
3986 q = r_str_newf ("?i Rename function %s to;afn `yp` 0x%"PFMT64x,
3987 fcn->name, tgt_addr);
3988 } else if (f) {
3989 q = r_str_newf ("?i Rename flag %s to;fr %s `yp`",
3990 f->name, f->name);
3991 } else {
3992 q = r_str_newf ("?i Create flag at 0x%"PFMT64x" named;f `yp` @ 0x%"PFMT64x,
3993 tgt_addr, tgt_addr);
3994 }
3995 }
3996
3997 if (q) {
3998 r_core_cmd0 (core, q);
3999 free (q);
4000 }
4001 r_anal_op_fini (&op);
4002 break;
4003 }
4004 case 'C':
4005 {
4006 RFlagItem *item = r_flag_get_i (core->flags, off);
4007 if (item) {
4008 char cmd[128];
4009 r_cons_show_cursor (true);
4010 r_cons_flush ();
4011 r_line_set_prompt ("color: ");
4012 if (r_cons_fgets (cmd, sizeof (cmd), 0, NULL) > 0) {
4013 r_flag_item_set_color (item, cmd);
4014 r_cons_set_raw (1);
4015 r_cons_show_cursor (false);
4016 }
4017 } else {
4018 eprintf ("Sorry. No flag here\n");
4019 r_cons_any_key (NULL);
4020 }
4021 }
4022 break;
4023 case '$':
4024 {
4025 RFlagItem *item = r_flag_get_i (core->flags, off);
4026 if (item) {
4027 char cmd[128];
4028 r_cons_printf ("Current flag size is: %" PFMT64d "\n", item->size);
4029 r_cons_show_cursor (true);
4030 r_cons_flush ();
4031 r_line_set_prompt ("new size: ");
4032 if (r_cons_fgets (cmd, sizeof (cmd), 0, NULL) > 0) {
4033 item->size = r_num_math (core->num, cmd);
4034 r_cons_set_raw (1);
4035 r_cons_show_cursor (false);
4036 }
4037 } else {
4038 eprintf ("Sorry. No flag here\n");
4039 r_cons_any_key (NULL);
4040 }
4041 }
4042 break;
4043 case 'e':
4044 // set function size
4045 {
4046 RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, off, 0);
4047 if (!fcn) {
4048 fcn = r_anal_get_fcn_in (core->anal, core->offset, 0);
4049 }
4050 if (fcn) {
4051 RAnalOp op;
4052 ut64 size;
4053 if (r_anal_op (core->anal, &op, off, core->block+delta,
4054 core->blocksize-delta, R_ANAL_OP_MASK_BASIC)) {
4055 size = off - fcn->addr + op.size;
4056 r_anal_function_resize (fcn, size);
4057 }
4058 }
4059 }
4060 break;
4061 case 'j':
4062 r_core_cmdf (core, "afm $$+$F @0x%08"PFMT64x, off);
4063 break;
4064 case 'k':
4065 eprintf ("TODO: merge up\n");
4066 r_cons_any_key (NULL);
4067 break;
4068 // very weak and incomplete
4069 case 'h': // "Vdh"
4070 handleHints (core);
4071 break;
4072 case 'r': // "Vdr"
4073 r_core_cmdf (core, "?i new function name;afn `yp` @ 0x%08"PFMT64x, off);
4074 break;
4075 case 'z': // "Vdz"
4076 r_core_cmdf (core, "?i zone name;fz `yp` @ 0x%08"PFMT64x, off);
4077 break;
4078 case 'R': // "VdR"
4079 eprintf ("Finding references to 0x%08"PFMT64x" ...\n", off);
4080 r_core_cmdf (core, "./r 0x%08"PFMT64x" @ $S", off);
4081 break;
4082 case 'S':
4083 {
4084 int i, j;
4085 bool is_wide = false;
4086 do {
4087 n = r_str_nlen_w ((const char *)p + ntotal,
4088 plen - ntotal) + 1;
4089 if (n < 2) {
4090 break;
4091 }
4092 name = malloc (n + 10);
4093 strcpy (name, "str.");
4094 for (i = 0, j = 0; i < n; i++, j++) {
4095 name[4 + i] = p[j + ntotal];
4096 if (!p[j + ntotal]) {
4097 break;
4098 }
4099 if (!p[j + 1 + ntotal]) {
4100 //check if is still wide
4101 if (j + 3 + ntotal < n) {
4102 if (p[j + 3]) {
4103 break;
4104 }
4105 }
4106 is_wide = true;
4107 j++;
4108 }
4109 }
4110 name[4 + n] = '\0';
4111 if (is_wide) {
4112 r_meta_set (core->anal, R_META_TYPE_STRING,
4113 off + ntotal, (n * 2) + ntotal,
4114 (const char *) name + 4);
4115 } else {
4116 r_meta_set (core->anal, R_META_TYPE_STRING,
4117 off + ntotal, n + ntotal,
4118 (const char *) name + 4);
4119 }
4120 r_name_filter (name, n + 10);
4121 r_flag_set (core->flags, name, off + ntotal, n);
4122 free (name);
4123 if (is_wide) {
4124 ntotal += n * 2 - 1;
4125 } else {
4126 ntotal += n;
4127 }
4128 } while (ntotal < plen);
4129 wordsize = ntotal;
4130 }
4131 break;
4132 case 's':
4133 {
4134 int i, j;
4135 bool is_wide = false;
4136 if (core->print->ocur != -1) {
4137 n = plen;
4138 } else {
4139 n = r_str_nlen_w ((const char*)p, plen) + 1;
4140 }
4141 name = malloc (n + 10);
4142 if (!name) {
4143 break;
4144 }
4145 strcpy (name, "str.");
4146 for (i = 0, j = 0; i < n; i++, j++) {
4147 name[4 + i] = p[j];
4148 if (!p[j + 1]) {
4149 break;
4150 }
4151 if (!p[j + 1]) {
4152 if (j + 3 < n) {
4153 if (p[j + 3]) {
4154 break;
4155 }
4156 }
4157 is_wide = true;
4158 j++;
4159 }
4160 }
4161 name[4 + n] = '\0';
4162 //handle wide strings
4163 //memcpy (name + 4, (const char *)p, n);
4164 if (is_wide) {
4165 r_meta_set (core->anal, R_META_TYPE_STRING, off,
4166 n * 2, (const char *) name + 4);
4167 } else {
4168 r_meta_set (core->anal, R_META_TYPE_STRING, off,
4169 n, (const char *) name + 4);
4170 }
4171 r_name_filter (name, n + 10);
4172 r_flag_set (core->flags, name, off, n);
4173 wordsize = n;
4174 free (name);
4175 }
4176 break;
4177 case 'd': // TODO: check
4178 r_meta_del (core->anal, R_META_TYPE_ANY, off, plen);
4179 r_meta_set (core->anal, R_META_TYPE_DATA, off, plen, "");
4180 break;
4181 case 'c': // TODO: check
4182 r_meta_del (core->anal, R_META_TYPE_ANY, off, plen);
4183 r_meta_set (core->anal, R_META_TYPE_CODE, off, plen, "");
4184 break;
4185 case 'u':
4186 r_core_anal_undefine (core, off);
4187 break;
4188 case 'f':
4189 {
4190 RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset, 0);
4191 if (fcn) {
4192 r_anal_function_resize (fcn, core->offset - fcn->addr);
4193 }
4194 r_cons_break_push (NULL, NULL);
4195 r_core_cmdf (core, "af @ 0x%08" PFMT64x, off); // required for thumb autodetection
4196 r_cons_break_pop ();
4197 }
4198 break;
4199 case 'v':
4200 {
4201 ut64 N;
4202 char *endptr = NULL;
4203 char *end_off = r_cons_input ("Last hexadecimal digits of instruction: ");
4204 if (end_off) {
4205 N = strtoull (end_off, &endptr, 16);
4206 }
4207 if (!end_off || end_off == endptr) {
4208 eprintf ("Invalid numeric input\n");
4209 r_cons_any_key (NULL);
4210 free (end_off);
4211 break;
4212 }
4213 free (end_off);
4214
4215 ut64 incr = 0x10;
4216 ut64 tmp_N = N >> 4;
4217 while (tmp_N > 0) {
4218 tmp_N = tmp_N >> 4;
4219 incr = incr << 4;
4220 }
4221 ut64 mask = incr - 1;
4222
4223 ut64 start_off = (off & ~mask) ^ N;
4224 if ((off & mask) > N) {
4225 if (start_off > incr) {
4226 start_off -= incr;
4227 } else {
4228 start_off = N;
4229 }
4230 }
4231
4232 ut64 try_off;
4233 RAnalOp *op = NULL;
4234 RAnalVar *var = NULL;
4235 for (try_off = start_off; try_off < start_off + incr*16; try_off += incr) {
4236 r_anal_op_free (op);
4237 op = r_core_anal_op (core, try_off, R_ANAL_OP_MASK_ALL);
4238 if (!op) {
4239 break;
4240 }
4241 var = r_anal_get_used_function_var (core->anal, op->addr);
4242 if (var) {
4243 break;
4244 }
4245 }
4246
4247 if (var) {
4248 char *newname = r_cons_input (sdb_fmt ("New variable name for '%s': ", var->name));
4249 if (newname && *newname) {
4250 r_anal_var_rename (var, newname, true);
4251 free (newname);
4252 }
4253 } else {
4254 eprintf ("Cannot find instruction with a variable\n");
4255 r_cons_any_key (NULL);
4256 }
4257
4258 r_anal_op_free (op);
4259 break;
4260 }
4261 case 'Q':
4262 case 'q':
4263 default:
4264 if (IS_DIGIT (ch)) {
4265 if (rep < 0) {
4266 rep = 0;
4267 }
4268 rep = rep * 10 + atoi ((char *)&ch);
4269 goto repeat;
4270 }
4271 break;
4272 }
4273 if (distance > 0) {
4274 distance--;
4275 off += wordsize;
4276 goto onemoretime;
4277 }
4278 }
4279
r_core_visual_colors(RCore * core)4280 R_API void r_core_visual_colors(RCore *core) {
4281 char *color = calloc (1, 64), cstr[32];
4282 char preview_cmd[128] = "pd $r";
4283 int ch, opt = 0, oopt = -1;
4284 bool truecolor = r_cons_singleton ()->context->color_mode == COLOR_MODE_16M;
4285 char *rgb_xxx_fmt = truecolor ? "rgb:%2.2x%2.2x%2.2x ":"rgb:%x%x%x ";
4286 const char *k;
4287 RColor rcolor;
4288
4289 r_cons_show_cursor (false);
4290 rcolor = r_cons_pal_get_i (opt);
4291 for (;;) {
4292 r_cons_clear ();
4293 r_cons_gotoxy (0, 0);
4294 k = r_cons_pal_get_name (opt);
4295 if (!k) {
4296 opt = 0;
4297 k = r_cons_pal_get_name (opt);
4298 }
4299 if (!truecolor) {
4300 rcolor.r &= 0xf;
4301 rcolor.g &= 0xf;
4302 rcolor.b &= 0xf;
4303 rcolor.r2 &= 0xf;
4304 rcolor.g2 &= 0xf;
4305 rcolor.b2 &= 0xf;
4306 } else {
4307 rcolor.r &= 0xff;
4308 rcolor.g &= 0xff;
4309 rcolor.b &= 0xff;
4310 rcolor.r2 &= 0xff;
4311 rcolor.g2 &= 0xff;
4312 rcolor.b2 &= 0xff;
4313 }
4314 sprintf (color, rgb_xxx_fmt, rcolor.r, rcolor.g, rcolor.b);
4315 if (rcolor.r2 || rcolor.g2 || rcolor.b2) {
4316 color = r_str_appendf (color, rgb_xxx_fmt, rcolor.r2, rcolor.g2, rcolor.b2);
4317 rcolor.a = ALPHA_FGBG;
4318 } else {
4319 rcolor.a = ALPHA_FG;
4320 }
4321 r_cons_rgb_str (cstr, sizeof (cstr), &rcolor);
4322 char *esc = strchr (cstr + 1, '\x1b');
4323 char *curtheme = r_core_get_theme (core);
4324
4325 r_cons_printf ("# Use '.' to randomize current color and ':' to randomize palette\n");
4326 r_cons_printf ("# Press '"Color_RED"rR"Color_GREEN"gG"Color_BLUE"bB"Color_RESET
4327 "' or '"Color_BGRED"eE"Color_BGGREEN"fF"Color_BGBLUE"vV"Color_RESET
4328 "' to change foreground/background color\n");
4329 r_cons_printf ("# Export colorscheme with command 'ec* > filename'\n");
4330 r_cons_printf ("# Preview command: '%s' - Press 'c' to change it\n", preview_cmd);
4331 r_cons_printf ("# Selected colorscheme : %s - Use 'hl' or left/right arrow keys to change colorscheme\n", r_str_get_fail (curtheme, "default"));
4332 r_cons_printf ("# Selected element: %s - Use 'jk' or up/down arrow keys to change element\n", k);
4333 r_cons_printf ("# ec %s %s # %d (\\x1b%.*s)",
4334 k, color, atoi (cstr+7), esc ? (int)(esc - cstr - 1) : (int)strlen (cstr + 1), cstr+1);
4335 if (esc) {
4336 r_cons_printf (" (\\x1b%s)", esc + 1);
4337 }
4338 r_cons_newline ();
4339
4340 r_core_cmdf (core, "ec %s %s", k, color);
4341 char * res = r_core_cmd_str (core, preview_cmd);
4342 int h, w = r_cons_get_size (&h);
4343 char *body = r_str_ansi_crop (res, 0, 0, w, h - 8);
4344 if (body) {
4345 r_cons_printf ("\n%s", body);
4346 }
4347 r_cons_flush ();
4348 ch = r_cons_readchar ();
4349 ch = r_cons_arrow_to_hjkl (ch);
4350 switch (ch) {
4351 #define CASE_RGB(x,X,y) \
4352 case x:if ((y) > 0x00) { (y)--; } break;\
4353 case X:if ((y) < 0xff) { (y)++; } break;
4354 CASE_RGB ('R','r',rcolor.r);
4355 CASE_RGB ('G','g',rcolor.g);
4356 CASE_RGB ('B','b',rcolor.b);
4357 CASE_RGB ('E','e',rcolor.r2);
4358 CASE_RGB ('F','f',rcolor.g2);
4359 CASE_RGB ('V','v',rcolor.b2);
4360 case 'Q':
4361 case 'q':
4362 free (body);
4363 free (color);
4364 return;
4365 case 'k':
4366 opt--;
4367 break;
4368 case 'j':
4369 opt++;
4370 break;
4371 case 'l':
4372 r_core_cmd0 (core, "ecn");
4373 oopt = -1;
4374 break;
4375 case 'h':
4376 r_core_cmd0 (core, "ecp");
4377 oopt = -1;
4378 break;
4379 case 'K':
4380 opt = 0;
4381 break;
4382 case 'J':
4383 opt = r_cons_pal_len () - 1;
4384 break;
4385 case ':':
4386 r_cons_pal_random ();
4387 break;
4388 case '.':
4389 rcolor.r = r_num_rand (0xff);
4390 rcolor.g = r_num_rand (0xff);
4391 rcolor.b = r_num_rand (0xff);
4392 break;
4393 case 'c':
4394 r_line_set_prompt ("Preview command> ");
4395 r_cons_show_cursor (true);
4396 r_cons_fgets (preview_cmd, sizeof (preview_cmd), 0, NULL);
4397 r_cons_show_cursor (false);
4398 }
4399 if (opt != oopt) {
4400 rcolor = r_cons_pal_get_i (opt);
4401 oopt = opt;
4402 }
4403 free (body);
4404 }
4405 }
4406