radare2/libr/core/panels.c

1203 lines
29 KiB
C
Raw Normal View History

/* Copyright radare2 2014-2018 - Author: pancake, vane11ope */
// pls move the typedefs into roons and rename it -> RConsPanel
#include <r_core.h>
#define LIMIT 256
#define PANEL_TITLE_SYMBOLS "Symbols"
#define PANEL_TITLE_STACK "Stack"
#define PANEL_TITLE_REGISTERS "Registers"
#define PANEL_TITLE_REGISTERREFS "RegisterRefs"
#define PANEL_TITLE_DISASSEMBLY "Disassembly"
#define PANEL_TITLE_NEWFILES "New files"
#define PANEL_TITLE_INFO "Info"
#define PANEL_TITLE_DATABASE "Database"
#define PANEL_TITLE_HEXDUMP "Hexdump"
#define PANEL_TITLE_FUNCTIONS "Functions"
#define PANEL_TITLE_COMMENTS "Comments"
#define PANEL_TITLE_ENTROPY "Entropy"
#define PANEL_TITLE_DRX "DRX"
#define PANEL_TITLE_SECTIONS "Sections"
#define PANEL_TITLE_STRINGS "Strings"
#define PANEL_TITLE_MAPS "Maps"
#define PANEL_TITLE_MODULES "Modules"
#define PANEL_TITLE_BACKTRACE "Backtrace"
#define PANEL_TITLE_BREAKPOINTS "Breakpoints"
#define PANEL_TITLE_IMPORTS "Imports"
#define PANEL_TITLE_CLIPBOARD "Clipboard"
#define PANEL_TITLE_FCNINFO "FcnInfo"
#define PANEL_CMD_SYMBOLS "isq"
#define PANEL_CMD_STACK "px 256@r:SP"
#define PANEL_CMD_REGISTERS "dr="
#define PANEL_CMD_REGISTERREFS "drr"
#define PANEL_CMD_DISASSEMBLY "pd $r @e:scr.utf8=0"
static RConsCanvas *can;
typedef struct {
int x;
int y;
int w;
int h;
int depth;
int type;
int sx; // scroll-x
int sy; // scroll-y
char *cmd;
char *text;
bool refresh;
} Panel;
enum {
PANEL_TYPE_FRAME,
PANEL_TYPE_MENU
};
enum {
LAYOUT_DEFAULT,
LAYOUT_BALANCE
};
static Panel *panels = NULL;
static int n_panels = 0;
static int columnWidth = 80;
2016-11-22 01:58:52 +01:00
static const int layoutCount = 2;
static int layout = 0;
static RCore *_core;
static int menu_pos = 0;
static int menu_x = 0;
static int menu_y = 0;
static int callgraph = 0;
static bool isResizing = false;
static const char *menus[] = {
2015-08-31 11:53:03 +02:00
"File", "Edit", "View", "Tools", "Search", "Debug", "Analyze", "Help",
NULL
};
static const char *menus_File[] = {
2016-11-22 01:58:52 +01:00
"New", "Open", "Close", ".", "Sections", "Strings", "Symbols", "Imports", "Info", "Database", ".", "Quit",
NULL
};
static const char *menus_Edit[] = {
"Copy", "Paste", "Clipboard", "Write String", "Write Hex", "Write Value", "Assemble", "Fill", "io.cache",
NULL
};
static const char *menus_View[] = {
2015-08-31 05:43:38 +02:00
"Hexdump", "Disassembly", "Graph", "FcnInfo", "Functions", "Comments", "Entropy", "Colors",
NULL
};
static const char *menus_Tools[] = {
"Assembler", "Calculator", "R2 Shell", "System Shell",
NULL
};
2015-08-31 11:53:03 +02:00
static const char *menus_Search[] = {
"String", "ROP", "Code", "Hexpairs",
NULL
};
static const char *menus_Debug[] = {
2015-10-07 11:32:08 +02:00
"Registers", "RegisterRefs", "DRX", "Breakpoints",
2016-11-22 01:58:52 +01:00
"Watchpoints", "Maps", "Modules",
"Backtrace",
2016-11-22 01:58:52 +01:00
".",
"Continue", "Cont until.",
"Step", "Step Over",
NULL
};
static const char *menus_Analyze[] = {
"Function", "Program", "Calls", "References",
NULL
};
static const char *menus_Help[] = {
2016-11-22 01:58:52 +01:00
"Fortune", "Commands", "2048", "License", ".", "About",
NULL
};
static const char **menus_sub[] = {
menus_File,
menus_Edit,
menus_View,
menus_Tools,
2015-08-31 11:53:03 +02:00
menus_Search,
menus_Debug,
menus_Analyze,
menus_Help,
NULL
};
// TODO: handle mouse wheel
static int curnode = 0;
static void Panel_print(RConsCanvas *can, Panel *n, int cur) {
2018-03-23 12:52:56 +01:00
if (!n || !can || !n->refresh) {
return;
}
n->refresh = false;
char *text;
char title[128];
2015-11-22 11:39:54 +01:00
int delta_x, delta_y;
delta_x = n->sx;
delta_y = n->sy;
// clear the canvas first
r_cons_canvas_fill (can, n->x, n->y, n->w, n->h, ' ', 0);
// for menu
RCons *cons = r_cons_singleton ();
if (n->type == PANEL_TYPE_MENU) {
(void) r_cons_canvas_gotoxy (can, n->x + 2, n->y + 2);
text = r_str_ansi_crop (n->text,
delta_x, delta_y, n->w + 5, n->h - delta_y);
if (text) {
r_cons_canvas_write (can, text);
free (text);
} else {
r_cons_canvas_write (can, n->text);
}
} else {
if (cur) {
const char *k = cons->pal.graph_box;
snprintf (title, sizeof (title) - 1,
"%s[x] %s"Color_RESET, k, n->text);
} else {
snprintf (title, sizeof (title) - 1,
" %s ", n->text);
}
if (r_cons_canvas_gotoxy (can, n->x + 1, n->y + 1)) {
r_cons_canvas_write (can, title); // delta_x
}
(void) r_cons_canvas_gotoxy (can, n->x + 2, n->y + 2);
char *foo = r_core_cmd_str (_core, n->cmd);
if (delta_y < 0) {
delta_y = 0;
}
if (delta_x < 0) {
char *white = (char*)r_str_pad (' ', 128);;
int idx = -delta_x;
if (idx >= sizeof (white)) {
idx = sizeof (white) - 1;
}
white[idx] = 0;
text = r_str_ansi_crop (foo,
0, delta_y, n->w + delta_x - 2, n->h - 2 + delta_y);
char *newText = r_str_prefix_all (text, white);
if (newText) {
free (text);
text = newText;
}
} else {
text = r_str_ansi_crop (foo,
delta_x, delta_y, n->w + delta_x - 2, n->h - 2 + delta_y);
}
if (text) {
r_cons_canvas_write (can, text);
free (text);
} else {
r_cons_canvas_write (can, n->text);
}
free (foo);
}
if (cur) {
r_cons_canvas_box (can, n->x, n->y, n->w, n->h, cons->pal.graph_box2);
} else {
r_cons_canvas_box (can, n->x, n->y, n->w, n->h, cons->pal.graph_box);
}
}
static void Layout_run(Panel *panels) {
int h, w = r_cons_get_size (&h);
int i, j;
int colpos = w - columnWidth;
2016-05-09 11:13:37 +02:00
if (colpos < 0) {
columnWidth = w;
colpos = 0;
}
can->sx = 0;
can->sy = 0;
for (i = j = 0; i < n_panels; i++) {
switch (panels[i].type) {
case PANEL_TYPE_MENU:
panels[i].w = r_str_bounds (
panels[i].text,
&panels[i].h);
panels[i].h += 4;
break;
case PANEL_TYPE_FRAME:
2016-11-22 01:58:52 +01:00
switch (layout) {
case LAYOUT_DEFAULT:
2016-11-22 01:58:52 +01:00
if (j == 0) {
panels[i].x = 0;
panels[i].y = 1;
if (panels[j + 1].text) {
panels[i].w = colpos + 1;
2016-11-22 01:58:52 +01:00
} else {
panels[i].w = w;
}
panels[i].h = h - 1;
} else {
2016-11-22 01:58:52 +01:00
int ph = ((h - 1) / (n_panels - 2));
panels[i].x = colpos;
panels[i].y = 1 + (ph * (j - 1));
panels[i].w = w - colpos;
2016-11-22 01:58:52 +01:00
if (panels[i].w < 0) {
panels[i].w = 0;
}
panels[i].h = ph;
if (!panels[i + 1].text) {
panels[i].h = h - panels[i].y;
}
if (j != 1) {
panels[i].y--;
panels[i].h++;
}
}
2016-11-22 01:58:52 +01:00
break;
case LAYOUT_BALANCE:
2016-11-22 01:58:52 +01:00
if (j == 0) {
panels[i].x = 0;
panels[i].y = 1;
if (panels[j + 1].text) {
2016-11-22 01:58:52 +01:00
panels[i].w = colpos + 1;
} else {
panels[i].w = w;
}
panels[i].h = (h / 2) + 1;
} else if (j == 1) {
panels[i].x = 0;
panels[i].y = (h / 2) + 1;
if (panels[j + 1].text) {
2016-11-22 01:58:52 +01:00
panels[i].w = colpos + 1;
} else {
panels[i].w = w;
}
panels[i].h = (h - 1) / 2;
2016-11-22 01:58:52 +01:00
} else {
int ph = ((h - 1) / (n_panels - 3));
panels[i].x = colpos;
panels[i].y = 1 + (ph * (j - 2));
panels[i].w = w - colpos;
if (panels[i].w < 0) {
panels[i].w = 0;
}
panels[i].h = ph;
if (!panels[i + 1].text) {
panels[i].h = h - panels[i].y;
}
if (j != 2) {
panels[i].y--;
panels[i].h++;
}
}
2016-11-22 01:58:52 +01:00
break;
}
j++;
}
}
}
static void delcurpanel() {
2016-05-09 11:13:37 +02:00
int i;
2016-10-26 23:16:31 +02:00
if (curnode > 0 && n_panels > 3) {
2016-05-09 11:13:37 +02:00
for (i = curnode; i < (n_panels - 1); i++) {
panels[i] = panels[i + 1];
}
panels[i].text = 0;
n_panels--;
2016-05-09 11:13:37 +02:00
if (curnode >= n_panels) {
curnode = n_panels - 1;
}
}
}
static void zoom() {
2016-05-09 11:13:37 +02:00
if (n_panels > 2) {
if (curnode < 2) {
2015-08-31 05:43:38 +02:00
curnode = 2;
}
Panel ocurnode = panels[curnode];
panels[curnode] = panels[1];
panels[1] = ocurnode;
2016-11-22 01:58:52 +01:00
curnode = 1;
}
}
static void refreshAll() {
int i;
for (i = 0; i < n_panels; i++) {
panels[i].refresh = true;
}
}
static void addPanelFrame(const char *title, const char *cmd) {
if (title) {
panels[n_panels].text = strdup (title);
panels[n_panels].cmd = r_str_newf (cmd);
} else {
panels[n_panels].text = r_core_cmd_str (_core, cmd);
panels[n_panels].cmd = NULL;
}
panels[n_panels].type = PANEL_TYPE_FRAME;
panels[n_panels].refresh = true;
panels[n_panels + 1].text = NULL;
n_panels++;
2016-11-22 01:58:52 +01:00
curnode = n_panels - 1;
zoom ();
2016-11-22 01:58:52 +01:00
menu_y = 0;
refreshAll ();
}
static bool initPanel() {
panels = NULL;
panels = calloc (sizeof (Panel), LIMIT);
if (!panels) return false;
n_panels = 0;
menu_pos = 0;
panels[n_panels].text = strdup ("");
panels[n_panels].type = PANEL_TYPE_MENU;
panels[n_panels].refresh = true;
n_panels++;
addPanelFrame (PANEL_TITLE_SYMBOLS, PANEL_CMD_SYMBOLS);
addPanelFrame (PANEL_TITLE_STACK, PANEL_CMD_STACK);
addPanelFrame (PANEL_TITLE_REGISTERS, PANEL_CMD_REGISTERS);
addPanelFrame (PANEL_TITLE_REGISTERREFS, PANEL_CMD_REGISTERREFS);
addPanelFrame (PANEL_TITLE_DISASSEMBLY, PANEL_CMD_DISASSEMBLY);
2016-11-22 01:58:52 +01:00
curnode = 1;
return true;
}
// damn singletons.. there should be only one screen and therefor
// only one visual instance of the graph view. refactoring this
// into a struct makes the code to reference pointers unnecesarily
// we can look for a non-global solution here in the future if
// necessary
2015-08-31 11:53:03 +02:00
static void r_core_panels_refresh(RCore *core) {
char title[1024];
const char *color = curnode? core->cons->pal.graph_box : core->cons->pal.graph_box2;
2015-08-31 11:53:03 +02:00
char str[1024];
int i, j, h, w = r_cons_get_size (&h);
r_cons_gotoxy (0, 0);
if (!can) {
return;
}
if (isResizing) {
isResizing = false;
r_cons_canvas_resize (can, w, h);
refreshAll ();
}
2016-11-22 01:58:52 +01:00
#if 0
/* avoid flickering */
r_cons_canvas_clear (can);
r_cons_flush ();
2016-11-22 01:58:52 +01:00
#endif
if (panels) {
panels[menu_pos].x = (menu_y > 0) ? menu_x * 6 : w;
panels[menu_pos].y = 1;
free (panels[menu_pos].text);
2017-03-24 10:46:13 +01:00
panels[menu_pos].text = calloc (1, 1024); // r_str_newf ("%d", menu_y);
int maxsub = 0;
for (i = 0; menus_sub[i]; i++) {
maxsub = i;
}
if (menu_x < 0) {
menu_x = 0;
}
if (menu_x > maxsub) {
menu_x = maxsub;
}
if (menu_x >= 0 && menu_x <= maxsub && menus_sub[menu_x]) {
for (j = 0; menus_sub[menu_x][j]; j++) {
if (menu_y - 1 == j) {
strcat (panels[menu_pos].text, "> ");
} else {
strcat (panels[menu_pos].text, " ");
}
strcat (panels[menu_pos].text, menus_sub[menu_x][j]);
strcat (panels[menu_pos].text, " \n");
}
}
for (i = 0; i < n_panels; i++) {
2015-08-31 11:53:03 +02:00
if (i != curnode) {
Panel_print (can, &panels[i], 0);
2015-08-31 11:53:03 +02:00
}
}
}
2018-03-26 13:42:39 +02:00
if (panels && n_panels > 1) {
// always refresh first panel or can be trashed
panels[1].refresh = true;
}
if (menu_y) {
2015-03-12 15:16:38 -04:00
curnode = menu_pos;
}
2017-07-26 18:46:22 +02:00
if (panels) {
if (panels[curnode].type == PANEL_TYPE_MENU) {
panels[curnode].refresh = true;
Panel_print (can, &panels[curnode], menu_y);
} else {
Panel_print (can, &panels[curnode], 1);
2017-07-26 18:46:22 +02:00
}
}
(void) r_cons_canvas_gotoxy (can, -can->sx, -can->sy);
title[0] = 0;
2016-10-26 23:16:31 +02:00
if (curnode == 0) {
strcpy (title, "> ");
2016-10-26 23:16:31 +02:00
}
for (i = 0; menus[i]; i++) {
if (menu_x == i) {
snprintf (str, sizeof (title) - 1, "%s[%s]"Color_RESET, color, menus[i]);
} else {
snprintf (str, sizeof (title) - 1, "%s %s "Color_RESET, color, menus[i]);
}
strcat (title, str);
}
2016-10-26 23:16:31 +02:00
if (curnode == 0) {
r_cons_canvas_write (can, Color_BLUE);
r_cons_canvas_write (can, title);
r_cons_canvas_write (can, Color_RESET);
} else {
r_cons_canvas_write (can, Color_RESET);
r_cons_canvas_write (can, title);
}
snprintf (title, sizeof (title) - 1,
"[0x%08"PFMT64x "]", core->offset);
(void) r_cons_canvas_gotoxy (can, -can->sx + w - strlen (title), -can->sy);
r_cons_canvas_write (can, title);
r_cons_canvas_print (can);
r_cons_flush ();
}
static void doRefresh(RCore *core) {
isResizing = true;
Layout_run (panels);
r_core_panels_refresh (core);
}
2015-08-31 11:53:03 +02:00
static int havePanel(const char *s) {
int i;
2016-10-26 23:16:31 +02:00
if (!panels || !panels[0].text) {
2015-08-31 11:53:03 +02:00
return 0;
2016-10-26 23:16:31 +02:00
}
2015-08-31 11:53:03 +02:00
// add new panel for testing
2016-10-26 23:16:31 +02:00
for (i = 1; panels[i].text; i++) {
if (!strcmp (panels[i].text, s)) {
2015-08-31 11:53:03 +02:00
return 1;
}
}
return 0;
}
static void panel_single_step_in(RCore *core) {
if (r_config_get_i (core->config, "cfg.debug")) {
if (core->print->cur_enabled) {
// dcu 0xaddr
r_core_cmdf (core, "dcu 0x%08"PFMT64x, core->offset + core->print->cur);
core->print->cur_enabled = 0;
} else {
r_core_cmd (core, "ds", 0);
r_core_cmd (core, ".dr*", 0);
}
} else {
r_core_cmd (core, "aes", 0);
r_core_cmd (core, ".ar*", 0);
}
}
static void panel_single_step_over(RCore *core) {
if (r_config_get_i (core->config, "cfg.debug")) {
if (core->print->cur_enabled) {
r_core_cmd (core, "dcr", 0);
core->print->cur_enabled = 0;
} else {
r_core_cmd (core, "dso", 0);
r_core_cmd (core, ".dr*", 0);
}
} else {
r_core_cmd (core, "aeso", 0);
r_core_cmd (core, ".ar*", 0);
}
}
static void panel_breakpoint(RCore *core) {
r_core_cmd (core, "dbs $$", 0);
}
static void panel_continue(RCore *core) {
r_core_cmd (core, "dc", 0);
}
2018-02-21 19:49:54 +08:00
static bool init (RCore *core, int w, int h) {
layout = 0;
_core = core;
menu_pos = 0;
menu_x = 0;
callgraph = 0;
isResizing = false;
can = r_cons_canvas_new (w, h);
if (!can) {
eprintf ("Cannot create RCons.canvas context\n");
return false;
}
can->linemode = r_config_get_i (core->config, "graph.linemode");
can->color = r_config_get_i (core->config, "scr.color");
2016-05-09 11:13:37 +02:00
if (w < 140) {
columnWidth = w / 3;
}
if (!initPanel ()) {
return false;
}
2018-02-21 19:49:54 +08:00
return true;
}
R_API int r_core_visual_panels(RCore *core) {
int okey, key, wheel;
int w, h;
int asm_comments = 0;
int asm_bytes = 0;
int have_utf8 = 0;
w = r_cons_get_size (&h);
2018-02-21 19:49:54 +08:00
if (!init (core, w, h)) {
return false;
}
asm_comments = r_config_get_i (core->config, "asm.comments");
asm_bytes = r_config_get_i (core->config, "asm.bytes");
have_utf8 = r_config_get_i (core->config, "scr.utf8");
r_config_set_i (core->config, "asm.comments", 0);
r_config_set_i (core->config, "asm.bytes", 0);
r_config_set_i (core->config, "scr.utf8", 1);
repeat:
core->cons->event_data = core;
// core->cons->event_resize = (RConsEvent) r_core_panels_refresh;
core->cons->event_resize = (RConsEvent) doRefresh;
Layout_run (panels);
r_core_panels_refresh (core);
wheel = r_config_get_i (core->config, "scr.wheel");
2016-11-22 01:58:52 +01:00
if (wheel) {
2015-09-14 12:35:38 +02:00
r_cons_enable_mouse (true);
2016-11-22 01:58:52 +01:00
}
// r_core_graph_inputhandle()
okey = r_cons_readchar ();
key = r_cons_arrow_to_hjkl (okey);
const char *cmd;
switch (key) {
case 'u':
r_core_cmd0 (core, "s-");
break;
case 'U':
r_core_cmd0 (core, "s+");
break;
case 'n':
{
r_cons_enable_mouse (false);
char *res = r_cons_input ("New panel with command: ");
if (res) {
if (*res) {
addPanelFrame (res, res);
// do not refresh stuff
}
free (res);
}
r_cons_enable_mouse (true);
}
break;
case 'N':
{
r_cons_enable_mouse (false);
char *res = r_cons_input ("New panel with command: ");
if (res) {
if (*res) {
addPanelFrame (NULL, res);
}
free (res);
}
r_cons_enable_mouse (true);
}
break;
case 'p':
r_core_cmd0 (core, "sp");
break;
case 'P':
r_core_cmd0 (core, "sn");
break;
case '.':
if (r_config_get_i (core->config, "cfg.debug")) {
2015-10-31 01:57:52 +01:00
r_core_cmd0 (core, "sr PC");
2017-03-24 10:46:13 +01:00
// r_core_seek (core, r_num_math (core->num, "entry0"), 1);
} else {
r_core_cmd0 (core, "s entry0; px");
}
doRefresh (core);
break;
case ' ':
case '\r':
case '\n':
if (curnode == 0 && menu_y) {
const char *action = menus_sub[menu_x][menu_y - 1];
if (strstr (action, "New")) {
addPanelFrame (PANEL_TITLE_NEWFILES, "o");
} else if (strstr (action, "Open")) {
/* XXX doesnt autocompletes filenames */
r_cons_enable_mouse (false);
char *res = r_cons_input ("open file: ");
2015-08-31 11:53:03 +02:00
if (res) {
if (*res) {
2015-08-31 11:53:03 +02:00
r_core_cmdf (core, "o %s", res);
}
2015-08-31 11:53:03 +02:00
free (res);
}
r_cons_enable_mouse (true);
} else if (strstr (action, "RegisterRefs")) {
addPanelFrame ("drr", "drr");
} else if (strstr (action, "Registers")) {
addPanelFrame ("dr=", "dr=");
} else if (strstr (action, "Info")) {
addPanelFrame (PANEL_TITLE_INFO, "i");
} else if (strstr (action, "Database")) {
addPanelFrame (PANEL_TITLE_DATABASE, "k ***");
} else if (strstr (action, "Registers")) {
2015-08-31 11:53:03 +02:00
if (!havePanel ("Registers")) {
addPanelFrame (PANEL_TITLE_REGISTERS, "dr=");
}
2015-08-31 11:53:03 +02:00
} else if (strstr (action, "About")) {
char *s = r_core_cmd_str (core, "?V");
r_cons_message (s);
free (s);
} else if (strstr (action, "Hexdump")) {
addPanelFrame (PANEL_TITLE_HEXDUMP, "px 512");
} else if (strstr (action, "Disassembly")) {
addPanelFrame (PANEL_TITLE_DISASSEMBLY, "pd 128");
} else if (strstr (action, "Functions")) {
addPanelFrame (PANEL_TITLE_FUNCTIONS, "afl");
2015-08-31 05:43:38 +02:00
} else if (strstr (action, "Comments")) {
addPanelFrame (PANEL_TITLE_COMMENTS, "CC");
2015-08-31 05:43:38 +02:00
} else if (strstr (action, "Entropy")) {
addPanelFrame (PANEL_TITLE_ENTROPY, "p=e");
} else if (strstr (action, "Function")) {
r_core_cmdf (core, "af");
2015-08-31 11:53:03 +02:00
} else if (strstr (action, "DRX")) {
addPanelFrame (PANEL_TITLE_DRX, "drx");
} else if (strstr (action, "Program")) {
r_core_cmdf (core, "aaa");
} else if (strstr (action, "Calls")) {
r_core_cmdf (core, "aac");
2015-08-31 11:53:03 +02:00
} else if (strstr (action, "ROP")) {
r_cons_enable_mouse (false);
2015-08-31 11:53:03 +02:00
char *res = r_cons_input ("rop grep: ");
if (res) {
2016-05-09 11:13:37 +02:00
r_core_cmdf (core, "\"/R %s\"", res);
2015-08-31 11:53:03 +02:00
free (res);
}
r_cons_enable_mouse (true);
2015-08-31 11:53:03 +02:00
} else if (strstr (action, "String")) {
r_cons_enable_mouse (false);
2015-08-31 11:53:03 +02:00
char *res = r_cons_input ("search string: ");
if (res) {
2016-05-09 11:13:37 +02:00
r_core_cmdf (core, "\"/ %s\"", res);
2015-08-31 11:53:03 +02:00
free (res);
}
r_cons_enable_mouse (true);
2015-08-31 11:53:03 +02:00
} else if (strstr (action, "Hexpairs")) {
r_cons_enable_mouse (false);
2015-08-31 11:53:03 +02:00
char *res = r_cons_input ("search hexpairs: ");
if (res) {
2016-05-09 11:13:37 +02:00
r_core_cmdf (core, "\"/x %s\"", res);
2015-08-31 11:53:03 +02:00
free (res);
}
r_cons_enable_mouse (true);
2015-08-31 11:53:03 +02:00
} else if (strstr (action, "Code")) {
r_cons_enable_mouse (false);
2015-08-31 11:53:03 +02:00
char *res = r_cons_input ("search code: ");
if (res) {
2016-05-09 11:13:37 +02:00
r_core_cmdf (core, "\"/c %s\"", res);
2015-08-31 11:53:03 +02:00
free (res);
}
r_cons_enable_mouse (true);
} else if (strstr (action, "Copy")) {
r_cons_enable_mouse (false);
char *res = r_cons_input ("How many bytes? ");
if (res) {
2016-05-09 11:13:37 +02:00
r_core_cmdf (core, "\"y %s\"", res);
free (res);
}
r_cons_enable_mouse (true);
} else if (strstr (action, "Write String")) {
r_cons_enable_mouse (false);
char *res = r_cons_input ("insert string: ");
if (res) {
2016-05-09 11:13:37 +02:00
r_core_cmdf (core, "\"w %s\"", res);
free (res);
}
r_cons_enable_mouse (true);
} else if (strstr (action, "Write Value")) {
r_cons_enable_mouse (false);
char *res = r_cons_input ("insert number: ");
if (res) {
2016-05-09 11:13:37 +02:00
r_core_cmdf (core, "\"wv %s\"", res);
free (res);
}
r_cons_enable_mouse (true);
} else if (strstr (action, "Write Hex")) {
r_cons_enable_mouse (false);
char *res = r_cons_input ("insert hexpairs: ");
if (res) {
2016-05-09 11:13:37 +02:00
r_core_cmdf (core, "\"wx %s\"", res);
free (res);
}
r_cons_enable_mouse (true);
} else if (strstr (action, "Calculator")) {
r_cons_enable_mouse (false);
for (;;) {
char *s = r_cons_input ("> ");
2015-08-31 00:42:21 -04:00
if (!s || !*s) {
free (s);
break;
2015-08-31 00:42:21 -04:00
}
r_core_cmdf (core, "? %s", s);
r_cons_flush ();
free (s);
}
r_cons_enable_mouse (true);
} else if (strstr (action, "Assemble")) {
r_core_visual_asm (core, core->offset);
} else if (strstr (action, "Sections")) {
addPanelFrame (PANEL_TITLE_SECTIONS, "iSq");
} else if (strstr (action, "Close")) {
r_core_cmd0 (core, "o-*");
} else if (strstr (action, "Strings")) {
addPanelFrame (PANEL_TITLE_STRINGS, "izq");
} else if (strstr (action, "Maps")) {
addPanelFrame (PANEL_TITLE_MAPS, "dm");
2016-11-22 01:58:52 +01:00
} else if (strstr (action, "Modules")) {
addPanelFrame (PANEL_TITLE_MODULES, "dmm");
} else if (strstr (action, "Backtrace")) {
addPanelFrame (PANEL_TITLE_BACKTRACE, "dbt");
2016-11-22 01:58:52 +01:00
} else if (strstr (action, "Step")) {
r_core_cmd (core, "ds", 0);
r_cons_flush ();
} else if (strstr (action, "Step Over")) {
r_core_cmd (core, "dso", 0);
r_cons_flush ();
} else if (strstr (action, "Continue")) {
r_core_cmd (core, "dc", 0);
r_cons_flush ();
} else if (strstr (action, "Breakpoints")) {
addPanelFrame (PANEL_TITLE_BREAKPOINTS, "db");
} else if (strstr (action, "Symbols")) {
addPanelFrame (PANEL_TITLE_SYMBOLS, "isq");
} else if (strstr (action, "Imports")) {
addPanelFrame (PANEL_TITLE_IMPORTS, "iiq");
} else if (strstr (action, "Paste")) {
r_core_cmd0 (core, "yy");
} else if (strstr (action, "Clipboard")) {
addPanelFrame (PANEL_TITLE_CLIPBOARD, "yx");
} else if (strstr (action, "io.cache")) {
r_core_cmd0 (core, "e!io.cache");
} else if (strstr (action, "Fill")) {
2017-03-24 10:46:13 +01:00
r_cons_enable_mouse (false);
char *s = r_cons_input ("Fill with: ");
r_core_cmdf (core, "wow %s", s);
free (s);
2017-03-24 10:46:13 +01:00
r_cons_enable_mouse (true);
} else if (strstr (action, "References")) {
r_core_cmdf (core, "aar");
2015-08-31 05:43:38 +02:00
} else if (strstr (action, "FcnInfo")) {
addPanelFrame (PANEL_TITLE_FCNINFO, "afi");
} else if (strstr (action, "Graph")) {
r_core_visual_graph (core, NULL, NULL, true);
// addPanelFrame ("Graph", "agf");
2015-08-31 05:43:38 +02:00
} else if (strstr (action, "System Shell")) {
r_cons_set_raw (0);
r_cons_flush ();
2015-08-31 05:43:38 +02:00
r_sys_cmd ("$SHELL");
} else if (strstr (action, "R2 Shell")) {
2015-09-14 12:35:38 +02:00
core->vmode = false;
r_core_visual_prompt_input (core);
2015-09-14 12:35:38 +02:00
core->vmode = true;
} else if (!strcmp (action, "2048")) {
2016-05-26 17:58:02 +03:00
r_cons_2048 (can->color);
} else if (strstr (action, "License")) {
2016-12-21 00:36:38 +01:00
r_cons_message ("Copyright 2006-2016 - pancake - LGPL");
} else if (strstr (action, "Fortune")) {
char *s = r_core_cmd_str (core, "fo");
r_cons_message (s);
free (s);
} else if (strstr (action, "Commands")) {
r_core_cmd0 (core, "?;?@?;?$?;???");
r_cons_any_key (NULL);
} else if (strstr (action, "Colors")) {
r_core_cmd0 (core, "e!scr.color");
} else if (strstr (action, "Quit")) {
goto beach;
}
} else {
2016-11-22 01:58:52 +01:00
if (curnode > 0) {
zoom ();
} else {
menu_y = 1;
}
}
doRefresh (core);
break;
case '?':
r_cons_clear00 ();
r_cons_printf ("Visual Ascii Art Panels:\n"
" ! - run r2048 game\n"
" . - seek to PC or entrypoint\n"
" : - run r2 command in prompt\n"
" _ - start the hud input mode\n"
" ? - show this help\n"
" x - close current panel\n"
" m - open menubar\n"
" V - view graph\n"
" C - toggle color\n"
" M - open new custom frame\n"
" hl - toggle scr.color\n"
" HL - move vertical column split\n"
" jk - scroll/select menu\n"
" JK - select prev/next panels (same as TAB)\n"
" sS - step in / step over\n"
" uU - undo / redo seek\n"
" pP - seek to next or previous scr.nkey\n"
" nN - create new panel with given command\n"
" q - quit, back to visual mode\n"
);
r_cons_flush ();
r_cons_any_key (NULL);
break;
case 's':
if (r_config_get_i (core->config, "cfg.debug")) {
2017-03-24 10:46:13 +01:00
r_core_cmd0 (core, "ds;.dr*"); // ;sr PC");
} else {
panel_single_step_in (core);
}
refreshAll ();
break;
case 'S':
if (r_config_get_i (core->config, "cfg.debug")) {
2017-03-24 10:46:13 +01:00
r_core_cmd0 (core, "dso;.dr*"); // ;sr PC");
} else {
panel_single_step_over (core);
}
refreshAll ();
break;
case ':':
2015-09-14 12:35:38 +02:00
core->vmode = false;
r_core_visual_prompt_input (core);
2015-09-14 12:35:38 +02:00
core->vmode = true;
// FIX: Issue with visual mode instruction highlighter
// not updating after 'ds' or 'dcu' commands.
r_core_cmd0 (core, ".dr*");
doRefresh (core);
break;
case 'C':
can->color = !can->color;
2017-03-24 10:46:13 +01:00
// r_config_toggle (core->config, "scr.color");
// refresh graph
doRefresh (core);
break;
case 'R':
2016-11-22 01:58:52 +01:00
if (r_config_get_i (core->config, "scr.randpal")) {
r_core_cmd0 (core, "ecr");
} else {
r_core_cmd0 (core, "ecn");
}
doRefresh (core);
break;
case 'j':
panels[curnode].refresh = true;
2016-11-22 01:58:52 +01:00
if (curnode == 0) {
if (panels[curnode].type == PANEL_TYPE_MENU) {
if (menus_sub[menu_x][menu_y]) {
menu_y++;
}
}
} else {
if (curnode == 1) {
int cols = core->print->cols;
RAnalFunction *f = NULL;
RAsmOp op;
f = r_anal_get_fcn_in (core->anal, core->offset, 0);
op.size = 1;
if (f && f->folded) {
cols = core->offset - f->addr + r_anal_fcn_size (f);
} else {
r_asm_set_pc (core->assembler, core->offset);
cols = r_asm_disassemble (core->assembler,
&op, core->block, 32);
}
if (cols < 1) {
cols = op.size > 1 ? op.size : 1;
}
r_core_seek (core, core->offset + cols, 1);
r_core_block_read (core);
} else {
panels[curnode].sy++;
}
}
break;
case 'k':
panels[curnode].refresh = true;
if (curnode == 0) {
if (panels[curnode].type == PANEL_TYPE_MENU) {
menu_y--;
if (menu_y < 0) {
menu_y = 0;
}
}
} else {
if (curnode == 1) {
r_core_cmd0 (core, "s-8");
} else {
if (panels[curnode].sy > 0) {
panels[curnode].sy--;
}
}
}
break;
2015-08-31 13:57:39 +02:00
case '_':
r_core_visual_hud (core);
break;
case 'x':
2016-10-26 23:16:31 +02:00
delcurpanel ();
refreshAll ();
break;
case 9: // TAB
case 'J':
menu_y = 0;
menu_x = -1;
panels[curnode].refresh = true;
curnode++;
panels[curnode].refresh = true;
if (!panels[curnode].text) {
curnode = 0;
menu_x = 0;
}
break;
case 'Z': // SHIFT-TAB
case 'K':
menu_y = 0;
menu_x = -1;
panels[curnode].refresh = true;
curnode--;
panels[curnode].refresh = true;
2016-10-26 23:16:31 +02:00
if (curnode < 0) {
curnode = n_panels - 1;
}
if (!curnode) {
menu_x = 0;
}
break;
case 'M':
{
r_cons_enable_mouse (false);
char *name = r_cons_input ("Name: ");
char *cmd = r_cons_input ("Command: ");
if (name && *name && cmd && *cmd) {
addPanelFrame (name, cmd);
}
free (name);
free (cmd);
r_cons_enable_mouse (true);
}
break;
case 'm':
curnode = 0;
2016-10-26 23:16:31 +02:00
if (menu_x < 0) {
menu_x = 0;
r_core_panels_refresh (core);
}
menu_y = 1;
break;
case 'H':
columnWidth += 4;
isResizing = true;
break;
case 'L':
columnWidth -= 4;
isResizing = true;
if (columnWidth < 0) {
columnWidth = 0;
}
break;
case 'h':
panels[curnode].refresh = true;
if (curnode == 0) {
if (menu_x) {
menu_x--;
menu_y = menu_y? 1: 0;
r_core_panels_refresh (core);
}
} else {
panels[curnode].sx--;
}
break;
case 'l':
panels[curnode].refresh = true;
if (curnode == 0) {
if (menus[menu_x + 1]) {
menu_x++;
menu_y = menu_y? 1: 0;
r_core_panels_refresh (core);
}
} else {
panels[curnode].sx++;
}
break;
case 'V':
/* copypasta from visual.c */
if (r_config_get_i (core->config, "graph.web")) {
r_core_cmd0 (core, "agv $$");
} else {
RAnalFunction *fun = r_anal_get_fcn_in (core->anal, core->offset, R_ANAL_FCN_TYPE_NULL);
int ocolor;
if (!fun) {
r_cons_message ("Not in a function. Type 'df' to define it here");
break;
} else if (r_list_empty (fun->bbs)) {
r_cons_message ("No basic blocks in this function. You may want to use 'afb+'.");
break;
}
ocolor = r_config_get_i (core->config, "scr.color");
r_core_visual_graph (core, NULL, NULL, true);
r_config_set_i (core->config, "scr.color", ocolor);
}
break;
2016-11-22 01:58:52 +01:00
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 'w':
layout++;
if (layout >= layoutCount) {
layout = 0;
}
refreshAll ();
2016-11-22 01:58:52 +01:00
break;
case R_CONS_KEY_F1:
cmd = r_config_get (core->config, "key.f1");
if (cmd && *cmd) {
key = r_core_cmd0 (core, cmd);
}
break;
case R_CONS_KEY_F2:
cmd = r_config_get (core->config, "key.f2");
if (cmd && *cmd) {
key = r_core_cmd0 (core, cmd);
} else {
panel_breakpoint (core);
}
break;
case R_CONS_KEY_F3:
cmd = r_config_get (core->config, "key.f3");
if (cmd && *cmd) {
key = r_core_cmd0 (core, cmd);
}
break;
case R_CONS_KEY_F4:
cmd = r_config_get (core->config, "key.f4");
if (cmd && *cmd) {
key = r_core_cmd0 (core, cmd);
}
break;
case R_CONS_KEY_F5:
cmd = r_config_get (core->config, "key.f5");
if (cmd && *cmd) {
key = r_core_cmd0 (core, cmd);
}
break;
case R_CONS_KEY_F6:
cmd = r_config_get (core->config, "key.f6");
if (cmd && *cmd) {
key = r_core_cmd0 (core, cmd);
}
break;
case R_CONS_KEY_F7:
cmd = r_config_get (core->config, "key.f7");
if (cmd && *cmd) {
key = r_core_cmd0 (core, cmd);
} else {
panel_single_step_in (core);
}
break;
case R_CONS_KEY_F8:
cmd = r_config_get (core->config, "key.f8");
if (cmd && *cmd) {
key = r_core_cmd0 (core, cmd);
} else {
panel_single_step_over (core);
}
break;
case R_CONS_KEY_F9:
cmd = r_config_get (core->config, "key.f9");
if (cmd && *cmd) {
key = r_core_cmd0 (core, cmd);
} else {
panel_continue (core);
}
break;
case R_CONS_KEY_F10:
cmd = r_config_get (core->config, "key.f10");
if (cmd && *cmd) {
key = r_core_cmd0 (core, cmd);
}
break;
case R_CONS_KEY_F11:
cmd = r_config_get (core->config, "key.f11");
if (cmd && *cmd) {
key = r_core_cmd0 (core, cmd);
}
break;
case R_CONS_KEY_F12:
cmd = r_config_get (core->config, "key.f12");
if (cmd && *cmd) {
key = r_core_cmd0 (core, cmd);
}
break;
case '!':
case 'q':
2015-03-23 14:45:31 +01:00
case -1: // EOF
if (menu_y < 1) {
goto beach;
}
menu_y = 0;
break;
2015-08-31 05:43:38 +02:00
#if 0
case 27: // ESC
if (r_cons_readchar () == 91) {
if (r_cons_readchar () == 90) {}
}
break;
2015-08-31 05:43:38 +02:00
#endif
default:
2017-03-24 10:46:13 +01:00
// eprintf ("Key %d\n", key);
// sleep (1);
break;
}
goto repeat;
beach:
free (panels);
2015-05-31 17:33:07 +03:00
r_config_set_i (core->config, "scr.color", can->color);
free (can);
r_config_set_i (core->config, "asm.comments", asm_comments);
r_config_set_i (core->config, "asm.bytes", asm_bytes);
r_config_set_i (core->config, "scr.utf8", have_utf8);
2015-09-14 12:35:38 +02:00
return true;
}