radare2/libr/core/vmenus.c

4488 lines
105 KiB
C
Raw Normal View History

/* radare - LGPL - Copyright 2009-2021 - pancake */
#include <r_core.h>
#include <r_util.h>
2015-10-14 23:50:16 +02:00
#include <string.h>
#define MAX_FORMAT 3
enum {
R_BYTE_DATA = 1,
R_WORD_DATA = 2,
R_DWORD_DATA = 4,
R_QWORD_DATA = 8
};
enum {
SORT_NONE,
SORT_NAME,
SORT_OFFSET
};
typedef struct {
RCore *core;
int t_idx;
int t_ctr;
const char *type;
char *curname;
char *curfmt;
const char *optword;
} RCoreVisualTypes;
// TODO: move this helper into r_cons
static char *prompt(const char *str, const char *txt) {
char cmd[1024];
char *res = NULL;
char *oprompt = strdup (r_cons_singleton ()->line->prompt);
2015-09-14 12:35:38 +02:00
r_cons_show_cursor (true);
if (txt && *txt) {
free (r_cons_singleton ()->line->contents);
r_cons_singleton ()->line->contents = strdup (txt);
} else {
R_FREE (r_cons_singleton ()->line->contents);
}
*cmd = '\0';
r_line_set_prompt (str);
2020-02-29 22:47:10 +03:00
if (r_cons_fgets (cmd, sizeof (cmd), 0, NULL) < 0) {
*cmd = '\0';
}
//line[strlen(line)-1]='\0';
if (*cmd) {
res = strdup (cmd);
}
r_line_set_prompt (oprompt);
free (oprompt);
R_FREE (r_cons_singleton ()->line->contents);
return res;
}
static inline char *getformat(RCoreVisualTypes *vt, const char *k) {
r_strf_var (key, 64, "type.%s", k);
return sdb_get (vt->core->anal->sdb_types, key, 0);
}
2016-11-05 01:18:32 +01:00
static char *colorize_asm_string(RCore *core, const char *buf_asm, int optype, ut64 addr) {
2016-09-27 18:35:49 +02:00
char *tmp, *spacer = NULL;
char *source = (char*)buf_asm;
bool use_color = core->print->flags & R_PRINT_FLAGS_COLOR;
const char *color_num = core->cons->context->pal.num;
const char *color_reg = core->cons->context->pal.reg;
RAnalFunction* fcn = r_anal_get_fcn_in (core->anal, addr, R_ANAL_FCN_TYPE_NULL);
if (!use_color) {
return strdup (source);
}
// workaround dummy colorizer in case of paired commands (tms320 & friends)
spacer = strstr (source, "||");
if (spacer) {
2018-06-10 21:15:23 +02:00
char *s1 = r_str_ndup (source, spacer - source);
char *s2 = strdup (spacer + 2);
char *scol1 = r_print_colorize_opcode (core->print, s1, color_reg, color_num, false, fcn ? fcn->addr : 0);
char *scol2 = r_print_colorize_opcode (core->print, s2, color_reg, color_num, false, fcn ? fcn->addr : 0);
char *source = r_str_newf ("%s||%s", r_str_get (scol1), r_str_get (scol2));
free (scol1);
free (scol2);
2018-06-10 21:15:23 +02:00
free (s1);
free (s2);
return source;
}
char *res = strdup ("");
res = r_str_append (res, r_print_color_op_type (core->print, optype));
tmp = r_print_colorize_opcode (core->print, source, color_reg, color_num, false, fcn ? fcn->addr : 0);
res = r_str_append (res, tmp);
2016-09-27 18:35:49 +02:00
free (tmp);
return res;
}
static int rotate_nibble(const ut8 b, int dir) {
if (dir > 0) {
bool high = b >> 7;
return (b << 1) | high;
}
bool lower = b & 1;
return (b >> 1) | (lower << 7);
}
static int wordpos(const char *esil, int n) {
const char *w = esil;
if (n < 1) {
n = 0;
}
while (w && n--) {
const char *nw = strchr (w + 1, ',');
if (!nw) {
return strlen (esil);
}
w = nw;
}
if (!w && n > 0) {
return strlen (esil);
}
return (size_t)(w - esil);
}
static void showreg(RAnalEsil *esil, const char *rn, const char *desc) {
ut64 nm = 0;
int sz = 0;
r_cons_printf ("%s 0x%08"PFMT64x" (%d) ; %s\n", rn, nm, sz, desc);
}
R_API bool r_core_visual_esil(RCore *core, const char *input) {
const int nbits = sizeof (ut64) * 8;
int analopType;
char *word = NULL;
int x = 0;
char *ginput = NULL;
RAsmOp asmop;
RAnalOp analop;
ut8 buf[sizeof (ut64)];
Fix #9595 (#9673) * Added an address mask inside the RAnalEsil struct in order to be sure that the address accessed is relevant with the asm.bits of the file + Changed the calls to r_anal_esil_new * Corrected the addrmask in r_anal_esil_new * RTTI: Read MSVC Complete Object Locator * RTTI: Read MSVC Class Hierarchy Descriptor * VTable End on Reference * RTTI: Read MSVC Type Descriptor * RTTI: Read MSVC Base Class Array, Better Printing * Add anal.cpp.abi * Minor Code Style Changes in RTTI * Fix rahash2 entropy to show non truncated double (#9629) * Anal - whitespace fixes * Honor CFLAGS on the static build test compilation (#9677) * change coding style tab width to 4 (#9670) * Meson: use more built-in options (#9678) * Add support for extended regex in asm search (#9675) * Fix #9665 - Backwardly handle scr.color={bool} * Fix #9676 - Infinite loop in ecs with scr.color=2 * Adding help for redirection (#9679) * Refactores function r_str_split_list to receive the character to split by (#9672) * Fix #9666 - lines with comments do not use Unicode reflines * Fix uninitialized optypes_list issue in cmd_debug * update asan.sh to actually take the env for ASAN * removed incorrect return (#9685) * Fix UB in ESIL * Initial import of the CoreUndo API and uc command * Initial implementation of cmd.pdc to select pseudo-decompiler * Handle recursive pdc calls * Fix RPrint.strconv_mode memleak * Fix leaks in RSyscall.srdb * Use r_syscall_ref to avoid dblfree-or-leak issue * Arm thumb/thumb selector for the armass (#9681) * added function to translate number to imm12 * added function to get thumb shifts easily * added selector, newfangled implementation of adc * add bitmask for command suffixes * added new routine for parsing suffixes to opcodes. Error check added in getnum. Bugfixes. * Few improvements to 8051 memory mapping (#9686) * update memory map when idata/sfr/xdata regs change * set address space name on map * fix regression, remove debug output * fix regression, enable map name * Some fixups for #9682 (#9688) * Fix: coredump generation for huge programs (#9680) * Refix #9666 - lines with comments do not use Unicode reflines * Removed code unnecessary due to dcf3db025085c45124ec21890550a4ef19bd015c * Fixed free const warning * Fix another memleak in RSyscall * Fix more memleaks * Fix leak in RConsPal.rainbow * Fix 18K leak in anal.x86.cs * Fix some more memleaks in disasm and fix issue in str overlap * Fix memleak in RCore.anal_refs and fix regression * Revert "Fix some more memleaks in disasm and fix issue in str overlap" This reverts commit a902df837b0d499e1723179ed5c957c078703b51. * Fix memleak regressions * Bring back another memleak fix * Fix an undefined behaviour in RParse.filter * Fix memleaks in disasm.c * Add cundo.c to Meson (#9694) * Bring back an ugly buffer pack access issue to make it work * Cast to void * in R_FREE (#9692) * Set anal.cpp.abi to msvc for pe * Add better help for av * Split avr into avr and avra * Make av, avr and avra breakable * Add RTTI struct specific print functions * RTTI: Support MSVC x86_64 * PE: Fix too short section name. * PDB: define a constant to store the max length of a section name and use id. * PDB: dump the size of structure and union in JSON mode. * Fix cast issue in eprintf for debug.core.linux * Move the asm and anal plugins for x86.udis to extras Available via r2pm -ci udis86 * Remove more udis86 references * Fix warnings * fix pcache ptr-fuckup * Fix defragger theme * Fix crash in asl and fix its behaviour * Fix memory leak in blaze anal and silent a warning * Implement ?q to be like ?v but in quiet mode * Fix Meson build * Add missing 8, 16, 32 bit registers (and flags) for the linux-arm64 debugger reg profile * Fix 'Cannot find function at UT64_MAX message' * Add some Pingu to fortunes.fun * Loading Core (x86, x86_64, aarch64) (#9669) * Ragg2-cc -> Ragg2 merge (#9658) - change of 'access' function for 'r_file_exists' for windows portability - several changes in the way ragg2.c is done, see PR #9658 pancake comments - change function for the remove of 'file'.text - open changed for r_file_dump - some elt of cEnv_t are now const - skip all the pointers verification in set_cEnv but do them in check_cEnv instead - add 2 r_str_sanitize for file and CC in parseCFile - rewrite the removal of .o, .tmp, .bin, .s files, with cleaner code - changed the long command with sed and grep to 2 C functions. - The function parseCompiled that basically does what the command was doing - And r_str_stripLines that is equivalent to "grep -v" (maybe we should put this one in str.c ?) - simplify a bit getCompiler function with a const char* array - add ternary operator for armOrMips condition - use r_file_path for finding path to compilers - new file created in libr/egg which contains all the C file parser - modifications of 2 files to match the change : - libr/egg/r_egg.h - libr/egg/Makefile - the function r_str_stripLine is simplier (the mallocs wasn't needed) - the function r_str_stripLine is moved to libr/util/str.c - libr/include/r_util/r_str.h is changed accordingly * Revert bd3465c9a3fbeddf83980dc07eaac588320f7d (warning remains fixed) This reverts commit titled "Fixed free const warning". * Added an address mask inside the RAnalEsil struct in order to be sure that the address accessed is relevant with the asm.bits of the file + Changed the calls to r_anal_esil_new * Corrected the addrmask in r_anal_esil_new * Cleanup expressions in esil.c (addr &=...) * Corrected r_anal_esil_new definition in r_anal.h * Added an address size max in the ESIL config (maximum address size reachable by the ESIL VM)
2018-03-16 10:45:17 +01:00
unsigned int addrsize = r_config_get_i (core->config, "esil.addr.size");
if (input && !*input) {
input = NULL;
}
if (input && *input == '?') {
eprintf ("Usage: aev [esil-expression] # same as VbE\n");
return false;
}
if (!r_config_get_b (core->config, "scr.interactive")) {
return false;
}
if (core->blocksize < sizeof (ut64)) {
return false;
}
r_reg_arena_push (core->anal->reg);
RAnalEsil *esil = r_anal_esil_new (20, 0, addrsize);
r_anal_esil_setup (esil, core->anal, false, false, false);
// esil->anal = core->anal;
r_anal_esil_set_pc (esil, core->offset);
char *expr = NULL;
bool refresh = false;
for (;;) {
R_FREE (expr);
r_cons_clear00 ();
if (refresh) {
x = 0;
refresh = false;
}
if (input) {
expr = strdup (input);
} else {
memcpy (buf, core->block, sizeof (ut64));
// bool use_color = core->print->flags & R_PRINT_FLAGS_COLOR;
(void) r_asm_disassemble (core->rasm, &asmop, buf, sizeof (ut64));
analop.type = -1;
(void)r_anal_op (core->anal, &analop, core->offset, buf, sizeof (ut64), R_ANAL_OP_MASK_ESIL);
analopType = analop.type & R_ANAL_OP_TYPE_MASK;
r_cons_printf ("r2's esil debugger:\n\n");
r_cons_printf ("addr: 0x%08"PFMT64x"\n", core->offset);
r_cons_printf ("pos: %d\n", x);
{
char *op_hex = r_asm_op_get_hex (&asmop);
char *res = r_print_hexpair (core->print, op_hex, -1);
r_cons_printf ("hex: %s\n"Color_RESET, res);
free (res);
free (op_hex);
}
char *op = colorize_asm_string (core, r_asm_op_get_asm (&asmop), analopType, core->offset);
r_cons_printf (Color_RESET"asm: %s\n"Color_RESET, op);
free (op);
expr = strdup (r_strbuf_get (&analop.esil));
}
{
r_cons_printf (Color_RESET"esil: %s\n"Color_RESET, expr);
int wp = wordpos (expr, x);
char *pas = strdup (r_str_pad (' ', wp ? wp + 1: 0));
int wp2 = wordpos (expr, x + 1);
free (word);
word = r_str_ndup (expr + (wp?(wp+1):0), (wp2 - wp) - (wp?1:0));
if (wp == wp2) {
refresh = true;
}
const char *pad = r_str_pad ('-', wp2 - ((wp > 0)? wp + 1: 0));
r_cons_printf (Color_RESET" %s%s\n"Color_RESET, pas, pad);
free (pas);
// free (pad);
}
r_cons_printf ("esil regs:\n");
showreg (esil, "$$", "address");
showreg (esil, "$z", "zero");
showreg (esil, "$b", "borrow");
showreg (esil, "$c", "carry");
showreg (esil, "$o", "overflow");
showreg (esil, "$p", "parity");
showreg (esil, "$r", "regsize");
showreg (esil, "$s", "sign");
showreg (esil, "$d", "delay");
showreg (esil, "$j", "jump");
r_cons_printf ("regs:\n");
char *r = r_core_cmd_str (core, "dr=");
if (r) {
r_cons_printf ("%s", r);
free (r);
}
r_cons_printf ("esil stack:\n");
r_anal_esil_dumpstack (esil);
if (!input) {
r_anal_op_fini (&analop);
}
r_cons_newline ();
r_cons_visual_flush ();
int ch = r_cons_readchar ();
if (ch == -1 || ch == 4) {
break;
}
ch = r_cons_arrow_to_hjkl (ch); // get ESC+char, return 'hjkl' char
switch (ch) {
case 'Q':
case 'q':
goto beach;
case 'n':
case 'P':
x = 0;
r_anal_esil_free (esil);
esil = r_anal_esil_new (20, 0, addrsize);
esil->anal = core->anal;
r_core_cmd0 (core, "so+1");
r_anal_esil_set_pc (esil, core->offset);
break;
case 'N':
case 'p':
x = 0;
r_anal_esil_free (esil);
esil = r_anal_esil_new (20, 0, addrsize);
esil->anal = core->anal;
r_core_cmd0 (core, "so-1");
r_anal_esil_set_pc (esil, core->offset);
break;
case 'e':
{
char *s = r_cons_input ("esil: ");
free (ginput);
if (*s) {
input = s;
ginput = s;
} else {
ginput = NULL;
input = NULL;
free (s);
}
}
break;
case 'o':
{
char *s = r_cons_input ("offset: ");
r_core_cmdf (core, "s %s", s);
free (s);
}
break;
case 's':
// eprintf ("step ((%s))\n", word);
// r_sys_usleep (500);
x = R_MIN (x + 1, nbits - 1);
r_anal_esil_runword (esil, word);
break;
case 'S':
eprintf ("esil step back :D\n");
r_sys_usleep (500);
break;
case 'r':
case 'h':
x = 0; //R_MAX (x - 1, 0);
break;
case '?':
r_cons_clear00 ();
r_cons_printf (
"Vd1?: Visual Bit Editor Help:\n\n"
" q - quit the bit editor\n"
" h/r - reset / go back (reinitialize esil state)\n"
" s - esil step in\n"
" o - specify offset to seek\n"
" e - type a new esil expression to debug\n"
" j/k - toggle bit value (same as space key)\n"
" n/p - go next/prev instruction\n"
" : - enter command\n");
r_cons_flush ();
r_cons_any_key (NULL);
break;
case ':': // TODO: move this into a separate helper function
r_cons_show_cursor (true);
r_cons_set_raw (0);
while (1) {
char cmd[1024];
*cmd = 0;
r_line_set_prompt (":> ");
if (r_cons_fgets (cmd, sizeof (cmd), 0, NULL) < 0) {
cmd[0] = '\0';
}
r_core_cmd0 (core, cmd);
if (!cmd[0]) {
break;
}
r_cons_flush ();
}
r_cons_show_cursor (false);
r_cons_set_raw (1);
r_cons_clear ();
break;
}
}
beach:
free (expr);
r_reg_arena_pop (core->anal->reg);
r_anal_esil_free (esil);
2017-06-12 11:28:54 +02:00
free (word);
free (ginput);
return true;
}
R_API bool r_core_visual_bit_editor(RCore *core) {
const int nbits = sizeof (ut64) * 8;
bool colorBits = false;
int analopType;
int i, j, x = 0;
RAsmOp asmop;
RAnalOp analop;
ut8 buf[sizeof (ut64)];
bool bitsInLine = false;
if (core->blocksize < sizeof (ut64)) {
return false;
}
int cur = 0;
if (core->print->cur != -1) {
cur = core->print->cur;
}
memcpy (buf, core->block + cur, sizeof (ut64));
for (;;) {
r_cons_clear00 ();
bool use_color = core->print->flags & R_PRINT_FLAGS_COLOR;
(void) r_asm_disassemble (core->rasm, &asmop, buf, sizeof (ut64));
analop.type = -1;
(void)r_anal_op (core->anal, &analop, core->offset, buf, sizeof (ut64), R_ANAL_OP_MASK_ESIL);
analopType = analop.type & R_ANAL_OP_TYPE_MASK;
r_cons_printf ("r2's bit editor:\n\n");
r_cons_printf ("offset: 0x%08"PFMT64x"\n"Color_RESET, core->offset + cur);
{
2019-08-01 00:33:04 +03:00
char *op_hex = r_asm_op_get_hex (&asmop);
char *res = r_print_hexpair (core->print, op_hex, -1);
r_cons_printf ("hex: %s\n"Color_RESET, res);
free (res);
2019-08-01 00:33:04 +03:00
free (op_hex);
}
r_cons_printf ("len: %d\n", asmop.size);
{
ut32 word = (x % 32);
r_cons_printf ("shift: >> %d << %d\n", word, (asmop.size * 8) - word - 1);
}
{
char *op = colorize_asm_string (core, r_asm_op_get_asm (&asmop), analopType, core->offset);
r_cons_printf (Color_RESET"asm: %s\n"Color_RESET, op);
free (op);
}
r_cons_printf (Color_RESET"esl: %s\n"Color_RESET, r_strbuf_get (&analop.esil));
r_anal_op_fini (&analop);
r_cons_printf ("chr:");
for (i = 0; i < 8; i++) {
const ut8 *byte = buf + i;
char ch = IS_PRINTABLE (*byte)? *byte: '?';
if (i == 4) {
2020-10-30 19:30:42 +08:00
r_cons_print (" |");
}
if (use_color) {
r_cons_printf (" %5s'%s%c"Color_RESET"'", " ", core->cons->context->pal.btext, ch);
} else {
r_cons_printf (" %5s'%c'", " ", ch);
}
}
r_cons_printf ("\ndec:");
for (i = 0; i < 8; i++) {
const ut8 *byte = buf + i;
if (i == 4) {
2020-10-30 19:30:42 +08:00
r_cons_print (" |");
}
r_cons_printf (" %8d", *byte);
}
r_cons_printf ("\nhex:");
for (i = 0; i < 8; i++) {
const ut8 *byte = buf + i;
if (i == 4) {
2020-10-30 19:30:42 +08:00
r_cons_print (" |");
}
r_cons_printf (" 0x%02x", *byte);
}
if (bitsInLine) {
r_cons_printf ("\nbit: ");
for (i = 0; i < 8; i++) {
ut8 *byte = buf + i;
if (i == 4) {
2020-10-30 19:30:42 +08:00
r_cons_print ("| ");
}
if (colorBits && i >= asmop.size) {
r_cons_print (Color_RESET);
colorBits = false;
}
for (j = 0; j < 8; j++) {
bool bit = R_BIT_CHK (byte, 7 - j);
r_cons_printf ("%d", bit? 1: 0);
}
r_cons_print (" ");
}
} else {
int set;
const char *ws = r_config_get_i (core->config, "scr.utf8")? "·": " ";
for (set = 1; set >= 0 ; set--) {
r_cons_printf ("\nbit: ");
for (i = 0; i < 8; i++) {
ut8 *byte = buf + i;
if (i == 4) {
2020-10-30 19:30:42 +08:00
r_cons_print ("| ");
}
if (colorBits && i >= asmop.size) {
r_cons_print (Color_RESET);
colorBits = false;
}
for (j = 0; j < 8; j++) {
bool bit = R_BIT_CHK (byte, 7 - j);
if (set && bit) {
2020-10-30 19:30:42 +08:00
r_cons_print ("1");
} else if (!set && !bit) {
2020-10-30 19:30:42 +08:00
r_cons_print ("0");
} else {
2020-10-30 19:30:42 +08:00
r_cons_print (ws);
}
}
r_cons_print (" ");
}
}
}
r_cons_newline ();
char str_pos[128];
memset (str_pos, '-', nbits + 9);
int pos = x;
if (pos > 31) {
pos += 2;
}
str_pos[pos + (x / 8)] = '^';
str_pos[nbits + 9] = 0;
str_pos[8] = ' ';
str_pos[17] = ' ';
str_pos[26] = ' ';
str_pos[35] = ' ';
str_pos[36] = ' ';
str_pos[37] = ' ';
str_pos[46] = ' ';
str_pos[55] = ' ';
str_pos[64] = ' ';
r_cons_printf ("pos: %s\n", str_pos);
r_cons_newline ();
r_cons_visual_flush ();
int ch = r_cons_readchar ();
if (ch == -1 || ch == 4) {
break;
}
if (ch != 10) {
ch = r_cons_arrow_to_hjkl (ch); // get ESC+char, return 'hjkl' char
}
switch (ch) {
case 'Q':
case 'q':
{
2019-08-01 00:33:04 +03:00
char *op_hex = r_asm_op_get_hex (&asmop);
char *res = r_print_hexpair (core->print, op_hex, -1);
r_core_cmdf (core, "wx %02x%02x%02x%02x", buf[0], buf[1], buf[2], buf[3]);
free (res);
2019-08-01 00:33:04 +03:00
free (op_hex);
}
return false;
case 'H':
{
int y = R_MAX (x - 8, 0);
x = y - y % 8;
}
break;
case 'L':
case 9:
{
int y = R_MIN (x + 8, nbits - 8);
x = y - y % 8;
}
break;
case 'j':
case 'k':
case 10:
case ' ':
//togglebit();
{
const int nbyte = x / 8;
const int nbit = 7 - (x - (nbyte * 8));
ut8 *byte = buf + nbyte;
bool bit = R_BIT_CHK (byte, nbit);
if (bit) {
R_BIT_UNSET (byte, nbit);
} else {
R_BIT_SET (byte, nbit);
}
}
break;
case '>':
buf[x/8] = rotate_nibble (buf [(x / 8)], -1);
break;
case '<':
buf[x / 8] = rotate_nibble (buf [(x / 8)], 1);
break;
case 'i':
{
r_line_set_prompt ("> ");
const char *line = r_line_readline ();
ut64 num = r_num_math (core->num, line);
if (num || (!num && *line == '0')) {
buf[x / 8] = num;
}
}
break;
case 'R':
if (r_config_get_i (core->config, "scr.randpal")) {
r_core_cmd0 (core, "ecr");
} else {
r_core_cmd0 (core, "ecn");
}
break;
2016-07-05 12:31:25 +02:00
case '+':
buf[(x/8)]++;
break;
case '-':
buf[(x/8)]--;
break;
case 'h':
x = R_MAX (x - 1, 0);
break;
case 'l':
x = R_MIN (x + 1, nbits - 1);
break;
case 'b':
bitsInLine = !bitsInLine;
break;
case '?':
r_cons_clear00 ();
r_cons_printf (
"Vd1?: Visual Bit Editor Help:\n\n"
" q - quit the bit editor\n"
" R - randomize color palette\n"
" b - toggle bitsInLine\n"
" j/k - toggle bit value (same as space key)\n"
" h/l - select next/previous bit\n"
" +/- - increment or decrement byte value\n"
" </> - rotate left/right byte value\n"
" i - insert numeric value of byte\n"
" : - enter command\n");
r_cons_flush ();
r_cons_any_key (NULL);
break;
case ':': // TODO: move this into a separate helper function
{
char cmd[1024];
r_cons_show_cursor (true);
r_cons_set_raw (0);
cmd[0]='\0';
r_line_set_prompt (":> ");
2020-02-29 22:47:10 +03:00
if (r_cons_fgets (cmd, sizeof (cmd), 0, NULL) < 0) {
cmd[0] = '\0';
}
r_core_cmd (core, cmd, 1);
r_cons_set_raw (1);
r_cons_show_cursor (false);
if (cmd[0]) {
r_cons_any_key (NULL);
}
r_cons_clear ();
}
break;
}
}
return true;
}
// belongs to r_core_visual_types
static bool sdbforcb(void *p, const char *k, const char *v) {
const char *pre = " ";
RCoreVisualTypes *vt = (RCoreVisualTypes*)p;
bool use_color = vt->core->print->flags & R_PRINT_FLAGS_COLOR;
char *color_sel = vt->core->cons->context->pal.prompt;
if (vt->optword) {
if (!strcmp (vt->type, "struct")) {
char *s = r_str_newf ("struct.%s.", vt->optword);
/* enum */
if (!strncmp (s, k, strlen (s))) {
if (vt->t_idx == vt->t_ctr) {
free (vt->curname);
vt->curname = strdup (k);
free (vt->curfmt);
vt->curfmt = strdup (v);
pre = ">";
}
if (use_color && *pre == '>') {
r_cons_printf ("%s %s %s %s %10s\n", color_sel,
Color_RESET, pre, k+strlen (s), v);
} else {
r_cons_printf (" %s %s %10s\n",
pre, k + strlen (s), v);
}
vt->t_ctr ++;
}
free (s);
} else {
char *s = r_str_newf ("%s.", vt->optword);
/* enum */
if (!strncmp (s, k, strlen (s))) {
if (!strstr (k, ".0x")) {
if (vt->t_idx == vt->t_ctr) {
free (vt->curname);
vt->curname = strdup (v);
free (vt->curfmt);
vt->curfmt = strdup (v);
pre = ">";
}
if (use_color && *pre=='>') {
2020-10-21 17:27:17 +08:00
r_cons_printf ("%s"Color_RESET" %s %s %s\n", color_sel,
pre, k, v);
} else {
r_cons_printf (" %s %s %s\n",
pre, k, v);
}
vt->t_ctr ++;
}
}
free (s);
}
} else if (!strcmp (v, vt->type)) {
if (!strcmp (vt->type, "type")) {
char *fmt = getformat (vt, k);
if (vt->t_idx == vt->t_ctr) {
free (vt->curname);
vt->curname = strdup (k);
free (vt->curfmt);
vt->curfmt = strdup (fmt);
pre = ">";
}
if (use_color && *pre == '>') {
r_cons_printf ("%s %s pf %3s %s\n"Color_RESET,
color_sel, pre, fmt, k);
} else {
r_cons_printf (" %s pf %3s %s\n",
pre, fmt, k);
}
free (fmt);
} else {
if (vt->t_idx == vt->t_ctr) {
free (vt->curname);
vt->curname = strdup (k);
free (vt->curfmt);
vt->curfmt = strdup (v);
pre = ">";
}
if (use_color && *pre == '>') {
r_cons_printf ("%s %s %s\n"Color_RESET, color_sel,
(vt->t_idx == vt->t_ctr)? ">": " ", k);
} else {
r_cons_printf (" %s %s\n", (vt->t_idx == vt->t_ctr)? ">": " ", k);
}
}
vt->t_ctr ++;
}
return true;
}
R_API int r_core_visual_types(RCore *core) {
2015-10-23 16:55:38 +02:00
RCoreVisualTypes vt = {core, 0, 0};
2019-02-03 16:06:45 +01:00
int i, ch;
int _option = 0;
int option = 0;
char *txt;
char cmd[1024];
int menu = 0;
int h_opt = 0;
char *optword = NULL;
const char *opts[] = {
"type",
"enum",
"struct",
"func",
"union",
"cc",
NULL
};
bool use_color = core->print->flags & R_PRINT_FLAGS_COLOR;
2019-02-03 16:06:45 +01:00
if (r_flag_space_is_empty (core->flags)) {
menu = 1;
}
for (;;) {
r_cons_clear00 ();
for (i = 0; opts[i]; i++) {
if (use_color) {
if (h_opt == i) {
r_cons_printf ("%s[%s]%s ", core->cons->context->pal.call,
opts[i], Color_RESET);
} else {
r_cons_printf ("%s%s%s ", core->cons->context->pal.other,
opts[i], Color_RESET);
}
} else {
r_cons_printf (h_opt == i ? "[%s] " : " %s ", opts[i]);
}
}
r_cons_newline ();
if (optword) {
r_cons_printf (">> %s\n", optword);
}
if (!strcmp (opts[h_opt], "cc")) {
// XXX TODO: make this work (select with cursor, to delete, or add a new one with 'i', etc)
r_core_cmdf (core, "tfcl");
} else {
vt.t_idx = option;
vt.t_ctr = 0;
vt.type = opts[h_opt];
vt.optword = optword;
sdb_foreach (core->anal->sdb_types, sdbforcb, &vt);
}
r_cons_visual_flush ();
ch = r_cons_readchar ();
if (ch == -1 || ch == 4) {
return false;
}
ch = r_cons_arrow_to_hjkl (ch); // get ESC+char, return 'hjkl' char
switch (ch) {
case 'h':
h_opt--;
2016-11-09 02:35:44 +01:00
if (h_opt < 0) {
h_opt = 0;
2016-11-09 02:35:44 +01:00
}
option = 0;
R_FREE (optword);
break;
case 'l':
h_opt++;
option = 0;
2016-11-09 02:35:44 +01:00
if (!opts[h_opt]) {
h_opt--;
2016-11-09 02:35:44 +01:00
}
R_FREE (optword);
break;
case 'o':
{
char *file = prompt ("Filename: ", NULL);
if (file) {
r_core_cmdf (core, "\"to %s\"", file);
free (file);
}
}
break;
case 'j':
if (++option >= vt.t_ctr) {
option = vt.t_ctr - 1;
}
break;
case 'J':
option += 10;
if (option >= vt.t_ctr) {
option = vt.t_ctr-1;
}
break;
case 'k':
if (--option < 0) {
option = 0;
}
break;
case 'K':
option -= 10;
if (option < 0) {
option = 0;
}
break;
case 'b':
r_core_cmdf (core, "tl %s", vt.curname);
break;
2015-03-23 16:18:35 +01:00
case -1: // EOF
case 'Q':
case 'q':
if (optword) {
R_FREE (optword);
break;
}
if (menu <= 0) {
return true;
}
menu--;
option = _option;
if (menu==0) {
// if no flagspaces, just quit
2019-02-03 16:06:45 +01:00
if (r_flag_space_is_empty (core->flags)) {
return true;
}
}
break;
case 'a':
{
txt = prompt ("add C type: ", NULL);
if (txt) {
r_core_cmdf (core, "\"td %s\"", txt);
free (txt);
}
}
break;
case 'd':
r_core_cmdf (core, "t- %s", vt.curname);
break;
case '-':
r_core_cmd0 (core, "to -");
break;
case ' ':
case '\r':
case '\n':
case 'e':
if (optword) {
/* TODO: edit field */
} else {
switch (h_opt) {
case 0: { // type
/* TODO: do something with this data */
char *r = NULL;
r = prompt ("name: ", vt.curname);
free (r);
r = prompt ("pf: ", vt.curfmt);
free (r);
break;
}
case 1: // enum
case 2: // struct
free (optword);
2016-11-09 02:35:44 +01:00
if (vt.curname) {
optword = strdup (vt.curname);
} else {
optword = NULL;
}
break;
default:
break;
}
}
break;
case '?':
r_cons_clear00 ();
r_cons_printf (
"Vt?: Visual Types Help:\n\n"
" q - quit menu\n"
" j/k - down/up keys\n"
" h/l - left-right\n"
" a - add new type (C syntax)\n"
" b - bind type to current offset\n"
" d - delete current type\n"
" e - edit current type\n"
" o - open .h include file\n"
" - - Open cfg.editor to load types\n"
" : - enter command\n");
r_cons_flush ();
r_cons_any_key (NULL);
break;
case ':':
2015-09-14 12:35:38 +02:00
r_cons_show_cursor (true);
r_cons_set_raw (0);
2016-11-09 02:35:44 +01:00
cmd[0] = '\0';
r_line_set_prompt (":> ");
2020-02-29 22:47:10 +03:00
if (r_cons_fgets (cmd, sizeof (cmd), 0, NULL) < 0) {
cmd[0]='\0';
}
r_core_cmd (core, cmd, 1);
r_cons_set_raw (1);
2015-09-14 12:35:38 +02:00
r_cons_show_cursor (false);
if (cmd[0]) {
r_cons_any_key (NULL);
}
r_cons_clear ();
continue;
}
}
2015-09-14 12:35:38 +02:00
return true;
}
2017-01-29 03:57:40 +01:00
R_API bool r_core_visual_hudclasses(RCore *core) {
RListIter *iter, *iter2;
RBinClass *c;
RBinField *f;
RBinSymbol *m;
ut64 addr;
char *res;
RList *list = r_list_new ();
if (!list) {
return false;
}
list->free = free;
RList *classes = r_bin_get_classes (core->bin);
r_list_foreach (classes, iter, c) {
r_list_foreach (c->fields, iter2, f) {
r_list_append (list, r_str_newf ("0x%08"PFMT64x" %s %s",
f->vaddr, c->name, f->name));
}
r_list_foreach (c->methods, iter2, m) {
2017-04-11 00:16:36 +02:00
const char *name = m->dname? m->dname: m->name;
2017-01-29 03:57:40 +01:00
r_list_append (list, r_str_newf ("0x%08"PFMT64x" %s %s",
2017-04-11 00:16:36 +02:00
m->vaddr, c->name, name));
2017-01-29 03:57:40 +01:00
}
}
res = r_cons_hud (list, NULL);
2017-01-29 03:57:40 +01:00
if (res) {
char *p = strchr (res, ' ');
if (p) {
*p = 0;
}
addr = r_num_get (NULL, res);
r_core_seek (core, addr, true);
free (res);
}
r_list_free (list);
return res;
2017-01-29 03:57:40 +01:00
}
static bool hudstuff_append(RFlagItem *fi, void *user) {
RList *list = (RList *)user;
char *s = r_str_newf ("0x%08"PFMT64x" %s", fi->offset, fi->name);
if (s) {
r_list_append (list, s);
}
return true;
}
2015-10-08 14:01:07 +02:00
R_API bool r_core_visual_hudstuff(RCore *core) {
ut64 addr;
char *res;
RList *list = r_list_new ();
if (!list) {
return false;
}
2015-10-08 14:01:07 +02:00
list->free = free;
r_flag_foreach (core->flags, hudstuff_append, list);
2020-05-09 20:49:28 +02:00
RIntervalTreeIter it;
RAnalMetaItem *mi;
r_interval_tree_foreach (&core->anal->meta, it, mi) {
if (mi->type == R_META_TYPE_COMMENT) {
char *s = r_str_newf ("0x%08"PFMT64x" %s", r_interval_tree_iter_get (&it)->start, mi->str);
if (s) {
r_list_push (list, s);
}
}
}
res = r_cons_hud (list, NULL);
2015-10-08 14:01:07 +02:00
if (res) {
char *p = strchr (res, ' ');
if (p) {
*p = 0;
}
2015-10-08 14:01:07 +02:00
addr = r_num_get (NULL, res);
r_core_seek (core, addr, true);
free (res);
}
r_list_free (list);
return res;
2015-10-08 14:01:07 +02:00
}
2015-10-23 16:55:38 +02:00
static bool r_core_visual_config_hud(RCore *core) {
RListIter *iter;
RConfigNode *bt;
RList *list = r_list_new ();
if (!list) {
return false;
}
2015-10-23 16:55:38 +02:00
list->free = free;
r_list_foreach (core->config->nodes, iter, bt) {
r_list_append (list, r_str_newf ("%s %s", bt->name, bt->value));
2015-10-23 16:55:38 +02:00
}
char *res = r_cons_hud (list, NULL);
2015-10-23 16:55:38 +02:00
if (res) {
const char *oldvalue = NULL;
char cmd[512];
char *p = strchr (res, ' ');
if (p) {
*p = 0;
}
2015-10-23 16:55:38 +02:00
oldvalue = r_config_get (core->config, res);
r_cons_show_cursor (true);
r_cons_set_raw (false);
2015-10-23 16:55:38 +02:00
cmd[0] = '\0';
eprintf ("Set new value for %s (old=%s)\n", res, oldvalue);
2015-10-23 16:55:38 +02:00
r_line_set_prompt (":> ");
2020-02-29 22:47:10 +03:00
if (r_cons_fgets (cmd, sizeof (cmd), 0, NULL) < 0) {
cmd[0] = '\0';
}
2015-10-23 16:55:38 +02:00
r_config_set (core->config, res, cmd);
r_cons_set_raw (true);
2015-10-23 16:55:38 +02:00
r_cons_show_cursor (false);
}
r_list_free (list);
return true;
}
// TODO: skip N first elements
// TODO: show only N elements of the list
// TODO: wrap index when out of boundaries
// TODO: Add support to show class fields too
// Segfaults - stack overflow, because of recursion
static void *show_class(RCore *core, int mode, int *idx, RBinClass *_c, const char *grep, RList *list) {
2016-04-28 01:24:49 +02:00
bool show_color = r_config_get_i (core->config, "scr.color");
RListIter *iter;
RBinClass *c, *cur = NULL;
RBinSymbol *m, *mur = NULL;
RBinField *f, *fur = NULL;
int i = 0;
int skip = *idx - 10;
bool found = false;
switch (mode) {
case 'c':
r_cons_printf ("[hjkl_/Cfm]> classes:\n\n");
r_list_foreach (list, iter, c) {
2016-04-28 01:24:49 +02:00
if (grep) {
if (!r_str_casestr (c->name, grep)) {
2016-04-28 00:15:12 +02:00
i++;
continue;
}
2016-04-28 01:24:49 +02:00
} else {
if (*idx > 10) {
2016-04-28 01:24:49 +02:00
skip--;
if (skip > 0) {
i++;
continue;
}
}
2016-04-28 00:15:12 +02:00
}
2016-04-28 01:24:49 +02:00
if (show_color) {
if (i == *idx) {
2016-04-28 01:24:49 +02:00
const char *clr = Color_BLUE;
r_cons_printf (Color_GREEN ">>" Color_RESET " %02d %s0x%08"
PFMT64x Color_YELLOW " %s\n" Color_RESET,
i, clr, c->addr, c->name);
} else {
r_cons_printf ("- %02d %s0x%08"PFMT64x Color_RESET" %s\n",
i, core->cons->context->pal.offset, c->addr, c->name);
2016-04-28 01:24:49 +02:00
}
} else {
r_cons_printf ("%s %02d 0x%08"PFMT64x" %s\n",
(i==*idx)?">>":"- ", i, c->addr, c->name);
2016-04-28 01:24:49 +02:00
}
if (i++ == *idx) {
cur = c;
2016-04-28 01:24:49 +02:00
}
found = true;
}
if (!cur) {
*idx = i - 1;
if (!found) {
return NULL;
}
// r_cons_clear00 ();
return NULL; // show_class (core, mode, idx, _c, "", list);
}
return cur;
case 'f':
// show fields
r_cons_printf ("[hjkl_/cFm]> fields of %s:\n\n", _c->name);
r_list_foreach (_c->fields, iter, f) {
const char *name = f->name;
if (grep) {
if (!r_str_casestr (name, grep)) {
i++;
continue;
}
} else {
if (*idx > 10) {
skip--;
if (skip > 0) {
i++;
continue;
}
}
}
char *mflags = strdup ("");
if (r_str_startswith (name, _c->name)) {
name += strlen (_c->name);
}
if (show_color) {
if (i == *idx) {
const char *clr = Color_BLUE;
r_cons_printf (Color_GREEN ">>" Color_RESET " %02d %s0x%08"
PFMT64x Color_YELLOW " %s %s\n" Color_RESET,
i, clr, f->vaddr, mflags, name);
} else {
r_cons_printf ("- %02d %s0x%08"PFMT64x Color_RESET" %s %s\n",
i, core->cons->context->pal.offset, f->vaddr, mflags, name);
}
} else {
r_cons_printf ("%s %02d 0x%08"PFMT64x" %s %s\n",
(i==*idx)? ">>": "- ", i, f->vaddr, mflags, name);
}
R_FREE (mflags);
if (i++ == *idx) {
fur = f;
}
}
if (!fur) {
*idx = i - 1;
if (r_list_empty (_c->fields)) {
return NULL;
}
// r_cons_clear00 ();
return NULL; // show_class (core, mode, idx, _c, grep, list);
}
return fur;
break;
case 'm':
// show methods
if (!_c) {
eprintf ("No class selected.\n");
return mur;
}
r_cons_printf ("[hjkl_/cfM]> methods of %s\n\n", _c->name);
r_list_foreach (_c->methods, iter, m) {
2017-04-11 00:16:36 +02:00
const char *name = m->dname? m->dname: m->name;
char *mflags;
if (grep) {
2017-04-11 00:16:36 +02:00
if (!r_str_casestr (name, grep)) {
i++;
continue;
}
} else {
if (*idx > 10) {
skip--;
if (skip > 0) {
2016-04-28 01:24:49 +02:00
i++;
continue;
}
}
}
2017-06-27 17:02:14 +02:00
mflags = r_core_bin_method_flags_str (m->method_flags, 0);
if (show_color) {
if (r_str_startswith (name, _c->name)) {
name += strlen (_c->name);
}
if (i == *idx) {
const char *clr = Color_BLUE;
r_cons_printf (Color_GREEN ">>" Color_RESET " %02d %s0x%08"
PFMT64x Color_YELLOW " %s %s\n" Color_RESET,
i, clr, m->vaddr, mflags, name);
2016-04-28 01:24:49 +02:00
} else {
r_cons_printf ("- %02d %s0x%08"PFMT64x Color_RESET" %s %s\n",
i, core->cons->context->pal.offset, m->vaddr, mflags, name);
2016-04-28 01:24:49 +02:00
}
} else {
r_cons_printf ("%s %02d 0x%08"PFMT64x" %s %s\n",
(i==*idx)? ">>": "- ", i, m->vaddr, mflags, name);
}
R_FREE (mflags);
if (i++ == *idx) {
mur = m;
}
}
if (!mur) {
*idx = i - 1;
if (r_list_empty (_c->methods)) {
return NULL;
}
// r_cons_clear00 ();
return NULL; // show_class (core, mode, idx, _c, grep, list);
}
return mur;
}
return NULL;
}
R_API int r_core_visual_classes(RCore *core) {
int ch, index = 0;
char cmd[1024];
int mode = 'c';
RBinClass *cur = NULL;
RBinSymbol *mur = NULL;
2019-08-24 20:30:33 +02:00
RBinField *fur = NULL;
void *ptr;
2016-04-28 00:15:12 +02:00
int oldcur = 0;
2016-04-28 01:24:49 +02:00
char *grep = NULL;
bool grepmode = false;
RList *list = r_bin_get_classes (core->bin);
2017-03-12 22:52:02 +01:00
if (r_list_empty (list)) {
r_cons_message ("No Classes");
return false;
}
for (;;) {
2016-04-28 01:24:49 +02:00
int cols;
r_cons_clear00 ();
2016-04-28 01:24:49 +02:00
if (grepmode) {
r_cons_printf ("Grep: %s\n", r_str_get (grep));
2016-04-28 01:24:49 +02:00
}
ptr = show_class (core, mode, &index, cur, grep, list);
switch (mode) {
case 'f':
fur = (RBinField*)ptr;
break;
case 'm':
mur = (RBinSymbol*)ptr;
break;
case 'c':
cur = (RBinClass*)ptr;
break;
}
2016-04-28 01:24:49 +02:00
/* update terminal size */
(void) r_cons_get_size (&cols);
r_cons_visual_flush ();
ch = r_cons_readchar ();
if (ch == -1 || ch == 4) {
2017-07-29 19:55:40 +08:00
R_FREE (grep);
2016-04-28 00:15:12 +02:00
return false;
}
2016-04-28 01:24:49 +02:00
if (grepmode) {
switch (ch) {
case 127:
if (grep) {
int len = strlen (grep);
if (len < 1) {
grepmode = false;
} else {
grep[len - 1] = 0;
}
}
break;
case ' ':
case '\r':
case '\n':
R_FREE (grep);
grepmode = false;
break;
default:
grep = grep
? r_str_appendf (grep, "%c", ch)
: r_str_newf ("%c", ch);
2016-04-28 01:24:49 +02:00
break;
}
continue;
}
ch = r_cons_arrow_to_hjkl (ch); // get ESC+char, return 'hjkl' char
switch (ch) {
case 'C':
r_config_toggle (core->config, "scr.color");
break;
2017-01-29 03:57:40 +01:00
case '_':
if (r_core_visual_hudclasses (core)) {
return true;
}
break;
case 'J': index += 10; break;
case 'j': index++; break;
2020-02-29 22:47:10 +03:00
case 'k':
if (--index < 0) {
index = 0;
}
break;
2020-02-29 22:47:10 +03:00
case 'K':
index -= 10;
if (index < 0) {
index = 0;
}
break;
2016-04-28 01:24:49 +02:00
case 'g':
index = 0;
break;
case 'G':
index = r_list_length (list) - 1;
break;
case 'i':
2016-04-28 01:24:49 +02:00
{
char *num = prompt ("Index:", NULL);
if (num) {
index = atoi (num);
free (num);
}
2016-04-28 01:24:49 +02:00
}
break;
2016-04-28 03:17:16 +02:00
case 'p':
if (mode == 'm' && mur) {
r_core_seek (core, mur->vaddr, true);
r_core_cmd0 (core, "af;pdf~..");
}
break;
case 'm': // methods
mode = 'm';
break;
case 'f': // fields
mode = 'f';
break;
case 'h':
2016-04-28 01:24:49 +02:00
case 127: // backspace
case 'b': // back
case 'Q':
case 'c':
case 'q':
if (mode == 'c') {
return true;
}
mode = 'c';
index = oldcur;
break;
case '/':
2016-04-28 01:24:49 +02:00
grepmode = true;
break;
case 'l':
case ' ':
case '\r':
case '\n':
if (mur && mode == 'm') {
r_core_seek (core, mur->vaddr, true);
return true;
}
if (fur) {
r_core_seek (core, fur->vaddr, true);
return true;
}
if (cur) {
oldcur = index;
index = 0;
mode = 'm';
}
break;
case '?':
r_cons_clear00 ();
r_cons_printf (
"\nVF: Visual Classes help:\n\n"
" q - quit menu\n"
" j/k - down/up keys\n"
" h/b - go back\n"
" g/G - go first/last item\n"
" i - specify index\n"
2016-04-28 01:24:49 +02:00
" / - grep mode\n"
" C - toggle colors\n"
" f - show class fields\n"
" m - show class methods\n"
" l/' ' - accept current selection\n"
2016-04-28 03:17:16 +02:00
" p - preview method disasm with less\n"
" : - enter command\n");
r_cons_flush ();
r_cons_any_key (NULL);
break;
case ':':
r_cons_show_cursor (true);
r_cons_set_raw (0);
cmd[0] = '\0';
r_line_set_prompt (":> ");
2020-02-29 22:47:10 +03:00
if (r_cons_fgets (cmd, sizeof (cmd), 0, NULL) < 0) {
cmd[0]='\0';
}
//line[strlen(line)-1]='\0';
r_core_cmd (core, cmd, 1);
r_cons_set_raw (1);
r_cons_show_cursor (false);
if (cmd[0]) {
r_cons_any_key (NULL);
}
//cons_gotoxy(0,0);
r_cons_clear ();
break;
}
}
return true;
}
static void anal_class_print(RAnal *anal, const char *class_name) {
RVector *bases = r_anal_class_base_get_all (anal, class_name);
RVector *vtables = r_anal_class_vtable_get_all (anal, class_name);
RVector *methods = r_anal_class_method_get_all (anal, class_name);
r_cons_print (class_name);
if (bases) {
RAnalBaseClass *base;
bool first = true;
r_vector_foreach (bases, base) {
if (first) {
r_cons_print (": ");
first = false;
} else {
r_cons_print (", ");
}
r_cons_print (base->class_name);
}
r_vector_free (bases);
}
r_cons_print ("\n");
if (vtables) {
RAnalVTable *vtable;
r_vector_foreach (vtables, vtable) {
r_cons_printf (" %2s vtable 0x%"PFMT64x" @ +0x%"PFMT64x" size:+0x%"PFMT64x"\n", vtable->id, vtable->addr, vtable->offset, vtable->size);
}
r_vector_free (vtables);
}
r_cons_print ("\n");
if (methods) {
RAnalMethod *meth;
r_vector_foreach (methods, meth) {
r_cons_printf (" %s @ 0x%"PFMT64x, meth->name, meth->addr);
if (meth->vtable_offset >= 0) {
r_cons_printf (" (vtable + 0x%"PFMT64x")\n", (ut64)meth->vtable_offset);
} else {
r_cons_print ("\n");
}
}
r_vector_free (methods);
}
}
static const char *show_anal_classes(RCore *core, char mode, int *idx, SdbList *list, const char *class_name) {
bool show_color = r_config_get_i (core->config, "scr.color");
SdbListIter *iter;
SdbKv *kv;
int i = 0;
int skip = *idx - 10;
const char * cur_class = NULL;
r_cons_printf ("[hjkl_/Cfm]> anal classes:\n\n");
if (mode == 'd' && class_name) {
anal_class_print (core->anal, class_name);
return class_name;
}
ls_foreach (list, iter, kv) {
if (*idx > 10) {
skip--;
if (skip > 0) {
i++;
continue;
}
}
class_name = sdbkv_key (kv);
if (show_color) {
const char *pointer = "- ";
const char *txt_clr = "";
if (i == *idx) {
pointer = Color_GREEN ">>";
Fix wording and whitespacing ##doc (#18065) * Fix wording, whitespacing and other minor stuff * cmd.c: ellaborated yy syntax, improved descriptions - replace "srcoff" with "origin" * cmd.c(cmd_autocomplete): - refactor help into function: render autocomplete types with generic help subsystem; - "Types" heading now follow the "Usage" style by not being prefixed by a pipe character; * cmd_anal.c: fix whitespaces & help text * cmd_info.c: fix help text capitalization. * cmd_print.c: - fix `pf` cmd help; - TODO: what pz? is doing here? * cons.c: - refactor & better document r_cons_cmd_help(); - fix whitespaces; * visual & panels modes: - as of commit 46187fe4e14dc465dc6ac03fcc56a362f0b8e335, '!' no longer launches the r2048 game. The game itself it broken anyway, even when running from the Help menu in panels mode; - transitioning from panels to visual is not 'entering' but actually swapping/replacing visual panels with just panels, thus... - reword 'enter into the' to 'swap into' or even just 'enter', e.g.: "enter into the visual panels mode" -> "enter visual panels mode". - remove the "(dwm style)" words from a fortune tip, because I have no idea what it is, and it does not appear to be a valid command in any of the r2 modes. - update global help text. * [WIP 2] Fix wording, whitespacing and other minor stuff * visual.c: - r_core_visual_append_help(): first steps merging with r_cons_cmd_help from cons.c; use consistent colors for headers. * [WIP 3] Fix wording, whitespacing and other minor stuff * panels.c(__update_help): - shorten code and titles; - add comment to clarify that it is not a copy-paste error; * [WIP 4] Fix wording, whitespacing and other minor stuff panels.c, visual.c: tweak help text; * [WIP 5] Fix wording, whitespacing and other minor stuff * cmd_help.c: update global help text about visual mode -- it was outdated and overloaded. * vmenus.c: - rename stuff, shuffle around static consts to reflect an actual ordering when viewing as a help text; - slightly improve help text rendering; - fix whitespaces; * [WIP 6] Fix wording, whitespacing and other minor stuff * lots of help text changed. still working on proper commit message.
2020-12-21 03:12:08 +03:00
txt_clr = Color_YELLOW;
cur_class = class_name;
Fix wording and whitespacing ##doc (#18065) * Fix wording, whitespacing and other minor stuff * cmd.c: ellaborated yy syntax, improved descriptions - replace "srcoff" with "origin" * cmd.c(cmd_autocomplete): - refactor help into function: render autocomplete types with generic help subsystem; - "Types" heading now follow the "Usage" style by not being prefixed by a pipe character; * cmd_anal.c: fix whitespaces & help text * cmd_info.c: fix help text capitalization. * cmd_print.c: - fix `pf` cmd help; - TODO: what pz? is doing here? * cons.c: - refactor & better document r_cons_cmd_help(); - fix whitespaces; * visual & panels modes: - as of commit 46187fe4e14dc465dc6ac03fcc56a362f0b8e335, '!' no longer launches the r2048 game. The game itself it broken anyway, even when running from the Help menu in panels mode; - transitioning from panels to visual is not 'entering' but actually swapping/replacing visual panels with just panels, thus... - reword 'enter into the' to 'swap into' or even just 'enter', e.g.: "enter into the visual panels mode" -> "enter visual panels mode". - remove the "(dwm style)" words from a fortune tip, because I have no idea what it is, and it does not appear to be a valid command in any of the r2 modes. - update global help text. * [WIP 2] Fix wording, whitespacing and other minor stuff * visual.c: - r_core_visual_append_help(): first steps merging with r_cons_cmd_help from cons.c; use consistent colors for headers. * [WIP 3] Fix wording, whitespacing and other minor stuff * panels.c(__update_help): - shorten code and titles; - add comment to clarify that it is not a copy-paste error; * [WIP 4] Fix wording, whitespacing and other minor stuff panels.c, visual.c: tweak help text; * [WIP 5] Fix wording, whitespacing and other minor stuff * cmd_help.c: update global help text about visual mode -- it was outdated and overloaded. * vmenus.c: - rename stuff, shuffle around static consts to reflect an actual ordering when viewing as a help text; - slightly improve help text rendering; - fix whitespaces; * [WIP 6] Fix wording, whitespacing and other minor stuff * lots of help text changed. still working on proper commit message.
2020-12-21 03:12:08 +03:00
}
r_cons_printf ("%s" Color_RESET " %02d"
" %s%s\n" Color_RESET, pointer, i, txt_clr, class_name);
} else {
r_cons_printf ("%s %02d %s\n", (i==*idx) ? ">>" : "- ", i, class_name);
}
Fix wording and whitespacing ##doc (#18065) * Fix wording, whitespacing and other minor stuff * cmd.c: ellaborated yy syntax, improved descriptions - replace "srcoff" with "origin" * cmd.c(cmd_autocomplete): - refactor help into function: render autocomplete types with generic help subsystem; - "Types" heading now follow the "Usage" style by not being prefixed by a pipe character; * cmd_anal.c: fix whitespaces & help text * cmd_info.c: fix help text capitalization. * cmd_print.c: - fix `pf` cmd help; - TODO: what pz? is doing here? * cons.c: - refactor & better document r_cons_cmd_help(); - fix whitespaces; * visual & panels modes: - as of commit 46187fe4e14dc465dc6ac03fcc56a362f0b8e335, '!' no longer launches the r2048 game. The game itself it broken anyway, even when running from the Help menu in panels mode; - transitioning from panels to visual is not 'entering' but actually swapping/replacing visual panels with just panels, thus... - reword 'enter into the' to 'swap into' or even just 'enter', e.g.: "enter into the visual panels mode" -> "enter visual panels mode". - remove the "(dwm style)" words from a fortune tip, because I have no idea what it is, and it does not appear to be a valid command in any of the r2 modes. - update global help text. * [WIP 2] Fix wording, whitespacing and other minor stuff * visual.c: - r_core_visual_append_help(): first steps merging with r_cons_cmd_help from cons.c; use consistent colors for headers. * [WIP 3] Fix wording, whitespacing and other minor stuff * panels.c(__update_help): - shorten code and titles; - add comment to clarify that it is not a copy-paste error; * [WIP 4] Fix wording, whitespacing and other minor stuff panels.c, visual.c: tweak help text; * [WIP 5] Fix wording, whitespacing and other minor stuff * cmd_help.c: update global help text about visual mode -- it was outdated and overloaded. * vmenus.c: - rename stuff, shuffle around static consts to reflect an actual ordering when viewing as a help text; - slightly improve help text rendering; - fix whitespaces; * [WIP 6] Fix wording, whitespacing and other minor stuff * lots of help text changed. still working on proper commit message.
2020-12-21 03:12:08 +03:00
i++;
}
return cur_class;
}
// TODO add other commands that Vbc has
// Should the classes be refreshed after command execution with :
// in case new class information would be added?
// Add grep?
R_API int r_core_visual_anal_classes(RCore *core) {
int ch, index = 0;
char command[1024];
SdbList *list = r_anal_class_get_all (core->anal, true);
int oldcur = 0;
char mode = ' ';
const char *class_name = "";
if (r_list_empty (list)) {
r_cons_message ("No Classes");
goto cleanup;
}
for (;;) {
int cols;
r_cons_clear00 ();
class_name = show_anal_classes (core, mode, &index, list, class_name);
/* update terminal size */
(void) r_cons_get_size (&cols);
r_cons_visual_flush ();
ch = r_cons_readchar ();
if (ch == -1 || ch == 4) {
goto cleanup;
}
ch = r_cons_arrow_to_hjkl (ch); // get ESC+char, return 'hjkl' char
switch (ch) {
case 'C':
r_config_toggle (core->config, "scr.color");
break;
Fix wording and whitespacing ##doc (#18065) * Fix wording, whitespacing and other minor stuff * cmd.c: ellaborated yy syntax, improved descriptions - replace "srcoff" with "origin" * cmd.c(cmd_autocomplete): - refactor help into function: render autocomplete types with generic help subsystem; - "Types" heading now follow the "Usage" style by not being prefixed by a pipe character; * cmd_anal.c: fix whitespaces & help text * cmd_info.c: fix help text capitalization. * cmd_print.c: - fix `pf` cmd help; - TODO: what pz? is doing here? * cons.c: - refactor & better document r_cons_cmd_help(); - fix whitespaces; * visual & panels modes: - as of commit 46187fe4e14dc465dc6ac03fcc56a362f0b8e335, '!' no longer launches the r2048 game. The game itself it broken anyway, even when running from the Help menu in panels mode; - transitioning from panels to visual is not 'entering' but actually swapping/replacing visual panels with just panels, thus... - reword 'enter into the' to 'swap into' or even just 'enter', e.g.: "enter into the visual panels mode" -> "enter visual panels mode". - remove the "(dwm style)" words from a fortune tip, because I have no idea what it is, and it does not appear to be a valid command in any of the r2 modes. - update global help text. * [WIP 2] Fix wording, whitespacing and other minor stuff * visual.c: - r_core_visual_append_help(): first steps merging with r_cons_cmd_help from cons.c; use consistent colors for headers. * [WIP 3] Fix wording, whitespacing and other minor stuff * panels.c(__update_help): - shorten code and titles; - add comment to clarify that it is not a copy-paste error; * [WIP 4] Fix wording, whitespacing and other minor stuff panels.c, visual.c: tweak help text; * [WIP 5] Fix wording, whitespacing and other minor stuff * cmd_help.c: update global help text about visual mode -- it was outdated and overloaded. * vmenus.c: - rename stuff, shuffle around static consts to reflect an actual ordering when viewing as a help text; - slightly improve help text rendering; - fix whitespaces; * [WIP 6] Fix wording, whitespacing and other minor stuff * lots of help text changed. still working on proper commit message.
2020-12-21 03:12:08 +03:00
case 'J':
index += 10;
if (index >= list->length) {
index = list->length -1;
}
break;
Fix wording and whitespacing ##doc (#18065) * Fix wording, whitespacing and other minor stuff * cmd.c: ellaborated yy syntax, improved descriptions - replace "srcoff" with "origin" * cmd.c(cmd_autocomplete): - refactor help into function: render autocomplete types with generic help subsystem; - "Types" heading now follow the "Usage" style by not being prefixed by a pipe character; * cmd_anal.c: fix whitespaces & help text * cmd_info.c: fix help text capitalization. * cmd_print.c: - fix `pf` cmd help; - TODO: what pz? is doing here? * cons.c: - refactor & better document r_cons_cmd_help(); - fix whitespaces; * visual & panels modes: - as of commit 46187fe4e14dc465dc6ac03fcc56a362f0b8e335, '!' no longer launches the r2048 game. The game itself it broken anyway, even when running from the Help menu in panels mode; - transitioning from panels to visual is not 'entering' but actually swapping/replacing visual panels with just panels, thus... - reword 'enter into the' to 'swap into' or even just 'enter', e.g.: "enter into the visual panels mode" -> "enter visual panels mode". - remove the "(dwm style)" words from a fortune tip, because I have no idea what it is, and it does not appear to be a valid command in any of the r2 modes. - update global help text. * [WIP 2] Fix wording, whitespacing and other minor stuff * visual.c: - r_core_visual_append_help(): first steps merging with r_cons_cmd_help from cons.c; use consistent colors for headers. * [WIP 3] Fix wording, whitespacing and other minor stuff * panels.c(__update_help): - shorten code and titles; - add comment to clarify that it is not a copy-paste error; * [WIP 4] Fix wording, whitespacing and other minor stuff panels.c, visual.c: tweak help text; * [WIP 5] Fix wording, whitespacing and other minor stuff * cmd_help.c: update global help text about visual mode -- it was outdated and overloaded. * vmenus.c: - rename stuff, shuffle around static consts to reflect an actual ordering when viewing as a help text; - slightly improve help text rendering; - fix whitespaces; * [WIP 6] Fix wording, whitespacing and other minor stuff * lots of help text changed. still working on proper commit message.
2020-12-21 03:12:08 +03:00
case 'j':
if (++index >= list->length) {
index = 0;
}
Fix wording and whitespacing ##doc (#18065) * Fix wording, whitespacing and other minor stuff * cmd.c: ellaborated yy syntax, improved descriptions - replace "srcoff" with "origin" * cmd.c(cmd_autocomplete): - refactor help into function: render autocomplete types with generic help subsystem; - "Types" heading now follow the "Usage" style by not being prefixed by a pipe character; * cmd_anal.c: fix whitespaces & help text * cmd_info.c: fix help text capitalization. * cmd_print.c: - fix `pf` cmd help; - TODO: what pz? is doing here? * cons.c: - refactor & better document r_cons_cmd_help(); - fix whitespaces; * visual & panels modes: - as of commit 46187fe4e14dc465dc6ac03fcc56a362f0b8e335, '!' no longer launches the r2048 game. The game itself it broken anyway, even when running from the Help menu in panels mode; - transitioning from panels to visual is not 'entering' but actually swapping/replacing visual panels with just panels, thus... - reword 'enter into the' to 'swap into' or even just 'enter', e.g.: "enter into the visual panels mode" -> "enter visual panels mode". - remove the "(dwm style)" words from a fortune tip, because I have no idea what it is, and it does not appear to be a valid command in any of the r2 modes. - update global help text. * [WIP 2] Fix wording, whitespacing and other minor stuff * visual.c: - r_core_visual_append_help(): first steps merging with r_cons_cmd_help from cons.c; use consistent colors for headers. * [WIP 3] Fix wording, whitespacing and other minor stuff * panels.c(__update_help): - shorten code and titles; - add comment to clarify that it is not a copy-paste error; * [WIP 4] Fix wording, whitespacing and other minor stuff panels.c, visual.c: tweak help text; * [WIP 5] Fix wording, whitespacing and other minor stuff * cmd_help.c: update global help text about visual mode -- it was outdated and overloaded. * vmenus.c: - rename stuff, shuffle around static consts to reflect an actual ordering when viewing as a help text; - slightly improve help text rendering; - fix whitespaces; * [WIP 6] Fix wording, whitespacing and other minor stuff * lots of help text changed. still working on proper commit message.
2020-12-21 03:12:08 +03:00
break;
case 'k':
if (--index < 0) {
index = list->length - 1;
}
break;
case 'K':
index -= 10;
if (index < 0) {
index = 0;
}
break;
case 'g':
index = 0;
break;
case 'G':
index = list->length - 1;
break;
case 'h':
case 127: // backspace
case 'b': // back
case 'Q':
case 'c':
case 'q':
if (mode == ' ') {
goto cleanup;
}
mode = ' ';
index = oldcur;
break;
case 'l':
case ' ':
case '\r':
case '\n':
mode = 'd';
break;
case '?':
r_cons_clear00 ();
r_cons_printf (
"\nVF: Visual Classes help:\n\n"
" q - quit menu\n"
" j/k - down/up keys\n"
" h/b - go back\n"
" g/G - go first/last item\n"
" l/' ' - accept current selection\n"
" : - enter command\n");
r_cons_flush ();
r_cons_any_key (NULL);
break;
case ':':
r_cons_show_cursor (true);
r_cons_set_raw (0);
command[0] = '\0';
r_line_set_prompt (":> ");
if (r_cons_fgets (command, sizeof (command), 0, NULL) < 0) {
command[0]='\0';
}
//line[strlen(line)-1]='\0';
r_core_cmd (core, command, 1);
r_cons_set_raw (1);
r_cons_show_cursor (false);
if (command[0]) {
r_cons_any_key (NULL);
}
//cons_gotoxy(0,0);
r_cons_clear ();
break;
}
}
cleanup:
ls_free(list);
return true;
}
static int flag_name_sort(const void *a, const void *b) {
const RFlagItem *fa = (const RFlagItem *)a;
const RFlagItem *fb = (const RFlagItem *)b;
return strcmp (fa->name, fb->name);
}
static int flag_offset_sort(const void *a, const void *b) {
const RFlagItem *fa = (const RFlagItem *)a;
const RFlagItem *fb = (const RFlagItem *)b;
if (fa->offset < fb->offset) {
return -1;
}
if (fa->offset > fb->offset) {
return 1;
}
return 0;
}
static void sort_flags(RList *l, int sort) {
switch (sort) {
case SORT_NAME:
r_list_sort (l, flag_name_sort);
break;
case SORT_OFFSET:
r_list_sort (l, flag_offset_sort);
break;
case SORT_NONE:
default:
break;
}
}
// TODO: remove this statement, should be a separate .o
static char *print_rop(void *_core, void *_item, bool selected) {
char *line = _item;
// TODO: trim if too long
return r_str_newf ("%c %s\n", selected?'>':' ', line);
}
R_API int r_core_visual_view_rop(RCore *core) {
RListIter *iter;
const int rows = 7;
int cur = 0;
r_line_set_prompt ("rop regexp: ");
const char *line = r_line_readline ();
int scr_h, scr_w = r_cons_get_size (&scr_h);
if (!line || !*line) {
return false;
}
// maybe store in RCore, so we can save it in project and use it outside visual
eprintf ("Searching ROP gadgets...\n");
char *ropstr = r_core_cmd_strf (core, "\"/Rl %s\" @e:scr.color=0", line);
RList *rops = r_str_split_list (ropstr, "\n", 0);
int delta = 0;
bool show_color = core->print->flags & R_PRINT_FLAGS_COLOR;
bool forceaddr = false;
ut64 addr = UT64_MAX;
char *cursearch = strdup (line);
while (true) {
r_cons_clear00 ();
r_cons_printf ("[0x%08"PFMT64x"]-[visual-r2rop] %s (see pdp command)\n",
(addr == UT64_MAX)? 0: addr + delta, cursearch);
// compute chain
RStrBuf *sb = r_strbuf_new ("");
char *msg;
r_list_foreach (core->ropchain, iter, msg) {
if (core->rasm->config->bits == 64) {
ut64 n = r_num_get (NULL, msg);
n = r_read_be64 (&n);
r_strbuf_appendf (sb, "%016"PFMT64x, n);
} else {
ut32 n = r_num_get (NULL, msg);
n = r_read_be32 (&n);
r_strbuf_appendf (sb, "%08x", n);
}
}
char *chainstr = r_strbuf_drain (sb);
char *wlist = r_str_widget_list (core, rops, rows, cur, print_rop);
r_cons_printf ("%s", wlist);
free (wlist);
char *curline = r_str_dup (NULL, r_str_trim_head_ro (r_str_widget_list (
core, rops, rows, cur, print_rop)));
if (curline) {
char *sp = strchr (curline, ' ');
if (sp) {
*sp = 0;
if (!forceaddr) {
addr = r_num_math (NULL, curline);
}
*sp = ' ';
}
if (addr != UT64_MAX) {
r_cons_printf ("Gadget:");
// get comment
char *output = r_core_cmd_strf (core, "piu 10 @ 0x%08"PFMT64x, addr + delta);
if (output) {
r_cons_strcat_at (output, 0, 10, scr_w, 10);
free (output);
}
}
}
int count = 0;
r_cons_flush ();
r_cons_gotoxy (0, 20);
r_cons_printf ("ROPChain:\n %s\n", r_str_get (chainstr));
r_list_foreach (core->ropchain, iter, msg) {
int extra = strlen (chainstr) / scr_w;
r_cons_gotoxy (0, extra + 22 + count);
r_cons_strcat (msg);
2020-05-09 20:49:28 +02:00
const char *cmt = r_meta_get_string (core->anal, R_META_TYPE_COMMENT, r_num_get (NULL, msg));
if (cmt) {
r_cons_strcat (cmt);
}
count ++;
}
r_cons_flush ();
int ch = r_cons_readchar ();
if (ch == -1 || ch == 4) {
free (curline);
free (cursearch);
R_FREE (chainstr);
return false;
}
#define NEWTYPE(x,y) r_mem_dup (&(y), sizeof (x));
ch = r_cons_arrow_to_hjkl (ch); // get ESC+char, return 'hjkl' char
switch (ch) {
case 127:
free (r_list_pop (core->ropchain));
break;
case '?':
r_cons_clear00 ();
r_cons_printf ("[r2rop-visual] Help\n"
" jk - select next/prev rop gadget\n"
" JK - scroll next/prev page from list\n"
" hl - increase/decrease delta offset in disasm\n"
" \\n - enter key or dot will add the current offset into the chain\n"
" i - enter a number to be pushed into the chain\n"
" : - run r2 command\n"
" ; - add comment in current offset\n"
" <- - backspace - delete last gadget from the chain\n"
" / - highlight given word\n"
" y - yank current rop chain into the clipboard (y?)\n"
" o - seek to given offset\n"
" r - run /R again\n"
" ? - show this help message\n"
" q - quit this view\n"
);
r_cons_flush ();
r_cons_any_key (NULL);
break;
case ':': // TODO: move this into a separate helper function
r_cons_show_cursor (true);
r_cons_set_raw (0);
while (true) {
char cmd[1024];
cmd[0] = '\0';
r_line_set_prompt (":> ");
2020-02-29 22:47:10 +03:00
if (r_cons_fgets (cmd, sizeof (cmd), 0, NULL) < 0) {
cmd[0] = '\0';
}
if (!*cmd || *cmd == 'q') {
break;
}
ut64 oseek = core->offset;
r_core_seek (core, addr + delta, false);
r_core_cmd (core, cmd, 1);
r_core_seek (core, oseek, false);
r_cons_flush ();
}
r_cons_set_raw (1);
r_cons_show_cursor (false);
break;
case 'y':
r_core_cmdf (core, "yfx %s", chainstr);
break;
case 'o':
{
r_line_set_prompt ("offset: ");
const char *line = r_line_readline ();
if (line && *line) {
ut64 off = r_num_math (core->num, line);
r_core_seek (core, off, true);
addr = off;
forceaddr = true;
delta = 0;
}
}
break;
case 'r':
{
r_line_set_prompt ("rop regexp: ");
const char *line = r_line_readline ();
if (line && *line) {
free (cursearch);
delta = 0;
addr = UT64_MAX;
cur = 0;
cursearch = strdup (line);
free (ropstr);
ropstr = r_core_cmd_strf (core, "\"/Rl %s\" @e:scr.color=0", line);
r_list_free (rops);
rops = r_str_split_list (ropstr, "\n", 0);
}
}
break;
case '/':
r_core_cmd0 (core, "?i highlight;e scr.highlight=`yp`");
break;
case 'i':
{
r_line_set_prompt ("insert value: ");
const char *line = r_line_readline ();
if (line && *line) {
ut64 n = r_num_math (core->num, line);
r_list_push (core->ropchain, r_str_newf ("0x%08"PFMT64x, n));
}
}
break;
case ';':
{
r_line_set_prompt ("comment: ");
const char *line = r_line_readline ();
if (line && *line) {
// XXX code injection bug here
r_core_cmdf (core, "CC %s @ 0x%08"PFMT64x, line, addr + delta);
}
}
break;
case '.':
case '\n':
case '\r':
if (curline && *curline) {
char *line = r_core_cmd_strf (core, "piuq@0x%08"PFMT64x, addr + delta);
r_str_replace_char (line, '\n', ';');
if (show_color) {
// XXX parsing fails to read this ansi-offset
// const char *offsetColor = r_cons_singleton ()->context->pal.offset; // TODO etooslow. must cache
// r_list_push (core->ropchain, r_str_newf ("%s0x%08"PFMT64x""Color_RESET" %s", offsetColor, addr + delta, line));
r_list_push (core->ropchain, r_str_newf ("0x%08"PFMT64x" %s", addr + delta, line));
} else {
r_list_push (core->ropchain, r_str_newf ("0x%08"PFMT64x" %s", addr + delta, line));
}
free (line);
}
break;
case 'h':
delta--;
break;
case 'l':
delta++;
break;
case 'J':
cur+=10;
forceaddr = false;
delta = 0;
break;
case 'K':
delta = 0;
forceaddr = false;
if (cur > 10) {
cur-=10;
} else {
cur = 0;
}
break;
case '0':
delta = 0;
cur = 0;
break;
case 'j':
delta = 0;
cur++;
forceaddr = false;
break;
case 'k':
delta = 0;
forceaddr = false;
if (cur > 0) {
cur--;
} else {
cur = 0;
}
break;
case 'q':
free (curline);
free (cursearch);
R_FREE (chainstr);
return true;
}
R_FREE (chainstr);
free (curline);
}
free (cursearch);
return false;
}
R_API int r_core_visual_trackflags(RCore *core) {
const char *fs = NULL, *fs2 = NULL;
int hit, i, j, ch;
int _option = 0;
int option = 0;
char cmd[1024];
int format = 0;
int delta = 7;
int menu = 0;
int sort = SORT_NONE;
2019-02-03 16:06:45 +01:00
if (r_flag_space_is_empty (core->flags)) {
2017-03-15 12:12:01 +01:00
menu = 1;
}
for (;;) {
2018-02-09 13:59:27 +01:00
bool hasColor = r_config_get_i (core->config, "scr.color");
r_cons_clear00 ();
if (menu) {
r_cons_printf ("Flags in flagspace '%s'. Press '?' for help.\n\n",
2019-02-03 16:06:45 +01:00
r_flag_space_cur_name (core->flags));
hit = 0;
i = j = 0;
2019-02-03 16:06:45 +01:00
RList *l = r_flag_all_list (core->flags, true);
RListIter *iter;
RFlagItem *fi;
sort_flags (l, sort);
r_list_foreach (l, iter, fi) {
if (option == i) {
fs2 = fi->name;
hit = 1;
}
if ((i>=option-delta) && ((i<option+delta)||((option<delta)&&(i<(delta<<1))))) {
2018-02-09 13:59:27 +01:00
bool cur = option == i;
if (cur && hasColor) {
r_cons_printf (Color_INVERT);
}
r_cons_printf (" %c %03d 0x%08"PFMT64x" %4"PFMT64d" %s\n",
cur?'>':' ', i, fi->offset, fi->size, fi->name);
2018-02-09 13:59:27 +01:00
if (cur && hasColor) {
r_cons_printf (Color_RESET);
}
j++;
}
i++;
}
r_list_free (l);
if (!hit && i > 0) {
option = i - 1;
continue;
}
2013-09-21 17:50:09 +02:00
if (fs2) {
int cols, rows = r_cons_get_size (&cols);
//int rows = 20;
rows -= 12;
2013-09-21 17:50:09 +02:00
r_cons_printf ("\n Selected: %s\n\n", fs2);
// Honor MAX_FORMATS here
2013-09-21 17:50:09 +02:00
switch (format) {
case 0: snprintf (cmd, sizeof (cmd), "px %d @ %s!64", rows*16, fs2); core->printidx = 0; break;
case 1: snprintf (cmd, sizeof (cmd), "pd %d @ %s!64", rows, fs2); core->printidx = 1; break;
case 2: snprintf (cmd, sizeof (cmd), "ps @ %s!64", fs2); core->printidx = 5; break;
case 3: strcpy (cmd, "f="); break;
2013-09-21 17:50:09 +02:00
default: format = 0; continue;
}
if (*cmd) {
r_core_cmd (core, cmd, 0);
}
2017-03-15 12:12:01 +01:00
} else {
r_cons_printf ("(no flags)\n");
}
} else {
r_cons_printf ("Flag spaces:\n\n");
hit = 0;
2021-11-19 23:45:34 +01:00
RSpaceIter *it;
2019-02-03 16:06:45 +01:00
const RSpace *s, *cur = r_flag_space_cur (core->flags);
int i = 0;
r_flag_space_foreach (core->flags, it, s) {
if (option == i) {
fs = s->name;
hit = 1;
}
2019-02-03 16:06:45 +01:00
if ((i >= option - delta) && ((i < option + delta) ||
((option < delta) && (i < (delta << 1))))) {
r_cons_printf (" %c %c %s\n",
(option == i)? '>': ' ',
(s == cur)? '*': ' ',
s->name);
}
i++;
}
2019-02-03 16:06:45 +01:00
if (option == i) {
fs = "*";
hit = 1;
}
r_cons_printf (" %c %c %s\n", (option == i)? '>': ' ',
!cur? '*': ' ', "*");
i++;
if (!hit && i > 0) {
option = i - 1;
continue;
}
}
r_cons_visual_flush ();
ch = r_cons_readchar ();
if (ch == -1 || ch == 4) {
return false;
}
ch = r_cons_arrow_to_hjkl (ch); // get ESC+char, return 'hjkl' char
switch (ch) {
case 'C':
r_config_toggle (core->config, "scr.color");
break;
2015-10-08 14:01:07 +02:00
case '_':
2017-01-29 03:57:40 +01:00
if (r_core_visual_hudstuff (core)) {
2015-10-08 14:01:07 +02:00
return true;
2017-01-29 03:57:40 +01:00
}
2015-10-08 14:01:07 +02:00
break;
case 'J': option += 10; break;
case 'o': sort = SORT_OFFSET; break;
case 'n': sort = SORT_NAME; break;
case 'j': option++; break;
case 'k':
if (--option < 0) {
option = 0;
}
break;
case 'K': option-=10;
if (option < 0) {
option = 0;
}
break;
case 'h':
case 'b': // back
case 'Q':
case 'q':
2018-02-09 13:59:27 +01:00
if (menu <= 0) {
return true;
}
menu--;
option = _option;
if (menu == 0) {
2018-02-09 13:59:27 +01:00
r_flag_space_set (core->flags, NULL);
2013-09-21 17:50:09 +02:00
// if no flagspaces, just quit
2019-02-03 16:06:45 +01:00
if (r_flag_space_is_empty (core->flags)) {
return true;
}
2013-09-21 17:50:09 +02:00
}
break;
case 'a':
switch (menu) {
case 0: // new flag space
2015-09-14 12:35:38 +02:00
r_cons_show_cursor (true);
r_line_set_prompt ("add flagspace: ");
strcpy (cmd, "fs ");
2020-02-29 22:47:10 +03:00
if (r_cons_fgets (cmd + 3, sizeof (cmd) - 3, 0, NULL) > 0) {
r_core_cmd (core, cmd, 0);
r_cons_set_raw (1);
2015-09-14 12:35:38 +02:00
r_cons_show_cursor (false);
}
break;
case 1: // new flag
2015-09-14 12:35:38 +02:00
r_cons_show_cursor (true);
r_line_set_prompt ("add flag: ");
strcpy (cmd, "f ");
2020-02-29 22:47:10 +03:00
if (r_cons_fgets (cmd + 2, sizeof (cmd) - 2, 0, NULL) > 0) {
r_core_cmd (core, cmd, 0);
r_cons_set_raw (1);
2015-09-14 12:35:38 +02:00
r_cons_show_cursor (false);
}
break;
}
break;
case 'd':
r_flag_unset_name (core->flags, fs2);
break;
case 'e':
/* TODO: prompt for addr, size, name */
eprintf ("TODO\n");
r_sys_sleep (1);
break;
case '*':
r_core_block_size (core, core->blocksize+16);
break;
case '/':
r_core_block_size (core, core->blocksize-16);
break;
2013-09-21 17:50:09 +02:00
case '+':
if (menu == 1) {
2013-09-21 17:50:09 +02:00
r_core_cmdf (core, "f %s=%s+1", fs2, fs2);
} else {
r_core_block_size (core, core->blocksize + 1);
}
2013-09-21 17:50:09 +02:00
break;
case '-':
if (menu == 1) {
2013-09-21 17:50:09 +02:00
r_core_cmdf (core, "f %s=%s-1", fs2, fs2);
} else {
r_core_block_size (core, core->blocksize-1);
}
break;
2014-10-22 01:01:38 +02:00
case 'r': // "Vtr"
if (menu == 1) {
int len;
2015-09-14 12:35:38 +02:00
r_cons_show_cursor (true);
r_cons_set_raw (0);
// TODO: use r_flag_rename or wtf?..fr doesnt uses this..
snprintf (cmd, sizeof (cmd), "fr %s ", fs2);
len = strlen (cmd);
eprintf ("Rename flag '%s' as:\n", fs2);
r_line_set_prompt (":> ");
2020-02-29 22:47:10 +03:00
if (r_cons_fgets (cmd + len, sizeof (cmd) - len, 0, NULL) < 0) {
cmd[0] = '\0';
}
r_core_cmd (core, cmd, 0);
r_cons_set_raw (1);
2015-09-14 12:35:38 +02:00
r_cons_show_cursor (false);
}
break;
case 'R':
if (menu == 1) {
char line[1024];
2015-09-14 12:35:38 +02:00
r_cons_show_cursor (true);
r_cons_set_raw (0);
eprintf ("Rename function '%s' as:\n", fs2);
r_line_set_prompt (":> ");
if (r_cons_fgets (line, sizeof (line), 0, NULL) < 0) {
cmd[0] = '\0';
}
int res = snprintf (cmd, sizeof (cmd), "afr %s %s", line, fs2);
if (res < sizeof (cmd)) {
r_core_cmd (core, cmd, 0);
}
r_cons_set_raw (1);
2015-09-14 12:35:38 +02:00
r_cons_show_cursor (false);
}
break;
case 'P':
if (--format < 0) {
format = MAX_FORMAT;
}
break;
// = (format<=0)? MAX_FORMAT: format-1; break;
case 'p': format++; break;
case 'l':
case ' ':
case '\r':
case '\n':
if (menu == 1) {
sprintf (cmd, "s %s", fs2);
r_core_cmd (core, cmd, 0);
2015-09-14 12:35:38 +02:00
return true;
}
r_flag_space_set (core->flags, fs);
menu = 1;
_option = option;
option = 0;
break;
case '?':
r_cons_clear00 ();
r_cons_printf (
"\nVF: Visual Flags help:\n\n"
" q - quit menu\n"
2015-10-14 03:01:33 +02:00
" j/k - line down/up keys\n"
" J/K - page down/up keys\n"
" h/b - go back\n"
" C - toggle colors\n"
" l/' ' - accept current selection\n"
" a/d/e - add/delete/edit flag\n"
" +/- - increase/decrease block size\n"
" o - sort flags by offset\n"
" r/R - rename flag / Rename function\n"
" n - sort flags by name\n"
" p/P - rotate print format\n"
2015-10-08 14:01:07 +02:00
" _ - hud for flags and comments\n"
" : - enter command\n");
r_cons_flush ();
r_cons_any_key (NULL);
break;
case ':':
2015-09-14 12:35:38 +02:00
r_cons_show_cursor (true);
r_cons_set_raw (0);
2018-02-09 13:59:27 +01:00
*cmd = 0;
r_line_set_prompt (":> ");
2020-02-29 22:47:10 +03:00
if (r_cons_fgets (cmd, sizeof (cmd), 0, NULL) <0) {
2018-02-09 13:59:27 +01:00
*cmd = 0;
}
cmd[sizeof (cmd) - 1] = 0;
2018-06-06 14:32:45 +02:00
r_core_cmd_task_sync (core, cmd, 1);
r_cons_set_raw (1);
2015-09-14 12:35:38 +02:00
r_cons_show_cursor (false);
2018-02-09 13:59:27 +01:00
if (*cmd) {
r_cons_any_key (NULL);
2018-02-09 13:59:27 +01:00
}
//cons_gotoxy(0,0);
r_cons_clear ();
continue;
}
}
2015-09-14 12:35:38 +02:00
return true;
}
R_API int r_core_visual_comments(RCore *core) {
2018-04-11 10:25:22 +02:00
char *str;
char cmd[512], *p = NULL;
int ch, option = 0;
int format = 0, i = 0;
ut64 addr, from = 0, size = 0;
for (;;) {
r_cons_clear00 ();
r_cons_strcat ("Comments:\n");
2020-05-09 20:49:28 +02:00
RIntervalTreeIter it;
RAnalMetaItem *item;
i = 0;
2020-05-09 20:49:28 +02:00
r_interval_tree_foreach (&core->anal->meta, it, item) {
if (item->type != R_META_TYPE_COMMENT) {
continue;
}
str = item->str;
2020-05-09 20:49:28 +02:00
addr = r_interval_tree_iter_get (&it)->start;
if (option==i) {
from = addr;
size = 1; // XXX: remove this thing size for comments is useless d->size;
free (p);
2020-05-09 20:49:28 +02:00
p = strdup (str);
r_cons_printf (" > %s\n", str);
} else {
r_cons_printf (" %s\n", str);
}
i ++;
}
if (!i) {
if (--option < 0) {
2018-04-11 09:16:25 +02:00
r_cons_any_key ("No comments");
break;
}
2011-11-24 09:50:40 +01:00
continue;
}
r_cons_newline ();
switch (format) {
case 0: sprintf (cmd, "px @ 0x%"PFMT64x":64", from); core->printidx = 0; break;
case 1: sprintf (cmd, "pd 12 @ 0x%"PFMT64x":64", from); core->printidx = 1; break;
case 2: sprintf (cmd, "ps @ 0x%"PFMT64x":64", from); core->printidx = 5; break;
default: format = 0; continue;
}
if (*cmd) {
r_core_cmd (core, cmd, 0);
}
r_cons_visual_flush ();
ch = r_cons_readchar ();
ch = r_cons_arrow_to_hjkl (ch); // get ESC+char, return 'hjkl' char
switch (ch) {
case 'a':
//TODO
break;
case 'e':
//TODO
break;
case 'd':
2017-02-06 00:24:01 +01:00
if (p) {
2017-10-30 23:01:46 +08:00
r_meta_del (core->anal, R_META_TYPE_ANY, from, size);
2017-02-06 00:24:01 +01:00
}
break;
case 'P':
2017-02-06 00:24:01 +01:00
if (--format < 0) {
format = MAX_FORMAT;
2017-02-06 00:24:01 +01:00
}
break;
case 'p':
format++;
break;
case 'J':
option += 10;
break;
case 'j':
option++;
break;
case 'k':
if (--option < 0) {
option = 0;
}
break;
case 'K':
option -= 10;
if (option < 0) {
option = 0;
}
break;
case 'l':
case ' ':
case '\r':
case '\n':
r_core_cmdf (core, "s 0x%"PFMT64x, from);
R_FREE (p);
2015-09-14 12:35:38 +02:00
return true;
case 'Q':
case 'q':
R_FREE (p);
2015-09-14 12:35:38 +02:00
return true;
2011-11-24 09:50:40 +01:00
case '?':
case 'h':
r_cons_clear00 ();
r_cons_printf (
"\nVT: Visual Comments/Anal help:\n\n"
" q - quit menu\n"
" j/k - down/up keys\n"
" h/b - go back\n"
" l/' ' - accept current selection\n"
" a/d/e - add/delete/edit comment/anal symbol\n"
" p/P - rotate print format\n");
r_cons_flush ();
r_cons_any_key (NULL);
break;
}
2017-02-06 00:24:01 +01:00
R_FREE (p);
}
2015-09-14 12:35:38 +02:00
return true;
}
static void config_visual_hit_i(RCore *core, const char *name, int delta) {
struct r_config_node_t *node;
node = r_config_node_get (core->config, name);
2020-01-16 15:05:55 +01:00
if (node && r_config_node_is_int (node)) {
2017-03-15 12:12:01 +01:00
int hitDelta = r_config_get_i (core->config, name) + delta;
(void) r_config_set_i (core->config, name, hitDelta);
}
}
/* Visually activate the config variable */
static void config_visual_hit(RCore *core, const char *name, int editor) {
char buf[1024];
RConfigNode *node;
2017-02-06 00:24:01 +01:00
if (!(node = r_config_node_get (core->config, name))) {
return;
2017-02-06 00:24:01 +01:00
}
2020-01-16 15:05:55 +01:00
if (r_config_node_is_bool (node)) {
r_config_set_i (core->config, name, node->i_value? 0:1);
} else {
// XXX: must use config_set () to run callbacks!
if (editor) {
char * buf = r_core_editor (core, NULL, node->value);
node->value = r_str_dup (node->value, buf);
free (buf);
} else {
// FGETS AND SO
r_cons_printf ("New value (old=%s): \n", node->value);
2015-09-14 12:35:38 +02:00
r_cons_show_cursor (true);
r_cons_flush ();
r_cons_set_raw (0);
r_line_set_prompt (":> ");
2020-02-29 22:47:10 +03:00
r_cons_fgets (buf, sizeof (buf), 0, 0);
r_cons_set_raw (1);
2015-09-14 12:35:38 +02:00
r_cons_show_cursor (false);
r_config_set (core->config, name, buf);
//node->value = r_str_dup (node->value, buf);
}
}
}
static void show_config_options(RCore *core, const char *opt) {
RConfigNode *node = r_config_node_get (core->config, opt);
if (node && !r_list_empty (node->options)) {
int h, w = r_cons_get_size (&h);
const char *item;
RListIter *iter;
RStrBuf *sb = r_strbuf_new (" Options: ");
r_list_foreach (node->options, iter, item) {
r_strbuf_appendf (sb, "%s%s", iter->p? ", ": "", item);
if (r_strbuf_length (sb) + 5 >= w) {
char *s = r_strbuf_drain (sb);
r_cons_println (s);
free (s);
sb = r_strbuf_new ("");
}
}
char *s = r_strbuf_drain (sb);
r_cons_println (s);
free (s);
}
}
R_API void r_core_visual_config(RCore *core) {
2015-03-21 02:04:49 +01:00
char *fs = NULL, *fs2 = NULL, *desc = NULL;
int i, j, ch, hit, show;
int option, _option = 0;
RListIter *iter;
RConfigNode *bt;
char old[1024];
int delta = 9;
int menu = 0;
old[0]='\0';
option = 0;
for (;;) {
r_cons_clear00 ();
2015-04-14 03:07:57 +02:00
r_cons_get_size (&delta);
delta /= 4;
switch (menu) {
case 0: // flag space
r_cons_printf ("[EvalSpace]\n\n");
hit = j = i = 0;
r_list_foreach (core->config->nodes, iter, bt) {
if (option == i) {
fs = bt->name;
}
if (!old[0]) {
r_str_ccpy (old, bt->name, '.');
show = 1;
} else if (r_str_ccmp (old, bt->name, '.')) {
r_str_ccpy (old, bt->name, '.');
show = 1;
} else {
show = 0;
}
if (show) {
if (option == i) {
hit = 1;
}
if ( (i >=option-delta) && ((i<option+delta)||((option<delta)&&(i<(delta<<1))))) {
r_cons_printf (" %c %s\n", (option == i)?'>':' ', old);
j++;
}
i++;
}
}
if (!hit && j > 0) {
option--;
continue;
}
r_cons_printf ("\n Sel: %s \n\n", fs);
break;
case 1: // flag selection
r_cons_printf ("[EvalSpace < Variables: %s]\n\n", fs);
hit = 0;
j = i = 0;
// TODO: cut -d '.' -f 1 | sort | uniq !!!
r_list_foreach (core->config->nodes, iter, bt) {
if (!r_str_ccmp (bt->name, fs, '.')) {
if (option == i) {
fs2 = bt->name;
desc = bt->desc;
hit = 1;
}
if ( (i>=option-delta) && ((i<option+delta)||((option<delta)&&(i<(delta<<1))))) {
// TODO: Better align
r_cons_printf (" %c %s = %s\n", (option==i)?'>':' ', bt->name, bt->value);
j++;
}
i++;
}
}
if (!hit && j > 0) {
option = i - 1;
continue;
}
if (fs2) {
// TODO: Break long lines.
r_cons_printf ("\n Selected: %s (%s)\n", fs2, desc);
show_config_options (core, fs2);
r_cons_newline ();
}
}
2016-05-20 17:11:29 +02:00
if (fs && !strncmp (fs, "asm.", 4)) {
2016-01-11 00:40:14 +01:00
r_core_cmd (core, "pd $r", 0);
2016-05-20 17:11:29 +02:00
}
r_cons_visual_flush ();
ch = r_cons_readchar ();
if (ch == 4 || ch == -1) {
2014-02-08 12:09:12 +01:00
return;
}
ch = r_cons_arrow_to_hjkl (ch); // get ESC+char, return 'hjkl' char
switch (ch) {
case 'j': option++; break;
case 'k': option = (option < 1)? 0: option - 1; break;
case 'J': option += 4; break;
case 'K': option = (option < 4)? 0: option - 4; break;
case 'h':
case 'b': // back
menu = 0;
option = _option;
break;
2015-10-23 16:55:38 +02:00
case '_':
r_core_visual_config_hud (core);
break;
case 'Q':
case 'q':
if (menu <= 0) {
return;
}
menu--;
2015-07-15 01:39:00 +02:00
option = _option;
break;
case '$':
r_core_cmd0 (core, "?$");
r_cons_any_key (NULL);
break;
case '*':
case '+':
fs2 ? config_visual_hit_i (core, fs2, +1) : 0;
continue;
case '/':
case '-':
fs2 ? config_visual_hit_i (core, fs2, -1) : 0;
continue;
case 'l':
case 'E': // edit value
case 'e': // edit value
case ' ':
case '\r':
case '\n': // never happens
if (menu == 1) {
fs2 ? config_visual_hit (core, fs2, (ch=='E')) : 0;
} else {
menu = 1;
_option = option;
option = 0;
}
break;
case '?':
r_cons_clear00 ();
r_cons_printf ("\nVe: Visual Eval help:\n\n"
" q - quit menu\n"
" j/k - down/up keys\n"
" h/b - go back\n"
" $ - same as ?$ - show values of vars\n"
" e/' ' - edit/toggle current variable\n"
" E - edit variable with 'cfg.editor' (vi?)\n"
" +/- - increase/decrease numeric value (* and /, too)\n"
" : - enter command\n");
r_cons_flush ();
r_cons_any_key (NULL);
break;
case ':':
2015-09-14 12:35:38 +02:00
r_cons_show_cursor (true);
r_cons_set_raw (0);
{
char *cmd = prompt (":> ", NULL);
r_core_cmd (core, cmd, 1);
free (cmd);
}
r_cons_set_raw (1);
2015-09-14 12:35:38 +02:00
r_cons_show_cursor (false);
r_cons_any_key (NULL);
r_cons_clear00 ();
continue;
}
}
}
R_API void r_core_visual_mounts(RCore *core) {
2015-02-05 00:29:59 -05:00
RList *list = NULL;
2015-02-05 10:30:46 +01:00
RFSRoot *fsroot = NULL;
2011-07-11 22:52:05 +02:00
RListIter *iter;
RFSFile *file;
RFSPartition *part;
int i, ch, option, mode, partition, dir, delta = 7;
char *str, path[4096], buf[1024], *root = NULL;
2011-07-11 22:52:05 +02:00
const char *n, *p;
dir = partition = option = mode = 0;
for (;;) {
/* Clear */
r_cons_clear00 ();
2011-07-11 22:52:05 +02:00
/* Show */
if (mode == 0) {
if (list) {
2015-02-08 00:30:25 +01:00
r_list_free (list);
list = NULL;
2015-02-05 00:29:59 -05:00
}
2014-11-03 04:05:19 +01:00
r_cons_printf ("Press '/' to navigate the root filesystem.\nPartitions:\n\n");
2011-07-11 22:52:05 +02:00
n = r_fs_partition_type_get (partition);
list = r_fs_partitions (core->fs, n, 0);
i = 0;
if (list) {
r_list_foreach (list, iter, part) {
if ((option-delta <= i) && (i <= option+delta)) {
if (option == i) {
r_cons_printf (" > ");
} else {
r_cons_printf (" ");
}
r_cons_printf ("%d %02x 0x%010"PFMT64x" 0x%010"PFMT64x"\n",
part->number, part->type,
part->start, part->start+part->length);
2011-07-11 22:52:05 +02:00
}
i++;
2011-07-11 22:52:05 +02:00
}
r_list_free (list);
2015-02-17 00:34:51 +01:00
list = NULL;
} else {
r_cons_printf ("Cannot read partition\n");
}
2011-07-11 22:52:05 +02:00
} else if (mode == 1) {
r_cons_printf ("Types:\n\n");
for (i=0;;i++) {
2011-07-11 22:52:05 +02:00
n = r_fs_partition_type_get (i);
if (!n) {
break;
}
2011-07-11 22:52:05 +02:00
r_cons_printf ("%s%s\n", (i==partition)?" > ":" ", n);
}
} else if (mode == 3) {
i = 0;
r_cons_printf ("Mountpoints:\n\n");
r_list_foreach (core->fs->roots, iter, fsroot) {
2015-02-05 10:30:46 +01:00
if (fsroot && (option-delta <= i) && (i <= option+delta)) {
r_cons_printf ("%s %s\n", (option == i)?" > ":" ",
fsroot->path);
}
i++;
}
2011-07-11 22:52:05 +02:00
} else {
if (root) {
list = r_fs_dir (core->fs, path);
if (list) {
r_cons_printf ("%s:\n\n", path);
2011-07-11 22:52:05 +02:00
i = 0;
r_list_foreach (list, iter, file) {
if ((dir-delta <= i) && (i <= dir+delta)) {
r_cons_printf ("%s%c %s\n", (dir == i)?" > ":" ",
file->type, file->name);
}
i++;
2011-07-11 22:52:05 +02:00
}
r_cons_printf ("\n");
2011-07-11 22:52:05 +02:00
r_list_free (list);
2015-02-17 00:34:51 +01:00
list = NULL;
} else {
r_cons_printf ("Cannot open '%s' directory\n", root);
}
} else {
r_cons_printf ("Root undefined\n");
}
2011-07-11 22:52:05 +02:00
}
if (mode==2) {
r_str_trim_path (path);
size_t n = strlen (path);
str = path + n;
snprintf (str, sizeof (path) - n, "/");
list = r_fs_dir (core->fs, path);
file = r_list_get_n (list, dir);
if (file && file->type != 'd') {
r_core_cmdf (core, "px @ 0x%" PFMT64x "!64", file->off);
}
2015-01-29 12:16:37 +01:00
r_list_free (list);
2015-02-17 00:34:51 +01:00
list = NULL;
*str='\0';
}
2011-07-11 22:52:05 +02:00
r_cons_flush ();
/* Ask for option */
ch = r_cons_readchar ();
2015-01-30 22:50:48 +01:00
if (ch==-1||ch==4){
free (root);
return;
}
2011-07-11 22:52:05 +02:00
ch = r_cons_arrow_to_hjkl (ch);
switch (ch) {
2014-11-03 04:05:19 +01:00
case '/':
R_FREE (root);
2014-11-03 04:05:19 +01:00
root = strdup ("/");
strncpy (path, root, sizeof (path)-1);
mode = 2;
break;
case 'l':
2011-07-11 22:52:05 +02:00
case '\r':
case '\n':
if (mode == 0) {
n = r_fs_partition_type_get (partition);
list = r_fs_partitions (core->fs, n, 0);
if (!list) {
r_cons_printf ("Unknown partition\n");
r_cons_any_key (NULL);
2011-07-11 22:52:05 +02:00
r_cons_flush ();
break;
}
part = r_list_get_n (list, option);
if (!part) {
r_cons_printf ("Unknown partition\n");
r_cons_any_key (NULL);
2011-07-11 22:52:05 +02:00
r_cons_flush ();
break;
}
p = r_fs_partition_type (n, part->type);
if (p) {
if (r_fs_mount (core->fs, p, "/root", part->start)) {
2015-01-30 22:50:48 +01:00
free (root);
2011-07-11 22:52:05 +02:00
root = strdup ("/root");
2011-09-18 20:41:36 +02:00
strncpy (path, root, sizeof (path)-1);
2011-07-11 22:52:05 +02:00
mode = 2;
} else {
r_cons_printf ("Cannot mount partition\n");
r_cons_flush ();
r_cons_any_key (NULL);
2011-07-11 22:52:05 +02:00
}
} else {
r_cons_printf ("Unknown partition type\n");
r_cons_flush ();
r_cons_any_key (NULL);
2011-07-11 22:52:05 +02:00
}
2015-01-29 12:16:37 +01:00
r_list_free (list);
2015-02-17 00:34:51 +01:00
list = NULL;
2011-07-11 22:52:05 +02:00
} else if (mode == 2){
r_str_trim_path (path);
size_t n = strlen (path);
snprintf (path + n, sizeof (path) - n, "/");
2011-07-11 22:52:05 +02:00
list = r_fs_dir (core->fs, path);
file = r_list_get_n (list, dir);
if (file) {
if (file->type == 'd') {
n = strlen (path);
snprintf (path + n, sizeof (path) - n, "%s", file->name);
r_str_trim_path (path);
if (root && strncmp (root, path, strlen (root) - 1)) {
strncpy (path, root, sizeof (path) - 1);
}
} else {
r_core_cmdf (core, "s 0x%"PFMT64x, file->off);
2011-07-11 22:52:05 +02:00
r_fs_umount (core->fs, root);
2014-05-03 04:11:05 +04:00
free (root);
2011-07-11 22:52:05 +02:00
return;
}
} else {
r_cons_printf ("Unknown file\n");
r_cons_flush ();
r_cons_any_key (NULL);
2011-07-11 22:52:05 +02:00
}
} else if (mode == 3) {
fsroot = r_list_get_n (core->fs->roots, option);
if (fsroot) {
root = strdup (fsroot->path);
strncpy (path, root, sizeof (path)-1);
}
mode = 2;
2011-07-11 22:52:05 +02:00
}
dir = partition = option = 0;
2011-07-11 22:52:05 +02:00
break;
case 'k':
if (mode == 0 || mode == 3) {
if (option > 0) {
2011-07-11 22:52:05 +02:00
option--;
}
2011-07-11 22:52:05 +02:00
} else if (mode == 1) {
if (partition > 0) {
2011-07-11 22:52:05 +02:00
partition--;
}
2011-07-11 22:52:05 +02:00
} else {
if (dir > 0) {
2011-07-11 22:52:05 +02:00
dir--;
}
2011-07-11 22:52:05 +02:00
}
break;
case 'j':
if (mode == 0) {
n = r_fs_partition_type_get (partition);
list = r_fs_partitions (core->fs, n, 0);
if (option < r_list_length (list) - 1) {
2011-07-11 22:52:05 +02:00
option++;
}
2011-07-11 22:52:05 +02:00
} else if (mode == 1) {
if (partition < r_fs_partition_get_size () - 1) {
2011-07-11 22:52:05 +02:00
partition++;
}
} else if (mode == 3) {
if (option < r_list_length (core->fs->roots) - 1) {
option++;
}
2011-07-11 22:52:05 +02:00
} else {
list = r_fs_dir (core->fs, path);
if (dir < r_list_length (list) - 1) {
dir++;
}
2011-07-11 22:52:05 +02:00
}
break;
case 't':
mode = 1;
break;
case 'h':
if (mode == 2) {
if (!root) {
mode = 0;
} else
if (strcmp (path, root)) {
strcat (path, "/..");
r_str_trim_path (path);
} else {
r_fs_umount (core->fs, root);
mode = 0;
}
} else if (mode == 1) {
mode = 0;
} else {
return;
}
break;
case 'Q':
case 'q':
if (mode == 2 && root) {
2011-07-11 22:52:05 +02:00
r_fs_umount (core->fs, root);
mode = 0;
} else {
return;
}
break;
case 'g':
2015-02-05 10:30:46 +01:00
if (mode == 2) {
r_str_trim_path (path);
size_t n = strlen (path);
str = path + n;
snprintf (str, sizeof (path) - n, "/");
list = r_fs_dir (core->fs, path);
file = r_list_get_n (list, dir);
2015-02-05 10:30:46 +01:00
if (file && root) {
n = strlen (path);
snprintf (path + n, sizeof (path) - n, "%s", file->name);
r_str_trim_path (path);
if (strncmp (root, path, strlen (root) - 1)) {
strncpy (path, root, sizeof (path) - 1);
}
file = r_fs_open (core->fs, path, false);
if (file) {
r_fs_read (core->fs, file, 0, file->size);
2015-09-14 12:35:38 +02:00
r_cons_show_cursor (true);
r_cons_set_raw (0);
r_line_set_prompt ("Dump path (ej: /tmp/file): ");
2020-02-29 22:47:10 +03:00
r_cons_fgets (buf, sizeof (buf), 0, 0);
r_cons_set_raw (1);
2015-09-14 12:35:38 +02:00
r_cons_show_cursor (false);
2015-04-03 04:04:46 +02:00
r_file_dump (buf, file->data, file->size, 0);
r_fs_close (core->fs, file);
r_cons_printf ("Done\n");
} else {
r_cons_printf ("Cannot dump file\n");
}
} else {
r_cons_printf ("Cannot dump file\n");
}
r_cons_flush ();
r_cons_any_key (NULL);
*str='\0';
}
2011-07-11 22:52:05 +02:00
break;
case 'm':
mode = 3;
option = 0;
break;
2011-07-11 22:52:05 +02:00
case '?':
r_cons_clear00 ();
r_cons_printf ("\nVM: Visual Mount points help:\n\n");
r_cons_printf (" q - go back or quit menu\n");
2011-07-11 22:52:05 +02:00
r_cons_printf (" j/k - down/up keys\n");
r_cons_printf (" h/l - forward/go keys\n");
2011-07-11 22:52:05 +02:00
r_cons_printf (" t - choose partition type\n");
r_cons_printf (" g - dump file\n");
r_cons_printf (" m - show mountpoints\n");
r_cons_printf (" : - enter command\n");
2011-07-11 22:52:05 +02:00
r_cons_printf (" ? - show this help\n");
r_cons_flush ();
r_cons_any_key (NULL);
2011-07-11 22:52:05 +02:00
break;
case ':':
2015-09-14 12:35:38 +02:00
r_cons_show_cursor (true);
2011-07-11 22:52:05 +02:00
r_cons_set_raw (0);
r_line_set_prompt (":> ");
2020-02-29 22:47:10 +03:00
r_cons_fgets (buf, sizeof (buf), 0, 0);
2011-07-11 22:52:05 +02:00
r_cons_set_raw (1);
2015-09-14 12:35:38 +02:00
r_cons_show_cursor (false);
2011-07-11 22:52:05 +02:00
r_core_cmd (core, buf, 1);
r_cons_any_key (NULL);
2011-07-11 22:52:05 +02:00
break;
}
}
}
// helper
static void function_rename(RCore *core, ut64 addr, const char *name) {
RListIter *iter;
RAnalFunction *fcn;
r_list_foreach (core->anal->fcns, iter, fcn) {
if (fcn->addr == addr) {
r_flag_unset_name (core->flags, fcn->name);
free (fcn->name);
fcn->name = strdup (name);
r_flag_set (core->flags, name, addr, r_anal_function_size_from_entry (fcn));
break;
}
}
}
static void variable_rename(RCore *core, ut64 addr, int vindex, const char *name) {
2017-09-27 00:01:55 -07:00
RAnalFunction* fcn = r_anal_get_fcn_in (core->anal, addr, R_ANAL_FCN_TYPE_NULL);
ut64 a_tmp = core->offset;
int i = 0;
RListIter *iter;
RList *list = r_anal_var_all_list (core->anal, fcn);
2017-09-27 00:01:55 -07:00
RAnalVar* var;
r_list_foreach (list, iter, var) {
if (i == vindex) {
r_core_seek (core, addr, false);
r_core_cmd_strf (core, "afvn %s %s", name, var->name);
2017-09-27 00:01:55 -07:00
r_core_seek (core, a_tmp, false);
break;
}
++i;
}
r_list_free (list);
}
static void variable_set_type(RCore *core, ut64 addr, int vindex, const char *type) {
RAnalFunction* fcn = r_anal_get_fcn_in (core->anal, addr, R_ANAL_FCN_TYPE_NULL);
RList *list = r_anal_var_all_list (core->anal, fcn);
RListIter *iter;
RAnalVar* var;
r_list_foreach (list, iter, var) {
if (vindex == 0) {
r_anal_var_set_type (var, type);
break;
}
vindex--;
}
r_list_free (list);
}
// In visual mode, display function list
static ut64 var_functions_show(RCore *core, int idx, int show, int cols) {
int wdelta = (idx > 5)? idx - 5: 0;
char *var_functions;
ut64 seek = core->offset;
ut64 addr = core->offset;
RAnalFunction *fcn;
int window, i = 0, print_full_func;
RListIter *iter;
// Adjust the windows size automaticaly
(void)r_cons_get_size (&window);
window -= 8; // Size of printed things
bool color = r_config_get_i (core->config, "scr.color");
const char *color_addr = core->cons->context->pal.offset;
const char *color_fcn = core->cons->context->pal.fname;
r_list_foreach (core->anal->fcns, iter, fcn) {
print_full_func = true;
if (i >= wdelta) {
if (i > window + wdelta - 1) {
r_cons_printf ("...\n");
break;
}
if (idx == i) {
addr = fcn->addr;
}
if (show) {
char *tmp;
if (color) {
2020-10-21 17:27:17 +08:00
var_functions = r_str_newf ("%c%c %s0x%08"PFMT64x"" Color_RESET" %4"PFMT64d" %s%s"Color_RESET"",
(seek == fcn->addr)?'>':' ',
(idx==i)?'*':' ',
color_addr, fcn->addr, r_anal_function_realsize (fcn),
color_fcn, fcn->name);
} else {
2020-10-21 17:27:17 +08:00
var_functions = r_str_newf ("%c%c 0x%08"PFMT64x" %4"PFMT64d" %s",
(seek == fcn->addr)?'>':' ',
(idx==i)?'*':' ',
fcn->addr, r_anal_function_realsize (fcn), fcn->name);
}
if (var_functions) {
if (!r_cons_singleton ()->show_vals) {
int fun_len = r_str_ansi_len (var_functions);
int columns = fun_len > cols ? cols - 2 : cols;
tmp = r_str_ansi_crop (var_functions, 0, 0, columns, window);
if (r_str_ansi_len (tmp) < fun_len) {
r_cons_printf ("%s..%s\n", tmp, Color_RESET);
print_full_func = false;
}
r_free (tmp);
}
if (print_full_func) {
r_cons_println (var_functions);
}
r_free (var_functions);
}
}
}
i++;
}
return addr;
}
// In visual mode, display the variables.
static ut64 var_variables_show(RCore* core, int idx, int *vindex, int show, int cols) {
int i = 0;
2021-10-19 10:49:11 +02:00
int window, wdelta = (idx > 5) ? idx - 5 : 0;
const ut64 addr = var_functions_show (core, idx, 0, cols);
RAnalFunction* fcn = r_anal_get_fcn_in (core->anal, addr, R_ANAL_FCN_TYPE_NULL);
RListIter *iter;
2021-10-19 10:49:11 +02:00
if (!fcn) {
return UT64_MAX;
}
RList *list = r_anal_var_all_list (core->anal, fcn);
RAnalVar* var;
// Adjust the window size automatically.
(void)r_cons_get_size (&window);
window -= 8; // Size of printed things.
// A new line so this looks reasonable.
r_cons_newline ();
int llen = r_list_length (list);
if (*vindex >= llen) {
*vindex = llen - 1;
}
r_list_foreach (list, iter, var) {
if (i > window + wdelta) {
r_cons_printf ("...\n");
break;
}
if (show) {
switch (var->kind & 0xff) {
case 'r':
{
RRegItem *r = r_reg_index_get (core->anal->reg, var->delta);
if (!r) {
eprintf ("Register not found");
break;
}
r_cons_printf ("%sarg %s %s @ %s\n",
i == *vindex ? "* ":" ",
var->type, var->name,
r->name);
}
break;
case 'b':
r_cons_printf ("%s%s %s %s @ %s%s0x%x\n",
i == *vindex ? "* ":" ",
var->delta < 0? "var": "arg",
var->type, var->name,
core->anal->reg->name[R_REG_NAME_BP],
(var->kind == 'v')?"-":"+",
var->delta);
break;
case 's':
r_cons_printf ("%s%s %s %s @ %s%s0x%x\n",
i == *vindex ? "* ":" ",
var->delta < 0? "var": "arg",
var->type, var->name,
core->anal->reg->name[R_REG_NAME_SP],
(var->kind == 'v')?"-":"+",
var->delta + fcn->maxstack);
break;
}
}
++i;
}
r_list_free (list);
return addr;
}
static int level = 0;
static st64 delta = 0;
static int option = 0;
static int variable_option = 0;
static int printMode = 0;
static bool selectPanel = false;
#define lastPrintMode 6
2020-04-16 01:20:46 -04:00
static const char *printCmds[lastPrintMode] = {
"pdf", "pd $r", "afi", "pdsf", "pdc", "pdr"
};
static void r_core_visual_anal_refresh_column(RCore *core, int colpos) {
2016-05-20 17:11:29 +02:00
const ut64 addr = (level != 0 && level != 1)
? core->offset
: var_functions_show (core, option, 0, colpos);
// RAnalFunction* fcn = r_anal_get_fcn_in(core->anal, addr, R_ANAL_FCN_TYPE_NULL);
int h, w = r_cons_get_size (&h);
// int sz = (fcn)? R_MIN (r_anal_function_size (fcn), h * 15) : 16; // max instr is 15 bytes.
2016-05-20 17:11:29 +02:00
2020-04-16 01:20:46 -04:00
const char *cmd;
if (printMode > 0 && printMode < lastPrintMode) {
cmd = printCmds[printMode];
} else {
cmd = printCmds[printMode = 0];
}
char *cmdf = r_str_newf ("%s @ 0x%"PFMT64x, cmd, addr + delta);
if (!cmdf) {
return;
}
2016-05-20 17:11:29 +02:00
char *output = r_core_cmd_str (core, cmdf);
if (output) {
// 'h - 2' because we have two new lines in r_cons_printf
char *out = r_str_ansi_crop (output, 0, 0, w - colpos, h - 2);
r_cons_printf ("\n%s\n", out);
2016-05-20 17:11:29 +02:00
free (out);
R_FREE (output);
}
2016-05-20 17:11:29 +02:00
free (cmdf);
}
2019-07-24 22:40:10 +05:30
static const char *help_fun_visual[] = {
Fix wording and whitespacing ##doc (#18065) * Fix wording, whitespacing and other minor stuff * cmd.c: ellaborated yy syntax, improved descriptions - replace "srcoff" with "origin" * cmd.c(cmd_autocomplete): - refactor help into function: render autocomplete types with generic help subsystem; - "Types" heading now follow the "Usage" style by not being prefixed by a pipe character; * cmd_anal.c: fix whitespaces & help text * cmd_info.c: fix help text capitalization. * cmd_print.c: - fix `pf` cmd help; - TODO: what pz? is doing here? * cons.c: - refactor & better document r_cons_cmd_help(); - fix whitespaces; * visual & panels modes: - as of commit 46187fe4e14dc465dc6ac03fcc56a362f0b8e335, '!' no longer launches the r2048 game. The game itself it broken anyway, even when running from the Help menu in panels mode; - transitioning from panels to visual is not 'entering' but actually swapping/replacing visual panels with just panels, thus... - reword 'enter into the' to 'swap into' or even just 'enter', e.g.: "enter into the visual panels mode" -> "enter visual panels mode". - remove the "(dwm style)" words from a fortune tip, because I have no idea what it is, and it does not appear to be a valid command in any of the r2 modes. - update global help text. * [WIP 2] Fix wording, whitespacing and other minor stuff * visual.c: - r_core_visual_append_help(): first steps merging with r_cons_cmd_help from cons.c; use consistent colors for headers. * [WIP 3] Fix wording, whitespacing and other minor stuff * panels.c(__update_help): - shorten code and titles; - add comment to clarify that it is not a copy-paste error; * [WIP 4] Fix wording, whitespacing and other minor stuff panels.c, visual.c: tweak help text; * [WIP 5] Fix wording, whitespacing and other minor stuff * cmd_help.c: update global help text about visual mode -- it was outdated and overloaded. * vmenus.c: - rename stuff, shuffle around static consts to reflect an actual ordering when viewing as a help text; - slightly improve help text rendering; - fix whitespaces; * [WIP 6] Fix wording, whitespacing and other minor stuff * lots of help text changed. still working on proper commit message.
2020-12-21 03:12:08 +03:00
"(a)", "analyze ", "(-)", "delete ", "(x)", "xrefs ", "(X)", "refs ", "(j/k)", "next/prev\n",
"(r)", "rename ", "(c)", "calls ", "(d)", "define ", "(Tab)", "disasm ", "(_)", "hud\n",
"(d)", "define ", "(v)", "vars ", "(?)", " help ", "(:)", "shell " ,"(q)", "quit\n",
"(s)", "edit function signature\n\n",
2019-07-24 22:40:10 +05:30
NULL
};
static const char *help_var_visual[] = {
"(a)", "add " ,"(x)", "xrefs ", "(r)", "rename\n",
"(t)", "type ", "(g)", "go ", "(-)" ,"delete\n",
"(q)", "quit ", "(s)", "signature\n\n",
NULL
};
Fix wording and whitespacing ##doc (#18065) * Fix wording, whitespacing and other minor stuff * cmd.c: ellaborated yy syntax, improved descriptions - replace "srcoff" with "origin" * cmd.c(cmd_autocomplete): - refactor help into function: render autocomplete types with generic help subsystem; - "Types" heading now follow the "Usage" style by not being prefixed by a pipe character; * cmd_anal.c: fix whitespaces & help text * cmd_info.c: fix help text capitalization. * cmd_print.c: - fix `pf` cmd help; - TODO: what pz? is doing here? * cons.c: - refactor & better document r_cons_cmd_help(); - fix whitespaces; * visual & panels modes: - as of commit 46187fe4e14dc465dc6ac03fcc56a362f0b8e335, '!' no longer launches the r2048 game. The game itself it broken anyway, even when running from the Help menu in panels mode; - transitioning from panels to visual is not 'entering' but actually swapping/replacing visual panels with just panels, thus... - reword 'enter into the' to 'swap into' or even just 'enter', e.g.: "enter into the visual panels mode" -> "enter visual panels mode". - remove the "(dwm style)" words from a fortune tip, because I have no idea what it is, and it does not appear to be a valid command in any of the r2 modes. - update global help text. * [WIP 2] Fix wording, whitespacing and other minor stuff * visual.c: - r_core_visual_append_help(): first steps merging with r_cons_cmd_help from cons.c; use consistent colors for headers. * [WIP 3] Fix wording, whitespacing and other minor stuff * panels.c(__update_help): - shorten code and titles; - add comment to clarify that it is not a copy-paste error; * [WIP 4] Fix wording, whitespacing and other minor stuff panels.c, visual.c: tweak help text; * [WIP 5] Fix wording, whitespacing and other minor stuff * cmd_help.c: update global help text about visual mode -- it was outdated and overloaded. * vmenus.c: - rename stuff, shuffle around static consts to reflect an actual ordering when viewing as a help text; - slightly improve help text rendering; - fix whitespaces; * [WIP 6] Fix wording, whitespacing and other minor stuff * lots of help text changed. still working on proper commit message.
2020-12-21 03:12:08 +03:00
static const char *help_visual_anal_actions[] = {
"functions:", "Add, Modify, Delete, Xrefs Calls Vars",
"variables:", "Add, Modify, Delete",
2019-07-24 22:40:10 +05:30
NULL
};
Fix wording and whitespacing ##doc (#18065) * Fix wording, whitespacing and other minor stuff * cmd.c: ellaborated yy syntax, improved descriptions - replace "srcoff" with "origin" * cmd.c(cmd_autocomplete): - refactor help into function: render autocomplete types with generic help subsystem; - "Types" heading now follow the "Usage" style by not being prefixed by a pipe character; * cmd_anal.c: fix whitespaces & help text * cmd_info.c: fix help text capitalization. * cmd_print.c: - fix `pf` cmd help; - TODO: what pz? is doing here? * cons.c: - refactor & better document r_cons_cmd_help(); - fix whitespaces; * visual & panels modes: - as of commit 46187fe4e14dc465dc6ac03fcc56a362f0b8e335, '!' no longer launches the r2048 game. The game itself it broken anyway, even when running from the Help menu in panels mode; - transitioning from panels to visual is not 'entering' but actually swapping/replacing visual panels with just panels, thus... - reword 'enter into the' to 'swap into' or even just 'enter', e.g.: "enter into the visual panels mode" -> "enter visual panels mode". - remove the "(dwm style)" words from a fortune tip, because I have no idea what it is, and it does not appear to be a valid command in any of the r2 modes. - update global help text. * [WIP 2] Fix wording, whitespacing and other minor stuff * visual.c: - r_core_visual_append_help(): first steps merging with r_cons_cmd_help from cons.c; use consistent colors for headers. * [WIP 3] Fix wording, whitespacing and other minor stuff * panels.c(__update_help): - shorten code and titles; - add comment to clarify that it is not a copy-paste error; * [WIP 4] Fix wording, whitespacing and other minor stuff panels.c, visual.c: tweak help text; * [WIP 5] Fix wording, whitespacing and other minor stuff * cmd_help.c: update global help text about visual mode -- it was outdated and overloaded. * vmenus.c: - rename stuff, shuffle around static consts to reflect an actual ordering when viewing as a help text; - slightly improve help text rendering; - fix whitespaces; * [WIP 6] Fix wording, whitespacing and other minor stuff * lots of help text changed. still working on proper commit message.
2020-12-21 03:12:08 +03:00
static const char *help_visual_anal_keys[] = {
"j/k", "select next/prev item; scroll disasm column",
"J/K", "scroll next/prev by page",
"b/h", "functions analysis (level 0)",
"v/l", "variables analysis (level 1)",
"c", "calls/xref analysis (level 2)",
"q/Q", "go back one level or quit",
"Space/Enter", "quit",
"p/P", "switch next/prev print mode",
"x/X", "see xrefs to the selected function",
"Tab", "disasm column scrolling",
"!", "run `afls` to sort all functions by address",
".", "seek to current function address",
":", "run r2 commands",
"_", "hud mode, same as `s $(afl~...)`",
2019-07-24 22:40:10 +05:30
NULL
};
static void r_core_vmenu_append_help(RStrBuf *p, const char **help) {
2019-07-24 22:40:10 +05:30
int i;
RConsContext *cons_ctx = r_cons_singleton ()->context;
const char *pal_args_color = cons_ctx->color_mode ? cons_ctx->pal.args : "",
*pal_help_color = cons_ctx->color_mode ? cons_ctx->pal.help : "",
*pal_reset = cons_ctx->color_mode ? cons_ctx->pal.reset : "";
for (i = 0; help[i]; i += 2) {
r_strbuf_appendf (p, "%s%s %s%s%s",
pal_args_color, help[i],
pal_help_color, help[i + 1], pal_reset);
}
}
static ut64 r_core_visual_anal_refresh(RCore *core) {
2018-06-29 20:48:25 +09:00
if (!core) {
return 0LL;
}
ut64 addr;
2019-07-24 22:40:10 +05:30
RStrBuf *buf;
char old[1024];
bool color = r_config_get_i (core->config, "scr.color");
int h, cols = r_cons_get_size (&h);
old[0] = '\0';
addr = core->offset;
cols -= 50;
if (cols > 60) {
cols = 60;
}
2014-08-23 02:27:31 +02:00
r_cons_clear00 ();
2016-05-20 17:11:29 +02:00
r_core_visual_anal_refresh_column (core, cols);
if (cols > 30) {
r_cons_column (cols);
}
switch (level) {
// Show functions list help in visual mode
case 0:
2019-07-24 22:40:10 +05:30
buf = r_strbuf_new ("");
if (color) {
r_cons_strcat (core->cons->context->pal.prompt);
}
if (selectPanel) {
r_cons_printf ("-- functions -----------------[ %s ]-->>", printCmds[printMode]);
} else {
r_cons_printf ("-[ functions ]----------------- %s ---", printCmds[printMode]);
}
if (color) {
r_cons_strcat ("\n" Color_RESET);
}
2019-07-24 22:40:10 +05:30
r_core_vmenu_append_help (buf, help_fun_visual);
r_cons_printf ("%s", r_strbuf_drain (buf));
addr = var_functions_show (core, option, 1, cols);
break;
case 1:
2019-07-24 22:40:10 +05:30
buf = r_strbuf_new ("");
if (color) {
r_cons_strcat (core->cons->context->pal.prompt);
}
r_cons_printf ("-[ variables ]----- 0x%08"PFMT64x"", addr);
if (color) {
r_cons_strcat ("\n" Color_RESET);
}
r_core_vmenu_append_help (buf, help_var_visual);
2020-01-17 12:58:29 +08:00
char *drained = r_strbuf_drain (buf);
r_cons_printf ("%s", drained);
addr = var_variables_show (core, option, &variable_option, 1, cols);
2020-01-17 12:58:29 +08:00
free (drained);
// var_index_show (core->anal, fcn, addr, option);
break;
case 2:
2014-08-23 02:27:31 +02:00
r_cons_printf ("Press 'q' to quit call refs\n");
2019-07-24 22:40:10 +05:30
if (color) {
r_cons_strcat (core->cons->context->pal.prompt);
}
r_cons_printf ("-[ calls ]----------------------- 0x%08"PFMT64x" (TODO)\n", addr);
2019-07-24 22:40:10 +05:30
if (color) {
r_cons_strcat ("\n" Color_RESET);
}
2014-08-23 02:27:31 +02:00
// TODO: filter only the callrefs. but we cant grep here
sprintf (old, "afi @ 0x%08"PFMT64x, addr);
char *output = r_core_cmd_str (core, old);
if (output) {
// 'h - 2' because we have two new lines in r_cons_printf
if (!r_cons_singleton ()->show_vals) {
char *out = r_str_ansi_crop(output, 0, 0, cols, h - 2);
r_cons_printf ("\n%s\n", out);
free (out);
R_FREE (output);
} else {
r_cons_printf ("\n%s\n", output);
R_FREE (output);
}
}
break;
default:
// assert
break;
}
r_cons_flush ();
return addr;
}
static void r_core_visual_anal_refresh_oneshot(RCore *core) {
2019-11-26 08:52:17 +01:00
r_core_task_enqueue_oneshot (&core->tasks, (RCoreTaskOneShot) r_core_visual_anal_refresh, core);
2018-07-09 21:26:38 +02:00
}
static void r_core_visual_debugtraces_help(RCore *core) {
r_cons_clear00 ();
r_cons_printf (
"vbd: Visual Browse Debugtraces:\n\n"
" q - quit the bit editor\n"
" Q - Quit (jump into the disasm view)\n"
" j/k - Select next/previous trace\n"
" : - enter command\n");
r_cons_flush ();
r_cons_any_key (NULL);
}
R_API void r_core_visual_debugtraces(RCore *core, const char *input) {
int i, delta = 0;
for (;;) {
char *trace_addr_str = r_core_cmd_strf (core, "dtdq %d", delta);
ut64 trace_addr = r_num_get (NULL, trace_addr_str);
free (trace_addr_str);
r_cons_printf ("[0x%08"PFMT64x"]> %d dbg.trace\n", trace_addr, delta);
for (i = 0; i < delta; i++) {
r_core_cmdf (core, ".dte %d", i);
}
r_core_cmd0 (core, "x 64@r:SP");
r_core_cmd0 (core, "dri");
// limit by rows here
//int rows = r_cons_get_size (NULL);
r_core_cmdf (core, "dtd %d", delta);
r_cons_visual_flush ();
signed char ch;
if (input && *input) {
ch = *input;
input++;
} else {
ch = r_cons_readchar ();
}
2021-08-19 18:26:22 +02:00
if (ch == 4 || (int)ch == -1) {
if (level == 0) {
goto beach;
}
level--;
continue;
}
ch = r_cons_arrow_to_hjkl (ch); // get ESC+char, return 'hjkl' char
switch (ch) {
case 'Q': // tab
{
ut64 oseek = core->offset;
core->vmode = false;
r_core_seek (core, trace_addr, true);
r_core_visual (core, "");
r_core_seek (core, oseek, true);
}
break;
case 'q':
goto beach;
break;
case ']':
r_config_set_i (core->config, "hex.cols", r_config_get_i (core->config, "hex.cols") + 1);
break;
case '[':
r_config_set_i (core->config, "hex.cols", r_config_get_i (core->config, "hex.cols") - 1);
break;
case 'J':
delta += 10;
break;
case 'K':
delta -= 10;
if (delta < 0) {
delta = 0;
}
case 'j':
delta++;
break;
case 'k':
delta--;
if (delta < 0) {
delta = 0;
}
break;
case ':':
r_core_visual_prompt (core);
r_cons_any_key (NULL);
break;
case '?':
r_core_visual_debugtraces_help (core);
break;
}
}
beach:
;
}
static char *__prompt(const char *msg, void *p) {
char res[128];
r_cons_show_cursor (true);
r_cons_set_raw (false);
r_line_set_prompt (msg);
res[0] =0;
if (!r_cons_fgets (res, sizeof (res), 0, NULL)) {
res[0] = 0;
}
return strdup (res);
}
static void addVar(RCore *core, int ch, const char *msg) {
char *src = __prompt (msg, NULL);
char *name = __prompt ("Variable Name: ", NULL);
char *type = __prompt ("Type of Variable (int32_t): ", NULL);
char *cmd = r_str_newf ("afv%c %s %s %s", ch, src, name, type);
r_str_trim (cmd);
r_core_cmd0 (core, cmd);
free(cmd);
free (src);
free (name);
free (type);
}
/* Like emenu but for real */
2018-11-25 01:23:33 +01:00
R_API void r_core_visual_anal(RCore *core, const char *input) {
char old[218];
int nfcns, ch, _option = 0;
2018-07-09 21:26:38 +02:00
RConsEvent olde = core->cons->event_resize;
2018-07-09 21:26:38 +02:00
void *olde_user = core->cons->event_data;
ut64 addr = core->offset;
2018-07-09 21:26:38 +02:00
core->cons->event_resize = NULL; // avoid running old event with new data
core->cons->event_data = core;
core->cons->event_resize = (RConsEvent) r_core_visual_anal_refresh_oneshot;
level = 0;
2014-08-23 02:27:31 +02:00
int asmbytes = r_config_get_i (core->config, "asm.bytes");
r_config_set_i (core->config, "asm.bytes", 0);
for (;;) {
nfcns = r_list_length (core->anal->fcns);
addr = r_core_visual_anal_refresh (core);
2018-11-25 01:23:33 +01:00
if (input && *input) {
ch = *input;
input++;
} else {
ch = r_cons_readchar ();
}
if (ch == 4 || ch == -1) {
if (level == 0) {
2014-02-08 12:09:12 +01:00
goto beach;
}
2014-02-08 12:09:12 +01:00
level--;
continue;
}
ch = r_cons_arrow_to_hjkl (ch); // get ESC+char, return 'hjkl' char
switch (ch) {
case '[':
r_cons_singleton ()->show_vals = true;
break;
case ']':
r_cons_singleton ()->show_vals = false;
break;
case '?':
r_cons_clear00 ();
Fix wording and whitespacing ##doc (#18065) * Fix wording, whitespacing and other minor stuff * cmd.c: ellaborated yy syntax, improved descriptions - replace "srcoff" with "origin" * cmd.c(cmd_autocomplete): - refactor help into function: render autocomplete types with generic help subsystem; - "Types" heading now follow the "Usage" style by not being prefixed by a pipe character; * cmd_anal.c: fix whitespaces & help text * cmd_info.c: fix help text capitalization. * cmd_print.c: - fix `pf` cmd help; - TODO: what pz? is doing here? * cons.c: - refactor & better document r_cons_cmd_help(); - fix whitespaces; * visual & panels modes: - as of commit 46187fe4e14dc465dc6ac03fcc56a362f0b8e335, '!' no longer launches the r2048 game. The game itself it broken anyway, even when running from the Help menu in panels mode; - transitioning from panels to visual is not 'entering' but actually swapping/replacing visual panels with just panels, thus... - reword 'enter into the' to 'swap into' or even just 'enter', e.g.: "enter into the visual panels mode" -> "enter visual panels mode". - remove the "(dwm style)" words from a fortune tip, because I have no idea what it is, and it does not appear to be a valid command in any of the r2 modes. - update global help text. * [WIP 2] Fix wording, whitespacing and other minor stuff * visual.c: - r_core_visual_append_help(): first steps merging with r_cons_cmd_help from cons.c; use consistent colors for headers. * [WIP 3] Fix wording, whitespacing and other minor stuff * panels.c(__update_help): - shorten code and titles; - add comment to clarify that it is not a copy-paste error; * [WIP 4] Fix wording, whitespacing and other minor stuff panels.c, visual.c: tweak help text; * [WIP 5] Fix wording, whitespacing and other minor stuff * cmd_help.c: update global help text about visual mode -- it was outdated and overloaded. * vmenus.c: - rename stuff, shuffle around static consts to reflect an actual ordering when viewing as a help text; - slightly improve help text rendering; - fix whitespaces; * [WIP 6] Fix wording, whitespacing and other minor stuff * lots of help text changed. still working on proper commit message.
2020-12-21 03:12:08 +03:00
RStrBuf *rsb = r_strbuf_new ("");
r_core_visual_append_help (rsb, "Functions/Variables Visual Analysis Mode (Vv) Help", (const char *[]){ NULL });
r_core_visual_append_help (rsb, "Actions Supported", help_visual_anal_actions);
r_core_visual_append_help (rsb, "Keys", help_visual_anal_keys);
r_cons_less_str (r_strbuf_get (rsb), "?");
r_strbuf_free (rsb);
break;
case 9:
selectPanel = !selectPanel;
if (!selectPanel) {
delta = 0;
printMode = 0;
}
break;
case ':':
{
ut64 orig = core->offset;
r_core_seek (core, addr, false);
while (r_core_visual_prompt (core));
r_core_seek (core, orig, false);
}
continue;
case '/':
r_core_cmd0 (core, "?i highlight;e scr.highlight=`yp`");
break;
case 'a':
switch (level) {
case 0:
r_core_cmd0 (core, "af-$$;af"); // reanalize
break;
case 1:
{
eprintf ("Select variable source ('r'egister, 's'tackptr or 'b'aseptr): ");
int type = r_cons_readchar ();
switch (type) {
case 'r':
addVar (core, type, "Source Register Name: ");
break;
case 's':
addVar (core, type, "BP Relative Delta: ");
break;
case 'b':
addVar (core, type, "SP Relative Delta: ");
break;
}
}
break;
}
break;
2016-09-15 13:00:27 +02:00
case 'r':
{
switch (level) {
case 1:
r_cons_show_cursor (true);
r_cons_set_raw (false);
r_line_set_prompt ("New name: ");
if (r_cons_fgets (old, sizeof (old), 0, NULL)) {
if (*old) {
//old[strlen (old)-1] = 0;
variable_rename (core, addr, variable_option, old);
}
}
break;
default:
r_line_set_prompt ("New name: ");
if (r_cons_fgets (old, sizeof (old), 0, NULL)) {
if (*old) {
//old[strlen (old)-1] = 0;
function_rename (core, addr, old);
}
}
break;
2016-11-05 01:18:32 +01:00
}
r_cons_set_raw (true);
r_cons_show_cursor (false);
2016-11-05 01:18:32 +01:00
}
break;
case 't':
if (level == 1) {
r_cons_show_cursor (true);
r_cons_set_raw (false);
r_line_set_prompt ("New type: ");
if (r_cons_fgets (old, sizeof (old), 0, NULL)) {
if (*old) {
//old[strlen (old)-1] = 0;
variable_set_type (core, addr, variable_option, old);
}
}
r_cons_set_raw (true);
r_cons_show_cursor (false);
}
break;
case '.':
delta = 0;
break;
case 'R':
r_core_cmd0 (core, "ecn");
break;
case 'p':
printMode ++;
break;
case 'P':
if (printMode == 0) {
printMode = lastPrintMode;
} else {
printMode --;
}
break;
case 'd':
r_core_visual_define(core, "", 0);
break;
case '-':
switch (level) {
case 0:
r_core_cmdf (core, "af-0x%"PFMT64x, addr);
break;
}
break;
case 'x':
r_core_visual_refs (core, false, true);
break;
case 'X':
r_core_visual_refs (core, true, true);
break;
case 's':
r_core_cmdf (core, "afs!@0x%08"PFMT64x, addr);
break;
case 'c':
level = 2;
break;
case 'v':
level = 1;
variable_option = 0;
break;
case '_':
{
r_core_cmd0 (core, "s $(afl~...)");
int n = 0;
RListIter *iter;
RAnalFunction *fcn;
r_list_foreach (core->anal->fcns, iter, fcn) {
if (fcn->addr == core->offset) {
option = n;
break;
}
n ++;
}
}
break;
case 'j':
if (selectPanel) {
printMode = 1;
delta += 16;
} else {
delta = 0;
switch (level) {
case 1:
variable_option++;
break;
default:
option++;
if (option >= nfcns) {
option--;
}
break;
}
}
break;
case '!':
// TODO: use aflsn/aflsb/aflss/...
{
static int sortMode = 0;
const char *sortModes[4] = { "aflsa", "aflss", "aflsb", "aflsn" };
r_core_cmd0 (core, sortModes[sortMode%4]);
sortMode++;
}
break;
case 'k':
if (selectPanel) {
printMode = 1;
delta -= 16;
} else {
delta = 0;
switch (level) {
case 1:
variable_option = (variable_option<=0)? 0: variable_option-1;
break;
default:
option = (option<=0)? 0: option-1;
break;
}
}
break;
case 'J':
if (selectPanel) {
printMode = 1;
delta += 40;
} else {
int rows = 0;
r_cons_get_size (&rows);
option += (rows - 5);
if (option >= nfcns) {
option = nfcns - 1;
}
}
break;
case 'K':
if (selectPanel) {
printMode = 1;
delta -= 40;
} else {
int rows = 0;
r_cons_get_size (&rows);
option -= (rows - 5);
if (option < 0) {
option = 0;
}
}
break;
case 'g':
{
r_core_visual_showcursor (core, true);
r_core_visual_offset (core); // change the seek to selected offset
RListIter *iter; // change the current option to selected seek
RAnalFunction *fcn;
int i = 0;
r_list_foreach (core->anal->fcns, iter, fcn) {
if (core->offset == fcn->addr){
option = i;
}
i++;
}
r_core_visual_showcursor (core, false);
}
break;
case 'G':
r_core_seek (core, addr, SEEK_SET);
goto beach;
case ' ':
case '\r':
case '\n':
level = 0;
r_core_seek (core, addr, SEEK_SET);
goto beach;
case 'l':
level = 1;
_option = option;
break;
case 'h':
case 'b': // back
level = 0;
option = _option;
break;
case 'Q':
case 'q':
if (level == 0) {
goto beach;
}
level--;
break;
}
}
beach:
2018-07-09 21:26:38 +02:00
core->cons->event_resize = NULL; // avoid running old event with new data
core->cons->event_data = olde_user;
core->cons->event_resize = olde;
level = 0;
2014-08-23 02:27:31 +02:00
r_config_set_i (core->config, "asm.bytes", asmbytes);
}
struct seek_flag_offset_t {
ut64 offset;
ut64 *next;
bool is_next;
};
static bool seek_flag_offset(RFlagItem *fi, void *user) {
struct seek_flag_offset_t *u = (struct seek_flag_offset_t *)user;
if (u->is_next) {
if (fi->offset < *u->next && fi->offset > u->offset) {
*u->next = fi->offset;
}
} else {
if (fi->offset > *u->next && fi->offset < u->offset) {
*u->next = fi->offset;
}
}
return true;
}
R_API void r_core_seek_next(RCore *core, const char *type) {
RListIter *iter;
ut64 next = UT64_MAX;
if (strstr (type, "opc")) {
RAnalOp aop;
if (r_anal_op (core->anal, &aop, core->offset, core->block, core->blocksize, R_ANAL_OP_MASK_BASIC)) {
2013-12-06 05:18:57 +01:00
next = core->offset + aop.size;
} else {
eprintf ("Invalid opcode\n");
}
} else if (strstr (type, "fun")) {
RAnalFunction *fcni;
r_list_foreach (core->anal->fcns, iter, fcni) {
if (fcni->addr < next && fcni->addr > core->offset) {
next = fcni->addr;
}
}
} else if (strstr (type, "hit")) {
const char *pfx = r_config_get (core->config, "search.prefix");
struct seek_flag_offset_t u = { .offset = core->offset, .next = &next, .is_next = true };
r_flag_foreach_prefix (core->flags, pfx, -1, seek_flag_offset, &u);
} else { // flags
struct seek_flag_offset_t u = { .offset = core->offset, .next = &next, .is_next = true };
r_flag_foreach (core->flags, seek_flag_offset, &u);
}
if (next != UT64_MAX) {
r_core_seek (core, next, true);
}
}
R_API void r_core_seek_previous(RCore *core, const char *type) {
RListIter *iter;
ut64 next = 0;
if (strstr (type, "opc")) {
eprintf ("TODO: r_core_seek_previous (opc)\n");
} else
if (strstr (type, "fun")) {
RAnalFunction *fcni;
r_list_foreach (core->anal->fcns, iter, fcni) {
if (fcni->addr > next && fcni->addr < core->offset) {
next = fcni->addr;
}
}
} else
if (strstr (type, "hit")) {
const char *pfx = r_config_get (core->config, "search.prefix");
struct seek_flag_offset_t u = { .offset = core->offset, .next = &next, .is_next = false };
r_flag_foreach_prefix (core->flags, pfx, -1, seek_flag_offset, &u);
} else { // flags
struct seek_flag_offset_t u = { .offset = core->offset, .next = &next, .is_next = false };
r_flag_foreach (core->flags, seek_flag_offset, &u);
}
if (next != 0) {
r_core_seek (core, next, true);
}
}
// define the data at offset according to the type (byte, word...) n times
static void define_data_ntimes(RCore *core, ut64 off, int times, int type, int typesize) {
int i = 0;
if (times < 1) {
times = 1;
}
2022-03-15 15:22:25 +01:00
ut64 amount = ((ut64)typesize) * times;
r_meta_del (core->anal, R_META_TYPE_ANY, off, amount);
for (i = 0; i < times; i++, off += typesize) {
2020-05-09 20:49:28 +02:00
r_meta_set (core->anal, R_META_TYPE_DATA, off, type, "");
}
}
static bool isDisasmPrint(int mode) {
return (mode == 1 || mode == 2);
}
static void handleHints(RCore *core) {
//TODO extend for more anal hints
int i = 0;
2022-03-11 19:48:37 -06:00
char ch[64] = {0};
const char *lines[] = {"[dh]- Define anal hint:"
," b [16,32,64] set bits hint"
, NULL};
for (i = 0; lines[i]; i++) {
r_cons_fill_line ();
r_cons_printf ("\r%s\n", lines[i]);
}
r_cons_flush ();
r_line_set_prompt ("anal hint: ");
2020-02-29 22:47:10 +03:00
if (r_cons_fgets (ch, sizeof (ch), 0, NULL) > 0) {
switch (ch[0]) {
case 'b':
{
char *arg = ch + 1;
r_str_trim (arg);
int bits = atoi (arg);
if (bits == 8 || bits == 16 || bits == 32 || bits == 64) {
r_anal_hint_set_bits (core->anal, core->offset, bits);
}
}
break;
default:
break;
}
}
}
R_API void r_core_visual_define(RCore *core, const char *args, int distance) {
int plen = core->blocksize;
2013-06-28 11:58:30 +02:00
ut64 off = core->offset;
int i, h = 0, n, ch, ntotal = 0;
2013-06-28 11:58:30 +02:00
ut8 *p = core->block;
2016-02-11 11:11:45 +01:00
int rep = -1;
2013-06-28 11:58:30 +02:00
char *name;
int delta = 0;
if (core->print->cur_enabled) {
int cur = core->print->cur;
if (core->print->ocur != -1) {
2019-08-29 16:17:12 +02:00
plen = R_ABS (core->print->cur - core->print->ocur) + 1;
if (core->print->ocur<cur) {
cur = core->print->ocur;
}
}
2013-06-28 11:58:30 +02:00
off += cur;
p += cur;
}
(void) r_cons_get_size (&h);
h -= 19;
if (h < 0) {
h = 0;
r_cons_clear00 ();
} else {
2018-05-10 10:51:35 +02:00
r_cons_gotoxy (0, 3);
2014-09-08 01:33:50 +02:00
}
const char *lines[] = { ""
,"[Vd]- Define current block as:"
," $ define flag size"
," 1 edit bits"
2019-07-02 04:02:17 +02:00
," a assembly"
2019-08-29 16:17:12 +02:00
," b as byte (1 byte)"
," B define half word (16 bit, 2 byte size)"
," c as code (unset any data / string / format) in here"
2014-09-08 01:33:50 +02:00
," C define flag color (fc)"
," d set as data"
," e end of function"
," f analyze function"
," F format"
2019-08-29 16:17:12 +02:00
," h define hint (for half-word, see 'B')"
," i (ahi) immediate base (b(in), o(ct), d(ec), h(ex), s(tr))"
," I (ahi1) immediate base (b(in), o(ct), d(ec), h(ex), s(tr))"
," j merge down (join this and next functions)"
," k merge up (join this and previous function)"
," h define anal hint"
," m manpage for current call"
," n rename flag or variable referenced by the instruction in cursor"
," N edit function signature (afs!)"
," o opcode string"
2014-09-08 01:33:50 +02:00
," r rename function"
," s set string"
," S set strings in current block"
," t set opcode type via aht hints (call, nop, jump, ...)"
2014-09-08 01:33:50 +02:00
," u undefine metadata here"
," v rename variable at offset that matches some hex digits"
2016-02-16 01:21:36 +01:00
," x find xrefs to current address (./r)"
," X find cross references /r"
2014-09-08 01:33:50 +02:00
," w set as 32bit word"
," W set as 64bit word"
," q quit menu"
2016-10-06 02:40:26 +02:00
," z zone flag"
2014-09-08 01:33:50 +02:00
, NULL};
for (i = 0; lines[i]; i++) {
r_cons_fill_line ();
r_cons_printf ("\r%s\n", lines[i]);
2014-09-08 01:33:50 +02:00
}
r_cons_flush ();
2018-12-15 12:39:09 +01:00
int wordsize = 0;
// get ESC+char, return 'hjkl' char
2016-02-11 11:11:45 +01:00
repeat:
if (*args) {
ch = *args;
args++;
} else {
ch = r_cons_arrow_to_hjkl (r_cons_readchar ());
}
onemoretime:
2018-12-15 12:39:09 +01:00
wordsize = 4;
switch (ch) {
case 'N':
r_core_cmdf (core, "afs! @ 0x%08"PFMT64x, off);
break;
case 'F':
{
char cmd[128];
2015-09-14 12:35:38 +02:00
r_cons_show_cursor (true);
r_core_cmd0 (core, "pf?");
r_cons_flush ();
r_line_set_prompt ("format: ");
strcpy (cmd, "Cf 0 ");
2020-02-29 22:47:10 +03:00
if (r_cons_fgets (cmd + 5, sizeof (cmd) - 5, 0, NULL) > 0) {
r_core_cmdf (core, "%s @ 0x%08"PFMT64x, cmd, off);
r_cons_set_raw (1);
2015-09-14 12:35:38 +02:00
r_cons_show_cursor (false);
}
}
break;
case '1':
r_core_visual_bit_editor (core);
break;
case 't':
case 'o':
{
char str[128];
r_cons_show_cursor (true);
r_line_set_prompt (ch=='t'?"type: ": "opstr: ");
if (r_cons_fgets (str, sizeof (str), 0, NULL) > 0) {
r_core_cmdf (core, "ah%c %s @ 0x%"PFMT64x, ch, str, off);
}
}
break;
2016-02-16 01:21:36 +01:00
case 'x':
2017-12-16 02:01:28 +01:00
r_core_cmd0 (core, "/r $$");
2016-02-16 01:21:36 +01:00
break;
case 'i':
{
char str[128];
r_cons_show_cursor (true);
r_line_set_prompt ("immbase: ");
if (r_cons_fgets (str, sizeof (str), 0, NULL) > 0) {
r_core_cmdf (core, "ahi %s @ 0x%"PFMT64x, str, off);
}
}
break;
case 'I':
{
char str[128];
r_cons_show_cursor (true);
r_line_set_prompt ("immbase: ");
if (r_cons_fgets (str, sizeof (str), 0, NULL) > 0) {
r_core_cmdf (core, "ahi1 %s @ 0x%"PFMT64x, str, off);
}
}
break;
2019-07-02 04:02:17 +02:00
case 'a':
r_core_visual_asm (core, off);
break;
case 'b':
if (plen != core->blocksize) {
rep = plen / 2;
}
2018-12-15 12:39:09 +01:00
wordsize = 1;
define_data_ntimes (core, off, rep, R_BYTE_DATA, wordsize);
break;
2019-08-29 16:17:12 +02:00
case 'B': // "VdB"
if (plen != core->blocksize) {
2019-08-29 16:17:12 +02:00
rep = plen / 2;
}
2018-12-15 12:39:09 +01:00
wordsize = 2;
define_data_ntimes (core, off, rep, R_WORD_DATA, wordsize);
break;
case 'w':
if (plen != core->blocksize) {
rep = plen / 4;
}
2018-12-15 12:39:09 +01:00
wordsize = 4;
define_data_ntimes (core, off, rep, R_DWORD_DATA, wordsize);
break;
case 'W':
if (plen != core->blocksize) {
rep = plen / 8;
}
2018-12-15 12:39:09 +01:00
wordsize = 8;
define_data_ntimes (core, off, rep, R_QWORD_DATA, wordsize);
break;
case 'm':
{
char *man = NULL;
/* check for manpage */
2018-06-08 00:02:00 +05:30
RAnalOp *op = r_core_anal_op (core, off, R_ANAL_OP_MASK_BASIC);
if (op) {
if (op->jump != UT64_MAX) {
RFlagItem *item = r_flag_get_i (core->flags, op->jump);
if (item) {
const char *ptr = r_str_lchr (item->name, '.');
if (ptr) {
man = strdup (ptr + 1);
}
}
}
r_anal_op_free (op);
}
if (man) {
char *p = strstr (man, "INODE");
if (p) {
*p = 0;
}
r_cons_clear ();
r_cons_flush ();
r_sys_cmdf ("man %s", man);
free (man);
}
r_cons_any_key (NULL);
}
break;
case 'n':
{
RAnalOp op;
char *q = NULL;
ut64 tgt_addr = UT64_MAX;
if (!isDisasmPrint (core->printidx)) {
break;
}
// TODO: get the aligned instruction even if the cursor is in the middle of it.
int rc = r_anal_op (core->anal, &op, off,
core->block + off - core->offset, 32, R_ANAL_OP_MASK_BASIC);
if (rc < 1) {
eprintf ("Error analyzing opcode at 0x%08"PFMT64x"\n", off);
} else {
tgt_addr = op.jump != UT64_MAX ? op.jump : op.ptr;
RAnalVar *var = r_anal_get_used_function_var (core->anal, op.addr);
if (var) {
// q = r_str_newf ("?i Rename variable %s to;afvn %s `yp`", op.var->name, op.var->name);
r_strf_var (prompt, 128, "New variable name for '%s': ", var->name);
char *newname = r_cons_input (prompt);
if (newname && *newname) {
r_anal_var_rename (var, newname, true);
free (newname);
}
} else if (tgt_addr != UT64_MAX) {
RAnalFunction *fcn = r_anal_get_function_at (core->anal, tgt_addr);
RFlagItem *f = r_flag_get_i (core->flags, tgt_addr);
if (fcn) {
q = r_str_newf ("?i Rename function %s to;afn `yp` 0x%"PFMT64x,
fcn->name, tgt_addr);
} else if (f) {
q = r_str_newf ("?i Rename flag %s to;fr %s `yp`",
f->name, f->name);
} else {
q = r_str_newf ("?i Create flag at 0x%"PFMT64x" named;f `yp` @ 0x%"PFMT64x,
tgt_addr, tgt_addr);
}
}
}
if (q) {
r_core_cmd0 (core, q);
free (q);
} else {
eprintf ("Sorry. No flags or variables referenced here\n");
r_cons_any_key (NULL);
}
r_anal_op_fini (&op);
break;
}
2014-09-08 01:33:50 +02:00
case 'C':
{
RFlagItem *item = r_flag_get_i (core->flags, off);
if (item) {
char cmd[128];
2015-09-14 12:35:38 +02:00
r_cons_show_cursor (true);
2014-09-08 01:33:50 +02:00
r_cons_flush ();
r_line_set_prompt ("color: ");
2020-02-29 22:47:10 +03:00
if (r_cons_fgets (cmd, sizeof (cmd), 0, NULL) > 0) {
r_flag_item_set_color (item, cmd);
2014-09-08 01:33:50 +02:00
r_cons_set_raw (1);
2015-09-14 12:35:38 +02:00
r_cons_show_cursor (false);
2014-09-08 01:33:50 +02:00
}
} else {
eprintf ("Sorry. No flag here\n");
r_cons_any_key (NULL);
2014-09-08 01:33:50 +02:00
}
}
break;
case '$':
{
RFlagItem *item = r_flag_get_i (core->flags, off);
if (item) {
char cmd[128];
2020-10-21 17:27:17 +08:00
r_cons_printf ("Current flag size is: %" PFMT64d "\n", item->size);
2015-09-14 12:35:38 +02:00
r_cons_show_cursor (true);
2014-09-08 01:33:50 +02:00
r_cons_flush ();
r_line_set_prompt ("new size: ");
2020-02-29 22:47:10 +03:00
if (r_cons_fgets (cmd, sizeof (cmd), 0, NULL) > 0) {
2014-09-08 01:33:50 +02:00
item->size = r_num_math (core->num, cmd);
r_cons_set_raw (1);
2015-09-14 12:35:38 +02:00
r_cons_show_cursor (false);
2014-09-08 01:33:50 +02:00
}
} else {
eprintf ("Sorry. No flag here\n");
r_cons_any_key (NULL);
2014-09-08 01:33:50 +02:00
}
}
break;
case 'e':
// set function size
{
RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, off, 0);
if (!fcn) {
fcn = r_anal_get_fcn_in (core->anal, core->offset, 0);
}
if (fcn) {
RAnalOp op;
ut64 size;
if (r_anal_op (core->anal, &op, off, core->block+delta,
core->blocksize-delta, R_ANAL_OP_MASK_BASIC)) {
size = off - fcn->addr + op.size;
r_anal_function_resize (fcn, size);
}
}
}
break;
case 'j':
r_core_cmdf (core, "afm $$+$F @0x%08"PFMT64x, off);
break;
case 'k':
eprintf ("TODO: merge up\n");
r_cons_any_key (NULL);
break;
2019-08-29 16:17:12 +02:00
// very weak and incomplete
2014-10-22 01:01:38 +02:00
case 'h': // "Vdh"
handleHints (core);
break;
2014-10-22 01:01:38 +02:00
case 'r': // "Vdr"
r_core_cmdf (core, "?i new function name;afn `yp` @ 0x%08"PFMT64x, off);
break;
2016-10-06 02:40:26 +02:00
case 'z': // "Vdz"
r_core_cmdf (core, "?i zone name;fz `yp` @ 0x%08"PFMT64x, off);
2016-10-06 02:40:26 +02:00
break;
case 'X': // "VdX"
eprintf ("Finding cross-references to 0x%08"PFMT64x" ...\n", off);
r_core_cmdf (core, "./r 0x%08"PFMT64x" @ $S", off);
2015-02-09 03:21:47 +01:00
break;
2011-06-09 02:29:24 +02:00
case 'S':
{
int i, j;
bool is_wide = false;
2011-06-09 02:29:24 +02:00
do {
n = r_str_nlen_w ((const char *)p + ntotal,
plen - ntotal) + 1;
if (n < 2) {
break;
}
name = malloc (n + 10);
2011-09-18 20:41:36 +02:00
strcpy (name, "str.");
for (i = 0, j = 0; i < n; i++, j++) {
name[4 + i] = p[j + ntotal];
if (!p[j + ntotal]) {
break;
}
if (!p[j + 1 + ntotal]) {
//check if is still wide
if (j + 3 + ntotal < n) {
if (p[j + 3]) {
break;
}
}
is_wide = true;
j++;
}
}
name[4 + n] = '\0';
if (is_wide) {
2020-05-09 20:49:28 +02:00
r_meta_set (core->anal, R_META_TYPE_STRING,
off + ntotal, (n * 2) + ntotal,
(const char *) name + 4);
} else {
2020-05-09 20:49:28 +02:00
r_meta_set (core->anal, R_META_TYPE_STRING,
off + ntotal, n + ntotal,
(const char *) name + 4);
}
r_name_filter (name, n + 10);
2018-02-09 13:59:27 +01:00
r_flag_set (core->flags, name, off + ntotal, n);
2011-06-09 02:29:24 +02:00
free (name);
if (is_wide) {
ntotal += n * 2 - 1;
} else {
ntotal += n;
}
} while (ntotal < plen);
2018-12-15 12:39:09 +01:00
wordsize = ntotal;
}
2011-06-09 02:29:24 +02:00
break;
case 's':
{
int i, j;
2016-11-10 11:43:07 +01:00
bool is_wide = false;
if (core->print->ocur != -1) {
n = plen;
} else {
n = r_str_nlen_w ((const char*)p, plen) + 1;
}
name = malloc (n + 10);
if (!name) {
break;
}
strcpy (name, "str.");
for (i = 0, j = 0; i < n; i++, j++) {
name[4 + i] = p[j];
if (!p[j + 1]) {
break;
}
if (!p[j + 1]) {
if (j + 3 < n) {
if (p[j + 3]) {
break;
}
}
is_wide = true;
j++;
}
}
name[4 + n] = '\0';
//handle wide strings
//memcpy (name + 4, (const char *)p, n);
if (is_wide) {
2020-05-09 20:49:28 +02:00
r_meta_set (core->anal, R_META_TYPE_STRING, off,
n * 2, (const char *) name + 4);
} else {
2020-05-09 20:49:28 +02:00
r_meta_set (core->anal, R_META_TYPE_STRING, off,
n, (const char *) name + 4);
}
r_name_filter (name, n + 10);
r_flag_set (core->flags, name, off, n);
2018-12-15 12:39:09 +01:00
wordsize = n;
free (name);
}
break;
case 'd': // TODO: check
2020-05-09 20:49:28 +02:00
r_meta_del (core->anal, R_META_TYPE_ANY, off, plen);
r_meta_set (core->anal, R_META_TYPE_DATA, off, plen, "");
break;
case 'c': // TODO: check
2020-05-09 20:49:28 +02:00
r_meta_del (core->anal, R_META_TYPE_ANY, off, plen);
r_meta_set (core->anal, R_META_TYPE_CODE, off, plen, "");
break;
case 'u':
r_core_anal_undefine (core, off);
break;
case 'f':
{
2014-09-26 18:10:33 +02:00
RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset, 0);
2016-09-16 11:31:30 +02:00
if (fcn) {
r_anal_function_resize (fcn, core->offset - fcn->addr);
2016-09-16 11:31:30 +02:00
}
r_cons_break_push (NULL, NULL);
2016-09-16 11:31:30 +02:00
r_core_cmdf (core, "af @ 0x%08" PFMT64x, off); // required for thumb autodetection
r_cons_break_pop ();
}
break;
2019-12-31 01:21:33 +01:00
case 'v':
{
ut64 N;
2018-06-11 11:48:22 +02:00
char *endptr = NULL;
char *end_off = r_cons_input ("Last hexadecimal digits of instruction: ");
if (end_off) {
2018-06-11 11:48:22 +02:00
N = strtoull (end_off, &endptr, 16);
}
if (!end_off || end_off == endptr) {
eprintf ("Invalid numeric input\n");
r_cons_any_key (NULL);
2018-06-11 11:48:22 +02:00
free (end_off);
break;
}
free (end_off);
ut64 incr = 0x10;
ut64 tmp_N = N >> 4;
while (tmp_N > 0) {
tmp_N = tmp_N >> 4;
incr = incr << 4;
}
ut64 mask = incr - 1;
2019-12-31 01:21:33 +01:00
ut64 start_off = (off & ~mask) ^ N;
if ((off & mask) > N) {
if (start_off > incr) {
start_off -= incr;
} else {
start_off = N;
}
}
ut64 try_off;
2019-12-30 17:18:52 +01:00
RAnalOp *op = NULL;
RAnalVar *var = NULL;
2019-12-30 17:18:52 +01:00
for (try_off = start_off; try_off < start_off + incr*16; try_off += incr) {
r_anal_op_free (op);
op = r_core_anal_op (core, try_off, R_ANAL_OP_MASK_ALL);
if (!op) {
break;
}
var = r_anal_get_used_function_var (core->anal, op->addr);
if (var) {
break;
}
}
if (var) {
r_strf_var (promptstr, 128, "New variable name for '%s': ", var->name);
char *newname = r_cons_input (promptstr);
if (newname && *newname) {
r_anal_var_rename (var, newname, true);
free (newname);
}
} else {
eprintf ("Cannot find instruction with a variable\n");
r_cons_any_key (NULL);
}
2019-12-30 17:18:52 +01:00
r_anal_op_free (op);
break;
}
case 'Q':
case 'q':
default:
if (IS_DIGIT (ch)) {
if (rep < 0) {
rep = 0;
}
2016-02-11 11:11:45 +01:00
rep = rep * 10 + atoi ((char *)&ch);
goto repeat;
}
break;
}
if (distance > 0) {
distance--;
2018-12-15 12:39:09 +01:00
off += wordsize;
goto onemoretime;
}
}
R_API void r_core_visual_colors(RCore *core) {
char *color = calloc (1, 64), cstr[32];
char preview_cmd[128] = "pd $r";
int ch, opt = 0, oopt = -1;
bool truecolor = r_cons_singleton ()->context->color_mode == COLOR_MODE_16M;
char *rgb_xxx_fmt = truecolor ? "rgb:%2.2x%2.2x%2.2x ":"rgb:%x%x%x ";
const char *k;
RColor rcolor;
r_cons_show_cursor (false);
rcolor = r_cons_pal_get_i (opt);
for (;;) {
r_cons_clear ();
r_cons_gotoxy (0, 0);
k = r_cons_pal_get_name (opt);
if (!k) {
opt = 0;
k = r_cons_pal_get_name (opt);
}
if (!truecolor) {
rcolor.r &= 0xf;
rcolor.g &= 0xf;
rcolor.b &= 0xf;
rcolor.r2 &= 0xf;
rcolor.g2 &= 0xf;
rcolor.b2 &= 0xf;
} else {
rcolor.r &= 0xff;
rcolor.g &= 0xff;
rcolor.b &= 0xff;
rcolor.r2 &= 0xff;
rcolor.g2 &= 0xff;
rcolor.b2 &= 0xff;
}
sprintf (color, rgb_xxx_fmt, rcolor.r, rcolor.g, rcolor.b);
if (rcolor.r2 || rcolor.g2 || rcolor.b2) {
color = r_str_appendf (color, rgb_xxx_fmt, rcolor.r2, rcolor.g2, rcolor.b2);
rcolor.a = ALPHA_FGBG;
} else {
rcolor.a = ALPHA_FG;
}
r_cons_rgb_str (cstr, sizeof (cstr), &rcolor);
char *esc = strchr (cstr + 1, '\x1b');
char *curtheme = r_core_get_theme (core);
r_cons_printf ("# Use '.' to randomize current color and ':' to randomize palette\n");
r_cons_printf ("# Press '"Color_RED"rR"Color_GREEN"gG"Color_BLUE"bB"Color_RESET
"' or '"Color_BGRED"eE"Color_BGGREEN"fF"Color_BGBLUE"vV"Color_RESET
"' to change foreground/background color\n");
r_cons_printf ("# Export colorscheme with command 'ec* > filename'\n");
r_cons_printf ("# Preview command: '%s' - Press 'c' to change it\n", preview_cmd);
r_cons_printf ("# Theme (eco): %s - Use 'hl' or left/right arrow keys to change colorscheme\n", r_str_get_fail (curtheme, "default"));
r_cons_printf ("# Item (%s) - Use 'jk' or up/down arrow keys to change element\n", k);
r_cons_printf ("# ec %s %s # %d (\\x1b%.*s)",
2020-10-21 17:27:17 +08:00
k, color, atoi (cstr+7), esc ? (int)(esc - cstr - 1) : (int)strlen (cstr + 1), cstr+1);
if (esc) {
r_cons_printf (" (\\x1b%s)", esc + 1);
}
r_cons_newline ();
r_core_cmdf (core, "ec %s %s", k, color);
char * res = r_core_cmd_str (core, preview_cmd);
2017-07-31 11:33:39 +02:00
int h, w = r_cons_get_size (&h);
char *body = r_str_ansi_crop (res, 0, 0, w, h - 8);
2018-03-19 11:51:04 +01:00
if (body) {
r_cons_printf ("\n%s", body);
2018-03-19 11:51:04 +01:00
}
r_cons_flush ();
ch = r_cons_readchar ();
ch = r_cons_arrow_to_hjkl (ch);
switch (ch) {
#define CASE_RGB(x,X,y) \
case x:if ((y) > 0x00) { (y)--; } break;\
case X:if ((y) < 0xff) { (y)++; } break;
CASE_RGB ('R','r',rcolor.r);
CASE_RGB ('G','g',rcolor.g);
CASE_RGB ('B','b',rcolor.b);
CASE_RGB ('E','e',rcolor.r2);
CASE_RGB ('F','f',rcolor.g2);
CASE_RGB ('V','v',rcolor.b2);
case 'Q':
2018-06-09 18:27:53 -07:00
case 'q':
2018-03-19 11:51:04 +01:00
free (body);
free (color);
2018-03-19 11:51:04 +01:00
return;
2018-06-09 18:27:53 -07:00
case 'k':
opt--;
break;
case 'j':
opt++;
break;
case 'l':
r_core_cmd0 (core, "ecn");
oopt = -1;
break;
case 'h':
r_core_cmd0 (core, "ecp");
oopt = -1;
break;
2018-06-09 18:27:53 -07:00
case 'K':
opt = 0;
break;
case 'J':
opt = r_cons_pal_len () - 1;
break;
case ':':
r_core_visual_prompt_input (core);
break;
case ',':
2018-06-09 18:27:53 -07:00
r_cons_pal_random ();
break;
case '.':
rcolor.r = r_num_rand (0xff);
rcolor.g = r_num_rand (0xff);
rcolor.b = r_num_rand (0xff);
break;
case 'c':
r_line_set_prompt ("Preview command> ");
r_cons_show_cursor (true);
{
char newcmd[128] = {0};
r_cons_fgets (newcmd, sizeof (newcmd), 0, NULL);
if (*newcmd) {
r_str_ncpy (preview_cmd, newcmd, sizeof (preview_cmd) - 1);
}
}
r_cons_show_cursor (false);
}
if (opt != oopt) {
rcolor = r_cons_pal_get_i (opt);
oopt = opt;
}
2018-06-17 05:42:40 +09:00
free (body);
}
}