Rizin
unix-like reverse engineering framework and cli tools
graph.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2007-2020 pancake <pancake@nopcode.org>
2 // SPDX-FileCopyrightText: 2007-2020 ret2libc <sirmy15@gmail.com>
3 // SPDX-License-Identifier: LGPL-3.0-only
4 
5 #include <rz_util.h>
6 
7 enum {
11 };
12 
13 static RzGraphNode *rz_graph_node_new(void *data) {
15  if (p) {
16  p->data = data;
17  p->free = NULL;
18  p->out_nodes = rz_list_new();
19  p->in_nodes = rz_list_new();
20  p->all_neighbours = rz_list_new();
21  }
22  return p;
23 }
24 
26  if (!n) {
27  return;
28  }
29  if (n->free) {
30  n->free(n->data);
31  }
32  rz_list_free(n->out_nodes);
33  rz_list_free(n->in_nodes);
34  rz_list_free(n->all_neighbours);
35  free(n);
36 }
37 
38 static int node_cmp(unsigned int idx, RzGraphNode *b) {
39  return idx == b->idx ? 0 : -1;
40 }
41 
42 // direction == true => forwards
43 static void dfs_node(RzGraph *g, RzGraphNode *n, RzGraphVisitor *vis, int color[], const bool direction) {
44  if (!n) {
45  return;
46  }
47  RzStack *s = rz_stack_new(2 * g->n_edges + 1);
48  if (!s) {
49  return;
50  }
52  if (!edg) {
54  return;
55  }
56  edg->from = NULL;
57  edg->to = n;
58  rz_stack_push(s, edg);
59  while (!rz_stack_is_empty(s)) {
60  RzGraphEdge *cur_edge = (RzGraphEdge *)rz_stack_pop(s);
61  RzGraphNode *v, *cur = cur_edge->to, *from = cur_edge->from;
62  RzListIter *it;
63  int i;
64 
65  if (from && cur) {
66  if (color[cur->idx] == WHITE_COLOR && vis->tree_edge) {
67  vis->tree_edge(cur_edge, vis);
68  } else if (color[cur->idx] == GRAY_COLOR && vis->back_edge) {
69  vis->back_edge(cur_edge, vis);
70  } else if (color[cur->idx] == BLACK_COLOR && vis->fcross_edge) {
71  vis->fcross_edge(cur_edge, vis);
72  }
73  } else if (!cur && from) {
74  if (color[from->idx] != BLACK_COLOR && vis->finish_node) {
75  vis->finish_node(from, vis);
76  }
77  color[from->idx] = BLACK_COLOR;
78  }
79  free(cur_edge);
80  if (!cur || color[cur->idx] != WHITE_COLOR) {
81  continue;
82  }
83  if (color[cur->idx] == WHITE_COLOR && vis->discover_node) {
84  vis->discover_node(cur, vis);
85  }
86  color[cur->idx] = GRAY_COLOR;
87 
88  edg = RZ_NEW0(RzGraphEdge);
89  if (!edg) {
90  break;
91  }
92  edg->from = cur;
93  rz_stack_push(s, edg);
94 
95  i = 0;
96  const RzList *neighbours = direction ? cur->out_nodes : cur->in_nodes;
97  rz_list_foreach (neighbours, it, v) {
98  edg = RZ_NEW(RzGraphEdge);
99  edg->from = cur;
100  edg->to = v;
101  edg->nth = i++;
102  rz_stack_push(s, edg);
103  }
104  }
105  rz_stack_free(s);
106 }
107 
109  RzGraph *t = RZ_NEW0(RzGraph);
110  if (!t) {
111  return NULL;
112  }
113  t->nodes = rz_list_new();
114  if (!t->nodes) {
115  rz_graph_free(t);
116  return NULL;
117  }
119  t->n_nodes = 0;
120  t->last_index = 0;
121  return t;
122 }
123 
125  rz_list_free(t->nodes);
126  free(t);
127 }
128 
129 RZ_API RzGraphNode *rz_graph_get_node(const RzGraph *t, unsigned int idx) {
130  RzListIter *it = rz_list_find(t->nodes, (void *)(size_t)idx, (RzListComparator)node_cmp);
131  if (!it) {
132  return NULL;
133  }
134  return (RzGraphNode *)it->data;
135 }
136 
137 RZ_API RzListIter *rz_graph_node_iter(const RzGraph *t, unsigned int idx) {
138  return rz_list_find(t->nodes, (void *)(size_t)idx, (RzListComparator)node_cmp);
139 }
140 
142  rz_list_free(t->nodes);
143  t->nodes = rz_list_new();
144  if (!t->nodes) {
145  return;
146  }
148  t->n_nodes = 0;
149  t->n_edges = 0;
150  t->last_index = 0;
151 }
152 
154  if (!t) {
155  return NULL;
156  }
158  if (!n) {
159  return NULL;
160  }
161  n->idx = t->last_index++;
162  rz_list_append(t->nodes, n);
163  t->n_nodes++;
164  return n;
165 }
166 
167 RZ_API RzGraphNode *rz_graph_add_nodef(RzGraph *graph, void *data, RzListFree user_free) {
168  RzGraphNode *node = rz_graph_add_node(graph, data);
169  if (node) {
170  node->free = user_free;
171  }
172  return node;
173 }
174 
175 /* remove the node from the graph and free the node */
176 /* users of this function should be aware they can't access n anymore */
178  RzGraphNode *gn;
179  RzListIter *it;
180  if (!n) {
181  return;
182  }
183  rz_list_foreach (n->in_nodes, it, gn) {
186  t->n_edges--;
187  }
188 
189  rz_list_foreach (n->out_nodes, it, gn) {
192  t->n_edges--;
193  }
194 
196  t->n_nodes--;
197 }
198 
200  rz_graph_add_edge_at(t, from, to, -1);
201 }
202 
204  if (from && to) {
205  rz_list_insert(from->out_nodes, nth, to);
206  rz_list_append(from->all_neighbours, to);
207  rz_list_append(to->in_nodes, from);
208  rz_list_append(to->all_neighbours, from);
209  t->n_edges++;
210  }
211 }
212 
213 // splits the "split_me", so that new node has it's outnodes
215  RzGraphNode *front = rz_graph_add_node(g, data);
216  RzList *tmp = front->out_nodes;
217  front->out_nodes = split_me->out_nodes;
218  split_me->out_nodes = tmp;
219  RzListIter *iter;
220  RzGraphNode *n;
221  rz_list_foreach (front->out_nodes, iter, n) {
222  rz_list_delete_data(n->in_nodes, split_me); // optimize me
223  rz_list_delete_data(n->all_neighbours, split_me); // boy this all_neighbours is so retarding perf here
225  rz_list_append(n->all_neighbours, front);
226  rz_list_append(n->in_nodes, front);
228  }
229  return front;
230 }
231 
233  if (!from || !to || !rz_graph_adjacent(t, from, to)) {
234  return;
235  }
236  rz_list_delete_data(from->out_nodes, to);
237  rz_list_delete_data(from->all_neighbours, to);
238  rz_list_delete_data(to->in_nodes, from);
239  rz_list_delete_data(to->all_neighbours, from);
240  t->n_edges--;
241 }
242 
243 // XXX remove comments and static inline all this stuff
244 /* returns the list of nodes reachable from `n` */
246  return n ? n->out_nodes : NULL;
247 }
248 
249 /* returns the n-th nodes reachable from the give node `n`.
250  * This, of course, depends on the order of the nodes. */
252  return n ? (RzGraphNode *)rz_list_get_n(n->out_nodes, nth) : NULL;
253 }
254 
255 /* returns the list of nodes that can reach `n` */
257  return n ? n->in_nodes : NULL;
258 }
259 
260 /* returns the list of nodes reachable from `n` and that can reach `n`. */
262  return n ? n->all_neighbours : NULL;
263 }
264 
266  return g ? g->nodes : NULL;
267 }
268 
269 /* true if there is an edge from the node `from` to the node `to` */
271  if (!g || !from) {
272  return false;
273  }
274  return rz_list_contains(from->out_nodes, to);
275 }
276 
278  if (!g || !n || !vis) {
279  return;
280  }
281  int *color = RZ_NEWS0(int, g->last_index);
282  if (color) {
283  dfs_node(g, n, vis, color, true);
284  free(color);
285  }
286 }
287 
289  if (!g || !n || !vis) {
290  return;
291  }
292  int *color = RZ_NEWS0(int, g->last_index);
293  if (color) {
294  dfs_node(g, n, vis, color, false);
295  free(color);
296  }
297 }
298 
300  rz_return_if_fail(g && vis);
301  RzGraphNode *n;
302  RzListIter *it;
303 
304  int *color = RZ_NEWS0(int, g->last_index);
305  if (color) {
306  rz_list_foreach (g->nodes, it, n) {
307  if (color[n->idx] == WHITE_COLOR) {
308  dfs_node(g, n, vis, color, true);
309  }
310  }
311  free(color);
312  }
313 }
lzma_index ** i
Definition: index.h:629
#define RZ_API
#define NULL
Definition: cris-opc.c:27
const char * v
Definition: dsignal.c:12
struct @667 g
RZ_API RzGraph * rz_graph_new(void)
Definition: graph.c:108
static int node_cmp(unsigned int idx, RzGraphNode *b)
Definition: graph.c:38
RZ_API void rz_graph_free(RzGraph *t)
Definition: graph.c:124
RZ_API RzGraphNode * rz_graph_add_node(RzGraph *t, void *data)
Definition: graph.c:153
RZ_API void rz_graph_add_edge_at(RzGraph *t, RzGraphNode *from, RzGraphNode *to, int nth)
Definition: graph.c:203
RZ_API const RzList * rz_graph_all_neighbours(const RzGraph *g, const RzGraphNode *n)
Definition: graph.c:261
RZ_API void rz_graph_dfs(RzGraph *g, RzGraphVisitor *vis)
Definition: graph.c:299
static void dfs_node(RzGraph *g, RzGraphNode *n, RzGraphVisitor *vis, int color[], const bool direction)
Definition: graph.c:43
RZ_API RzGraphNode * rz_graph_nth_neighbour(const RzGraph *g, const RzGraphNode *n, int nth)
Definition: graph.c:251
RZ_API bool rz_graph_adjacent(const RzGraph *g, const RzGraphNode *from, const RzGraphNode *to)
Definition: graph.c:270
RZ_API const RzList * rz_graph_get_nodes(const RzGraph *g)
Definition: graph.c:265
RZ_API void rz_graph_dfs_node(RzGraph *g, RzGraphNode *n, RzGraphVisitor *vis)
Definition: graph.c:277
RZ_API RzGraphNode * rz_graph_node_split_forward(RzGraph *g, RzGraphNode *split_me, void *data)
Definition: graph.c:214
static RzGraphNode * rz_graph_node_new(void *data)
Definition: graph.c:13
RZ_API void rz_graph_add_edge(RzGraph *t, RzGraphNode *from, RzGraphNode *to)
Definition: graph.c:199
@ BLACK_COLOR
Definition: graph.c:10
@ WHITE_COLOR
Definition: graph.c:8
@ GRAY_COLOR
Definition: graph.c:9
RZ_API const RzList * rz_graph_get_neighbours(const RzGraph *g, const RzGraphNode *n)
Definition: graph.c:245
RZ_API void rz_graph_reset(RzGraph *t)
Definition: graph.c:141
RZ_API RzGraphNode * rz_graph_get_node(const RzGraph *t, unsigned int idx)
Definition: graph.c:129
static void rz_graph_node_free(RzGraphNode *n)
Definition: graph.c:25
RZ_API void rz_graph_del_node(RzGraph *t, RzGraphNode *n)
Definition: graph.c:177
RZ_API void rz_graph_dfs_node_reverse(RzGraph *g, RzGraphNode *n, RzGraphVisitor *vis)
Definition: graph.c:288
RZ_API RzListIter * rz_graph_node_iter(const RzGraph *t, unsigned int idx)
Definition: graph.c:137
RZ_API const RzList * rz_graph_innodes(const RzGraph *g, const RzGraphNode *n)
Definition: graph.c:256
RZ_API RzGraphNode * rz_graph_add_nodef(RzGraph *graph, void *data, RzListFree user_free)
Definition: graph.c:167
RZ_API void rz_graph_del_edge(RzGraph *t, RzGraphNode *from, RzGraphNode *to)
Definition: graph.c:232
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
void * p
Definition: libc.cpp:67
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.
Definition: list.c:620
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.
Definition: list.c:592
RZ_API RZ_BORROW RzListIter * rz_list_insert(RZ_NONNULL RzList *list, ut32 n, void *data)
Inserts a new element at the N-th position.
Definition: list.c:342
RZ_API bool rz_list_delete_data(RZ_NONNULL RzList *list, void *ptr)
Deletes an entry in the list by searching for a pointer.
Definition: list.c:148
RZ_API RZ_OWN RzList * rz_list_new(void)
Returns a new initialized RzList pointer (free method is not initialized)
Definition: list.c:235
RZ_API RZ_BORROW void * rz_list_get_n(RZ_NONNULL const RzList *list, ut32 n)
Returns the N-th element of the list.
Definition: list.c:574
RZ_API RZ_BORROW RzListIter * rz_list_append(RZ_NONNULL RzList *list, void *data)
Appends at the end of the list a new element.
Definition: list.c:288
RZ_API void rz_list_free(RZ_NONNULL RzList *list)
Empties the list and frees the list pointer.
Definition: list.c:137
int n
Definition: mipsasm.c:19
int idx
Definition: setup.py:197
static RzSocket * s
Definition: rtr.c:28
#define rz_return_if_fail(expr)
Definition: rz_assert.h:100
void(* RzListFree)(void *ptr)
Definition: rz_list.h:11
int(* RzListComparator)(const void *value, const void *list_data)
Definition: rz_list.h:33
RZ_API bool rz_stack_is_empty(RzStack *s)
Definition: stack.c:68
RZ_API void * rz_stack_pop(RzStack *s)
Definition: stack.c:59
RZ_API bool rz_stack_push(RzStack *s, void *el)
Definition: stack.c:42
RZ_API RzStack * rz_stack_new(ut32 n)
Definition: stack.c:6
RZ_API void rz_stack_free(RzStack *s)
Definition: stack.c:29
#define RZ_NEW0(x)
Definition: rz_types.h:284
#define RZ_NEW(x)
Definition: rz_types.h:285
#define RZ_NEWS0(x, y)
Definition: rz_types.h:282
static struct sockaddr static addrlen static backlog const void static flags void struct sockaddr from
Definition: sfsocketcall.h:123
static struct sockaddr static addrlen static backlog const void static flags void struct sockaddr socklen_t static fromlen const void const struct sockaddr to
Definition: sfsocketcall.h:125
#define b(i)
Definition: sha256.c:42
RzGraphNode * to
Definition: rz_graph.h:21
RzGraphNode * from
Definition: rz_graph.h:20
unsigned int idx
Definition: rz_graph.h:11
RzList * out_nodes
Definition: rz_graph.h:13
RzList * all_neighbours
Definition: rz_graph.h:15
RzList * in_nodes
Definition: rz_graph.h:14
RzListFree free
Definition: rz_graph.h:16
RzList * nodes
Definition: rz_graph.h:29
int last_index
Definition: rz_graph.h:28
unsigned int n_nodes
Definition: rz_graph.h:26
unsigned int n_edges
Definition: rz_graph.h:27
void(* finish_node)(RzGraphNode *n, struct rz_graph_visitor_t *vis)
Definition: rz_graph.h:34
void(* discover_node)(RzGraphNode *n, struct rz_graph_visitor_t *vis)
Definition: rz_graph.h:33
void(* back_edge)(const RzGraphEdge *e, struct rz_graph_visitor_t *vis)
Definition: rz_graph.h:36
void(* tree_edge)(const RzGraphEdge *e, struct rz_graph_visitor_t *vis)
Definition: rz_graph.h:35
void(* fcross_edge)(const RzGraphEdge *e, struct rz_graph_visitor_t *vis)
Definition: rz_graph.h:37
void * data
Definition: rz_list.h:14
RzListFree free
Definition: rz_list.h:21
static int color
Definition: visual.c:20