Rizin
unix-like reverse engineering framework and cli tools
seek.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2009-2020 pancake <pancake@nopcode.org>
2 // SPDX-FileCopyrightText: 2021 ret2libc <sirmy15@gmail.com>
3 // SPDX-License-Identifier: LGPL-3.0-only
4 
5 #include <rz_core.h>
6 
8  free(item);
9 }
10 
11 static void get_current_seek_state(RzCore *core, RzCoreSeekItem *elem) {
12  elem->offset = core->offset;
13  elem->cursor = core->print->cur_enabled ? rz_print_get_cursor(core->print) : 0;
14  elem->is_current = false;
15 }
16 
17 static void set_current_seek_state(RzCore *core, RzCoreSeekItem *elem) {
18  rz_core_seek(core, elem->offset, true);
19  core->print->cur = elem->cursor;
20 }
21 
22 static void add_seek_history(RzCore *core) {
23  RzVector *vundo = &core->seek_history.undos;
24  RzVector *vredo = &core->seek_history.redos;
25  RzCoreSeekItem *item = &core->seek_history.saved_item;
26  ut64 histsize = rz_config_get_i(core->config, "cfg.seek.histsize");
27  if (!rz_vector_empty(vundo)) {
28  RzCoreSeekItem *last = rz_vector_index_ptr(vundo, rz_vector_len(vundo) - 1);
29  if (item->offset == last->offset && item->cursor == last->cursor) {
30  return;
31  }
32  }
33  if (histsize != 0 && rz_vector_len(vundo) >= histsize) {
34  rz_vector_remove_at(vundo, 0, NULL);
35  }
36  rz_vector_push(vundo, item);
37  rz_vector_clear(vredo);
38 }
39 
40 static bool seek_check_save(RzCore *core, ut64 addr, bool rb, bool save) {
41  if (save) {
42  return rz_core_seek_and_save(core, addr, rb);
43  } else {
44  return rz_core_seek(core, addr, rb);
45  }
46 }
47 
58  if (!rz_config_get_i(core->config, "cfg.seek.silent")) {
60  core->seek_history.saved_set = true;
61  return true;
62  }
63  core->seek_history.saved_set = false;
64  return false;
65 }
66 
67 static bool need_add2history(RzCore *core, ut64 addr) {
68  RzCoreSeekHistory *hist = &core->seek_history;
69  return hist->saved_set && (addr != hist->saved_item.offset || hist->saved_item.cursor != 0);
70 }
71 
72 static bool seek_save(RzCore *core, ut64 addr) {
73  if (need_add2history(core, addr)) {
74  add_seek_history(core);
75  core->seek_history.saved_set = false;
76  return true;
77  }
78  core->seek_history.saved_set = false;
79  return false;
80 }
81 
88  return seek_save(core, core->offset);
89 }
90 
101 RZ_API bool rz_core_seek_and_save(RzCore *core, ut64 addr, bool rb) {
102  if (!core->seek_history.saved_set) {
103  rz_core_seek_mark(core);
104  }
105  seek_save(core, addr);
106  return rz_core_seek(core, addr, rb);
107 }
108 
116 RZ_API bool rz_core_seek(RzCore *core, ut64 addr, bool rb) {
117  core->offset = rz_io_seek(core->io, addr, RZ_IO_SEEK_SET);
118  if (rb) {
119  rz_core_block_read(core);
120  }
121  if (core->binat) {
122  RzBinFile *bf = rz_bin_file_at(core->bin, core->offset);
123  if (bf) {
124  core->bin->cur = bf;
125  rz_bin_select_bfid(core->bin, bf->id);
126  } else {
127  core->bin->cur = NULL;
128  }
129  }
130  return core->offset == addr;
131 }
132 
141 RZ_API bool rz_core_seek_opt(RzCore *core, ut64 addr, bool rb, bool save) {
142  return seek_check_save(core, addr, rb, save);
143 }
144 
153  ut64 newaddr;
154  if (delta > 0 && UT64_ADD_OVFCHK(core->offset, (ut64)(delta))) {
155  newaddr = UT64_MAX;
156  } else if (delta < 0 && core->offset < (ut64)RZ_ABS(delta)) {
157  newaddr = 0;
158  } else {
159  newaddr = core->offset + delta;
160  }
161  return seek_check_save(core, newaddr, true, save);
162 }
163 
171 RZ_API int rz_core_seek_base(RzCore *core, const char *hex, bool save) {
172  ut64 addr = rz_num_tail(core->num, core->offset, hex);
173  return seek_check_save(core, addr, true, save);
174 }
175 
179  bool is_next;
180 };
181 
182 static bool seek_flag_offset(RzFlagItem *fi, void *user) {
183  struct seek_flag_offset_t *u = (struct seek_flag_offset_t *)user;
184  if (u->is_next) {
185  if (fi->offset < *u->next && fi->offset > u->offset) {
186  *u->next = fi->offset;
187  }
188  } else {
189  if (fi->offset > *u->next && fi->offset < u->offset) {
190  *u->next = fi->offset;
191  }
192  }
193  return true;
194 }
195 
203 RZ_API bool rz_core_seek_next(RzCore *core, const char *type, bool save) {
204  RzListIter *iter;
205  ut64 next = UT64_MAX;
206  if (strstr(type, "opc")) {
207  RzAnalysisOp aop;
208  if (rz_analysis_op(core->analysis, &aop, core->offset, core->block, core->blocksize, RZ_ANALYSIS_OP_MASK_BASIC) > 0) {
209  next = core->offset + aop.size;
210  } else {
211  eprintf("Invalid opcode\n");
212  }
213  } else if (strstr(type, "fun")) {
214  RzAnalysisFunction *fcni;
215  rz_list_foreach (core->analysis->fcns, iter, fcni) {
216  if (fcni->addr < next && fcni->addr > core->offset) {
217  next = fcni->addr;
218  }
219  }
220  } else if (strstr(type, "hit")) {
221  const char *pfx = rz_config_get(core->config, "search.prefix");
222  struct seek_flag_offset_t u = { .offset = core->offset, .next = &next, .is_next = true };
223  rz_flag_foreach_prefix(core->flags, pfx, -1, seek_flag_offset, &u);
224  } else { // flags
225  struct seek_flag_offset_t u = { .offset = core->offset, .next = &next, .is_next = true };
227  }
228  if (next == UT64_MAX) {
229  return false;
230  }
231  return seek_check_save(core, next, true, save);
232 }
233 
241 RZ_API bool rz_core_seek_prev(RzCore *core, const char *type, bool save) {
242  RzListIter *iter;
243  ut64 next = 0;
244  if (strstr(type, "opc")) {
245  eprintf("TODO: rz_core_seek_prev (opc)\n");
246  } else if (strstr(type, "fun")) {
247  RzAnalysisFunction *fcni;
248  rz_list_foreach (core->analysis->fcns, iter, fcni) {
249  if (fcni->addr > next && fcni->addr < core->offset) {
250  next = fcni->addr;
251  }
252  }
253  } else if (strstr(type, "hit")) {
254  const char *pfx = rz_config_get(core->config, "search.prefix");
255  struct seek_flag_offset_t u = { .offset = core->offset, .next = &next, .is_next = false };
256  rz_flag_foreach_prefix(core->flags, pfx, -1, seek_flag_offset, &u);
257  } else { // flags
258  struct seek_flag_offset_t u = { .offset = core->offset, .next = &next, .is_next = false };
260  }
261  if (next == 0) {
262  return false;
263  }
264  return seek_check_save(core, next, true, save);
265 }
266 
274 RZ_API bool rz_core_seek_align(RzCore *core, ut64 align, bool save) {
275  if (!align) {
276  return false;
277  }
278  int diff = core->offset % align;
279  return seek_check_save(core, core->offset - diff, true, save);
280 }
281 
291  if (block) {
292  seek_check_save(core, block->addr, false, save);
293  return true;
294  }
295  return false;
296 }
297 
302  if (rz_vector_empty(&core->seek_history.undos)) {
303  return false;
304  }
305  RzCoreSeekItem elem;
306  get_current_seek_state(core, &elem);
307  rz_vector_push(&core->seek_history.redos, &elem);
308  rz_vector_pop(&core->seek_history.undos, &elem);
309  set_current_seek_state(core, &elem);
310  return true;
311 }
312 
317  if (rz_vector_empty(&core->seek_history.redos)) {
318  return false;
319  }
320  RzCoreSeekItem elem;
321  get_current_seek_state(core, &elem);
322  rz_vector_push(&core->seek_history.undos, &elem);
323  rz_vector_pop(&core->seek_history.redos, &elem);
324  set_current_seek_state(core, &elem);
325  return true;
326 }
327 
330  if (!res) {
331  return NULL;
332  }
333  get_current_seek_state(core, res);
334  res->is_current = true;
335  res->idx = 0;
336  return res;
337 }
338 
341  if (!res) {
342  return NULL;
343  }
344  res->offset = item->offset;
345  res->cursor = item->cursor;
346  res->is_current = item->is_current;
347  res->idx = i;
348  return res;
349 }
350 
362  if (idx == 0) {
363  return get_current_item(core);
364  } else if (idx < 0) {
365  RzVector *vundo = &core->seek_history.undos;
366  size_t i = RZ_ABS(idx) - 1;
367  size_t len = rz_vector_len(vundo);
368  if (i >= len) {
369  return NULL;
370  }
371  RzCoreSeekItem *vel = (RzCoreSeekItem *)rz_vector_index_ptr(vundo, len - i - 1);
372  return dup_seek_history_item(vel, idx);
373  } else {
374  RzVector *vredo = &core->seek_history.redos;
375  size_t i = RZ_ABS(idx) - 1;
376  size_t len = rz_vector_len(vredo);
377  if (i >= len) {
378  return NULL;
379  }
380  RzCoreSeekItem *vel = (RzCoreSeekItem *)rz_vector_index_ptr(vredo, len - i - 1);
381  return dup_seek_history_item(vel, idx);
382  }
383 }
384 
393 }
394 
401 }
402 
411 RZ_API RzList /*<RzCoreSeekItem *>*/ *rz_core_seek_list(RzCore *core) {
413  if (!res) {
414  return NULL;
415  }
416 
417  RzCoreSeekItem *it;
418  int i = -rz_vector_len(&core->seek_history.undos);
419  rz_vector_foreach(&core->seek_history.undos, it) {
421  if (!dup) {
422  goto err;
423  }
424  rz_list_append(res, dup);
425  }
426 
427  RzCoreSeekItem *cur = get_current_item(core);
428  if (!cur) {
429  goto err;
430  }
431  rz_list_append(res, cur);
432 
433  i = 1;
436  if (!dup) {
437  goto err;
438  }
439  rz_list_append(res, dup);
440  }
441  return res;
442 
443 err:
444  rz_list_free(res);
445  return NULL;
446 }
447 
448 /* \brief Seek to the \p index instruction in the current basic block
449  *
450  * Allows \p index to be negative, in this case it will count
451  * the instructions from the end of the block
452  * */
453 RZ_IPI bool rz_core_seek_bb_instruction(RzCore *core, int index) {
455  if (!bb) {
456  RZ_LOG_ERROR("Can't find a basic block for 0x%08" PFMT64x "\n", core->offset);
457  return false;
458  }
459  // handle negative indices
460  if (index < 0) {
461  index = bb->ninstr + index;
462  }
463  if (!(index >= 0 && index < bb->ninstr)) {
464  RZ_LOG_ERROR("The current basic block has %d instructions\n", bb->ninstr);
465  return false;
466  }
467  ut64 inst_addr = rz_analysis_block_get_op_addr(bb, index);
468  return rz_core_seek(core, inst_addr, true);
469 }
size_t len
Definition: 6502dis.c:15
#define RZ_IPI
Definition: analysis_wasm.c:11
lzma_index ** i
Definition: index.h:629
static bool err
Definition: armass.c:435
RZ_API RzBinFile * rz_bin_file_at(RzBin *bin, ut64 at)
Definition: bin.c:1160
RZ_API bool rz_bin_select_bfid(RzBin *bin, ut32 bf_id)
Definition: bin.c:833
RZ_API ut64 rz_analysis_block_get_op_addr(RzAnalysisBlock *block, size_t i)
Definition: block.c:1016
RZ_API RzAnalysisBlock * rz_analysis_find_most_relevant_block_in(RzAnalysis *analysis, ut64 off)
Definition: block.c:997
RZ_API int rz_core_block_read(RzCore *core)
Definition: cio.c:243
RZ_API ut64 rz_config_get_i(RzConfig *cfg, RZ_NONNULL const char *name)
Definition: config.c:119
RZ_API RZ_BORROW const char * rz_config_get(RzConfig *cfg, RZ_NONNULL const char *name)
Definition: config.c:75
#define RZ_API
#define NULL
Definition: cris-opc.c:27
RZ_API void rz_flag_foreach_prefix(RzFlag *f, const char *pfx, int pfx_len, RzFlagItemCb cb, void *user)
Definition: flag.c:804
RZ_API void rz_flag_foreach(RzFlag *f, RzFlagItemCb cb, void *user)
Definition: flag.c:800
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
voidpf uLong offset
Definition: ioapi.h:144
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 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
static int save
Definition: main.c:14
static static fork const void static count static fd const char const char static newpath char char char static envp time_t static t const char static mode static whence const char static dir time_t static t unsigned static seconds const char struct utimbuf static buf static inc static sig const char static mode dup
Definition: sflib.h:68
@ RZ_ABS
int type
Definition: mipsasm.c:17
int idx
Definition: setup.py:197
RZ_API int rz_analysis_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, const ut8 *data, int len, RzAnalysisOpMask mask)
Definition: op.c:96
RZ_API int rz_print_get_cursor(RzPrint *p)
Definition: print.c:1571
static const char hex[16]
Definition: print.c:21
#define eprintf(x, y...)
Definition: rlcc.c:7
@ RZ_ANALYSIS_OP_MASK_BASIC
Definition: rz_analysis.h:440
RZ_API ut64 rz_io_seek(RzIO *io, ut64 offset, int whence)
Definition: io.c:632
#define RZ_IO_SEEK_SET
Definition: rz_io.h:15
void(* RzListFree)(void *ptr)
Definition: rz_list.h:11
#define RZ_LOG_ERROR(fmtstr,...)
Definition: rz_log.h:58
RZ_API ut64 rz_num_tail(RzNum *num, ut64 addr, const char *hex)
Definition: unum.c:775
#define RZ_NEW0(x)
Definition: rz_types.h:284
#define PFMT64x
Definition: rz_types.h:393
#define st64
Definition: rz_types_base.h:10
#define UT64_MAX
Definition: rz_types_base.h:86
#define UT64_ADD_OVFCHK(x, y)
RZ_API void rz_vector_pop(RzVector *vec, void *into)
Definition: vector.c:184
static void * rz_vector_index_ptr(RzVector *vec, size_t index)
Definition: rz_vector.h:88
RZ_API void rz_vector_remove_at(RzVector *vec, size_t index, void *into)
Definition: vector.c:127
RZ_API void * rz_vector_push(RzVector *vec, void *x)
Definition: vector.c:197
#define rz_vector_foreach(vec, it)
Definition: rz_vector.h:169
RZ_API void rz_vector_fini(RzVector *vec)
Definition: vector.c:61
RZ_API void rz_vector_clear(RzVector *vec)
Definition: vector.c:68
#define rz_vector_foreach_prev(vec, it)
Definition: rz_vector.h:173
static size_t rz_vector_len(const RzVector *vec)
Definition: rz_vector.h:82
RZ_API void rz_vector_init(RzVector *vec, size_t elem_size, RzVectorFree free, void *free_user)
Definition: vector.c:33
static bool rz_vector_empty(const RzVector *vec)
Definition: rz_vector.h:74
RZ_API bool rz_core_seek_redo(RzCore *core)
Definition: seek.c:316
static bool seek_save(RzCore *core, ut64 addr)
Definition: seek.c:72
RZ_API RzList * rz_core_seek_list(RzCore *core)
Return the seek history.
Definition: seek.c:411
RZ_API RzCoreSeekItem * rz_core_seek_peek(RzCore *core, int idx)
Return a element in the undo/redo list.
Definition: seek.c:361
static void set_current_seek_state(RzCore *core, RzCoreSeekItem *elem)
Definition: seek.c:17
RZ_API bool rz_core_seek_delta(RzCore *core, st64 delta, bool save)
Seek relative to current offset and optionally save the current offset in seek history.
Definition: seek.c:152
static RzCoreSeekItem * dup_seek_history_item(RzCoreSeekItem *item, int i)
Definition: seek.c:339
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 .
Definition: seek.c:101
RZ_API bool rz_core_seek_mark(RzCore *core)
Mark current state (offset+cursor) as the next state to save in history.
Definition: seek.c:57
static bool need_add2history(RzCore *core, ut64 addr)
Definition: seek.c:67
RZ_API bool rz_core_seek_next(RzCore *core, const char *type, bool save)
Seek to the next type of item from current offset.
Definition: seek.c:203
static void get_current_seek_state(RzCore *core, RzCoreSeekItem *elem)
Definition: seek.c:11
RZ_API int rz_core_seek_base(RzCore *core, const char *hex, bool save)
Seek to a new address composed of current offset with last hex digits replaced with those of hex.
Definition: seek.c:171
RZ_API void rz_core_seek_reset(RzCore *core)
Definition: seek.c:388
RZ_IPI bool rz_core_seek_bb_instruction(RzCore *core, int index)
Definition: seek.c:453
RZ_API bool rz_core_seek_prev(RzCore *core, const char *type, bool save)
Seek to the previous type of item from current offset.
Definition: seek.c:241
static bool seek_check_save(RzCore *core, ut64 addr, bool rb, bool save)
Definition: seek.c:40
RZ_API bool rz_core_seek_undo(RzCore *core)
Definition: seek.c:301
RZ_API void rz_core_seek_free(RzCore *core)
Definition: seek.c:398
RZ_API bool rz_core_seek_opt(RzCore *core, ut64 addr, bool rb, bool save)
Seek to addr and optionally save the current offset in seek history.
Definition: seek.c:141
RZ_API void rz_core_seek_item_free(RzCoreSeekItem *item)
Definition: seek.c:7
RZ_API bool rz_core_seek_align(RzCore *core, ut64 align, bool save)
Seek to current offset aligned to align.
Definition: seek.c:274
RZ_API bool rz_core_seek_save(RzCore *core)
Save last marked position, if any, in the seek history.
Definition: seek.c:87
RZ_API bool rz_core_seek_analysis_bb(RzCore *core, ut64 addr, bool save)
Seek to basic block that contains address addr.
Definition: seek.c:289
static void add_seek_history(RzCore *core)
Definition: seek.c:22
RZ_API bool rz_core_seek(RzCore *core, ut64 addr, bool rb)
Seek to addr.
Definition: seek.c:116
static RzCoreSeekItem * get_current_item(RzCore *core)
Definition: seek.c:328
static bool seek_flag_offset(RzFlagItem *fi, void *user)
Definition: seek.c:182
RzList * fcns
Definition: rz_analysis.h:565
XX curplugin == o->plugin.
Definition: rz_bin.h:298
RZ_DEPRECATE RzBinFile * cur
never use this in new code! Get a file from the binfiles list or track it yourself.
Definition: rz_bin.h:330
RzCoreSeekItem saved_item
Position to save in history.
Definition: rz_core.h:294
RzVector undos
Stack of RzCoreSeekItems, allowing to "go back in time".
Definition: rz_core.h:291
RzVector redos
Stack of RzCoreSeekItems, allowing to re-do an action that was undone.
Definition: rz_core.h:292
bool saved_set
When true, the saved field is set.
Definition: rz_core.h:293
int idx
Position of the item relative to the current seek item (0 current seek, < 0 for undos,...
Definition: rz_core.h:148
ut64 offset
Value of core->offset at the given time in history.
Definition: rz_core.h:145
bool is_current
True if this is the current seek value.
Definition: rz_core.h:147
int cursor
Position of the cursor at the given time in history.
Definition: rz_core.h:146
RzBin * bin
Definition: rz_core.h:298
ut64 offset
Definition: rz_core.h:301
RzAnalysis * analysis
Definition: rz_core.h:322
RzIO * io
Definition: rz_core.h:313
RzNum * num
Definition: rz_core.h:316
bool binat
Definition: rz_core.h:374
ut8 * block
Definition: rz_core.h:305
RzFlag * flags
Definition: rz_core.h:330
RzCoreSeekHistory seek_history
Definition: rz_core.h:388
RzPrint * print
Definition: rz_core.h:327
ut32 blocksize
Definition: rz_core.h:303
RzConfig * config
Definition: rz_core.h:300
ut64 offset
Definition: rz_flag.h:38
bool cur_enabled
Definition: rz_print.h:130
ut64 * next
Definition: seek.c:178
static st64 delta
Definition: vmenus.c:2425
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
static int addr
Definition: z80asm.c:58