radare2/libr/core/panels.c
2019-02-17 12:25:58 +01:00

3698 lines
95 KiB
C

/* Copyright radare2 2014-2019 - Author: pancake, vane11ope */
// pls move the typedefs into roons and rename it -> RConsPanel
#include <r_core.h>
#define PANEL_NUM_LIMIT 64
#define PANEL_TITLE_SYMBOLS "Symbols"
#define PANEL_TITLE_STACK "Stack"
#define PANEL_TITLE_STACKREFS "StackRefs"
#define PANEL_TITLE_REGISTERS "Registers"
#define PANEL_TITLE_REGISTERREFS "RegisterRefs"
#define PANEL_TITLE_DISASSEMBLY "Disassembly"
#define PANEL_TITLE_PSEUDO "Pseudo"
#define PANEL_TITLE_GRAPH "Graph"
#define PANEL_TITLE_FUNCTIONS "Functions"
#define PANEL_TITLE_FCNINFO "FcnInfo"
#define PANEL_CMD_SYMBOLS "isq"
#define PANEL_CMD_STACK "px 256@r:SP"
#define PANEL_CMD_STACKREFS "pxr 256@r:SP"
#define PANEL_CMD_LOCALS "afvd"
#define PANEL_CMD_REGISTERS "dr="
#define PANEL_CMD_REGISTERREFS "drr"
#define PANEL_CMD_DISASSEMBLY "pd $r"
#define PANEL_CMD_PSEUDO "pdc"
#define PANEL_CMD_GRAPH "agf"
#define PANEL_CMD_FUNCTIONS "afl"
#define PANEL_CMD_FCNINFO "afi"
#define PANEL_CMD_HEXDUMP "xc"
#define PANEL_CONFIG_MENU_MAX 64
#define PANEL_CONFIG_PAGE 10
#define PANEL_CONFIG_SIDEPANEL_W 60
#define PANEL_CONFIG_RESIZE_W 4
#define PANEL_CONFIG_RESIZE_H 4
typedef enum {
LEFT,
RIGHT,
UP,
DOWN
} Direction;
static const char *menus[] = {
"File", "Edit", "View", "Tools", "Search", "Debug", "Analyze", "Help",
NULL
};
static const char *menus_File[] = {
"New", "Open", "ReOpen", "Close", "Sections", "Strings", "Symbols", "Imports", "Info", "Database", "Save Layout", "Load Layout", "Quit",
NULL
};
static const char *menus_ReOpen[] = {
"In RW", "In Debugger",
NULL
};
static const char *menus_loadLayout[] = {
"Saved", "Default",
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[] = {
"Hexdump", "Disassembly", "Graph", "FcnInfo", "Functions", "Breakpoints", "Comments", "Entropy", "Colors",
"Stack", "StackRefs", "Pseudo", "Var READ address", "Var WRITE address",
NULL
};
static const char *menus_Tools[] = {
"Calculator", "R2 Shell", "System Shell",
NULL
};
static const char *menus_Search[] = {
"String", "ROP", "Code", "Hexpairs",
NULL
};
static const char *menus_Debug[] = {
"Registers", "RegisterRefs", "DRX", "Breakpoints", "Watchpoints",
"Maps", "Modules", "Backtrace", "Locals", "Continue",
"Step", "Step Over", "Reload",
NULL
};
static const char *menus_Analyze[] = {
"Function", "Symbols", "Program", "BasicBlocks", "Calls", "References",
NULL
};
static const char *menus_Help[] = {
"Fortune", "Commands", "2048", "License", "Lock Screen", "About",
NULL
};
static const char *help_msg_panels[] = {
"|", "split the current panel vertically",
"-", "split the current panel horizontally",
":", "run r2 command in prompt",
"_", "start the hud input mode",
"?", "show this help",
"??", "show the user-friendly hud",
"!", "run r2048 game",
".", "seek to PC or entrypoint",
"*", "show pseudo code/r2dec in the current panel",
"/", "highlight the keyword",
"(", "toggle snow",
"[1-9]", "follow jmp/call identified by shortcut (like ;[1])",
"' '", "(space) toggle graph / panels",
"tab", "go to the next panel",
"b", "browse symbols, flags, configurations, classes, ...",
"c", "toggle cursor",
"C", "toggle color",
"d", "define in the current address. Same as Vd",
"D", "show disassembly in the current panel",
"e", "change title and command of current panel",
"g", "show graph in the current panel",
"i", "insert hex",
"hjkl", "move around (left-down-up-right)",
"J", "scroll panels down by page",
"K", "scroll panels up by page",
"m", "select the menu panel",
"M", "open new custom frame",
"nN", "create new panel with given command",
"o", "go/seek to given offset",
"pP", "seek to next or previous scr.nkey",
"q", "quit, back to visual mode",
"r", "toggle jmphints/leahints",
"sS", "step in / step over",
"uU", "undo / redo seek",
"w", "start Window mode",
"V", "go to the graph mode",
"X", "close current panel",
"z", "swap current panel with the first one",
NULL
};
static const char *help_msg_panels_window[] = {
"?", "show this help",
"??", "show the user-friendly hud",
"Enter", "start Zoom mode",
"c", "toggle cursor",
"hjkl", "move around (left-down-up-right)",
"JK", "resize panels vertically",
"HL", "resize panels horizontally",
"q", "quit Window mode",
NULL
};
static const char *help_msg_panels_zoom[] = {
"?", "show this help",
"??", "show the user-friendly hud",
":", "run r2 command in prompt",
"Enter", "quit Zoom mode",
"tab", "go to the next panel",
"hjkl", "move around (left-down-up-right)",
"sS", "step in / step over",
"X", "close current panel",
"q", "quit Zoom mode",
NULL
};
static void layoutDefault(RPanels *panels);
static int layoutSidePanel(void *user);
static void changePanelNum(RPanels *panels, int now, int after);
static void splitPanelVertical(RCore *core);
static void splitPanelHorizontal(RCore *core);
static void panelPrint(RCore *core, RConsCanvas *can, RPanel *panel, int color);
static void menuPanelPrint(RConsCanvas *can, RPanel *panel, int x, int y, int w, int h);
static void defaultPanelPrint(RCore *core, RConsCanvas *can, RPanel *panel, int x, int y, int w, int h, int color);
static void panelAllClear(RPanels *panels);
static bool checkPanelNum(RPanels *panels);
static void addPanelFrame(RCore *core, const char *title, const char *cmd, const bool caching);
static bool checkFunc(RCore *core);
static char *handleCacheCmdStr(RCore *core, RPanel* panel);
static void activateCursor(RCore *core);
static void cursorLeft(RCore *core);
static void cursorRight(RCore *core);
static void cursorDown(RCore *core);
static void cursorUp(RCore *core);
static int cursorThreshold(RPanel* panel);
static void delPanel(RPanels *panels, int delPanelNum);
static void delCurPanel(RPanels *panels);
static void delInvalidPanels(RPanels *panels);
static void fixBlockSize(RCore *core);
static void dismantlePanel(RPanels *panels);
static void doPanelsRefresh(RCore *core);
static void doPanelsRefreshOneShot(RCore *core);
static void refreshCoreOffset (RCore *core);
static bool handleZoomMode(RCore *core, const int key);
static bool handleWindowMode(RCore *core, const int key);
static bool handleCursorMode(RCore *core, const int key);
static void resizePanelLeft(RPanels *panels);
static void resizePanelRight(RPanels *panels);
static void resizePanelUp(RPanels *panels);
static void resizePanelDown(RPanels *panels);
static void fitToCanvas(RPanels *panels);
static void handleTabKey(RCore *core, bool shift);
static int openMenuCb(void *user);
static int openFileCb(void *user);
static int rwCb(void *user);
static int debuggerCb(void *user);
static int loadLayoutSavedCb(void *user);
static int loadLayoutDefaultCb(void *user);
static int closeFileCb(void *user);
static int saveLayoutCb(void *user);
static int copyCb(void *user);
static int pasteCb(void *user);
static int writeStrCb(void *user);
static int writeHexCb(void *user);
static int assembleCb(void *user);
static int fillCb(void *user);
static int iocacheCb(void *user);
static int colorsCb(void *user);
static int calculatorCb(void *user);
static int r2shellCb(void *user);
static int systemShellCb(void *user);
static int stringCb(void *user);
static int ropCb(void *user);
static int codeCb(void *user);
static int hexpairsCb(void *user);
static int continueCb(void *user);
static int stepCb(void *user);
static int stepoverCb(void *user);
static int reloadCb(void *user);
static int functionCb(void *user);
static int symbolsCb(void *user);
static int programCb(void *user);
static int basicblocksCb(void *user);
static int callsCb(void *user);
static int breakpointsCb(void *user);
static int watchpointsCb(void *user);
static int referencesCb(void *user);
static int fortuneCb(void *user);
static int commandsCb(void *user);
static int gameCb(void *user);
static int licenseCb(void *user);
static int aboutCb(void *user);
static int quitCb(void *user);
static void directionDefaultCb(void *user, int direction);
static void directionDisassemblyCb(void *user, int direction);
static void directionGraphCb(void *user, int direction);
static void directionRegisterCb(void *user, int direction);
static void directionStackCb(void *user, int direction);
static void directionHexdumpCb(void *user, int direction);
static void updateDisassemblyAddr (RCore *core);
static void addMenu(RCore *core, const char *parent, const char *name, RPanelsMenuCallback cb);
static void removeMenu(RPanels *panels);
static int file_history_up(RLine *line);
static int file_history_down(RLine *line);
static void hudstuff(RCore *core);
static char *getPanelsConfigPath();
static bool init(RCore *core, RPanels *panels, int w, int h);
static void initSdb(RPanels *panels);
static bool initPanelsMenu(RCore *core);
static bool initPanels(RCore *core, RPanels *panels);
static RStrBuf *drawMenu(RPanelsMenuItem *item);
static void moveMenuCursor(RPanelsMenu *menu, RPanelsMenuItem *parent);
static void freeSinglePanel(RPanel *panel);
static void freeAllPanels(RPanels *panels);
static void panelBreakpoint(RCore *core);
static void panelContinue(RCore *core);
static void panelPrompt(const char *prompt, char *buf, int len);
static void panelSingleStepIn(RCore *core);
static void panelSingleStepOver(RCore *core);
static void setRefreshAll(RPanels *panels, bool clearCache);
static void setCursor(RCore *core, bool cur);
static void savePanelPos(RPanel* panel);
static void restorePanelPos(RPanel* panel);
static void savePanelsLayout(RCore* core, bool temp);
static int loadSavedPanelsLayout(RCore *core, bool temp);
static void replaceCmd(RPanels *panels, const char *title, const char *cmd, const bool caching);
static void swapPanels(RPanels *panels, int p0, int p1);
static bool handleMenu(RCore *core, const int key);
static void toggleZoomMode(RPanels *panels);
static void toggleWindowMode(RPanels *panels);
static void maximizePanelSize(RPanels *panels);
static void insertValue(RCore *core);
static bool moveToDirection(RPanels *panels, Direction direction);
static void showHelp(RCore *core, RPanelsMode mode);
static void createDefaultPanels(RCore *core);
static void createNewPanel(RCore *core, char *name, char *cmd, bool caching);
static void printSnow(RPanels *panels);
static void resetSnow(RPanels *panels);
static void checkEdge(RPanels *panels);
static void callVisualGraph(RCore *core);
static char *parsePanelsConfig(const char *cfg, int len);
static RPanel *getPanel(RPanels *panels, int i);
static RPanel *getCurPanel(RPanels *panels);
static RConsCanvas *createNewCanvas(RCore *core, int w, int h);
static RPanel *getPanel(RPanels *panels, int i) {
return &panels->panel[i];
}
static RPanel *getCurPanel(RPanels *panels) {
return getPanel (panels, panels->curnode);
}
static void panelPrint(RCore *core, RConsCanvas *can, RPanel *panel, int color) {
if (!can || !panel|| !panel->refresh) {
return;
}
if (can->w <= panel->pos.x || can->h <= panel->pos.y) {
return;
}
panel->refresh = false;
int w = R_MIN (can->w - panel->pos.x, panel->pos.w);
int h = R_MIN (can->h - panel->pos.y, panel->pos.h);
r_cons_canvas_fill (can, panel->pos.x, panel->pos.y, w, h, ' ');
if (panel->type == PANEL_TYPE_MENU) {
menuPanelPrint (can, panel, panel->sx, panel->sy, w, h);
} else {
defaultPanelPrint (core, can, panel, panel->sx, panel->sy, w, h, color);
}
if (color) {
r_cons_canvas_box (can, panel->pos.x, panel->pos.y, w, h, core->cons->context->pal.graph_box2);
} else {
r_cons_canvas_box (can, panel->pos.x, panel->pos.y, w, h, core->cons->context->pal.graph_box);
}
}
static void menuPanelPrint(RConsCanvas *can, RPanel *panel, int x, int y, int w, int h) {
(void) r_cons_canvas_gotoxy (can, panel->pos.x + 2, panel->pos.y + 2);
char *text = r_str_ansi_crop (panel->title, x, y, w, h);
if (text) {
r_cons_canvas_write (can, text);
free (text);
} else {
r_cons_canvas_write (can, panel->title);
}
}
static void defaultPanelPrint(RCore *core, RConsCanvas *can, RPanel *panel, int x, int y, int w, int h, int color) {
int graph_pad = 0;
char title[128], *text, *cmdStr = NULL;
if (color) {
snprintf (title, sizeof (title) - 1,
"%s[x] %s"Color_RESET, core->cons->context->pal.graph_box2, panel->title);
} else {
snprintf (title, sizeof (title) - 1,
" %s ", panel->title);
}
if (r_cons_canvas_gotoxy (can, panel->pos.x + 1, panel->pos.y + 1)) {
r_cons_canvas_write (can, title);
}
(void) r_cons_canvas_gotoxy (can, panel->pos.x + 2, panel->pos.y + 2);
if (panel->cmd) {
if (!strcmp (panel->cmd, PANEL_CMD_DISASSEMBLY)) {
ut64 o_offset = core->offset;
core->offset = panel->addr;
r_core_seek (core, panel->addr, 1);
r_core_block_read (core);
cmdStr = handleCacheCmdStr (core, panel);
core->offset = o_offset;
} else if (!strcmp (panel->cmd, PANEL_CMD_STACK)) {
const int delta = r_config_get_i (core->config, "stack.delta");
const char sign = (delta < 0)? '+': '-';
const int absdelta = R_ABS (delta);
cmdStr = r_core_cmd_strf (core, "%s%c%d", PANEL_CMD_STACK, sign, absdelta);
} else if (!strcmp (panel->cmd, PANEL_CMD_HEXDUMP)) {
ut64 o_offset = core->offset;
if (!panel->caching) {
core->offset = panel->addr;
r_core_seek (core, core->offset, 1);
}
cmdStr = handleCacheCmdStr (core, panel);
core->offset = o_offset;
} else {
cmdStr = handleCacheCmdStr (core, panel);
if (!strcmp (panel->cmd, PANEL_CMD_GRAPH)) {
graph_pad = 1;
core->cons->event_resize = NULL; // avoid running old event with new data
core->cons->event_data = core;
core->cons->event_resize = (RConsEvent) doPanelsRefreshOneShot;
}
}
}
if (y < 0) {
y = 0;
}
if (x < 0) {
char *white = (char*)r_str_pad (' ', 128);
int idx = R_MIN (-x, strlen (white) - 1);
white[idx] = 0;
text = r_str_ansi_crop (cmdStr,
0, y + graph_pad, w + x - 3, h - 2 + y);
char *newText = r_str_prefix_all (text, white);
if (newText) {
free (text);
text = newText;
}
} else {
text = r_str_ansi_crop (cmdStr,
x, y + graph_pad, w + x - 3, h - 2 + y);
}
if (text) {
r_cons_canvas_write (can, text);
free (text);
}
if (!panel->cmdStrCache) {
free (cmdStr);
}
}
char *handleCacheCmdStr(RCore *core, RPanel* panel) {
if (panel->cmdStrCache) {
return panel->cmdStrCache;
} else {
char *ret;
ret = r_core_cmd_str (core, panel->cmd);
if (panel->caching) {
panel->cmdStrCache = ret;
}
return ret;
}
}
static void panelAllClear(RPanels *panels) {
if (!panels) {
return;
}
int i;
RPanel *panel = NULL;
for (i = 0; i < panels->n_panels; i++) {
panel = getPanel (panels, i);
r_cons_canvas_fill (panels->can, panel->pos.x, panel->pos.y, panel->pos.w, panel->pos.h, ' ');
}
r_cons_canvas_print (panels->can);
r_cons_flush ();
}
R_API void r_core_panels_layout (RPanels *panels) {
panels->can->sx = 0;
panels->can->sy = 0;
layoutDefault (panels);
}
static void layoutDefault(RPanels *panels) {
int h, w = r_cons_get_size (&h);
int ph = (h - 1) / (panels->n_panels - 2);
int i;
int colpos = w - panels->columnWidth;
RPanel *p0 = getPanel (panels, 0);
RPanel *p1 = getPanel (panels, 1);
p0->pos.x = 0;
p0->pos.y = 1;
if (panels->n_panels <= 1) {
p0->pos.w = w;
p0->pos.h = h - 1;
return;
}
p0->pos.w = colpos / 2 + 1;
p0->pos.h = h - 1;
p1->pos.x = colpos / 2;
p1->pos.y = 1;
p1->pos.w = colpos / 2 + 1;
p1->pos.h = h - 1;
for (i = 2; i < panels->n_panels; i++) {
RPanel *p = getPanel (panels, i);
p->pos.x = colpos;
p->pos.y = 2 + (ph * (i - 2));
p->pos.w = w - colpos;
if (p->pos.w < 0) {
p->pos.w = 0;
}
if ((i + 1) == panels->n_panels) {
p->pos.h = h - p->pos.y;
} else {
p->pos.h = ph;
}
p->pos.y--;
p->pos.h++;
}
}
static int layoutSidePanel(void *user) {
RCore *core = (RCore *)user;
RPanels *panels = core->panels;
if (!checkPanelNum (panels)) {
return 0;
}
RPanelsMenu *menu = core->panels->panelsMenu;
RPanelsMenuItem *parent = menu->history[menu->depth - 1];
RPanelsMenuItem *child = parent->sub[parent->selectedIndex];
const char *cmd = sdb_get (panels->db, child->name, 0);
if (!cmd) {
return 0;
}
int i, h;
(void)r_cons_get_size (&h);
for (i = 0; i < panels->n_panels; i++) {
RPanel *p = getPanel (panels, i);
if (p->pos.x == 0) {
if (p->pos.w >= PANEL_CONFIG_SIDEPANEL_W) {
p->pos.x += PANEL_CONFIG_SIDEPANEL_W - 1;
p->pos.w -= PANEL_CONFIG_SIDEPANEL_W - 1;
}
}
}
bool caching = r_cons_yesno ('y', "Cache the result? (Y/n)");
addPanelFrame (core, child->name, cmd, caching);
changePanelNum (panels, panels->n_panels - 1, 0);
RPanel *p0 = getPanel (panels, 0);
p0->pos.x = 0;
p0->pos.y = 1;
p0->pos.w = PANEL_CONFIG_SIDEPANEL_W;
p0->pos.h = h - 1;
panels->curnode = 0;
setRefreshAll (panels, false);
return 0;
}
static void splitPanelVertical(RCore *core) {
RPanels *panels = core->panels;
if (!checkPanelNum (panels)) {
return;
}
RPanel *cur = getCurPanel (panels);
RPanel *next = getPanel (panels, panels->curnode + 1);
const int owidth = cur->pos.w;
addPanelFrame (core, cur->title, cur->cmd, cur->caching);
changePanelNum (panels, panels->n_panels - 1, panels->curnode + 1);
cur->pos.w = owidth / 2 + 1;
next->pos.x = cur->pos.x + cur->pos.w - 1;
next->pos.y = cur->pos.y;
next->pos.w = owidth - cur->pos.w + 1;
next->pos.h = cur->pos.h;
setRefreshAll (panels, false);
}
static void splitPanelHorizontal(RCore *core) {
RPanels *panels = core->panels;
if (!checkPanelNum (panels)) {
return;
}
RPanel *cur = getCurPanel (panels);
RPanel *next = getPanel (panels, panels->curnode + 1);
const int oheight = cur->pos.h;
cur->curpos = 0;
addPanelFrame (core, cur->title, cur->cmd, cur->caching);
changePanelNum (panels, panels->n_panels - 1, panels->curnode + 1);
cur->pos.h = oheight / 2 + 1;
next->pos.x = cur->pos.x;
next->pos.y = cur->pos.y + cur->pos.h - 1;
next->pos.w = cur->pos.w;
next->pos.h = oheight - cur->pos.h + 1;
setRefreshAll (panels, false);
}
R_API void r_core_panels_layout_refresh(RCore *core) {
fixBlockSize (core);
delInvalidPanels (core->panels);
checkEdge (core->panels);
r_core_panels_check_stackbase (core);
r_core_panels_refresh (core);
}
static void changePanelNum(RPanels *panels, int now, int after) {
RPanel *panel = panels->panel;
const int n_panels = panels->n_panels;
int i;
RPanel tmpPanel = panel[now];
for (i = n_panels - 1; i > after; i--) {
panel[i] = panel[i - 1];
}
panel[after] = tmpPanel;
}
static void setCursor(RCore *core, bool cur) {
RPanel *p = getCurPanel (core->panels);
RPrint *print = core->print;
print->cur_enabled = cur;
if (cur) {
print->cur = p->curpos;
} else {
p->curpos = print->cur;
}
print->col = print->cur_enabled ? 1: 0;
}
static void cursorRight(RCore *core) {
RPanel *cur = getCurPanel (core->panels);
RPrint *print = core->print;
if (!strcmp (cur->cmd, PANEL_CMD_STACK) && print->cur >= 15) {
return;
}
if (!strcmp (cur->cmd, PANEL_CMD_REGISTERS)
|| !strcmp (cur->cmd, PANEL_CMD_STACK)) {
print->cur++;
cur->addr++;
} else {
print->cur++;
int threshold = cursorThreshold (cur);
int row = r_print_row_at_off (print, print->cur);
if (row >= threshold) {
core->offset = cur->addr;
RAsmOp op;
ut32 next_roff = r_print_rowoff (print, row + 1);
int sz = r_asm_disassemble (core->assembler, &op,
core->block + next_roff, 32);
if (sz < 1) {
sz = 1;
}
r_core_seek_delta (core, sz);
cur->addr = core->offset;
r_core_block_read (core);
print->cur = R_MAX (print->cur - sz, 0);
}
}
}
static void activateCursor(RCore *core) {
RPanels *panels = core->panels;
RPanel *cur = getCurPanel (panels);
if (!strcmp (cur->cmd, PANEL_CMD_STACK)
|| !strcmp (cur->cmd, PANEL_CMD_REGISTERS)
|| !strcmp (cur->cmd, PANEL_CMD_DISASSEMBLY)
|| !strcmp (cur->cmd, PANEL_CMD_HEXDUMP)) {
setCursor (core, !core->print->cur_enabled);
cur->refresh = true;
}
}
static void cursorLeft(RCore *core) {
RPanel *cur = getCurPanel (core->panels);
RPrint *print = core->print;
if (!strcmp (cur->cmd, PANEL_CMD_REGISTERS)
|| !strcmp (cur->cmd, PANEL_CMD_STACK)) {
if (print->cur > 0) {
print->cur--;
cur->addr--;
}
} else if (!strcmp (cur->cmd, PANEL_CMD_DISASSEMBLY)) {
print->cur--;
int row = r_print_row_at_off (print, print->cur);
if (row < 0) {
int cols = print->cols;
ut64 prevoff = core->offset;
core->offset = cur->addr;
r_core_visual_disasm_up (core, &cols);
r_core_seek_delta (core, -cols);
cur->addr = core->offset;
print->cur = prevoff - core->offset - 1;
}
} else {
print->cur--;
}
}
static void cursorUp(RCore *core) {
RPrint *print = core->print;
ut32 roff;
int row;
if (print->row_offsets) {
row = r_print_row_at_off (print, print->cur);
roff = r_print_rowoff (print, row);
if (roff == UT32_MAX) {
print->cur--;
return;
}
if (row > 0) {
ut32 prev_roff;
int delta, prev_sz;
prev_roff = r_print_rowoff (print, row - 1);
delta = print->cur - roff;
prev_sz = roff - prev_roff;
int res = R_MIN (delta, prev_sz - 1);
ut64 cur = prev_roff + res;
if (cur == print->cur) {
if (print->cur > 0) {
print->cur--;
}
} else {
print->cur = prev_roff + delta;
}
} else {
RPanel *cur = getCurPanel (core->panels);
int cols = print->cols;
ut64 prevoff = core->offset;
r_core_visual_disasm_up (core, &cols);
r_core_seek_delta (core, -cols);
cur->addr = core->offset;
print->cur = R_MIN (prevoff - core->offset - 1, print->cur);
}
} else {
print->cur -= print->cols;
}
}
static void cursorDown(RCore *core) {
RPanel *cur = getCurPanel (core->panels);
RPrint *print = core->print;
ut32 roff, next_roff;
int row, sz, delta, threshold = cursorThreshold (cur);
RAsmOp op;
if (print->row_offsets) {
row = r_print_row_at_off (print, print->cur);
roff = r_print_rowoff (print, row);
if (roff == -1) {
print->cur++;
return;
}
next_roff = r_print_rowoff (print, row + 1);
if (next_roff == -1) {
print->cur++;
return;
}
sz = r_asm_disassemble (core->assembler, &op,
core->block + next_roff, 32);
if (sz < 1) {
sz = 1;
}
delta = print->cur - roff;
print->cur = next_roff + R_MIN (delta, sz - 1);
row = r_print_row_at_off (print, print->cur);
if (row >= threshold) {
r_core_seek_delta (core, sz);
print->cur = R_MAX (print->cur - sz, 0);
}
} else {
print->cur += R_MAX (1, print->cols);
}
}
static int cursorThreshold(RPanel* panel) {
int threshold = (panel->pos.h - 4) / 2;
if (threshold < 10) {
threshold = 1;
}
return threshold;
}
static bool handleZoomMode(RCore *core, const int key) {
RPanels *panels = core->panels;
r_cons_switchbuf (false);
switch (key) {
case 'Q':
case 'q':
case 0x0d:
toggleZoomMode (panels);
break;
case 'h':
case 'j':
case 'k':
case 'l':
case 'c':
case 's':
case 'S':
case ':':
case '?':
return false;
case 'X':
toggleZoomMode (panels);
delCurPanel (panels);
toggleZoomMode (panels);
break;
case 9:
restorePanelPos (&panels->panel[panels->curnode]);
handleTabKey (core, false);
savePanelPos (&panels->panel[panels->curnode]);
maximizePanelSize (panels);
break;
case 'Z':
restorePanelPos (&panels->panel[panels->curnode]);
handleTabKey (core, true);
savePanelPos (&panels->panel[panels->curnode]);
maximizePanelSize (panels);
break;
}
return true;
}
static bool handleWindowMode(RCore *core, const int key) {
RPanels *panels = core->panels;
r_cons_switchbuf (false);
switch (key) {
case 'Q':
case 'q':
toggleWindowMode (panels);
break;
case 0x0d:
toggleZoomMode (panels);
break;
case 'h':
if (moveToDirection (panels, LEFT)) {
setRefreshAll (panels, false);
}
if (panels->fun == PANEL_FUN_SNOW) {
resetSnow (panels);
}
break;
case 'j':
if (moveToDirection (panels, DOWN)) {
setRefreshAll (panels, false);
}
if (panels->fun == PANEL_FUN_SNOW) {
resetSnow (panels);
}
break;
case 'k':
if (moveToDirection (panels, UP)) {
setRefreshAll (panels, false);
}
if (panels->fun == PANEL_FUN_SNOW) {
resetSnow (panels);
}
break;
case 'l':
if (moveToDirection (panels, RIGHT)) {
setRefreshAll (panels, false);
}
if (panels->fun == PANEL_FUN_SNOW) {
resetSnow (panels);
}
break;
case 'H':
r_cons_switchbuf (false);
resizePanelLeft (panels);
break;
case 'L':
r_cons_switchbuf (false);
resizePanelRight (panels);
break;
case 'J':
r_cons_switchbuf (false);
resizePanelDown (panels);
break;
case 'K':
r_cons_switchbuf (false);
resizePanelUp (panels);
break;
case '?':
return false;
}
return true;
}
static bool handleCursorMode(RCore *core, const int key) {
RPanel *cur = getCurPanel (core->panels);
RPrint *print = core->print;
switch (key) {
case 'h':
case 'j':
case 'k':
case 'l':
return false;
case 'Q':
case 'q':
setCursor (core, !print->cur_enabled);
cur->refresh = true;
break;
case 'i':
insertValue (core);
break;
case '*':
if (!strcmp (cur->cmd, PANEL_CMD_DISASSEMBLY)) {
r_core_cmdf (core, "dr PC=0x%08"PFMT64x, core->offset + print->cur);
cur->addr = core->offset + print->cur;
cur->refresh = true;
}
break;
}
return true;
}
static void resizePanelLeft(RPanels *panels) {
RPanel *cur = getCurPanel (panels);
int i, cx0, cy0, cy1, tx0, tx1, ty0, ty1, cur1 = 0, cur2 = 0;
cx0 = cur->pos.x;
cy0 = cur->pos.y;
cy1 = cur->pos.y + cur->pos.h - 1;
RPanel **targets1 = malloc (sizeof (RPanel *) * panels->n_panels);
RPanel **targets2 = malloc (sizeof (RPanel *) * panels->n_panels);
if (!targets1 || !targets2) {
goto beach;
}
for (i = 0; i < panels->n_panels; i++) {
if (i == panels->curnode) {
continue;
}
RPanel *p = getPanel (panels, i);
tx0 = p->pos.x;
tx1 = p->pos.x + p->pos.w - 1;
ty0 = p->pos.y;
ty1 = p->pos.y + p->pos.h - 1;
if (ty0 == cy0 && ty1 == cy1 && tx1 == cx0) {
if (tx1 - PANEL_CONFIG_RESIZE_W > tx0) {
p->pos.w -= PANEL_CONFIG_RESIZE_W;
cur->pos.x -= PANEL_CONFIG_RESIZE_W;
cur->pos.w += PANEL_CONFIG_RESIZE_W;
p->refresh = true;
cur->refresh = true;
}
goto beach;
}
if (tx1 == cx0) {
if (tx1 - PANEL_CONFIG_RESIZE_W <= tx0) {
goto beach;
}
targets1[cur1++] = p;
}
if (tx0 == cx0) {
if (tx0 - PANEL_CONFIG_RESIZE_W <= 0) {
goto beach;
}
targets2[cur2++] = p;
}
}
if (cur1 > 0) {
for (i = 0; i < cur1; i++) {
targets1[i]->pos.w -= PANEL_CONFIG_RESIZE_W;
targets1[i]->refresh = true;
}
for (i = 0; i < cur2; i++) {
targets2[i]->pos.x -= PANEL_CONFIG_RESIZE_W;
targets2[i]->pos.w += PANEL_CONFIG_RESIZE_W;
targets2[i]->refresh = true;
}
cur->pos.x -= PANEL_CONFIG_RESIZE_W;
cur->pos.w += PANEL_CONFIG_RESIZE_W;
cur->refresh = true;
}
beach:
free (targets1);
free (targets2);
}
static void resizePanelRight(RPanels *panels) {
RPanel *cur = getCurPanel (panels);
int i, tx0, tx1, ty0, ty1, cur1 = 0, cur2 = 0;
int cx1 = cur->pos.x + cur->pos.w - 1;
int cy0 = cur->pos.y;
int cy1 = cur->pos.y + cur->pos.h - 1;
RPanel **targets1 = malloc (sizeof (RPanel *) * panels->n_panels);
RPanel **targets2 = malloc (sizeof (RPanel *) * panels->n_panels);
if (!targets1 || !targets2) {
goto beach;
}
for (i = 0; i < panels->n_panels; i++) {
if (i == panels->curnode) {
continue;
}
RPanel *p = getPanel (panels, i);
tx0 = p->pos.x;
tx1 = p->pos.x + p->pos.w - 1;
ty0 = p->pos.y;
ty1 = p->pos.y + p->pos.h - 1;
if (ty0 == cy0 && ty1 == cy1 && tx0 == cx1) {
if (cx1 + PANEL_CONFIG_RESIZE_W < tx1) {
p->pos.x += PANEL_CONFIG_RESIZE_W;
p->pos.w -= PANEL_CONFIG_RESIZE_W;
cur->pos.w += PANEL_CONFIG_RESIZE_W;
p->refresh = true;
cur->refresh = true;
}
goto beach;
}
if (tx0 == cx1) {
if (tx0 + PANEL_CONFIG_RESIZE_W >= tx1) {
goto beach;
}
targets1[cur1++] = p;
continue;
}
if (tx1 == cx1) {
if (tx1 + PANEL_CONFIG_RESIZE_W >= panels->can->w) {
goto beach;
}
targets2[cur2++] = p;
}
}
if (cur1 > 0) {
for (i = 0; i < cur1; i++) {
targets1[i]->pos.x += PANEL_CONFIG_RESIZE_W;
targets1[i]->pos.w -= PANEL_CONFIG_RESIZE_W;
targets1[i]->refresh = true;
}
for (i = 0; i < cur2; i++) {
targets2[i]->pos.w += PANEL_CONFIG_RESIZE_W;
targets2[i]->refresh = true;
}
cur->pos.w += PANEL_CONFIG_RESIZE_W;
cur->refresh = true;
}
beach:
free (targets1);
free (targets2);
}
static void resizePanelUp(RPanels *panels) {
RPanel *cur = getCurPanel (panels);
int i, tx0, tx1, ty0, ty1, cur1 = 0, cur2 = 0;
int cx0 = cur->pos.x;
int cx1 = cur->pos.x + cur->pos.w - 1;
int cy0 = cur->pos.y;
RPanel **targets1 = malloc (sizeof (RPanel *) * panels->n_panels);
RPanel **targets2 = malloc (sizeof (RPanel *) * panels->n_panels);
if (!targets1 || !targets2) {
goto beach;
}
for (i = 0; i < panels->n_panels; i++) {
if (i == panels->curnode) {
continue;
}
RPanel *p = getPanel (panels, i);
tx0 = p->pos.x;
tx1 = p->pos.x + p->pos.w - 1;
ty0 = p->pos.y;
ty1 = p->pos.y + p->pos.h - 1;
if (tx0 == cx0 && tx1 == cx1 && ty1 == cy0) {
if (ty1 - PANEL_CONFIG_RESIZE_H > ty0) {
p->pos.h -= PANEL_CONFIG_RESIZE_H;
cur->pos.y -= PANEL_CONFIG_RESIZE_H;
cur->pos.h += PANEL_CONFIG_RESIZE_H;
p->refresh = true;
cur->refresh = true;
}
goto beach;
}
if (ty1 == cy0) {
if (ty1 - PANEL_CONFIG_RESIZE_H <= ty0) {
goto beach;
}
targets1[cur1++] = p;
}
if (ty0 == cy0) {
if (ty0 - PANEL_CONFIG_RESIZE_H <= 0) {
goto beach;
}
targets2[cur2++] = p;
}
}
if (cur1) {
for (i = 0; i < cur1; i++) {
targets1[i]->pos.h -= PANEL_CONFIG_RESIZE_H;
targets1[i]->refresh = true;
}
for (i = 0; i < cur2; i++) {
targets2[i]->pos.y -= PANEL_CONFIG_RESIZE_H;
targets2[i]->pos.h += PANEL_CONFIG_RESIZE_H;
targets2[i]->refresh = true;
}
cur->refresh = true;
cur->pos.y -= PANEL_CONFIG_RESIZE_H;
cur->pos.h += PANEL_CONFIG_RESIZE_H;
}
beach:
free (targets1);
free (targets2);
}
static void resizePanelDown(RPanels *panels) {
RPanel *cur = getCurPanel (panels);
int i, tx0, tx1, ty0, ty1, cur1 = 0, cur2 = 0;
int cx0 = cur->pos.x;
int cx1 = cur->pos.x + cur->pos.w - 1;
int cy1 = cur->pos.y + cur->pos.h - 1;
RPanel **targets1 = malloc (sizeof (RPanel *) * panels->n_panels);
RPanel **targets2 = malloc (sizeof (RPanel *) * panels->n_panels);
if (!targets1 || !targets2) {
goto beach;
}
for (i = 0; i < panels->n_panels; i++) {
if (i == panels->curnode) {
continue;
}
RPanel *p = getPanel (panels, i);
tx0 = p->pos.x;
tx1 = p->pos.x + p->pos.w - 1;
ty0 = p->pos.y;
ty1 = p->pos.y + p->pos.h - 1;
if (tx0 == cx0 && tx1 == cx1 && ty0 == cy1) {
if (ty0 + PANEL_CONFIG_RESIZE_H < ty1) {
p->pos.y += PANEL_CONFIG_RESIZE_H;
p->pos.h -= PANEL_CONFIG_RESIZE_H;
cur->pos.h += PANEL_CONFIG_RESIZE_H;
p->refresh = true;
cur->refresh = true;
}
goto beach;
}
if (ty0 == cy1) {
if (ty0 + PANEL_CONFIG_RESIZE_H >= ty1) {
goto beach;
}
targets1[cur1++] = p;
}
if (ty1 == cy1) {
if (ty1 + PANEL_CONFIG_RESIZE_H >= panels->can->h) {
goto beach;
}
targets2[cur2++] = p;
}
}
if (cur1 > 0) {
for (i = 0; i < cur1; i++) {
targets1[i]->pos.y += PANEL_CONFIG_RESIZE_H;
targets1[i]->pos.h -= PANEL_CONFIG_RESIZE_H;
targets1[i]->refresh = true;
}
for (i = 0; i < cur2; i++) {
targets2[i]->pos.h += PANEL_CONFIG_RESIZE_H;
targets2[i]->refresh = true;
}
cur->pos.h += PANEL_CONFIG_RESIZE_H;
cur->refresh = true;
}
beach:
free (targets1);
free (targets2);
}
static void checkEdge(RPanels *panels) {
int i, tmpright, tmpbottom, maxright = 0, maxbottom = 0;
for (i = 0; i < panels->n_panels; i++) {
RPanel *panel = getPanel (panels, i);
tmpright = panel->pos.x + panel->pos.w;
tmpbottom = panel->pos.y + panel->pos.h;
if (tmpright > maxright) {
maxright = tmpright;
}
if (tmpbottom > maxbottom) {
maxbottom = tmpbottom;
}
}
int f1, f2;
for (i = 0; i < panels->n_panels; i++) {
RPanel *panel = getPanel (panels, i);
f1 = f2 = 0;
if (panel->pos.x + panel->pos.w == maxright) {
f1 = (1 << PANEL_EDGE_RIGHT);
}
if (panel->pos.y + panel->pos.h == maxbottom) {
f2 = (1 << PANEL_EDGE_BOTTOM);
}
panel->edgeflag = f1 | f2;
}
}
static void fitToCanvas(RPanels *panels) {
RConsCanvas *can = panels->can;
int i, w, h;
for (i = 0; i < panels->n_panels; i++) {
RPanel *panel = getPanel (panels, i);
if (panel->edgeflag & 1 << PANEL_EDGE_RIGHT && panel->pos.x < can->w) {
w = can->w - panel->pos.x;
if (w != panel->pos.w) {
panel->pos.w = w;
panel->refresh = true;
}
}
if (panel->edgeflag & 1 << PANEL_EDGE_BOTTOM && panel->pos.y < can->h) {
h = can->h - panel->pos.y;
if (h != panel->pos.h) {
panel->pos.h = h;
panel->refresh = true;
}
}
}
}
static void delPanel(RPanels *panels, int delPanelNum) {
int i;
for (i = delPanelNum; i < (panels->n_panels - 1); i++) {
panels->panel[i] = panels->panel[i + 1];
}
panels->panel[i].title = 0;
panels->n_panels--;
if (panels->curnode >= panels->n_panels) {
panels->curnode = panels->n_panels - 1;
}
}
static void delCurPanel(RPanels *panels) {
if (panels->n_panels <= 2) {
return;
}
dismantlePanel (panels);
delPanel (panels, panels->curnode);
}
static void fixBlockSize(RCore *core) {
int cols = r_config_get_i (core->config, "hex.cols");
r_core_block_size (core, (int)(core->cons->rows * cols * 3.5));
}
static void delInvalidPanels(RPanels *panels) {
int i;
for (i = 1; i < panels->n_panels; i++) {
RPanel *panel = getPanel (panels, i);
if (panel->pos.w < 2) {
delPanel (panels, i);
delInvalidPanels (panels);
break;
}
if (panel->pos.h < 2) {
delPanel (panels, i);
delInvalidPanels (panels);
break;
}
}
}
static void dismantlePanel(RPanels *panels) {
RPanel *cur = getCurPanel (panels);
RPanel *justLeftPanel = NULL, *justRightPanel = NULL, *justUpPanel = NULL, *justDownPanel = NULL;
RPanel *tmpPanel = NULL;
bool leftUpValid = false, leftDownValid = false, rightUpValid = false, rightDownValid = false,
upLeftValid = false, upRightValid = false, downLeftValid = false, downRightValid = false;
int left[PANEL_NUM_LIMIT], right[PANEL_NUM_LIMIT], up[PANEL_NUM_LIMIT], down[PANEL_NUM_LIMIT];
memset (left, -1, sizeof (left));
memset (right, -1, sizeof (right));
memset (up, -1, sizeof (up));
memset (down, -1, sizeof (down));
int i, ox, oy, ow, oh;
ox = cur->pos.x;
oy = cur->pos.y;
ow = cur->pos.w;
oh = cur->pos.h;
for (i = 0; i < panels->n_panels; i++) {
tmpPanel = getPanel (panels, i);
if (tmpPanel->pos.x + tmpPanel->pos.w - 1 == ox) {
left[i] = 1;
if (oy == tmpPanel->pos.y) {
leftUpValid = true;
if (oh == tmpPanel->pos.h) {
justLeftPanel = tmpPanel;
break;
}
}
if (oy + oh == tmpPanel->pos.y + tmpPanel->pos.h) {
leftDownValid = true;
}
}
if (tmpPanel->pos.x == ox + ow - 1) {
right[i] = 1;
if (oy == tmpPanel->pos.y) {
rightUpValid = true;
if (oh == tmpPanel->pos.h) {
rightDownValid = true;
justRightPanel = tmpPanel;
}
}
if (oy + oh == tmpPanel->pos.y + tmpPanel->pos.h) {
rightDownValid = true;
}
}
if (tmpPanel->pos.y + tmpPanel->pos.h - 1 == oy) {
up[i] = 1;
if (ox == tmpPanel->pos.x) {
upLeftValid = true;
if (ow == tmpPanel->pos.w) {
upRightValid = true;
justUpPanel = tmpPanel;
}
}
if (ox + ow == tmpPanel->pos.x + tmpPanel->pos.w) {
upRightValid = true;
}
}
if (tmpPanel->pos.y == oy + oh - 1) {
down[i] = 1;
if (ox == tmpPanel->pos.x) {
downLeftValid = true;
if (ow == tmpPanel->pos.w) {
downRightValid = true;
justDownPanel = tmpPanel;
}
}
if (ox + ow == tmpPanel->pos.x + tmpPanel->pos.w) {
downRightValid = true;
}
}
}
if (justLeftPanel) {
justLeftPanel->pos.w += ox + ow - (justLeftPanel->pos.x + justLeftPanel->pos.w);
} else if (justRightPanel) {
justRightPanel->pos.w = justRightPanel->pos.x + justRightPanel->pos.w - ox;
justRightPanel->pos.x = ox;
} else if (justUpPanel) {
justUpPanel->pos.h += oy + oh - (justUpPanel->pos.y + justUpPanel->pos.h);
} else if (justDownPanel) {
justDownPanel->pos.h = oh + justDownPanel->pos.y + justDownPanel->pos.h - (oy + oh);
justDownPanel->pos.y = oy;
} else if (leftUpValid && leftDownValid) {
for (i = 0; i < panels->n_panels; i++) {
if (left[i] != -1) {
tmpPanel = getPanel (panels, i);
tmpPanel->pos.w += ox + ow - (tmpPanel->pos.x + tmpPanel->pos.w);
}
}
} else if (rightUpValid && rightDownValid) {
for (i = 0; i < panels->n_panels; i++) {
if (right[i] != -1) {
tmpPanel = getPanel (panels, i);
tmpPanel->pos.w = tmpPanel->pos.x + tmpPanel->pos.w - ox;
tmpPanel->pos.x = ox;
}
}
} else if (upLeftValid && upRightValid) {
for (i = 0; i < panels->n_panels; i++) {
if (up[i] != -1) {
tmpPanel = getPanel (panels, i);
tmpPanel->pos.h += oy + oh - (tmpPanel->pos.y + tmpPanel->pos.h);
}
}
} else if (downLeftValid && downRightValid) {
for (i = 0; i < panels->n_panels; i++) {
if (down[i] != -1) {
tmpPanel = getPanel (panels, i);
tmpPanel->pos.h = oh + tmpPanel->pos.y + tmpPanel->pos.h - (oy + oh);
tmpPanel->pos.y = oy;
}
}
}
}
static void replaceCmd(RPanels* panels, const char *title, const char *cmd, const bool caching) {
RPanel *cur = getCurPanel (panels);
freeSinglePanel (cur);
cur->title = strdup (title);
cur->cmd = r_str_newf (cmd);
cur->caching = caching;
cur->cmdStrCache = NULL;
setRefreshAll (panels, false);
}
static void swapPanels(RPanels *panels, int p0, int p1) {
RPanel *panel0 = getPanel (panels, p0);
RPanel *panel1 = getPanel (panels, p1);
char *t = panel0->title;
char *c = panel0->cmd;
char *cc = panel0->cmdStrCache;
int cur = panel0->curpos;
ut64 ba = panel0->baseAddr;
ut64 a = panel0->addr;
panel0->title = panel1->title;
panel0->cmd = panel1->cmd;
panel0->cmdStrCache = panel1->cmdStrCache;
panel0->curpos = panel1->curpos;
panel0->baseAddr = panel1->baseAddr;
panel0->addr = panel1->addr;
panel1->title = t;
panel1->cmd = c;
panel1->cmdStrCache = cc;
panel1->curpos = cur;
panel1->baseAddr = ba;
panel1->addr = a;
}
static void callVisualGraph(RCore *core) {
if (checkFunc (core)) {
RPanels *panels = core->panels;
r_cons_canvas_free (panels->can);
panels->can = NULL;
int 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);
int h, w = r_cons_get_size (&h);
panels->can = createNewCanvas (core, w, h);
setRefreshAll (panels, false);
}
}
static bool checkFunc(RCore *core) {
RAnalFunction *fun = r_anal_get_fcn_in (core->anal, core->offset, R_ANAL_FCN_TYPE_NULL);
if (!fun) {
r_cons_message ("Not in a function. Type 'df' to define it here");
return false;
}
if (r_list_empty (fun->bbs)) {
r_cons_message ("No basic blocks in this function. You may want to use 'afb+'.");
return false;
}
return true;
}
static void setRefreshAll(RPanels *panels, bool clearCache) {
int i;
for (i = 0; i < panels->n_panels; i++) {
RPanel *panel = getPanel (panels, i);
panel->refresh = true;
if (clearCache) {
free (panel->cmdStrCache);
panel->cmdStrCache = NULL;
}
}
}
static void createNewPanel(RCore *core, char *name, char *cmd, bool caching) {
RPanels *panels = core->panels;
addPanelFrame (core, name, cmd, caching);
changePanelNum (panels, panels->n_panels - 1, 0);
r_core_panels_layout (panels);
panels->curnode = 0;
setRefreshAll (panels, false);
}
static RConsCanvas *createNewCanvas(RCore *core, int w, int h) {
RConsCanvas *can = r_cons_canvas_new (w, h);
if (!can) {
eprintf ("Cannot create RCons.canvas context\n");
return false;
}
r_cons_canvas_fill (can, 0, 0, w, h, ' ');
can->linemode = r_config_get_i (core->config, "graph.linemode");
can->color = r_config_get_i (core->config, "scr.color");
return can;
}
static bool checkPanelNum(RPanels *panels) {
if (panels->n_panels + 1 > PANEL_NUM_LIMIT) {
const char *msg = "panel limit exceeded.";
r_cons_yesno ('y', msg);
return false;
}
return true;
}
static void addPanelFrame(RCore *core, const char *title, const char *cmd, const bool caching) {
RPanels *panels = core->panels;
RPanel *p = getPanel (panels, panels->n_panels);
if (title) {
p->title = strdup (title);
p->cmd = r_str_newf (cmd);
} else {
p->title = r_core_cmd_str (core, cmd);
p->cmd = NULL;
}
p->type = PANEL_TYPE_DEFAULT;
p->refresh = true;
p->curpos = 0;
p->caching = caching;
p->cmdStrCache = NULL;
p->addr = core->offset;
if (p->cmd) {
if (!strcmp (p->cmd, PANEL_CMD_STACK)) {
const char *sp = r_reg_get_name (core->anal->reg, R_REG_NAME_SP);
const ut64 stackbase = r_reg_getv (core->anal->reg, sp);
p->baseAddr = stackbase;
p->addr = stackbase - r_config_get_i (core->config, "stack.delta");
p->directionCb = directionStackCb;
} else if (!strcmp (p->cmd, PANEL_CMD_GRAPH)) {
p->directionCb = directionGraphCb;
} else if (!strcmp (p->cmd, PANEL_CMD_DISASSEMBLY)) {
p->directionCb = directionDisassemblyCb;
} else if (!strcmp (p->cmd, PANEL_CMD_REGISTERS)) {
p->directionCb = directionRegisterCb;
} else if (!strcmp (p->cmd, PANEL_CMD_HEXDUMP)) {
p->directionCb = directionHexdumpCb;
} else {
p->directionCb = directionDefaultCb;
}
}
panels->n_panels++;
}
static int openFileCb(void *user) {
RCore *core = (RCore *)user;
core->cons->line->file_prompt = true;
r_line_set_hist_callback (core->cons->line, &file_history_up, &file_history_down);
char *res = r_cons_input ("open file: ");
if (res) {
if (*res) {
r_core_cmdf (core, "o %s", res);
}
free (res);
}
core->cons->line->file_prompt = false;
r_line_set_hist_callback (core->cons->line, &cmd_history_up, &cmd_history_down);
return 0;
}
static int rwCb(void *user) {
RCore *core = (RCore *)user;
r_core_cmd (core, "oo+", 0);
return 0;
}
static int debuggerCb(void *user) {
RCore *core = (RCore *)user;
r_core_cmd (core, "oo", 0);
return 0;
}
static int loadLayoutSavedCb(void *user) {
RCore *core = (RCore *)user;
if (!loadSavedPanelsLayout (core, false)) {
createDefaultPanels (core);
r_core_panels_layout (core->panels);
}
core->panels->curnode = 0;
core->panels->panelsMenu->depth = 1;
return 0;
}
static int loadLayoutDefaultCb(void *user) {
RCore *core = (RCore *)user;
initPanels (core, core->panels);
createDefaultPanels (core);
r_core_panels_layout (core->panels);
setRefreshAll (core->panels, false);
core->panels->panelsMenu->depth = 1;
return 0;
}
static int closeFileCb(void *user) {
RCore *core = (RCore *)user;
r_core_cmd0 (core, "o-*");
return 0;
}
static int saveLayoutCb(void *user) {
RCore *core = (RCore *)user;
savePanelsLayout (core, false);
const char *msg = "Panels layout saved!";
r_cons_yesno ('y', msg);
return 0;
}
static int copyCb(void *user) {
RCore *core = (RCore *)user;
char *res = r_cons_input ("How many bytes? ");
if (res) {
r_core_cmdf (core, "\"y %s\"", res);
free (res);
}
return 0;
}
static int pasteCb(void *user) {
RCore *core = (RCore *)user;
r_core_cmd0 (core, "yy");
return 0;
}
static int writeStrCb(void *user) {
RCore *core = (RCore *)user;
char *res = r_cons_input ("insert string: ");
if (res) {
r_core_cmdf (core, "\"w %s\"", res);
free (res);
}
return 0;
}
static int writeHexCb(void *user) {
RCore *core = (RCore *)user;
char *res = r_cons_input ("insert hexpairs: ");
if (res) {
r_core_cmdf (core, "\"wx %s\"", res);
free (res);
}
return 0;
}
static int assembleCb(void *user) {
RCore *core = (RCore *)user;
r_core_visual_asm (core, core->offset);
return 0;
}
static int fillCb(void *user) {
RCore *core = (RCore *)user;
char *s = r_cons_input ("Fill with: ");
r_core_cmdf (core, "wow %s", s);
free (s);
return 0;
}
static int iocacheCb(void *user) {
RCore *core = (RCore *)user;
r_core_cmd0 (core, "e!io.cache");
return 0;
}
static int colorsCb(void *user) {
RCore *core = (RCore *)user;
r_core_cmd0 (core, "e!scr.color");
return 0;
}
static int calculatorCb(void *user) {
RCore *core = (RCore *)user;
for (;;) {
char *s = r_cons_input ("> ");
if (!s || !*s) {
free (s);
break;
}
r_core_cmdf (core, "? %s", s);
r_cons_flush ();
free (s);
}
return 0;
}
static int r2shellCb(void *user) {
RCore *core = (RCore *)user;
core->vmode = false;
r_core_visual_prompt_input (core);
core->vmode = true;
return 0;
}
static int systemShellCb(void *user) {
r_cons_set_raw (0);
r_cons_flush ();
r_sys_cmd ("$SHELL");
return 0;
}
static int stringCb(void *user) {
RCore *core = (RCore *)user;
char *res = r_cons_input ("search string: ");
if (res) {
r_core_cmdf (core, "\"/ %s\"", res);
free (res);
}
return 0;
}
static int ropCb(void *user) {
RCore *core = (RCore *)user;
char *res = r_cons_input ("rop grep: ");
if (res) {
r_core_cmdf (core, "\"/R %s\"", res);
free (res);
}
return 0;
}
static int codeCb(void *user) {
RCore *core = (RCore *)user;
char *res = r_cons_input ("search code: ");
if (res) {
r_core_cmdf (core, "\"/c %s\"", res);
free (res);
}
return 0;
}
static int hexpairsCb(void *user) {
RCore *core = (RCore *)user;
char *res = r_cons_input ("search hexpairs: ");
if (res) {
r_core_cmdf (core, "\"/x %s\"", res);
free (res);
}
return 0;
}
static int continueCb(void *user) {
RCore *core = (RCore *)user;
r_core_cmd (core, "dc", 0);
r_cons_flush ();
return 0;
}
static int stepCb(void *user) {
RCore *core = (RCore *)user;
panelSingleStepIn (core);
updateDisassemblyAddr (core);
return 0;
}
static int stepoverCb(void *user) {
RCore *core = (RCore *)user;
panelSingleStepOver (core);
updateDisassemblyAddr (core);
return 0;
}
static void updateDisassemblyAddr (RCore *core) {
RPanels *panels = core->panels;
int i;
for (i = 0; i < panels->n_panels; i++) {
RPanel *p = getPanel (panels, i);
if (!strcmp (p->cmd, PANEL_CMD_DISASSEMBLY)) {
p->addr = core->offset;
}
}
setRefreshAll (panels, false);
}
static int reloadCb(void *user) {
RCore *core = (RCore *)user;
r_core_file_reopen_debug (core, "");
updateDisassemblyAddr (core);
setRefreshAll (core->panels, false);
return 0;
}
static int functionCb(void *user) {
RCore *core = (RCore *)user;
r_core_cmdf (core, "af");
setRefreshAll (core->panels, false);
return 0;
}
static int symbolsCb(void *user) {
RCore *core = (RCore *)user;
r_core_cmdf (core, "aa");
setRefreshAll (core->panels, false);
return 0;
}
static int programCb(void *user) {
RCore *core = (RCore *)user;
r_core_cmdf (core, "aaa");
setRefreshAll (core->panels, false);
return 0;
}
static int basicblocksCb(void *user) {
RCore *core = (RCore *)user;
r_core_cmdf (core, "aab");
setRefreshAll (core->panels, false);
return 0;
}
static int callsCb(void *user) {
RCore *core = (RCore *)user;
r_core_cmdf (core, "aac");
setRefreshAll (core->panels, false);
return 0;
}
static int breakpointsCb(void *user) {
RCore *core = (RCore *)user;
RPanels *panels = core->panels;
char buf[128];
const char *prompt = "addr: ";
panelPrompt (prompt, buf, sizeof (buf));
ut64 addr = r_num_math (core->num, buf);
r_core_cmdf (core, "dbs 0x%08"PFMT64x, addr);
setRefreshAll (panels, false);
return 0;
}
static int watchpointsCb(void *user) {
RCore *core = (RCore *)user;
RPanels *panels = core->panels;
char addrBuf[128], rw[128];
const char *addrPrompt = "addr: ", *rwPrompt = "<r/w/rw>: ";
panelPrompt (addrPrompt, addrBuf, sizeof (addrBuf));
panelPrompt (rwPrompt, rw, sizeof (rw));
ut64 addr = r_num_math (core->num, addrBuf);
r_core_cmdf (core, "dbw 0x%08"PFMT64x" %s", addr, rw);
setRefreshAll (panels, false);
return 0;
}
static int referencesCb(void *user) {
RCore *core = (RCore *)user;
r_core_cmdf (core, "aar");
setRefreshAll (core->panels, false);
return 0;
}
static int fortuneCb(void *user) {
RCore *core = (RCore *)user;
char *s = r_core_cmd_str (core, "fo");
r_cons_message (s);
free (s);
return 0;
}
static int commandsCb(void *user) {
RCore *core = (RCore *)user;
r_core_cmd0 (core, "?;?@?;?$?;???");
r_cons_any_key (NULL);
return 0;
}
static int gameCb(void *user) {
RCore *core = (RCore *)user;
r_cons_2048 (core->panels->can->color);
return 0;
}
static int screenLock(void *user) {
RCore *core = (RCore *)user;
r_core_cmd0 (core, "LL");
return 0;
}
static int licenseCb(void *user) {
r_cons_message ("Copyright 2006-2018 - pancake - LGPL");
return 0;
}
static int aboutCb(void *user) {
RCore *core = (RCore *)user;
char *s = r_core_cmd_str (core, "?V");
r_cons_message (s);
free (s);
return 0;
}
static int writeValueCb(void *user) {
RCore *core = (RCore *)user;
char *res = r_cons_input ("insert number: ");
if (res) {
r_core_cmdf (core, "\"wv %s\"", res);
free (res);
}
return 0;
}
static int quitCb(void *user) {
return 1;
}
static void directionDefaultCb(void *user, int direction) {
RCore *core = (RCore *)user;
RPanel *cur = getCurPanel (core->panels);
cur->refresh = true;
switch ((Direction)direction) {
case LEFT:
if (cur->sx > 0) {
cur->sx--;
}
return;
case RIGHT:
cur->sx++;
return;
case UP:
if (cur->sy > 0) {
cur->sy--;
}
return;
case DOWN:
cur->sy++;
return;
}
}
static void directionDisassemblyCb(void *user, int direction) {
RCore *core = (RCore *)user;
RPanels *panels = core->panels;
RPanel *cur = getCurPanel (panels);
int cols = core->print->cols;
cur->refresh = true;
switch ((Direction)direction) {
case LEFT:
if (core->print->cur_enabled) {
cursorLeft (core);
} else if (cur->sx > 0) {
cur->sx--;
cur->refresh = true;
}
return;
case RIGHT:
if (core->print->cur_enabled) {
cursorRight (core);
} else {
cur->sx++;
cur->refresh = true;
}
return;
case UP:
core->offset = cur->addr;
if (core->print->cur_enabled) {
cursorUp (core);
cur->addr = core->offset;
} else {
r_core_visual_disasm_up (core, &cols);
r_core_seek_delta (core, -cols);
cur->addr = core->offset;
}
return;
case DOWN:
core->offset = cur->addr;
if (core->print->cur_enabled) {
cursorDown (core);
r_core_block_read (core);
cur->addr = core->offset;
} else {
RAsmOp op;
r_core_visual_disasm_down (core, &op, &cols);
r_core_seek (core, core->offset + cols, 1);
r_core_block_read (core);
cur->addr = core->offset;
}
return;
}
}
static void directionGraphCb(void *user, int direction) {
RCore *core = (RCore *)user;
RPanels *panels = core->panels;
RPanel *cur = getCurPanel (panels);
cur->refresh = true;
switch ((Direction)direction) {
case LEFT:
if (cur->sx > 0) {
cur->sx -= r_config_get_i (core->config, "graph.scroll");
}
return;
case RIGHT:
cur->sx += r_config_get_i (core->config, "graph.scroll");
return;
case UP:
if (cur->sy > 0) {
cur->sy -= r_config_get_i (core->config, "graph.scroll");
}
return;
case DOWN:
cur->sy += r_config_get_i (core->config, "graph.scroll");
return;
}
}
static void directionRegisterCb(void *user, int direction) {
RCore *core = (RCore *)user;
RPanels *panels = core->panels;
RPanel *cur = getCurPanel (panels);
int cols = core->dbg->regcols;
cols = cols > 0 ? cols : 3;
cur->refresh = true;
switch ((Direction)direction) {
case LEFT:
if (core->print->cur_enabled) {
cursorLeft (core);
} else if (cur->sx > 0) {
cur->sx--;
cur->refresh = true;
}
return;
case RIGHT:
if (core->print->cur_enabled) {
cursorRight (core);
} else {
cur->sx++;
cur->refresh = true;
}
return;
case UP:
if (core->print->cur_enabled) {
int tmp = core->print->cur;
tmp -= cols;
if (tmp >= 0) {
core->print->cur = tmp;
}
}
return;
case DOWN:
if (core->print->cur_enabled) {
core->print->cur += cols;
}
return;
}
}
static void directionStackCb(void *user, int direction) {
RCore *core = (RCore *)user;
RPanels *panels = core->panels;
RPanel *cur = getCurPanel (panels);
int cols = r_config_get_i (core->config, "hex.cols");
if (cols < 1) {
cols = 16;
}
cur->refresh = true;
switch ((Direction)direction) {
case LEFT:
if (core->print->cur_enabled) {
cursorLeft (core);
} else if (cur->sx > 0) {
cur->sx--;
cur->refresh = true;
}
return;
case RIGHT:
if (core->print->cur_enabled) {
cursorRight (core);
} else {
cur->sx++;
cur->refresh = true;
}
return;
case UP:
r_config_set_i (core->config, "stack.delta",
r_config_get_i (core->config, "stack.delta") + cols);
cur->addr -= cols;
return;
case DOWN:
r_config_set_i (core->config, "stack.delta",
r_config_get_i (core->config, "stack.delta") - cols);
cur->addr += cols;
return;
}
}
static void directionHexdumpCb(void *user, int direction) {
RCore *core = (RCore *)user;
RPanels *panels = core->panels;
RPanel *cur = getCurPanel (panels);
int cols = r_config_get_i (core->config, "hex.cols");
if (cols < 1) {
cols = 16;
}
cur->refresh = true;
switch ((Direction)direction) {
case LEFT:
if (!core->print->cur) {
cur->addr -= cols;
core->print->cur += cols - 1;
} else if (core->print->cur_enabled) {
cursorLeft (core);
} else if (cur->sx > 0) {
cur->sx--;
cur->refresh = true;
}
return;
case RIGHT:
if (core->print->cur / cols + 1 > cur->pos.h - 5
&& core->print->cur % cols == cols - 1) {
cur->addr += cols;
core->print->cur -= cols - 1;
} else if (core->print->cur_enabled) {
cursorRight (core);
} else {
cur->sx++;
cur->refresh = true;
}
return;
case UP:
if (!cur->caching) {
if (core->print->cur_enabled) {
if (!(core->print->cur / cols)) {
cur->addr -= cols;
} else {
cursorUp (core);
}
} else {
if (cur->addr <= cols) {
cur->addr = 0;
} else {
cur->addr -= cols;
}
}
} else if (cur->sy > 0) {
cur->sy--;
}
return;
case DOWN:
if (!cur->caching) {
if (core->print->cur_enabled) {
if (core->print->cur / cols + 1 > cur->pos.h - 5) {
cur->addr += cols;
} else {
cursorDown (core);
}
} else {
cur->addr += cols;
}
} else {
cur->sy++;
}
return;
}
}
static void hudstuff(RCore *core) {
RPanels *panels = core->panels;
RPanel *cur = getCurPanel (panels);
r_core_visual_hudstuff (core);
if (!strcmp (cur->cmd, PANEL_CMD_DISASSEMBLY)) {
cur->addr = core->offset;
} else {
int i;
for (i = 0; i < panels->n_panels; i++) {
RPanel *panel = &panels->panel[i];
if (!strcmp (panel->cmd, PANEL_CMD_DISASSEMBLY)) {
panel->addr = core->offset;
break;
}
}
}
setRefreshAll (panels, true);
}
static void printSnow(RPanels *panels) {
if (!panels->snows) {
panels->snows = r_list_newf (free);
}
RPanel *cur = getCurPanel (panels);
int i, amount = r_num_rand (4);
if (amount > 0) {
for (i = 0; i < amount; i++) {
RPanelsSnow *snow = R_NEW (RPanelsSnow);
snow->x = r_num_rand (cur->pos.w) + cur->pos.x;
snow->y = cur->pos.y;
r_list_append (panels->snows, snow);
}
}
RListIter *iter, *iter2;
RPanelsSnow *snow;
r_list_foreach_safe (panels->snows, iter, iter2, snow) {
int pos = r_num_rand (3) - 1;
snow->x += pos;
snow->y++;
if (snow->x >= cur->pos.w + cur->pos.x || snow->x <= cur->pos.x + 1) {
r_list_delete (panels->snows, iter);
continue;
}
if (snow->y >= cur->pos.h + cur->pos.y - 1) {
r_list_delete (panels->snows, iter);
continue;
}
if (r_cons_canvas_gotoxy (panels->can, snow->x, snow->y)) {
r_cons_canvas_write (panels->can, "*");
}
}
}
static void resetSnow(RPanels *panels) {
RPanel *cur = getCurPanel (panels);
r_list_free (panels->snows);
panels->snows = NULL;
cur->refresh = true;
}
static int openMenuCb (void *user) {
RCore* core = (RCore *)user;
RPanelsMenu *menu = core->panels->panelsMenu;
RPanelsMenuItem *parent = menu->history[menu->depth - 1];
RPanelsMenuItem *child = parent->sub[parent->selectedIndex];
if (menu->depth < 2) {
child->p->pos.x = menu->root->selectedIndex * 6;
child->p->pos.y = 1;
} else {
RPanelsMenuItem *p = menu->history[menu->depth - 2];
RPanelsMenuItem *parent2 = p->sub[p->selectedIndex];
child->p->pos.x = parent2->p->pos.x + parent2->p->pos.w - 1;
child->p->pos.y = menu->depth == 2 ? parent2->p->pos.y + parent2->selectedIndex : parent2->p->pos.y;
}
RStrBuf *buf = drawMenu (child);
if (!buf) {
return 0;
}
child->p->title = r_strbuf_drain (buf);
child->p->pos.w = r_str_bounds (child->p->title, &child->p->pos.h);
child->p->pos.h += 4;
child->p->type = PANEL_TYPE_MENU;
child->p->refresh = true;
menu->refreshPanels[menu->n_refresh++] = child->p;
menu->history[menu->depth++] = child;
return 0;
}
static void addMenu(RCore *core, const char *parent, const char *name, RPanelsMenuCallback cb) {
RPanels *panels = core->panels;
RPanelsMenuItem *p_item, *item = R_NEW0 (RPanelsMenuItem);
if (!item) {
return;
}
if (parent) {
void *addr = ht_pp_find (panels->mht, parent, NULL);
p_item = (RPanelsMenuItem *)addr;
ht_pp_insert (panels->mht, sdb_fmt ("%s.%s", parent, name), item);
} else {
p_item = panels->panelsMenu->root;
ht_pp_insert (panels->mht, sdb_fmt ("%s", name), item);
}
item->n_sub = 0;
item->selectedIndex = 0;
item->name = name ? strdup (name) : NULL;
item->sub = NULL;
item->cb = cb;
item->p = R_NEW0 (RPanel);
if (!item->p) {
free (item);
return;
}
p_item->n_sub++;
struct r_panels_menu_item **sub = realloc (p_item->sub, sizeof (RPanelsMenuItem *) * p_item->n_sub);
if (sub) {
p_item->sub = sub;
p_item->sub[p_item->n_sub - 1] = item;
} else {
free (item);
}
}
static void removeMenu(RPanels *panels) {
RPanelsMenu *menu = panels->panelsMenu;
int i;
menu->depth--;
for (i = 1; i < menu->depth; i++) {
menu->history[i]->p->refresh = true;
menu->refreshPanels[i - 1] = menu->history[i]->p;
}
menu->n_refresh = menu->depth - 1;
setRefreshAll (panels, false);
}
static RStrBuf *drawMenu(RPanelsMenuItem *item) {
RStrBuf *buf = r_strbuf_new (NULL);
if (!buf) {
return NULL;
}
int i;
for (i = 0; i < item->n_sub; i++) {
if (i == item->selectedIndex) {
r_strbuf_append (buf, "> ");
} else {
r_strbuf_append (buf, " ");
}
r_strbuf_append (buf, item->sub[i]->name);
r_strbuf_append (buf, " \n");
}
return buf;
}
static void moveMenuCursor(RPanelsMenu *menu, RPanelsMenuItem *parent) {
RPanel *p = parent->p;
RStrBuf *buf = drawMenu (parent);
if (!buf) {
return;
}
p->title = r_strbuf_drain (buf);
p->pos.w = r_str_bounds (p->title, &p->pos.h);
p->pos.h += 4;
p->type = PANEL_TYPE_MENU;
p->refresh = true;
menu->refreshPanels[menu->n_refresh++] = p;
}
static bool initPanelsMenu(RCore *core) {
RPanels *panels = core->panels;
RPanelsMenu *panelsMenu = R_NEW0 (RPanelsMenu);
RPanelsMenuItem *root = R_NEW0 (RPanelsMenuItem);
panels->panelsMenu = panelsMenu;
panelsMenu->root = root;
root->n_sub = 0;
root->selectedIndex = 0;
root->name = NULL;
root->sub = NULL;
int i = 0;
while (menus[i]) {
addMenu (core, NULL, menus[i], openMenuCb);
i++;
}
char *parent = "File";
i = 0;
while (menus_File[i]) {
if (!strcmp (menus_File[i], "Open")) {
addMenu (core, parent, menus_File[i], openFileCb);
} else if (!strcmp (menus_File[i], "ReOpen")) {
addMenu (core, parent, menus_File[i], openMenuCb);
} else if (!strcmp (menus_File[i], "Close")) {
addMenu (core, parent, menus_File[i], closeFileCb);
} else if (!strcmp (menus_File[i], "Save Layout")) {
addMenu (core, parent, menus_File[i], saveLayoutCb);
} else if (!strcmp (menus_File[i], "Load Layout")) {
addMenu (core, parent, menus_File[i], openMenuCb);
} else if (!strcmp (menus_File[i], "Quit")) {
addMenu (core, parent, menus_File[i], quitCb);
} else {
addMenu (core, parent, menus_File[i], layoutSidePanel);
}
i++;
}
parent = "Edit";
i = 0;
while (menus_Edit[i]) {
if (!strcmp (menus_Edit[i], "Copy")) {
addMenu (core, parent, menus_Edit[i], copyCb);
} else if (!strcmp (menus_Edit[i], "Paste")) {
addMenu (core, parent, menus_Edit[i], pasteCb);
} else if (!strcmp (menus_Edit[i], "Write String")) {
addMenu (core, parent, menus_Edit[i], writeStrCb);
} else if (!strcmp (menus_Edit[i], "Write Hex")) {
addMenu (core, parent, menus_Edit[i], writeHexCb);
} else if (!strcmp (menus_Edit[i], "Write Value")) {
addMenu (core, parent, menus_Edit[i], writeValueCb);
} else if (!strcmp (menus_Edit[i], "Assemble")) {
addMenu (core, parent, menus_Edit[i], assembleCb);
} else if (!strcmp (menus_Edit[i], "Fill")) {
addMenu (core, parent, menus_Edit[i], fillCb);
} else if (!strcmp (menus_Edit[i], "io.cache")) {
addMenu (core, parent, menus_Edit[i], iocacheCb);
} else {
addMenu (core, parent, menus_Edit[i], layoutSidePanel);
}
i++;
}
parent = "View";
i = 0;
while (menus_View[i]) {
if (!strcmp (menus_View[i], "Colors")) {
addMenu (core, parent, menus_View[i], colorsCb);
} else {
addMenu (core, parent, menus_View[i], layoutSidePanel);
}
i++;
}
parent = "Tools";
i = 0;
while (menus_Tools[i]) {
if (!strcmp (menus_Tools[i], "Calculator")) {
addMenu (core, parent, menus_Tools[i], calculatorCb);
} else if (!strcmp (menus_Tools[i], "R2 Shell")) {
addMenu (core, parent, menus_Tools[i], r2shellCb);
} else if (!strcmp (menus_Tools[i], "System Shell")) {
addMenu (core, parent, menus_Tools[i], systemShellCb);
}
i++;
}
parent = "Search";
i = 0;
while (menus_Search[i]) {
if (!strcmp (menus_Search[i], "String")) {
addMenu (core, parent, menus_Search[i], stringCb);
} else if (!strcmp (menus_Search[i], "ROP")) {
addMenu (core, parent, menus_Search[i], ropCb);
} else if (!strcmp (menus_Search[i], "Code")) {
addMenu (core, parent, menus_Search[i], codeCb);
} else if (!strcmp (menus_Search[i], "Hexpairs")) {
addMenu (core, parent, menus_Search[i], hexpairsCb);
}
i++;
}
parent = "Debug";
i = 0;
while (menus_Debug[i]) {
if (!strcmp (menus_Debug[i], "Breakpoints")) {
addMenu (core, parent, menus_Debug[i], breakpointsCb);
} else if (!strcmp (menus_Debug[i], "Watchpoints")) {
addMenu (core, parent, menus_Debug[i], watchpointsCb);
} else if (!strcmp (menus_Debug[i], "Continue")) {
addMenu (core, parent, menus_Debug[i], continueCb);
} else if (!strcmp (menus_Debug[i], "Step")) {
addMenu (core, parent, menus_Debug[i], stepCb);
} else if (!strcmp (menus_Debug[i], "Step Over")) {
addMenu (core, parent, menus_Debug[i], stepoverCb);
} else if (!strcmp (menus_Debug[i], "Reload")) {
addMenu (core, parent, menus_Debug[i], reloadCb);
} else {
addMenu (core, parent, menus_Debug[i], layoutSidePanel);
}
i++;
}
parent = "Analyze";
i = 0;
while (menus_Analyze[i]) {
if (!strcmp (menus_Analyze[i], "Function")) {
addMenu (core, parent, menus_Analyze[i], functionCb);
} else if (!strcmp (menus_Analyze[i], "Symbols")) {
addMenu (core, parent, menus_Analyze[i], symbolsCb);
} else if (!strcmp (menus_Analyze[i], "Program")) {
addMenu (core, parent, menus_Analyze[i], programCb);
} else if (!strcmp (menus_Analyze[i], "BasicBlocks")) {
addMenu (core, parent, menus_Analyze[i], basicblocksCb);
} else if (!strcmp (menus_Analyze[i], "Calls")) {
addMenu (core, parent, menus_Analyze[i], callsCb);
} else if (!strcmp (menus_Analyze[i], "References")) {
addMenu (core, parent, menus_Analyze[i], referencesCb);
}
i++;
}
parent = "Help";
i = 0;
while (menus_Help[i]) {
if (!strcmp (menus_Help[i], "Fortune")) {
addMenu (core, parent, menus_Help[i], fortuneCb);
} else if (!strcmp (menus_Help[i], "Commands")) {
addMenu (core, parent, menus_Help[i], commandsCb);
} else if (!strcmp (menus_Help[i], "2048")) {
addMenu (core, parent, menus_Help[i], gameCb);
} else if (!strcmp (menus_Help[i], "License")) {
addMenu (core, parent, menus_Help[i], licenseCb);
} else if (!strcmp (menus_Help[i], "Lock Screen")) {
addMenu (core, parent, menus_Help[i], screenLock);
} else if (!strcmp (menus_Help[i], "About")) {
addMenu (core, parent, menus_Help[i], aboutCb);
}
i++;
}
parent = "File.ReOpen";
i = 0;
while (menus_ReOpen[i]) {
if (!strcmp (menus_ReOpen[i], "In RW")) {
addMenu (core, parent, menus_ReOpen[i], rwCb);
} else if (!strcmp (menus_ReOpen[i], "In Debugger")) {
addMenu (core, parent, menus_ReOpen[i], debuggerCb);
}
i++;
}
parent = "File.Load Layout";
i = 0;
while (menus_loadLayout[i]) {
if (!strcmp (menus_loadLayout[i], "Saved")) {
addMenu (core, parent, menus_loadLayout[i], loadLayoutSavedCb);
} else if (!strcmp (menus_loadLayout[i], "Default")) {
addMenu (core, parent, menus_loadLayout[i], loadLayoutDefaultCb);
}
i++;
}
root->selectedIndex = 0;
panelsMenu->history = calloc (8, sizeof (RPanelsMenuItem *));
panelsMenu->history[0] = root;
panelsMenu->depth = 1;
panelsMenu->n_refresh = 0;
panelsMenu->refreshPanels = calloc (8, sizeof (RPanel *));
return true;
}
static bool initPanels(RCore *core, RPanels *panels) {
panels->panel = calloc (sizeof (RPanel), PANEL_NUM_LIMIT);
if (!panels->panel) {
return false;
}
return true;
}
static void freeSinglePanel(RPanel *panel) {
free (panel->title);
free (panel->cmd);
free (panel->cmdStrCache);
}
static void freeAllPanels(RPanels *panels) {
int i;
for (i = 0; i < panels->n_panels; i++) {
RPanel *p = getPanel (panels, i);
freeSinglePanel (p);
}
free (panels->panel);
}
static void refreshCoreOffset (RCore *core) {
RPanels *panels = core->panels;
RPanel *cur = getCurPanel (panels);
if (!strcmp (cur->cmd, PANEL_CMD_DISASSEMBLY)) {
core->offset = cur->addr;
}
}
R_API void r_core_panels_refresh(RCore *core) {
RPanels *panels = core->panels;
if (!panels) {
return;
}
RPanel *panel = panels->panel;
if (!panel) {
return;
}
RConsCanvas *can = panels->can;
if (!can) {
return;
}
char title[1024];
char str[1024];
int i, h, w = r_cons_get_size (&h);
refreshCoreOffset (core);
r_cons_gotoxy (0, 0);
if (panels->isResizing || (can->w != w || can->h != h)) {
panels->isResizing = false;
if (!r_cons_canvas_resize (can, w, h)) {
return;
}
setRefreshAll (panels, false);
}
fitToCanvas (panels);
for (i = 0; i < panels->n_panels; i++) {
if (i != panels->curnode) {
panelPrint (core, can, &panel[i], 0);
}
}
if (panels->mode == PANEL_MODE_MENU) {
panelPrint (core, can, &panel[panels->curnode], 0);
} else {
panelPrint (core, can, &panel[panels->curnode], 1);
}
for (i = 0; i < panels->panelsMenu->n_refresh; i++) {
panelPrint (core, can, panels->panelsMenu->refreshPanels[i], 1);
}
panels->panelsMenu->n_refresh = 0;
(void) r_cons_canvas_gotoxy (can, -can->sx, -can->sy);
r_cons_canvas_fill (can, -can->sx, -can->sy, w, 1, ' ');
title[0] = 0;
if (panels->mode == PANEL_MODE_MENU) {
strcpy (title, "> ");
}
const char *color = panels->mode == PANEL_MODE_MENU ? core->cons->context->pal.graph_box : core->cons->context->pal.graph_box2;
if (panels->mode == PANEL_MODE_ZOOM) {
snprintf (str, sizeof (title) - 1, "%s Zoom Mode | Press Enter or q to quit"Color_RESET, color);
strcat (title, str);
} else if (panels->mode == PANEL_MODE_WINDOW) {
snprintf (str, sizeof (title) - 1, "%s Window Mode | hjkl: move around the panels | q: quit the mode | Enter: Zoom mode"Color_RESET, color);
strcat (title, str);
} else {
RPanelsMenuItem *parent = panels->panelsMenu->root;
for (i = 0; i < parent->n_sub; i++) {
RPanelsMenuItem *item = parent->sub[i];
if (panels->mode == PANEL_MODE_MENU) {
if (i == parent->selectedIndex) {
snprintf (str, sizeof (title) - 1, "%s[%s]"Color_RESET, color, item->name);
} else {
snprintf (str, sizeof (title) - 1, "%s %s "Color_RESET, color, item->name);
}
} else {
snprintf (str, sizeof (title) - 1, "%s %s "Color_RESET, color, item->name);
}
strcat (title, str);
}
}
if (panels->mode == PANEL_MODE_MENU) {
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);
i = -can->sx + w - strlen (title);
(void) r_cons_canvas_gotoxy (can, i, -can->sy);
r_cons_canvas_write (can, title);
sprintf (str, "Press L to refresh all the panels ");
i -= strlen (str);
(void) r_cons_canvas_gotoxy (can, i, -can->sy);
r_cons_canvas_write (can, str);
if (panels->fun == PANEL_FUN_SNOW) {
printSnow (panels);
}
r_cons_canvas_print (can);
if (core->scr_gadgets) {
r_core_cmd0 (core, "pg");
}
r_cons_flush ();
}
static void doPanelsRefresh(RCore *core) {
if (!core->panels) {
return;
}
core->panels->isResizing = true;
panelAllClear (core->panels);
r_core_panels_refresh (core);
}
static void doPanelsRefreshOneShot(RCore *core) {
r_core_task_enqueue_oneshot (core, (RCoreTaskOneShot) doPanelsRefresh, core);
}
static void panelSingleStepIn(RCore *core) {
if (r_config_get_i (core->config, "cfg.debug")) {
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 panelSingleStepOver(RCore *core) {
bool io_cache = r_config_get_i (core->config, "io.cache");
r_config_set_i (core->config, "io.cache", false);
if (r_config_get_i (core->config, "cfg.debug")) {
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);
}
r_config_set_i (core->config, "io.cache", io_cache);
}
static void panelBreakpoint(RCore *core) {
RPanel *cur = getCurPanel (core->panels);
if (!strcmp (cur->cmd, PANEL_CMD_DISASSEMBLY)) {
r_core_cmd (core, "dbs $$", 0);
cur->refresh = true;
}
}
static void panelContinue(RCore *core) {
r_core_cmd (core, "dc", 0);
}
R_API void r_core_panels_check_stackbase(RCore *core) {
if (!core || !core->panels) {
return;
}
int i;
const char *sp = r_reg_get_name (core->anal->reg, R_REG_NAME_SP);
const ut64 stackbase = r_reg_getv (core->anal->reg, sp);
RPanels *panels = core->panels;
for (i = 1; i < panels->n_panels; i++) {
RPanel *panel = getPanel (panels, i);
if (panel->cmd && !strcmp (panel->cmd, PANEL_CMD_STACK) && panel->baseAddr != stackbase) {
panel->baseAddr = stackbase;
panel->addr = stackbase - r_config_get_i (core->config, "stack.delta") + core->print->cur;
panel->refresh = true;
}
}
}
static void panelPrompt(const char *prompt, char *buf, int len) {
r_line_set_prompt (prompt);
*buf = 0;
r_cons_fgets (buf, len, 0, NULL);
}
static void initSdb(RPanels *panels) {
sdb_set (panels->db, "Symbols", "isq", 0);
sdb_set (panels->db, "Stack" , "px 256@r:SP", 0);
sdb_set (panels->db, "Locals", "afvd", 0);
sdb_set (panels->db, "StackRefs", "pxr 256@r:SP", 0);
sdb_set (panels->db, "Registers", "dr=", 0);
sdb_set (panels->db, "RegisterRefs", "drr", 0);
sdb_set (panels->db, "Disassembly", "pd $r", 0);
sdb_set (panels->db, "Pseudo", "pdc", 0);
sdb_set (panels->db, "Graph", "agf", 0);
sdb_set (panels->db, "Info", "i", 0);
sdb_set (panels->db, "Database", "k ***", 0);
sdb_set (panels->db, "Hexdump", "xc", 0);
sdb_set (panels->db, "Functions", "afl", 0);
sdb_set (panels->db, "Comments", "CC", 0);
sdb_set (panels->db, "Entropy", "p=e", 0);
sdb_set (panels->db, "DRX", "drx", 0);
sdb_set (panels->db, "Sections", "iSq", 0);
sdb_set (panels->db, "Strings", "izq", 0);
sdb_set (panels->db, "Maps", "dm", 0);
sdb_set (panels->db, "Modules", "dmm", 0);
sdb_set (panels->db, "Backtrace", "dbt", 0);
sdb_set (panels->db, "Breakpoints", "db", 0);
sdb_set (panels->db, "Imports", "iiq", 0);
sdb_set (panels->db, "Clipboard", "yx", 0);
sdb_set (panels->db, "FcnInfo", "afi", 0);
sdb_set (panels->db, "New", "o", 0);
sdb_set (panels->db, "Var READ address", "afvR", 0);
sdb_set (panels->db, "Var WRITE address", "afvW", 0);
}
static void mht_free_kv(HtPPKv *kv) {
free (kv->key);
free (kv->value);
}
static bool init(RCore *core, RPanels *panels, int w, int h) {
panels->panel = NULL;
panels->n_panels = 0;
panels->columnWidth = 80;
if (r_config_get_i (core->config, "cfg.debug")) {
panels->layout = PANEL_LAYOUT_DEFAULT_DYNAMIC;
} else {
panels->layout = PANEL_LAYOUT_DEFAULT_STATIC;
}
panels->isResizing = false;
panels->can = createNewCanvas (core, w, h);
panels->db = sdb_new0 ();
panels->mht = ht_pp_new (NULL, (HtPPKvFreeFunc)mht_free_kv, (HtPPCalcSizeV)strlen);
panels->mode = PANEL_MODE_DEFAULT;
panels->fun = PANEL_FUN_NOFUN;
panels->prevMode = PANEL_MODE_DEFAULT;
initSdb (panels);
if (w < 140) {
panels->columnWidth = w / 3;
}
return true;
}
static int file_history_up(RLine *line) {
RCore *core = line->user;
RList *files = r_id_storage_list (core->io->files);
int num_files = r_list_length (files);
if (line->file_hist_index >= num_files || line->file_hist_index < 0) {
return false;
}
line->file_hist_index++;
RIODesc *desc = r_list_get_n (files, num_files - line->file_hist_index);
if (desc) {
strncpy (line->buffer.data, desc->name, R_LINE_BUFSIZE - 1);
line->buffer.index = line->buffer.length = strlen (line->buffer.data);
}
r_list_free (files);
return true;
}
static int file_history_down(RLine *line) {
RCore *core = line->user;
RList *files = r_id_storage_list (core->io->files);
int num_files = r_list_length (files);
if (line->file_hist_index <= 0 || line->file_hist_index > num_files) {
return false;
}
line->file_hist_index--;
if (line->file_hist_index <= 0) {
line->buffer.data[0] = '\0';
line->buffer.index = line->buffer.length = 0;
return false;
}
RIODesc *desc = r_list_get_n (files, num_files - line->file_hist_index);
if (desc) {
strncpy (line->buffer.data, desc->name, R_LINE_BUFSIZE - 1);
line->buffer.index = line->buffer.length = strlen (line->buffer.data);
}
r_list_free (files);
return true;
}
static bool handleMenu(RCore *core, const int key) {
RPanels *panels = core->panels;
RPanelsMenu *menu = panels->panelsMenu;
r_cons_switchbuf (false);
switch (key) {
case 'h':
if (menu->depth <= 2) {
if (menu->root->selectedIndex > 0) {
menu->root->selectedIndex--;
} else {
menu->root->selectedIndex = menu->root->n_sub - 1;
}
if (menu->depth == 2) {
menu->depth = 1;
setRefreshAll (panels, false);
menu->root->sub[menu->root->selectedIndex]->cb (core);
}
} else {
removeMenu (panels);
}
break;
case 'j':
{
if (menu->depth == 1) {
RPanelsMenuItem *parent = menu->history[menu->depth - 1];
parent->sub[parent->selectedIndex]->cb(core);
} else {
RPanelsMenuItem *parent = menu->history[menu->depth - 1];
parent->selectedIndex = R_MIN (parent->n_sub - 1, parent->selectedIndex + 1);
moveMenuCursor (menu, parent);
}
}
break;
case 'k':
{
if (menu->depth < 2) {
break;
}
RPanelsMenuItem *parent = menu->history[menu->depth - 1];
if (parent->selectedIndex > 0) {
parent->selectedIndex--;
moveMenuCursor (menu, parent);
} else if (menu->depth == 2) {
menu->depth--;
setRefreshAll (panels, false);
}
}
break;
case 'l':
{
if (menu->depth == 1) {
menu->root->selectedIndex++;
menu->root->selectedIndex %= menu->root->n_sub;
break;
}
RPanelsMenuItem *child = menu->history[menu->depth - 1];
if (child->sub[child->selectedIndex]->sub) {
child->sub[child->selectedIndex]->cb (core);
} else {
menu->root->selectedIndex++;
menu->root->selectedIndex %= menu->root->n_sub;
menu->depth = 1;
setRefreshAll (panels, false);
menu->root->sub[menu->root->selectedIndex]->cb (core);
}
}
break;
case 'q':
case -1:
if (panels->panelsMenu->depth > 1) {
removeMenu (panels);
} else {
panels->mode = PANEL_MODE_DEFAULT;
}
break;
case ' ':
case '\r':
case '\n':
{
RPanelsMenuItem *parent = menu->history[menu->depth - 1];
RPanelsMenuItem *child = parent->sub[parent->selectedIndex];
if (child->cb (core)) {
return false;
}
}
break;
case 9:
handleTabKey (core, false);
break;
case 'Z':
handleTabKey (core, true);
break;
case ':':
{
r_core_visual_prompt_input (core);
int i;
for (i = 0; i < panels->n_panels; i++) {
RPanel *p = getPanel (panels, i);
if (!strcmp (p->cmd, PANEL_CMD_DISASSEMBLY)) {
p->addr = core->offset;
break;
}
}
setRefreshAll (panels, false);
}
break;
case '?':
showHelp (core, panels->mode);
break;
}
return true;
}
static void handleTabKey(RCore *core, bool shift) {
RPanels *panels = core->panels;
RPanel *cur = getCurPanel (panels);
r_cons_switchbuf (false);
cur->refresh = true;
if (!shift) {
if (panels->mode == PANEL_MODE_MENU) {
panels->curnode = 0;
panels->mode = PANEL_MODE_DEFAULT;
} else if (panels->mode == PANEL_MODE_ZOOM) {
if (panels->curnode == panels->n_panels - 1) {
panels->curnode = 0;
} else {
panels->curnode++;
}
} else {
if (panels->curnode == panels->n_panels - 1) {
panels->mode = PANEL_MODE_MENU;
} else {
panels->curnode++;
}
}
} else {
if (panels->mode == PANEL_MODE_MENU) {
panels->curnode = panels->n_panels - 1;
panels->mode = PANEL_MODE_DEFAULT;
} else if (panels->mode == PANEL_MODE_ZOOM) {
if (panels->curnode) {
panels->curnode--;
} else {
panels->curnode = panels->n_panels - 1;
}
} else {
if (panels->curnode) {
panels->curnode--;
} else {
panels->mode = PANEL_MODE_MENU;
}
}
}
cur = getCurPanel (panels);
if (!strcmp (cur->cmd, PANEL_CMD_DISASSEMBLY)) {
setRefreshAll (panels, false);
return;
}
cur->refresh = true;
if (panels->fun == PANEL_FUN_SNOW) {
resetSnow (panels);
}
}
static void savePanelPos(RPanel* panel) {
panel->prevPos.x = panel->pos.x;
panel->prevPos.y = panel->pos.y;
panel->prevPos.w = panel->pos.w;
panel->prevPos.h = panel->pos.h;
}
static void restorePanelPos(RPanel* panel) {
panel->pos.x = panel->prevPos.x;
panel->pos.y = panel->prevPos.y;
panel->pos.w = panel->prevPos.w;
panel->pos.h = panel->prevPos.h;
}
static char *getPanelsConfigPath() {
char *configPath = r_str_newf (R_JOIN_2_PATHS (R2_HOME_DATADIR, ".r2panels"));
if (!configPath) {
return NULL;
}
char *newPath = r_str_home (configPath);
R_FREE (configPath);
return newPath;
}
static void savePanelsLayout(RCore* core, bool temp) {
RPanels *panels = core->panels;
int i;
PJ *pj = NULL;
pj = pj_new ();
pj_a (pj);
for (i = 0; i < panels->n_panels; i++) {
RPanel *panel = getPanel (panels, i);
pj_o (pj);
pj_ks (pj, "Title", panel->title);
pj_ks (pj, "Cmd", panel->cmd);
pj_kn (pj, "x", panel->pos.x);
pj_kn (pj, "y", panel->pos.y);
pj_kn (pj, "w", panel->pos.w);
pj_kn (pj, "h", panel->pos.h);
pj_kb (pj, "caching", panel->caching);
pj_end (pj);
}
pj_end (pj);
if (!temp) {
char *configPath = getPanelsConfigPath ();
FILE *panelsConfig = r_sandbox_fopen (configPath, "w");
free (configPath);
if (panelsConfig) {
fprintf (panelsConfig, "%s", pj_string (pj));
fclose (panelsConfig);
}
} else {
core->panels_tmpcfg = strdup (pj_string (pj));
}
pj_free (pj);
}
static char *parsePanelsConfig(const char *cfg, int len) {
if (!cfg || !*cfg || len < 2 || *cfg != '[') {
eprintf ("Not valid config!\n");
return NULL;
}
char *tmp = strdup (cfg + 1);
int i = 0;
for (; i < len; i++) {
if (tmp[i] == '}' && i + 1 < len) {
if (tmp[i + 1] == ',') {
tmp[i + 1] = '\n';
continue;
}
if (tmp[i + 1] == ']') {
tmp[i + 1] = '\n';
break;
}
eprintf ("Not valid config!\n");
free (tmp);
return NULL;
}
}
return tmp;
}
static int loadSavedPanelsLayout(RCore* core, bool temp) {
int i, s;
char *panelsConfig;
if (!temp) {
char *configPath = getPanelsConfigPath ();
panelsConfig = r_file_slurp (configPath, &s);
free (configPath);
if (!panelsConfig) {
free (panelsConfig);
return 0;
}
} else {
panelsConfig = core->panels_tmpcfg;
}
char *parsedConfig = parsePanelsConfig (panelsConfig, strlen (panelsConfig));
free (panelsConfig);
if (!parsedConfig) {
return 0;
}
int count = r_str_split (parsedConfig, '\n');
RPanels *panels = core->panels;
panelAllClear (panels);
panels->n_panels = 0;
panels->curnode = 0;
char *title, *cmd, *x, *y, *w, *h, *cfg = parsedConfig;
bool caching;
for (i = 1; i < count; i++) {
title = sdb_json_get_str (cfg, "Title");
cmd = sdb_json_get_str (cfg, "Cmd");
x = sdb_json_get_str (cfg, "x");
y = sdb_json_get_str (cfg, "y");
w = sdb_json_get_str (cfg, "w");
h = sdb_json_get_str (cfg, "h");
caching = sdb_json_get_bool (cfg, "caching");
RPanel *p = getPanel (panels, panels->n_panels);
p->pos.x = atoi (x);
p->pos.y = atoi (y);
p->pos.w = atoi (w);
p->pos.h = atoi (h);
addPanelFrame (core, title, cmd, caching);
cfg += strlen (cfg) + 1;
}
free (parsedConfig);
if (!panels->n_panels) {
return 0;
}
setRefreshAll (core->panels, true);
return 1;
}
static void maximizePanelSize(RPanels *panels) {
RPanel *cur = getCurPanel (panels);
cur->pos.x = 0;
cur->pos.y = 1;
cur->pos.w = panels->can->w;
cur->pos.h = panels->can->h - 1;
cur->refresh = true;
}
static void toggleZoomMode(RPanels *panels) {
RPanel *cur = getCurPanel (panels);
if (panels->mode != PANEL_MODE_ZOOM) {
panels->prevMode = panels->mode;
panels->mode = PANEL_MODE_ZOOM;
savePanelPos (cur);
maximizePanelSize (panels);
} else {
panels->mode = panels->prevMode;
panels->prevMode = PANEL_MODE_DEFAULT;
restorePanelPos (cur);
setRefreshAll (panels, false);
if (panels->fun == PANEL_FUN_SNOW) {
resetSnow (panels);
}
}
}
static void toggleWindowMode(RPanels *panels) {
if (panels->mode != PANEL_MODE_WINDOW) {
panels->prevMode = panels->mode;
panels->mode = PANEL_MODE_WINDOW;
} else {
panels->mode = panels->prevMode;
panels->prevMode = PANEL_MODE_DEFAULT;
}
}
static void showHelp(RCore *core, RPanelsMode mode) {
RStrBuf *p = r_strbuf_new (NULL);
if (!p) {
return;
}
r_cons_clear00 ();
const char *title;
const char **msg;
switch (mode) {
case PANEL_MODE_WINDOW:
title = "Panels Window mode help";
msg = help_msg_panels_window;
break;
case PANEL_MODE_ZOOM:
title = "Panels Zoom mode help";
msg = help_msg_panels_zoom;
break;
default:
title = "Visual Ascii Art Panels";
msg = help_msg_panels;
break;
}
r_core_visual_append_help (p, title, msg);
int ret = r_cons_less_str (r_strbuf_get (p), "?");
r_strbuf_free (p);
if (ret == '?') {
r_core_visual_hud (core);
}
}
static void insertValue(RCore *core) {
RPanels *panels = core->panels;
RPanel *cur = getCurPanel (panels);
char buf[128];
if (!strcmp (cur->cmd, PANEL_CMD_STACK)) {
const char *prompt = "insert hex: ";
panelPrompt (prompt, buf, sizeof (buf));
r_core_cmdf (core, "wx %s @ 0x%08" PFMT64x, buf, cur->addr);
cur->refresh = true;
} else if (!strcmp (cur->cmd, PANEL_CMD_REGISTERS)) {
const char *creg = core->dbg->creg;
if (creg) {
const char *prompt = "new-reg-value> ";
panelPrompt (prompt, buf, sizeof (buf));
r_core_cmdf (core, "dr %s = %s", creg, buf);
cur->refresh = true;
}
} else if (!strcmp (cur->cmd, PANEL_CMD_DISASSEMBLY)) {
const char *prompt = "insert hex: ";
panelPrompt (prompt, buf, sizeof (buf));
r_core_cmdf (core, "wx %s @ 0x%08" PFMT64x, buf, core->offset + core->print->cur);
cur->refresh = true;
} else if (!strcmp (cur->cmd, PANEL_CMD_HEXDUMP)) {
const char *prompt = "insert hex: ";
panelPrompt (prompt, buf, sizeof (buf));
r_core_cmdf (core, "wx %s @ 0x%08" PFMT64x, buf, cur->addr + core->print->cur);
cur->refresh = true;
}
}
R_API RPanels *r_core_panels_new(RCore *core) {
RPanels *panels = R_NEW0 (RPanels);
if (!panels) {
return NULL;
}
int h, w = r_cons_get_size (&h);
if (!init (core, panels, w, h)) {
free (panels);
return NULL;
}
return panels;
}
R_API void r_core_panels_free(RPanels *panels) {
r_cons_switchbuf (true);
if (panels) {
freeAllPanels (panels);
r_cons_canvas_free (panels->can);
sdb_free (panels->db);
ht_pp_free (panels->mht);
free (panels);
}
}
static bool moveToDirection(RPanels *panels, Direction direction) {
RPanel *cur = getCurPanel (panels);
int cur_x0 = cur->pos.x, cur_x1 = cur->pos.x + cur->pos.w - 1, cur_y0 = cur->pos.y, cur_y1 = cur->pos.y + cur->pos.h - 1;
int temp_x0, temp_x1, temp_y0, temp_y1;
int i;
for (i = 0; i < panels->n_panels; i++) {
RPanel *p = getPanel (panels, i);
temp_x0 = p->pos.x;
temp_x1 = p->pos.x + p->pos.w - 1;
temp_y0 = p->pos.y;
temp_y1 = p->pos.y + p->pos.h - 1;
switch (direction) {
case LEFT:
if (temp_x1 == cur_x0) {
if (temp_y1 <= cur_y0 || cur_y1 <= temp_y0) {
continue;
}
panels->curnode = i;
return true;
}
break;
case RIGHT:
if (temp_x0 == cur_x1) {
if (temp_y1 <= cur_y0 || cur_y1 <= temp_y0) {
continue;
}
panels->curnode = i;
return true;
}
break;
case UP:
if (temp_y1 == cur_y0) {
if (temp_x1 <= cur_x0 || cur_x1 <= temp_x0) {
continue;
}
panels->curnode = i;
return true;
}
break;
case DOWN:
if (temp_y0 == cur_y1) {
if (temp_x1 <= cur_x0 || cur_x1 <= temp_x0) {
continue;
}
panels->curnode = i;
return true;
}
break;
default:
break;
}
}
return false;
}
static void createDefaultPanels(RCore *core) {
RPanels *panels = core->panels;
panels->n_panels = 0;
addPanelFrame (core, PANEL_TITLE_DISASSEMBLY, PANEL_CMD_DISASSEMBLY, 0);
RAnalFunction *fun = r_anal_get_fcn_in (core->anal, core->offset, R_ANAL_FCN_TYPE_NULL);
if (fun && !r_list_empty (fun->bbs)) {
addPanelFrame (core, PANEL_TITLE_PSEUDO, PANEL_CMD_PSEUDO, 1);
}
if (panels->layout == PANEL_LAYOUT_DEFAULT_DYNAMIC) {
addPanelFrame (core, PANEL_TITLE_STACK, PANEL_CMD_STACK, 0);
addPanelFrame (core, PANEL_TITLE_STACKREFS, PANEL_CMD_STACKREFS, 0);
addPanelFrame (core, PANEL_TITLE_REGISTERS, PANEL_CMD_REGISTERS, 0);
addPanelFrame (core, PANEL_TITLE_REGISTERREFS, PANEL_CMD_REGISTERREFS,0);
} else {
addPanelFrame (core, PANEL_TITLE_FUNCTIONS, PANEL_CMD_FUNCTIONS, 0);
addPanelFrame (core, PANEL_TITLE_FCNINFO, PANEL_CMD_FCNINFO, 1);
addPanelFrame (core, PANEL_TITLE_SYMBOLS, PANEL_CMD_SYMBOLS, 0);
}
panels->curnode = 0;
}
R_API int r_core_visual_panels(RCore *core, RPanels *panels) {
int i, okey, key;
if (!panels) {
panels = r_core_panels_new (core);
if (!panels) {
r_core_panels_free (panels);
return false;
}
}
RPanels *prev = core->panels;
core->panels = panels;
if (!initPanelsMenu (core)) {
return false;
}
if (!initPanels (core, panels)) {
r_core_panels_free (panels);
return false;
}
r_cons_switchbuf (false);
int originCursor = core->print->cur;
core->print->cur = 0;
core->print->cur_enabled = false;
core->print->col = 0;
bool originVmode = core->vmode;
core->vmode = true;
r_cons_enable_mouse (false);
if (!core->panels_tmpcfg || !loadSavedPanelsLayout (core, true)) {
createDefaultPanels (core);
r_core_panels_layout (panels);
}
repeat:
core->panels = panels;
core->cons->event_resize = NULL; // avoid running old event with new data
core->cons->event_data = core;
core->cons->event_resize = (RConsEvent) doPanelsRefreshOneShot;
r_core_panels_layout_refresh (core);
RPanel *cur = getCurPanel (panels);
if (panels->mode != PANEL_MODE_MENU && panels->fun == PANEL_FUN_SNOW) {
okey = r_cons_readchar_timeout (300);
if (okey == -1) {
cur->refresh = true;
goto repeat;
}
} else {
okey = r_cons_readchar ();
}
key = r_cons_arrow_to_hjkl (okey);
r_cons_switchbuf (true);
if (panels->mode == PANEL_MODE_MENU) {
if (!handleMenu (core, key)) {
goto exit;
}
goto repeat;
}
if (core->print->cur_enabled) {
if (handleCursorMode (core, key)) {
goto repeat;
}
}
if (panels->mode == PANEL_MODE_ZOOM) {
if (handleZoomMode (core, key)) {
goto repeat;
}
}
if (panels->mode == PANEL_MODE_WINDOW) {
if (handleWindowMode (core, key)) {
goto repeat;
}
}
if (!strcmp (cur->cmd, PANEL_CMD_DISASSEMBLY)
&& '0' < key && key <= '9') {
ut8 ch = key;
r_core_visual_jump (core, ch);
cur->addr = core->offset;
cur->refresh = true;
goto repeat;
}
const char *cmd;
RConsCanvas *can = panels->can;
switch (key) {
case 'u':
r_core_cmd0 (core, "s-");
break;
case 'U':
r_core_cmd0 (core, "s+");
break;
case 'n':
case 'N':
{
if (!checkPanelNum (panels)) {
break;
}
char *res = r_cons_input ("New panel with command: ");
bool caching = r_cons_yesno ('y', "Cache the result? (Y/n)");
if (res && *res) {
createNewPanel (core, res, res, caching);
}
free (res);
}
break;
case 'p':
r_core_cmd0 (core, "sp");
break;
case 'P':
r_core_cmd0 (core, "sn");
break;
case '.':
if (!strcmp (cur->cmd, PANEL_CMD_DISASSEMBLY)) {
ut64 addr = r_debug_reg_get (core->dbg, "PC");
if (addr && addr != UT64_MAX) {
r_core_seek (core, addr, 1);
} else {
addr = r_num_get (core->num, "entry0");
if (addr && addr != UT64_MAX) {
r_core_seek (core, addr, 1);
}
}
cur->addr = core->offset;
cur->refresh = true;
}
break;
case '?':
showHelp (core, panels->mode);
break;
case 'b':
r_core_visual_browse (core, NULL);
break;
case 'o':
r_core_visual_showcursor (core, true);
r_core_visual_offset (core);
r_core_visual_showcursor (core, false);
cur->addr = core->offset;
cur->refresh = true;
break;
case 's':
panelSingleStepIn (core);
if (!strcmp (cur->cmd, PANEL_CMD_DISASSEMBLY)) {
cur->addr = core->offset;
}
setRefreshAll (panels, false);
break;
case 'S':
panelSingleStepOver (core);
if (!strcmp (cur->cmd, PANEL_CMD_DISASSEMBLY)) {
cur->addr = core->offset;
}
setRefreshAll (panels, false);
break;
case ' ':
if (r_config_get_i (core->config, "graph.web")) {
r_core_cmd0 (core, "agv $$");
} else {
callVisualGraph (core);
}
break;
case ':':
r_core_visual_prompt_input (core);
cur->addr = core->offset;
setRefreshAll (panels, false);
break;
case 'c':
activateCursor (core);
break;
case 'C':
can->color = !can->color;
// r_config_toggle (core->config, "scr.color");
// refresh graph
setRefreshAll (panels, false);
break;
case 'r':
r_core_cmd0 (core, "e!asm.hint.jmp");
r_core_cmd0 (core, "e!asm.hint.lea");
setRefreshAll (panels, false);
break;
case 'R':
if (r_config_get_i (core->config, "scr.randpal")) {
r_core_cmd0 (core, "ecr");
} else {
r_core_cmd0 (core, "ecn");
}
doPanelsRefresh (core);
break;
case 'A':
r_core_visual_asm (core, core->offset);
break;
case 'd':
r_core_visual_define (core, "", 0);
setRefreshAll (panels, false);
break;
case 'D':
replaceCmd (panels, PANEL_TITLE_DISASSEMBLY, PANEL_CMD_DISASSEMBLY, 0);
break;
case 'j':
r_cons_switchbuf (false);
cur->directionCb (core, (int)DOWN);
break;
case 'k':
r_cons_switchbuf (false);
cur->directionCb (core, (int)UP);
break;
case 'K':
r_cons_switchbuf (false);
for (i = 0; i < PANEL_CONFIG_PAGE; i++) {
cur->directionCb (core, (int)UP);
}
break;
case 'J':
r_cons_switchbuf (false);
for (i = 0; i < PANEL_CONFIG_PAGE; i++) {
cur->directionCb (core, (int)DOWN);
}
break;
case '_':
hudstuff (core);
break;
case 'x':
r_core_visual_refs (core, true, true);
cur->addr = core->offset;
setRefreshAll (panels, false);
break;
case 'X':
delCurPanel (panels);
setRefreshAll (panels, false);
break;
case 9: // TAB
handleTabKey (core, false);
break;
case 'Z': // SHIFT-TAB
handleTabKey (core, true);
break;
case 'M':
{
if (!checkPanelNum (panels)) {
break;
}
char *name = r_cons_input ("Name: ");
char *cmd = r_cons_input ("Command: ");
bool caching = r_cons_yesno ('y', "Cache the result? (Y/n)");
if (name && *name && cmd && *cmd) {
createNewPanel (core, name, cmd, caching);
}
free (name);
free (cmd);
}
break;
case 'e':
{
char *new_name = r_cons_input ("New name: ");
char *new_cmd = r_cons_input ("New command: ");
bool caching = r_cons_yesno ('y', "Cache the result? (Y/n)");
if (new_name && *new_name && new_cmd && *new_cmd) {
replaceCmd (panels, new_name, new_cmd, caching);
}
free (new_name);
free (new_cmd);
}
break;
case 'm':
panels->mode = PANEL_MODE_MENU;
break;
case 'g':
if (checkFunc (core)) {
replaceCmd (panels, PANEL_TITLE_GRAPH, PANEL_CMD_GRAPH, 1);
}
break;
case 'h':
r_cons_switchbuf (false);
cur->directionCb (core, (int)LEFT);
break;
case 'l':
r_cons_switchbuf (false);
cur->directionCb (core, (int)RIGHT);
break;
case 'L':
setRefreshAll (panels, true);
break;
case 'V':
if (r_config_get_i (core->config, "graph.web")) {
r_core_cmd0 (core, "agv $$");
} else {
callVisualGraph (core);
}
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 '/':
r_core_cmd0 (core, "?i highlight;e scr.highlight=`yp`");
break;
case 'z':
if (panels->curnode > 0) {
swapPanels (panels, 0, panels->curnode);
panels->curnode = 0;
setRefreshAll (panels, false);
}
break;
case 'w':
toggleWindowMode (panels);
setRefreshAll (panels, false);
break;
case 0x0d: // "\\n"
toggleZoomMode (panels);
break;
case '|':
splitPanelVertical (core);
break;
case '-':
splitPanelHorizontal (core);
break;
case '*':
if (checkFunc (core)) {
r_cons_canvas_free (can);
panels->can = NULL;
replaceCmd (panels, PANEL_TITLE_PSEUDO, PANEL_CMD_PSEUDO, 1);
int h, w = r_cons_get_size (&h);
panels->can = createNewCanvas (core, w, h);
}
break;
case '(':
if (panels->fun != PANEL_FUN_SNOW) {
panels->fun = PANEL_FUN_SNOW;
} else {
panels->fun = PANEL_FUN_NOFUN;
resetSnow (panels);
}
break;
case R_CONS_KEY_F1:
cmd = r_config_get (core->config, "key.f1");
if (cmd && *cmd) {
(void)r_core_cmd0 (core, cmd);
}
break;
case R_CONS_KEY_F2:
cmd = r_config_get (core->config, "key.f2");
if (cmd && *cmd) {
(void)r_core_cmd0 (core, cmd);
} else {
panelBreakpoint (core);
}
break;
case R_CONS_KEY_F3:
cmd = r_config_get (core->config, "key.f3");
if (cmd && *cmd) {
(void)r_core_cmd0 (core, cmd);
}
break;
case R_CONS_KEY_F4:
cmd = r_config_get (core->config, "key.f4");
if (cmd && *cmd) {
(void)r_core_cmd0 (core, cmd);
}
break;
case R_CONS_KEY_F5:
cmd = r_config_get (core->config, "key.f5");
if (cmd && *cmd) {
(void)r_core_cmd0 (core, cmd);
}
break;
case R_CONS_KEY_F6:
cmd = r_config_get (core->config, "key.f6");
if (cmd && *cmd) {
(void)r_core_cmd0 (core, cmd);
}
break;
case R_CONS_KEY_F7:
cmd = r_config_get (core->config, "key.f7");
if (cmd && *cmd) {
(void)r_core_cmd0 (core, cmd);
} else {
panelSingleStepIn (core);
setRefreshAll (panels, false);
}
break;
case R_CONS_KEY_F8:
cmd = r_config_get (core->config, "key.f8");
if (cmd && *cmd) {
(void)r_core_cmd0 (core, cmd);
} else {
panelSingleStepOver (core);
setRefreshAll (panels, false);
}
break;
case R_CONS_KEY_F9:
cmd = r_config_get (core->config, "key.f9");
if (cmd && *cmd) {
(void)r_core_cmd0 (core, cmd);
} else {
panelContinue (core);
}
break;
case R_CONS_KEY_F10:
cmd = r_config_get (core->config, "key.f10");
if (cmd && *cmd) {
(void)r_core_cmd0 (core, cmd);
}
break;
case R_CONS_KEY_F11:
cmd = r_config_get (core->config, "key.f11");
if (cmd && *cmd) {
(void)r_core_cmd0 (core, cmd);
}
break;
case R_CONS_KEY_F12:
cmd = r_config_get (core->config, "key.f12");
if (cmd && *cmd) {
(void)r_core_cmd0 (core, cmd);
}
break;
case '!':
r_cons_2048 (core->panels->can->color);
break;
case 'q':
case -1: // EOF
goto exit;
#if 0
case 27: // ESC
if (r_cons_readchar () == 91) {
if (r_cons_readchar () == 90) {}
}
break;
#endif
default:
// eprintf ("Key %d\n", key);
// sleep (1);
break;
}
goto repeat;
exit:
savePanelsLayout (core, true);
core->cons->event_resize = NULL;
core->cons->event_data = NULL;
core->print->cur = originCursor;
core->print->cur_enabled = false;
core->print->col = 0;
core->vmode = originVmode;
r_core_panels_free (panels);
core->panels = prev;
return true;
}