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 (i)CFG node type annotations + bug fix #4221

Merged
merged 14 commits into from
Feb 14, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 32 additions & 13 deletions librz/core/agraph.c
Original file line number Diff line number Diff line change
Expand Up @@ -3724,11 +3724,17 @@ RZ_API void rz_agraph_set_title(RzAGraph *g, const char *title) {

/**
* \brief Convert a RzGraphNodeInfo \p info to RzANode and add to \p g.
Rot127 marked this conversation as resolved.
Show resolved Hide resolved
*
* \param g The agraph to append the nodes to.
* \param info The node info to add.
* \param utf8 If true, the node title can contain UTF-8 characters. If false, it will only contain ASCII.
*
* \return Pointer to the added node. Or NULL in case of failure.
*/
RZ_API RZ_BORROW RzANode *rz_agraph_add_node_from_node_info(RZ_NONNULL const RzAGraph *g, RZ_NONNULL const RzGraphNodeInfo *info) {
RZ_API RZ_BORROW RzANode *rz_agraph_add_node_from_node_info(RZ_NONNULL const RzAGraph *g, RZ_NONNULL const RzGraphNodeInfo *info, bool utf8) {
rz_return_val_if_fail(g && info, NULL);
RzANode *an = NULL;
char title[20] = { 0 };
char title[64] = { 0 };
switch (info->type) {
default:
RZ_LOG_ERROR("Node type %d not handled.\n", info->type);
Expand All @@ -3740,16 +3746,19 @@ RZ_API RZ_BORROW RzANode *rz_agraph_add_node_from_node_info(RZ_NONNULL const RzA
}
an->offset = info->def.offset;
break;
case RZ_GRAPH_NODE_TYPE_CFG:
rz_strf(title, "0x%" PFMT64x, info->cfg.address);
an = rz_agraph_add_node(g, title, "");
case RZ_GRAPH_NODE_TYPE_CFG: {
char *cfg_title = rz_str_appendf(NULL, "0x%" PFMT64x "%s", info->cfg.address, rz_graph_get_node_subtype_annotation(info->subtype, utf8));
an = rz_agraph_add_node(g, cfg_title, "");
free(cfg_title);
if (!an) {
return NULL;
}
an->offset = info->cfg.address;
break;
}
case RZ_GRAPH_NODE_TYPE_ICFG:
rz_strf(title, "0x%" PFMT64x, info->icfg.address);
rz_strf(title, "0x%" PFMT64x "%s", info->icfg.address,
info->subtype & RZ_GRAPH_NODE_SUBTYPE_ICFG_MALLOC ? " (alloc)" : "");
an = rz_agraph_add_node(g, title, "");
if (!an) {
return NULL;
Expand Down Expand Up @@ -4960,9 +4969,17 @@ RZ_IPI int rz_core_visual_graph(RzCore *core, RzAGraph *g, RzAnalysisFunction *_

/**
* \brief Create RzAGraph from generic RzGraph with RzGraphNodeInfo as node data at \p ag from \p g
* \return Success
*
* \param ag The RzAGraph to append the nodes to.
* \param g The graph to build the RzAGraph from.
* \param info The node info to add.
* \param free_on_fail If true, \p ag will be freed in case of failure. If false, \p ag is not freed.
* \param utf8 If true, the node titles can contain UTF-8 characters. If false, they will only contain ASCII.
*
* \return true In case of success.
* \return false In case of failure.
*/
RZ_API bool create_agraph_from_graph_at(RZ_NONNULL RzAGraph *ag, RZ_NONNULL const RzGraph /*<RzGraphNodeInfo *>*/ *g, bool free_on_fail) {
RZ_API bool create_agraph_from_graph_at(RZ_NONNULL RzAGraph *ag, RZ_NONNULL const RzGraph /*<RzGraphNodeInfo *>*/ *g, bool free_on_fail, bool utf8) {
rz_return_val_if_fail(ag && g, false);
ag->need_reload_nodes = false;
// Cache lookup to build edges
Expand All @@ -4978,7 +4995,7 @@ RZ_API bool create_agraph_from_graph_at(RZ_NONNULL RzAGraph *ag, RZ_NONNULL cons
// Traverse the list, create new ANode for each Node
rz_list_foreach (g->nodes, iter, node) {
RzGraphNodeInfo *info = node->data;
RzANode *a_node = rz_agraph_add_node_from_node_info(ag, info);
RzANode *a_node = rz_agraph_add_node_from_node_info(ag, info, utf8);
if (!a_node) {
goto failure;
}
Expand Down Expand Up @@ -5018,17 +5035,19 @@ RZ_API bool create_agraph_from_graph_at(RZ_NONNULL RzAGraph *ag, RZ_NONNULL cons
/**
* \brief Create RzAGraph from generic RzGraph with RzGraphNodeInfo as node data
*
* \param graph <RzGraphNodeInfo>
* \return RzAGraph* NULL if failure
* \param graph The graph to create the RzAGraph from.
* \param utf8 If true, the node titles can contain UTF-8 characters. If false, they are ASCII only.
*
* \return RzAGraph* The agraph or NULL in case of failure
*/
RZ_API RZ_OWN RzAGraph *create_agraph_from_graph(RZ_NONNULL const RzGraph /*<RzGraphNodeInfo *>*/ *graph) {
RZ_API RZ_OWN RzAGraph *create_agraph_from_graph(RZ_NONNULL const RzGraph /*<RzGraphNodeInfo *>*/ *graph, bool utf8) {
rz_return_val_if_fail(graph, NULL);

RzAGraph *result_agraph = rz_agraph_new(rz_cons_canvas_new(1, 1));
if (!result_agraph) {
return NULL;
}
if (!create_agraph_from_graph_at(result_agraph, graph, true)) {
if (!create_agraph_from_graph_at(result_agraph, graph, true, utf8)) {
return NULL;
}
return result_agraph;
Expand Down
2 changes: 1 addition & 1 deletion librz/core/cagraph.c
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ RZ_IPI bool rz_core_agraph_apply(RzCore *core, RzGraph /*<RzGraphNodeInfo *>*/ *
if (!(core && core->graph && graph)) {
return false;
}
if (!create_agraph_from_graph_at(core->graph, graph, false)) {
if (!create_agraph_from_graph_at(core->graph, graph, false, rz_config_get_b(core->config, "scr.utf8"))) {
return false;
}
if (rz_core_agraph_is_shortcuts(core, core->graph)) {
Expand Down
8 changes: 8 additions & 0 deletions librz/core/cgraph.c
Original file line number Diff line number Diff line change
Expand Up @@ -1065,6 +1065,10 @@ RZ_API RZ_OWN RzGraph /*<RzGraphNodeInfo *>*/ *rz_core_graph_cfg(RZ_NONNULL RzCo
}

if (curr_op.jump != UT64_MAX && !is_call(&curr_op)) {
if (rz_io_nread_at(core->io, curr_op.jump, buf, sizeof(buf)) < 0) {
RZ_LOG_ERROR("Could not generate CFG at 0x%" PFMT64x ". rz_io_nread_at() failed at 0x%" PFMT64x ".\n", addr, cur_addr);
goto error;
}
if (rz_analysis_op(core->analysis, &target_op, curr_op.jump, buf, sizeof(buf), RZ_ANALYSIS_OP_MASK_DISASM) <= 0) {
rz_analysis_op_fini(&target_op);
goto error;
Expand All @@ -1075,6 +1079,10 @@ RZ_API RZ_OWN RzGraph /*<RzGraphNodeInfo *>*/ *rz_core_graph_cfg(RZ_NONNULL RzCo
rz_analysis_op_fini(&target_op);
}
if (curr_op.fail != UT64_MAX && !is_call(&curr_op)) {
if (rz_io_nread_at(core->io, curr_op.fail, buf, sizeof(buf)) < 0) {
RZ_LOG_ERROR("Could not generate CFG at 0x%" PFMT64x ". rz_io_nread_at() failed at 0x%" PFMT64x ".\n", addr, cur_addr);
goto error;
}
if (rz_analysis_op(core->analysis, &target_op, curr_op.fail, buf, sizeof(buf), RZ_ANALYSIS_OP_MASK_DISASM) <= 0) {
rz_analysis_op_fini(&target_op);
goto error;
Expand Down
6 changes: 3 additions & 3 deletions librz/include/rz_agraph.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ RZ_API void rz_agraph_set_title(RzAGraph *g, const char *title);
RZ_API RzANode *rz_agraph_get_first_node(const RzAGraph *g);
RZ_API RzANode *rz_agraph_get_node(const RzAGraph *g, const char *title);
RZ_API RzANode *rz_agraph_add_node(const RzAGraph *g, const char *title, const char *body);
RZ_API RZ_BORROW RzANode *rz_agraph_add_node_from_node_info(RZ_NONNULL const RzAGraph *g, RZ_NONNULL const RzGraphNodeInfo *info);
RZ_API RZ_BORROW RzANode *rz_agraph_add_node_from_node_info(RZ_NONNULL const RzAGraph *g, RZ_NONNULL const RzGraphNodeInfo *info, bool utf8);
RZ_API bool rz_agraph_del_node(const RzAGraph *g, const char *title);
RZ_API void rz_agraph_add_edge(const RzAGraph *g, RzANode *a, RzANode *b);
RZ_API void rz_agraph_add_edge_at(const RzAGraph *g, RzANode *a, RzANode *b, int nth);
Expand All @@ -110,8 +110,8 @@ RZ_API Sdb *rz_agraph_get_sdb(RzAGraph *g);
RZ_API void rz_agraph_foreach(RzAGraph *g, RzANodeCallback cb, void *user);
RZ_API void rz_agraph_foreach_edge(RzAGraph *g, RAEdgeCallback cb, void *user);
RZ_API void rz_agraph_set_curnode(RzAGraph *g, RzANode *node);
RZ_API bool create_agraph_from_graph_at(RZ_NONNULL RzAGraph *ag, RZ_NONNULL const RzGraph /*<RzGraphNodeInfo *>*/ *g, bool free_on_fail);
RZ_API RZ_OWN RzAGraph *create_agraph_from_graph(RZ_NONNULL const RzGraph /*<RzGraphNodeInfo *>*/ *graph);
RZ_API bool create_agraph_from_graph_at(RZ_NONNULL RzAGraph *ag, RZ_NONNULL const RzGraph /*<RzGraphNodeInfo *>*/ *g, bool free_on_fail, bool utf8);
RZ_API RZ_OWN RzAGraph *create_agraph_from_graph(RZ_NONNULL const RzGraph /*<RzGraphNodeInfo *>*/ *graph, bool utf8);
#endif

#endif
1 change: 1 addition & 0 deletions librz/include/rz_util/rz_graph_drawable.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ typedef struct rz_analysis_graph_node_info_t {
};
} RzGraphNodeInfo;

RZ_API RZ_OWN char *rz_graph_get_node_subtype_annotation(RzGraphNodeSubType subtype, bool utf8);
RZ_API RZ_OWN RzGraphNodeInfo *rz_graph_get_node_info_data(RZ_BORROW void *data);
RZ_API void rz_graph_free_node_info(RZ_NULLABLE void *ptr);
RZ_API RzGraphNodeInfo *rz_graph_create_node_info_default(const char *title, const char *body, ut64 offset);
Expand Down
80 changes: 71 additions & 9 deletions librz/util/graph_drawable.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,47 @@
#include <rz_core.h>
#include <rz_util/rz_graph_drawable.h>

/**
* \brief Translates the \p subtype flags of a node to its annotation symbols.
*
* \param subtype The sub-type flags of the node.
* \param utf8 If true, the symbols will be UTF-8 characters. If false, they are in ASCII.
*
* \return A string with all symbols.
*/
RZ_API RZ_OWN char *rz_graph_get_node_subtype_annotation(RzGraphNodeSubType subtype, bool utf8) {
Rot127 marked this conversation as resolved.
Show resolved Hide resolved
char *annotation = rz_str_newf(" ");
if (!utf8) {
rz_str_append(annotation, "(");
}
if (subtype == RZ_GRAPH_NODE_SUBTYPE_NONE) {
rz_str_append(annotation, utf8 ? "○" : ".");
if (!utf8) {
rz_str_append(annotation, ")");
}
return annotation;
}
if (subtype & RZ_GRAPH_NODE_SUBTYPE_CFG_ENTRY) {
rz_str_append(annotation, utf8 ? "↓" : "e");
}
if (subtype & RZ_GRAPH_NODE_SUBTYPE_CFG_CALL) {
rz_str_append(annotation, utf8 ? "⇢" : "C");
}
if (subtype & RZ_GRAPH_NODE_SUBTYPE_CFG_RETURN) {
rz_str_append(annotation, utf8 ? "↑" : "r");
}
if (subtype & RZ_GRAPH_NODE_SUBTYPE_CFG_COND) {
rz_str_append(annotation, utf8 ? "⤹" : "c");
}
if (subtype & RZ_GRAPH_NODE_SUBTYPE_CFG_EXIT) {
rz_str_append(annotation, utf8 ? "⭳" : "E");
}
if (!utf8) {
rz_str_append(annotation, ")");
}
return annotation;
}

/**
* \brief Casts the given graph node data pointer to a
* RzGraphNodeInfo pointer and makes some plausibility tests on the data.
Expand Down Expand Up @@ -150,33 +191,54 @@ RZ_API RZ_OWN char *rz_graph_drawable_to_dot(RZ_NONNULL RzGraph /*<RzGraphNodeIn
rz_list_foreach (nodes, it, node) {
RzGraphNodeInfo *print_node = (RzGraphNodeInfo *)node->data;
char *url;
char *label;
RzStrBuf *label = rz_strbuf_new("");

switch (print_node->type) {
default:
RZ_LOG_ERROR("Unhandled node type. Graph node either doesn't support dot graph printing or it isn't implemented.\n");
rz_strbuf_free(label);
return NULL;
case RZ_GRAPH_NODE_TYPE_CFG:
label = rz_str_newf("0x%" PFMT64x, print_node->cfg.address);
url = label;
rz_strbuf_appendf(label, "0x%" PFMT64x, print_node->cfg.address);
if (print_node->subtype & RZ_GRAPH_NODE_SUBTYPE_CFG_ENTRY) {
rz_strbuf_append(label, " (entry)");
}
if (print_node->subtype & RZ_GRAPH_NODE_SUBTYPE_CFG_CALL) {
rz_strbuf_append(label, " (call)");
}
if (print_node->subtype & RZ_GRAPH_NODE_SUBTYPE_CFG_RETURN) {
rz_strbuf_append(label, " (ret)");
}
if (print_node->subtype & RZ_GRAPH_NODE_SUBTYPE_CFG_COND) {
rz_strbuf_append(label, " (cond)");
}
if (print_node->subtype & RZ_GRAPH_NODE_SUBTYPE_CFG_EXIT) {
rz_strbuf_append(label, " (exit)");
}
url = rz_strbuf_get(label);
break;
case RZ_GRAPH_NODE_TYPE_ICFG:
label = rz_str_newf("0x%" PFMT64x, print_node->icfg.address);
url = label;
rz_strbuf_appendf(label, "0x%" PFMT64x, print_node->icfg.address);
if (print_node->subtype == RZ_GRAPH_NODE_SUBTYPE_ICFG_MALLOC) {
rz_strbuf_append(label, " (alloc)");
}
url = rz_strbuf_get(label);
break;
case RZ_GRAPH_NODE_TYPE_DEFAULT:
url = print_node->def.title;
if (print_node->def.body && print_node->def.body[0]) {
rz_str_replace_ch(print_node->def.body, '\"', '\'', true);
label = rz_str_newf("%s\\n%s", print_node->def.title, print_node->def.body);
rz_strbuf_appendf(label, "%s\\n%s", print_node->def.title, print_node->def.body);
} else {
label = rz_str_dup(print_node->def.title);
rz_strbuf_append(label, print_node->def.title);
}
}

rz_strbuf_appendf(&buf, "%d [URL=\"%s\", color=\"lightgray\", label=\"%s\"]\n",
node->idx, url, label);
free(label);
node->idx, url, rz_strbuf_get(label));
rz_strbuf_free(label);
// url sometimes is set to label above and shouldn't be used after label was freed.
url = NULL;
rz_list_foreach (node->out_nodes, itt, target) {
rz_strbuf_appendf(&buf, "%d -> %d\n", node->idx, target->idx);
}
Expand Down
Loading
Loading