25 #define GRAPH_MERGE_FEATURE 0
28 #define BORDER_WIDTH 4
29 #define BORDER_HEIGHT 3
30 #define MARGIN_TEXT_X 2
31 #define MARGIN_TEXT_Y 2
32 #define HORIZONTAL_NODE_SPACING 4
33 #define VERTICAL_NODE_SPACING 2
34 #define MIN_NODE_WIDTH 22
35 #define MIN_NODE_HEIGHT BORDER_HEIGHT
37 #define DEFAULT_SPEED 1
38 #define PAGEKEY_SPEED (h / 2)
40 #define MINIGRAPH_NODE_TEXT_CUR "<@@@@@@>"
41 #define MINIGRAPH_NODE_MIN_WIDTH 12
42 #define MINIGRAPH_NODE_TITLE_LEN 4
43 #define MINIGRAPH_NODE_CENTER_X 3
44 #define MININODE_MIN_WIDTH 16
47 #define ZOOM_DEFAULT 100
49 #define BODY_OFFSETS 0x1
50 #define BODY_SUMMARY 0x2
51 #define BODY_COMMENTS 0x4
53 #define NORMALIZE_MOV(x) ((x) < 0 ? -1 : ((x) > 0 ? 1 : 0))
56 #define get_anode(gn) ((gn) ? (RzANode *)(gn)->data : NULL)
58 #define graph_foreach_anode(list, it, pos, anode) \
60 for ((it) = (list)->head; (it) && ((pos) = (it)->data) && (pos) && ((anode) = (RzANode *)(pos)->data); (it) = (it)->n)
109 #define G(x, y) rz_cons_canvas_gotoxy(g->can, x, y)
110 #define W(x) rz_cons_canvas_write(g->can, x)
111 #define F(x, y, x2, y2, c) rz_cons_canvas_fill(g->can, x, y, x2, y2, c)
145 if (
n->title && *
n->title) {
148 const RzList *outnodes =
in ?
n->gnode->in_nodes :
n->gnode->out_nodes;
152 rz_list_foreach (outnodes,
iter, gn) {
221 }
else if (
n->is_mini) {
240 if (edgemode == 2 && !callgraph) {
260 strncat(title,
sdb_fmt(
"[o%s]", shortcut), left);
285 (void)
G(-
g->can->sx, -
g->can->sy + 2);
291 (void)
G(-
g->can->sx, -
g->can->sy + 3);
295 (void)
G(-
g->can->sx, -
g->can->sy + 3);
301 int l = strlen(
n->title);
317 cur ?
"[ %s ]" :
" %s ",
n->title);
346 ut32 center_x = 0, center_y = 0;
347 ut32 delta_x = 0, delta_txt_x = 0;
348 ut32 delta_y = 0, delta_txt_y = 0;
353 const bool showTitle =
g->show_node_titles;
354 const bool showBody =
g->show_node_body;
356 x =
n->x +
g->can->sx;
357 y =
n->y +
g->can->sy;
370 snprintf(title,
sizeof(title) - 1,
"[%s]",
n->title);
376 if ((delta_x < strlen(title)) &&
G(
n->x +
MARGIN_TEXT_X + delta_x,
n->y + 1)) {
387 delta_txt_x =
RZ_MIN(delta_x, center_x);
388 delta_txt_y =
RZ_MIN(delta_y, center_y);
393 ut32 body_x = center_x >= delta_x ? 0 : delta_x - center_x;
394 ut32 body_y = center_y >= delta_y ? 0 : delta_y - center_y;
400 if (body_y + 1 <= body_h) {
416 if (
n->body && *
n->body) {
419 if (delta_x < strlen(dots)) {
435 int maxlayer,
int i,
int from_up,
443 for (j = 0; j <
len; j++) {
451 if (
i > 0 && from_up) {
455 for (j = 0; j < layers[
i - 1].
n_nodes; j++) {
461 rz_list_foreach (neigh, itk, gk) {
467 for (
s = 0;
s < j;
s++) {
473 rz_list_foreach (neigh_s, itt,
gt) {
475 if (
gt == gk ||
gt ==
gs) {
484 eprintf (
"(WARNING) \"%s\" (%d) or \"%s\" (%d) are not on the right layer (%d)\n",
499 if (
i < maxlayer - 1 && !from_up) {
503 for (j = 0; j < layers[
i].
n_nodes; j++) {
542 for (
i = 0;
i <
len;
i++) {
550 int maxlayer,
int i,
int from_up) {
553 int n_rows, j, changed =
false;
561 for (j = 0; j <
len - 1; j++) {
571 if (cross_matrix[auidx][avidx] > cross_matrix[avidx][auidx]) {
574 layers[
i].
nodes[j + 1] = u;
582 for (j = 0; j < layers[
i].
n_nodes; j++) {
587 for (j = 0; j < n_rows; j++) {
588 free(cross_matrix[j]);
600 new_e->from =
e->from;
613 if (
RZ_ABS(
a->layer -
b->layer) > 1) {
618 new_e->
from =
e->from;
639 rz_list_foreach (
g->back_edges, it,
e) {
669 layer_vis.
data = topological_sort;
681 if (preva->
layer + 1 >
n->layer) {
682 n->layer = preva->
layer + 1;
691 return a->from ==
b->to &&
a->to ==
b->from ? 0 : 1;
710 dummy_vis.
data =
g->long_edges;
715 rz_list_foreach (
g->long_edges, it,
e) {
723 for (
i = 1;
i < diff_layer;
i++) {
753 if (
n->layer >
g->n_layers) {
754 g->n_layers =
n->layer;
760 if (
sizeof(
struct layer_t) *
g->n_layers <
g->n_layers) {
766 g->layers[
n->layer].n_nodes++;
769 for (
i = 0;
i <
g->n_layers;
i++) {
770 if (
sizeof(
RzGraphNode *) *
g->layers[
i].n_nodes <
g->layers[
i].n_nodes) {
774 1 +
g->layers[
i].n_nodes);
775 g->layers[
i].position = 0;
778 n->pos_in_layer =
g->layers[
n->layer].position;
779 g->layers[
n->layer].nodes[
g->layers[
n->layer].position++] = gn;
787 int i, cross_changed, max_changes = 4096;
790 cross_changed =
false;
793 for (
i = 0;
i <
g->n_layers;
i++) {
798 cross_changed |= !!rc;
800 }
while (cross_changed && max_changes);
805 cross_changed =
false;
808 for (
i =
g->n_layers - 1;
i >= 0;
i--) {
813 cross_changed |= !!rc;
815 }
while (cross_changed && max_changes);
819 return a->from ==
b->from &&
a->to ==
b->to ? 0 : 1;
843 if (aa && ab && aa->layer == ab->layer) {
847 for (
i = aa->pos_in_layer; i < ab->pos_in_layer;
i++) {
865 if (acur && anext && !
found) {
875 res += acur->
w / 2 + anext->
w / 2 + space;
894 vi =
g->layers[l].nodes[cur];
895 vip =
g->layers[l].nodes[next];
906 d->dist = (avip && avi) ? avip->
x - avi->
x : 0;
913 return pos >= 0 &&
pos <
g->layers[l].n_nodes;
925 HtPPOptions ht_opt = { 0 };
927 HtPP *res = ht_pp_new_opt(&ht_opt);
931 for (
int i = 0;
i <
g->n_layers;
i++) {
932 for (
int j = 0; j <
g->layers[
i].n_nodes; j++) {
939 ht_pp_insert(res, gn, vert);
978 for (
i = 0;
i <
g->n_layers;
i++) {
981 for (j = is_left ? 0 :
g->layers[
i].n_nodes - 1;
982 (is_left && j < g->layers[
i].n_nodes) || (!is_left && j >= 0);
983 j = is_left ? j + 1 : j - 1) {
987 if (aj->
klass == -1) {
988 const RzList *laj = ht_pp_find(v_nodes, gj,
NULL);
1004 *n_classes =
g->n_layers;
1010 return (
a <
b) - (
a >
b);
1015 int pos =
n->pos_in_layer;
1017 if ((is_left && is_adjust_class) || (!is_left && !is_adjust_class)) {
1024 res =
g->layers[
n->layer].nodes[
pos];
1062 if (sibl_anode->
klass ==
c) {
1082 size_t d = (ak->
x - an->
x);
1103 const int new_val = is_left ? old_val +
dist : old_val -
dist;
1104 ht_pu_update(res, gn, (
ut64)(
size_t)new_val);
1120 return RZ_MAX(oldval, newval);
1122 return RZ_MIN(oldval, newval);
1127 const RzList *lv = ht_pp_find(v_nodes, gn,
NULL);
1128 int p = 0,
v, is_first =
true;
1154 p = is_left ? 0 : 50;
1158 ht_pu_update(res, gk, (
ut64)(
size_t)
p);
1172 HtPUOptions pu_opt = { 0 };
1173 HtPPOptions pp_opt = { 0 };
1174 HtPU *res = ht_pu_new_opt(&pu_opt);
1175 SetP *placed = (
SetP *)ht_pp_new_opt(&pp_opt);
1176 if (!res || !placed) {
1181 for (
i = 0;
i < n_classes;
i++) {
1185 rz_list_foreach (
classes[
i], it, gn) {
1195 for (
i = 0;
i < n_classes;
i++) {
1214 if (!vertical_nodes) {
1235 ht_pp_free(vertical_nodes);
1243 int k, layer = an->
layer;
1245 for (
k = an->
pos_in_layer + 1; k < g->layers[layer].n_nodes;
k++) {
1262 int j,
d = from_up ? 1 : -1;
1264 if (
i + d < 0 || i + d >=
g->n_layers) {
1267 for (j = 0; j <
g->layers[
i +
d].n_nodes; j++) {
1287 for (
k = wma->pos_in_layer + 1; k < wpa->pos_in_layer;
k++) {
1295 ht_pu_update(
D, vm, (
ut64)(
size_t)from_up);
1300 ht_pu_update(
D,
v, (
ut64)(
size_t)from_up);
1322 const RzList *neigh = from_up
1344 av->
x = sum_x /
len;
1357 return (
a->pos <
b->pos) - (
a->pos >
b->pos);
1361 return (
a->pos >
b->pos) - (
a->pos <
b->pos);
1372 for (
i = is_left ?
s :
e - 1; (is_left &&
i <
e) || (!is_left &&
i >=
s);
i = is_left ?
i + 1 :
i - 1) {
1387 if ((is_left && av->
x >= avi->
x) || (!is_left && av->
x <= avi->
x)) {
1434 int rm,
rp, t,
m,
i;
1439 vt =
g->layers[l].nodes[t - 1];
1440 vtp =
g->layers[l].nodes[t];
1450 while (atp->
x - at->
x <
m) {
1451 if (atp->
x == at->
x) {
1457 if (rz_list_empty(Rm)) {
1466 if (rz_list_empty(Rp)) {
1482 for (
i = t - 2;
i >=
a;
i--) {
1490 for (
i = t + 1;
i <
r;
i++) {
1507 }
else if (vr > va + 1) {
1508 int vt = (vr + va) / 2;
1521 for (
i = from_up ? 0 :
g->n_layers - 1;
1522 (from_up && i < g->n_layers) || (!from_up &&
i >= 0);
1523 i = from_up ?
i + 1 :
i - 1) {
1529 while (j < g->layers[
i].n_nodes && !bm) {
1542 vr =
g->layers[
i].n_nodes;
1545 for (
k = va;
k < vr - 1;
k++) {
1558 vr =
g->layers[bma->
layer].n_nodes;
1560 for (
k = va;
k < vr - 1;
k++) {
1572 ht_pu_update(
P, bm, 1);
1588 HtPUOptions opt = { 0 };
1590 HtPU *
D = ht_pu_new_opt(&opt);
1594 HtPU *
P = ht_pu_new_opt(&opt);
1612 if (right_v && right) {
1613 ht_pu_update(
D, gn, 0);
1615 ht_pu_update(
P, gn, (
ut64)(
size_t)dt_eq);
1629 static void remove_dummy_nodes(
const RzAGraph *
g) {
1653 g->layers[0].gap = 0;
1654 for (
i = 0;
i <
g->n_layers;
i++) {
1656 if (
i + 1 <
g->n_layers) {
1657 g->layers[
i + 1].gap = gap;
1659 for (j = 0; j <
g->layers[
i].n_nodes; j++) {
1660 ga =
g->layers[
i].nodes[j];
1667 if (!outnodes || !
a) {
1671 if (
g->layout == 0) {
1672 if ((
b->x !=
a->x) ||
b->layer <=
a->layer) {
1674 if (
b->layer <=
a->layer) {
1675 g->layers[
b->layer].gap += 1;
1677 }
else if ((!
a->is_dummy &&
b->is_dummy) || (
a->is_dummy && !
b->is_dummy)) {
1681 if ((
b->y ==
a->y &&
b->h !=
a->h) ||
b->y !=
a->y ||
b->layer <=
a->layer) {
1683 if (
b->layer <=
a->layer) {
1684 g->layers[
b->layer].gap += 1;
1686 }
else if ((!
a->is_dummy &&
b->is_dummy) || (
a->is_dummy && !
b->is_dummy)) {
1692 if (
i + 1 <
g->n_layers) {
1693 g->layers[
i + 1].gap += gap;
1707 while (
tmp->is_dummy) {
1710 if (
tmp->gnode->idx ==
from->gnode->idx) {
1717 while (
tmp->gnode->idx !=
from->gnode->idx) {
1722 while (
v->gnode->idx !=
g->layers[
v->layer].nodes[
i]->idx) {
1726 while (
i + 1 <
g->layers[
v->layer].n_nodes) {
1727 g->layers[
v->layer].nodes[
i] =
g->layers[
v->layer].nodes[
i + 1];
1730 g->layers[
v->layer].nodes[
g->layers[
v->layer].n_nodes - 1] = 0;
1731 g->layers[
v->layer].n_nodes -= 1;
1745 if (outgoing &&
src->is_dummy) {
1749 const RzList *neighbours = outgoing
1755 if (
g->is_callgraph) {
1757 }
else if (exit_edges == 1) {
1760 if (outgoing && gv->
idx == (
dst->gnode)->idx) {
1763 if (!outgoing && gv->
idx == (
src->gnode)->idx) {
1786 for (
i = 0;
i <
g->n_layers;
i++) {
1793 for (
i = 0;
i <
g->n_layers;
i++) {
1794 for (j = 0; j <
g->layers[
i].n_nodes; j++) {
1803 int tc =
g->layout == 0 ? t->
x : t->
y;
1804 int tl =
g->layout == 0 ? t->
w : t->
h;
1807 arr[
i][1] = tc + tl;
1810 if (
arr[
i][0] > tc) {
1814 if (
arr[
i][1] < tc + tl) {
1815 arr[
i][1] = tc + tl;
1819 for (j = 0; j <
g->layers[
i].n_nodes; j++) {
1821 if (!
a ||
a->is_dummy) {
1832 }
else if (
i ==
g->n_layers - 1) {
1837 if (
b->layer >
a->layer) {
1844 int ax =
g->layout == 0 ?
a->x + xinc :
a->y + (
a->h / 2) + nth;
1845 int bx =
g->layout == 0 ?
b->x + xinc :
b->y + (
b->h / 2) + nth;
1847 if (
g->layout == 0 && nth == 0 && bx >
ax) {
1853 for (
k =
b->layer; k <= a->layer;
k++) {
1866 for (
k =
b->layer; k <= a->layer;
k++) {
1880 e->is_reversed =
true;
1905 e->is_reversed =
true;
1910 if (
g->layout == 0) {
1926 e->is_reversed =
true;
1931 if (
g->layout == 0) {
1932 rz_list_append(
e->y, (
void *)(
size_t)(
n->y +
g->layers[
g->n_layers - 1].height + 2 + outedge));
1934 rz_list_append(
e->x, (
void *)(
size_t)(
n->x +
g->layers[
g->n_layers - 1].width + 2 + outedge));
1939 for (
i =
i - 1;
i >= 0;
i--) {
1975 for (
i = 0;
i <
g->n_layers;
i++) {
1978 for (j = 0; j <
g->layers[
i].n_nodes; j++) {
1987 g->layers[
i].height = rh;
1988 g->layers[
i].width = rw;
1991 for (
i = 0;
i <
g->n_layers;
i++) {
1992 for (j = 0; j <
g->layers[
i].n_nodes; j++) {
1995 if (
g->layout == 0) {
1996 a->h =
g->layers[
i].height;
1998 a->w =
g->layers[
i].width;
2001 a->layer_height =
g->layers[
i].height;
2002 a->layer_width =
g->layers[
i].width;
2017 rz_list_foreach (
g->back_edges, it,
e) {
2025 switch (
g->layout) {
2029 for (
i = 0;
i <
g->n_layers;
i++) {
2030 for (j = 0; j <
g->layers[
i].n_nodes; j++) {
2044 for (
i = 0;
i <
g->n_layers;
i++) {
2046 tmp_y =
g->layers[0].gap;
2047 for (
k = 1;
k <=
i;
k++) {
2048 tmp_y +=
g->layers[
k - 1].height +
g->layers[
k].gap + 3;
2053 for (j = 0; j <
g->layers[
i].n_nodes; j++) {
2064 for (
i = 0;
i <
g->n_layers;
i++) {
2065 for (j = 0; j <
g->layers[
i].n_nodes; j++) {
2068 for (
k = 0;
k < j;
k++) {
2078 for (
i = 0;
i <
g->n_layers;
i++) {
2079 int xval = 1 +
g->layers[0].gap + 1;
2080 for (
k = 1;
k <=
i;
k++) {
2081 xval +=
g->layers[
k - 1].width +
g->layers[
k].gap + 3;
2083 for (j = 0; j <
g->layers[
i].n_nodes; j++) {
2094 for (
i = 0;
i <
g->n_layers;
i++) {
2095 free(
g->layers[
i].nodes);
2111 "asm.cmt.col",
"asm.marks",
"asm.offset",
2112 "asm.comments",
"asm.cmt.right",
"asm.bb.line",
NULL);
2170 if (
b->parent_reg_arena) {
2181 if (
b->parent_stackptr !=
INT_MAX) {
2184 char *body =
get_body(core,
b->addr,
b->size, opts);
2186 if (
b->jump >
b->addr) {
2199 if (
b->fail >
b->addr) {
2215 return a->addr -
b->addr;
2239 rz_list_foreach (fcn->
bbs,
iter, bb) {
2249 sdb_set(
g->db,
sdb_fmt(
"agraph.nodes.%s.shortcut", title), shortcut, 0);
2284 g->need_reload_nodes =
true;
2289 n->is_mini = (tp ==
NULL);
2291 g->need_update_dim = 1;
2296 RzListIter *it, *in_it, *in_it2, *in_it2_tmp;
2298 rz_list_foreach (
g->graph->nodes, it,
n) {
2299 rz_list_foreach (
n->out_nodes, in_it,
a) {
2300 for (in_it2 = in_it->
n; in_it2 && (
b = in_it2->
data, in_it2_tmp = in_it2->
n, 1); in_it2 = in_it2_tmp) {
2301 if (
a->idx ==
b->idx) {
2306 g->graph->n_edges--;
2334 char *shortcut =
NULL;
2353 rz_list_foreach (fcn->
bbs,
iter, bb) {
2357 if (rz_analysis_block_contains(bb, core->
offset)) {
2365 rz_list_foreach (fcn->
bbs,
iter, bb) {
2369 if (few && !
isbbfew(curbb, bb)) {
2381 sdb_set(
g->db,
sdb_fmt(
"agraph.nodes.%s.shortcut", title), shortcut, 0);
2393 rz_list_foreach (fcn->
bbs,
iter, bb) {
2397 if (few && !
isbbfew(curbb, bb)) {
2472 rz_list_foreach (xrefs,
iter, xref) {
2507 const bool is_c =
g->is_callgraph;
2515 int x =
n->x + can->
sx;
2516 int y =
n->y + can->
sy;
2520 const bool doscroll = force || y < 0 || y + 5 >
h ||
x + 5 >
w ||
x +
n->w + 5 < 0;
2525 can->
sx = -
n->x -
n->w / 2 +
w / 2;
2530 can->
sy = -
n->y -
n->h / 8 +
h / 4;
2537 return (
n->y == y &&
n->x >
x) ||
n->y > y;
2539 return (
n->y == y &&
n->x <
x) ||
n->y < y;
2545 return (
n->x ==
x &&
n->y > y) ||
n->x >
x;
2547 return (
n->x ==
x &&
n->y < y) ||
n->x <
x;
2556 const int default_v = is_next ? INT_MIN :
INT_MAX;
2557 const int start_x = acur ? acur->
x : default_v;
2558 const int start_y = acur ? acur->
y : default_v;
2563 ?
is_near(
n, start_x, start_y, is_next)
2574 if ((is_next && resn->
y >
n->y) || (!is_next && resn->
y <
n->y)) {
2576 }
else if ((is_next && resn->
y ==
n->y && resn->
x >
n->x) ||
2577 (!is_next && resn->
y ==
n->y && resn->
x <
n->x)) {
2582 if (!resgn && cur) {
2591 RzANode *ak, *min_gn, *max_gn;
2593 int delta_x, delta_y;
2597 max_x = max_y = INT_MIN;
2598 min_gn = max_gn =
NULL;
2609 if (ak->
y - len < g->y) {
2614 if (ak->
x + ak->
w > max_x) {
2615 max_x = ak->
x + ak->
w;
2621 if (ak->
y + ak->
h +
len > max_y) {
2622 max_y = ak->
y + ak->
h +
len;
2627 rz_list_foreach (
g->edges, it,
e) {
2634 rz_list_foreach (
e->x, kt, vv) {
2635 v = (
int)(
size_t)vv;
2639 if (
v + 1 > max_x) {
2643 rz_list_foreach (
e->y, kt, vv) {
2644 v = (
int)(
size_t)vv;
2648 if (
v + 1 > max_y) {
2670 g->w = max_x -
g->x;
2672 size_t len = strlen(
g->title);
2676 if ((
int)
len >
g->w) {
2680 g->h = max_y -
g->y;
2690 delta_x =
g->x < 0 ? -
g->x : 0;
2691 delta_y =
g->y < 0 ? -
g->y : 0;
2700 g->curnode =
a->gnode;
2702 sdb_set(
g->db,
"agraph.curnode",
a->title, 0);
2703 if (
g->on_curnode_change) {
2704 g->on_curnode_change(
a,
g->on_curnode_change_data);
2710 return g->x < 0 ? -
g->x +
v :
v;
2726 k =
sdb_fmt(
"agraph.nodes.%s.x",
a->title);
2728 k =
sdb_fmt(
"agraph.nodes.%s.y",
a->title);
2730 k =
sdb_fmt(
"agraph.nodes.%s.w",
a->title);
2732 k =
sdb_fmt(
"agraph.nodes.%s.h",
a->title);
2739 g->update_seek_on =
n;
2740 g->force_update_seek = force;
2747 const int cur =
g->curnode &&
get_anode(
g->curnode) ==
n;
2751 }
else if (isMini ||
n->is_mini) {
2765 if (gn !=
g->curnode) {
2805 const RzList *outnodes =
n->gnode->out_nodes;
2809 int sx2 = n2->
w / 2;
2817 n->x + sx,
n->y + sy,
2818 n2->
x + sx2, n2->
y, &style);
2822 n2->
x + sx2, n2->
y - 1,
2823 n2->
x + sx2, n2->
y + n2->
h, &style);
2853 if (
g->edgemode == 1) {
2857 int out_nth, in_nth, bendpoint;
2872 int ax, ay, bx, by, a_x_inc, b_x_inc;
2878 rz_list_foreach (lyr, ito, tl) {
2879 if (tl->
layer ==
a->layer) {
2881 if (
g->layout == 0) {
2882 if (tm->
minx >
a->x) {
2885 if (tm->
maxx <
a->x +
a->w) {
2889 if (tm->
minx >
a->y) {
2892 if (tm->
maxx <
a->y +
a->h) {
2906 if (
g->layout == 0) {
2919 if (many && !
g->is_callgraph) {
2928 bool parent_many =
false;
2931 while (
in &&
in->is_dummy) {
2934 if (
in &&
in->gnode) {
2937 parent_many =
false;
2942 if (many || parent_many) {
2963 switch (
g->layout) {
2967 if (
a->y +
a->h >
b->y) {
2974 bx =
b->is_dummy ?
b->x : (
b->x + b_x_inc);
2978 if (many && !
g->is_callgraph) {
2980 ax =
a->is_dummy ?
a->x : (
a->x +
a->w / 2 + (t / 2 - a_x_inc));
2981 bendpoint = bx <
ax ? neighbours->
length - out_nth : out_nth;
2983 ax =
a->is_dummy ?
a->x : (
a->x + a_x_inc);
2987 if (!
a->is_dummy && itn == neighbours->
head && out_nth == 0 && bx >
ax) {
2988 ax += (many && !
g->is_callgraph) ? 0 : 4;
2990 if (
a->h <
a->layer_height) {
2992 ay =
a->y +
a->layer_height;
3003 tmp->edgectr = bendpoint;
3004 tmp->fromlayer =
a->layer;
3005 tmp->tolayer =
b->layer;
3013 if (
b->x !=
a->x ||
b->layer <=
a->layer || (!
a->is_dummy &&
b->is_dummy) || (
a->is_dummy && !
b->is_dummy)) {
3021 if (
a->x +
a->w >
b->x) {
3032 if (!
a->is_dummy &&
g->zoom > 0) {
3037 if (!
b->is_dummy &&
g->zoom > 0) {
3041 if (
a->w <
a->layer_width) {
3045 ax +=
a->layer_width;
3061 tmp->fromlayer =
a->layer;
3062 tmp->tolayer =
b->layer;
3071 if ((
b->y ==
a->y &&
b->h !=
a->h) ||
b->y !=
a->y ||
b->layer <=
a->layer || (!
a->is_dummy &&
b->is_dummy) || (
a->is_dummy && !
b->is_dummy)) {
3080 rz_list_foreach (bckedges, itm, temp) {
3081 int leftlen, rightlen;
3082 int minx = 0, maxx = 0;
3088 rz_list_foreach (lyr, ito, tl) {
3105 if (
g->layout == 0) {
3114 int arg = (rightlen < leftlen) ?
maxx + 1 :
minx - 1;
3118 rz_list_foreach (lyr, ito, tl) {
3122 if (rightlen < leftlen) {
3133 rz_list_foreach (lyr, ito, tl) {
3137 rz_list_foreach (bckedges, ito, tl) {
3147 g->is_callgraph = !
g->is_callgraph;
3148 g->need_reload_nodes =
true;
3149 g->force_update_seek =
true;
3165 g->can->sy = (
g->can->sy * K) / 1000;
3167 g->can->sy = (
g->can->sy * 1000) / K;
3170 g->need_update_dim =
true;
3171 g->need_set_layout =
true;
3187 while (
a &&
a->is_dummy) {
3208 #if GRAPH_MERGE_FEATURE
3209 #define K_NEIGHBOURS(x) (sdb_fmt("agraph.nodes.%s.neighbours", x->title))
3220 acn->
h += ann->
h - 3;
3228 char *neis =
sdb_get(
g->db, K_NEIGHBOURS(ann), 0);
3241 g->is_tiny = !
g->is_tiny;
3242 g->need_update_dim = 1;
3251 n->is_mini = !
n->is_mini;
3253 g->need_update_dim = 1;
3275 rz_list_foreach (gnodes,
iter, gn) {
3283 rz_list_foreach (
options, iter2, o) {
3299 if (ch >=
'0' && ch <=
'9') {
3306 nth = atoi(nth_string);
3307 if (nth == 0 && *nth_string !=
'0') {
3333 while (
a &&
a->is_dummy) {
3343 while (
a &&
a->is_dummy) {
3354 "%s[0x%08" PFMT64x "]> %s # %s ",
3356 fcn->
addr,
a ?
a->title :
"", sig);
3368 if (
g->need_reload_nodes && core) {
3369 if (!
g->update_seek_on && !
g->force_update_seek) {
3371 oldpos[0] =
g->can->sx;
3372 oldpos[1] =
g->can->sy;
3381 if (core && core->
config) {
3387 if (
g->need_update_dim ||
g->need_reload_nodes || !is_interactive) {
3390 if (
g->need_set_layout ||
g->need_reload_nodes || !is_interactive) {
3398 if (fcn && ((is_interactive && !cur_anode) || (cur_anode && strcmp(cur_anode->
title, title)))) {
3400 if (
g->update_seek_on) {
3402 g->force_update_seek =
true;
3410 if (
g->update_seek_on ||
g->force_update_seek) {
3412 if (!
n &&
g->curnode) {
3419 if (oldpos[0] || oldpos[1]) {
3420 g->can->sx = oldpos[0];
3421 g->can->sy = oldpos[1];
3423 g->need_reload_nodes =
false;
3424 g->need_update_dim =
false;
3425 g->need_set_layout =
false;
3426 g->update_seek_on =
NULL;
3427 g->force_update_seek =
false;
3438 if (is_interactive) {
3445 h = is_interactive ?
h :
g->h + 1;
3446 w = is_interactive ?
w :
g->w + 2;
3451 if (!is_interactive) {
3453 g->can->sy = -
g->y - 1;
3456 (void)
G(-
g->can->sx + 1, -
g->can->sy + 2);
3472 if (
g->title && *
g->title) {
3477 if (
g->title && *
g->title) {
3481 (void)
G(-
g->can->sx, -
g->can->sy);
3485 if (is_interactive &&
g->title) {
3486 int title_len = strlen(
g->title);
3488 w - title_len, 1,
' ');
3493 if (is_interactive) {
3496 bool mustFlush =
false;
3498 if (cmdv && *cmdv) {
3546 if (!acur || strcmp(acur->
title, title)) {
3550 g->is_instep =
false;
3564 g->need_reload_nodes =
true;
3566 if (
f && fcn &&
f != *fcn) {
3569 g->need_reload_nodes =
true;
3570 g->force_update_seek =
true;
3609 .cmp = (HtPPListComparator)strcmp,
3613 .calcsizeK = (HtPPCalcSizeK)strlen,
3616 .elem_size =
sizeof(HtPPKv),
3620 g->is_callgraph =
false;
3621 g->is_instep =
false;
3622 g->need_reload_nodes =
true;
3623 g->show_node_titles =
true;
3624 g->show_node_body =
true;
3625 g->force_update_seek =
true;
3638 int delta = (dir ==
'k') ? -1 : 1;
3642 if (dir ==
'h' || dir ==
'l') {
3647 int delta = (dir ==
'l') ? 1 : -1;
3656 }
else if (
g->is_dis) {
3680 g->need_update_dim =
true;
3681 g->need_set_layout =
true;
3689 if (
g->graph->n_nodes > 0) {
3695 RzList *nodes =
g->graph->nodes, *neighbours =
NULL;
3701 rz_list_foreach (nodes, it, node) {
3708 pj_k(pj,
"out_nodes");
3711 rz_list_foreach (neighbours, itt, neighbour) {
3712 pj_i(pj, neighbour->idx);
3723 sdb_set(
g->db,
"agraph.title",
g->title, 0);
3746 ht_pp_update(
g->nodes, res->
title, res);
3752 if (
len > 0 &&
b[
len - 1] ==
'\n') {
3797 ht_pp_delete(
g->nodes, res->
title);
3803 void *user_data = user->
data;
3814 void *user_data = user->
data;
3824 cb(
n, an, user_data);
3834 ht_pp_foreach(
g->nodes, (HtPPForeachCallback)
user_node_cb, &u);
3843 ht_pp_foreach(
g->nodes, (HtPPForeachCallback)
user_edge_cb, &u);
3857 RzANode *node = ht_pp_find(
g->nodes, title_trunc,
NULL);
3865 if (
a->title &&
b->title) {
3866 char *
k =
sdb_fmt(
"agraph.nodes.%s.neighbours",
a->title);
3873 if (
a->title &&
b->title) {
3874 char *
k =
sdb_fmt(
"agraph.nodes.%s.neighbours",
a->title);
3882 if (
a->title &&
b->title) {
3883 const char *
k =
sdb_fmt(
"agraph.nodes.%s.neighbours",
a->title);
3890 ht_pp_free(
g->nodes);
3900 g->update_seek_on =
NULL;
3901 g->need_reload_nodes =
false;
3902 g->need_set_layout =
true;
3903 g->need_update_dim =
true;
3904 g->x =
g->y =
g->w =
g->h = 0;
3911 ht_pp_free(
g->nodes);
3945 if (
buf[2] ==
'.') {
3955 const char *
h =
"[Fast goto call/jmp]> ";
3995 if (title && strcmp(title,
n->title)) {
4009 g->is_instep =
true;
4010 g->need_reload_nodes =
true;
4015 g->is_instep =
true;
4016 g->need_reload_nodes =
true;
4080 can->
sx = -
pos->x + can->
w / 2;
4081 can->
sy = -
pos->y + can->
h / 2;
4090 const size_t MAX_COUNT = 4096;
4091 const char *
a =
NULL;
4116 eprintf(
"Interactive graph mode requires scr.interactive=true.\n");
4120 int o_vmode = core->
vmode;
4121 int exit_graph =
false, is_error =
false;
4128 bool graph_allocated =
false;
4144 eprintf(
"Cannot create RzCons.canvas context. Invalid screen "
4145 "size? See scr.columns + scr.rows\n");
4154 graph_allocated =
true;
4170 g->is_tiny = is_interactive == 2;
4182 g->on_curnode_change_data =
core;
4185 g->is_interactive = is_interactive;
4203 grd->
fs = is_interactive == 1;
4208 if (!ret || is_interactive != 1) {
4242 case 1:
key =
key ==
'k' ?
'h' :
'l';
break;
4243 case 2:
key =
key ==
'k' ?
'J' :
'K';
break;
4244 case 3:
key =
key ==
'k' ?
'L' :
'H';
break;
4249 movspeed =
g->movspeed;
4255 g->force_update_seek =
true;
4259 g->force_update_seek =
true;
4283 g->need_update_dim =
true;
4284 g->need_set_layout =
true;
4297 g->need_update_dim =
true;
4313 g->can->linemode =
e;
4356 if (key_s && *key_s) {
4392 " :e cmd.gprompt = agft - show tinygraph in one side\n"
4393 " +/-/0 - zoom in/out/default\n"
4394 " ; - add comment in current basic block\n"
4395 " . (dot) - center graph to the current node\n"
4396 " , (comma) - toggle graph.few\n"
4397 " ^ - seek to the first bb of the function\n"
4398 " = - toggle graph.layout\n"
4399 " :cmd - run rizin command\n"
4400 " ' - toggle graph.comments\n"
4401 " \" - toggle graph.refs\n"
4402 " # - toggle graph.hints\n"
4403 " / - highlight text\n"
4404 " \\ - scroll the graph canvas to the next highlight location\n"
4405 " | - set cmd.gprompt\n"
4406 " _ - enter hud selector\n"
4407 " > - show function callgraph (see graph.refs)\n"
4408 " < - show program callgraph (see graph.refs)\n"
4409 " ( - reverse conditional branch of last instruction in bb\n"
4410 " ) - rotate asm.emu and emu.str\n"
4411 " Home/End - go to the top/bottom of the canvas\n"
4412 " Page-UP/DOWN - scroll canvas up/down\n"
4413 " b - visual browse things\n"
4414 " c - toggle graph cursor mode\n"
4415 " C - toggle scr.colors\n"
4416 " d - rename function\n"
4417 " D - toggle the mixed graph+disasm mode\n"
4418 " e - rotate graph.edges (show/hide edges)\n"
4419 " E - rotate graph.linemode (square/diagonal lines)\n"
4420 " F - enter flag selector\n"
4421 " g - go/seek to given offset\n"
4422 " G - debug trace callgraph (generated with dtc)\n"
4423 " hjkl/HJKL - scroll canvas or node depending on graph cursor (uppercase for faster)\n"
4424 " i - select input nodes by index\n"
4425 " I - select output node by index\n"
4426 " m/M - change mouse modes\n"
4427 " n/N - next/previous scr.nkey (function/flag..)\n"
4428 " o([A-Za-z]*) - follow jmp/call identified by shortcut (like ;[oa])\n"
4429 " O - toggle asm.pseudo and asm.esil\n"
4430 " p/P - rotate graph modes (normal, display offsets, minigraph, summary)\n"
4431 " q - back to Visual mode\n"
4432 " r - toggle jmphints/leahints\n"
4433 " R - randomize colors\n"
4434 " s/S - step / step over\n"
4435 " tab - select next node\n"
4436 " TAB - select previous node\n"
4437 " t/f - follow true/false edges\n"
4438 " u/U - undo/redo seek\n"
4439 " V - toggle basicblock / call graphs\n"
4440 " w - toggle between movements speed 1 and graph.scroll\n"
4441 " x/X - jump to xref/ref\n"
4442 " Y - toggle tiny graph\n"
4443 " z - toggle node folding\n"
4444 " Z - toggle basic block folding");
4457 g->need_reload_nodes =
true;
4464 g->need_reload_nodes =
true;
4472 g->need_reload_nodes =
true;
4489 g->need_reload_nodes =
true;
4500 g->need_reload_nodes =
true;
4516 g->need_reload_nodes =
true;
4528 g->need_reload_nodes =
true;
4549 g->need_reload_nodes =
true;
4560 g->need_reload_nodes =
true;
4591 g->need_reload_nodes =
true;
4597 g->need_reload_nodes =
true;
4607 g->is_dis = !
g->is_dis;
4633 can->
sy -= (5 * movspeed) * (invscroll ? -1 : 1);
4641 can->
sy += (5 * movspeed) * (invscroll ? -1 : 1);
4655 can->
sx += (5 * movspeed) * (invscroll ? -1 : 1);
4663 can->
sx -= (5 * movspeed) * (invscroll ? -1 : 1);
4678 can->
sy -= movspeed * (invscroll ? -1 : 1);
4691 can->
sy += movspeed * (invscroll ? -1 : 1);
4700 can->
sx -= movspeed * (invscroll ? -1 : 1);
4708 can->
sx += movspeed * (invscroll ? -1 : 1);
4721 g->need_reload_nodes =
true;
4731 g->need_reload_nodes =
true;
4737 g->need_reload_nodes =
true;
4743 g->need_reload_nodes =
true;
4752 g->need_reload_nodes =
true;
4775 g->need_reload_nodes =
true;
4869 if (
g->is_callgraph) {
4896 if (graph_allocated) {
4920 if (!result_agraph) {
4925 HtPPOptions pointer_options = { 0 };
4926 HtPP *hashmap = ht_pp_new_opt(&pointer_options);
4936 rz_list_foreach (graph->
nodes,
iter, node) {
4942 ht_pp_insert(hashmap, node, a_node);
4946 rz_list_foreach (graph->
nodes,
iter, node) {
4947 RzANode *a_node = ht_pp_find(hashmap, node,
NULL);
4954 rz_list_foreach (node->
in_nodes, neighbour_iter, neighbour) {
4955 RzANode *a_neighbour = ht_pp_find(hashmap, neighbour,
NULL);
4963 ht_pp_free(hashmap);
4964 return result_agraph;
4966 ht_pp_free(hashmap);
static bool is_offset(const RzAGraph *g)
static void append_shortcut(const RzAGraph *g, char *title, char *nodetitle, int left)
static void fold_asm_trace(RzCore *core, RzAGraph *g)
RZ_API int rz_core_visual_graph(RzCore *core, RzAGraph *g, RzAnalysisFunction *_fcn, int is_interactive)
static void free_vertical_nodes_kv(HtPPKv *kv)
static void rotateAsmemu(RzCore *core)
RZ_API RzANode * rz_agraph_add_node_with_color(const RzAGraph *g, const char *title, const char *body, int color)
RZ_API bool rz_agraph_del_node(const RzAGraph *g, const char *title)
static void goto_asmqjmps(RzAGraph *g, RzCore *core)
static char * get_title(ut64 addr)
static void mini_RzANode_print(const RzAGraph *g, const RzANode *n, int cur, bool details)
static void minimize_crossings(const RzAGraph *g)
static int place_nodes_val(const RzAGraph *g, const RzGraphNode *gn, const RzGraphNode *sibl, HtPU *res, int is_left)
static void original_traverse_l(const RzAGraph *g, HtPU *D, HtPU *P, int from_up)
static int dist_nodes(const RzAGraph *g, const RzGraphNode *a, const RzGraphNode *b)
static void graph_single_step_in(RzCore *core, RzAGraph *g)
static void agraph_refresh_oneshot(struct agraph_refresh_data *grd)
static int RM_listcmp(const struct len_pos_t *a, const struct len_pos_t *b)
static int ** get_crossing_matrix(const RzGraph *g, const struct layer_t layers[], int maxlayer, int i, int from_up, int *n_rows)
static void place_single(const RzAGraph *g, int l, const RzGraphNode *bm, const RzGraphNode *bp, int from_up, int va)
static int hash_get_int(HtPU *ht, const void *key)
static void agraph_sdb_init(const RzAGraph *g)
static void set_layout(RzAGraph *g)
RZ_API void rz_agraph_free(RzAGraph *g)
static void assign_layers(const RzAGraph *g)
static void agraph_edge_free(AEdge *e)
static void agraph_print_edges(RzAGraph *g)
#define graph_foreach_anode(list, it, pos, anode)
RZ_API void rz_agraph_set_title(RzAGraph *g, const char *title)
RZ_API RzAGraph * rz_agraph_new(RzConsCanvas *can)
static int agraph_refresh(struct agraph_refresh_data *grd)
static int cmp_dist(const size_t a, const size_t b)
static void collect_changes(const RzAGraph *g, int l, const RzGraphNode *b, int from_up, int s, int e, RzList *list, int is_left)
static void create_dummy_nodes(RzAGraph *g)
RZ_API RzANode * rz_agraph_get_first_node(const RzAGraph *g)
static bool is_comments(const RzAGraph *g)
RZ_API void rz_agraph_del_edge(const RzAGraph *g, RzANode *a, RzANode *b)
static int find_edge(const RzGraphEdge *a, const RzGraphEdge *b)
static void visual_offset(RzAGraph *g, RzCore *core)
RZ_API RzANode * rz_agraph_add_node(const RzAGraph *g, const char *title, const char *body)
static HtPU * compute_pos(const RzAGraph *g, int is_left, HtPP *v_nodes)
static RzGraphNode * get_right_dummy(const RzAGraph *g, const RzGraphNode *n)
static bool isbbfew(RzAnalysisBlock *curbb, RzAnalysisBlock *bb)
static void remove_cycles(RzAGraph *g)
static void tiny_RzANode_print(const RzAGraph *g, const RzANode *n, int cur)
static int mode2opts(const RzAGraph *g)
static void agraph_toggle_callgraph(RzAGraph *g)
static void adjust_class(const RzAGraph *g, int is_left, RzList **classes, HtPU *res, int c)
static int is_valid_pos(const RzAGraph *g, int l, int pos)
static int get_edge_number(const RzAGraph *g, RzANode *src, RzANode *dst, bool outgoing)
static void agraph_set_need_reload_nodes(struct agraph_refresh_data *grd)
static void agraph_print_node(const RzAGraph *g, RzANode *n)
static void view_cyclic_edge(const RzGraphEdge *e, const RzGraphVisitor *vis)
static int bbcmp(RzAnalysisBlock *a, RzAnalysisBlock *b)
static int next_mode(int mode)
static int agraph_print(RzAGraph *g, int is_interactive, RzCore *core, RzAnalysisFunction *fcn)
static void delete_dup_edges(RzAGraph *g)
RZ_API Sdb * rz_agraph_get_sdb(RzAGraph *g)
static RzGraphNode * agraph_get_title(const RzAGraph *g, RzANode *n, bool in)
static bool reload_nodes(RzAGraph *g, RzCore *core, RzAnalysisFunction *fcn)
static void place_dummies(const RzAGraph *g)
static RzGraphNode * get_sibling(const RzAGraph *g, const RzANode *n, int is_left, int is_adjust_class)
RZ_API void rz_agraph_set_curnode(RzAGraph *g, RzANode *a)
static ut64 rebase(RzAGraph *g, int v)
static void agraph_print_edges_simple(RzAGraph *g)
struct ascii_edge_t AEdge
static bool user_node_cb(struct g_cb *user, RZ_UNUSED const void *k, const void *v)
static HtPP * compute_vertical_nodes(const RzAGraph *g)
static void graph_breakpoint(RzCore *core)
static void nextword(RzCore *core, RzAGraph *g, const char *word)
static int is_near_h(const RzANode *n, int x, int y, int is_next)
XXX is wrong.
static bool check_changes(RzAGraph *g, int is_interactive, RzCore *core, RzAnalysisFunction *fcn)
static const char * mousemodes[]
static void agraph_set_layout(RzAGraph *g)
static void agraph_node_free(RzANode *n)
static void agraph_next_node(RzAGraph *g)
static int count_edges(const RzAGraph *g, RzANode *src, RzANode *dst)
static void graphNodeMove(RzAGraph *g, int dir, int speed)
RZ_API void rz_agraph_reset(RzAGraph *g)
static void add_sorted(RzGraphNode *n, RzGraphVisitor *vis)
static void set_dist_nodes(const RzAGraph *g, int l, int cur, int next)
static void place_original(RzAGraph *g)
static const RzGraphNode * find_near_of(const RzAGraph *g, const RzGraphNode *cur, int is_next)
static void agraph_toggle_mini(RzAGraph *g)
static void agraph_follow_true(RzAGraph *g)
RZ_API void rz_agraph_foreach_edge(RzAGraph *g, RAEdgeCallback cb, void *user)
static void set_layer_gap(RzAGraph *g)
static RzList ** compute_classes(const RzAGraph *g, HtPP *v_nodes, int is_left, int *n_classes)
#define MINIGRAPH_NODE_TITLE_LEN
#define MINIGRAPH_NODE_TEXT_CUR
static int first_x_cmp(const void *_a, const void *_b)
static void agraph_set_zoom(RzAGraph *g, int v)
static char * get_node_color(int color, int cur)
RZ_API RzANode * rz_agraph_get_node(const RzAGraph *g, const char *title)
static char * get_graph_string(RzCore *core, RzAGraph *g)
#define MINIGRAPH_NODE_MIN_WIDTH
static void agraph_update_title(RzCore *core, RzAGraph *g, RzAnalysisFunction *fcn)
static int get_bbnodes(RzAGraph *g, RzCore *core, RzAnalysisFunction *fcn)
static int is_near(const RzANode *n, int x, int y, int is_next)
static void graph_single_step_over(RzCore *core, RzAGraph *g)
#define HORIZONTAL_NODE_SPACING
static char * get_bb_body(RzCore *core, RzAnalysisBlock *b, int opts, RzAnalysisFunction *fcn, bool emu, ut64 saved_gp, ut8 *saved_arena)
static void normal_RzANode_print(const RzAGraph *g, const RzANode *n, int cur)
RZ_API void rz_agraph_print(RzAGraph *g)
static void update_seek(RzConsCanvas *can, RzANode *n, int force)
static bool agraph_reload_nodes(RzAGraph *g, RzCore *core, RzAnalysisFunction *fcn)
static void combine_sequences(const RzAGraph *g, int l, const RzGraphNode *bm, const RzGraphNode *bp, int from_up, int a, int r)
RZ_API RzAGraph * create_agraph_from_graph(const RzGraph *graph)
Create RzAGraph from generic RzGraph with RzGraphNodeInfo as node data.
static void applyDisMode(RzCore *core)
static void place_sequence(const RzAGraph *g, int l, const RzGraphNode *bm, const RzGraphNode *bp, int from_up, int va, int vr)
static void create_layers(RzAGraph *g)
static bool is_reversed(const RzAGraph *g, const RzGraphEdge *e)
static int RP_listcmp(const struct len_pos_t *a, const struct len_pos_t *b)
static bool get_cgnodes(RzAGraph *g, RzCore *core, RzAnalysisFunction *fcn)
static bool is_mini(const RzAGraph *g)
static bool is_summary(const RzAGraph *g)
static int adjust_class_val(const RzAGraph *g, const RzGraphNode *gn, const RzGraphNode *sibl, HtPU *res, int is_left)
static int find_dist(const struct dist_t *a, const struct dist_t *b)
static char * get_body(RzCore *core, ut64 addr, int size, int opts)
int tmplayercmp(const void *a, const void *b)
static bool is_tiny(const RzAGraph *g)
static void place_nodes(const RzAGraph *g, const RzGraphNode *gn, int is_left, HtPP *v_nodes, RzList **classes, HtPU *res, SetP *placed)
static void agraph_follow_innodes(RzAGraph *g, bool in)
static void agraph_prev_node(RzAGraph *g)
static void sdb_set_enc(Sdb *db, const char *key, const char *v, ut32 cas)
static void update_graph_sizes(RzAGraph *g)
static int layer_sweep(const RzGraph *g, const struct layer_t layers[], int maxlayer, int i, int from_up)
RZ_API void rz_agraph_add_edge_at(const RzAGraph *g, RzANode *a, RzANode *b, int nth)
RZ_API void rz_agraph_foreach(RzAGraph *g, RzANodeCallback cb, void *user)
#define VERTICAL_NODE_SPACING
static HtPPOptions nodes_opt
RZ_API void rz_agraph_print_json(RzAGraph *g, PJ *pj)
static bool user_edge_cb(struct g_cb *user, RZ_UNUSED const void *k, const void *v)
static void agraph_toggle_speed(RzAGraph *g, RzCore *core)
static void agraph_print_nodes(const RzAGraph *g)
static void move_current_node(RzAGraph *g, int xdiff, int ydiff)
static void check_function_modified(RzCore *core, RzAnalysisFunction *fcn)
static void seek_to_node(RzANode *n, RzCore *core)
static void rotateColor(RzCore *core)
static void graph_continue(RzCore *core)
RZ_API void rz_agraph_add_edge(const RzAGraph *g, RzANode *a, RzANode *b)
static void free_nodes_kv(HtPPKv *kv)
static void adjust_directions(const RzAGraph *g, int i, int from_up, HtPU *D, HtPU *P)
static void get_bbupdate(RzAGraph *g, RzCore *core, RzAnalysisFunction *fcn)
#define MININODE_MIN_WIDTH
static void agraph_init(RzAGraph *g)
static void showcursor(RzCore *core, int x)
static void view_dummy(const RzGraphEdge *e, const RzGraphVisitor *vis)
static void fix_back_edge_dummy_nodes(RzAGraph *g, RzANode *from, RzANode *to)
static void update_node_dimension(const RzGraph *g, int is_mini, int zoom, int edgemode, bool callgraph, int layout)
static int prev_mode(int mode)
static void agraph_update_seek(RzAGraph *g, RzANode *n, int force)
static int place_nodes_sel_p(int newval, int oldval, int is_first, int is_left)
static void agraph_toggle_tiny(RzAGraph *g)
static void backedge_info(RzAGraph *g)
#define MINIGRAPH_NODE_CENTER_X
static void agraph_follow_false(RzAGraph *g)
static void follow_nth(RzAGraph *g, int nth)
RZ_API bool rz_analysis_function_was_modified(RzAnalysisFunction *fcn)
RZ_API ut8 * rz_reg_arena_dup(RzReg *reg, const ut8 *source)
RZ_API ut8 * rz_reg_arena_peek(RzReg *reg)
RZ_API void rz_reg_arena_poke(RzReg *reg, const ut8 *ret)
RZ_API int sdb_array_add(Sdb *s, const char *key, const char *val, ut32 cas)
RZ_API int sdb_array_insert(Sdb *s, const char *key, int idx, const char *val, ut32 cas)
RZ_API int sdb_array_remove(Sdb *s, const char *key, const char *val, ut32 cas)
RZ_API char * sdb_encode(const ut8 *bin, int len)
static RzList * classes(RzBinFile *bf)
RzBinInfo * info(RzBinFile *bf)
RZ_API RzAnalysisBlock * rz_analysis_get_block_at(RzAnalysis *analysis, ut64 addr)
RZ_API RzAnalysisBlock * rz_analysis_find_most_relevant_block_in(RzAnalysis *analysis, ut64 off)
const lzma_allocator const uint8_t * in
RZ_IPI void rz_core_agraph_print_interactive(RzCore *core)
RZ_IPI void rz_core_agraph_reset(RzCore *core)
RZ_API bool rz_core_analysis_function_add(RzCore *core, const char *name, ut64 addr, bool analyze_recursively)
RZ_IPI char * rz_core_analysis_function_signature(RzCore *core, RzOutputMode mode, char *fcn_name)
RZ_API void rz_cons_canvas_print_region(RzConsCanvas *c)
RZ_API void rz_cons_canvas_fill(RzConsCanvas *c, int x, int y, int w, int h, char ch)
RZ_API int rz_cons_canvas_resize(RzConsCanvas *c, int w, int h)
RZ_API void rz_cons_canvas_line(RzConsCanvas *c, int x, int y, int x2, int y2, RzCanvasLineStyle *style)
RZ_API RzConsCanvas * rz_cons_canvas_new(int w, int h)
RZ_API void rz_cons_canvas_box(RzConsCanvas *c, int x, int y, int w, int h, const char *color)
RZ_API void rz_cons_canvas_free(RzConsCanvas *c)
RZ_API void rz_cons_canvas_line_square_defined(RzConsCanvas *c, int x, int y, int x2, int y2, RzCanvasLineStyle *style, int bendpoint, int isvert)
RZ_API void rz_cons_canvas_line_back_edge(RzConsCanvas *c, int x, int y, int x2, int y2, RzCanvasLineStyle *style, int ybendpoint1, int xbendpoint, int ybendpoint2, int isvert)
RZ_API void rz_core_debug_breakpoint_toggle(RZ_NONNULL RzCore *core, ut64 addr)
Toggle breakpoint.
RZ_IPI void rz_core_debug_continue(RzCore *core)
RZ_IPI void rz_core_debug_single_step_in(RzCore *core)
RZ_IPI void rz_core_debug_single_step_over(RzCore *core)
RZ_API int rz_core_cmd0(RzCore *core, const char *cmd)
RZ_API char * rz_core_cmd_strf(RzCore *core, const char *fmt,...)
RZ_API char * rz_core_cmd_str(RzCore *core, const char *cmd)
Executes a rizin command and returns the stdout as a string.
RZ_API void rz_core_theme_nextpal(RzCore *core, RzConsPalSeekMode mode)
RZ_API void rz_core_gadget_print(RzCore *core)
Prints or displays the print gadgets while in visual mode.
RZ_IPI bool rz_core_seek_to_register(RzCore *core, const char *regname, bool is_silent)
RZ_IPI int rz_core_seek_opcode(RzCore *core, int n, bool silent)
RZ_API ut64 rz_config_get_i(RzConfig *cfg, RZ_NONNULL const char *name)
RZ_API RzConfigNode * rz_config_set(RzConfig *cfg, RZ_NONNULL const char *name, const char *value)
RZ_API RzConfigNode * rz_config_set_i(RzConfig *cfg, RZ_NONNULL const char *name, const ut64 i)
RZ_API RZ_BORROW const char * rz_config_get(RzConfig *cfg, RZ_NONNULL const char *name)
RZ_API bool rz_config_toggle(RzConfig *cfg, RZ_NONNULL const char *name)
RZ_API void rz_cons_clear00(void)
RZ_API int rz_cons_get_size(int *rows)
RZ_API RZ_OWN char * rz_cons_get_buffer_dup(void)
Return a newly allocated buffer containing what's currently in RzCons buffer.
RZ_API bool rz_cons_enable_mouse(const bool enable)
RZ_API RzCons * rz_cons_singleton(void)
RZ_API void rz_cons_clear_line(int std_err)
RZ_API void rz_cons_strcat(const char *str)
RZ_API void rz_cons_newline(void)
RZ_API void rz_cons_break_pop(void)
RZ_API void rz_cons_break_push(RzConsBreak cb, void *user)
RZ_API int rz_cons_printf(const char *format,...)
RZ_API bool rz_cons_is_interactive(void)
RZ_API void rz_cons_visual_flush(void)
RZ_API void rz_cons_show_cursor(int cursor)
RZ_API void rz_cons_flush(void)
RZ_API void rz_cons_break_end(void)
RZ_API bool rz_cons_is_breaked(void)
RZ_API void rz_cons_gotoxy(int x, int y)
RZ_API void rz_cons_reset(void)
RZ_IPI bool rz_core_seek_bb_instruction(RzCore *core, int index)
RZ_API bool rz_core_reg_set_by_role_or_name(RzCore *core, const char *name, ut64 num)
set on rz_core_reg_default()
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void count
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags cmd
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void static offset struct stat static buf void long static basep static whence static length const void static len key
RZ_API int rz_line_hist_cmd_down(RzLine *line)
RZ_API const char * rz_line_readline(void)
RZ_API int rz_line_hist_cmd_up(RzLine *line)
RZ_API int rz_line_set_hist_callback(RzLine *line, RzLineHistoryUpCb up, RzLineHistoryDownCb down)
static states step(struct re_guts *, sopno, sopno, states, int, states)
RZ_DEPRECATE RZ_API RzAnalysisFunction * rz_analysis_get_fcn_in(RzAnalysis *analysis, ut64 addr, int type)
RZ_API void rz_analysis_function_update_analysis(RzAnalysisFunction *fcn)
RZ_API char * sdb_fmt(const char *fmt,...)
RZ_API bool rz_core_hack(RzCore *core, const char *op)
Write/Modify instructions at current offset based on op.
RZ_API void rz_config_hold_restore(RzConfigHold *h)
Restore whatever config options were previously saved in h.
RZ_API RzConfigHold * rz_config_hold_new(RzConfig *cfg)
Create an opaque object to save/restore some configuration options.
RZ_API bool rz_config_hold_i(RzConfigHold *h,...)
Save the current values of a list of config options that have integer values.
RZ_API void rz_config_hold_free(RzConfigHold *h)
Free a RzConfigHold object h.
RZ_API void Ht_() free(HtName_(Ht) *ht)
static void freefn(HtName_(Ht) *ht, HT_(Kv) *kv)
static ut32 hashfn(HtName_(Ht) *ht, const KEY_TYPE k)
RZ_API const KEY_TYPE bool * found
RZ_API void rz_cons_message(RZ_NONNULL const char *msg)
RZ_API void rz_cons_less(void)
RZ_API ut64 rz_core_get_asmqjmps(RzCore *core, const char *str)
RZ_API char * rz_core_add_asmqjmp(RzCore *core, ut64 addr)
static void list(RzEgg *egg)
RZ_API RZ_BORROW RzListIter * rz_list_find(RZ_NONNULL const RzList *list, const void *p, RZ_NONNULL RzListComparator cmp)
Returns RzListIter element which matches via the RzListComparator.
RZ_API RZ_BORROW RzListIter * rz_list_contains(RZ_NONNULL const RzList *list, RZ_NONNULL const void *ptr)
Returns the RzListIter of the given pointer, if found.
RZ_API RZ_BORROW RzListIter * rz_list_prepend(RZ_NONNULL RzList *list, void *data)
Appends at the beginning of the list a new element.
RZ_API RZ_OWN RzList * rz_list_newf(RzListFree f)
Returns a new initialized RzList pointer and sets the free method.
RZ_API void rz_list_delete(RZ_NONNULL RzList *list, RZ_NONNULL RzListIter *iter)
Removes an entry in the list by using the RzListIter pointer.
RZ_API void * rz_list_iter_get_data(RzListIter *list)
returns the value stored in the list element
RZ_API bool rz_list_delete_data(RZ_NONNULL RzList *list, void *ptr)
Deletes an entry in the list by searching for a pointer.
RZ_API RZ_OWN void * rz_list_pop(RZ_NONNULL RzList *list)
Removes and returns the last element of the list.
RZ_API RZ_OWN RzList * rz_list_new(void)
Returns a new initialized RzList pointer (free method is not initialized)
RZ_API void rz_list_sort(RZ_NONNULL RzList *list, RZ_NONNULL RzListComparator cmp)
Sorts via merge sort or via insertion sort a list.
RZ_API RZ_BORROW void * rz_list_first(RZ_NONNULL const RzList *list)
Returns the first element of the list.
RZ_API RZ_BORROW void * rz_list_get_n(RZ_NONNULL const RzList *list, ut32 n)
Returns the N-th element of the list.
RZ_API RZ_BORROW RzListIter * rz_list_push(RZ_NONNULL RzList *list, void *item)
Alias for rz_list_append.
RZ_API ut32 rz_list_length(RZ_NONNULL const RzList *list)
Returns the length of the list.
RZ_API RZ_BORROW RzListIter * rz_list_append(RZ_NONNULL RzList *list, void *data)
Appends at the end of the list a new element.
RZ_API RZ_BORROW RzListIter * rz_list_add_sorted(RZ_NONNULL RzList *list, void *data, RZ_NONNULL RzListComparator cmp)
Adds an element to a sorted list via the RzListComparator.
RZ_API void rz_list_free(RZ_NONNULL RzList *list)
Empties the list and frees the list pointer.
RZ_API void rz_list_purge(RZ_NONNULL RzList *list)
Empties the list without freeing the list pointer.
void * calloc(size_t number, size_t size)
RZ_API void rz_line_set_prompt(const char *prompt)
return strdup("=SP r13\n" "=LR r14\n" "=PC r15\n" "=A0 r0\n" "=A1 r1\n" "=A2 r2\n" "=A3 r3\n" "=ZF zf\n" "=SF nf\n" "=OF vf\n" "=CF cf\n" "=SN or0\n" "gpr lr .32 56 0\n" "gpr pc .32 60 0\n" "gpr cpsr .32 64 0 ____tfiae_________________qvczn\n" "gpr or0 .32 68 0\n" "gpr tf .1 64.5 0 thumb\n" "gpr ef .1 64.9 0 endian\n" "gpr jf .1 64.24 0 java\n" "gpr qf .1 64.27 0 sticky_overflow\n" "gpr vf .1 64.28 0 overflow\n" "gpr cf .1 64.29 0 carry\n" "gpr zf .1 64.30 0 zero\n" "gpr nf .1 64.31 0 negative\n" "gpr itc .4 64.10 0 if_then_count\n" "gpr gef .4 64.16 0 great_or_equal\n" "gpr r0 .32 0 0\n" "gpr r1 .32 4 0\n" "gpr r2 .32 8 0\n" "gpr r3 .32 12 0\n" "gpr r4 .32 16 0\n" "gpr r5 .32 20 0\n" "gpr r6 .32 24 0\n" "gpr r7 .32 28 0\n" "gpr r8 .32 32 0\n" "gpr r9 .32 36 0\n" "gpr r10 .32 40 0\n" "gpr r11 .32 44 0\n" "gpr r12 .32 48 0\n" "gpr r13 .32 52 0\n" "gpr r14 .32 56 0\n" "gpr r15 .32 60 0\n" "gpr r16 .32 64 0\n" "gpr r17 .32 68 0\n")
static const char struct stat static buf struct stat static buf static vhangup int options
RZ_API int sdb_num_set(Sdb *s, const char *key, ut64 v, ut32 cas)
RZ_API int sdb_bool_set(Sdb *db, const char *str, bool v, ut32 cas)
RZ_API void rz_cons_pal_random(void)
RZ_API bool rz_core_visual_panels_root(RzCore *core, RzPanelsRoot *panels_root)
RZ_API ut64 rz_reg_getv(RzReg *reg, const char *name)
RZ_API RzRegItem * rz_reg_get(RzReg *reg, const char *name, int type)
RZ_API const char * rz_reg_get_name(RzReg *reg, int role)
RZ_API ut64 rz_reg_get_value(RzReg *reg, RzRegItem *item)
#define RZ_AGRAPH_MODE_NORMAL
#define RZ_AGRAPH_MODE_COMMENTS
void(* RAEdgeCallback)(RzANode *from, RzANode *to, void *user)
#define RZ_AGRAPH_MODE_MINI
#define RZ_AGRAPH_MODE_SUMMARY
void(* RzANodeCallback)(RzANode *n, void *user)
#define RZ_AGRAPH_MODE_MAX
#define RZ_AGRAPH_MODE_TINY
#define RZ_AGRAPH_MODE_OFFSET
@ RZ_ANALYSIS_DIFF_TYPE_MATCH
@ RZ_ANALYSIS_DIFF_TYPE_UNMATCH
#define rz_return_if_fail(expr)
#define rz_return_val_if_fail(expr, val)
void(* RzConsEvent)(void *)
#define DOT_STYLE_CONDITIONAL
#define DOT_STYLE_BACKEDGE
#define RZ_CORE_ASMQJMPS_LEN_LETTERS
RZ_API RzGraph * rz_graph_new(void)
RZ_API void rz_graph_del_node(RzGraph *g, RzGraphNode *n)
void(* RzGraphEdgeCallback)(const RzGraphEdge *e, RzGraphVisitor *vis)
RZ_API const RzList * rz_graph_all_neighbours(const RzGraph *g, const RzGraphNode *n)
RZ_API void rz_graph_dfs(RzGraph *g, RzGraphVisitor *vis)
RZ_API void rz_graph_del_edge(RzGraph *g, RzGraphNode *from, RzGraphNode *to)
RZ_API RzGraphNode * rz_graph_nth_neighbour(const RzGraph *g, const RzGraphNode *n, int nth)
RZ_API const RzList * rz_graph_get_nodes(const RzGraph *g)
RZ_API const RzList * rz_graph_get_neighbours(const RzGraph *g, const RzGraphNode *n)
RZ_API void rz_graph_reset(RzGraph *g)
RZ_API const RzList * rz_graph_innodes(const RzGraph *g, const RzGraphNode *n)
RZ_API void rz_graph_add_edge(RzGraph *g, RzGraphNode *from, RzGraphNode *to)
RZ_API void rz_graph_add_edge_at(RzGraph *g, RzGraphNode *from, RzGraphNode *to, int nth)
RZ_API void rz_graph_free(RzGraph *g)
RZ_API RzGraphNode * rz_graph_add_node(RzGraph *g, void *data)
void(* RzGraphNodeCallback)(RzGraphNode *n, RzGraphVisitor *vis)
RZ_API bool rz_io_is_valid_offset(RzIO *io, ut64 offset, int hasperm)
void(* RzListFree)(void *ptr)
int(* RzListComparator)(const void *value, const void *list_data)
RZ_API ut64 rz_num_get(RzNum *num, const char *str)
RZ_API PJ * pj_ki(PJ *j, const char *k, int d)
RZ_API PJ * pj_k(PJ *j, const char *k)
RZ_API PJ * pj_end(PJ *j)
RZ_API PJ * pj_i(PJ *j, int d)
RZ_API PJ * pj_ks(PJ *j, const char *k, const char *v)
RZ_API char * rz_str_trim_lines(char *str)
#define RZ_STR_ISNOTEMPTY(x)
RZ_API const char * rz_str_str_xy(const char *s, const char *word, const char *prev, int *x, int *y)
RZ_API char * rz_str_newf(const char *fmt,...) RZ_PRINTF_CHECK(1
RZ_API char * rz_str_append(char *ptr, const char *string)
RZ_API const char * rz_str_bool(int b)
#define RZ_STR_ISEMPTY(x)
RZ_API char * rz_str_ansi_crop(const char *str, unsigned int x, unsigned int y, unsigned int x2, unsigned int y2)
RZ_API char * rz_str_replace(char *str, const char *key, const char *val, int g)
RZ_API char * rz_str_trunc_ellipsis(const char *str, int len)
RZ_API void rz_str_trim(RZ_NONNULL RZ_INOUT char *str)
Removes whitespace characters (space, tab, newline etc.) from the beginning and end of a string.
RZ_API int rz_str_bounds(const char *str, int *h)
@ RZ_OUTPUT_MODE_STANDARD
static void * rz_vector_index_ptr(RzVector *vec, size_t index)
RZ_API void * rz_vector_push(RzVector *vec, void *x)
RZ_API void rz_vector_fini(RzVector *vec)
RZ_API void rz_vector_clear(RzVector *vec)
RZ_API void rz_vector_init(RzVector *vec, size_t elem_size, RzVectorFree free, void *free_user)
RZ_API int sdb_set_owned(Sdb *s, const char *key, char *val, ut32 cas)
RZ_API int sdb_set(Sdb *s, const char *key, const char *val, ut32 cas)
RZ_API Sdb * sdb_new0(void)
RZ_API char * sdb_get(Sdb *s, const char *key, ut32 *cas)
RZ_API bool sdb_free(Sdb *s)
RZ_API void sdb_reset(Sdb *s)
RZ_API const char * sdb_const_get(Sdb *s, const char *key, ut32 *cas)
RZ_API ut32 sdb_hash(const char *key)
RZ_API bool rz_core_seek_redo(RzCore *core)
RZ_API bool rz_core_seek_and_save(RzCore *core, ut64 addr, bool rb)
Save currently marked state in seek history and seek to addr .
RZ_API bool rz_core_seek_next(RzCore *core, const char *type, bool save)
Seek to the next type of item from current offset.
RZ_API bool rz_core_seek_prev(RzCore *core, const char *type, bool save)
Seek to the previous type of item from current offset.
RZ_API bool rz_core_seek_undo(RzCore *core)
RZ_API bool rz_core_seek(RzCore *core, ut64 addr, bool rb)
Seek to addr.
RZ_API void set_p_free(SetP *p)
RZ_API bool set_p_contains(SetP *s, const void *u)
RZ_API void set_p_add(SetP *s, const void *u)
static struct sockaddr static addrlen static backlog const void static flags void struct sockaddr from
static struct sockaddr static addrlen static backlog const void static flags void struct sockaddr socklen_t static fromlen const void const struct sockaddr to
RzAnalysisFunction ** fcn
RzAnalysisSwitchOp * switch_op
Generic drawable graph node.
RzConsPrintablePalette pal
RzCoreTaskScheduler tasks
RzPanelsRoot * panels_root
void(* finish_node)(RzGraphNode *n, struct rz_graph_visitor_t *vis)
void(* back_edge)(const RzGraphEdge *e, struct rz_graph_visitor_t *vis)
void(* tree_edge)(const RzGraphEdge *e, struct rz_graph_visitor_t *vis)
void(* fcross_edge)(const RzGraphEdge *e, struct rz_graph_visitor_t *vis)
RzLinePromptType prompt_type
struct rz_list_iter_t * n
RZ_API void rz_core_task_enqueue_oneshot(RzCoreTaskScheduler *scheduler, RzCoreTaskOneShot func, void *user)
RZ_API RzDebugTracepoint * rz_debug_trace_get(RzDebug *dbg, ut64 addr)
RZ_API void rz_core_visual_toggle_decompiler_disasm(RzCore *core, bool for_graph, bool reset)
RZ_API void rz_core_visual_prompt_input(RzCore *core)
RZ_API void rz_core_visual_browse(RzCore *core, const char *input)
RZ_API void rz_core_print_scrollbar(RzCore *core)
RZ_API int rz_core_visual_xrefs(RzCore *core, bool xref_to, bool fcnInsteadOfAddr)
RZ_API void rz_core_visual_toggle_hints(RzCore *core)
RZ_API int rz_line_hist_offset_up(RzLine *line)
RZ_API int rz_line_hist_offset_down(RzLine *line)
if(dbg->bits==RZ_SYS_BITS_64)
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
RZ_API RzList * rz_analysis_function_get_xrefs_from(RzAnalysisFunction *fcn)
static unsigned char * obuf