Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add "save to file" to ag*w commands + colorize comments like ";arg1" #10860

Merged
merged 8 commits into from Aug 4, 2018
2 changes: 1 addition & 1 deletion libr/anal/var.c
Expand Up @@ -703,7 +703,7 @@ R_API void extract_rarg(RAnal *anal, RAnalOp *op, RAnalFunction *fcn, int *reg_s
r_anal_var_link (anal, op->addr, op->var);
}
r_anal_var_access (anal, fcn->addr, 'r', 1, delta, 0, op->addr);
r_meta_set_string (anal, R_META_TYPE_COMMENT, op->addr, vname);
r_meta_set_string (anal, R_META_TYPE_VARTYPE, op->addr, vname);
free (vname);
}
if (op->dst && opdreg && !strcmp (opdreg, regname)) {
Expand Down
30 changes: 1 addition & 29 deletions libr/core/cconfig.c
Expand Up @@ -2295,34 +2295,6 @@ static char *getViewerPath() {
return NULL;
}

R_API char* r_core_graph_cmd(RCore *core, char *r2_cmd) {
char *cmd = NULL;
char *xdotPath = r_file_path ("xdot");
const char *ext = r_config_get (core->config, "graph.extension");
if (r_file_exists (xdotPath)) {
cmd = r_str_newf ("%s > a.dot;!xdot a.dot", r2_cmd);
} else {
char *dotPath = r_file_path ("dot");
if (r_file_exists (dotPath)) {
R_FREE (dotPath);
char *viewer = getViewerPath();
if (viewer) {
cmd = r_str_newf ("%s > a.dot;!dot -T%s -oa.%s a.dot;!%s a.%s", r2_cmd, ext, ext, viewer, ext);
free (viewer);
} else {
eprintf ("Cannot find a valid picture viewer");
}
} else {
cmd = r_str_new ("agf");
}
free (dotPath);
}
free (xdotPath);
return cmd;
}



#define SLURP_LIMIT (10*1024*1024)
R_API int r_core_config_init(RCore *core) {
int i;
Expand Down Expand Up @@ -2840,7 +2812,7 @@ R_API int r_core_config_init(RCore *core) {
/* graph */
SETPREF ("graph.comments", "true", "Show disasm comments in graph");
SETPREF ("graph.cmtright", "false", "Show comments at right");
SETCB ("graph.extension", "gif", &cb_graphformat, "Graph extension when using 'w' format (png, jpg, pdf, ps, svg, json)");
SETCB ("graph.gv.format", "gif", &cb_graphformat, "Graph image extension when using 'w' format (png, jpg, pdf, ps, svg, json)");
SETPREF ("graph.refs", "false", "Graph references in callgraphs (.agc*;aggi)");
SETI ("graph.edges", 2, "0=no edges, 1=simple edges, 2=avoid collisions");
SETI ("graph.layout", 0, "Graph layout (0=vertical, 1=horizontal)");
Expand Down
161 changes: 102 additions & 59 deletions libr/core/cmd_anal.c
Expand Up @@ -386,31 +386,31 @@ static const char *help_msg_afvs[] = {
static const char *help_msg_ag[] = {
"Usage:", "ag<graphtype><format> [addr]", "",
"Graph commands:", "", "",
"agc", "[format] [fcn addr]", "Function callgraph",
"agf", "[format] [fcn addr]", "Basic blocks function graph",
"agx", "[format] [addr]", "Cross references graph",
"agr", "[format] [fcn addr]", "References graph",
"aga", "[format] [fcn addr]", "Data references graph",
"aga", "[format] [@ fcn addr]", "Data references graph",
"agA", "[format]", "Global data references graph",
"agc", "[format] [@ fcn addr]", "Function callgraph",
"agC", "[format]", "Global callgraph",
"agd", "[format] [fcn addr]", "Diff graph",
"agf", "[format] [@ fcn addr]", "Basic blocks function graph",
"agi", "[format]", "Imports graph",
"agC", "[format]", "Global callgraph",
"agr", "[format] [@ fcn addr]", "References graph",
"agR", "[format]", "Global references graph",
"agA", "[format]", "Global data references graph",
"agx", "[format] [@ addr]", "Cross references graph",
"agg", "[format]", "Custom graph",
"ag-", "", "Clear the custom graph",
"agn", "[?] title body", "Add a node to the custom graph",
"age", "[?] title1 title2", "Add an edge to the custom graph",
"","","",
"Output formats:", "", "",
"<blank>", "", "Ascii art",
"v", "", "Interactive ascii art",
"t", "", "Tiny ascii art",
"*", "", "r2 commands",
"d", "", "Graphviz dot",
"j", "", "json ('J' for formatted disassembly)",
"g", "", "Graph Modelling Language (gml)",
"j", "", "json ('J' for formatted disassembly)",
"k", "", "SDB key-value",
"*", "", "r2 commands",
"w", "", "Web/image (see graph.extension and graph.web)",
"t", "", "Tiny ascii art",
"v", "", "Interactive ascii art",
"w", " [path]", "Write to path or display graph image (see graph.gv.format and graph.web)",
NULL
};

Expand Down Expand Up @@ -5740,6 +5740,53 @@ static void agraph_print_node(RANode *n, void *user) {
free (encbody);
}

static char *getViewerPath() {
int i;
const char *viewers[] = {
"open",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where are my changes? :(

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait, maybe I fucked up the merge of the conflicts, let me check

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I copied the old getViewerPath and left the new one in cconfig.c :(
Sorry, my bad, will fix it

"geeqie",
"gqview",
"eog",
"xdg-open",
NULL
};
for (i = 0; viewers[i]; i++) {
char *dotPath = r_file_path (viewers[i]);
if (dotPath && strcmp (dotPath, viewers[i])) {
return dotPath;
}
free (dotPath);
}
return NULL;
}

static char* graph_cmd(RCore *core, char *r2_cmd, const char *save_path) {
char *cmd = NULL;
const char *ext = r_config_get (core->config, "graph.gv.format");
char *dotPath = r_file_path ("dot");
if (!r_file_exists (dotPath)) {
free (dotPath);
dotPath = r_file_path ("xdot");
}
if (r_file_exists (dotPath)) {
if (save_path && *save_path) {
cmd = r_str_newf ("%s > a.dot;!%s -T%s -o%s a.dot;", r2_cmd, dotPath, ext, save_path);
} else {
char *viewer = getViewerPath();
if (viewer) {
cmd = r_str_newf ("%s > a.dot;!%s -T%s -oa.%s a.dot;!%s a.%s", r2_cmd, dotPath, ext, ext, viewer, ext);
free (viewer);
} else {
eprintf ("Cannot find a valid picture viewer");
}
}
} else {
cmd = r_str_new ("agf");
}
free (dotPath);
return cmd;
}

static void agraph_print_edge_dot(RANode *from, RANode *to, void *user) {
r_cons_printf ("\"%s\" -> \"%s\"\n", from->title, to->title);
}
Expand Down Expand Up @@ -5895,14 +5942,16 @@ static void cmd_agraph_print(RCore *core, const char *input) {
}
break;
}
case 'd': // "aggd" - dot format
case 'd': { // "aggd" - dot format
const char *font = r_config_get (core->config, "graph.font");
r_cons_printf ("digraph code {\ngraph [bgcolor=white];\n"
"node [color=lightgray, style=filled shape=box "
"fontname=\"Courier\" fontsize=\"8\"];\n");
"fontname=\"%s\" fontsize=\"8\"];\n", font);
r_agraph_foreach (core->graph, agraph_print_node_dot, NULL);
r_agraph_foreach_edge (core->graph, agraph_print_edge_dot, NULL);
r_cons_printf ("}\n");
break;
}
case '*': // "agg*" -
r_agraph_foreach (core->graph, agraph_print_node, NULL);
r_agraph_foreach_edge (core->graph, agraph_print_edge, NULL);
Expand All @@ -5923,8 +5972,12 @@ static void cmd_agraph_print(RCore *core, const char *input) {
if (r_config_get_i (core->config, "graph.web")) {
r_core_cmd0 (core, "=H /graph/");
} else {
char *cmd = r_core_graph_cmd (core, "aggd");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

char *cmd = graph_cmd (core, "aggd", input + 1);
if (cmd && *cmd) {
if (input[1]) {
r_cons_printf ("Saving to file %s ...\n", input + 1);
r_cons_flush ();
}
r_core_cmd0 (core, cmd);
}
free (cmd);
Expand All @@ -5944,15 +5997,13 @@ static void cmd_anal_graph(RCore *core, const char *input) {
r_core_visual_graph (core, NULL, NULL, false);
break;
case ' ':{ // "agf "
ut64 off_fcn = (*(input + 2)) ? r_num_math (core->num, input + 2) : core->offset;
RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, off_fcn, 0);
RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset, 0);
r_core_visual_graph (core, NULL, fcn, false);
break;
}
case 'v': // "agfv"
eprintf ("\rRendering graph...");
ut64 off_fcn = (*(input + 2)) ? r_num_math (core->num, input + 2) : core->offset;
RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, off_fcn, 0);
RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset, 0);
if (fcn) {
r_core_visual_graph (core, NULL, fcn, 1);
}
Expand All @@ -5962,8 +6013,7 @@ static void cmd_anal_graph(RCore *core, const char *input) {
case 't': { // "agft" - tiny graph
int e = r_config_get_i (core->config, "graph.edges");
r_config_set_i (core->config, "graph.edges", 0);
ut64 off_fcn = (*(input + 2)) ? r_num_math (core->num, input + 2) : core->offset;
RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, off_fcn, 0);
RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset, 0);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why drop the use of specifying the offset as argument?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it makes more sense to have a consistent api that uses @ addr to seek to address, instead of having arguments for the seek.

r_core_visual_graph (core, NULL, fcn, 2);
r_config_set_i (core->config, "graph.edges", e);
break;
Expand All @@ -5985,29 +6035,30 @@ static void cmd_anal_graph(RCore *core, const char *input) {
R_CORE_ANAL_JSON | R_CORE_ANAL_JSON_FORMAT_DISASM);
break;
case 'g':{ // "agfg"
ut64 off_fcn = (*(input + 2)) ? r_num_math (core->num, input + 2) : core->offset;
RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, off_fcn, 0);
RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset, 0);
r_core_print_bb_gml (core, fcn);
break;
}
case 'k':{ // "agfk"
ut64 addr = (*(input + 2)) ? r_num_math (core->num, input + 2) : core->offset;
r_core_cmdf (core, "ag-; .agf* %"PFMT64u"; aggk", addr);
r_core_cmdf (core, "ag-; .agf* @ %"PFMT64u"; aggk", core->offset);
break;
}
case '*':{// "agf*"
ut64 off_fcn = (*(input + 2)) ? r_num_math (core->num, input + 2) : core->offset;
RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, off_fcn, 0);
RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset, 0);
r_core_print_bb_custom (core, fcn);
break;
}
case 'w':// "agfw"
if (r_config_get_i (core->config, "graph.web")) {
r_core_cmd0 (core, "=H /graph/");
} else {
char *cmdargs = r_str_newf ("agfd %"PFMT64u, r_num_math (core->num, input + 2));
char *cmd = r_core_graph_cmd (core, cmdargs);
char *cmdargs = r_str_newf ("agfd @ 0x%"PFMT64x, core->offset);
char *cmd = graph_cmd (core, cmdargs, input + 2);
if (cmd && *cmd) {
if (*(input + 2)) {
r_cons_printf ("Saving to file %s ...\n", input + 2);
r_cons_flush ();
}
r_core_cmd0 (core, cmd);
}
free (cmd);
Expand Down Expand Up @@ -6043,7 +6094,7 @@ static void cmd_anal_graph(RCore *core, const char *input) {
case ' ':
case 0: {
core->graph->is_callgraph = true;
r_core_cmdf (core, "ag-; .agC*; agg%c;", input[1]);
r_core_cmdf (core, "ag-; .agC*; agg%s;", input + 1);
core->graph->is_callgraph = false;
break;
}
Expand Down Expand Up @@ -6077,14 +6128,12 @@ static void cmd_anal_graph(RCore *core, const char *input) {
case 'w':
case ' ': {
core->graph->is_callgraph = true;
ut64 addr = input[2] ? r_num_math (core->num, input + 2) : core->offset;
r_core_cmdf (core, "ag-; .agr* %"PFMT64u"; agg%c;", addr, input[1]);
r_core_cmdf (core, "ag-; .agr* @ %"PFMT64u"; agg%s;", core->offset, input + 1);
core->graph->is_callgraph = false;
break;
}
case '*': {
ut64 addr = input[2] ? r_num_math (core->num, input + 2) : core->offset;
r_core_anal_coderefs (core, addr);
r_core_anal_coderefs (core, core->offset);
}
break;
case 0:
Expand All @@ -6108,7 +6157,7 @@ static void cmd_anal_graph(RCore *core, const char *input) {
case ' ':
case 0: {
core->graph->is_callgraph = true;
r_core_cmdf (core, "ag-; .agR*; agg%c;", input[1]);
r_core_cmdf (core, "ag-; .agR*; agg%s;", input + 1);
core->graph->is_callgraph = false;
break;
}
Expand Down Expand Up @@ -6140,13 +6189,11 @@ static void cmd_anal_graph(RCore *core, const char *input) {
case 'k':
case 'w':
case ' ': {
ut64 addr = input[2] ? r_num_math (core->num, input + 2) : core->offset;
r_core_cmdf (core, "ag-; .agx* %"PFMT64u"; agg%c;", addr, input[1]);
r_core_cmdf (core, "ag-; .agx* @ %"PFMT64u"; agg%s;", core->offset, input + 1);
break;
}
case '*': {
ut64 addr = input[2] ? r_num_math (core->num, input + 2) : core->offset;
r_core_anal_codexrefs (core, addr);
r_core_anal_codexrefs (core, core->offset);
}
break;
case 0:
Expand All @@ -6169,7 +6216,7 @@ static void cmd_anal_graph(RCore *core, const char *input) {
case 'w':
case ' ':
case 0:
r_core_cmdf (core, "ag-; .agi*; agg%c;", input[1]);
r_core_cmdf (core, "ag-; .agi*; agg%s;", input + 1);
break;
case '*':
r_core_anal_importxrefs (core);
Expand All @@ -6187,8 +6234,7 @@ static void cmd_anal_graph(RCore *core, const char *input) {
case 'w':
case ' ': {
core->graph->is_callgraph = true;
ut64 addr = input[2] ? r_num_math (core->num, input + 2) : core->offset;
r_core_cmdf (core, "ag-; .agc* %"PFMT64u"; agg%c;", addr, input[1]);
r_core_cmdf (core, "ag-; .agc* @ %"PFMT64u"; agg%s;", core->offset, input + 1);
core->graph->is_callgraph = false;
break;
}
Expand All @@ -6198,24 +6244,20 @@ static void cmd_anal_graph(RCore *core, const char *input) {
core->graph->is_callgraph = false;
break;
case 'g': {
ut64 addr = input[2] ? r_num_math (core->num, input + 2): core->offset;
r_core_anal_callgraph (core, addr, R_GRAPH_FORMAT_GMLFCN);
r_core_anal_callgraph (core, core->offset, R_GRAPH_FORMAT_GMLFCN);
break;
}
case 'd': {
ut64 addr = input[2] ? r_num_math (core->num, input + 2): core->offset;
r_core_anal_callgraph (core, addr, R_GRAPH_FORMAT_DOT);
r_core_anal_callgraph (core, core->offset, R_GRAPH_FORMAT_DOT);
break;
}
case 'J':
case 'j': {
ut64 addr = input[2]? r_num_math (core->num, input + 2): core->offset;
r_core_anal_callgraph (core, addr, R_GRAPH_FORMAT_JSON);
r_core_anal_callgraph (core, core->offset, R_GRAPH_FORMAT_JSON);
break;
}
case '*': {
ut64 addr = input[2]? r_num_math (core->num, input + 2): core->offset;
r_core_anal_callgraph (core, addr, R_GRAPH_FORMAT_CMD);
r_core_anal_callgraph (core, core->offset, R_GRAPH_FORMAT_CMD);
break;
}
default:
Expand Down Expand Up @@ -6246,16 +6288,14 @@ static void cmd_anal_graph(RCore *core, const char *input) {
case 'J':
case 'd':
case ' ': {
ut64 addr = input[2] ? r_num_math (core->num, input + 2): core->offset;
r_core_cmdf (core, "ag-; .aga* %"PFMT64u"; agg%c;", addr, input[1]);
r_core_cmdf (core, "ag-; .aga* @ %"PFMT64u"; agg%s;", core->offset, input + 1);
break;
}
case 0:
r_core_cmd0 (core, "ag-; .aga* $$; agg;");
break;
case '*': {
ut64 addr = input[2]? r_num_math (core->num, input + 2): core->offset;
r_core_anal_datarefs (core, addr);
r_core_anal_datarefs (core, core->offset);
break;
}
default:
Expand Down Expand Up @@ -6315,9 +6355,8 @@ static void cmd_anal_graph(RCore *core, const char *input) {
break;
}
case 'w': {
char *cmdargs = r_str_newf ("agdd %"PFMT64u,
input[2] ? r_num_math (core->num, input + 2) : core->offset);
char *cmd = r_core_graph_cmd (core, cmdargs);
char *cmdargs = r_str_newf ("agdd 0x%"PFMT64x, core->offset);
char *cmd = graph_cmd (core, cmdargs, input + 2);
if (cmd && *cmd) {
r_core_cmd0 (core, cmd);
}
Expand All @@ -6334,9 +6373,13 @@ static void cmd_anal_graph(RCore *core, const char *input) {
if (r_config_get_i (core->config, "graph.web")) {
r_core_cmd0 (core, "=H /graph/");
} else {
char *cmdargs = r_str_newf ("agfd %"PFMT64u, r_num_math (core->num, input + 1));
char *cmd = r_core_graph_cmd (core, cmdargs);
char *cmdargs = r_str_newf ("agfd @ 0x%"PFMT64x, core->offset);
char *cmd = graph_cmd (core, cmdargs, input + 1);
if (cmd && *cmd) {
if (input[1]) {
r_cons_printf ("Saving to file %s ...\n", input + 1);
r_cons_flush ();
}
r_core_cmd0 (core, cmd);
}
free (cmd);
Expand Down