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