Skip to content

Commit

Permalink
Add the set of call targets to a CFG node of iwords.
Browse files Browse the repository at this point in the history
  • Loading branch information
Rot127 committed Feb 19, 2024
1 parent 9fdec55 commit c149237
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 26 deletions.
3 changes: 2 additions & 1 deletion librz/core/agraph.c
Original file line number Diff line number Diff line change
Expand Up @@ -3746,7 +3746,8 @@ 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: {
case RZ_GRAPH_NODE_TYPE_CFG:
case RZ_GRAPH_NODE_TYPE_CFG_IWORD: {
char *annotation = rz_graph_get_node_subtype_annotation(info->subtype, utf8);
rz_return_val_if_fail(annotation, NULL);
char *cfg_title = rz_str_appendf(NULL, "0x%" PFMT64x "%s", info->cfg.address, annotation);
Expand Down
14 changes: 2 additions & 12 deletions librz/core/cgraph.c
Original file line number Diff line number Diff line change
Expand Up @@ -976,7 +976,7 @@ static RzGraphNode *add_node_info_cfg(RzGraph /*<RzGraphNodeInfo *>*/ *cfg, cons
subtype |= RZ_GRAPH_NODE_SUBTYPE_CFG_ENTRY;
}
ut64 call_target = is_call(op) ? op->jump : UT64_MAX;
RzGraphNodeInfo *data = rz_graph_create_node_info_cfg(op->addr, call_target, RZ_GRAPH_NODE_TYPE_CFG, subtype);
RzGraphNodeInfo *data = rz_graph_create_node_info_cfg(op->addr, call_target, subtype);
if (!data) {
return NULL;
}
Expand Down Expand Up @@ -1153,17 +1153,7 @@ static RzGraphNode *add_iword_to_cfg(RzGraph /*<RzGraphNodeInfo *>*/ *cfg, const
if (is_entry) {
subtype |= RZ_GRAPH_NODE_SUBTYPE_CFG_ENTRY;
}
ut64 call_target = UT64_MAX;
set_u_iter_init(it);
set_u_foreach(iword->call_targets, it) {
size_t ct_num = set_u_size(iword->call_targets);
if (ct_num > 1) {
RZ_LOG_WARN("TODO: iword contained %zu call targets, but only 1 was added to node.\n", ct_num);
}
call_target = it.v;
break;
}
RzGraphNodeInfo *data = rz_graph_create_node_info_cfg(iword->addr, call_target, RZ_GRAPH_NODE_TYPE_CFG, subtype);
RzGraphNodeInfo *data = rz_graph_create_node_info_cfg_iword(iword->addr, iword->call_targets, subtype);
if (!data) {
return NULL;
}
Expand Down
15 changes: 11 additions & 4 deletions librz/include/rz_util/rz_graph_drawable.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#ifndef RZ_GRAPH_DRAWABLE_H
#define RZ_GRAPH_DRAWABLE_H

#include <rz_util/set.h>
#include <rz_types.h>
#include <rz_util/rz_graph.h>
#include <rz_config.h>
Expand All @@ -14,7 +15,8 @@ extern "C" {
typedef enum {
RZ_GRAPH_NODE_TYPE_NONE = 0, ///< No type for this node specified.
RZ_GRAPH_NODE_TYPE_DEFAULT, ///< Node contains a title string, a body string and an absract offset value.
RZ_GRAPH_NODE_TYPE_CFG, ///< Node is part of an control flow graph of a procedure.
RZ_GRAPH_NODE_TYPE_CFG, ///< Nodes are instructions of a procedure's control flow graph.
RZ_GRAPH_NODE_TYPE_CFG_IWORD, ///< Nodes are instruction words of a procedure's control flow graph.
RZ_GRAPH_NODE_TYPE_ICFG, ///< Node is part of an inter-procedural control flow graph.
} RzGraphNodeType;

Expand Down Expand Up @@ -49,10 +51,14 @@ typedef struct {
*/
ut64 address;
/**
* \brief Address of called procedure, if node is of type RZ_GRAPH_NODE_TYPE_CFG_CALL.
* \brief Addresses of called procedure(s), if the node is of type RZ_GRAPH_NODE_TYPE_CFG_CALL.
* It is set to UT64_MAX if invalid.
* For instruction word nodes this can hold multiple addresses.
*/
ut64 call_address;
union {
ut64 insn; ///< The call target address of a single instruction.
SetU *iword; ///< A set of call target addresses of an instruction word.
} call_addresses;
} RzGraphNodeInfoDataCFG;

typedef struct {
Expand Down Expand Up @@ -86,7 +92,8 @@ 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);
RZ_API RzGraphNodeInfo *rz_graph_create_node_info_icfg(ut64 address, RzGraphNodeType type, RzGraphNodeSubType subtype);
RZ_API RzGraphNodeInfo *rz_graph_create_node_info_cfg(ut64 address, ut64 call_target_addr, RzGraphNodeType type, RzGraphNodeSubType subtype);
RZ_API RzGraphNodeInfo *rz_graph_create_node_info_cfg(ut64 address, ut64 call_target_addr, RzGraphNodeSubType subtype);
RZ_API RzGraphNodeInfo *rz_graph_create_node_info_cfg_iword(ut64 address, RZ_NULLABLE RZ_BORROW SetU *call_targets, RzGraphNodeSubType subtype);
RZ_API RzGraphNode *rz_graph_add_node_info(RzGraph /*<RzGraphNodeInfo *>*/ *graph, const char *title, const char *body, ut64 offset);

/**
Expand Down
57 changes: 53 additions & 4 deletions librz/util/graph_drawable.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include <rz_core.h>
#include <rz_util/rz_graph_drawable.h>
#include <rz_util/set.h>

/**
* \brief Translates the \p subtype flags of a node to its annotation symbols.
Expand Down Expand Up @@ -63,6 +64,7 @@ RZ_API RZ_OWN RzGraphNodeInfo *rz_graph_get_node_info_data(RZ_BORROW void *data)
return NULL;
case RZ_GRAPH_NODE_TYPE_DEFAULT:
case RZ_GRAPH_NODE_TYPE_CFG:
case RZ_GRAPH_NODE_TYPE_CFG_IWORD:
case RZ_GRAPH_NODE_TYPE_ICFG:
break;
}
Expand All @@ -81,6 +83,9 @@ RZ_API void rz_graph_free_node_info(RZ_NULLABLE void *ptr) {
case RZ_GRAPH_NODE_TYPE_CFG:
case RZ_GRAPH_NODE_TYPE_ICFG:
break;
case RZ_GRAPH_NODE_TYPE_CFG_IWORD:
set_u_free(info->cfg.call_addresses.iword);
break;
case RZ_GRAPH_NODE_TYPE_DEFAULT:
free(info->def.body);
free(info->def.title);
Expand Down Expand Up @@ -120,15 +125,42 @@ RZ_API RzGraphNodeInfo *rz_graph_create_node_info_default(const char *title, con
*
* \return The initialized RzGraphNodeInfo or NULL in case of failure.
*/
RZ_API RzGraphNodeInfo *rz_graph_create_node_info_cfg(ut64 address, ut64 call_target_addr, RzGraphNodeType type, RzGraphNodeSubType subtype) {
RZ_API RzGraphNodeInfo *rz_graph_create_node_info_cfg(ut64 address, ut64 call_target_addr, RzGraphNodeSubType subtype) {
RzGraphNodeInfo *data = RZ_NEW0(RzGraphNodeInfo);
if (!data) {
return NULL;
}
data->type = RZ_GRAPH_NODE_TYPE_CFG;
data->subtype = subtype;
data->cfg.address = address;
data->cfg.call_address = call_target_addr;
data->cfg.call_addresses.insn = call_target_addr;
return data;
}

/**
* \brief Initializes a info struct for a CFG with instruction words.
*
* \param address The address of the instruction this node represents.
* \param call_targets The addresses of called procedure.
* \param flags Additional flags which describe the node.
*
* \return The initialized RzGraphNodeInfo or NULL in case of failure.
*/
RZ_API RzGraphNodeInfo *rz_graph_create_node_info_cfg_iword(ut64 address, RZ_NULLABLE RZ_BORROW SetU *call_targets, RzGraphNodeSubType subtype) {
RzGraphNodeInfo *data = RZ_NEW0(RzGraphNodeInfo);
if (!data) {
return NULL;
}
data->type = RZ_GRAPH_NODE_TYPE_CFG_IWORD;
data->subtype = subtype;
data->cfg.address = address;
data->cfg.call_addresses.iword = set_u_new();
if (call_targets) {
set_u_iter_init(it);
set_u_foreach(call_targets, it) {
set_u_add(data->cfg.call_addresses.iword, it.v);
}
}
return data;
}

Expand Down Expand Up @@ -199,6 +231,7 @@ RZ_API RZ_OWN char *rz_graph_drawable_to_dot(RZ_NONNULL RzGraph /*<RzGraphNodeIn
rz_strbuf_free(label);
return NULL;
case RZ_GRAPH_NODE_TYPE_CFG:
case RZ_GRAPH_NODE_TYPE_CFG_IWORD:
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)");
Expand Down Expand Up @@ -280,8 +313,23 @@ RZ_API void rz_graph_drawable_to_json(RZ_NONNULL RzGraph /*<RzGraphNodeInfo *>*/
} else if (print_node->type == RZ_GRAPH_NODE_TYPE_CFG) {
pj_kn(pj, "address", print_node->cfg.address);
pj_kb(pj, "is_call", print_node->type & RZ_GRAPH_NODE_SUBTYPE_CFG_CALL);
if (print_node->subtype & RZ_GRAPH_NODE_SUBTYPE_CFG_CALL && print_node->cfg.call_address != UT64_MAX) {
pj_kn(pj, "call_address", print_node->cfg.call_address);
if (print_node->subtype & RZ_GRAPH_NODE_SUBTYPE_CFG_CALL && print_node->cfg.call_addresses.insn != UT64_MAX) {
pj_kn(pj, "call_address", print_node->cfg.call_addresses.insn);
}
pj_kb(pj, "is_entry", print_node->subtype & RZ_GRAPH_NODE_SUBTYPE_CFG_ENTRY);
pj_kb(pj, "is_exit", print_node->subtype & RZ_GRAPH_NODE_SUBTYPE_CFG_EXIT);
pj_kb(pj, "is_return", print_node->subtype & RZ_GRAPH_NODE_SUBTYPE_CFG_RETURN);
} else if (print_node->type == RZ_GRAPH_NODE_TYPE_CFG_IWORD) {
pj_kn(pj, "address", print_node->cfg.address);
pj_kb(pj, "is_call", print_node->type & RZ_GRAPH_NODE_SUBTYPE_CFG_CALL);
if (print_node->subtype & RZ_GRAPH_NODE_SUBTYPE_CFG_CALL && set_u_size(print_node->cfg.call_addresses.iword) != 0) {
pj_k(pj, "call_targets");
pj_a(pj);
set_u_iter_init(it);
set_u_foreach(print_node->cfg.call_addresses.iword, it) {
pj_n(pj, it.v);
}
pj_end(pj);
}
pj_kb(pj, "is_entry", print_node->subtype & RZ_GRAPH_NODE_SUBTYPE_CFG_ENTRY);
pj_kb(pj, "is_exit", print_node->subtype & RZ_GRAPH_NODE_SUBTYPE_CFG_EXIT);
Expand Down Expand Up @@ -386,6 +434,7 @@ RZ_API RZ_OWN char *rz_graph_drawable_to_gml(RZ_NONNULL RzGraph /*<RzGraphNodeIn
RZ_LOG_ERROR("Unhandled node type. Graph node either doesn't support dot graph printing or it isn't implemented.\n");
return NULL;
case RZ_GRAPH_NODE_TYPE_CFG:
case RZ_GRAPH_NODE_TYPE_CFG_IWORD:
label = rz_strf(tmp, "0x%" PFMT64x, print_node->cfg.address);
break;
case RZ_GRAPH_NODE_TYPE_ICFG:
Expand Down
10 changes: 5 additions & 5 deletions test/integration/test_analysis_graph.c
Original file line number Diff line number Diff line change
Expand Up @@ -277,31 +277,31 @@ bool test_analysis_graph_cfg() {
mu_assert_eq(info->type, RZ_GRAPH_NODE_TYPE_CFG, "info type");
mu_assert_eq(info->subtype, RZ_GRAPH_NODE_SUBTYPE_CFG_ENTRY, "info subtype");
mu_assert_eq(info->cfg.address, 0x117a, "info address");
mu_assert_eq(info->cfg.call_address, UT64_MAX, "info call address");
mu_assert_eq(info->cfg.call_addresses.insn, UT64_MAX, "info call address");

info = rz_graph_get_node_info_data(rz_graph_get_node(g, 3)->data);
mu_assert_eq(info->type, RZ_GRAPH_NODE_TYPE_CFG, "info type");
mu_assert_eq(info->subtype, RZ_GRAPH_NODE_SUBTYPE_CFG_CALL, "info subtype");
mu_assert_eq(info->cfg.address, 0x1182, "info address");
mu_assert_eq(info->cfg.call_address, 0x1050, "info call address");
mu_assert_eq(info->cfg.call_addresses.insn, 0x1050, "info call address");

info = rz_graph_get_node_info_data(rz_graph_get_node(g, 10)->data);
mu_assert_eq(info->type, RZ_GRAPH_NODE_TYPE_CFG, "info type");
mu_assert_eq(info->subtype, RZ_GRAPH_NODE_SUBTYPE_CFG_COND, "info subtype");
mu_assert_eq(info->cfg.address, 0x11a7, "info address");
mu_assert_eq(info->cfg.call_address, UT64_MAX, "info call address");
mu_assert_eq(info->cfg.call_addresses.insn, UT64_MAX, "info call address");

info = rz_graph_get_node_info_data(rz_graph_get_node(g, 24)->data);
mu_assert_eq(info->type, RZ_GRAPH_NODE_TYPE_CFG, "info type");
mu_assert_eq(info->subtype, RZ_GRAPH_NODE_SUBTYPE_CFG_CALL, "info subtype");
mu_assert_eq(info->cfg.address, 0x11cd, "info address");
mu_assert_eq(info->cfg.call_address, UT64_MAX, "info call address");
mu_assert_eq(info->cfg.call_addresses.insn, UT64_MAX, "info call address");

info = rz_graph_get_node_info_data(rz_graph_get_node(g, 18)->data);
mu_assert_eq(info->type, RZ_GRAPH_NODE_TYPE_CFG, "info type");
mu_assert_eq(info->subtype, RZ_GRAPH_NODE_SUBTYPE_CFG_RETURN, "info subtype");
mu_assert_eq(info->cfg.address, 0x11d3, "info address");
mu_assert_eq(info->cfg.call_address, UT64_MAX, "info call address");
mu_assert_eq(info->cfg.call_addresses.insn, UT64_MAX, "info call address");

rz_graph_free(g);

Expand Down

0 comments on commit c149237

Please sign in to comment.