Rizin
unix-like reverse engineering framework and cli tools
analysis_tp.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2016-2020 oddcoder <ahmedsoliman@oddcoder.com>
2 // SPDX-FileCopyrightText: 2016-2020 sivaramaaa <sivaramaaa@gmail.com>
3 // SPDX-License-Identifier: LGPL-3.0-only
4 /* type matching - type propagation */
5 
6 #include <rz_analysis.h>
7 #include <rz_util.h>
8 #include <ht_uu.h>
9 #include <rz_core.h>
10 #define LOOP_MAX 10
11 
13  if (!core->analysis->esil) {
14  return false;
15  }
16  *dt = core->dbg->trace;
17  *et = core->analysis->esil->trace;
18 
19  core->dbg->trace = rz_debug_trace_new();
21 
22  rz_config_hold_i(hc, "esil.romem", "dbg.trace",
23  "esil.nonull", "dbg.follow", NULL);
24  rz_config_set(core->config, "esil.romem", "true");
25  rz_config_set(core->config, "dbg.trace", "true");
26  rz_config_set(core->config, "esil.nonull", "true");
27  rz_config_set_i(core->config, "dbg.follow", false);
28  const char *bp = rz_reg_get_name(core->analysis->reg, RZ_REG_NAME_BP);
29  const char *sp = rz_reg_get_name(core->analysis->reg, RZ_REG_NAME_SP);
30  if ((bp && !rz_reg_getv(core->analysis->reg, bp)) && (sp && !rz_reg_getv(core->analysis->reg, sp))) {
31  eprintf("Stack isn't initialized.\n");
32  eprintf("Try running aei and aeim commands before aft for default stack initialization\n");
33  return false;
34  }
35  return (core->dbg->trace && core->analysis->esil->trace);
36 }
37 
43  core->analysis->esil->trace = et;
44  core->dbg->trace = dt;
45 }
46 
47 static bool type_pos_hit(RzAnalysis *analysis, RzILTraceInstruction *instr_trace, bool in_stack, int size, const char *place) {
48  if (in_stack) {
49  const char *sp_name = rz_reg_get_name(analysis->reg, RZ_REG_NAME_SP);
50  ut64 sp = rz_reg_getv(analysis->reg, sp_name);
51 
52  ut64 write_addr = 0LL;
53  if (instr_trace && (instr_trace->stats & RZ_IL_TRACE_INS_HAS_MEM_W)) {
54  // TODO : This assumes an op will only write to memory once
55  // : which may be wrong in some archs. this is only a temporary solution
56  RzILTraceMemOp *mem = rz_pvector_at(instr_trace->write_mem_ops, 0);
57  write_addr = mem->addr;
58  } else {
59  // no reg write
60  write_addr = 0LL;
61  }
62  return (write_addr == sp + size);
63  }
64 
65  return rz_analysis_il_reg_trace_contains(instr_trace, place, true);
66 }
67 
68 static void var_rename(RzAnalysis *analysis, RzAnalysisVar *v, const char *name, ut64 addr) {
69  if (!name || !v) {
70  return;
71  }
72  if (!*name || !strcmp(name, "...")) {
73  return;
74  }
75  bool is_default = (rz_str_startswith(v->name, VARPREFIX) || rz_str_startswith(v->name, ARGPREFIX));
76  if (*name == '*') {
78  name++;
79  }
80  // longer name tends to be meaningful like "src" instead of "s1"
81  if (!is_default && (strlen(v->name) > strlen(name))) {
82  return;
83  }
84  RzAnalysisFunction *fcn = rz_analysis_get_fcn_in(analysis, addr, 0);
85  if (!fcn) {
86  return;
87  }
88  rz_analysis_var_rename(v, name, false);
89 }
90 
91 static void var_type_set_sign(RzAnalysis *analysis, RzAnalysisVar *var, bool sign) {
92  rz_return_if_fail(analysis && var);
93  // Check if it's integral number first
94  if (rz_type_is_integral(analysis->typedb, var->type)) {
95  rz_type_integral_set_sign(analysis->typedb, &var->type, sign);
96  }
97 }
98 
99 static bool var_type_simple_to_complex(const RzTypeDB *typedb, RzType *a, RzType *b) {
100  // `*int*` types to anything else of the typeclass
101  if (rz_type_is_integral(typedb, a) && !rz_type_is_char_ptr_nested(a) && !rz_type_is_integral(typedb, b)) {
102  return true;
103  }
104  // `*int*` types to pointers or arrays
106  return true;
107  }
108  return false;
109 }
110 
111 // TODO: Handle also non-atomic types here
112 static void var_type_set(RzAnalysis *analysis, RzAnalysisVar *var, RZ_BORROW RzType *type, bool ref, bool resolve_overlaps) {
113  rz_return_if_fail(analysis && var && type);
114  RzTypeDB *typedb = analysis->typedb;
115  // removing this return makes 64bit vars become 32bit
116  if (rz_type_is_default(typedb, type) || rz_type_atomic_is_void(typedb, type)) {
117  // default or void (not void* !) type
118  return;
119  }
120  if (!rz_type_is_default(typedb, var->type) && !rz_type_is_void_ptr(var->type) && !var_type_simple_to_complex(typedb, var->type, type)) {
121  // return since type is already propagated
122  // except for "void *", since "void *" => "char *" is possible
123  // except for simple types to the more complex types
124  return;
125  }
126  // Since the type could be used by something else we should clone it
127  RzType *cloned = rz_type_clone(type);
128  if (!cloned) {
129  eprintf("Cannot clone the type for the variable \"%s.%s\"\n", var->fcn->name, var->name);
130  return;
131  }
132  // Make a pointer of the existing type
133  if (ref) {
134  // By default we create non-const pointers
135  RzType *ptrtype = rz_type_pointer_of_type(typedb, cloned, false);
136  if (!ptrtype) {
137  eprintf("Cannot convert the type for the variable \"%s.%s\" into pointer\n", var->fcn->name, var->name);
138  return;
139  }
140  rz_analysis_var_set_type(var, ptrtype, resolve_overlaps);
141  return;
142  }
143 
144  rz_analysis_var_set_type(var, cloned, resolve_overlaps);
145 }
146 
147 static void var_type_set_resolve_overlaps(RzAnalysis *analysis, RzAnalysisVar *var, RZ_BORROW RzType *type, bool ref) {
148  var_type_set(analysis, var, type, ref, true);
149 }
150 
151 static void vars_resolve_overlaps(RzPVector *vars) {
152  for (size_t i = 0; i < rz_pvector_len(vars); i++) {
153  RzAnalysisVar *var = rz_pvector_at(vars, i);
155  }
156 }
157 
158 static void var_type_set_str(RzAnalysis *analysis, RzAnalysisVar *var, const char *type, bool ref) {
159  rz_return_if_fail(analysis && var && type);
160  char *error_msg = NULL;
161  RzType *realtype = rz_type_parse_string_single(analysis->typedb->parser, type, &error_msg);
162  if (!realtype && error_msg) {
163  eprintf("Fail to parse type \"%s\":\n%s\n", type, error_msg);
164  free(error_msg);
165  return;
166  }
167  var_type_set_resolve_overlaps(analysis, var, realtype, ref);
168  // Since we clone the type here, free it
169  rz_type_free(realtype);
170 }
171 
172 static void get_src_regname(RzCore *core, ut64 addr, char *regname, int size) {
173  RzAnalysis *analysis = core->analysis;
175  if (!op || rz_strbuf_is_empty(&op->esil)) {
177  return;
178  }
179  char *op_esil = strdup(rz_strbuf_get(&op->esil));
180  char *tmp = strchr(op_esil, ',');
181  if (tmp) {
182  *tmp = '\0';
183  }
184  memset(regname, 0, size);
185  RzRegItem *ri = rz_reg_get(analysis->reg, op_esil, -1);
186  if (ri) {
187  if ((analysis->bits == 64) && (ri->size == 32)) {
188  const char *reg = rz_reg_32_to_64(analysis->reg, op_esil);
189  if (reg) {
190  free(op_esil);
191  op_esil = strdup(reg);
192  }
193  }
194  strncpy(regname, op_esil, size - 1);
195  }
196  free(op_esil);
198 }
199 
200 static ut64 get_addr(RzAnalysis *analysis, const char *regname, int idx) {
201  if (!regname || !*regname) {
202  return UT64_MAX;
203  }
204 
205  RzAnalysisEsilTrace *etrace = analysis->esil->trace;
206  RzILTraceInstruction *instruction_trace = rz_analysis_esil_get_instruction_trace(etrace, idx);
207  RzILTraceRegOp *reg_op = rz_analysis_il_get_reg_op_trace(instruction_trace, regname, false);
208 
209  if (!reg_op) {
210  return UT64_MAX;
211  }
212 
213  return reg_op->value;
214 }
215 
216 static RzList *parse_format(RzCore *core, char *fmt) {
217  if (!fmt || !*fmt) {
218  return NULL;
219  }
220  RzList *ret = rz_list_new();
221  if (!ret) {
222  return NULL;
223  }
224  Sdb *s = core->analysis->sdb_fmts;
225  const char *spec = rz_config_get(core->config, "analysis.types.spec");
226  char arr[10] = { 0 };
227  char *ptr = strchr(fmt, '%');
228  fmt[strlen(fmt) - 1] = '\0';
229  while (ptr) {
230  ptr++;
231  // strip [width] specifier
232  while (IS_DIGIT(*ptr)) {
233  ptr++;
234  }
235  rz_str_ncpy(arr, ptr, sizeof(arr) - 1);
236  char *tmp = arr;
237  while (tmp && (IS_LOWER(*tmp) || IS_UPPER(*tmp))) {
238  tmp++;
239  }
240  *tmp = '\0';
241  const char *query = sdb_fmt("spec.%s.%s", spec, arr);
242  char *type = (char *)sdb_const_get(s, query, 0);
243  if (type) {
244  rz_list_append(ret, type);
245  }
246  ptr = strchr(ptr, '%');
247  }
248  return ret;
249 }
250 
251 static void retype_callee_arg(RzAnalysis *analysis, const char *callee_name, bool in_stack, const char *place, int size, RZ_BORROW RzType *type) {
252  RzAnalysisFunction *fcn = rz_analysis_get_function_byname(analysis, callee_name);
253  if (!fcn) {
254  return;
255  }
256  if (in_stack) {
258  if (!var) {
259  return;
260  }
261  var_type_set_resolve_overlaps(analysis, var, type, false);
262  } else {
263  RzRegItem *item = rz_reg_get(analysis->reg, place, -1);
264  if (!item) {
265  return;
266  }
268  if (!rvar) {
269  return;
270  }
271  var_type_set_resolve_overlaps(analysis, rvar, type, false);
273  if (lvar) {
274  var_type_set_resolve_overlaps(analysis, lvar, type, false);
275  }
276  }
277 }
278 
279 RzAnalysisOp *op_cache_get(HtUP *cache, RzCore *core, ut64 addr) {
280  RzAnalysisOp *op = ht_up_find(cache, addr, NULL);
281  if (op) {
282  return op;
283  }
285  if (!ht_up_insert(cache, addr, op)) {
287  return NULL;
288  }
289  return op;
290 }
291 
292 RzCallable *function_type_derive(RzAnalysis *analysis, RZ_NONNULL const char *fcn_name, bool *owned) {
293  rz_return_val_if_fail(fcn_name && owned, NULL);
294  // Because in the case of `rz_type_func_get()` we get the borrowed
295  // pointer to the RzCallable and in the case of `rz_analysis_function_derive_type()`
296  // we get the owned pointer, we should free the pointer in the one case but not another.
297  *owned = false;
298  RzCallable *callable = rz_type_func_get(analysis->typedb, fcn_name);
299  if (!callable) {
300  RzAnalysisFunction *fcn = rz_analysis_get_function_byname(analysis, fcn_name);
301  if (!fcn) {
302  return NULL;
303  }
304  callable = rz_analysis_function_derive_type(analysis, fcn);
305  if (!callable) {
306  return NULL;
307  }
308  *owned = true;
309  }
310  return callable;
311 }
312 
313 bool function_argument_type_derive(RZ_NULLABLE const RzCallable *callable, int arg_num, RzType **type, char **name) {
314  rz_return_val_if_fail(type && name, false);
315  if (!callable) {
316  return false;
317  }
318  if (arg_num >= rz_pvector_len(callable->args)) {
319  return false;
320  }
321  RzCallableArg *arg = *rz_pvector_index_ptr(callable->args, arg_num);
322  if (!arg) {
323  return false;
324  }
325  *type = rz_type_clone(arg->type);
326  *name = strdup(arg->name);
327  return true;
328 }
329 
330 #define DEFAULT_MAX 3
331 #define REGNAME_SIZE 10
332 #define MAX_INSTR 5
333 
345 static void type_match(RzCore *core, char *fcn_name, ut64 addr, ut64 baddr, const char *cc,
346  int prev_idx, bool userfnc, ut64 caddr, HtUP *op_cache) {
347  RzAnalysisEsilTrace *etrace = core->analysis->esil->trace;
348  RzTypeDB *typedb = core->analysis->typedb;
349  RzAnalysis *analysis = core->analysis;
350  RzList *types = NULL;
351 
352  int idx = rz_pvector_len(etrace->instructions) - 1;
353 
354  bool verbose = rz_config_get_i(core->config, "analysis.types.verbose");
355  bool stack_rev = false, in_stack = false, format = false;
356 
357  if (!fcn_name || !cc) {
358  return;
359  }
360  int i, j, pos = 0, size = 0, max = rz_type_func_args_count(typedb, fcn_name);
361  const char *place = rz_analysis_cc_arg(analysis, cc, ST32_MAX);
363 
364  if (place && !strcmp(place, "stack_rev")) {
365  stack_rev = true;
366  }
367  place = rz_analysis_cc_arg(analysis, cc, 0);
368  if (place && rz_str_startswith("stack", place)) {
369  in_stack = true;
370  }
371  if (verbose && !strncmp(fcn_name, "sym.imp.", 8)) {
372  eprintf("%s missing function definition\n", fcn_name + 8);
373  }
374  if (!max || max == -1) {
375  if (!in_stack) {
376  max = rz_analysis_cc_max_arg(analysis, cc);
377  } else {
378  max = DEFAULT_MAX;
379  }
380  }
381  // Because in the case of `rz_type_func_get()` we get the borrowed
382  // pointer to the RzCallable and in the case of `rz_analysis_function_derive_type()`
383  // we get the owned pointer, we should free the pointer in the one case but not another.
384  bool owned = false;
385  RzCallable *callable = function_type_derive(analysis, fcn_name, &owned);
386  // We don't check if the callable is NULL because we not always need it, for example
387  // in case of the `format` set it's unnecessary for the type derivation.
388  for (i = 0; i < max; i++) {
389  int arg_num = stack_rev ? (max - 1 - i) : i;
390  RzType *type = NULL;
391  char *name = NULL;
392  if (format) {
393  if (rz_list_empty(types)) {
394  break;
395  }
396  const char *typestr = rz_str_new(rz_list_get_n(types, pos++));
397  if (typestr) {
398  type = rz_type_parse_string_single(typedb->parser, typestr, NULL);
399  }
400  } else {
401  if (!function_argument_type_derive(callable, arg_num, &type, &name)) {
402  continue;
403  }
404  }
405  if (!type && !userfnc) {
406  free(name);
407  continue;
408  }
409  if (!in_stack) {
410  // XXX: param arg_num must be fixed to support floating point register
411  place = rz_analysis_cc_arg(analysis, cc, arg_num);
412  if (place && rz_str_startswith("stack", place)) {
413  in_stack = true;
414  }
415  }
416  char regname[REGNAME_SIZE] = { 0 };
417  ut64 xaddr = UT64_MAX;
418  bool memref = false;
419  bool cmt_set = false;
420  bool res = false;
421  // Backtrace instruction from source sink to prev source sink
422  for (j = idx; j >= prev_idx; j--) {
423  RzILTraceInstruction *instr_trace = rz_analysis_esil_get_instruction_trace(etrace, j);
424  ut64 instr_addr = instr_trace->addr;
425  if (instr_addr < baddr) {
426  break;
427  }
428  RzAnalysisOp *op = op_cache_get(op_cache, core, instr_addr);
429  if (!op) {
430  break;
431  }
432  RzAnalysisOp *next_op = op_cache_get(op_cache, core, instr_addr + op->size);
433  if (!next_op || (j != idx && (next_op->type == RZ_ANALYSIS_OP_TYPE_CALL || next_op->type == RZ_ANALYSIS_OP_TYPE_JMP))) {
434  break;
435  }
436  RzAnalysisVar *var = rz_analysis_get_used_function_var(analysis, op->addr);
437 
438  // FIXME : It seems also assume only read memory once ?
439  if (op->type == RZ_ANALYSIS_OP_TYPE_MOV && (instr_trace->stats & RZ_IL_TRACE_INS_HAS_MEM_R)) {
440  memref = !(!memref && var && (var->kind != RZ_ANALYSIS_VAR_KIND_REG));
441  }
442  // Match type from function param to instr
443  if (type_pos_hit(analysis, instr_trace, in_stack, size, place)) {
444  if (!cmt_set && type && name) {
445  char *typestr = rz_type_as_string(analysis->typedb, type);
446  const char *maybe_space = type->kind == RZ_TYPE_KIND_POINTER ? "" : " ";
447  rz_meta_set_string(analysis, RZ_META_TYPE_VARTYPE, instr_addr,
448  sdb_fmt("%s%s%s", typestr, maybe_space, name));
449  cmt_set = true;
450  if ((op->ptr && op->ptr != UT64_MAX) && !strcmp(name, "format")) {
452  if (f) {
453  char formatstr[0x200];
454  int read = rz_io_nread_at(core->io, f->offset, (ut8 *)formatstr, RZ_MIN(sizeof(formatstr) - 1, f->size));
455  if (read > 0) {
456  formatstr[read] = '\0';
457  if ((types = parse_format(core, formatstr))) {
459  }
460  format = true;
461  }
462  }
463  }
464  free(typestr);
465  }
466  if (var) {
467  if (!userfnc) {
468  // not a userfunction, propagate the callee's arg types into our function's vars
469  var_type_set_resolve_overlaps(analysis, var, type, memref);
470  var_rename(analysis, var, name, addr);
471  } else {
472  // callee is a userfunction, propagate our variable's type into the callee's args
473  retype_callee_arg(analysis, fcn_name, in_stack, place, size, var->type);
474  }
475  res = true;
476  } else {
477  get_src_regname(core, instr_addr, regname, sizeof(regname));
478  xaddr = get_addr(analysis, regname, j);
479  }
480  }
481  // Type propagate by following source reg
482  if (!res && *regname && rz_analysis_il_get_reg_op_trace(instr_trace, regname, true)) {
483  if (var) {
484  if (!userfnc) {
485  // not a userfunction, propagate the callee's arg types into our function's vars
486  var_type_set_resolve_overlaps(analysis, var, type, memref);
487  var_rename(analysis, var, name, addr);
488  } else {
489  // callee is a userfunction, propagate our variable's type into the callee's args
490  retype_callee_arg(analysis, fcn_name, in_stack, place, size, var->type);
491  }
492  res = true;
493  } else {
494  switch (op->type) {
497  get_src_regname(core, instr_addr, regname, sizeof(regname));
498  break;
502  res = true;
503  break;
504  }
505  }
506  } else if (var && res && xaddr && (xaddr != UT64_MAX)) { // Type progation using value
507  char tmp[REGNAME_SIZE] = { 0 };
508  get_src_regname(core, instr_addr, tmp, sizeof(tmp));
509  ut64 ptr = get_addr(analysis, tmp, j);
510  if (ptr == xaddr) {
511  if (type) {
512  var_type_set_resolve_overlaps(analysis, var, type, memref);
513  } else {
514  var_type_set_str(analysis, var, "int", memref);
515  }
516  }
517  }
518  }
519  size += analysis->bits / 8;
521  free(name);
522  }
523  if (owned) {
524  rz_type_callable_free(callable);
525  }
528 }
529 
530 static int bb_cmpaddr(const void *_a, const void *_b) {
531  const RzAnalysisBlock *a = _a, *b = _b;
532  return a->addr > b->addr ? 1 : (a->addr < b->addr ? -1 : 0);
533 }
534 
535 void free_op_cache_kv(HtUPKv *kv) {
536  rz_analysis_op_free(kv->value);
537 }
538 
539 void handle_stack_canary(RzCore *core, RzAnalysisOp *aop, int cur_idx) {
540  RzILTraceInstruction *prev_trace = rz_analysis_esil_get_instruction_trace(
541  core->analysis->esil->trace,
542  cur_idx - 1);
543 
544  ut64 mov_addr;
545  if (prev_trace) {
546  mov_addr = prev_trace->addr;
547  } else {
548  return;
549  }
550 
552  if (mop) {
555  if (type == RZ_ANALYSIS_OP_TYPE_MOV) {
556  var_rename(core->analysis, mopvar, "canary", aop->addr);
557  }
558  }
559  rz_analysis_op_free(mop);
560 }
561 
563  bool resolved;
565  char *ret_reg;
566 };
567 
569  return !ctx->resolved && ctx->ret_type && ctx->ret_reg;
570 }
571 
572 // Progate return type passed using pointer
574  // int *ret; *ret = strlen(s);
575  // TODO: memref check , dest and next src match
576  char nsrc[REGNAME_SIZE] = { 0 };
577  void **uvit;
578  get_src_regname(core, addr, nsrc, sizeof(nsrc));
579  if (ctx->ret_reg && *nsrc && strstr(ctx->ret_reg, nsrc) && aop->direction == RZ_ANALYSIS_OP_DIR_READ) {
580  if (used_vars && !rz_pvector_empty(used_vars)) {
581  rz_pvector_foreach (used_vars, uvit) {
582  RzAnalysisVar *var = *uvit;
583  var_type_set(core->analysis, var, ctx->ret_type, true, false);
584  }
585  vars_resolve_overlaps(used_vars);
586  }
587  }
588 }
589 
590 // Forward propagation of function return type
591 static void propagate_return_type(RzCore *core, RzAnalysisOp *aop, RzAnalysisOp *next_op, RzILTraceInstruction *trace, struct ReturnTypeAnalysisCtx *ctx, RzPVector *used_vars) {
592  char src[REGNAME_SIZE] = { 0 };
593  void **uvit;
594 
595  // TODO : handle multiple registers case, this is a temporary solution
596  RzILTraceRegOp *single_write_reg = NULL;
597  if (trace && (trace->stats & RZ_IL_TRACE_INS_HAS_REG_W)) {
598  single_write_reg = rz_pvector_at(trace->write_reg_ops, 0);
599  }
600 
601  get_src_regname(core, aop->addr, src, sizeof(src));
603  if (ctx->ret_reg && *src && strstr(ctx->ret_reg, src)) {
604  if (used_vars && !rz_pvector_empty(used_vars) && aop->direction == RZ_ANALYSIS_OP_DIR_WRITE) {
605  rz_pvector_foreach (used_vars, uvit) {
606  RzAnalysisVar *var = *uvit;
607  var_type_set(core->analysis, var, ctx->ret_type, false, false);
608  }
609  vars_resolve_overlaps(used_vars);
610  ctx->resolved = true;
611  } else if (type == RZ_ANALYSIS_OP_TYPE_MOV) {
612  RZ_FREE(ctx->ret_reg);
613  if (single_write_reg && single_write_reg->reg_name) {
614  ctx->ret_reg = strdup(single_write_reg->reg_name);
615  }
616  }
617  } else if (single_write_reg) {
618  if (ctx->ret_reg &&
619  (single_write_reg->reg_name && strstr(ctx->ret_reg, single_write_reg->reg_name))) {
620  ctx->resolved = true;
621  } else if (type == RZ_ANALYSIS_OP_TYPE_MOV &&
622  (next_op && next_op->type == RZ_ANALYSIS_OP_TYPE_MOV)) {
623  // Progate return type passed using pointer
624  propagate_return_type_pointer(core, aop, used_vars, next_op->addr, ctx);
625  }
626  }
627 }
628 
631  int cur_idx;
632  const char *prev_dest;
633  bool str_flag;
634 };
635 
637  RzPVector *used_vars = rz_analysis_function_get_vars_used_at(fcn, aop->addr);
638  bool chk_constraint = rz_config_get_b(core->config, "analysis.types.constraint");
639  RzAnalysisOp *next_op = op_cache_get(op_cache, core, aop->addr + aop->size);
640  void **uvit;
641  RzType *prev_type = NULL;
642  int prev_idx = 0;
643  bool prev_var = false;
644  char *fcn_name = NULL;
645  bool userfnc = false;
646  bool prop = false;
648  RzAnalysis *analysis = core->analysis;
649 
650  RzAnalysisEsilTrace *etrace = core->analysis->esil->trace;
651  RzILTraceInstruction *cur_instr_trace = rz_analysis_esil_get_instruction_trace(etrace, ctx->cur_idx);
652 
654  char *full_name = NULL;
655  ut64 callee_addr;
656  if (aop->type == RZ_ANALYSIS_OP_TYPE_CALL) {
657  RzAnalysisFunction *fcn_call = rz_analysis_get_fcn_in(core->analysis, aop->jump, -1);
658  if (fcn_call) {
659  full_name = fcn_call->name;
660  callee_addr = fcn_call->addr;
661  }
662  } else if (aop->ptr != UT64_MAX) {
664  if (flag && flag->realname) {
665  full_name = flag->realname;
666  callee_addr = aop->ptr;
667  }
668  }
669  // TODO: Apart from checking the types database, we should also derive the information
670  // from the RzAnalysisFunction if nothing was found in the RzTypeDB
671  if (full_name) {
672  if (rz_type_func_exist(core->analysis->typedb, full_name)) {
673  fcn_name = strdup(full_name);
674  } else {
675  fcn_name = rz_analysis_function_name_guess(core->analysis->typedb, full_name);
676  }
677  if (!fcn_name) {
678  fcn_name = strdup(full_name);
679  userfnc = true;
680  }
681  const char *Cc = rz_analysis_cc_func(core->analysis, fcn_name);
682  if (Cc && rz_analysis_cc_exist(core->analysis, Cc)) {
683  char *cc = strdup(Cc);
684  type_match(core, fcn_name, aop->addr, bb->addr, cc, prev_idx, userfnc, callee_addr, op_cache);
685  prev_idx = ctx->cur_idx;
686  ctx->retctx->ret_type = rz_type_func_ret(core->analysis->typedb, fcn_name);
687  RZ_FREE(ctx->retctx->ret_reg);
688  const char *rr = rz_analysis_cc_ret(core->analysis, cc);
689  if (rr) {
690  ctx->retctx->ret_reg = strdup(rr);
691  }
692  ctx->retctx->resolved = false;
693  free(cc);
694  }
695  if (!strcmp(fcn_name, "__stack_chk_fail")) {
696  handle_stack_canary(core, aop, ctx->cur_idx);
697  }
698  free(fcn_name);
699  }
700  } else if (return_type_analysis_context_unresolved(ctx->retctx)) {
701  // Forward propagation of function return type
702  propagate_return_type(core, aop, next_op, cur_instr_trace, ctx->retctx, used_vars);
703  }
704  // Type propagation using instruction access pattern
705  if (used_vars && !rz_pvector_empty(used_vars)) {
706  rz_pvector_foreach (used_vars, uvit) {
707  RzAnalysisVar *var = *uvit;
708  bool sign = false;
709  if ((type == RZ_ANALYSIS_OP_TYPE_CMP) && next_op) {
710  if (next_op->sign) {
711  sign = true;
712  } else {
713  // cmp [local_ch], rax ; jb
714  // set to "unsigned"
715  var_type_set_sign(core->analysis, var, false);
716  }
717  }
718  // cmp [local_ch], rax ; jge
719  if (sign || aop->sign) {
720  // set to "signed"
721  var_type_set_sign(core->analysis, var, true);
722  }
723  // lea rax , str.hello ; mov [local_ch], rax;
724  // mov rdx , [local_4h] ; mov [local_8h], rdx;
725  if (ctx->prev_dest && (type == RZ_ANALYSIS_OP_TYPE_MOV || type == RZ_ANALYSIS_OP_TYPE_STORE)) {
726  char reg[REGNAME_SIZE] = { 0 };
727  get_src_regname(core, aop->addr, reg, sizeof(reg));
728  bool match = strstr(ctx->prev_dest, reg) != NULL;
729  if (ctx->str_flag && match) {
730  var_type_set_str(core->analysis, var, "const char *", false);
731  }
732  if (prop && match && prev_var && prev_type) {
733  // Here we clone the type
734  var_type_set(core->analysis, var, prev_type, false, false);
735  }
736  }
737  if (chk_constraint && var && (type == RZ_ANALYSIS_OP_TYPE_CMP && aop->disp != UT64_MAX) && next_op && next_op->type == RZ_ANALYSIS_OP_TYPE_CJMP) {
738  bool jmp = false;
739  RzAnalysisOp *jmp_op = { 0 };
740  ut64 jmp_addr = next_op->jump;
741  RzAnalysisBlock *jmpbb = rz_analysis_fcn_bbget_in(core->analysis, fcn, jmp_addr);
742 
743  // Check exit status of jmp branch
744  int i;
745  for (i = 0; i < MAX_INSTR; i++) {
746  jmp_op = rz_core_analysis_op(core, jmp_addr, RZ_ANALYSIS_OP_MASK_BASIC);
747  if (!jmp_op) {
748  break;
749  }
750  if ((jmp_op->type == RZ_ANALYSIS_OP_TYPE_RET && rz_analysis_block_contains(jmpbb, jmp_addr)) || jmp_op->type == RZ_ANALYSIS_OP_TYPE_CJMP) {
751  jmp = true;
752  rz_analysis_op_free(jmp_op);
753  break;
754  }
755  jmp_addr += jmp_op->size;
756  rz_analysis_op_free(jmp_op);
757  }
758  RzTypeConstraint constr = {
759  .cond = jmp ? rz_type_cond_invert(next_op->cond) : next_op->cond,
760  .val = aop->val
761  };
762  rz_analysis_var_add_constraint(var, &constr);
763  }
764  }
765  vars_resolve_overlaps(used_vars);
766  }
767  prev_var = (used_vars && !rz_pvector_empty(used_vars) && aop->direction == RZ_ANALYSIS_OP_DIR_READ);
768  ctx->str_flag = false;
769  prop = false;
770  ctx->prev_dest = NULL;
771  switch (type) {
775  if (aop->ptr && aop->refptr && aop->ptr != UT64_MAX) {
777  ut8 buf[256] = { 0 };
778  rz_io_read_at(core->io, aop->ptr, buf, sizeof(buf) - 1);
779  ut64 ptr = rz_read_ble(buf, core->print->big_endian, aop->refptr * 8);
780  if (ptr && ptr != UT64_MAX) {
782  if (f) {
783  ctx->str_flag = true;
784  }
785  }
786  } else if (rz_flag_exist_at(core->flags, "str", 3, aop->ptr)) {
787  ctx->str_flag = true;
788  }
789  }
790 
791  // Assert : reg write only once here
792  RzILTraceRegOp *w_reg = NULL;
793  if (cur_instr_trace) {
794  if (cur_instr_trace->stats & RZ_IL_TRACE_INS_HAS_REG_W) {
795  w_reg = rz_pvector_at(cur_instr_trace->write_reg_ops, 0);
796  if (w_reg) {
797  ctx->prev_dest = rz_str_constpool_get(&analysis->constpool, w_reg->reg_name);
798  }
799  }
800  }
801 
802  if (used_vars && !rz_pvector_empty(used_vars)) {
803  rz_pvector_foreach (used_vars, uvit) {
804  RzAnalysisVar *var = *uvit;
805  // mov dword [local_4h], str.hello;
806  if (ctx->str_flag) {
807  var_type_set_str(core->analysis, var, "const char *", false);
808  }
809  prev_type = var->type;
810  prop = true;
811  }
812  }
813  }
814 }
815 
816 RZ_API void rz_core_analysis_type_match(RzCore *core, RzAnalysisFunction *fcn, HtUU *loop_table) {
817  RzListIter *it;
818 
819  rz_return_if_fail(core && core->analysis && fcn);
820 
821  if (!core->analysis->esil) {
822  eprintf("Please run aeim\n");
823  return;
824  }
825 
826  RzAnalysis *analysis = core->analysis;
827  RzReg *reg = analysis->reg;
828  const int mininstrsz = rz_analysis_archinfo(analysis, RZ_ANALYSIS_ARCHINFO_MIN_OP_SIZE);
829  const int minopcode = RZ_MAX(1, mininstrsz);
831  if (!hc) {
832  return;
833  }
834  RzDebugTrace *dt = NULL;
837  if (!analysis_emul_init(core, hc, &dt, &et, &rt) || !fcn) {
838  analysis_emul_restore(core, hc, dt, et, rt);
839  return;
840  }
841 
842  // Reserve bigger ht to avoid rehashing
843  HtPPOptions opt;
844  RzDebugTrace *dtrace = core->dbg->trace;
845  opt = dtrace->ht->opt;
846  ht_pp_free(dtrace->ht);
847  dtrace->ht = ht_pp_new_size(fcn->ninstr, opt.dupvalue, opt.freefn, opt.calcsizeV);
848  dtrace->ht->opt = opt;
849 
850  // Create a new context to store the return type propagation state
851  struct ReturnTypeAnalysisCtx retctx = {
852  .resolved = false,
853  .ret_type = NULL,
854  .ret_reg = NULL,
855  };
856  struct TypeAnalysisCtx ctx = {
857  .retctx = &retctx,
858  .cur_idx = 0,
859  .prev_dest = NULL,
860  .str_flag = false
861  };
862 
863  HtUP *op_cache = NULL;
864  const char *pc = rz_reg_get_name(reg, RZ_REG_NAME_PC);
865  if (!pc) {
866  goto out_function;
867  }
868  RzRegItem *r = rz_reg_get(reg, pc, -1);
869  if (!r) {
870  goto out_function;
871  }
873  rz_list_sort(fcn->bbs, bb_cmpaddr);
874  // TODO: The algorithm can be more accurate if blocks are followed by their jmp/fail, not just by address
875  RzAnalysisBlock *bb;
876  rz_list_foreach (fcn->bbs, it, bb) {
877  ut64 addr = bb->addr;
879  ht_up_free(op_cache);
880  op_cache = ht_up_new(NULL, free_op_cache_kv, NULL);
881  if (!op_cache) {
882  break;
883  }
884  while (1) {
885  if (rz_cons_is_breaked()) {
886  goto out_function;
887  }
888  ut64 pcval = rz_reg_getv(reg, pc);
889  if ((addr >= bb->addr + bb->size) || (addr < bb->addr) || pcval != addr) {
890  break;
891  }
892  RzAnalysisOp *aop = op_cache_get(op_cache, core, addr);
893  if (!aop) {
894  break;
895  }
896  if (aop->type == RZ_ANALYSIS_OP_TYPE_ILL) {
897  addr += minopcode;
898  continue;
899  }
900 
901  // CHECK_ME : why we hold a loop_count here ?
902  // : can we remove it ?
903  // when set null, do not track loop count
904  if (loop_table) {
905  ut64 loop_count = ht_uu_find(loop_table, addr, NULL);
906  if (loop_count > LOOP_MAX || aop->type == RZ_ANALYSIS_OP_TYPE_RET) {
907  break;
908  }
909  loop_count += 1;
910  ht_uu_update(loop_table, addr, loop_count);
911  }
912 
913  if (rz_analysis_op_nonlinear(aop->type)) { // skip the instr
914  rz_reg_set_value(reg, r, addr + aop->size);
915  } else {
916  rz_core_esil_step(core, UT64_MAX, NULL, NULL, false);
917  }
918 
919  RzPVector *ins_traces = analysis->esil->trace->instructions;
920  ctx.cur_idx = rz_pvector_len(ins_traces) - 1;
921  RzList *fcns = rz_analysis_get_functions_in(analysis, aop->addr);
922  if (!fcns) {
923  break;
924  }
925  RzListIter *it;
926  RzAnalysisFunction *fcn;
927  rz_list_foreach (fcns, it, fcn) {
928  propagate_types_among_used_variables(core, op_cache, fcn, bb, aop, &ctx);
929  }
930  addr += aop->size;
931  rz_list_free(fcns);
932  }
933  }
934 
935  // Type propagation for register based args
936  void **vit;
937  rz_pvector_foreach (&fcn->vars, vit) {
938  RzAnalysisVar *rvar = *vit;
939  if (rvar->kind == RZ_ANALYSIS_VAR_KIND_REG) {
941  RzRegItem *i = rz_reg_index_get(reg, rvar->delta);
942  if (!i) {
943  continue;
944  }
945  // Note that every `var_type_set_resolve_overlaps()` call could remove some variables
946  // due to the overlaps resolution
947  if (lvar) {
948  // Propagate local var type = to => register-based var
949  var_type_set(analysis, rvar, lvar->type, false, false);
950  // Propagate local var type <= from = register-based var
951  var_type_set(analysis, lvar, rvar->type, false, false);
952  }
953  }
954  }
956 out_function:
958  ht_up_free(op_cache);
960  analysis_emul_restore(core, hc, dt, et, rt);
961 }
ut8 op
Definition: 6502dis.c:13
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 RzList * rz_analysis_get_functions_in(RzAnalysis *analysis, ut64 addr)
Definition: function.c:20
RZ_API int rz_analysis_archinfo(RzAnalysis *analysis, int query)
Definition: analysis.c:449
#define jmp
static void retype_callee_arg(RzAnalysis *analysis, const char *callee_name, bool in_stack, const char *place, int size, RZ_BORROW RzType *type)
Definition: analysis_tp.c:251
#define LOOP_MAX
Definition: analysis_tp.c:10
static bool var_type_simple_to_complex(const RzTypeDB *typedb, RzType *a, RzType *b)
Definition: analysis_tp.c:99
void propagate_types_among_used_variables(RzCore *core, HtUP *op_cache, RzAnalysisFunction *fcn, RzAnalysisBlock *bb, RzAnalysisOp *aop, struct TypeAnalysisCtx *ctx)
Definition: analysis_tp.c:636
RZ_API void rz_core_analysis_type_match(RzCore *core, RzAnalysisFunction *fcn, HtUU *loop_table)
Definition: analysis_tp.c:816
static void var_type_set_sign(RzAnalysis *analysis, RzAnalysisVar *var, bool sign)
Definition: analysis_tp.c:91
static void get_src_regname(RzCore *core, ut64 addr, char *regname, int size)
Definition: analysis_tp.c:172
static bool return_type_analysis_context_unresolved(struct ReturnTypeAnalysisCtx *ctx)
Definition: analysis_tp.c:568
static void type_match(RzCore *core, char *fcn_name, ut64 addr, ut64 baddr, const char *cc, int prev_idx, bool userfnc, ut64 caddr, HtUP *op_cache)
Definition: analysis_tp.c:345
static ut64 get_addr(RzAnalysis *analysis, const char *regname, int idx)
Definition: analysis_tp.c:200
#define REGNAME_SIZE
Definition: analysis_tp.c:331
void free_op_cache_kv(HtUPKv *kv)
Definition: analysis_tp.c:535
static void var_type_set_resolve_overlaps(RzAnalysis *analysis, RzAnalysisVar *var, RZ_BORROW RzType *type, bool ref)
Definition: analysis_tp.c:147
void handle_stack_canary(RzCore *core, RzAnalysisOp *aop, int cur_idx)
Definition: analysis_tp.c:539
static void var_type_set(RzAnalysis *analysis, RzAnalysisVar *var, RZ_BORROW RzType *type, bool ref, bool resolve_overlaps)
Definition: analysis_tp.c:112
static RzList * parse_format(RzCore *core, char *fmt)
Definition: analysis_tp.c:216
static bool analysis_emul_init(RzCore *core, RzConfigHold *hc, RzDebugTrace **dt, RzAnalysisEsilTrace **et, RzAnalysisRzilTrace **rt)
Definition: analysis_tp.c:12
static bool type_pos_hit(RzAnalysis *analysis, RzILTraceInstruction *instr_trace, bool in_stack, int size, const char *place)
Definition: analysis_tp.c:47
RzCallable * function_type_derive(RzAnalysis *analysis, RZ_NONNULL const char *fcn_name, bool *owned)
Definition: analysis_tp.c:292
#define MAX_INSTR
Definition: analysis_tp.c:332
static void vars_resolve_overlaps(RzPVector *vars)
Definition: analysis_tp.c:151
static void analysis_emul_restore(RzCore *core, RzConfigHold *hc, RzDebugTrace *dt, RzAnalysisEsilTrace *et, RzAnalysisRzilTrace *rt)
Definition: analysis_tp.c:38
RzAnalysisOp * op_cache_get(HtUP *cache, RzCore *core, ut64 addr)
Definition: analysis_tp.c:279
static void var_type_set_str(RzAnalysis *analysis, RzAnalysisVar *var, const char *type, bool ref)
Definition: analysis_tp.c:158
static void propagate_return_type_pointer(RzCore *core, RzAnalysisOp *aop, RzPVector *used_vars, ut64 addr, struct ReturnTypeAnalysisCtx *ctx)
Definition: analysis_tp.c:573
static void propagate_return_type(RzCore *core, RzAnalysisOp *aop, RzAnalysisOp *next_op, RzILTraceInstruction *trace, struct ReturnTypeAnalysisCtx *ctx, RzPVector *used_vars)
Definition: analysis_tp.c:591
static void var_rename(RzAnalysis *analysis, RzAnalysisVar *v, const char *name, ut64 addr)
Definition: analysis_tp.c:68
static int bb_cmpaddr(const void *_a, const void *_b)
Definition: analysis_tp.c:530
#define DEFAULT_MAX
Definition: analysis_tp.c:330
bool function_argument_type_derive(RZ_NULLABLE const RzCallable *callable, int arg_num, RzType **type, char **name)
Definition: analysis_tp.c:313
lzma_index ** i
Definition: index.h:629
lzma_index * src
Definition: index.h:567
static ut64 baddr(RzBinFile *bf)
Definition: bin_any.c:58
RZ_API RZ_OWN RzType * rz_type_parse_string_single(RzTypeParser *parser, const char *code, char **error_msg)
Parses the single C type definition.
Definition: c_cpp_parser.c:309
RZ_API RzAnalysisOp * rz_core_analysis_op(RzCore *core, ut64 addr, int mask)
Definition: canalysis.c:1033
RZ_API const char * rz_analysis_cc_func(RzAnalysis *analysis, const char *func_name)
Definition: cc.c:220
RZ_API const char * rz_analysis_cc_arg(RzAnalysis *analysis, const char *convention, int n)
Definition: cc.c:122
RZ_API bool rz_analysis_cc_exist(RzAnalysis *analysis, const char *convention)
Definition: cc.c:116
RZ_API int rz_analysis_cc_max_arg(RzAnalysis *analysis, const char *cc)
Definition: cc.c:171
RZ_API const char * rz_analysis_cc_ret(RzAnalysis *analysis, const char *convention)
Definition: cc.c:194
RZ_API int rz_core_esil_step(RzCore *core, ut64 until_addr, const char *until_expr, ut64 *prev_addr, bool stepOver)
Definition: cmd_analysis.c:860
RZ_API ut64 rz_config_get_i(RzConfig *cfg, RZ_NONNULL const char *name)
Definition: config.c:119
RZ_API bool rz_config_get_b(RzConfig *cfg, RZ_NONNULL const char *name)
Definition: config.c:142
RZ_API RzConfigNode * rz_config_set(RzConfig *cfg, RZ_NONNULL const char *name, const char *value)
Definition: config.c:267
RZ_API RzConfigNode * rz_config_set_i(RzConfig *cfg, RZ_NONNULL const char *name, const ut64 i)
Definition: config.c:419
RZ_API RZ_BORROW const char * rz_config_get(RzConfig *cfg, RZ_NONNULL const char *name)
Definition: config.c:75
RZ_API void rz_cons_break_pop(void)
Definition: cons.c:361
RZ_API void rz_cons_break_push(RzConsBreak cb, void *user)
Definition: cons.c:357
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
uint32_t ut32
const char * v
Definition: dsignal.c:12
int max
Definition: enough.c:225
RZ_API RzAnalysisEsilTrace * rz_analysis_esil_trace_new(RzAnalysisEsil *esil)
Definition: esil_trace.c:28
RZ_API void rz_analysis_esil_trace_free(RzAnalysisEsilTrace *trace)
Definition: esil_trace.c:79
RZ_API RZ_BORROW RzILTraceInstruction * rz_analysis_esil_get_instruction_trace(RZ_NONNULL RzAnalysisEsilTrace *etrace, int idx)
Definition: esil_trace.c:263
RZ_DEPRECATE RZ_API RzAnalysisFunction * rz_analysis_get_fcn_in(RzAnalysis *analysis, ut64 addr, int type)
Definition: fcn.c:1687
RZ_API RzAnalysisFunction * rz_analysis_get_function_byname(RzAnalysis *a, const char *name)
Definition: fcn.c:1729
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 bool rz_flag_exist_at(RzFlag *f, const char *flag_prefix, ut16 fp_size, ut64 off)
Definition: flag.c:293
RZ_API RzFlagItem * rz_flag_get_by_spaces(RzFlag *f, ut64 off,...)
Definition: flag.c:326
RZ_API char * sdb_fmt(const char *fmt,...)
Definition: fmt.c:26
RZ_API bool rz_type_is_char_ptr_nested(RZ_NONNULL const RzType *type)
Checks if the pointer RzType is a nested pointer of string ("char **", "char ***",...
Definition: helpers.c:328
RZ_API RzTypeCond rz_type_cond_invert(RzTypeCond cond)
return the inverted condition
Definition: helpers.c:504
RZ_API bool rz_type_is_void_ptr(RZ_NONNULL const RzType *type)
Checks if the pointer RzType is abstract pointer ("void *")
Definition: helpers.c:298
RZ_API bool rz_type_is_default(const RzTypeDB *typedb, RZ_NONNULL const RzType *type)
Checks if the RzType is default.
Definition: helpers.c:399
RZ_API RZ_OWN RzType * rz_type_pointer_of_type(const RzTypeDB *typedb, RZ_NONNULL RzType *type, bool is_const)
Creates a new pointer RzType from the given RzType.
Definition: helpers.c:102
RZ_API bool rz_type_atomic_is_void(const RzTypeDB *typedb, RZ_NONNULL const RzType *type)
Checks if the RzType is "void".
Definition: helpers.c:232
RZ_API bool rz_type_integral_set_sign(const RzTypeDB *typedb, RZ_NONNULL RzType **type, bool sign)
If the type is unsigned it sets the sign.
Definition: helpers.c:430
RZ_API void rz_config_hold_restore(RzConfigHold *h)
Restore whatever config options were previously saved in h.
Definition: hold.c:132
RZ_API RzConfigHold * rz_config_hold_new(RzConfig *cfg)
Create an opaque object to save/restore some configuration options.
Definition: hold.c:116
RZ_API bool rz_config_hold_i(RzConfigHold *h,...)
Save the current values of a list of config options that have integer values.
Definition: hold.c:81
RZ_API void rz_config_hold_free(RzConfigHold *h)
Free a RzConfigHold object h.
Definition: hold.c:152
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
RZ_API bool rz_analysis_il_reg_trace_contains(RzILTraceInstruction *trace, const char *regname, RzILTraceOpType op_type)
Definition: il_trace.c:220
RZ_API RzILTraceRegOp * rz_analysis_il_get_reg_op_trace(RzILTraceInstruction *trace, const char *regname, RzILTraceOpType op_type)
Definition: il_trace.c:172
voidpf void uLong size
Definition: ioapi.h:138
voidpf void * buf
Definition: ioapi.h:138
#define reg(n)
uint8_t ut8
Definition: lh5801.h:11
return memset(p, 0, total)
void * mem
Definition: libc.cpp:91
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 void rz_list_sort(RZ_NONNULL RzList *list, RZ_NONNULL RzListComparator cmp)
Sorts via merge sort or via insertion sort a list.
Definition: list.c:743
RZ_API RZ_BORROW void * rz_list_get_n(RZ_NONNULL const RzList *list, ut32 n)
Returns the N-th element of the list.
Definition: list.c:574
RZ_API ut32 rz_list_length(RZ_NONNULL const RzList *list)
Returns the length of the list.
Definition: list.c:109
RZ_API RZ_BORROW RzListIter * rz_list_append(RZ_NONNULL RzList *list, void *data)
Appends at the end of the list a new element.
Definition: list.c:288
RZ_API void rz_list_free(RZ_NONNULL RzList *list)
Empties the list and frees the list pointer.
Definition: list.c:137
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")
RZ_API bool rz_meta_set_string(RzAnalysis *a, RzAnalysisMetaType type, ut64 addr, const char *s)
Definition: meta.c:141
int type
Definition: mipsasm.c:17
int idx
Definition: setup.py:197
RZ_API void rz_analysis_op_free(void *op)
Definition: op.c:61
RZ_API bool rz_analysis_op_nonlinear(int t)
Definition: op.c:177
insn_type_descr_t types[]
Definition: or1k_disas.c:7
RZ_API ut64 rz_reg_getv(RzReg *reg, const char *name)
Definition: reg.c:332
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 RzRegItem * rz_reg_index_get(RzReg *reg, int idx)
Definition: reg.c:262
RZ_API const char * rz_reg_32_to_64(RzReg *reg, const char *rreg32)
Definition: reg.c:17
#define eprintf(x, y...)
Definition: rlcc.c:7
static RzSocket * s
Definition: rtr.c:28
RZ_API bool rz_reg_set_value(RzReg *reg, RzRegItem *item, ut64 value)
Definition: rvalue.c:186
#define VARPREFIX
Definition: rz_analysis.h:708
#define ARGPREFIX
Definition: rz_analysis.h:709
@ RZ_META_TYPE_VARTYPE
Definition: rz_analysis.h:297
@ RZ_ANALYSIS_OP_DIR_READ
Definition: rz_analysis.h:790
@ RZ_ANALYSIS_OP_DIR_WRITE
Definition: rz_analysis.h:791
@ RZ_ANALYSIS_OP_MASK_BASIC
Definition: rz_analysis.h:440
@ RZ_ANALYSIS_OP_MASK_VAL
Definition: rz_analysis.h:442
@ RZ_ANALYSIS_OP_MASK_ESIL
Definition: rz_analysis.h:441
#define RZ_ANALYSIS_OP_TYPE_MASK
Definition: rz_analysis.h:358
#define RZ_ANALYSIS_ARCHINFO_MIN_OP_SIZE
Definition: rz_analysis.h:98
@ RZ_ANALYSIS_VAR_KIND_REG
Definition: rz_analysis.h:703
@ RZ_ANALYSIS_VAR_KIND_BPV
Definition: rz_analysis.h:704
@ RZ_ANALYSIS_OP_TYPE_CMP
Definition: rz_analysis.h:399
@ RZ_ANALYSIS_OP_TYPE_LOAD
Definition: rz_analysis.h:416
@ RZ_ANALYSIS_OP_TYPE_JMP
Definition: rz_analysis.h:368
@ RZ_ANALYSIS_OP_TYPE_CALL
Definition: rz_analysis.h:378
@ RZ_ANALYSIS_OP_TYPE_STORE
Definition: rz_analysis.h:415
@ RZ_ANALYSIS_OP_TYPE_PUSH
Definition: rz_analysis.h:397
@ RZ_ANALYSIS_OP_TYPE_CJMP
Definition: rz_analysis.h:373
@ RZ_ANALYSIS_OP_TYPE_MOV
Definition: rz_analysis.h:390
@ RZ_ANALYSIS_OP_TYPE_ILL
Definition: rz_analysis.h:387
@ RZ_ANALYSIS_OP_TYPE_UCALL
Definition: rz_analysis.h:379
@ RZ_ANALYSIS_OP_TYPE_RET
Definition: rz_analysis.h:385
@ RZ_ANALYSIS_OP_TYPE_LEA
Definition: rz_analysis.h:417
#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
#define RZ_FLAGS_FS_IMPORTS
Definition: rz_core.h:59
#define RZ_FLAGS_FS_STRINGS
Definition: rz_core.h:66
static ut64 rz_read_ble(const void *src, bool big_endian, int size)
Definition: rz_endian.h:517
RZ_API bool rz_io_read_at(RzIO *io, ut64 addr, ut8 *buf, int len)
Definition: io.c:300
RZ_API int rz_io_nread_at(RzIO *io, ut64 addr, ut8 *buf, int len)
Definition: io.c:338
@ RZ_REG_NAME_SP
Definition: rz_reg.h:44
@ RZ_REG_NAME_BP
Definition: rz_reg.h:46
@ RZ_REG_NAME_PC
Definition: rz_reg.h:43
RZ_API char * rz_str_new(const char *str)
Definition: str.c:865
RZ_API size_t rz_str_ncpy(char *dst, const char *src, size_t n)
Secure string copy with null terminator.
Definition: str.c:923
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 const char * rz_str_constpool_get(RzStrConstPool *pool, const char *str)
Definition: str_constpool.c:19
#define IS_UPPER(c)
Definition: rz_str_util.h:14
#define IS_LOWER(c)
Definition: rz_str_util.h:15
#define IS_DIGIT(x)
Definition: rz_str_util.h:11
RZ_API char * rz_strbuf_get(RzStrBuf *sb)
Definition: strbuf.c:321
RZ_API bool rz_strbuf_is_empty(RzStrBuf *sb)
Definition: strbuf.c:24
@ RZ_TYPE_KIND_IDENTIFIER
Definition: rz_type.h:128
@ RZ_TYPE_KIND_POINTER
Definition: rz_type.h:129
#define RZ_NULLABLE
Definition: rz_types.h:65
#define RZ_NONNULL
Definition: rz_types.h:64
#define RZ_FREE(x)
Definition: rz_types.h:369
#define RZ_BORROW
Definition: rz_types.h:63
#define RZ_MIN(x, y)
#define ST32_MAX
Definition: rz_types_base.h:97
#define RZ_MAX(x, y)
#define UT64_MAX
Definition: rz_types_base.h:86
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
static bool rz_pvector_empty(RzPVector *vec)
Definition: rz_vector.h:246
static void * rz_pvector_at(const RzPVector *vec, size_t index)
Definition: rz_vector.h:236
#define rz_pvector_foreach(vec, it)
Definition: rz_vector.h:334
RZ_API const char * sdb_const_get(Sdb *s, const char *key, ut32 *cas)
Definition: sdb.c:279
#define b(i)
Definition: sha256.c:42
#define f(i)
Definition: sha256.c:46
#define a(i)
Definition: sha256.c:41
struct ReturnTypeAnalysisCtx * retctx
Definition: analysis_tp.c:630
const char * prev_dest
Definition: analysis_tp.c:632
const char * name
Definition: sparc-opc.c:1838
Definition: engine.c:71
Definition: z80asm.h:102
RzAnalysisEsilTrace * trace
Definition: rz_analysis.h:1077
RzTypeCond cond
Definition: rz_analysis.h:818
RzAnalysisOpDirection direction
Definition: rz_analysis.h:831
RzStrConstPool constpool
Definition: rz_analysis.h:620
struct rz_analysis_esil_t * esil
Definition: rz_analysis.h:584
RzTypeDB * typedb
Definition: rz_analysis.h:602
RzAnalysisVarKind kind
Definition: rz_analysis.h:728
RzAnalysisFunction * fcn
Definition: rz_analysis.h:726
RzAnalysis * analysis
Definition: rz_core.h:322
RzDebug * dbg
Definition: rz_core.h:329
RzIO * io
Definition: rz_core.h:313
RzFlag * flags
Definition: rz_core.h:330
RzPrint * print
Definition: rz_core.h:327
RzConfig * config
Definition: rz_core.h:300
RzDebugTrace * trace
Definition: rz_debug.h:281
char * realname
Definition: rz_flag.h:36
int big_endian
Definition: rz_print.h:124
int size
in bits> 8,16,32,64 ... 128/256
Definition: rz_reg.h:120
int index
Index in register profile.
Definition: rz_reg.h:126
type constrained by the type conditions
Definition: rz_type.h:209
RzTypeCond cond
Definition: rz_type.h:210
RzTypeParser * parser
Definition: rz_type.h:37
Definition: sdb.h:63
int pos
Definition: main.c:11
RZ_API void rz_debug_trace_free(RzDebugTrace *trace)
Definition: trace.c:29
RZ_API RzDebugTrace * rz_debug_trace_new(void)
Definition: trace.c:7
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 int rz_type_func_args_count(RzTypeDB *typedb, RZ_NONNULL const char *name)
Searches for the RzCallable type in types database and returns arguments' count.
Definition: function.c:262
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 void rz_type_callable_free(RZ_NONNULL RzCallable *callable)
Frees the RzCallable.
Definition: function.c:55
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
RZ_API bool rz_type_is_integral(const RzTypeDB *typedb, RZ_NONNULL const RzType *type)
Checks if the RzType is Integral typeclass.
Definition: typeclass.c:218
Definition: dis.c:32
RZ_API void rz_analysis_var_resolve_overlaps(RzAnalysisVar *var)
Definition: var.c:77
RZ_API RZ_BORROW RzAnalysisVar * rz_analysis_function_get_var(RzAnalysisFunction *fcn, char kind, int delta)
Definition: var.c:259
RZ_API RZ_BORROW RzPVector * rz_analysis_function_get_vars_used_at(RzAnalysisFunction *fcn, ut64 op_addr)
Definition: var.c:393
RZ_API void rz_analysis_var_add_constraint(RzAnalysisVar *var, RZ_BORROW RzTypeConstraint *constraint)
Definition: var.c:524
RZ_API bool rz_analysis_var_rename(RzAnalysisVar *var, const char *new_name, bool verbose)
Definition: var.c:348
RZ_API RzAnalysisVar * rz_analysis_var_get_dst_var(RzAnalysisVar *var)
Definition: var.c:417
RZ_API void rz_analysis_var_set_type(RzAnalysisVar *var, RZ_OWN RzType *type, bool resolve_overlaps)
Definition: var.c:170
RZ_DEPRECATE RZ_API RzAnalysisVar * rz_analysis_get_used_function_var(RzAnalysis *analysis, ut64 addr)
Definition: var.c:398
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
static char * regname(int reg)
Definition: dis.c:71
static int sp
Definition: z80asm.c:91
static int verbose
Definition: z80asm.c:73
static int addr
Definition: z80asm.c:58
int read(izstream &zs, T *x, Items items)
Definition: zstream.h:115