Rizin
unix-like reverse engineering framework and cli tools
vmenus_graph.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2019 pancake <pancake@nopcode.org>
2 // SPDX-License-Identifier: LGPL-3.0-only
3 
4 #include <rz_core.h>
5 #define SORT_ADDRESS 0
6 #define SORT_NAME 1
7 
8 // find a better name and move to rz_util or rz_cons?
9 RZ_API char *rz_str_widget_list(void *user, RzList /*<void *>*/ *list, int rows, int cur, PrintItemCallback cb) {
10  void *item;
11  RzStrBuf *sb = rz_strbuf_new("");
13  int count = 0;
14  int skip = 0;
15  if (cur > (rows / 2)) {
16  skip = cur - (rows / 2);
17  }
18  rz_list_foreach (list, iter, item) {
19  if (rows >= 0) {
20  if (skip > 0) {
21  skip--;
22  } else {
23  char *line = cb(user, item, cur == count);
24  if (line) {
25  rz_strbuf_appendf(sb, "%s", line);
26  free(line);
27  }
28  rows--;
29  if (rows == 0) {
30  break;
31  }
32  }
33  }
34  count++;
35  }
36  return rz_strbuf_drain(sb);
37 }
38 
39 typedef struct {
42  int cur; // current row selected
43  int cur_sort; // holds current sort
49 
50 typedef struct {
52  const char *name;
55 
56 static char *print_item(void *_core, void *_item, bool selected) {
57  RzCoreVisualViewGraphItem *item = _item;
58  if (item->name && *item->name) {
59  if (false && item->fcn && item->addr > item->fcn->addr) {
60  st64 delta = item->addr - item->fcn->addr;
61  return rz_str_newf("%c %s+0x%" PFMT64x "\n", selected ? '>' : ' ', item->name, delta);
62  } else {
63  return rz_str_newf("%c %s\n", selected ? '>' : ' ', item->name);
64  }
65  }
66  return rz_str_newf("%c 0x%08" PFMT64x "\n", selected ? '>' : ' ', item->addr);
67 }
68 
69 static RzList *__xrefs(RzCore *core, ut64 addr) {
72  RzAnalysisXRef *xref;
74  rz_list_foreach (xrefs, iter, xref) {
75  if (xref->type != RZ_ANALYSIS_XREF_TYPE_CALL) {
76  continue;
77  }
79  RzFlagItem *f = rz_flag_get_at(core->flags, xref->from, 0);
80  item->addr = xref->from;
81  item->name = f ? f->name : NULL;
83  item->fcn = rf;
84  if (rf) {
85  item->name = rf->name;
86  }
87  rz_list_append(r, item);
88  }
89  return r;
90 }
91 
92 static RzList *__refs(RzCore *core, ut64 addr) {
95  RzAnalysisXRef *xref;
97  if (!fcn) {
98  return r;
99  }
101  rz_list_foreach (xrefs, iter, xref) {
102  if (xref->type != RZ_ANALYSIS_XREF_TYPE_CALL) {
103  continue;
104  }
106  RzFlagItem *f = rz_flag_get_at(core->flags, xref->to, 0);
107  item->addr = xref->to;
108  item->name = f ? f->name : NULL;
109  RzAnalysisFunction *rf = rz_analysis_get_fcn_in(core->analysis, xref->to, 0);
110  if (rf) {
111  item->name = rf->name;
112  item->fcn = rf;
113  }
114  rz_list_append(r, item);
115  }
116  return r;
117 }
118 
119 static RzList *__fcns(RzCore *core) {
121  RzListIter *iter;
122  RzAnalysisFunction *fcn;
123  rz_list_foreach (core->analysis->fcns, iter, fcn) {
125  item->addr = fcn->addr;
126  item->name = fcn->name;
127  item->fcn = fcn;
128  rz_list_append(r, item);
129  }
130  return r; // core->analysis->fcns;
131 }
132 
134  ut64 target = 0;
135  if (status->fcn) {
136  target = status->fcn->addr;
137  } else {
138  target = status->addr;
139  }
140 
141  RzListIter *iter;
143  int cur = 0;
144  rz_list_foreach (status->mainCol, iter, item) {
145  if (target == item->addr) {
146  status->cur = cur;
147  }
148  cur++;
149  }
150  return;
151 }
152 
153 static int cmpaddr(const void *_a, const void *_b) {
154  const RzCoreVisualViewGraphItem *a = _a, *b = _b;
155  return a->addr - b->addr;
156 }
157 
158 static int cmpname(const void *_a, const void *_b) {
159  const RzCoreVisualViewGraphItem *a = _a, *b = _b;
160  if (!a || !b || !a->name || !b->name) {
161  return 0;
162  }
163  return (int)strcmp(a->name, b->name);
164 }
165 
168  RzListComparator cmp = (status->cur_sort == SORT_ADDRESS) ? cmpaddr : cmpname;
169  list->sorted = false;
171 }
172 
175  status->cur_sort = (status->cur_sort == SORT_ADDRESS) ? SORT_NAME : SORT_ADDRESS;
176  __sort(status, status->mainCol);
177  __sort(status, status->refsCol);
178  __sort(status, status->xrefsCol);
180 }
181 
183  status->addr = status->core->offset;
184  status->fcn = rz_analysis_get_function_at(status->core->analysis, status->addr);
185 
186  status->mainCol = __fcns(status->core);
187  __sort(status, status->mainCol);
189 
190  return;
191 }
192 
194  RzCoreVisualViewGraphItem *item = rz_list_get_n(status->mainCol, status->cur);
195  if (!item) {
196  rz_list_free(status->mainCol);
198  return;
199  }
200 
201  status->addr = item->addr;
202  status->fcn = item->fcn;
203 
204  // Update xrefs and refs columns based on selected element in fcns column
205  if (status->fcn && status->fcn->addr) {
206  status->xrefsCol = __xrefs(status->core, status->fcn->addr);
207  status->refsCol = __refs(status->core, status->fcn->addr);
208  } else {
209  status->xrefsCol = __xrefs(status->core, status->addr);
210  status->refsCol = rz_list_newf(free);
211  }
212  __sort(status, status->xrefsCol);
213  __sort(status, status->refsCol);
214 }
215 
217  int h, w = rz_cons_get_size(&h);
218  const int colw = w / 4;
219  const int colh = h / 2;
220  const int colx = w / 3;
221  rz_cons_clear00();
222 
223  char *xrefsColstr = rz_str_widget_list(core, status->xrefsCol, colh, 0, print_item);
224  char *mainColstr = rz_str_widget_list(core, status->mainCol, colh, status->cur, print_item);
225  char *refsColstr = rz_str_widget_list(core, status->refsCol, colh, 0, print_item);
226 
227  /* if (rz_list_empty (status->xrefsCol) && rz_list_empty (status->refsCol)) { */
228  /* // We've found ourselves in a bad state, reset the view */
229  /* rz_list_free (status->mainCol); */
230  /* __reset_status (status); */
231  /* } */
232 
233  char *title = rz_str_newf("[rz-visual-browser] addr=0x%08" PFMT64x " faddr=0x%08" PFMT64x "", status->addr, status->fcn ? status->fcn->addr : 0);
234  if (title) {
235  rz_cons_strcat_at(title, 0, 0, w - 1, 2);
236  free(title);
237  }
238  rz_cons_strcat_at(xrefsColstr, 0, 2, colw, colh);
239  rz_cons_strcat_at(mainColstr, colx, 2, colw * 2, colh);
240  rz_cons_strcat_at(refsColstr, colx * 2, 2, colw, colh);
241 
242  char *output = rz_core_cmd_strf(core, "pd %d @e:asm.flags=0@ 0x%08" PFMT64x "; pds 256 @ 0x%08" PFMT64x "\n",
243  32, status->addr, status->addr);
244  int disy = colh + 2;
245  rz_cons_strcat_at(output, 10, disy, w, h - disy);
246  free(output);
247  rz_cons_flush();
248 
249  free(xrefsColstr);
250  free(mainColstr);
251  free(refsColstr);
252  return 0;
253 }
254 
257  status.core = core;
258  status.cur_sort = SORT_NAME;
262  if (fcn) {
263  status.addr = fcn->addr;
264  status.fcn = fcn;
265  }
266  while (true) {
268  int ch = rz_cons_readchar();
269  if (ch == -1 || ch == 4) {
270  return true;
271  }
272  ch = rz_cons_arrow_to_hjkl(ch); // get ESC+char, return 'hjkl' char
273  switch (ch) {
274  case 'h':
275  if (!rz_list_empty(status.xrefsCol)) {
276  status.cur = 0;
277  rz_list_free(status.mainCol);
278  rz_list_free(status.refsCol);
279  status.mainCol = status.xrefsCol;
280 
282  }
283  break;
284  case 'l':
285  if (!rz_list_empty(status.refsCol)) {
286  status.cur = 0;
287  rz_list_free(status.mainCol);
288  rz_list_free(status.xrefsCol);
289  status.mainCol = status.refsCol;
290 
292  }
293  break;
294  case 'J': {
295  status.cur += 10;
296  int length = rz_list_length(status.mainCol);
297  if (status.cur >= length) {
298  status.cur = length - 1;
299  }
300  rz_list_free(status.xrefsCol);
301  rz_list_free(status.refsCol);
303  } break;
304  case 'K':
305  if (status.cur > 10) {
306  status.cur -= 10;
307  } else {
308  status.cur = 0;
309  }
310  rz_list_free(status.xrefsCol);
311  rz_list_free(status.refsCol);
313  break;
314  case '.':
315  // reset view and seek status->cur to current function
316  rz_list_free(status.mainCol);
318  break;
319  case 9:
320  case ' ':
321  case '\r':
322  case '\n': {
324  rz_core_seek(core, item->addr, true);
325  }
326  return true;
327  break;
328  case '_':
330  rz_list_free(status.mainCol);
331  rz_list_free(status.xrefsCol);
332  rz_list_free(status.refsCol);
335  break;
336  case 'r':
337  rz_list_free(status.mainCol);
338  rz_list_free(status.xrefsCol);
339  rz_list_free(status.refsCol);
342  break;
343  case 'j': {
344  status.cur++;
345  int length = rz_list_length(status.mainCol);
346  if (status.cur >= length) {
347  status.cur = length - 1;
348  }
349  rz_list_free(status.xrefsCol);
350  rz_list_free(status.refsCol);
352  } break;
353  case 'k':
354  if (status.cur > 0) {
355  status.cur--;
356  } else {
357  status.cur = 0;
358  }
359  rz_list_free(status.xrefsCol);
360  rz_list_free(status.refsCol);
362  break;
363  case '?':
364  rz_cons_clear00();
366  "vbg: Visual Browser (Code) Graph:\n\n"
367  " jkJK - scroll up/down\n"
368  " hl - move to the left/right panel\n"
369  " q - quit this visual mode\n"
370  " _ - enter the hud\n"
371  " . - go back to the initial function list view\n"
372  " : - enter command\n");
373  rz_cons_flush();
375  break;
376  case '/': {
377  char cmd[1024];
378  rz_cons_show_cursor(true);
379  rz_cons_set_raw(0);
380  cmd[0] = '\0';
381  rz_line_set_prompt(":> ");
382  if (rz_cons_fgets(cmd, sizeof(cmd), 0, NULL) < 0) {
383  cmd[0] = '\0';
384  }
385  rz_config_set(core->config, "scr.highlight", cmd);
386  rz_cons_set_raw(1);
387  rz_cons_show_cursor(false);
388  rz_cons_clear();
389  } break;
390  case 'q':
391  return false;
392  case ':': // TODO: move this into a separate helper function
393  {
394  char cmd[1024];
395  rz_cons_show_cursor(true);
396  rz_cons_set_raw(0);
397  cmd[0] = '\0';
398  rz_line_set_prompt(":> ");
399  if (rz_cons_fgets(cmd, sizeof(cmd), 0, NULL) < 0) {
400  cmd[0] = '\0';
401  }
402  rz_core_cmd0(core, cmd);
403  rz_cons_set_raw(1);
404  rz_cons_show_cursor(false);
405  if (cmd[0]) {
407  }
408  rz_cons_clear();
409  } break;
410  case '!': {
412  } break;
413  }
414  }
415  return false;
416 }
RZ_API RzAnalysisFunction * rz_analysis_get_function_at(RzAnalysis *analysis, ut64 addr)
Definition: function.c:184
static RzILOpEffect * cmp(cs_insn *insn, bool is_thumb)
Definition: arm_il32.c:942
static SblHeader sb
Definition: bin_mbn.c:26
RZ_API int rz_core_cmd0(RzCore *core, const char *cmd)
Definition: cmd.c:5428
RZ_API char * rz_core_cmd_strf(RzCore *core, const char *fmt,...)
Definition: cmd.c:5472
static RzCore * _core
Definition: cmd_debug.c:1622
RZ_API RzConfigNode * rz_config_set(RzConfig *cfg, RZ_NONNULL const char *name, const char *value)
Definition: config.c:267
RZ_API void rz_cons_clear00(void)
Definition: cons.c:778
RZ_API void rz_cons_set_raw(bool is_raw)
Definition: cons.c:1617
RZ_API int rz_cons_get_size(int *rows)
Definition: cons.c:1446
RZ_API int rz_cons_printf(const char *format,...)
Definition: cons.c:1202
RZ_API void rz_cons_strcat_at(const char *_str, int x, char y, int w, int h)
Definition: cons.c:260
RZ_API void rz_cons_show_cursor(int cursor)
Definition: cons.c:1581
RZ_API void rz_cons_flush(void)
Definition: cons.c:959
RZ_API void rz_cons_clear(void)
Definition: cons.c:787
#define RZ_API
#define NULL
Definition: cris-opc.c:27
#define r
Definition: crypto_rc6.c:12
#define w
Definition: crypto_rc6.c:13
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
Definition: sflib.h:98
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
Definition: sflib.h:79
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 static semflg const void static shmflg const struct timespec struct timespec static rem const char static group const void length
Definition: sflib.h:133
RZ_DEPRECATE RZ_API RzAnalysisFunction * rz_analysis_get_fcn_in(RzAnalysis *analysis, ut64 addr, int type)
Definition: fcn.c:1687
RZ_API RzFlagItem * rz_flag_get_at(RzFlag *f, ut64 off, bool closest)
Definition: flag.c:404
void skip(file *in, unsigned n)
Definition: gzappend.c:202
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
RZ_API int rz_cons_arrow_to_hjkl(int ch)
Definition: input.c:78
RZ_API int rz_cons_any_key(const char *msg)
Definition: input.c:393
RZ_API int rz_cons_fgets(char *buf, int len, int argc, const char **argv)
Definition: input.c:339
RZ_API int rz_cons_readchar(void)
Definition: input.c:619
static void list(RzEgg *egg)
Definition: rz-gg.c:52
RZ_API RZ_OWN RzList * rz_list_newf(RzListFree f)
Returns a new initialized RzList pointer and sets the free method.
Definition: list.c:248
RZ_API void rz_list_sort(RZ_NONNULL RzList *list, RZ_NONNULL RzListComparator cmp)
Sorts via merge sort or via insertion sort a list.
Definition: list.c:743
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 ut32 rz_list_length(RZ_NONNULL const RzList *list)
Returns the length of the list.
Definition: list.c:109
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
RZ_API void rz_line_set_prompt(const char *prompt)
Definition: line.c:56
static const char struct stat static buf struct stat static buf static vhangup int status
Definition: sflib.h:145
line
Definition: setup.py:34
@ RZ_ANALYSIS_XREF_TYPE_CALL
Definition: rz_analysis.h:901
#define rz_return_if_fail(expr)
Definition: rz_assert.h:100
int(* RzListComparator)(const void *value, const void *list_data)
Definition: rz_list.h:33
RZ_API char * rz_str_newf(const char *fmt,...) RZ_PRINTF_CHECK(1
RZ_API RZ_OWN char * rz_strbuf_drain(RzStrBuf *sb)
Definition: strbuf.c:342
RZ_API RzStrBuf * rz_strbuf_new(const char *s)
Definition: strbuf.c:8
RZ_API bool rz_strbuf_appendf(RzStrBuf *sb, const char *fmt,...) RZ_PRINTF_CHECK(2
#define RZ_NEW0(x)
Definition: rz_types.h:284
#define PFMT64x
Definition: rz_types.h:393
#define st64
Definition: rz_types_base.h:10
RZ_API bool rz_core_seek(RzCore *core, ut64 addr, bool rb)
Seek to addr.
Definition: seek.c:116
#define b(i)
Definition: sha256.c:42
#define f(i)
Definition: sha256.c:46
#define a(i)
Definition: sha256.c:41
#define h(i)
Definition: sha256.c:48
RzAnalysisFunction * fcn
Definition: vmenus_graph.c:53
RzAnalysisFunction * fcn
Definition: vmenus_graph.c:41
RzAnalysisXRefType type
Definition: rz_analysis.h:909
RzList * fcns
Definition: rz_analysis.h:565
RzAnalysis * analysis
Definition: rz_core.h:322
RzFlag * flags
Definition: rz_core.h:330
RzConfig * config
Definition: rz_core.h:300
RZ_API bool rz_core_visual_hudstuff(RzCore *core)
Definition: vmenus.c:539
static st64 delta
Definition: vmenus.c:2425
static RzList * __xrefs(RzCore *core, ut64 addr)
Definition: vmenus_graph.c:69
static int cmpname(const void *_a, const void *_b)
Definition: vmenus_graph.c:158
static char * print_item(void *_core, void *_item, bool selected)
Definition: vmenus_graph.c:56
static RzList * __refs(RzCore *core, ut64 addr)
Definition: vmenus_graph.c:92
RZ_API int __core_visual_view_graph_update(RzCore *core, RzCoreVisualViewGraph *status)
Definition: vmenus_graph.c:216
RZ_API int rz_core_visual_view_graph(RzCore *core)
Definition: vmenus_graph.c:255
#define SORT_ADDRESS
Definition: vmenus_graph.c:5
static void __toggleSort(RzCoreVisualViewGraph *status)
Definition: vmenus_graph.c:173
static void __reset_status(RzCoreVisualViewGraph *status)
Definition: vmenus_graph.c:182
#define SORT_NAME
Definition: vmenus_graph.c:6
static void __seek_cursor(RzCoreVisualViewGraph *status)
Definition: vmenus_graph.c:133
static void __sort(RzCoreVisualViewGraph *status, RzList *list)
Definition: vmenus_graph.c:166
static int cmpaddr(const void *_a, const void *_b)
Definition: vmenus_graph.c:153
static RzList * __fcns(RzCore *core)
Definition: vmenus_graph.c:119
RZ_API char * rz_str_widget_list(void *user, RzList *list, int rows, int cur, PrintItemCallback cb)
Definition: vmenus_graph.c:9
static void __sync_status_with_cursor(RzCoreVisualViewGraph *status)
Definition: vmenus_graph.c:193
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
RZ_API RzList * rz_analysis_xrefs_get_to(RzAnalysis *analysis, ut64 addr)
Definition: xrefs.c:173
RZ_API RzList * rz_analysis_function_get_xrefs_from(RzAnalysisFunction *fcn)
Definition: xrefs.c:297
static const char * cb[]
Definition: z80_tab.h:176
static int addr
Definition: z80asm.c:58
diff_output_t output
Definition: zipcmp.c:237