Rizin
unix-like reverse engineering framework and cli tools
fcn.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2010-2021 nibble <nibble.ds@gmail.com>
2 // SPDX-FileCopyrightText: 2010-2021 alvaro <alvaro.felipe91@gmail.com>
3 // SPDX-FileCopyrightText: 2010-2021 pancake <pancake@nopcode.org>
4 // SPDX-License-Identifier: LGPL-3.0-only
5 
6 #include <rz_analysis.h>
7 #include <rz_parse.h>
8 #include <rz_util.h>
9 #include <rz_list.h>
10 
11 #define READ_AHEAD 1
12 #define SDB_KEY_BB "bb.0x%" PFMT64x ".0x%" PFMT64x
13 // XXX must be configurable by the user
14 #define JMPTBL_LEA_SEARCH_SZ 64
15 #define BB_ALIGN 0x10
16 #define MAX_SCAN_SIZE 0x7ffffff
17 
18 // 16 KB is the maximum size for a basic block
19 #define MAX_FLG_NAME_SIZE 64
20 
21 // 64KB max size
22 // 256KB max function size
23 #define MAX_FCN_SIZE (1024 * 256)
24 
25 #define DB a->sdb_fcns
26 #define EXISTS(x, ...) snprintf(key, sizeof(key) - 1, x, ##__VA_ARGS__), sdb_exists(DB, key)
27 #define SETKEY(x, ...) snprintf(key, sizeof(key) - 1, x, ##__VA_ARGS__);
28 
29 typedef struct fcn_tree_iter_t {
30  int len;
34 
36  switch (type) {
37  case RZ_ANALYSIS_FCN_TYPE_NULL: return "null";
38  case RZ_ANALYSIS_FCN_TYPE_FCN: return "fcn";
39  case RZ_ANALYSIS_FCN_TYPE_LOC: return "loc";
40  case RZ_ANALYSIS_FCN_TYPE_SYM: return "sym";
41  case RZ_ANALYSIS_FCN_TYPE_IMP: return "imp";
42  case RZ_ANALYSIS_FCN_TYPE_INT: return "int"; // interrupt
43  case RZ_ANALYSIS_FCN_TYPE_ROOT: return "root";
44  }
45  return "unk";
46 }
47 
48 #if READ_AHEAD
50 
51 // TODO: move into io :?
52 static int read_ahead(RzAnalysis *analysis, ut64 addr, ut8 *buf, int len) {
53  static ut8 cache[1024];
54  const int cache_len = sizeof(cache);
55 
56  if (len < 1) {
57  return 0;
58  }
59  if (len > cache_len) {
60  int a = analysis->iob.read_at(analysis->iob.io, addr, buf, len); // double read
61  memcpy(cache, buf, cache_len);
62  cache_addr = addr;
63  return a;
64  }
65 
66  ut64 addr_end = UT64_ADD_OVFCHK(addr, len) ? UT64_MAX : addr + len;
67  ut64 cache_addr_end = UT64_ADD_OVFCHK(cache_addr, cache_len) ? UT64_MAX : cache_addr + cache_len;
68  bool isCached = ((addr != UT64_MAX) && (addr >= cache_addr) && (addr_end < cache_addr_end));
69  if (isCached) {
70  memcpy(buf, cache + (addr - cache_addr), len);
71  } else {
72  analysis->iob.read_at(analysis->iob.io, addr, cache, sizeof(cache));
73  memcpy(buf, cache, len);
74  cache_addr = addr;
75  }
76  return len;
77 }
78 #else
79 static int read_ahead(RzAnalysis *analysis, ut64 addr, ut8 *buf, int len) {
80  return analysis->iob.read_at(analysis->iob.io, addr, buf, len);
81 }
82 #endif
83 
85 #if READ_AHEAD
87 #endif
88 }
89 
91  RzAnalysis *analysis = fcn->analysis;
92  RzAnalysisBlock *bb;
93  RzListIter *iter, *iter2;
94 
95  rz_return_val_if_fail(fcn, false);
96 
97  if (newsize < 1) {
98  return false;
99  }
100 
101  // XXX this is something we should probably do for all the archs
102  bool is_arm = analysis->cur->arch && !strncmp(analysis->cur->arch, "arm", 3);
103  if (is_arm) {
104  return true;
105  }
106 
107  ut64 eof = fcn->addr + newsize;
108  rz_list_foreach_safe (fcn->bbs, iter, iter2, bb) {
109  if (bb->addr >= eof) {
111  continue;
112  }
113  if (bb->addr + bb->size >= eof) {
114  rz_analysis_block_set_size(bb, eof - bb->addr);
116  }
117  if (bb->jump != UT64_MAX && bb->jump >= eof) {
118  bb->jump = UT64_MAX;
119  }
120  if (bb->fail != UT64_MAX && bb->fail >= eof) {
121  bb->fail = UT64_MAX;
122  }
123  }
124  return true;
125 }
126 
127 // Create a new 0-sized basic block inside the function
129  RzAnalysisBlock *bb = rz_analysis_create_block(analysis, addr, 0);
130  if (!bb) {
131  return NULL;
132  }
134  bb->stackptr = fcn->stack;
135  bb->parent_stackptr = fcn->stack;
136  return bb;
137 }
138 
139 #define gotoBeach(x) \
140  ret = x; \
141  goto beach;
142 
143 static bool isInvalidMemory(RzAnalysis *analysis, const ut8 *buf, int len) {
144  if (analysis->opt.nonull > 0) {
145  int i;
146  const int count = RZ_MIN(len, analysis->opt.nonull);
147  for (i = 0; i < count; i++) {
148  if (buf[i]) {
149  break;
150  }
151  }
152  if (i == count) {
153  return true;
154  }
155  }
156  return !memcmp(buf, "\xff\xff\xff\xff", RZ_MIN(len, 4));
157 }
158 
160  rz_return_val_if_fail(analysis && op && analysis->flb.get_at, false);
161 
162  RzFlagItem *fi = analysis->flb.get_at(analysis->flb.f, op->addr + op->size, false);
163  return (fi && fi->name && (strstr(fi->name, "imp.") || strstr(fi->name, "sym.") || strstr(fi->name, "entry") || strstr(fi->name, "main")));
164 }
165 
166 static bool is_delta_pointer_table(RzAnalysis *analysis, ut64 addr, ut64 lea_ptr, ut64 *jmptbl_addr, ut64 *casetbl_addr, RzAnalysisOp *jmp_aop) {
167  int i;
168  ut64 dst;
169  st32 jmptbl[64] = { 0 };
170  /* check if current instruction is followed by an ujmp */
172  RzAnalysisOp *aop = jmp_aop;
173  RzAnalysisOp omov_aop = { 0 };
174  RzAnalysisOp mov_aop = { 0 };
175  RzAnalysisOp add_aop = { 0 };
176  RzRegItem *reg_src = NULL, *o_reg_dst = NULL;
177  RzAnalysisValue cur_scr, cur_dst = { 0 };
178  read_ahead(analysis, addr, (ut8 *)buf, sizeof(buf));
179  bool isValid = false;
180  for (i = 0; i + 8 < JMPTBL_LEA_SEARCH_SZ; i++) {
181  ut64 at = addr + i;
182  int left = JMPTBL_LEA_SEARCH_SZ - i;
184  if (len < 1) {
185  len = 1;
186  }
188  isValid = true;
189  break;
190  } else if (aop->type == RZ_ANALYSIS_OP_TYPE_JMP || aop->type == RZ_ANALYSIS_OP_TYPE_CJMP) {
191  break;
192  }
193  if (aop->type == RZ_ANALYSIS_OP_TYPE_MOV) {
194  omov_aop = mov_aop;
195  mov_aop = *aop;
196  o_reg_dst = cur_dst.reg;
197  if (mov_aop.dst) {
198  cur_dst = *mov_aop.dst;
199  }
200  if (mov_aop.src[0]) {
201  cur_scr = *mov_aop.src[0];
202  reg_src = cur_scr.regdelta;
203  }
204  }
205  if (aop->type == RZ_ANALYSIS_OP_TYPE_ADD) {
206  add_aop = *aop;
207  }
208  rz_analysis_op_fini(aop);
209  i += len - 1;
210  }
211  if (!isValid) {
212  return false;
213  }
214 
215  // check if we have a msvc 19xx style jump table using rva table entries
216  // lea reg1, [base_addr]
217  // mov reg2, dword [reg1 + tbl_off*4 + tbl_loc_off]
218  // add reg2, reg1
219  // jmp reg2
220  if (mov_aop.type && add_aop.type && mov_aop.addr < add_aop.addr && add_aop.addr < jmp_aop->addr && mov_aop.disp && mov_aop.disp != UT64_MAX) {
221  // disp in this case should be tbl_loc_off
222  *jmptbl_addr += mov_aop.disp;
223  if (o_reg_dst && reg_src && o_reg_dst->offset == reg_src->offset && omov_aop.disp != UT64_MAX) {
224  // Special case for indirection
225  // lea reg1, [base_addr]
226  // movzx reg2, byte [reg1 + tbl_off + casetbl_loc_off]
227  // mov reg3, dword [reg1 + reg2*4 + tbl_loc_off]
228  // add reg3, reg1
229  // jmp reg3
230  *casetbl_addr += omov_aop.disp;
231  }
232  }
233 #if 0
234  // required for the last jmptbl.. but seems to work without it and breaks other tests
235  if (mov_aop.type && mov_aop.ptr) {
236  *jmptbl_addr += mov_aop.ptr;
237  // absjmptbl
238  lea_ptr = mov_aop.ptr;
239  }
240 #endif
241  /* check if jump table contains valid deltas */
242  read_ahead(analysis, *jmptbl_addr, (ut8 *)&jmptbl, 64);
243  for (i = 0; i < 3; i++) {
244  dst = lea_ptr + (st32)rz_read_le32(jmptbl);
245  if (!analysis->iob.is_valid_offset(analysis->iob.io, dst, 0)) {
246  RZ_LOG_VERBOSE("Jump table target is not valid: 0x%" PFMT64x "\n", dst);
247  return false;
248  }
249  if (!UT64_ADD_OVFCHK(jmp_aop->addr, analysis->opt.jmptbl_maxoffset) &&
250  dst > jmp_aop->addr + analysis->opt.jmptbl_maxoffset) {
251  RZ_LOG_VERBOSE("Jump table target is too far away: 0x%" PFMT64x "\n", dst);
252  return false;
253  }
254  if (analysis->opt.jmpabove && !UT64_SUB_OVFCHK(jmp_aop->addr, analysis->opt.jmptbl_maxoffset) &&
255  dst < jmp_aop->addr - analysis->opt.jmptbl_maxoffset) {
256  RZ_LOG_VERBOSE("Jump table target is too far away: 0x%" PFMT64x "\n", dst);
257  return false;
258  }
259  }
260  return true;
261 }
262 
263 static ut64 try_get_cmpval_from_parents(RzAnalysis *analysis, RzAnalysisFunction *fcn, RzAnalysisBlock *my_bb, const char *cmp_reg) {
264  rz_return_val_if_fail(fcn && fcn->bbs && cmp_reg, UT64_MAX);
265  RzListIter *iter;
266  RzAnalysisBlock *tmp_bb;
267  rz_list_foreach (fcn->bbs, iter, tmp_bb) {
268  if (tmp_bb->jump == my_bb->addr || tmp_bb->fail == my_bb->addr) {
269  if (tmp_bb->cmpreg == cmp_reg) {
270  if (tmp_bb->cond) {
271  if (tmp_bb->cond->type == RZ_TYPE_COND_HI || tmp_bb->cond->type == RZ_TYPE_COND_GT) {
272  return tmp_bb->cmpval + 1;
273  }
274  }
275  return tmp_bb->cmpval;
276  }
277  }
278  }
279  return UT64_MAX;
280 }
281 
283  rz_return_val_if_fail(src && dst, false);
284  return src->reg && dst->reg && src->reg->name && dst->reg->name;
285 }
286 
287 // 0 if not skipped; 1 if skipped; 2 if skipped before
289  char *tmp_buf, int oplen, int un_idx, int *idx) {
290  // this step is required in order to prevent infinite recursion in some cases
291  if ((addr + un_idx - oplen) == fcn->addr) {
292  // use addr instead of op->addr to mark repeat
293  if (!analysis->flb.exist_at(analysis->flb.f, "skip", 4, addr)) {
294  snprintf(tmp_buf + 5, MAX_FLG_NAME_SIZE - 6, "%" PFMT64u, addr);
295  analysis->flb.set(analysis->flb.f, tmp_buf, addr, oplen);
296  fcn->addr += oplen;
297  rz_analysis_block_relocate(bb, bb->addr + oplen, bb->size - oplen);
298  *idx = un_idx;
299  return 1;
300  }
301  return 2;
302  }
303  return 0;
304 }
305 
306 static bool purity_checked(HtUP *ht, RzAnalysisFunction *fcn) {
307  bool checked;
308  ht_up_find(ht, fcn->addr, &checked);
309  return checked;
310 }
311 
312 /*
313  * Checks whether a given function is pure and sets its 'is_pure' field.
314  * This function marks fcn 'not pure' if fcn, or any function called by fcn, accesses data
315  * from outside, even if it only READS it.
316  * Probably worth changing it in the future, so that it marks fcn 'impure' only when it
317  * (or any function called by fcn) MODIFIES external data.
318  */
319 static void check_purity(HtUP *ht, RzAnalysisFunction *fcn) {
320  RzListIter *iter;
322  RzAnalysisXRef *xref;
323  ht_up_insert(ht, fcn->addr, NULL);
324  fcn->is_pure = true;
325  rz_list_foreach (xrefs, iter, xref) {
327  RzAnalysisFunction *called_fcn = rz_analysis_get_fcn_in(fcn->analysis, xref->to, 0);
328  if (!called_fcn) {
329  continue;
330  }
331  if (!purity_checked(ht, called_fcn)) {
332  check_purity(ht, called_fcn);
333  }
334  if (!called_fcn->is_pure) {
335  fcn->is_pure = false;
336  break;
337  }
338  }
339  if (xref->type == RZ_ANALYSIS_XREF_TYPE_DATA) {
340  fcn->is_pure = false;
341  break;
342  }
343  }
344  rz_list_free(xrefs);
345 }
346 
347 typedef struct {
350  char *reg;
351 } leaddr_pair;
352 
353 static void free_leaddr_pair(void *pair) {
354  leaddr_pair *_pair = pair;
355  free(_pair->reg);
356  free(_pair);
357 }
358 
359 static RzAnalysisBlock *bbget(RzAnalysis *analysis, ut64 addr, bool jumpmid) {
360  RzList *intersecting = rz_analysis_get_blocks_in(analysis, addr);
361  RzListIter *iter;
362  RzAnalysisBlock *bb;
363 
364  RzAnalysisBlock *ret = NULL;
365  rz_list_foreach (intersecting, iter, bb) {
366  ut64 eaddr = bb->addr + bb->size;
367  if (((bb->addr >= eaddr && addr == bb->addr) ||
368  rz_analysis_block_contains(bb, addr)) &&
369  (!jumpmid || rz_analysis_block_op_starts_at(bb, addr))) {
370  if (analysis->opt.delay) {
371  ut8 *buf = malloc(bb->size);
372  if (analysis->iob.read_at(analysis->iob.io, bb->addr, buf, bb->size)) {
373  const int last_instr_idx = bb->ninstr - 1;
374  bool in_delay_slot = false;
375  for (int i = last_instr_idx; i >= 0; i--) {
377  const ut64 at = bb->addr + off;
378  if (addr <= at || off >= bb->size) {
379  continue;
380  }
382  int size = rz_analysis_op(analysis, &op, at, buf + off, bb->size - off, RZ_ANALYSIS_OP_MASK_BASIC);
383  if (size > 0 && op.delay) {
384  if (op.delay >= last_instr_idx - i) {
385  in_delay_slot = true;
386  }
388  break;
389  }
391  }
392  if (in_delay_slot) {
393  free(buf);
394  continue;
395  }
396  }
397  free(buf);
398  }
399  ret = bb;
400  break;
401  }
402  }
403  rz_list_free(intersecting);
404  return ret;
405 }
406 
407 typedef struct {
409  const int stack_diff;
411 
413  BlockTakeoverCtx *ctx = user;
414  RzAnalysisFunction *our_fcn = ctx->fcn;
415  rz_analysis_block_ref(block);
416  while (!rz_list_empty(block->fcns)) {
417  RzAnalysisFunction *other_fcn = rz_list_first(block->fcns);
418  if (other_fcn->addr == block->addr) {
419  return false;
420  }
421  // Steal vars from this block
422  size_t i;
423  for (i = 0; i < block->ninstr; i++) {
424  const ut64 addr = rz_analysis_block_get_op_addr(block, i);
425  RzPVector *vars_used = rz_analysis_function_get_vars_used_at(other_fcn, addr);
426  if (!vars_used) {
427  continue;
428  }
429  // vars_used will get modified if rz_analysis_var_remove_access_at gets called
430  RzPVector *cloned_vars_used = (RzPVector *)rz_vector_clone((RzVector *)vars_used);
431  void **it;
432  rz_pvector_foreach (cloned_vars_used, it) {
433  RzAnalysisVar *other_var = *it;
434  int actual_delta = 0;
435  switch (other_var->kind) {
437  actual_delta = other_var->delta + ctx->stack_diff;
438  break;
440  actual_delta = other_var->delta + (other_fcn->bp_off - our_fcn->bp_off);
441  break;
443  actual_delta = other_var->delta;
444  break;
445  }
446  RzAnalysisVar *our_var = rz_analysis_function_get_var(our_fcn, other_var->kind, actual_delta);
447  if (!our_var) {
448  our_var = rz_analysis_function_set_var(our_fcn, actual_delta, other_var->kind, other_var->type, 0, other_var->isarg, other_var->name);
449  }
450  if (our_var) {
452  rz_analysis_var_set_access(our_var, acc->reg, addr, acc->type, acc->stackptr);
453  }
455  if (rz_vector_empty(&other_var->accesses)) {
456  rz_analysis_function_delete_var(other_fcn, other_var);
457  }
458  }
459  rz_pvector_free(cloned_vars_used);
460  }
461 
462  // TODO: remove block->ninstr from other_fcn considering delay slots
463  rz_analysis_function_remove_block(other_fcn, block);
464  }
465  block->stackptr -= ctx->stack_diff;
466  block->parent_stackptr -= ctx->stack_diff;
467  rz_analysis_function_add_block(our_fcn, block);
468  // TODO: add block->ninstr from our_fcn considering delay slots
470  return true;
471 }
472 
473 // Remove block and all of its recursive successors from all its functions and add them only to fcn
475  BlockTakeoverCtx ctx = { fcn, start_block->parent_stackptr - fcn->stack };
477 }
478 
479 static const char *retpoline_reg(RzAnalysis *analysis, ut64 addr) {
480  RzFlagItem *flag = analysis->flag_get(analysis->flb.f, addr);
481  if (flag) {
482  const char *token = "x86_indirect_thunk_";
483  const char *thunk = strstr(flag->name, token);
484  if (thunk) {
485  return thunk + strlen(token);
486  }
487  }
488 #if 0
489 // TODO: implement following code analysis check for stripped binaries:
490 // 1) op(addr).type == CALL
491 // 2) call_dest = op(addr).addr
492 // 3) op(call_dest).type == STORE
493 // 4) op(call_dest + op(call_dest).size).type == RET
494 [0x00000a65]> pid 6
495 0x00000a65 sym.__x86_indirect_thunk_rax:
496 0x00000a65 .------- e807000000 call 0xa71
497 0x00000a6a | f390 pause
498 0x00000a6c | 0faee8 lfence
499 0x00000a6f | ebf9 jmp 0xa6a
500 0x00000a71 `----> 48890424 mov qword [rsp], rax
501 0x00000a75 c3 ret
502 #endif
503  return NULL;
504 }
505 
506 static void analyze_retpoline(RzAnalysis *analysis, RzAnalysisOp *op) {
507  if (analysis->opt.retpoline) {
508  const char *rr = retpoline_reg(analysis, op->jump);
509  if (rr) {
511  op->reg = rr;
512  }
513  }
514 }
515 
516 static inline bool op_is_set_bp(RzAnalysisOp *op, const char *bp_reg, const char *sp_reg) {
517  bool has_dst_reg = op->dst && op->dst->reg && op->dst->reg->name;
518  bool has_src_reg = op->src[0] && op->src[0]->reg && op->src[0]->reg->name;
519  if (has_dst_reg && has_src_reg) {
520  return !strcmp(bp_reg, op->dst->reg->name) && !strcmp(sp_reg, op->src[0]->reg->name);
521  }
522  return false;
523 }
524 
525 static inline bool does_arch_destroys_dst(const char *arch) {
526  return arch && (!strncmp(arch, "arm", 3) || !strcmp(arch, "riscv") || !strcmp(arch, "ppc"));
527 }
528 
529 static int analyze_function_locally(RzAnalysis *analysis, RzAnalysisFunction *fcn, ut64 address) {
531  RzVector tasks;
532  rz_vector_init(&tasks, sizeof(RzAnalysisTaskItem), NULL, NULL);
533  RzAnalysisTaskItem item = { fcn, NULL, fcn->stack, address };
534  rz_vector_push(&tasks, &item);
535  int saved_stack = fcn->stack; // TODO: DO NOT use fcn->stack to keep track of stack during analysis
536  int ret = rz_analysis_run_tasks(&tasks);
537  rz_vector_fini(&tasks);
538  fcn->stack = saved_stack;
539  return ret;
540 }
541 
542 static inline void set_bb_branches(RZ_OUT RzAnalysisBlock *bb, const ut64 jump, const ut64 fail) {
543  bb->jump = jump;
544  bb->fail = fail;
545 }
546 
561  RzAnalysis *analysis = item->fcn->analysis;
562  RzAnalysisFunction *fcn = item->fcn;
563  fcn->stack = item->stack;
564  ut64 addr = item->start_address;
565  ut64 len = analysis->opt.bb_max_size;
566  const int continue_after_jump = analysis->opt.afterjmp;
567  const int addrbytes = analysis->iob.io ? analysis->iob.io->addrbytes : 1;
568  char *last_reg_mov_lea_name = NULL;
569  char *movbasereg = NULL;
570  RzAnalysisBlock *bb = item->block;
571  RzAnalysisBlock *bbg = NULL;
572  RzAnalysisBBEndCause ret = RZ_ANALYSIS_RET_END, skip_ret = 0;
573  bool overlapped = false;
574  RzAnalysisOp op = { 0 };
575  int oplen, idx = 0;
576  int lea_cnt = 0;
577  static ut64 cmpval = UT64_MAX; // inherited across functions, otherwise it breaks :?
578  bool varset = false;
579  struct {
580  int cnt;
581  int idx;
582  int after;
583  int pending;
584  int adjust;
585  int un_idx; // delay.un_idx
586  } delay = {
587  0
588  };
589  char tmp_buf[MAX_FLG_NAME_SIZE + 5] = "skip";
591  bool is_arm = false, is_x86 = false, is_amd64 = false, is_dalvik = false, is_hexagon = false;
592  if (analysis->cur->arch) {
593  is_arm = !strncmp(analysis->cur->arch, "arm", 3);
594  is_x86 = !strncmp(analysis->cur->arch, "x86", 3);
595  is_dalvik = !strncmp(analysis->cur->arch, "dalvik", 6);
596  is_hexagon = !strncmp(analysis->cur->arch, "hexagon", 7);
597  }
598  is_amd64 = is_x86 ? fcn->cc && !strcmp(fcn->cc, "amd64") : false;
599  bool can_jmpmid = analysis->opt.jmpmid && (is_dalvik || is_x86);
600 
601  RzRegItem *variadic_reg = NULL;
602  if (is_amd64) {
603  variadic_reg = rz_reg_get(analysis->reg, "rax", RZ_REG_TYPE_GPR);
604  }
605  bool has_variadic_reg = !!variadic_reg;
606 
607  if (rz_cons_is_breaked()) {
608  rz_analysis_task_item_new(analysis, tasks, fcn, bb, addr);
609  return RZ_ANALYSIS_RET_END;
610  }
611  if (analysis->sleep) {
612  rz_sys_usleep(analysis->sleep);
613  }
614 
615  // check if address is readable
616  if (!analysis->iob.is_valid_offset(analysis->iob.io, addr, 0)) {
617  if (addr != UT64_MAX && !analysis->iob.io->va) {
618  RZ_LOG_DEBUG("Invalid address 0x%" PFMT64x ". Try with io.va=true\n", addr);
619  }
620  return RZ_ANALYSIS_RET_ERROR; // MUST BE TOO DEEP
621  }
622 
623  RzAnalysisFunction *fcn_at_addr = rz_analysis_get_function_at(analysis, addr);
624  if (fcn_at_addr && fcn_at_addr != fcn) {
625  return RZ_ANALYSIS_RET_ERROR; // MUST BE NOT FOUND
626  }
627 
628  if (!bb) {
629  RzAnalysisBlock *existing_bb = bbget(analysis, addr, can_jmpmid);
630  if (existing_bb) {
631  bool existing_in_fcn = rz_list_contains(existing_bb->fcns, fcn);
632  existing_bb = rz_analysis_block_split(existing_bb, addr);
633  if (!existing_in_fcn && existing_bb) {
634  if (existing_bb->addr == fcn->addr) {
635  // our function starts directly there, so we steal what is ours!
636  fcn_takeover_block_recursive(fcn, existing_bb);
637  }
638  }
639  if (existing_bb) {
640  rz_analysis_block_unref(existing_bb);
641  }
642  if (analysis->opt.recont) {
643  return RZ_ANALYSIS_RET_END;
644  }
645  RZ_LOG_DEBUG("%s fails at 0x%" PFMT64x ".\n", __FUNCTION__, addr);
646  return RZ_ANALYSIS_RET_ERROR; // MUST BE NOT DUP
647  }
648 
649  item->block = bb = fcn_append_basic_block(analysis, fcn, addr);
650  // we checked before whether there is a bb at addr, so the create should have succeeded
652  }
653 
654  if (!analysis->leaddrs) {
656  if (!analysis->leaddrs) {
657  RZ_LOG_ERROR("Cannot allocate list of pairs<reg, addr> values.\n");
659  }
660  }
661  static ut64 lea_jmptbl_ip = UT64_MAX;
662  ut64 last_reg_mov_lea_val = UT64_MAX;
663  bool last_is_reg_mov_lea = false;
664  bool last_is_push = false;
665  bool last_is_mov_lr_pc = false;
666  ut64 last_push_addr = UT64_MAX;
667  if (analysis->limit && addr + idx < analysis->limit->from) {
669  }
670  RzAnalysisFunction *tmp_fcn = rz_analysis_get_fcn_in(analysis, addr, 0);
671  if (tmp_fcn) {
672  // Checks if var is already analyzed at given addr
673  RzList *list = rz_analysis_var_all_list(analysis, tmp_fcn);
674  if (!rz_list_empty(list)) {
675  varset = true;
676  }
678  }
679  ut64 movdisp = UT64_MAX; // used by jmptbl when coded as "mov reg, [reg * scale + disp]"
680  ut64 movscale = 0;
681  ut8 buf[32]; // 32 bytes is enough to hold any instruction.
682  int maxlen = len * addrbytes;
683  if (is_dalvik) {
684  bool skipAnalysis = false;
685  if (!strncmp(fcn->name, "sym.", 4)) {
686  if (!strncmp(fcn->name + 4, "imp.", 4)) {
687  skipAnalysis = true;
688  } else if (strstr(fcn->name, "field")) {
689  skipAnalysis = true;
690  }
691  }
692  if (skipAnalysis) {
694  }
695  }
696  if ((maxlen - (addrbytes * idx)) > MAX_SCAN_SIZE) {
697  RZ_LOG_DEBUG("Skipping large memory region during basic block analysis.\n");
698  maxlen = 0;
699  }
700 
701  while (addrbytes * idx < maxlen) {
702  ut32 at_delta;
703  ut64 at;
704  if (!last_is_reg_mov_lea) {
705  free(last_reg_mov_lea_name);
706  last_reg_mov_lea_name = NULL;
707  }
708  if (analysis->limit && analysis->limit->to <= addr + idx) {
709  break;
710  }
711  repeat:
712  at_delta = addrbytes * idx;
713  at = addr + at_delta;
714  if (rz_cons_is_breaked()) {
715  rz_analysis_task_item_new(analysis, tasks, fcn, bb, at);
716  break;
717  }
718  ut64 bytes_read = RZ_MIN(len - at_delta, sizeof(buf));
719  ret = read_ahead(analysis, at, buf, bytes_read);
720 
721  if (ret < 0) {
722  RZ_LOG_ERROR("Failed to read ahead\n");
723  break;
724  }
725  if (isInvalidMemory(analysis, buf, bytes_read)) {
726  RZ_LOG_DEBUG("FFFF opcode at 0x%08" PFMT64x "\n", at);
728  }
730  if ((oplen = rz_analysis_op(analysis, &op, at, buf, bytes_read, RZ_ANALYSIS_OP_MASK_ESIL | RZ_ANALYSIS_OP_MASK_VAL | RZ_ANALYSIS_OP_MASK_HINT)) < 1) {
731  RZ_LOG_DEBUG("Invalid instruction at 0x%" PFMT64x " with %d bits\n", at, analysis->bits);
732  // gotoBeach (RZ_ANALYSIS_RET_ERROR);
733  // RET_END causes infinite loops somehow
735  }
736 
737  const char *bp_reg = analysis->reg->name[RZ_REG_NAME_BP];
738  const char *sp_reg = analysis->reg->name[RZ_REG_NAME_SP];
739  bool has_stack_regs = bp_reg && sp_reg;
740 
741  if (analysis->opt.nopskip && fcn->addr == at) {
742  RzFlagItem *fi = analysis->flb.get_at(analysis->flb.f, addr, false);
743  if (!fi || strncmp(fi->name, "sym.", 4)) {
744  if ((addr + delay.un_idx - oplen) == fcn->addr) {
745  if (rz_analysis_block_relocate(bb, bb->addr + oplen, bb->size - oplen)) {
746  fcn->addr += oplen;
747  idx = delay.un_idx;
748  goto repeat;
749  }
750  }
751  }
752  switch (op.type & RZ_ANALYSIS_OP_TYPE_MASK) {
756  if (rz_analysis_block_relocate(bb, at + op.size, bb->size)) {
757  addr = at + op.size;
758  fcn->addr = addr;
759  goto repeat;
760  }
761  }
762  }
763 
764  if (op.hint.new_bits) {
765  rz_analysis_hint_set_bits(analysis, op.jump, op.hint.new_bits);
766  }
767  if (idx > 0 && !overlapped) {
768  bbg = bbget(analysis, at, can_jmpmid);
769  if (bbg && bbg != bb) {
770  bb->jump = at;
771  if (can_jmpmid) {
772  // This happens when we purposefully walked over another block and overlapped it
773  // and now we hit an offset where the instructions match again.
774  // So we need to split the overwalked block.
775  RzAnalysisBlock *split = rz_analysis_block_split(bbg, at);
777  }
778  overlapped = true;
779  RZ_LOG_DEBUG("Overlapped at 0x%08" PFMT64x "\n", at);
780  }
781  }
782  if (!overlapped) {
783  ut64 newbbsize = bb->size + oplen;
784  if (newbbsize > MAX_FCN_SIZE) {
786  }
787  rz_analysis_block_set_op_offset(bb, bb->ninstr++, at - bb->addr);
788  rz_analysis_block_set_size(bb, newbbsize);
789  fcn->ninstr++;
790  }
791  if (analysis->opt.trycatch) {
792  const char *name = analysis->coreb.getName(analysis->coreb.core, at);
793  if (name) {
794  if (rz_str_startswith(name, "try.") && rz_str_endswith(name, ".from")) {
795  char *handle = strdup(name);
796  // handle = rz_str_replace (handle, ".from", ".to", 0);
797  ut64 from_addr = analysis->coreb.numGet(analysis->coreb.core, handle);
798  handle = rz_str_replace(handle, ".from", ".catch", 0);
799  ut64 handle_addr = analysis->coreb.numGet(analysis->coreb.core, handle);
800  handle = rz_str_replace(handle, ".catch", ".filter", 0);
801  ut64 filter_addr = analysis->coreb.numGet(analysis->coreb.core, handle);
802  if (filter_addr) {
803  rz_analysis_xrefs_set(analysis, op.addr, filter_addr, RZ_ANALYSIS_XREF_TYPE_CALL);
804  }
805  bb->jump = at + oplen;
806  if (from_addr != bb->addr) {
807  bb->fail = handle_addr;
808  ret = analyze_function_locally(analysis, fcn, handle_addr);
809  if (bb->size == 0) {
811  }
814  bb = fcn_append_basic_block(analysis, fcn, bb->jump);
815  if (!bb) {
817  }
818  }
819  }
820  }
821  }
822  idx += oplen;
823  delay.un_idx = idx;
824  if (analysis->opt.delay && op.delay > 0 && !delay.pending) {
825  // Handle first pass through a branch delay jump:
826  // Come back and handle the current instruction later.
827  // Save the location of it in `delay.idx`
828  // note, we have still increased size of basic block
829  // (and function)
830  RZ_LOG_DEBUG("Enter branch delay at 0x%08" PFMT64x ". bb->sz=%" PFMT64u "\n", at - oplen, bb->size);
831  delay.idx = idx - oplen;
832  delay.cnt = op.delay;
833  delay.pending = 1; // we need this in case the actual idx is zero...
834  delay.adjust = !overlapped; // adjustment is required later to avoid double count
835  continue;
836  }
837 
838  if (delay.cnt > 0) {
839  // if we had passed a branch delay instruction, keep
840  // track of how many still to process.
841  delay.cnt--;
842  if (!delay.cnt) {
843  RZ_LOG_DEBUG("Last branch delayed opcode at 0x%08" PFMT64x ". bb->sz=%" PFMT64u "\n", addr + idx - oplen, bb->size);
844  delay.after = idx;
845  idx = delay.idx;
846  // At this point, we are still looking at the
847  // last instruction in the branch delay group.
848  // Next time, we will again be looking
849  // at the original instruction that entered
850  // the branch delay.
851  }
852  } else if (op.delay > 0 && delay.pending) {
853  RZ_LOG_DEBUG("Revisit branch delay jump at 0x%08" PFMT64x ". bb->sz=%" PFMT64u "\n", addr + idx - oplen, bb->size);
854  // This is the second pass of the branch delaying opcode
855  // But we also already counted this instruction in the
856  // size of the current basic block, so we need to fix that
857  if (delay.adjust) {
858  rz_analysis_block_set_size(bb, (ut64)addrbytes * (ut64)delay.after);
859  fcn->ninstr--;
860  RZ_LOG_DEBUG("Correct for branch delay @ 0x%08" PFMT64x " bb.addr=0x%08" PFMT64x " corrected.bb=%" PFMT64u " f.uncorr=%" PFMT64u "\n",
861  addr + idx - oplen, bb->addr, bb->size, rz_analysis_function_linear_size(fcn));
862  }
863  // Next time, we go to the opcode after the delay count
864  // Take care not to use this below, use delay.un_idx instead ...
865  idx = delay.after;
866  delay.pending = delay.after = delay.idx = delay.adjust = 0;
867  }
868  // Note: if we got two branch delay instructions in a row due to an
869  // compiler bug or junk or something it wont get treated as a delay
870  if (analysis->opt.vars && !varset) {
871  rz_analysis_extract_vars(analysis, fcn, &op);
872  }
873  if (has_stack_regs && arch_destroys_dst) {
874  if (op_is_set_bp(&op, bp_reg, sp_reg) && op.src[1]) {
875  switch (op.type & RZ_ANALYSIS_OP_TYPE_MASK) {
877  fcn->bp_off = fcn->stack - op.src[1]->imm;
878  break;
880  fcn->bp_off = fcn->stack + op.src[1]->imm;
881  break;
882  }
883  }
884  }
885  switch (op.stackop) {
887  if (RZ_ABS(op.stackptr) < 8096) {
888  fcn->stack += op.stackptr;
889  if (fcn->stack > fcn->maxstack) {
890  fcn->maxstack = fcn->stack;
891  }
892  }
893  bb->stackptr += op.stackptr;
894  break;
896  bb->stackptr = 0;
897  break;
898  default:
899  break;
900  }
901  if (op.ptr && op.ptr != UT64_MAX && op.ptr != UT32_MAX) {
902  // swapped parameters
904  }
905  analyze_retpoline(analysis, &op);
906 
907  switch (op.type & RZ_ANALYSIS_OP_TYPE_MASK) {
910  last_is_reg_mov_lea = false;
911  if (is_arm) { // mov lr, pc
912  const char *esil = rz_strbuf_get(&op.esil);
913  if (!rz_str_cmp(esil, "pc,lr,=", -1)) {
914  last_is_mov_lr_pc = true;
915  }
916  }
917  if (has_stack_regs && op_is_set_bp(&op, bp_reg, sp_reg)) {
918  fcn->bp_off = fcn->stack;
919  }
920  // Is this a mov of immediate value into a register?
921  if (op.dst && op.dst->reg && op.dst->reg->name && op.val > 0 && op.val != UT64_MAX) {
922  free(last_reg_mov_lea_name);
923  if ((last_reg_mov_lea_name = strdup(op.dst->reg->name))) {
924  last_reg_mov_lea_val = op.val;
925  last_is_reg_mov_lea = true;
926  }
927  }
928  // skip mov reg, reg
929  if (analysis->opt.jmptbl && op.scale && op.ireg) {
930  movdisp = op.disp;
931  movscale = op.scale;
932  if (op.src[0] && op.src[0]->reg) {
933  free(movbasereg);
934  movbasereg = strdup(op.src[0]->reg->name);
935  } else {
936  RZ_FREE(movbasereg);
937  }
938  }
939  if (analysis->opt.hpskip && regs_exist(op.src[0], op.dst) && !strcmp(op.src[0]->reg->name, op.dst->reg->name)) {
940  skip_ret = skip_hp(analysis, fcn, &op, bb, addr, tmp_buf, oplen, delay.un_idx, &idx);
941  if (skip_ret == 1) {
942  goto repeat;
943  }
944  if (skip_ret == 2) {
946  }
947  }
948  break;
950  last_is_reg_mov_lea = false;
951  // if first byte in op.ptr is 0xff, then set leaddr assuming its a jumptable
952  if (op.ptr != UT64_MAX) {
953  leaddr_pair *pair = RZ_NEW(leaddr_pair);
954  if (!pair) {
955  RZ_LOG_ERROR("Cannot allocate pair<reg, addr> structure\n");
957  }
958  pair->op_addr = op.addr;
959  pair->leaddr = op.ptr; // XXX movdisp is dupped but seems to be trashed sometimes(?), better track leaddr separately
960  pair->reg = op.reg
961  ? strdup(op.reg)
962  : op.dst && op.dst->reg
963  ? strdup(op.dst->reg->name)
964  : NULL;
965  lea_cnt++;
966  rz_list_append(analysis->leaddrs, pair);
967  }
968  if (has_stack_regs && op_is_set_bp(&op, bp_reg, sp_reg)) {
969  fcn->bp_off = fcn->stack - op.src[0]->delta;
970  }
971  if (op.dst && op.dst->reg && op.dst->reg->name && op.ptr > 0 && op.ptr != UT64_MAX) {
972  free(last_reg_mov_lea_name);
973  if ((last_reg_mov_lea_name = strdup(op.dst->reg->name))) {
974  last_reg_mov_lea_val = op.ptr;
975  last_is_reg_mov_lea = true;
976  }
977  }
978  // skip lea reg,[reg]
979  if (analysis->opt.hpskip && regs_exist(op.src[0], op.dst) && !strcmp(op.src[0]->reg->name, op.dst->reg->name)) {
980  skip_ret = skip_hp(analysis, fcn, &op, bb, at, tmp_buf, oplen, delay.un_idx, &idx);
981  if (skip_ret == 1) {
982  goto repeat;
983  }
984  if (skip_ret == 2) {
986  }
987  }
988  if (analysis->opt.jmptbl) {
989  RzAnalysisOp jmp_aop = { 0 };
990  ut64 jmptbl_addr = op.ptr;
991  ut64 casetbl_addr = op.ptr;
992  if (is_delta_pointer_table(analysis, op.addr, op.ptr, &jmptbl_addr, &casetbl_addr, &jmp_aop)) {
993  // we require both checks here since rz_analysis_get_jmptbl_info uses
994  // BB info of the final jmptbl jump, which is no present with
995  // is_delta_pointer_table just scanning ahead
996  // rz_analysis_get_delta_jmptbl_info doesn't work at times where the
997  // lea comes after the cmp/default case cjmp, which can be
998  // handled with rz_analysis_get_jmptbl_info
999  RzAnalysisJmpTableParams params = {
1000  .jmp_address = jmp_aop.addr,
1001  .jmptbl_loc = jmptbl_addr,
1002  .casetbl_loc = casetbl_addr,
1003  .entry_size = 4,
1004  .jmptbl_off = op.ptr,
1005  .tasks = tasks
1006  };
1007  if (rz_analysis_get_jmptbl_info(analysis, fcn, bb, jmp_aop.addr, &params) || rz_analysis_get_delta_jmptbl_info(analysis, fcn, jmp_aop.addr, op.addr, &params)) {
1008  ret = casetbl_addr == op.ptr
1009  ? rz_analysis_walkthrough_jmptbl(analysis, fcn, bb, &params)
1010  : rz_analysis_walkthrough_casetbl(analysis, fcn, bb, &params);
1011  if (ret) {
1012  lea_jmptbl_ip = jmp_aop.addr;
1013  }
1014  }
1015  }
1016  rz_analysis_op_fini(&jmp_aop);
1017  }
1018  break;
1020  if (analysis->opt.loads) {
1021  if (analysis->iob.is_valid_offset(analysis->iob.io, op.ptr, 0)) {
1022  rz_meta_set(analysis, RZ_META_TYPE_DATA, op.ptr, 4, "");
1023  }
1024  }
1025  break;
1026  // Case of valid but unused "add [rax], al"
1028  if (analysis->opt.ijmp) {
1029  if ((op.size + 4 <= bytes_read) && !memcmp(buf + op.size, "\x00\x00\x00\x00", 4)) {
1030  rz_analysis_block_set_size(bb, bb->size - oplen);
1031  op.type = RZ_ANALYSIS_OP_TYPE_RET;
1033  }
1034  }
1035  break;
1039  if (analysis->opt.aftertrap) {
1040  continue;
1041  }
1044  // do nothing, because the nopskip goes before this switch
1045  break;
1047  if (op.jump == UT64_MAX) {
1049  }
1050  {
1051  RzFlagItem *fi = analysis->flb.get_at(analysis->flb.f, op.jump, false);
1052  if (fi && strstr(fi->name, "imp.")) {
1054  }
1055  }
1056  if (rz_cons_is_breaked()) {
1058  }
1059  if (analysis->opt.jmpref) {
1060  (void)rz_analysis_xrefs_set(analysis, op.addr, op.jump, RZ_ANALYSIS_XREF_TYPE_CODE);
1061  }
1062  if (!analysis->opt.jmpabove && (op.jump < fcn->addr)) {
1064  }
1065  if (rz_analysis_noreturn_at(analysis, op.jump)) {
1066  if (continue_after_jump && is_hexagon) {
1067  rz_analysis_task_item_new(analysis, tasks, fcn, NULL, op.jump);
1068  rz_analysis_task_item_new(analysis, tasks, fcn, NULL, op.addr + op.size);
1069  if (!overlapped) {
1070  set_bb_branches(bb, op.jump, op.addr + op.size);
1071  }
1073  }
1075  }
1076  {
1077  bool must_eob = true;
1078  RzIOMap *map = analysis->iob.map_get(analysis->iob.io, addr);
1079  if (map) {
1080  must_eob = (op.jump < map->itv.addr || op.jump >= map->itv.addr + map->itv.size);
1081  }
1082  if (must_eob) {
1083  if (continue_after_jump && is_hexagon) {
1084  rz_analysis_task_item_new(analysis, tasks, fcn, NULL, op.jump);
1085  rz_analysis_task_item_new(analysis, tasks, fcn, NULL, op.addr + op.size);
1086  if (!overlapped) {
1087  set_bb_branches(bb, op.jump, op.addr + op.size);
1088  }
1090  }
1091  op.jump = UT64_MAX;
1093  }
1094  }
1095  if (!overlapped) {
1096  set_bb_branches(bb, op.jump, UT64_MAX);
1097  }
1098  rz_analysis_task_item_new(analysis, tasks, fcn, NULL, op.jump);
1099  if (continue_after_jump && (is_hexagon || (is_dalvik && op.cond == RZ_TYPE_COND_EXCEPTION))) {
1100  rz_analysis_task_item_new(analysis, tasks, fcn, NULL, op.addr + op.size);
1102  }
1103  int tc = analysis->opt.tailcall;
1104  if (tc) {
1105  int diff = op.jump - op.addr;
1106  if (tc < 0) {
1107  ut8 buf[32];
1108  (void)analysis->iob.read_at(analysis->iob.io, op.jump, (ut8 *)buf, sizeof(buf));
1109  if (rz_analysis_is_prelude(analysis, buf, sizeof(buf))) {
1110  rz_analysis_task_item_new(analysis, tasks, fcn, NULL, op.jump);
1111  }
1112  } else if (RZ_ABS(diff) > tc) {
1113  (void)rz_analysis_xrefs_set(analysis, op.addr, op.jump, RZ_ANALYSIS_XREF_TYPE_CALL);
1114  rz_analysis_task_item_new(analysis, tasks, fcn, NULL, op.jump);
1116  }
1117  }
1118  goto beach;
1119  break;
1121  if (op.val != UT64_MAX && op.val > 0 && op.val < analysis->opt.jmptbl_maxcount) {
1122  // if register is not stack
1123  cmpval = op.val;
1124  }
1125  break;
1126  case RZ_ANALYSIS_OP_TYPE_CMP: {
1127  ut64 val = is_x86 ? op.val : op.ptr;
1128  if (val) {
1129  if (val < analysis->opt.jmptbl_maxcount) {
1130  cmpval = val;
1131  }
1132  bb->cmpval = val;
1133  bb->cmpreg = op.reg;
1136  }
1137  } break;
1142  if (op.prefix & RZ_ANALYSIS_OP_PREFIX_HWLOOP_END) {
1143  if (op.jump != 0) {
1144  rz_analysis_xrefs_set(analysis, op.addr, op.jump, RZ_ANALYSIS_XREF_TYPE_CODE);
1145  }
1146  if (op.fail != 0) {
1147  rz_analysis_xrefs_set(analysis, op.addr, op.fail, RZ_ANALYSIS_XREF_TYPE_CODE);
1148  }
1149  if (continue_after_jump) {
1150  rz_analysis_task_item_new(analysis, tasks, fcn, NULL, op.addr + op.size);
1151  }
1152  if (!overlapped) {
1153  // If it is an endloop01 instruction the jump to the inner loop is not added yet.
1154  set_bb_branches(bb, op.jump, op.addr + op.size);
1155  }
1157  }
1158  if (analysis->opt.cjmpref) {
1159  rz_analysis_xrefs_set(analysis, op.addr, op.jump, RZ_ANALYSIS_XREF_TYPE_CODE);
1160  if (is_hexagon) {
1161  rz_analysis_xrefs_set(analysis, op.addr, op.fail, RZ_ANALYSIS_XREF_TYPE_CODE);
1162  }
1163  }
1164  if (!overlapped) {
1165  set_bb_branches(bb, op.jump, op.fail);
1166  }
1167  if (bb->cond) {
1168  bb->cond->type = op.cond;
1169  }
1170  if (analysis->opt.jmptbl) {
1171  if (op.ptr != UT64_MAX) {
1172  if (cmpval != UT64_MAX && op.fail != UT64_MAX && (op.reg || op.ireg)) {
1173  RzAnalysisJmpTableParams params = {
1174  .jmp_address = op.addr,
1175  .case_shift = 0,
1176  .jmptbl_loc = op.ptr,
1177  .casetbl_loc = UT64_MAX,
1178  .entry_size = analysis->bits >> 3,
1179  .table_count = cmpval + 1,
1180  .jmptbl_off = op.ptr,
1181  .default_case = op.fail,
1182  .tasks = tasks
1183  };
1184  if (op.ireg) {
1185  rz_analysis_walkthrough_jmptbl(analysis, fcn, bb, &params);
1186  } else { // op.reg
1187  rz_analysis_walkthrough_arm_jmptbl_style(analysis, fcn, bb, &params);
1188  }
1189  // check if op.jump and op.fail contain jump table location
1190  // clear jump address, because it's jump table location
1191  if (op.jump == op.ptr) {
1192  op.jump = UT64_MAX;
1193  } else if (op.fail == op.ptr) {
1194  op.fail = UT64_MAX;
1195  }
1196  cmpval = UT64_MAX;
1197  }
1198  }
1199  }
1200  rz_analysis_task_item_new(analysis, tasks, fcn, NULL, op.fail);
1201  rz_analysis_task_item_new(analysis, tasks, fcn, NULL, op.jump);
1202  if (continue_after_jump && is_hexagon) {
1203  if (op.type == RZ_ANALYSIS_OP_TYPE_RCJMP) {
1204  break;
1205  }
1206  rz_analysis_task_item_new(analysis, tasks, fcn, NULL, op.addr + op.size);
1208  }
1209  if (!continue_after_jump) {
1210  if (op.jump < fcn->addr) {
1211  if (!overlapped) {
1212  bb->jump = op.jump;
1213  bb->fail = UT64_MAX;
1214  }
1216  }
1217  }
1218 
1219  // XXX breaks mips analysis too !op.delay
1220  // this will be all x86, arm (at least)
1221  // without which the analysis is really slow,
1222  // presumably because each opcode would get revisited
1223  // (and already covered by a bb) many times
1224  if (!is_dalvik) {
1225  goto beach;
1226  }
1227  // For some reason, branch delayed code (MIPS) needs to continue
1228  break;
1233  /* call [dst] */
1234  // XXX: this is TYPE_MCALL or indirect-call
1235  (void)rz_analysis_xrefs_set(analysis, op.addr, op.ptr, RZ_ANALYSIS_XREF_TYPE_CALL);
1236 
1237  if (rz_analysis_noreturn_at(analysis, op.ptr)) {
1239  if (f) {
1240  f->is_noreturn = true;
1241  }
1243  }
1244  break;
1247  /* call dst */
1248  (void)rz_analysis_xrefs_set(analysis, op.addr, op.jump, RZ_ANALYSIS_XREF_TYPE_CALL);
1249 
1250  if (rz_analysis_noreturn_at(analysis, op.jump)) {
1252  if (f) {
1253  f->is_noreturn = true;
1254  }
1256  }
1257  break;
1260  if (is_hexagon) {
1261  if (op.analysis_vals[0].plugin_specific == 31) {
1262  // jumpr Rs instruction which uses R31.
1263  // This is a return, but not typed as such.
1265  } else {
1266  // Ignore
1267  break;
1268  }
1269  }
1270  if (is_arm && last_is_mov_lr_pc) {
1271  break;
1272  }
1273  /* fall through */
1277  // if the next instruction is a symbol
1278  if (analysis->opt.ijmp && isSymbolNextInstruction(analysis, &op)) {
1280  }
1281  // switch statement
1282  if (analysis->opt.jmptbl && lea_jmptbl_ip != op.addr) {
1283  RzAnalysisJmpTableParams params = {
1284  .jmp_address = op.addr,
1285  .entry_size = analysis->bits >> 3,
1286  .jmptbl_loc = op.ptr,
1287  .jmptbl_off = op.ptr,
1288  .tasks = tasks
1289  };
1290  // op.ireg since rip relative addressing produces way too many false positives otherwise
1291  // op.ireg is 0 for rip relative, "rax", etc otherwise
1292  if (op.ptr != UT64_MAX && op.ireg) { // direct jump
1293  if (rz_analysis_get_jmptbl_info(analysis, fcn, bb, op.addr, &params)) {
1294  bool case_table = false;
1295  RzAnalysisOp prev_op;
1296  analysis->iob.read_at(analysis->iob.io, op.addr - op.size, buf, sizeof(buf));
1297  if (rz_analysis_op(analysis, &prev_op, op.addr - op.size, buf, sizeof(buf), RZ_ANALYSIS_OP_MASK_VAL) > 0) {
1298  bool prev_op_has_dst_name = prev_op.dst && prev_op.dst->reg && prev_op.dst->reg->name;
1299  bool op_has_src_name = op.src[0] && op.src[0]->reg && op.src[0]->reg->name;
1300  bool same_reg = (op.ireg && prev_op_has_dst_name && !strcmp(op.ireg, prev_op.dst->reg->name)) || (op_has_src_name && prev_op_has_dst_name && !strcmp(op.src[0]->reg->name, prev_op.dst->reg->name));
1301  if (prev_op.type == RZ_ANALYSIS_OP_TYPE_MOV && prev_op.disp && prev_op.disp != UT64_MAX && same_reg) {
1302  // movzx reg, byte [reg + case_table]
1303  // jmp dword [reg*4 + jump_table]
1304  params.casetbl_loc = prev_op.disp;
1305  if (rz_analysis_walkthrough_casetbl(analysis, fcn, bb, &params)) {
1306  ret = case_table = true;
1307  }
1308  }
1309  }
1310  rz_analysis_op_fini(&prev_op);
1311  if (!case_table) {
1312  ret = rz_analysis_walkthrough_jmptbl(analysis, fcn, bb, &params);
1313  }
1314  }
1315  } else if (op.ptr != UT64_MAX && op.reg) { // direct jump
1316  if (rz_analysis_get_jmptbl_info(analysis, fcn, bb, op.addr, &params)) {
1317  ret = rz_analysis_walkthrough_jmptbl(analysis, fcn, bb, &params);
1318  }
1319  } else if (movdisp != UT64_MAX) {
1320  ut64 lea_op_off = UT64_MAX;
1321  RzListIter *iter;
1322  leaddr_pair *pair;
1323  params.jmptbl_off = 0;
1324  if (movbasereg) {
1325  // find nearest candidate leaddr before op.addr
1326  rz_list_foreach_prev(analysis->leaddrs, iter, pair) {
1327  if (pair->op_addr >= op.addr) {
1328  continue;
1329  }
1330  if ((lea_op_off == UT64_MAX || lea_op_off > op.addr - pair->op_addr) && pair->reg && !strcmp(movbasereg, pair->reg)) {
1331  lea_op_off = op.addr - pair->op_addr;
1332  params.jmptbl_off = pair->leaddr;
1333  }
1334  }
1335  }
1336  if (!rz_analysis_get_jmptbl_info(analysis, fcn, bb, op.addr, &params)) {
1337  params.table_count = cmpval + 1;
1338  params.default_case = -1;
1339  }
1340  params.jmptbl_loc = params.jmptbl_off + movdisp;
1341  params.entry_size = movscale;
1342  ret = rz_analysis_walkthrough_jmptbl(analysis, fcn, bb, &params);
1343  cmpval = UT64_MAX;
1344  } else if (is_arm) {
1345  params.jmptbl_loc = op.addr + op.size;
1346  params.jmptbl_off = op.addr + 4;
1347  params.default_case = UT64_MAX;
1348  if (op.ptrsize == 1) { // TBB
1349  ut64 pred_cmpval = try_get_cmpval_from_parents(analysis, fcn, bb, op.ireg);
1350  params.table_count = 0;
1351  if (pred_cmpval != UT64_MAX) {
1352  params.table_count += pred_cmpval;
1353  } else {
1354  params.table_count += cmpval;
1355  }
1356  params.entry_size = 1;
1357  ret = rz_analysis_walkthrough_jmptbl(analysis, fcn, bb, &params);
1358  // skip inlined jumptable
1359  idx += params.table_count;
1360  } else if (op.ptrsize == 2) { // LDRH on thumb/arm
1361  ut64 pred_cmpval = try_get_cmpval_from_parents(analysis, fcn, bb, op.ireg);
1362  params.table_count = 1;
1363  if (pred_cmpval != UT64_MAX) {
1364  params.table_count += pred_cmpval;
1365  } else {
1366  params.table_count += cmpval;
1367  }
1368  params.entry_size = 2;
1369  ret = rz_analysis_walkthrough_jmptbl(analysis, fcn, bb, &params);
1370  // skip inlined jumptable
1371  idx += (params.table_count * 2);
1372  }
1373  }
1374  }
1375  if (lea_jmptbl_ip == op.addr) {
1376  lea_jmptbl_ip = UT64_MAX;
1377  }
1378  if (analysis->opt.ijmp) {
1379  if (continue_after_jump) {
1380  rz_analysis_task_item_new(analysis, tasks, fcn, NULL, op.fail);
1381  rz_analysis_task_item_new(analysis, tasks, fcn, NULL, op.jump);
1382  if (overlapped) {
1383  goto analopfinish;
1384  }
1385  }
1386  if (rz_analysis_noreturn_at(analysis, op.jump) || op.eob) {
1387  goto analopfinish;
1388  }
1389  } else {
1390  analopfinish:
1391  if (op.type == RZ_ANALYSIS_OP_TYPE_RJMP) {
1393  } else {
1395  }
1396  }
1397  break;
1399  last_is_push = true;
1400  last_push_addr = op.val;
1401  if (analysis->iob.is_valid_offset(analysis->iob.io, last_push_addr, 1)) {
1402  (void)rz_analysis_xrefs_set(analysis, op.addr, last_push_addr, RZ_ANALYSIS_XREF_TYPE_DATA);
1403  }
1404  break;
1406  if ((op.type & RZ_ANALYSIS_OP_TYPE_REG) && last_is_reg_mov_lea && op.src[0] && op.src[0]->reg && op.src[0]->reg->name && !strcmp(op.src[0]->reg->name, last_reg_mov_lea_name)) {
1407  last_is_push = true;
1408  last_push_addr = last_reg_mov_lea_val;
1409  if (analysis->iob.is_valid_offset(analysis->iob.io, last_push_addr, 1)) {
1410  (void)rz_analysis_xrefs_set(analysis, op.addr, last_push_addr, RZ_ANALYSIS_XREF_TYPE_DATA);
1411  }
1412  }
1413  break;
1415  if (op.family == RZ_ANALYSIS_OP_FAMILY_PRIV) {
1417  }
1418  if (last_is_push && analysis->opt.pushret) {
1419  op.type = RZ_ANALYSIS_OP_TYPE_JMP;
1420  op.jump = last_push_addr;
1421  bb->jump = op.jump;
1422  rz_analysis_task_item_new(analysis, tasks, fcn, NULL, op.jump);
1423  goto beach;
1424  }
1425  if (!op.cond) {
1426  RZ_LOG_DEBUG("RET 0x%08" PFMT64x ". overlap=%s %" PFMT64u " %" PFMT64u "\n",
1427  addr + delay.un_idx - oplen, rz_str_bool(overlapped),
1430  }
1431  break;
1433  if (continue_after_jump && is_hexagon) {
1434  rz_analysis_task_item_new(analysis, tasks, fcn, NULL, op.addr + op.size);
1435  set_bb_branches(bb, op.addr + op.size, UT64_MAX);
1437  }
1438  }
1440  last_is_reg_mov_lea = false;
1441  }
1442  if (op.type != RZ_ANALYSIS_OP_TYPE_PUSH && op.type != RZ_ANALYSIS_OP_TYPE_RPUSH) {
1443  last_is_push = false;
1444  }
1445  if (is_arm && op.type != RZ_ANALYSIS_OP_TYPE_MOV) {
1446  last_is_mov_lr_pc = false;
1447  }
1448  if (has_variadic_reg && !fcn->is_variadic) {
1449  variadic_reg = rz_reg_get(analysis->reg, "rax", RZ_REG_TYPE_GPR);
1450  bool dst_is_variadic = op.dst && op.dst->reg && variadic_reg && op.dst->reg->offset == variadic_reg->offset;
1451  bool op_is_cmp = (op.type == RZ_ANALYSIS_OP_TYPE_CMP) || op.type == RZ_ANALYSIS_OP_TYPE_ACMP;
1452  if (dst_is_variadic && !op_is_cmp) {
1453  has_variadic_reg = false;
1454  } else if (op_is_cmp) {
1455  if (op.src[0] && op.src[0]->reg && (op.dst->reg == op.src[0]->reg) && dst_is_variadic) {
1456  fcn->is_variadic = true;
1457  }
1458  }
1459  }
1460  }
1461 beach:
1463  RZ_FREE(last_reg_mov_lea_name);
1464  if (bb) {
1465  if (bb->size) {
1467  } else {
1469  }
1471  }
1472  free(movbasereg);
1473  return ret;
1474 }
1475 
1489  rz_return_val_if_fail(analysis && tasks && fcn, false);
1490  RzAnalysisTaskItem item = { fcn, block, fcn->stack, address };
1491  RzAnalysisTaskItem *it;
1492  rz_vector_foreach(tasks, it) {
1493  if (item.start_address == it->start_address) {
1494  return true;
1495  }
1496  }
1497  return rz_vector_push(tasks, &item);
1498 }
1499 
1509 RZ_API int rz_analysis_run_tasks(RZ_NONNULL RzVector /*<RzAnalysisTaskItem>*/ *tasks) {
1511  int ret = RZ_ANALYSIS_RET_ERROR;
1512  while (!rz_vector_empty(tasks)) {
1513  RzAnalysisTaskItem item;
1514  rz_vector_pop(tasks, &item);
1515  int r = run_basic_block_analysis(&item, tasks);
1516  switch (r) {
1518  case RZ_ANALYSIS_RET_COND:
1519  continue;
1520  case RZ_ANALYSIS_RET_NOP:
1521  case RZ_ANALYSIS_RET_ERROR:
1522  if (ret != RZ_ANALYSIS_RET_END) {
1523  ret = r;
1524  }
1525  break;
1526  case RZ_ANALYSIS_RET_END:
1527  default:
1528  ret = r;
1529  break;
1530  }
1531  if (rz_cons_is_breaked()) {
1532  break;
1533  }
1534  }
1535  return ret;
1536 }
1537 
1538 RZ_API bool rz_analysis_check_fcn(RzAnalysis *analysis, ut8 *buf, ut16 bufsz, ut64 addr, ut64 low, ut64 high) {
1539  RzAnalysisOp op = {
1540  0
1541  };
1542  int i, oplen, opcnt = 0, pushcnt = 0, movcnt = 0, brcnt = 0;
1543  if (rz_analysis_is_prelude(analysis, buf, bufsz)) {
1544  return true;
1545  }
1546  for (i = 0; i < bufsz && opcnt < 10; i += oplen, opcnt++) {
1548  if ((oplen = rz_analysis_op(analysis, &op, addr + i, buf + i, bufsz - i, RZ_ANALYSIS_OP_MASK_BASIC | RZ_ANALYSIS_OP_MASK_HINT)) < 1) {
1549  return false;
1550  }
1551  switch (op.type) {
1555  pushcnt++;
1556  break;
1559  movcnt++;
1560  break;
1564  if (op.jump < low || op.jump >= high) {
1565  return false;
1566  }
1567  brcnt++;
1568  break;
1570  return false;
1571  default:
1572  break;
1573  }
1574  }
1575  return (pushcnt + movcnt + brcnt > 5);
1576 }
1577 
1579  RzAnalysisXRef *xref;
1581  RzListIter *iter;
1582  const bool is_x86 = analysis->cur->arch && !strcmp(analysis->cur->arch, "x86"); // HACK
1583 
1584  rz_list_foreach (xrefs, iter, xref) {
1585  if (xref->type == RZ_ANALYSIS_XREF_TYPE_CODE && rz_analysis_function_contains(fcn, xref->to) && (!is_x86 || !rz_analysis_function_contains(fcn, xref->from))) {
1586  rz_analysis_xrefs_deln(analysis, xref->from, xref->to, xref->type);
1587  }
1588  }
1589  rz_list_free(xrefs);
1590 }
1591 
1593  RzAnalysisXRef *xref;
1595  RzListIter *iter;
1596 
1597  rz_list_foreach (xrefs, iter, xref) {
1598  if (xref->type == RZ_ANALYSIS_XREF_TYPE_CODE) {
1599  rz_analysis_xrefs_deln(analysis, xref->from, xref->to, xref->type);
1600  }
1601  }
1602  rz_list_free(xrefs);
1603 }
1604 
1605 /* Does NOT invalidate read-ahead cache. */
1608  void **it;
1609  rz_pvector_foreach (metas, it) {
1610  RzAnalysisMetaItem *meta = ((RzIntervalNode *)*it)->data;
1611  switch (meta->type) {
1612  case RZ_META_TYPE_DATA:
1613  case RZ_META_TYPE_STRING:
1614  case RZ_META_TYPE_FORMAT:
1616  return 0;
1617  default:
1618  break;
1619  }
1620  }
1622  if (analysis->opt.norevisit) {
1623  if (!analysis->visited) {
1624  analysis->visited = set_u_new();
1625  }
1626  if (set_u_contains(analysis->visited, addr)) {
1627  RZ_LOG_DEBUG("rz_analysis_fcn: analysis.norevisit at 0x%08" PFMT64x " %c\n", addr, reftype);
1628  return RZ_ANALYSIS_RET_END;
1629  }
1630  set_u_add(analysis->visited, addr);
1631  } else {
1632  if (analysis->visited) {
1633  set_u_free(analysis->visited);
1634  analysis->visited = NULL;
1635  }
1636  }
1637  /* defines fcn. or loc. prefix */
1639  if (fcn->addr == UT64_MAX) {
1640  fcn->addr = addr;
1641  }
1642  fcn->maxstack = 0;
1643  if (fcn->cc && !strcmp(fcn->cc, "ms")) {
1644  // Probably should put this on the cc sdb
1645  const int shadow_store = 0x28; // First 4 args + retaddr
1646  fcn->stack = fcn->maxstack = fcn->reg_save_area = shadow_store;
1647  }
1648  RzVector tasks;
1649  rz_vector_init(&tasks, sizeof(RzAnalysisTaskItem), NULL, NULL);
1650  rz_analysis_task_item_new(analysis, &tasks, fcn, NULL, addr);
1651  int ret = rz_analysis_run_tasks(&tasks);
1652  rz_vector_fini(&tasks);
1653  return ret;
1654 }
1655 
1656 // XXX deprecate
1658  RzListIter *iter, *iter2;
1660  if (!f) {
1661  return false;
1662  }
1663  rz_list_foreach_safe (analysis->fcns, iter, iter2, fcn) {
1664  if (fcn->type != RZ_ANALYSIS_FCN_TYPE_LOC) {
1665  continue;
1666  }
1667  if (rz_analysis_function_contains(fcn, addr)) {
1669  }
1670  }
1671  rz_analysis_fcn_del(analysis, addr);
1672  return true;
1673 }
1674 
1676  RzAnalysisFunction *fcn;
1677  RzListIter *iter, *iter_tmp;
1678  rz_list_foreach_safe (a->fcns, iter, iter_tmp, fcn) {
1679  RZ_LOG_DEBUG("removing function at %" PFMT64x " %" PFMT64x "\n", fcn->addr, addr);
1680  if (fcn->addr == addr) {
1682  }
1683  }
1684  return true;
1685 }
1686 
1689  RzAnalysisFunction *ret = NULL;
1690  if (list && !rz_list_empty(list)) {
1692  RzAnalysisFunction *fcn;
1693  RzListIter *iter;
1694  rz_list_foreach (list, iter, fcn) {
1695  if (fcn->addr == addr) {
1696  ret = fcn;
1697  break;
1698  }
1699  }
1700  } else {
1701  ret = rz_list_first(list);
1702  }
1703  }
1704  rz_list_free(list);
1705  return ret;
1706 }
1707 
1709  RzAnalysisFunction *fcn, *ret = NULL;
1710  RzListIter *iter;
1712  rz_list_foreach (analysis->fcns, iter, fcn) {
1713  if (addr == fcn->addr) {
1714  return fcn;
1715  }
1716  }
1717  return NULL;
1718  }
1719  rz_list_foreach (analysis->fcns, iter, fcn) {
1720  if (!type || (fcn && fcn->type & type)) {
1721  if (rz_analysis_function_contains(fcn, addr)) {
1722  return fcn;
1723  }
1724  }
1725  }
1726  return ret;
1727 }
1728 
1730  bool found = false;
1731  RzAnalysisFunction *f = ht_pp_find(a->ht_name_fun, name, &found);
1732  if (f && found) {
1733  return f;
1734  }
1735  return NULL;
1736 }
1737 
1738 /* rename RzAnalysisFunctionBB.add() */
1740  if (size == 0) {
1741  RZ_LOG_ERROR("Empty basic block at 0x%08" PFMT64x " (not allowed).\n", addr);
1743  return false;
1744  }
1745  if (size > a->opt.bb_max_size) {
1746  RZ_LOG_ERROR("Cannot allocate such big bb of %" PFMT64d " bytes at 0x%08" PFMT64x "\n", (st64)size, addr);
1748  return false;
1749  }
1750 
1752  if (block) {
1753  rz_analysis_delete_block(block);
1754  block = NULL;
1755  }
1756 
1757  block = rz_analysis_create_block(a, addr, size);
1758  if (!block) {
1759  return false;
1760  }
1761 
1763  rz_analysis_function_add_block(fcn, block);
1764 
1765  block->jump = jump;
1766  block->fail = fail;
1767  if (diff) {
1768  if (!block->diff) {
1769  block->diff = rz_analysis_diff_new();
1770  }
1771  if (block->diff) {
1772  block->diff->type = diff->type;
1773  block->diff->addr = diff->addr;
1774  if (diff->name) {
1775  RZ_FREE(block->diff->name);
1776  block->diff->name = strdup(diff->name);
1777  }
1778  }
1779  }
1780  rz_analysis_block_unref(block);
1781  return true;
1782 }
1783 
1785  RzListIter *iter;
1786  RzAnalysisBlock *bb;
1787  ut32 loops = 0;
1788  rz_list_foreach (fcn->bbs, iter, bb) {
1789  if (bb->jump != UT64_MAX && bb->jump < bb->addr) {
1790  loops++;
1791  }
1792  if (bb->fail != UT64_MAX && bb->fail < bb->addr) {
1793  loops++;
1794  }
1795  }
1796  return loops;
1797 }
1798 
1800  /*
1801  CC = E - N + 2P
1802  E = the number of edges of the graph.
1803  N = the number of nodes of the graph.
1804  P = the number of connected components (exit nodes).
1805  */
1806  RzAnalysis *analysis = fcn->analysis;
1807  int E = 0, N = 0, P = 0;
1808  RzListIter *iter;
1809  RzAnalysisBlock *bb;
1810 
1811  rz_list_foreach (fcn->bbs, iter, bb) {
1812  N++; // nodes
1813  if (!analysis && bb->jump == UT64_MAX && bb->fail != UT64_MAX) {
1814  RZ_LOG_DEBUG("invalid bb jump/fail pair at 0x%08" PFMT64x " (fcn 0x%08" PFMT64x "\n", bb->addr, fcn->addr);
1815  }
1816  if (bb->jump == UT64_MAX && bb->fail == UT64_MAX) {
1817  P++; // exit nodes
1818  } else {
1819  E++; // edges
1820  if (bb->fail != UT64_MAX) {
1821  E++;
1822  }
1823  }
1824  if (bb->switch_op && bb->switch_op->cases) {
1825  E += rz_list_length(bb->switch_op->cases);
1826  }
1827  }
1828 
1829  int result = E - N + (2 * P);
1830  if (result < 1 && !analysis) {
1831  RZ_LOG_DEBUG("CC = E(%d) - N(%d) + (2 * P(%d)) < 1 at 0x%08" PFMT64x "\n", E, N, P, fcn->addr);
1832  }
1833  return result;
1834 }
1835 
1846  RzCallable *callable = rz_analysis_function_derive_type(analysis, f);
1847  if (!callable) {
1848  return -1;
1849  }
1850  rz_type_func_save(analysis->typedb, callable);
1851  return rz_pvector_len(callable->args);
1852 }
1853 
1854 // tfj and afsj call this function
1856  RzAnalysis *a = function->analysis;
1857  PJ *pj = pj_new();
1858  char *ret_type_str = NULL;
1859  RzType *ret_type = rz_type_func_ret(a->typedb, function->name);
1860  if (ret_type) {
1861  ret_type_str = rz_type_as_string(a->typedb, ret_type);
1862  }
1863  int argc = rz_analysis_function_get_arg_count(a, function);
1864 
1865  pj_o(pj);
1866  pj_ks(pj, "name", function->name);
1867  const bool no_return = rz_analysis_noreturn_at_addr(a, function->addr);
1868  pj_kb(pj, "noreturn", no_return);
1869  pj_ks(pj, "ret", ret_type_str ? ret_type_str : "void");
1870  if (function->cc) {
1871  pj_ks(pj, "cc", function->cc);
1872  }
1873  pj_k(pj, "args");
1874  pj_a(pj);
1875  for (int i = 0; i < argc; i++) {
1876  pj_o(pj);
1877  const char *arg_name = rz_type_func_args_name(a->typedb, function->name, i);
1878  RzType *arg_type = rz_type_func_args_type(a->typedb, function->name, i);
1879  char *arg_type_str = rz_type_as_string(a->typedb, arg_type);
1880  pj_ks(pj, "name", arg_name);
1881  pj_ks(pj, "type", arg_type_str);
1882  const char *cc_arg = rz_reg_get_name(a->reg, rz_reg_get_name_idx(sdb_fmt("A%d", i)));
1883  if (cc_arg) {
1884  pj_ks(pj, "cc", cc_arg);
1885  }
1886  pj_end(pj);
1887  free(arg_type_str);
1888  }
1889  pj_end(pj);
1890  pj_end(pj);
1891  free(ret_type_str);
1892  return pj_drain(pj);
1893 }
1894 
1896  rz_return_val_if_fail(function, NULL);
1897  RzAnalysis *a = function->analysis;
1898 
1899  RzCallable *callable = rz_analysis_function_derive_type(a, function);
1900  if (!callable) {
1901  return NULL;
1902  }
1903  char *signature = rz_type_callable_as_string(a->typedb, callable);
1904  rz_type_callable_free(callable);
1905  char *result = rz_str_newf("%s;", signature);
1906  free(signature);
1907  return result;
1908 }
1909 
1923  rz_return_val_if_fail(a && f && callable, false);
1924  // At first, we check if the arguments match, and rename/retype them
1925  void **it;
1926  size_t index = 0;
1927  if (rz_pvector_empty(callable->args)) {
1929  }
1930  size_t args_count = rz_pvector_len(callable->args);
1931  RzPVector *cloned_vars = (RzPVector *)rz_vector_clone((RzVector *)&f->vars);
1932  rz_pvector_foreach (cloned_vars, it) {
1933  RzAnalysisVar *var = *it;
1934  if (!var->isarg) {
1935  continue;
1936  }
1937  if (index < args_count) {
1938  RzCallableArg *arg = *rz_pvector_index_ptr(callable->args, index);
1939  if (arg) {
1940  free(var->name);
1941  if (arg->name) {
1942  var->name = strdup(arg->name);
1943  }
1944  rz_type_free(var->type);
1945  var->type = rz_type_clone(arg->type);
1946  }
1947  index++;
1948  } else {
1949  // There is no match for this argument in the RzCallable type,
1950  // thus we remove it from the function
1952  }
1953  }
1954  // For f->vars is already empty, add args into it
1955  for (; index < args_count; index++) {
1956  RzCallableArg *arg = *rz_pvector_index_ptr(callable->args, index);
1957  if (arg && arg->type) {
1958  size_t size = rz_type_db_get_bitsize(a->typedb, arg->type);
1959  // For user defined args, we set its delta and kind to its index and stack var by default
1961  }
1962  }
1963 
1964  if (callable->noret) {
1965  f->is_noreturn = true;
1966  } else {
1967  f->ret_type = callable->ret;
1968  }
1969  rz_pvector_free(cloned_vars);
1970  return true;
1971 }
1972 
1986  rz_return_val_if_fail(a && f && sig, false);
1987  char *error_msg = NULL;
1988  // At first we should check if the type is already presented in the types database
1989  // and remove it if exists
1990  if (rz_type_func_exist(a->typedb, f->name)) {
1991  rz_type_func_delete(a->typedb, f->name);
1992  }
1993  // Then we create a new one by parsing the string
1994  RzType *result = rz_type_parse_string_declaration_single(a->typedb->parser, sig, &error_msg);
1995  if (!result) {
1996  if (error_msg) {
1997  RZ_LOG_ERROR("%s", error_msg);
1998  free(error_msg);
1999  }
2000  RZ_LOG_ERROR("Cannot parse callable type\n");
2001  return false;
2002  }
2003  // Parsed result should be RzCallable
2004  if (result->kind != RZ_TYPE_KIND_CALLABLE) {
2005  RZ_LOG_ERROR("Parsed function signature should be RzCallable\n");
2006  return false;
2007  }
2008  if (!result->callable) {
2009  RZ_LOG_ERROR("Parsed function signature should not be NULL\n");
2010  return false;
2011  }
2012  return rz_analysis_function_set_type(a, f, result->callable);
2013 }
2014 
2016  RzAnalysisFunction *fcni;
2017  RzListIter *iter;
2018  RzAnalysisFunction *closer = NULL;
2019  rz_list_foreach (analysis->fcns, iter, fcni) {
2020  // if (fcni->addr == addr)
2021  if (fcni->addr > addr && (!closer || fcni->addr < closer->addr)) {
2022  closer = fcni;
2023  }
2024  }
2025  return closer;
2026 }
2027 
2029  int n = 0;
2030  RzAnalysisFunction *fcni;
2031  RzListIter *iter;
2032  rz_list_foreach (analysis->fcns, iter, fcni) {
2033  if (fcni->addr >= from && fcni->addr < to) {
2034  n++;
2035  }
2036  }
2037  return n;
2038 }
2039 
2040 /* return the basic block in fcn found at the given address.
2041  * NULL is returned if such basic block doesn't exist. */
2043  rz_return_val_if_fail(analysis && fcn, NULL);
2044  if (addr == UT64_MAX) {
2045  return NULL;
2046  }
2047  bool can_jmpmid = false;
2048  if (analysis->cur->arch) {
2049  bool is_x86 = !strncmp(analysis->cur->arch, "x86", 3);
2050  bool is_dalvik = !strncmp(analysis->cur->arch, "dalvik", 6);
2051  can_jmpmid = analysis->opt.jmpmid && (is_dalvik || is_x86);
2052  }
2053  RzListIter *iter;
2054  RzAnalysisBlock *bb;
2055  rz_list_foreach (fcn->bbs, iter, bb) {
2056  if (addr >= bb->addr && addr < (bb->addr + bb->size) && (!can_jmpmid || rz_analysis_block_op_starts_at(bb, addr))) {
2057  return bb;
2058  }
2059  }
2060  return NULL;
2061 }
2062 
2066  if (b) {
2067  return b;
2068  }
2069  RzListIter *iter;
2070  RzAnalysisBlock *bb;
2071  rz_list_foreach (fcn->bbs, iter, bb) {
2072  if (addr == bb->addr) {
2073  return bb;
2074  }
2075  }
2076  return NULL;
2077 }
2078 
2079 // compute the cyclomatic cost
2081  RzListIter *iter;
2082  RzAnalysisBlock *bb;
2083  ut32 totalCycles = 0;
2084  if (!fcn) {
2085  return 0;
2086  }
2087  RzAnalysis *analysis = fcn->analysis;
2088  rz_list_foreach (fcn->bbs, iter, bb) {
2089  RzAnalysisOp op;
2090  ut64 at, end = bb->addr + bb->size;
2091  ut8 *buf = malloc(bb->size);
2092  if (!buf) {
2093  continue;
2094  }
2095  (void)analysis->iob.read_at(analysis->iob.io, bb->addr, (ut8 *)buf, bb->size);
2096  int idx = 0;
2097  for (at = bb->addr; at < end;) {
2098  memset(&op, 0, sizeof(op));
2099  (void)rz_analysis_op(analysis, &op, at, buf + idx, bb->size - idx, RZ_ANALYSIS_OP_MASK_BASIC);
2100  if (op.size < 1) {
2101  op.size = 1;
2102  }
2103  idx += op.size;
2104  at += op.size;
2105  totalCycles += op.cycles;
2107  }
2108  free(buf);
2109  }
2110  return totalCycles;
2111 }
2112 
2114  rz_return_val_if_fail(fcn, 0);
2115  RzListIter *iter;
2116  RzAnalysisBlock *bb;
2117  int edges = 0;
2118  if (ebbs) {
2119  *ebbs = 0;
2120  }
2121  rz_list_foreach (fcn->bbs, iter, bb) {
2122  if (ebbs && bb->jump == UT64_MAX && bb->fail == UT64_MAX) {
2123  *ebbs = *ebbs + 1;
2124  } else {
2125  if (bb->jump != UT64_MAX) {
2126  edges++;
2127  }
2128  if (bb->fail != UT64_MAX) {
2129  edges++;
2130  }
2131  }
2132  }
2133  return edges;
2134 }
2135 
2137  if (fcn->has_changed) {
2138  HtUP *ht = ht_up_new(NULL, NULL, NULL);
2139  if (ht) {
2140  check_purity(ht, fcn);
2141  ht_up_free(ht);
2142  }
2143  }
2144  return fcn->is_pure;
2145 }
2146 
2147 static bool can_affect_bp(RzAnalysis *analysis, RzAnalysisOp *op) {
2148  RzAnalysisValue *dst = op->dst;
2149  RzAnalysisValue *src = op->src[0];
2150  const char *opdreg = (dst && dst->reg) ? dst->reg->name : NULL;
2151  const char *opsreg = (src && src->reg) ? src->reg->name : NULL;
2152  const char *bp_name = analysis->reg->name[RZ_REG_NAME_BP];
2153  bool is_bp_dst = opdreg && !dst->memref && !strcmp(opdreg, bp_name);
2154  bool is_bp_src = opsreg && !src->memref && !strcmp(opsreg, bp_name);
2155  if (op->type == RZ_ANALYSIS_OP_TYPE_XCHG) {
2156  return is_bp_src || is_bp_dst;
2157  }
2158  return is_bp_dst;
2159 }
2160 
2161 /*
2162  * This function checks whether any operation in a given function may change bp (excluding "mov bp, sp"
2163  * and "pop bp" at the end).
2164  */
2166  RzListIter *iter;
2167  RzAnalysisBlock *bb;
2168  char str_to_find[40] = "\"type\":\"reg\",\"value\":\"";
2169  char *pos;
2170  strncat(str_to_find, analysis->reg->name[RZ_REG_NAME_BP], 39);
2171  if (!fcn) {
2172  return;
2173  }
2174  rz_list_foreach (fcn->bbs, iter, bb) {
2175  RzAnalysisOp op;
2176  ut64 at, end = bb->addr + bb->size;
2177  ut8 *buf = malloc(bb->size);
2178  if (!buf) {
2179  continue;
2180  }
2181  (void)analysis->iob.read_at(analysis->iob.io, bb->addr, (ut8 *)buf, bb->size);
2182  int idx = 0;
2183  for (at = bb->addr; at < end;) {
2185  if (op.size < 1) {
2186  op.size = 1;
2187  }
2188  switch (op.type) {
2191  if (can_affect_bp(analysis, &op) && op.src[0] && op.src[0]->reg && op.src[0]->reg->name && strcmp(op.src[0]->reg->name, analysis->reg->name[RZ_REG_NAME_SP])) {
2192  fcn->bp_frame = false;
2194  free(buf);
2195  return;
2196  }
2197  break;
2211  // op.dst is not filled for these operations, so for now, check for bp as dst looks like this; in the future it may be just replaced with call to can_affect_bp
2212  pos = op.opex.ptr ? strstr(op.opex.ptr, str_to_find) : NULL;
2213  if (pos && pos - op.opex.ptr < 60) {
2214  fcn->bp_frame = false;
2216  free(buf);
2217  return;
2218  }
2219  break;
2221  if (op.opex.ptr && strstr(op.opex.ptr, str_to_find)) {
2222  fcn->bp_frame = false;
2224  free(buf);
2225  return;
2226  }
2227  break;
2229  break;
2230  default:
2231  break;
2232  }
2233  idx += op.size;
2234  at += op.size;
2236  }
2237  free(buf);
2238  }
2239 }
2240 
2242  rz_return_if_fail(fcn);
2244 }
2245 
2246 typedef struct {
2248  HtUP *visited;
2249 } BlockRecurseCtx;
2250 
2251 static bool mark_as_visited(RzAnalysisBlock *bb, void *user) {
2252  BlockRecurseCtx *ctx = user;
2253  ht_up_insert(ctx->visited, bb->addr, NULL);
2254  return true;
2255 }
2256 
2257 static bool analize_addr_cb(ut64 addr, void *user) {
2258  BlockRecurseCtx *ctx = user;
2259  RzAnalysis *analysis = ctx->fcn->analysis;
2260  RzAnalysisBlock *existing_bb = rz_analysis_get_block_at(analysis, addr);
2261  if (!existing_bb || !rz_list_contains(ctx->fcn->bbs, existing_bb)) {
2262  int old_len = rz_list_length(ctx->fcn->bbs);
2263  analyze_function_locally(ctx->fcn->analysis, ctx->fcn, addr);
2264  if (old_len != rz_list_length(ctx->fcn->bbs)) {
2266  }
2267  }
2268  ht_up_insert(ctx->visited, addr, NULL);
2269  return true;
2270 }
2271 
2272 static bool analize_descendents(RzAnalysisBlock *bb, void *user) {
2274 }
2275 
2276 static void free_ht_up(HtUPKv *kv) {
2277  ht_up_free((HtUP *)kv->value);
2278 }
2279 
2281  RzAnalysis *analysis = fcn->analysis;
2282  ut64 cur_addr;
2283  int opsz;
2284  from = align ? from - (from % align) : from;
2285  to = align ? RZ_ROUND(to, align) : to;
2286  if (UT64_SUB_OVFCHK(to, from)) {
2287  return;
2288  }
2289  ut64 len = to - from;
2290  ut8 *buf = malloc(len);
2291  if (!buf) {
2292  return;
2293  }
2294  if (analysis->iob.read_at(analysis->iob.io, from, buf, len) < len) {
2295  return;
2296  }
2297  for (cur_addr = from; cur_addr < to; cur_addr += opsz, len -= opsz) {
2298  RzAnalysisOp op;
2299  int ret = rz_analysis_op(analysis->coreb.core, &op, cur_addr, buf, len, RZ_ANALYSIS_OP_MASK_ESIL | RZ_ANALYSIS_OP_MASK_VAL);
2300  if (ret < 1 || op.size < 1) {
2302  break;
2303  }
2304  opsz = op.size;
2305  rz_analysis_extract_vars(analysis, fcn, &op);
2307  }
2308  free(buf);
2309 }
2310 
2311 // Clear function variable acesses inside in a block
2313  int i;
2314  if (rz_pvector_empty(&fcn->vars)) {
2315  return;
2316  }
2317  for (i = 0; i < bb->ninstr; i++) {
2319  if (addr < from) {
2320  continue;
2321  }
2322  if (addr >= to || addr == UT64_MAX) {
2323  break;
2324  }
2326  if (vars) {
2327  RzPVector *vars_clone = (RzPVector *)rz_vector_clone((RzVector *)vars);
2328  void **v;
2329  rz_pvector_foreach (vars_clone, v) {
2331  }
2332  rz_pvector_clear(vars_clone);
2333  }
2334  }
2335 }
2336 
2337 static void update_analysis(RzAnalysis *analysis, RzList *fcns, HtUP *reachable) {
2338  RzListIter *it, *it2, *tmp;
2339  RzAnalysisFunction *fcn;
2340  bool old_jmpmid = analysis->opt.jmpmid;
2341  analysis->opt.jmpmid = true;
2343  rz_list_foreach (fcns, it, fcn) {
2344  // Recurse through blocks of function, mark reachable,
2345  // analyze edges that don't have a block
2346  RzAnalysisBlock *bb = rz_analysis_get_block_at(analysis, fcn->addr);
2347  if (!bb) {
2348  analyze_function_locally(analysis, fcn, fcn->addr);
2349  bb = rz_analysis_get_block_at(analysis, fcn->addr);
2350  if (!bb) {
2351  continue;
2352  }
2353  }
2354  HtUP *ht = ht_up_new0();
2355  ht_up_insert(ht, bb->addr, NULL);
2356  BlockRecurseCtx ctx = { fcn, ht };
2358 
2359  // Remove non-reachable blocks
2360  rz_list_foreach_safe (fcn->bbs, it2, tmp, bb) {
2361  if (ht_up_find_kv(ht, bb->addr, NULL)) {
2362  continue;
2363  }
2364  HtUP *o_visited = ht_up_find(reachable, fcn->addr, NULL);
2365  if (!ht_up_find_kv(o_visited, bb->addr, NULL)) {
2366  // Avoid removing blocks that were already not reachable
2367  continue;
2368  }
2369  fcn->ninstr -= bb->ninstr;
2371  }
2372 
2373  RzList *bbs = rz_list_clone(fcn->bbs);
2376  rz_list_free(bbs);
2377  }
2378  analysis->opt.jmpmid = old_jmpmid;
2379 }
2380 
2381 static void calc_reachable_and_remove_block(RzList *fcns, RzAnalysisFunction *fcn, RzAnalysisBlock *bb, HtUP *reachable) {
2382  clear_bb_vars(fcn, bb, bb->addr, bb->addr + bb->size);
2383  if (!rz_list_contains(fcns, fcn)) {
2384  rz_list_append(fcns, fcn);
2385 
2386  // Calculate reachable blocks from the start of function
2387  HtUP *ht = ht_up_new0();
2388  BlockRecurseCtx ctx = { fcn, ht };
2390  ht_up_insert(reachable, fcn->addr, ht);
2391  }
2392  fcn->ninstr -= bb->ninstr;
2394 }
2395 
2397  rz_return_if_fail(analysis);
2398  RzListIter *it, *it2, *tmp;
2399  RzAnalysisBlock *bb;
2400  RzAnalysisFunction *fcn;
2402  if (rz_list_empty(blocks)) {
2404  return;
2405  }
2406  RzList *fcns = rz_list_new();
2407  HtUP *reachable = ht_up_new(NULL, free_ht_up, NULL);
2408  const int align = rz_analysis_archinfo(analysis, RZ_ANALYSIS_ARCHINFO_ALIGN);
2409  const ut64 end_write = addr + size;
2410 
2411  rz_list_foreach (blocks, it, bb) {
2412  if (!rz_analysis_block_was_modified(bb)) {
2413  continue;
2414  }
2415  rz_list_foreach_safe (bb->fcns, it2, tmp, fcn) {
2416  if (align > 1) {
2417  if ((end_write < rz_analysis_block_get_op_addr(bb, bb->ninstr - 1)) && (!bb->switch_op || end_write < bb->switch_op->addr)) {
2418  // Special case when instructions are aligned and we don't
2419  // need to worry about a write messing with the jump instructions
2420  clear_bb_vars(fcn, bb, addr > bb->addr ? addr : bb->addr, end_write);
2421  update_varz_analysisysis(fcn, align, addr > bb->addr ? addr : bb->addr, end_write);
2423  continue;
2424  }
2425  }
2426  calc_reachable_and_remove_block(fcns, fcn, bb, reachable);
2427  }
2428  }
2429  rz_list_free(blocks); // This will call rz_analysis_block_unref to actually remove blocks from RzAnalysis
2430  update_analysis(analysis, fcns, reachable);
2431  ht_up_free(reachable);
2432  rz_list_free(fcns);
2433 }
2434 
2436  rz_return_if_fail(fcn);
2437  RzListIter *it, *it2, *tmp, *tmp2;
2438  RzAnalysisBlock *bb;
2440  RzList *fcns = rz_list_new();
2441  HtUP *reachable = ht_up_new(NULL, free_ht_up, NULL);
2442  rz_list_foreach_safe (fcn->bbs, it, tmp, bb) {
2444  rz_list_foreach_safe (bb->fcns, it2, tmp2, f) {
2445  calc_reachable_and_remove_block(fcns, f, bb, reachable);
2446  }
2447  }
2448  }
2449  update_analysis(fcn->analysis, fcns, reachable);
2450  ht_up_free(reachable);
2451  rz_list_free(fcns);
2452 }
2453 
2461  if (!a || !fcn) {
2462  return 0;
2463  }
2464  void **it;
2465  size_t count = 0;
2466  rz_pvector_foreach (&fcn->vars, it) {
2467  RzAnalysisVar *var = *it;
2468  if (var->isarg) {
2469  count++;
2470  }
2471  }
2472  return count;
2473 }
2474 
2482  if (!a || !fcn) {
2483  return NULL;
2484  }
2486  if (!tmp) {
2487  return NULL;
2488  }
2489  RzAnalysisVar *var;
2490  void **it;
2491  int rarg_idx = 0;
2492  // Resort the pvector to order "reg_arg - stack_arg"
2493  rz_pvector_foreach (&fcn->vars, it) {
2494  var = *it;
2495  if (var->kind == RZ_ANALYSIS_VAR_KIND_REG) {
2496  rz_pvector_insert(tmp, rarg_idx++, var);
2497  } else {
2498  rz_pvector_push(tmp, var);
2499  }
2500  }
2501 
2503  if (!args) {
2505  return NULL;
2506  }
2507  rz_pvector_foreach (tmp, it) {
2508  var = *it;
2509  if (var->isarg) {
2510  int argnum;
2511  if (var->kind == RZ_ANALYSIS_VAR_KIND_REG) {
2512  argnum = rz_analysis_var_get_argnum(var);
2513  if (argnum < 0) {
2514  RZ_LOG_INFO("%s : arg \"%s\" has wrong position: %d\n", fcn->name, var->name, argnum);
2515  continue;
2516  }
2517  } else {
2518  argnum = fcn->argnum;
2519  }
2520  // pvector api is a bit ugly here, essentially we make a (possibly sparse) array
2521  // where each var is assigned at its argnum
2522  if (argnum >= rz_pvector_len(args)) {
2523  if (!rz_pvector_reserve(args, argnum + 1)) {
2524  goto cleanup;
2525  }
2526  while (argnum >= rz_pvector_len(args)) {
2528  }
2529  }
2530  rz_pvector_set(args, argnum, var);
2531  fcn->argnum++;
2532  }
2533  }
2534 cleanup:
2536  return args;
2537 }
2538 
2539 static int typecmp(const void *a, const void *b) {
2540  const RzType *t1 = a;
2541  const RzType *t2 = b;
2542  return !rz_types_equal(t1, t2);
2543 }
2544 
2546  RzListIter *iter;
2547  RzAnalysisVar *var;
2548  RzList *list = rz_analysis_var_all_list(analysis, fcn);
2549  RzList *type_used = rz_list_new();
2550  rz_list_foreach (list, iter, var) {
2551  rz_list_append(type_used, var->type);
2552  }
2553  RzList *uniq = rz_list_uniq(type_used, typecmp);
2554  rz_list_free(type_used);
2555  rz_list_free(list);
2556  return uniq;
2557 }
2558 
2569  rz_return_val_if_fail(analysis && f, NULL);
2570  // Check first if there is a match with some pre-existing RzCallable type in the database
2571  char *shortname = rz_analysis_function_name_guess(analysis->typedb, f->name);
2572  if (!shortname) {
2573  shortname = strdup(f->name);
2574  }
2575  // At this point the `callable` pointer is *borrowed*
2576  RzCallable *callable = rz_type_func_get(analysis->typedb, shortname);
2577  free(shortname);
2578  if (callable) {
2579  // TODO: Decide what to do if there is a mismatch between type
2580  // stored in the RzTypeDB database and the actual type of the
2581  // RzAnalysisFunction
2582  return rz_type_callable_clone(callable);
2583  }
2584  return NULL;
2585 }
2586 
2597  // TODO: Figure out if we should use shortname or a fullname here
2598  RzCallable *callable = rz_type_func_new(analysis->typedb, f->name, NULL);
2599  if (!callable) {
2600  return NULL;
2601  }
2602  return callable;
2603 }
2604 
2616  if (f->ret_type) {
2617  (*callable)->ret = rz_type_clone(f->ret_type);
2618  }
2619 }
2620 
2633  RzPVector *args = rz_analysis_function_args(analysis, f);
2634  if (!args || rz_pvector_empty(args)) {
2636  return true;
2637  }
2638  void **it;
2639  rz_pvector_foreach (args, it) {
2640  RzAnalysisVar *var = *it;
2641  if (!var) {
2642  // TODO: maybe create a stub void arg here?
2643  continue;
2644  }
2645  RzType *cloned_type = rz_type_clone(var->type);
2646  if (!cloned_type) {
2648  rz_type_callable_free(*callable);
2649  RZ_LOG_ERROR("Cannot parse function's argument type\n");
2650  return false;
2651  }
2652  RzCallableArg *arg = rz_type_callable_arg_new(analysis->typedb, var->name, cloned_type);
2653  if (!arg) {
2655  rz_type_callable_free(*callable);
2656  RZ_LOG_ERROR("Cannot create callable argument\n");
2657  return false;
2658  }
2659  rz_type_callable_arg_add(*callable, arg);
2660  }
2662  return true;
2663 }
2664 
2677  RzCallable *callable = rz_analysis_function_clone_type(analysis, f);
2678  if (!callable) {
2679  // If there is no match - create a new one.
2680  callable = rz_analysis_function_create_type(analysis, f);
2681  if (!callable) {
2682  return NULL;
2683  }
2684  // Derive retvar and args from that function
2686  if (!rz_analysis_function_derive_args(analysis, f, &callable)) {
2687  return NULL;
2688  }
2689  }
2690  return callable;
2691 }
size_t len
Definition: 6502dis.c:15
ut8 op
Definition: 6502dis.c:13
RZ_API RZ_OWN RzAnalysisDiff * rz_analysis_diff_new(void)
Definition: diff.c:9
RZ_API RZ_OWN char * rz_analysis_function_name_guess(RzTypeDB *typedb, RZ_NONNULL char *name)
Checks if varions function name variations present in the database.
Definition: function.c:458
RZ_API void rz_analysis_function_add_block(RzAnalysisFunction *fcn, RzAnalysisBlock *bb)
Definition: function.c:264
RZ_API RzAnalysisFunction * rz_analysis_get_function_at(RzAnalysis *analysis, ut64 addr)
Definition: function.c:184
RZ_API RzList * rz_analysis_get_functions_in(RzAnalysis *analysis, ut64 addr)
Definition: function.c:20
RZ_API ut64 rz_analysis_function_linear_size(RzAnalysisFunction *fcn)
Definition: function.c:318
RZ_API void rz_analysis_function_remove_block(RzAnalysisFunction *fcn, RzAnalysisBlock *bb)
Definition: function.c:286
RZ_API bool rz_analysis_function_delete(RzAnalysisFunction *fcn)
Definition: function.c:180
RZ_API bool rz_analysis_function_contains(RzAnalysisFunction *fcn, ut64 addr)
Definition: function.c:361
RZ_API bool rz_analysis_noreturn_at_addr(RzAnalysis *analysis, ut64 addr)
Definition: analysis.c:557
RZ_API bool rz_analysis_is_prelude(RzAnalysis *analysis, const ut8 *data, int len)
Definition: analysis.c:676
RZ_API int rz_analysis_archinfo(RzAnalysis *analysis, int query)
Definition: analysis.c:449
RZ_API bool rz_analysis_noreturn_at(RzAnalysis *analysis, ut64 addr)
Definition: analysis.c:597
#define jmp
static bool isValid(ut64 addr)
Definition: analysis_objc.c:51
lzma_index ** i
Definition: index.h:629
lzma_index * src
Definition: index.h:567
static RzILOpEffect * mov(cs_insn *insn, bool is_thumb)
Definition: arm_il32.c:351
ut16 val
Definition: armass64_const.h:6
static mcore_handle handle
Definition: asm_mcore.c:8
lsl lsr asr ror lsl lsr asr ror lsl lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror c3
int jump(int a, int b)
Definition: bcj_test.c:35
int call(int a, int b)
Definition: bcj_test.c:25
static char * signature(RzBinFile *bf, bool json)
Definition: bin_pe.c:117
RZ_API void rz_analysis_block_set_size(RzAnalysisBlock *block, ut64 size)
Definition: block.c:194
RZ_API bool rz_analysis_block_was_modified(RzAnalysisBlock *block)
Definition: block.c:680
RZ_API void rz_analysis_delete_block(RzAnalysisBlock *bb)
Definition: block.c:186
RZ_API bool rz_analysis_block_relocate(RzAnalysisBlock *block, ut64 addr, ut64 size)
Definition: block.c:213
RZ_API bool rz_analysis_block_set_op_offset(RzAnalysisBlock *block, size_t i, ut16 v)
Definition: block.c:1027
RZ_API void rz_analysis_block_ref(RzAnalysisBlock *bb)
Definition: block.c:40
RZ_API void rz_analysis_block_update_hash(RzAnalysisBlock *block)
Definition: block.c:698
RZ_API RzAnalysisBlock * rz_analysis_get_block_at(RzAnalysis *analysis, ut64 addr)
Definition: block.c:90
RZ_API bool rz_analysis_block_recurse_followthrough(RzAnalysisBlock *block, RzAnalysisBlockCb cb, void *user)
Definition: block.c:458
RZ_API ut64 rz_analysis_block_get_op_addr(RzAnalysisBlock *block, size_t i)
Definition: block.c:1016
RZ_API void rz_analysis_block_unref(RzAnalysisBlock *bb)
Definition: block.c:370
RZ_API RzList * rz_analysis_get_blocks_in(RzAnalysis *analysis, ut64 addr)
Definition: block.c:133
RZ_API RzAnalysisBlock * rz_analysis_create_block(RzAnalysis *analysis, ut64 addr, ut64 size)
Definition: block.c:174
RZ_API RzList * rz_analysis_get_blocks_intersect(RzAnalysis *analysis, ut64 addr, ut64 size)
Definition: block.c:165
RZ_API RzAnalysisBlock * rz_analysis_block_split(RzAnalysisBlock *bbi, ut64 addr)
Definition: block.c:255
RZ_API bool rz_analysis_block_recurse(RzAnalysisBlock *block, RzAnalysisBlockCb cb, void *user)
Definition: block.c:430
RZ_API bool rz_analysis_block_successor_addrs_foreach(RzAnalysisBlock *block, RzAnalysisAddrCb cb, void *user)
Definition: block.c:384
RZ_API ut16 rz_analysis_block_get_op_offset(RzAnalysisBlock *block, size_t i)
Definition: block.c:1006
RZ_API void rz_analysis_block_analyze_ops(RzAnalysisBlock *block)
Definition: block.c:1084
RZ_API bool rz_analysis_block_op_starts_at(RzAnalysisBlock *bb, ut64 addr)
Definition: block.c:582
RZ_API void rz_analysis_block_automerge(RzList *blocks)
Definition: block.c:892
RZ_API RZ_OWN RzType * rz_type_parse_string_declaration_single(RzTypeParser *parser, const char *code, char **error_msg)
Parses the single C type declaration.
Definition: c_cpp_parser.c:411
#define P
RZ_API RzAnalysisCond * rz_analysis_cond_new_from_op(RzAnalysisOp *op)
Definition: cond.c:92
RZ_API void rz_analysis_cond_free(RzAnalysisCond *c)
Definition: cond.c:19
RZ_API bool rz_cons_is_breaked(void)
Definition: cons.c:373
#define RZ_API
#define NULL
Definition: cris-opc.c:27
#define r
Definition: crypto_rc6.c:12
cs_arch arch
Definition: cstool.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
uint16_t ut16
uint32_t ut32
const char * v
Definition: dsignal.c:12
size_t map(int syms, int left, int len)
Definition: enough.c:237
void cleanup(void)
Definition: enough.c:244
#define MAX_FLG_NAME_SIZE
Definition: fcn.c:19
RZ_API RzAnalysisBlock * rz_analysis_fcn_bbget_at(RzAnalysis *analysis, RzAnalysisFunction *fcn, ut64 addr)
Definition: fcn.c:2063
#define JMPTBL_LEA_SEARCH_SZ
Definition: fcn.c:14
RZ_API RZ_OWN RzPVector * rz_analysis_function_args(RzAnalysis *a, RzAnalysisFunction *fcn)
Returns vector of all function arguments.
Definition: fcn.c:2481
static void free_leaddr_pair(void *pair)
Definition: fcn.c:353
static ut64 try_get_cmpval_from_parents(RzAnalysis *analysis, RzAnalysisFunction *fcn, RzAnalysisBlock *my_bb, const char *cmp_reg)
Definition: fcn.c:263
RZ_API bool rz_analysis_function_derive_args(RzAnalysis *analysis, RzAnalysisFunction *f, RzCallable **callable)
Sets the RzCallable args for the given function.
Definition: fcn.c:2632
RZ_API void rz_analysis_fcn_invalidate_read_ahead_cache(void)
Definition: fcn.c:84
static void check_purity(HtUP *ht, RzAnalysisFunction *fcn)
Definition: fcn.c:319
RZ_API RzAnalysisFunction * rz_analysis_fcn_next(RzAnalysis *analysis, ut64 addr)
Definition: fcn.c:2015
RZ_API RZ_OWN RzCallable * rz_analysis_function_clone_type(RzAnalysis *analysis, const RzAnalysisFunction *f)
Clones the RzCallable type for the given function.
Definition: fcn.c:2568
static RzAnalysisBlock * fcn_append_basic_block(RzAnalysis *analysis, RzAnalysisFunction *fcn, ut64 addr)
Definition: fcn.c:128
static void fcn_takeover_block_recursive(RzAnalysisFunction *fcn, RzAnalysisBlock *start_block)
Definition: fcn.c:474
static void set_bb_branches(RZ_OUT RzAnalysisBlock *bb, const ut64 jump, const ut64 fail)
Definition: fcn.c:542
RZ_API RZ_OWN RzCallable * rz_analysis_function_create_type(RzAnalysis *analysis, RzAnalysisFunction *f)
Creates the RzCallable type for the given function.
Definition: fcn.c:2596
#define MAX_FCN_SIZE
Definition: fcn.c:23
RZ_API int rz_analysis_function_resize(RzAnalysisFunction *fcn, int newsize)
Definition: fcn.c:90
#define MAX_SCAN_SIZE
Definition: fcn.c:16
static RzAnalysisBBEndCause run_basic_block_analysis(RzAnalysisTaskItem *item, RzVector *tasks)
Analyses the given task item item for branches.
Definition: fcn.c:559
static int analyze_function_locally(RzAnalysis *analysis, RzAnalysisFunction *fcn, ut64 address)
Definition: fcn.c:529
RZ_API int rz_analysis_run_tasks(RZ_NONNULL RzVector *tasks)
Runs analysis on the task items.
Definition: fcn.c:1509
static void update_varz_analysisysis(RzAnalysisFunction *fcn, int align, ut64 from, ut64 to)
Definition: fcn.c:2280
static bool analize_addr_cb(ut64 addr, void *user)
Definition: fcn.c:2257
RZ_API int rz_analysis_fcn_del(RzAnalysis *a, ut64 addr)
Definition: fcn.c:1675
static void __analysis_fcn_check_bp_use(RzAnalysis *analysis, RzAnalysisFunction *fcn)
Definition: fcn.c:2165
static ut64 cache_addr
Definition: fcn.c:49
static void calc_reachable_and_remove_block(RzList *fcns, RzAnalysisFunction *fcn, RzAnalysisBlock *bb, HtUP *reachable)
Definition: fcn.c:2381
static bool purity_checked(HtUP *ht, RzAnalysisFunction *fcn)
Definition: fcn.c:306
static bool mark_as_visited(RzAnalysisBlock *bb, void *user)
Definition: fcn.c:2251
RZ_API ut32 rz_analysis_function_cost(RzAnalysisFunction *fcn)
Definition: fcn.c:2080
RZ_API int rz_analysis_function_loops(RzAnalysisFunction *fcn)
Definition: fcn.c:1784
RZ_DEPRECATE RZ_API RzAnalysisFunction * rz_analysis_get_fcn_in(RzAnalysis *analysis, ut64 addr, int type)
Definition: fcn.c:1687
RZ_API bool rz_analysis_function_purity(RzAnalysisFunction *fcn)
Definition: fcn.c:2136
static bool isInvalidMemory(RzAnalysis *analysis, const ut8 *buf, int len)
Definition: fcn.c:143
RZ_API char * rz_analysis_function_get_json(RzAnalysisFunction *function)
Definition: fcn.c:1855
RZ_API void rz_analysis_function_derive_return_type(RzAnalysisFunction *f, RzCallable **callable)
Sets the RzCallable return type for the given function.
Definition: fcn.c:2615
RZ_API RzAnalysisFunction * rz_analysis_get_function_byname(RzAnalysis *a, const char *name)
Definition: fcn.c:1729
static bool op_is_set_bp(RzAnalysisOp *op, const char *bp_reg, const char *sp_reg)
Definition: fcn.c:516
static bool is_delta_pointer_table(RzAnalysis *analysis, ut64 addr, ut64 lea_ptr, ut64 *jmptbl_addr, ut64 *casetbl_addr, RzAnalysisOp *jmp_aop)
Definition: fcn.c:166
RZ_API bool rz_analysis_task_item_new(RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzVector *tasks, RZ_NONNULL RzAnalysisFunction *fcn, RZ_NULLABLE RzAnalysisBlock *block, ut64 address)
Adds a new task item to the tasks parameter.
Definition: fcn.c:1488
RZ_API bool rz_analysis_fcn_add_bb(RzAnalysis *a, RzAnalysisFunction *fcn, ut64 addr, ut64 size, ut64 jump, ut64 fail, RZ_BORROW RzAnalysisDiff *diff)
Definition: fcn.c:1739
static bool isSymbolNextInstruction(RzAnalysis *analysis, RzAnalysisOp *op)
Definition: fcn.c:159
RZ_DEPRECATE RZ_API RzAnalysisFunction * rz_analysis_get_fcn_in_bounds(RzAnalysis *analysis, ut64 addr, int type)
Definition: fcn.c:1708
RZ_API int rz_analysis_function_count_edges(const RzAnalysisFunction *fcn, RZ_NULLABLE int *ebbs)
Definition: fcn.c:2113
static RzAnalysisBlock * bbget(RzAnalysis *analysis, ut64 addr, bool jumpmid)
Definition: fcn.c:359
RZ_API bool rz_analysis_function_set_type_str(RzAnalysis *a, RZ_NONNULL RzAnalysisFunction *f, RZ_NONNULL const char *sig)
Parses the function type and sets it for the given function.
Definition: fcn.c:1985
static bool analize_descendents(RzAnalysisBlock *bb, void *user)
Definition: fcn.c:2272
static void analyze_retpoline(RzAnalysis *analysis, RzAnalysisOp *op)
Definition: fcn.c:506
static void free_ht_up(HtUPKv *kv)
Definition: fcn.c:2276
RZ_API int rz_analysis_fcn_count(RzAnalysis *analysis, ut64 from, ut64 to)
Definition: fcn.c:2028
static bool fcn_takeover_block_recursive_followthrough_cb(RzAnalysisBlock *block, void *user)
Definition: fcn.c:412
#define gotoBeach(x)
Definition: fcn.c:139
static void clear_bb_vars(RzAnalysisFunction *fcn, RzAnalysisBlock *bb, ut64 from, ut64 to)
Definition: fcn.c:2312
RZ_API int rz_analysis_function_get_arg_count(RzAnalysis *analysis, RzAnalysisFunction *f)
Gets the RzCallable's arg count for the given function.
Definition: fcn.c:1845
static int skip_hp(RzAnalysis *analysis, RzAnalysisFunction *fcn, RzAnalysisOp *op, RzAnalysisBlock *bb, ut64 addr, char *tmp_buf, int oplen, int un_idx, int *idx)
Definition: fcn.c:288
RZ_API size_t rz_analysis_function_arg_count(RzAnalysis *a, RzAnalysisFunction *fcn)
Returns the argument count of a function.
Definition: fcn.c:2460
static int typecmp(const void *a, const void *b)
Definition: fcn.c:2539
struct fcn_tree_iter_t FcnTreeIter
RZ_API void rz_analysis_function_update_analysis(RzAnalysisFunction *fcn)
Definition: fcn.c:2435
static int read_ahead(RzAnalysis *analysis, ut64 addr, ut8 *buf, int len)
Definition: fcn.c:52
RZ_API void rz_analysis_del_jmprefs(RzAnalysis *analysis, RzAnalysisFunction *fcn)
Definition: fcn.c:1592
RZ_API void rz_analysis_update_analysis_range(RzAnalysis *analysis, ut64 addr, int size)
Definition: fcn.c:2396
RZ_API const char * rz_analysis_fcntype_tostring(int type)
Definition: fcn.c:35
static bool does_arch_destroys_dst(const char *arch)
Definition: fcn.c:525
RZ_API int rz_analysis_fcn(RzAnalysis *analysis, RzAnalysisFunction *fcn, ut64 addr, ut64 len, int reftype)
Definition: fcn.c:1606
RZ_API bool rz_analysis_check_fcn(RzAnalysis *analysis, ut8 *buf, ut16 bufsz, ut64 addr, ut64 low, ut64 high)
Definition: fcn.c:1538
RZ_API void rz_analysis_function_check_bp_use(RzAnalysisFunction *fcn)
Definition: fcn.c:2241
RZ_API void rz_analysis_trim_jmprefs(RzAnalysis *analysis, RzAnalysisFunction *fcn)
Definition: fcn.c:1578
static bool can_affect_bp(RzAnalysis *analysis, RzAnalysisOp *op)
Definition: fcn.c:2147
RZ_API RZ_OWN RzCallable * rz_analysis_function_derive_type(RzAnalysis *analysis, RzAnalysisFunction *f)
Derives the RzCallable type for the given function.
Definition: fcn.c:2676
RZ_API RzAnalysisBlock * rz_analysis_fcn_bbget_in(const RzAnalysis *analysis, RzAnalysisFunction *fcn, ut64 addr)
Definition: fcn.c:2042
RZ_API RZ_OWN RzList * rz_analysis_types_from_fcn(RzAnalysis *analysis, RzAnalysisFunction *fcn)
Definition: fcn.c:2545
static const char * retpoline_reg(RzAnalysis *analysis, ut64 addr)
Definition: fcn.c:479
static void update_analysis(RzAnalysis *analysis, RzList *fcns, HtUP *reachable)
Definition: fcn.c:2337
static bool regs_exist(RzAnalysisValue *src, RzAnalysisValue *dst)
Definition: fcn.c:282
RZ_API bool rz_analysis_function_set_type(RzAnalysis *a, RZ_NONNULL RzAnalysisFunction *f, RZ_NONNULL RzCallable *callable)
Sets the RzCallable type for the given function.
Definition: fcn.c:1922
RZ_API int rz_analysis_fcn_del_locs(RzAnalysis *analysis, ut64 addr)
Definition: fcn.c:1657
RZ_API int rz_analysis_function_complexity(RzAnalysisFunction *fcn)
Definition: fcn.c:1799
RZ_API RZ_OWN char * rz_analysis_function_get_signature(RZ_NONNULL RzAnalysisFunction *function)
Definition: fcn.c:1895
RZ_API char * sdb_fmt(const char *fmt,...)
Definition: fmt.c:26
RZ_API void rz_analysis_hint_set_bits(RzAnalysis *a, ut64 addr, int bits)
Definition: hint.c:288
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
RZ_API const KEY_TYPE bool * found
Definition: ht_inc.h:130
voidpf void uLong size
Definition: ioapi.h:138
voidpf void * buf
Definition: ioapi.h:138
RZ_API bool rz_analysis_walkthrough_arm_jmptbl_style(RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisFunction *fcn, RZ_NONNULL RzAnalysisBlock *block, RZ_NONNULL RzAnalysisJmpTableParams *params)
Marks for analysis ARM specific jump table cases.
Definition: jmptbl.c:391
RZ_API bool rz_analysis_get_jmptbl_info(RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisFunction *fcn, RZ_NONNULL RzAnalysisBlock *block, ut64 jmp_address, RZ_NONNULL RzAnalysisJmpTableParams *params)
Gets some necessary information about a jump table to perform analysis on.
Definition: jmptbl.c:443
RZ_API bool rz_analysis_walkthrough_jmptbl(RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisFunction *fcn, RZ_NONNULL RzAnalysisBlock *block, RZ_NONNULL RzAnalysisJmpTableParams *params)
Marks the jump table cases for analysis.
Definition: jmptbl.c:176
RZ_API bool rz_analysis_get_delta_jmptbl_info(RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisFunction *fcn, ut64 jmp_address, ut64 lea_address, RZ_NONNULL RzAnalysisJmpTableParams *params)
Gets some necessary information about a jump table to perform analysis on.
Definition: jmptbl.c:288
RZ_API bool rz_analysis_walkthrough_casetbl(RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisFunction *fcn, RZ_NONNULL RzAnalysisBlock *block, RZ_NONNULL RzAnalysisJmpTableParams *params)
Marks for analysis jump table cases with a space optimization for multiple cases corresponding to the...
Definition: jmptbl.c:76
snprintf
Definition: kernel.h:364
uint8_t ut8
Definition: lh5801.h:11
return memset(p, 0, total)
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
static void list(RzEgg *egg)
Definition: rz-gg.c:52
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_OWN RzList * rz_list_uniq(RZ_NONNULL const RzList *list, RZ_NONNULL RzListComparator cmp)
Returns a new RzList which contains only unique values.
Definition: list.c:756
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_OWN RzList * rz_list_clone(RZ_NONNULL const RzList *list)
Shallow copies of the list (but doesn't free its elements)
Definition: list.c:496
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_first(RZ_NONNULL const RzList *list)
Returns the first element of the list.
Definition: list.c:77
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
void * malloc(size_t size)
Definition: malloc.c:123
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 pid
Definition: sflib.h:64
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")
char * dst
Definition: lz4.h:724
@ RZ_ABS
static uint32_t const uint8_t uint32_t uint32_t limit
Definition: memcmplen.h:45
RZ_API bool rz_meta_set(RzAnalysis *a, RzAnalysisMetaType type, ut64 addr, ut64 size, const char *str)
Definition: meta.c:191
RZ_API RzPVector * rz_meta_get_all_in(RzAnalysis *a, ut64 at, RzAnalysisMetaType type)
Definition: meta.c:223
int args
Definition: mipsasm.c:18
int n
Definition: mipsasm.c:19
int type
Definition: mipsasm.c:17
int idx
Definition: setup.py:197
RZ_API bool rz_analysis_op_fini(RzAnalysisOp *op)
Definition: op.c:37
RZ_API int rz_analysis_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, const ut8 *data, int len, RzAnalysisOpMask mask)
Definition: op.c:96
int off
Definition: pal.c:13
static int is_arm(RzBinPEObj *bin)
Definition: pe_info.c:12
RZ_API RzRegItem * rz_reg_get(RzReg *reg, const char *name, int type)
Definition: reg.c:344
RZ_API const char * rz_reg_get_name(RzReg *reg, int role)
Definition: reg.c:147
RZ_API int rz_reg_get_name_idx(const char *type)
Definition: reg.c:102
static void repeat(struct parse *, sopno, int, int)
Definition: regcomp.c:1155
#define RZ_ANALYSIS_ARCHINFO_ALIGN
Definition: rz_analysis.h:100
RzAnalysisBBEndCause
Definition: rz_analysis.h:472
@ RZ_ANALYSIS_RET_BRANCH
Definition: rz_analysis.h:476
@ RZ_ANALYSIS_RET_COND
Definition: rz_analysis.h:477
@ RZ_ANALYSIS_RET_ERROR
Definition: rz_analysis.h:474
@ RZ_ANALYSIS_RET_NOP
Definition: rz_analysis.h:473
@ RZ_ANALYSIS_RET_END
Definition: rz_analysis.h:475
@ RZ_ANALYSIS_FCN_TYPE_INT
Definition: rz_analysis.h:197
@ RZ_ANALYSIS_FCN_TYPE_SYM
Definition: rz_analysis.h:195
@ RZ_ANALYSIS_FCN_TYPE_IMP
Definition: rz_analysis.h:196
@ RZ_ANALYSIS_FCN_TYPE_LOC
Definition: rz_analysis.h:194
@ RZ_ANALYSIS_FCN_TYPE_NULL
Definition: rz_analysis.h:192
@ RZ_ANALYSIS_FCN_TYPE_ROOT
Definition: rz_analysis.h:198
@ RZ_ANALYSIS_FCN_TYPE_FCN
Definition: rz_analysis.h:193
@ RZ_ANALYSIS_STACK_RESET
Definition: rz_analysis.h:460
@ RZ_ANALYSIS_STACK_INC
Definition: rz_analysis.h:457
@ RZ_ANALYSIS_XREF_TYPE_CODE
Definition: rz_analysis.h:900
@ RZ_ANALYSIS_XREF_TYPE_CALL
Definition: rz_analysis.h:901
@ RZ_ANALYSIS_XREF_TYPE_DATA
Definition: rz_analysis.h:902
@ RZ_ANALYSIS_OP_FAMILY_PRIV
Definition: rz_analysis.h:316
@ RZ_META_TYPE_ANY
Definition: rz_analysis.h:288
@ RZ_META_TYPE_DATA
Definition: rz_analysis.h:289
@ RZ_META_TYPE_STRING
Definition: rz_analysis.h:291
@ RZ_META_TYPE_FORMAT
Definition: rz_analysis.h:292
@ RZ_ANALYSIS_OP_PREFIX_HWLOOP_END
Definition: rz_analysis.h:353
@ RZ_ANALYSIS_OP_MASK_BASIC
Definition: rz_analysis.h:440
@ RZ_ANALYSIS_OP_MASK_VAL
Definition: rz_analysis.h:442
@ RZ_ANALYSIS_OP_MASK_OPEX
Definition: rz_analysis.h:444
@ RZ_ANALYSIS_OP_MASK_ESIL
Definition: rz_analysis.h:441
@ RZ_ANALYSIS_OP_MASK_HINT
Definition: rz_analysis.h:443
#define RZ_ANALYSIS_OP_TYPE_MASK
Definition: rz_analysis.h:358
@ RZ_ANALYSIS_VAR_KIND_REG
Definition: rz_analysis.h:703
@ RZ_ANALYSIS_VAR_KIND_SPV
Definition: rz_analysis.h:705
@ RZ_ANALYSIS_VAR_KIND_BPV
Definition: rz_analysis.h:704
@ RZ_ANALYSIS_OP_TYPE_CMP
Definition: rz_analysis.h:399
@ RZ_ANALYSIS_OP_TYPE_SUB
Definition: rz_analysis.h:402
@ RZ_ANALYSIS_OP_TYPE_ICALL
Definition: rz_analysis.h:381
@ RZ_ANALYSIS_OP_TYPE_LOAD
Definition: rz_analysis.h:416
@ RZ_ANALYSIS_OP_TYPE_UNK
Definition: rz_analysis.h:388
@ RZ_ANALYSIS_OP_TYPE_ROL
Definition: rz_analysis.h:420
@ RZ_ANALYSIS_OP_TYPE_JMP
Definition: rz_analysis.h:368
@ RZ_ANALYSIS_OP_TYPE_AND
Definition: rz_analysis.h:411
@ RZ_ANALYSIS_OP_TYPE_SAL
Definition: rz_analysis.h:408
@ RZ_ANALYSIS_OP_TYPE_UPUSH
Definition: rz_analysis.h:395
@ RZ_ANALYSIS_OP_TYPE_RPUSH
Definition: rz_analysis.h:396
@ RZ_ANALYSIS_OP_TYPE_UJMP
Definition: rz_analysis.h:369
@ RZ_ANALYSIS_OP_TYPE_IJMP
Definition: rz_analysis.h:371
@ RZ_ANALYSIS_OP_TYPE_MJMP
Definition: rz_analysis.h:375
@ RZ_ANALYSIS_OP_TYPE_ROR
Definition: rz_analysis.h:419
@ RZ_ANALYSIS_OP_TYPE_SAR
Definition: rz_analysis.h:409
@ RZ_ANALYSIS_OP_TYPE_CMOV
Definition: rz_analysis.h:391
@ RZ_ANALYSIS_OP_TYPE_TRAP
Definition: rz_analysis.h:392
@ RZ_ANALYSIS_OP_TYPE_XCHG
Definition: rz_analysis.h:421
@ RZ_ANALYSIS_OP_TYPE_CCALL
Definition: rz_analysis.h:383
@ RZ_ANALYSIS_OP_TYPE_CALL
Definition: rz_analysis.h:378
@ RZ_ANALYSIS_OP_TYPE_ADD
Definition: rz_analysis.h:401
@ RZ_ANALYSIS_OP_TYPE_OR
Definition: rz_analysis.h:410
@ RZ_ANALYSIS_OP_TYPE_REG
Definition: rz_analysis.h:365
@ RZ_ANALYSIS_OP_TYPE_RCJMP
Definition: rz_analysis.h:374
@ RZ_ANALYSIS_OP_TYPE_CRET
Definition: rz_analysis.h:386
@ RZ_ANALYSIS_OP_TYPE_PUSH
Definition: rz_analysis.h:397
@ RZ_ANALYSIS_OP_TYPE_SHR
Definition: rz_analysis.h:406
@ RZ_ANALYSIS_OP_TYPE_IRJMP
Definition: rz_analysis.h:372
@ RZ_ANALYSIS_OP_TYPE_POP
Definition: rz_analysis.h:398
@ RZ_ANALYSIS_OP_TYPE_RJMP
Definition: rz_analysis.h:370
@ RZ_ANALYSIS_OP_TYPE_CJMP
Definition: rz_analysis.h:373
@ RZ_ANALYSIS_OP_TYPE_UCJMP
Definition: rz_analysis.h:377
@ RZ_ANALYSIS_OP_TYPE_MOV
Definition: rz_analysis.h:390
@ RZ_ANALYSIS_OP_TYPE_SHL
Definition: rz_analysis.h:407
@ RZ_ANALYSIS_OP_TYPE_ILL
Definition: rz_analysis.h:387
@ RZ_ANALYSIS_OP_TYPE_UCALL
Definition: rz_analysis.h:379
@ RZ_ANALYSIS_OP_TYPE_NOT
Definition: rz_analysis.h:414
@ RZ_ANALYSIS_OP_TYPE_RET
Definition: rz_analysis.h:385
@ RZ_ANALYSIS_OP_TYPE_NOP
Definition: rz_analysis.h:389
@ RZ_ANALYSIS_OP_TYPE_ACMP
Definition: rz_analysis.h:400
@ RZ_ANALYSIS_OP_TYPE_LEA
Definition: rz_analysis.h:417
@ RZ_ANALYSIS_OP_TYPE_RCALL
Definition: rz_analysis.h:380
@ RZ_ANALYSIS_OP_TYPE_XOR
Definition: rz_analysis.h:412
@ RZ_ANALYSIS_OP_TYPE_MCJMP
Definition: rz_analysis.h:376
@ RZ_ANALYSIS_OP_TYPE_IRCALL
Definition: rz_analysis.h:382
#define rz_warn_if_reached()
Definition: rz_assert.h:29
#define rz_return_if_fail(expr)
Definition: rz_assert.h:100
#define rz_return_val_if_fail(expr, val)
Definition: rz_assert.h:108
static ut32 rz_read_le32(const void *src)
Definition: rz_endian.h:239
#define RZ_LOG_VERBOSE(fmtstr,...)
Definition: rz_log.h:52
#define RZ_LOG_INFO(fmtstr,...)
Definition: rz_log.h:54
#define RZ_LOG_DEBUG(fmtstr,...)
Definition: rz_log.h:49
#define RZ_LOG_ERROR(fmtstr,...)
Definition: rz_log.h:58
RZ_API PJ * pj_new(void)
Definition: pj.c:25
RZ_API PJ * pj_kb(PJ *j, const char *k, bool v)
Definition: pj.c:177
RZ_API char * pj_drain(PJ *j)
Definition: pj.c:50
RZ_API PJ * pj_k(PJ *j, const char *k)
Definition: pj.c:104
RZ_API PJ * pj_end(PJ *j)
Definition: pj.c:87
RZ_API PJ * pj_o(PJ *j)
Definition: pj.c:75
RZ_API PJ * pj_ks(PJ *j, const char *k, const char *v)
Definition: pj.c:170
RZ_API PJ * pj_a(PJ *j)
Definition: pj.c:81
#define RZ_RBTREE_MAX_HEIGHT
Definition: rz_rbtree.h:16
@ RZ_REG_TYPE_GPR
Definition: rz_reg.h:21
@ RZ_REG_NAME_SP
Definition: rz_reg.h:44
@ RZ_REG_NAME_BP
Definition: rz_reg.h:46
RZ_API char * rz_str_newf(const char *fmt,...) RZ_PRINTF_CHECK(1
RZ_API const char * rz_str_bool(int b)
Definition: str.c:3896
RZ_API char * rz_str_replace(char *str, const char *key, const char *val, int g)
Definition: str.c:1110
RZ_API bool rz_str_startswith(RZ_NONNULL const char *str, RZ_NONNULL const char *needle)
Checks if a string starts with a specifc sequence of characters (case sensitive)
Definition: str.c:3286
RZ_API int rz_str_cmp(const char *dst, const char *orig, int len)
Definition: str.c:974
RZ_API bool rz_str_endswith(RZ_NONNULL const char *str, RZ_NONNULL const char *needle)
Checks if a string ends with a specifc sequence of characters (case sensitive)
Definition: str.c:3329
RZ_API char * rz_strbuf_get(RzStrBuf *sb)
Definition: strbuf.c:321
RZ_API int rz_sys_usleep(int usecs)
Sleep for usecs microseconds.
Definition: sys.c:317
@ RZ_TYPE_COND_HI
Unsigned higher Greater than, or unordered.
Definition: rz_type.h:197
@ RZ_TYPE_COND_GT
Greater than.
Definition: rz_type.h:187
@ RZ_TYPE_COND_EXCEPTION
Definition: rz_type.h:203
@ RZ_TYPE_KIND_CALLABLE
Definition: rz_type.h:131
#define PFMT64d
Definition: rz_types.h:394
#define RZ_NULLABLE
Definition: rz_types.h:65
#define RZ_OWN
Definition: rz_types.h:62
#define RZ_OUT
Definition: rz_types.h:51
#define RZ_NONNULL
Definition: rz_types.h:64
#define RZ_NEW(x)
Definition: rz_types.h:285
#define PFMT64u
Definition: rz_types.h:395
#define RZ_FREE(x)
Definition: rz_types.h:369
#define PFMT64x
Definition: rz_types.h:393
#define RZ_BORROW
Definition: rz_types.h:63
#define RZ_DEPRECATE
Definition: rz_types.h:66
#define RZ_ROUND(x, y)
#define RZ_MIN(x, y)
#define st64
Definition: rz_types_base.h:10
#define UT32_MAX
Definition: rz_types_base.h:99
#define UT64_MAX
Definition: rz_types_base.h:86
#define st32
Definition: rz_types_base.h:12
#define UT64_SUB_OVFCHK(a, b)
#define UT64_ADD_OVFCHK(x, y)
RZ_API void rz_vector_pop(RzVector *vec, void *into)
Definition: vector.c:184
static void ** rz_pvector_reserve(RzPVector *vec, size_t capacity)
Definition: rz_vector.h:312
static void rz_pvector_set(RzPVector *vec, size_t index, void *e)
Definition: rz_vector.h:241
static void ** rz_pvector_index_ptr(RzPVector *vec, size_t index)
Definition: rz_vector.h:251
static size_t rz_pvector_len(const RzPVector *vec)
Definition: rz_vector.h:231
RZ_API void * rz_vector_push(RzVector *vec, void *x)
Definition: vector.c:197
RZ_API RzPVector * rz_pvector_new(RzPVectorFree free)
Definition: vector.c:302
static bool rz_pvector_empty(RzPVector *vec)
Definition: rz_vector.h:246
#define rz_vector_foreach(vec, it)
Definition: rz_vector.h:169
static void ** rz_pvector_push(RzPVector *vec, void *x)
Definition: rz_vector.h:300
RZ_API void rz_vector_fini(RzVector *vec)
Definition: vector.c:61
RZ_API void rz_pvector_free(RzPVector *vec)
Definition: vector.c:336
RZ_API RzVector * rz_vector_clone(RzVector *vec)
Definition: vector.c:101
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 void rz_pvector_clear(RzPVector *vec)
Definition: vector.c:326
#define rz_pvector_foreach(vec, it)
Definition: rz_vector.h:334
static void ** rz_pvector_insert(RzPVector *vec, size_t index, void *x)
Definition: rz_vector.h:284
RZ_API SetU * set_u_new(void)
Definition: set.c:30
RZ_API void set_u_free(SetU *s)
Definition: set.c:46
RZ_API void set_u_add(SetU *s, ut64 u)
Definition: set.c:34
RZ_API bool set_u_contains(SetU *s, ut64 u)
Definition: set.c:38
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
#define f(i)
Definition: sha256.c:46
#define a(i)
Definition: sha256.c:41
HtUP * visited
Definition: fcn.c:2248
RzAnalysisFunction * fcn
Definition: fcn.c:2247
const int stack_diff
Definition: fcn.c:409
RzAnalysisFunction * fcn
Definition: fcn.c:408
const char * name
Definition: sparc-opc.c:1838
RBNode * cur
Definition: fcn.c:31
RBNode * path[RZ_RBTREE_MAX_HEIGHT]
Definition: fcn.c:32
int len
Definition: fcn.c:30
char * reg
Definition: fcn.c:350
ut64 leaddr
Definition: fcn.c:349
ut64 op_addr
Definition: fcn.c:348
Definition: z80asm.h:102
Definition: rz_pj.h:12
RzAnalysisCond * cond
Definition: rz_analysis.h:873
const char * cmpreg
Definition: rz_analysis.h:883
RzAnalysisSwitchOp * switch_op
Definition: rz_analysis.h:874
RzAnalysisDiff * diff
Definition: rz_analysis.h:872
struct rz_analysis_t * analysis
Definition: rz_analysis.h:267
RzAnalysisMetaType type
Definition: rz_analysis.h:302
RzAnalysisValue * dst
Definition: rz_analysis.h:840
RzAnalysisValue * src[3]
Definition: rz_analysis.h:839
RzAnalysisXRefType type
Definition: rz_analysis.h:909
RzAnalysisRange * limit
Definition: rz_analysis.h:587
RzFlagGetAtAddr flag_get
Definition: rz_analysis.h:616
RzList * leaddrs
Definition: rz_analysis.h:621
RzList * fcns
Definition: rz_analysis.h:565
struct rz_analysis_plugin_t * cur
Definition: rz_analysis.h:586
RzFlagBind flb
Definition: rz_analysis.h:575
RzAnalysisOptions opt
Definition: rz_analysis.h:608
SetU * visited
Definition: rz_analysis.h:619
RzIOBind iob
Definition: rz_analysis.h:574
RzTypeDB * typedb
Definition: rz_analysis.h:602
RzCoreBind coreb
Definition: rz_analysis.h:580
RzAnalysisBlock * block
Definition: rz_analysis.h:893
RzAnalysisFunction * fcn
Definition: rz_analysis.h:892
RzRegItem * regdelta
Definition: rz_analysis.h:785
RzAnalysisVarKind kind
Definition: rz_analysis.h:728
RzPVector * args
optional for the time being
Definition: rz_type.h:149
RzCoreNumGet numGet
Definition: rz_bind.h:47
void * core
Definition: rz_bind.h:31
RzCoreGetName getName
Definition: rz_bind.h:40
RzFlagExistAt exist_at
Definition: rz_flag.h:79
RzFlagSet set
Definition: rz_flag.h:84
RzFlagGetAt get_at
Definition: rz_flag.h:81
RzFlag * f
Definition: rz_flag.h:78
char * name
Definition: rz_flag.h:35
RzIOReadAt read_at
Definition: rz_io.h:240
RzIOIsValidOff is_valid_offset
Definition: rz_io.h:257
RzIOMapGet map_get
Definition: rz_io.h:259
RzIO * io
Definition: rz_io.h:232
size_t addrbytes
Definition: rz_io.h:66
int va
Definition: rz_io.h:63
int offset
Offset into register profile in bits.
Definition: rz_reg.h:121
char * name
Definition: rz_reg.h:118
char * name[RZ_REG_NAME_LAST]
Definition: rz_reg.h:149
RzTypeKind kind
Definition: rz_type.h:155
RzCallable * callable
Definition: rz_type.h:170
void after(uv_work_t *req, int status)
Definition: main.c:26
int pos
Definition: main.c:11
ut64 maxlen
Definition: core.c:76
uint64_t blocks
Definition: list.c:104
static struct Type metas[]
Definition: swift.c:39
#define fail(test)
Definition: tests.h:29
RZ_API RZ_OWN RzCallable * rz_type_callable_clone(RZ_BORROW RZ_NONNULL const RzCallable *callable)
Creates an exact clone of the RzCallable type.
Definition: function.c:33
RZ_API RZ_BORROW RzCallable * rz_type_func_get(RzTypeDB *typedb, RZ_NONNULL const char *name)
Returns the RzCallable from the database by name.
Definition: function.c:162
RZ_API bool rz_type_callable_arg_add(RZ_NONNULL RzCallable *callable, RZ_OWN RZ_NONNULL RzCallableArg *arg)
Adds a new argument to the RzCallable.
Definition: function.c:116
RZ_API RZ_BORROW const char * rz_type_func_args_name(RzTypeDB *typedb, RZ_NONNULL const char *name, int i)
Searches for the RzCallable type in types database and returns argument name.
Definition: function.c:302
RZ_API RZ_OWN RzCallable * rz_type_func_new(RzTypeDB *typedb, RZ_NONNULL const char *name, RZ_OWN RZ_NULLABLE RzType *type)
Creates a new RzCallable type.
Definition: function.c:131
RZ_API RZ_BORROW RzType * rz_type_func_ret(RzTypeDB *typedb, RZ_NONNULL const char *name)
Searches for the RzCallable type in types database and returns return type.
Definition: function.c:215
RZ_API bool rz_type_func_exist(RzTypeDB *typedb, RZ_NONNULL const char *name)
Checks if the RzCallable type exists in the database given the name.
Definition: function.c:203
RZ_API RZ_BORROW RzType * rz_type_func_args_type(RzTypeDB *typedb, RZ_NONNULL const char *name, int i)
Searches for the RzCallable type in types database and returns argument type.
Definition: function.c:278
RZ_API RZ_OWN RzCallableArg * rz_type_callable_arg_new(RzTypeDB *typedb, RZ_NONNULL const char *name, RZ_OWN RZ_NONNULL RzType *type)
Creates a new RzCallableArg given the name and type.
Definition: function.c:69
RZ_API void rz_type_callable_free(RZ_NONNULL RzCallable *callable)
Frees the RzCallable.
Definition: function.c:55
RZ_API bool rz_type_func_delete(RzTypeDB *typedb, RZ_NONNULL const char *name)
Removes RzCallable type from the types database.
Definition: function.c:179
RZ_API RZ_OWN char * rz_type_callable_as_string(const RzTypeDB *typedb, RZ_NONNULL const RzCallable *callable)
Returns the callable C representation.
Definition: function.c:487
RZ_API bool rz_type_func_save(RzTypeDB *typedb, RZ_NONNULL RzCallable *callable)
Stores RzCallable type in the types database.
Definition: function.c:147
RZ_API ut64 rz_type_db_get_bitsize(const RzTypeDB *typedb, RZ_NONNULL RzType *type)
Returns the type size in bits (target dependent)
Definition: type.c:779
RZ_API bool rz_types_equal(RZ_NONNULL const RzType *type1, RZ_NONNULL const RzType *type2)
Checks if two types are identical.
Definition: type.c:1218
RZ_API void rz_type_free(RZ_NULLABLE RzType *type)
Frees the RzType.
Definition: type.c:1273
RZ_API RZ_OWN RzType * rz_type_clone(RZ_BORROW RZ_NONNULL const RzType *type)
Creates an exact clone of the RzType.
Definition: type.c:1181
RZ_API RZ_OWN char * rz_type_as_string(const RzTypeDB *typedb, RZ_NONNULL const RzType *type)
Returns the type C representation.
Definition: type.c:817
Definition: dis.c:32
static bool arch_destroys_dst(const char *arch)
Definition: var.c:857
RZ_API void rz_analysis_function_delete_unused_vars(RzAnalysisFunction *fcn)
Definition: var.c:229
RZ_API RZ_BORROW RzAnalysisVar * rz_analysis_function_get_var(RzAnalysisFunction *fcn, char kind, int delta)
Definition: var.c:259
RZ_API void rz_analysis_function_delete_all_vars(RzAnalysisFunction *fcn)
Definition: var.c:220
RZ_API void rz_analysis_extract_vars(RzAnalysis *analysis, RzAnalysisFunction *fcn, RzAnalysisOp *op)
Definition: var.c:1103
RZ_API void rz_analysis_var_set_access(RzAnalysisVar *var, const char *reg, ut64 access_addr, int access_type, st64 stackptr)
Definition: var.c:441
RZ_API void rz_analysis_var_remove_access_at(RzAnalysisVar *var, ut64 address)
Definition: var.c:476
RZ_API RZ_BORROW RzPVector * rz_analysis_function_get_vars_used_at(RzAnalysisFunction *fcn, ut64 op_addr)
Definition: var.c:393
RZ_API RZ_BORROW RzAnalysisVar * rz_analysis_function_set_var(RzAnalysisFunction *fcn, int delta, char kind, RZ_BORROW RZ_NULLABLE const RzType *type, int size, bool isarg, RZ_NONNULL const char *name)
Definition: var.c:111
RZ_DEPRECATE RZ_API RzList * rz_analysis_var_all_list(RzAnalysis *analysis, RzAnalysisFunction *fcn)
Definition: var.c:1135
RZ_API int rz_analysis_var_get_argnum(RzAnalysisVar *var)
Definition: var.c:369
RZ_API RzAnalysisVarAccess * rz_analysis_var_get_access_at(RzAnalysisVar *var, ut64 addr)
Definition: var.c:509
RZ_API void rz_analysis_function_delete_var(RzAnalysisFunction *fcn, RzAnalysisVar *var)
Definition: var.c:241
if(dbg->bits==RZ_SYS_BITS_64)
Definition: windows-arm64.h:4
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
RZ_API bool rz_analysis_xrefs_set(RzAnalysis *analysis, ut64 from, ut64 to, RzAnalysisXRefType type)
Definition: xrefs.c:117
RZ_API bool rz_analysis_xrefs_deln(RzAnalysis *analysis, ut64 from, ut64 to, RzAnalysisXRefType type)
Definition: xrefs.c:148
RZ_API RzList * rz_analysis_function_get_xrefs_from(RzAnalysisFunction *fcn)
Definition: xrefs.c:297
static int addr
Definition: z80asm.c:58
reftype
Definition: z80asm.h:66
#define N
Definition: zip_err_str.c:8
#define E
Definition: zip_err_str.c:12