radare2/libr/core/vmenus.c
pancake 062deb4b69 Fix build. enhace mips anal, add recursive disasm
Fix UCALL opcode analysis in mips
Initial implementation of 'pdr' recursive disassembler
Workaround for code wrong basic block size in pdr
2012-08-29 14:46:19 +02:00

1263 lines
30 KiB
C

/* radare - LGPL - Copyright 2009-2012 pancake<nopcode.org> */
#include "r_core.h"
R_API int r_core_visual_trackflags(RCore *core) {
char cmd[1024];
RListIter *iter;
RFlagItem *flag;
#define MAX_FORMAT 2
int format = 0;
const char *fs = NULL;
char *fs2 = NULL;
int option = 0;
int _option = 0;
int delta = 7;
int menu = 0;
int hit, i, j, ch;
for (;;) {
r_cons_gotoxy (0, 0);
r_cons_clear ();
if (menu) {
r_cons_printf ("Flags in flagspace '%s'. Press '?' for help.\n\n",
(core->flags->space_idx==-1)?"*":core->flags->spaces[core->flags->space_idx]);
hit = 0;
i = j = 0;
r_list_foreach (core->flags->flags, iter, flag) {
/* filter per flag spaces */
if ((core->flags->space_idx != -1) &&
(flag->space != core->flags->space_idx))
continue;
if (option==i) {
fs2 = flag->name;
hit = 1;
}
if ((i>=option-delta) && ((i<option+delta)||((option<delta)&&(i<(delta<<1))))) {
r_cons_printf (" %c %03d 0x%08"PFMT64x" %4"PFMT64d" %s\n",
(option==i)?'>':' ',
i, flag->offset, flag->size, flag->name);
j++;
}
i++;
}
if (!hit && i>0) {
option = i-1;
continue;
}
r_cons_printf ("\n Selected: %s\n\n", fs2);
switch (format) {
case 0: sprintf (cmd, "px @ %s:64", fs2); core->printidx = 0; break;
case 1: sprintf (cmd, "pd 12 @ %s:64", fs2); core->printidx = 1; break;
case 2: sprintf (cmd, "ps @ %s:64", fs2); core->printidx = 5; break;
default: format = 0; continue;
}
if (*cmd) r_core_cmd (core, cmd, 0);
} else {
r_cons_printf ("Flag spaces:\n\n");
hit = 0;
for (j=i=0;i<R_FLAG_SPACES_MAX;i++) {
if (core->flags->spaces[i]) {
if (option==i) {
fs = core->flags->spaces[i];
hit = 1;
}
if ((i >=option-delta) && ((i<option+delta)|| \
((option<delta)&&(i<(delta<<1))))) {
r_cons_printf(" %c %02d %c %s\n",
(option==i)?'>':' ', j,
(i==core->flags->space_idx)?'*':' ',
core->flags->spaces[i]);
j++;
}
}
}
{
if (option == j) {
fs = "*";
hit = 1;
}
r_cons_printf (" %c %02d %c %s\n",
(option==j)?'>':' ', j,
(i==core->flags->space_idx)?'*':' ',
"*");
}
if (!hit && j>0) {
option = j-1;
continue;
}
}
r_cons_flush ();
ch = r_cons_readchar ();
ch = r_cons_arrow_to_hjkl (ch); // get ESC+char, return 'hjkl' char
switch (ch) {
case 'J':
option += 10;
break;
case 'o':
r_flag_sort (core->flags, 0);
break;
case 'n':
r_flag_sort (core->flags, 1);
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
menu = 0;
option = _option;
break;
case 'a':
switch (menu) {
case 0: // new flag space
r_cons_show_cursor (R_TRUE);
r_line_set_prompt ("add flagspace: ");
strcpy (cmd, "fs ");
if (r_cons_fgets (cmd+3, sizeof (cmd)-4, 0, NULL) > 0) {
r_core_cmd (core, cmd, 0);
r_cons_set_raw (1);
r_cons_show_cursor (R_FALSE);
}
break;
case 1: // new flag
r_cons_show_cursor (R_TRUE);
r_line_set_prompt ("add flag: ");
strcpy (cmd, "f ");
if (r_cons_fgets (cmd+2, sizeof (cmd)-3, 0, NULL) > 0) {
r_core_cmd (core, cmd, 0);
r_cons_set_raw (1);
r_cons_show_cursor (R_FALSE);
}
break;
}
break;
case 'd':
r_flag_unset (core->flags, fs2, NULL);
break;
case 'e':
/* TODO: prompt for addr, size, name */
eprintf ("TODO\n");
r_sys_sleep (1);
break;
case 'q':
if (menu<=0) return R_TRUE; menu--;
break;
case '*':
r_core_block_size (core, core->blocksize+16);
break;
case '+':
r_core_block_size (core, core->blocksize+1);
break;
case '/':
r_core_block_size (core, core->blocksize-16);
break;
case '-':
r_core_block_size (core, core->blocksize-1);
break;
case 'r':
if (menu == 1) {
int len;
r_cons_show_cursor (R_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 (":> ");
if (r_cons_fgets (cmd+len, sizeof (cmd)-len-1, 0, NULL) <0)
cmd[0]='\0';
r_core_cmd (core, cmd, 0);
r_cons_set_raw (1);
r_cons_show_cursor (R_FALSE);
}
break;
case 'R':
if (menu == 1) {
char line[1024];
r_cons_show_cursor (R_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';
snprintf (cmd, sizeof (cmd), "afr %s %s", line, fs2);
r_core_cmd (core, cmd, 0);
r_cons_set_raw (1);
r_cons_show_cursor (R_FALSE);
}
break;
case 'P':
if (--format<0)
format = MAX_FORMAT;
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);
return R_TRUE;
}
r_flag_space_set (core->flags, fs);
menu = 1;
_option = option;
option = 0;
break;
case '?':
r_cons_clear00 ();
r_cons_printf (
"\nVt: Visual Track 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 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"
" : - enter command\n");
r_cons_flush ();
r_cons_any_key ();
break;
case ':':
r_cons_show_cursor (R_TRUE);
r_cons_set_raw (0);
cmd[0]='\0';
r_line_set_prompt (":> ");
if (r_cons_fgets (cmd, sizeof (cmd)-1, 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 (R_FALSE);
if (cmd[0])
r_cons_any_key ();
//cons_gotoxy(0,0);
r_cons_clear ();
continue;
}
}
return R_TRUE;
}
R_API int r_core_visual_comments (RCore *core) {
char *str, cmd[512], *p = NULL;
int mode = 0;
int delta = 7;
int i, ch, option = 0;
int format = 0;
int found = 0;
ut64 from = 0, size = 0;
RListIter *iter;
RAnalFunction *fcn;
RMetaItem *d;
for (;;) {
r_cons_gotoxy (0, 0);
r_cons_clear ();
r_cons_printf ("Comments:\n");
i = 0;
found = 0;
mode = 0;
r_list_foreach (core->anal->meta->data, iter, d) {
str = r_str_unscape (d->str);
if (str) {
if (d->type=='s') /* Ignore strings, there are in trackflags */
continue;
if ((i>=option-delta) && ((i<option+delta)||((option<delta)&&(i<(delta<<1))))) {
r_str_sanitize (str);
if (option==i) {
mode = 0;
found = 1;
from = d->from;
size = d->size;
p = str;
r_cons_printf(" > %s\n", str);
} else {
r_cons_printf(" %s\n", str);
free (str);
}
}
i++;
}
}
if (!found) {
option--;
continue;
}
r_list_foreach (core->anal->fcns, iter, fcn) {
if ((i>=option-delta) && ((i<option+delta)||((option<delta)&&(i<(delta<<1))))) {
if (option==i) {
mode = 1;
from = fcn->addr;
size = fcn->size;
}
r_cons_printf(" %c %s\n", (option==i)?'>':' ', fcn->name);
}
i++;
}
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_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':
if (mode == 0) {
if (p) r_meta_del (core->anal->meta, R_META_TYPE_ANY, from, size, p);
} else {
r_anal_fcn_del (core->anal, from);
}
break;
case 'P':
if (--format<0)
format = MAX_FORMAT;
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':
sprintf (cmd, "s 0x%"PFMT64x, from);
r_core_cmd (core, cmd, 0);
if (p)
free (p);
return R_TRUE;
case 'q':
if (p)
free (p);
return R_TRUE;
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 ();
break;
}
if (p) {
free (p);
p = NULL;
}
}
return R_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);
if (node && ((node->flags & CN_INT) || (node->flags & CN_OFFT)))
r_config_set_i(core->config, name, r_config_get_i(core->config, name)+delta);
}
/* Visually activate the config variable */
static void config_visual_hit(RCore *core, const char *name, int editor) {
char buf[1024];
RConfigNode *node;
if (!(node = r_config_node_get (core->config, name)))
return;
if (node->flags & CN_BOOL) {
/* TOGGLE */
node->i_value = !node->i_value;
node->value = r_str_dup (node->value, node->i_value?"true":"false");
} else {
if (editor) {
char * buf = r_core_editor (core, 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);
r_cons_show_cursor (R_TRUE);
r_cons_flush ();
r_cons_set_raw (0);
r_line_set_prompt (":> ");
r_cons_fgets (buf, sizeof (buf)-1, 0, 0);
r_cons_set_raw (1);
r_cons_show_cursor (R_FALSE);
node->value = r_str_dup (node->value, buf);
}
}
}
R_API void r_core_visual_config(RCore *core) {
RListIter *iter;
RConfigNode *bt;
char cmd[1024];
#define MAX_FORMAT 2
char *fs = NULL;
char *fs2 = NULL;
int option, _option = 0;
int delta = 9;
int menu = 0;
int i,j, ch;
int hit;
int show;
char old[1024];
old[0]='\0';
option = 0;
for (;;) {
r_cons_gotoxy (0,0);
r_cons_clear ();
switch (menu) {
case 0: // flag space
r_cons_printf ("\n Eval spaces:\n\n");
hit = 0;
j = i = 0;
r_list_foreach (core->config->nodes, iter, bt) {
if (option==i) {
fs = bt->name;
hit = 1;
}
if (old[0]=='\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( (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 = j-1;
continue;
}
r_cons_printf ("\n Sel:%s \n\n", fs);
break;
case 1: // flag selection
r_cons_printf ("\n Eval 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 (option==i) {
fs2 = bt->name;
hit = 1;
}
if (!r_str_ccmp (bt->name, fs, '.')) {
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 != NULL)
r_cons_printf ("\n Selected: %s\n\n", fs2);
}
if (fs && !memcmp (fs, "asm.", 4))
r_core_cmd (core, "pd 5", 0);
r_cons_flush ();
ch = r_cons_readchar ();
ch = r_cons_arrow_to_hjkl (ch); // get ESC+char, return 'hjkl' char
switch (ch) {
case 'j':
option++;
break;
case 'k':
if (--option<0)
option = 0;
break;
case 'h':
case 'b': // back
menu = 0;
option = _option;
break;
case 'q':
if (menu<=0) return; menu--;
break;
case '*':
case '+':
if (fs2 != NULL)
config_visual_hit_i (core, fs2, +1);
continue;
case '/':
case '-':
if (fs2 != NULL)
config_visual_hit_i (core, fs2, -1);
continue;
case 'l':
case 'E': // edit value
case 'e': // edit value
case ' ':
case '\r':
case '\n': // never happens
if (menu == 1) {
if (fs2 != NULL)
config_visual_hit (core, fs2, (ch=='E'));
} else {
r_flag_space_set (core->flags, fs);
menu = 1;
_option = option;
option = 0;
}
break;
case '?':
r_cons_clear00 ();
r_cons_printf ("\nVe: Visual Eval help:\n\n");
r_cons_printf (" q - quit menu\n");
r_cons_printf (" j/k - down/up keys\n");
r_cons_printf (" h/b - go back\n");
r_cons_printf (" e/' ' - edit/toggle current variable\n");
r_cons_printf (" E - edit variable with 'cfg.editor' (vi?)\n");
r_cons_printf (" +/- - increase/decrease numeric value\n");
r_cons_printf (" : - enter command\n");
r_cons_flush ();
r_cons_any_key ();
break;
case ':':
r_cons_show_cursor (R_TRUE);
r_cons_set_raw(0);
/* WTF READLINE?? WE DONT USE THAT!! */
#if HAVE_LIB_READLINE
{
char *ptr = readline(VISUAL_PROMPT);
if (ptr) {
strncpy(cmd, ptr, sizeof (cmd)-1);
r_core_cmd(core, cmd, 1);
free(ptr);
}
}
#else
*cmd = '\0';
if (r_cons_fgets (cmd, sizeof (cmd)-1, 0, NULL) <0)
cmd[0]='\0';
//line[strlen(line)-1]='\0';
r_core_cmd (core, cmd, 1);
#endif
r_cons_set_raw (1);
r_cons_show_cursor (R_FALSE);
if (cmd[0])
r_cons_any_key ();
//r_cons_gotoxy(0,0);
r_cons_clear00 ();
continue;
}
}
}
R_API void r_core_visual_mounts (RCore *core) {
RList *list;
RListIter *iter;
RFSFile *file;
RFSPartition *part;
int i, ch, option, mode, partition, dir, delta = 7;
char *str, path[4096], buf[1024], *root = NULL;
const char *n, *p;
dir = partition = option = mode = 0;
for (;;) {
/* Clear */
r_cons_gotoxy (0,0);
r_cons_clear ();
/* Show */
if (mode == 0) {
r_cons_printf ("Partitions:\n\n");
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);
}
i++;
}
r_list_free (list);
} else r_cons_printf ("Cannot read partition\n");
} else if (mode == 1) {
r_cons_printf ("Types:\n\n");
for(i=0;;i++) {
n = r_fs_partition_type_get (i);
if (!n) break;
r_cons_printf ("%s%s\n", (i==partition)?" > ":" ", n);
}
} else {
if (root) {
list = r_fs_dir (core->fs, path);
if (list) {
r_cons_printf ("%s:\n\n", path);
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++;
}
r_cons_printf ("\n");
r_list_free (list);
} else r_cons_printf ("Cannot open '%s' directory\n", root);
} else r_cons_printf ("Root undefined\n");
}
if (mode==2) {
r_str_chop_path (path);
str = path + strlen (path);
strncat (path, "/", sizeof (path)-strlen (path)-1);
list = r_fs_dir (core->fs, path);
file = r_list_get_n (list, dir);
if (file && file->type != 'd')
r_core_cmdf (core, "x @ 0x%"PFMT64x":32", file->off);
*str='\0';
}
r_cons_flush ();
/* Ask for option */
ch = r_cons_readchar ();
ch = r_cons_arrow_to_hjkl (ch);
switch (ch) {
case 'l':
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 ();
r_cons_flush ();
break;
}
part = r_list_get_n (list, option);
if (!part) {
r_cons_printf ("Unknown partition\n");
r_cons_any_key ();
r_cons_flush ();
break;
}
p = r_fs_partition_type (n, part->type);
if (p) {
if (r_fs_mount (core->fs, p, "/root", part->start)) {
if (root)
free (root);
root = strdup ("/root");
strncpy (path, root, sizeof (path)-1);
mode = 2;
} else {
r_cons_printf ("Cannot mount partition\n");
r_cons_flush ();
r_cons_any_key ();
}
} else {
r_cons_printf ("Unknown partition type\n");
r_cons_flush ();
r_cons_any_key ();
}
} else if (mode == 2){
r_str_chop_path (path);
strncat (path, "/", sizeof (path)-strlen (path)-1);
list = r_fs_dir (core->fs, path);
file = r_list_get_n (list, dir);
if (file) {
if (file->type == 'd') {
strncat (path, file->name, sizeof (path)-strlen (path)-1);
r_str_chop_path (path);
if (memcmp (root, path, strlen (root)-1))
strncpy (path, root, sizeof (path)-1);
} else {
r_core_cmdf (core, "s 0x%"PFMT64x, file->off);
r_fs_umount (core->fs, root);
return;
}
} else {
r_cons_printf ("Unknown file\n");
r_cons_flush ();
r_cons_any_key ();
}
}
dir = partition = option = 0;
break;
case 'k':
if (mode == 0) {
if (option > 0)
option--;
} else if (mode == 1) {
if (partition > 0)
partition--;
} else {
if (dir>0)
dir--;
}
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)
option++;
} else if (mode == 1) {
if (partition < r_fs_partition_get_size ()-1)
partition++;
} else {
list = r_fs_dir (core->fs, path);
if (dir < r_list_length (list)-1)
dir++;
}
break;
case 't':
mode = 1;
break;
case 'h':
if (mode == 2) {
if (strcmp (path, root)) {
strcat (path, "/..");
r_str_chop_path (path);
} else {
r_fs_umount (core->fs, root);
mode = 0;
}
} else if (mode == 1)
mode = 0;
else
return;
break;
case 'q':
if (mode == 2 && root) {
r_fs_umount (core->fs, root);
mode = 0;
} else
return;
break;
case 'g':
if (mode == 2){
r_str_chop_path (path);
str = path + strlen (path);
strncat (path, "/", sizeof (path)-strlen (path)-1);
list = r_fs_dir (core->fs, path);
file = r_list_get_n (list, dir);
if (file) {
strncat (path, file->name, sizeof (path)-strlen (path)-1);
r_str_chop_path (path);
if (memcmp (root, path, strlen (root)-1))
strncpy (path, root, sizeof (path)-1);
file = r_fs_open (core->fs, path);
if (file) {
r_fs_read (core->fs, file, 0, file->size);
r_cons_show_cursor (R_TRUE);
r_cons_set_raw (0);
r_line_set_prompt ("Dump path (ej: /tmp/file): ");
r_cons_fgets (buf, sizeof (buf)-1, 0, 0);
r_cons_set_raw (1);
r_cons_show_cursor (R_FALSE);
r_file_dump (buf, file->data, file->size);
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 ();
*str='\0';
}
break;
case '?':
r_cons_clear00 ();
r_cons_printf ("\nVM: Visual Mount points help:\n\n");
r_cons_printf (" q - go back or quit menu\n");
r_cons_printf (" j/k - down/up keys\n");
r_cons_printf (" h/l - forward/go keys\n");
r_cons_printf (" t - choose partition type\n");
r_cons_printf (" g - dump file\n");
r_cons_printf (" : - enter command\n");
r_cons_printf (" ? - show this help\n");
r_cons_flush ();
r_cons_any_key ();
break;
case ':':
r_cons_show_cursor (R_TRUE);
r_cons_set_raw (0);
r_line_set_prompt (":> ");
r_cons_fgets (buf, sizeof (buf)-1, 0, 0);
r_cons_set_raw (1);
r_cons_show_cursor (R_FALSE);
r_core_cmd (core, buf, 1);
r_cons_any_key ();
break;
}
}
}
#if 1
static void var_index_show(RAnal *anal, RAnalFunction *fcn, ut64 addr, int idx) {
int i = 0;
RAnalVar *v;
RAnalVarAccess *x;
RListIter *iter, *iter2;
int window = 15;
int wdelta = (idx>5)?idx-5:0;
if (!fcn)
return;
r_list_foreach(fcn->vars, iter, v) {
if (addr == 0 || (addr >= v->addr && addr <= v->eaddr)) {
if (i>=wdelta) {
if (i> window+wdelta) {
r_cons_printf("...\n");
break;
}
if (idx == i) r_cons_printf (" * ");
else r_cons_printf (" ");
if (v->type->type == R_ANAL_TYPE_ARRAY)
r_cons_printf ("0x%08llx - 0x%08llx scope=%s type=%s name=%s delta=%d array=%d\n",
v->addr, v->eaddr, r_anal_var_scope_to_str (anal, v->scope),
r_anal_type_to_str (anal, v->type, ""),
v->name, v->delta, v->type->custom.a->count);
else
r_cons_printf ("0x%08llx - 0x%08llx scope=%s type=%s name=%s delta=%d\n",
v->addr, v->eaddr, r_anal_var_scope_to_str (anal, v->scope),
r_anal_type_to_str (anal, v->type, ""), v->name, v->delta);
r_list_foreach (v->accesses, iter2, x) {
r_cons_printf (" 0x%08llx %s\n", x->addr, x->set?"set":"get");
}
}
i++;
}
}
}
// 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 (core->flags, fcn->name, NULL);
free (fcn->name);
fcn->name = strdup (name);
r_flag_set (core->flags, name, addr, fcn->size, 0);
break;
}
}
}
static ut64 var_functions_show(RCore *core, int idx, int show) {
int i = 0;
ut64 seek = core->offset;
ut64 addr = core->offset;
int window = 15;
int wdelta = (idx>5)?idx-5:0;
RListIter *iter;
RAnalFunction *fcn;
r_list_foreach (core->anal->fcns, iter, fcn) {
if (i>=wdelta) {
if (i> window+wdelta) {
r_cons_printf("...\n");
break;
}
//if (seek >= fcn->addr && seek <= fcn->addr+fcn->size)
if (idx == i)
addr = fcn->addr;
if (show)
r_cons_printf ("%c%c 0x%08llx (%s)\n",
(seek == fcn->addr)?'>':' ',
(idx==i)?'*':' ',
fcn->addr, fcn->name);
}
i++;
}
return addr;
}
static int level = 0;
static ut64 addr = 0;
static int option = 0;
static void r_core_visual_anal_refresh (RCore *core) {
ut64 addr = core->offset;
char old[1024];
old[0]='\0';
int cols = r_cons_get_size (NULL);
RAnalFunction *fcn = r_anal_fcn_find (core->anal, core->offset, R_ANAL_FCN_TYPE_NULL); // once
char *oprofile;
cols -= 50;
if (cols> 60) cols = 60;
r_cons_clear ();
if (cols>10) {
r_cons_printf ("Visual code analysis manipulation\n");
if (!level)
addr = var_functions_show (core, option, 0);
oprofile = strdup (r_config_get (core->config, "asm.profile"));
r_config_set (core->config, "asm.profile", "simple");
r_core_cmdf (core, "pd @ 0x%"PFMT64x":32", addr);
r_config_set (core->config, "asm.profile", oprofile);
free (oprofile);
r_cons_column (cols); //32);
}
switch (level) {
case 0:
r_cons_printf ("-[ functions ]---------------- \n"
"(a) add (x)xrefs (q)quit \n"
"(m) modify (c)calls (g)go \n"
"(d) delete (v)variables \n");
addr = var_functions_show (core, option, 1);
break;
case 1:
r_cons_printf ("-[ variables ]---------------- 0x%08"PFMT64x"\n"
"(a) add (x)xrefs (q)quit \n"
"(m) modify (c)calls (g)go \n"
"(d) delete (v)variables \n", addr);
var_index_show (core->anal, fcn, addr, option);
break;
case 2:
r_cons_printf ("-[ calls ]----------------------- 0x%08"PFMT64x" (TODO)\n", addr);
#if 0
sprintf(old, "aCf@0x%08llx", addr);
cons_flush();
radare_cmd(old, 0);
#endif
break;
case 3:
r_cons_printf ("-[ xrefs ]----------------------- 0x%08"PFMT64x"\n", addr);
sprintf (old, "arl~0x%08"PFMT64x, addr);
r_core_cmd0 (core, old);
//cons_printf("\n");
break;
}
r_cons_flush ();
}
/* Like emenu but for real */
R_API void r_core_visual_anal(RCore *core) {
char old[218];
RConsEvent olde;
int _option = 0;
int ch; //, level = 0;
olde = core->cons->event_resize;
core->cons->event_resize = (RConsEvent)
r_core_visual_anal_refresh;
level = 0;
addr = core->offset;
for (;;) {
r_core_visual_anal_refresh (core);
// show indexable vars
ch = r_cons_readchar ();
ch = r_cons_arrow_to_hjkl (ch); // get ESC+char, return 'hjkl' char
switch (ch) {
case ':':
r_core_visual_prompt (core);
continue;
case 'a':
switch (level) {
case 0:
eprintf ("TODO: Add new function manually\n");
/*
r_cons_show_cursor (R_TRUE);
r_cons_set_raw (R_FALSE);
r_line_set_prompt ("Address: ");
if (!r_cons_fgets (old, sizeof (old), 0, NULL)) break;
old[strlen (old)-1] = 0;
if (!*old) break;
addr = r_num_math (core->num, old);
r_line_set_prompt ("Size: ");
if (!r_cons_fgets (old, sizeof (old), 0, NULL)) break;
old[strlen (old)-1] = 0;
if (!*old) break;
size = r_num_math (core->num, old);
r_line_set_prompt ("Name: ");
if (!r_cons_fgets (old, sizeof (old), 0, NULL)) break;
old[strlen (old)-1] = 0;
r_flag_set (core->flags, old, addr, 0, 0);
//XXX sprintf(cmd, "CF %lld @ 0x%08llx", size, addr);
// XXX r_core_cmd0(core, cmd);
r_cons_set_raw (R_TRUE);
r_cons_show_cursor (R_FALSE);
*/
break;
case 1:
break;
}
break;
case 'm':
r_cons_show_cursor (R_TRUE);
r_cons_set_raw (R_FALSE);
r_line_set_prompt ("New name: ");
if (!r_cons_fgets (old, sizeof (old), 0, NULL)) break;
//old[strlen (old)-1] = 0;
function_rename (core, addr, old);
r_cons_set_raw (R_TRUE);
r_cons_show_cursor (R_FALSE);
break;
case 'd':
switch (level) {
case 0:
eprintf ("TODO\n");
//data_del(addr, DATA_FUN, 0);
// XXX correcly remove all the data contained inside the size of the function
//flag_remove_at(addr);
break;
}
break;
case 'x':
level = 3;
break;
case 'c':
level = 2;
break;
case 'v':
level = 1;
break;
case 'j':
option++;
break;
case 'k':
if (--option<0)
option = 0;
break;
case 'g': // go!
r_core_seek (core, addr, SEEK_SET);
goto beach;
case ' ':
case 'l':
level = 1;
_option = option;
break;
case 'h':
case 'b': // back
level = 0;
option = _option;
break;
case 'q':
if (level==0)
goto beach;
break;
}
}
beach:
core->cons->event_resize = olde;
level = 0;
}
#endif
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))
next = core->offset + aop.length;
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");
RFlagItem *flag;
r_list_foreach (core->flags->flags, iter, flag) {
if (!memcmp (flag->name, pfx, strlen (pfx)))
if (flag->offset < next && flag->offset > core->offset)
next = flag->offset;
}
} else { // flags
RFlagItem *flag;
r_list_foreach (core->flags->flags, iter, flag) {
if (flag->offset < next && flag->offset > core->offset)
next = flag->offset;
}
}
if (next!=UT64_MAX)
r_core_seek (core, next, 1);
}
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")) {
RFlagItem *flag;
const char *pfx = r_config_get (core->config, "search.prefix");
r_list_foreach (core->flags->flags, iter, flag) {
if (!memcmp (flag->name, pfx, strlen (pfx)))
if (flag->offset > next && flag->offset< core->offset)
next = flag->offset;
}
} else { // flags
RFlagItem *flag;
r_list_foreach (core->flags->flags, iter, flag) {
if (flag->offset > next && flag->offset < core->offset)
next = flag->offset;
}
}
if (next!=0)
r_core_seek (core, next, 1);
}
R_API void r_core_visual_define (RCore *core) {
int ch, ntotal = 0;
ut64 off = core->offset;
ut8 *p = core->block;
int plen = core->blocksize;
if (core->print->cur_enabled) {
off += core->print->cur;
p += core->print->cur;
plen -= core->print->cur;
}
r_cons_printf ("Define current block as:\n"
" d - set as data\n"
" c - set as code\n"
" s - set string\n"
" S - set strings in current block\n"
" f - analyze function\n"
" u - undefine metadata here\n"
" q - quit/cancel operation\n"
"TODO: add support for data, string, code ..\n");
r_cons_flush ();
// get ESC+char, return 'hjkl' char
ch = r_cons_arrow_to_hjkl (r_cons_readchar ());
switch (ch) {
case 'S':
do {
char *name;
int n = r_str_nlen ((const char*)p+ntotal, plen-ntotal)+1;
name = malloc (n+10);
strcpy (name, "str.");
strncpy (name+4, (const char *)p+ntotal, n);
r_flag_set (core->flags, name, off, n, 0);
r_meta_add (core->anal->meta, R_META_TYPE_STRING,
off+ntotal, off+n+ntotal, (const char *)p+ntotal);
free (name);
if (n<2) break;
ntotal+= n;
} while (ntotal<core->blocksize);
break;
case 's':
{
char *name;
int n = r_str_nlen ((const char*)p, plen)+1;
name = malloc (n+10);
strcpy (name, "str.");
strncpy (name+4, (const char *)p, n);
r_flag_set (core->flags, name, off, n, 0);
r_meta_add (core->anal->meta, R_META_TYPE_STRING, off, off+n, (const char *)p);
free (name);
}
break;
case 'd': // TODO: check
r_meta_add (core->anal->meta, R_META_TYPE_DATA, off, off+core->blocksize, "");
break;
case 'c': // TODO: check
r_meta_add (core->anal->meta, R_META_TYPE_CODE, off, off+core->blocksize, "");
break;
case 'u':
r_meta_del (core->anal->meta, R_META_TYPE_ANY, off, 1, "");
r_flag_unset_i (core->flags, off, NULL);
r_anal_fcn_del (core->anal, off);
break;
case 'f':
r_cons_break(NULL,NULL);
r_core_anal_fcn (core, off, -1, R_ANAL_REF_TYPE_NULL,
r_config_get_i (core->config, "anal.depth"));
r_cons_break_end();
break;
case 'q':
default:
break;
}
}