Rizin
unix-like reverse engineering framework and cli tools
analysis_tp.c File Reference
#include <rz_analysis.h>
#include <rz_util.h>
#include <ht_uu.h>
#include <rz_core.h>

Go to the source code of this file.

Classes

struct  ReturnTypeAnalysisCtx
 
struct  TypeAnalysisCtx
 

Macros

#define LOOP_MAX   10
 
#define DEFAULT_MAX   3
 
#define REGNAME_SIZE   10
 
#define MAX_INSTR   5
 

Functions

static bool analysis_emul_init (RzCore *core, RzConfigHold *hc, RzDebugTrace **dt, RzAnalysisEsilTrace **et, RzAnalysisRzilTrace **rt)
 
static void analysis_emul_restore (RzCore *core, RzConfigHold *hc, RzDebugTrace *dt, RzAnalysisEsilTrace *et, RzAnalysisRzilTrace *rt)
 
static bool type_pos_hit (RzAnalysis *analysis, RzILTraceInstruction *instr_trace, bool in_stack, int size, const char *place)
 
static void var_rename (RzAnalysis *analysis, RzAnalysisVar *v, const char *name, ut64 addr)
 
static void var_type_set_sign (RzAnalysis *analysis, RzAnalysisVar *var, bool sign)
 
static bool var_type_simple_to_complex (const RzTypeDB *typedb, RzType *a, RzType *b)
 
static void var_type_set (RzAnalysis *analysis, RzAnalysisVar *var, RZ_BORROW RzType *type, bool ref, bool resolve_overlaps)
 
static void var_type_set_resolve_overlaps (RzAnalysis *analysis, RzAnalysisVar *var, RZ_BORROW RzType *type, bool ref)
 
static void vars_resolve_overlaps (RzPVector *vars)
 
static void var_type_set_str (RzAnalysis *analysis, RzAnalysisVar *var, const char *type, bool ref)
 
static void get_src_regname (RzCore *core, ut64 addr, char *regname, int size)
 
static ut64 get_addr (RzAnalysis *analysis, const char *regname, int idx)
 
static RzListparse_format (RzCore *core, char *fmt)
 
static void retype_callee_arg (RzAnalysis *analysis, const char *callee_name, bool in_stack, const char *place, int size, RZ_BORROW RzType *type)
 
RzAnalysisOpop_cache_get (HtUP *cache, RzCore *core, ut64 addr)
 
RzCallablefunction_type_derive (RzAnalysis *analysis, RZ_NONNULL const char *fcn_name, bool *owned)
 
bool function_argument_type_derive (RZ_NULLABLE const RzCallable *callable, int arg_num, RzType **type, char **name)
 
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)
 
static int bb_cmpaddr (const void *_a, const void *_b)
 
void free_op_cache_kv (HtUPKv *kv)
 
void handle_stack_canary (RzCore *core, RzAnalysisOp *aop, int cur_idx)
 
static bool return_type_analysis_context_unresolved (struct ReturnTypeAnalysisCtx *ctx)
 
static void propagate_return_type_pointer (RzCore *core, RzAnalysisOp *aop, RzPVector *used_vars, ut64 addr, struct ReturnTypeAnalysisCtx *ctx)
 
static void propagate_return_type (RzCore *core, RzAnalysisOp *aop, RzAnalysisOp *next_op, RzILTraceInstruction *trace, struct ReturnTypeAnalysisCtx *ctx, RzPVector *used_vars)
 
void propagate_types_among_used_variables (RzCore *core, HtUP *op_cache, RzAnalysisFunction *fcn, RzAnalysisBlock *bb, RzAnalysisOp *aop, struct TypeAnalysisCtx *ctx)
 
RZ_API void rz_core_analysis_type_match (RzCore *core, RzAnalysisFunction *fcn, HtUU *loop_table)
 

Macro Definition Documentation

◆ DEFAULT_MAX

#define DEFAULT_MAX   3

Definition at line 330 of file analysis_tp.c.

◆ LOOP_MAX

#define LOOP_MAX   10

Definition at line 10 of file analysis_tp.c.

◆ MAX_INSTR

#define MAX_INSTR   5

Definition at line 332 of file analysis_tp.c.

◆ REGNAME_SIZE

#define REGNAME_SIZE   10

Definition at line 331 of file analysis_tp.c.

Function Documentation

◆ analysis_emul_init()

static bool analysis_emul_init ( RzCore core,
RzConfigHold hc,
RzDebugTrace **  dt,
RzAnalysisEsilTrace **  et,
RzAnalysisRzilTrace **  rt 
)
static

Definition at line 12 of file analysis_tp.c.

12  {
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 }
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
#define NULL
Definition: cris-opc.c:27
RZ_API RzAnalysisEsilTrace * rz_analysis_esil_trace_new(RzAnalysisEsil *esil)
Definition: esil_trace.c:28
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 ut64 rz_reg_getv(RzReg *reg, const char *name)
Definition: reg.c:332
RZ_API const char * rz_reg_get_name(RzReg *reg, int role)
Definition: reg.c:147
#define eprintf(x, y...)
Definition: rlcc.c:7
@ RZ_REG_NAME_SP
Definition: rz_reg.h:44
@ RZ_REG_NAME_BP
Definition: rz_reg.h:46
RzAnalysisEsilTrace * trace
Definition: rz_analysis.h:1077
struct rz_analysis_esil_t * esil
Definition: rz_analysis.h:584
RzAnalysis * analysis
Definition: rz_core.h:322
RzDebug * dbg
Definition: rz_core.h:329
RzConfig * config
Definition: rz_core.h:300
RzDebugTrace * trace
Definition: rz_debug.h:281
RZ_API RzDebugTrace * rz_debug_trace_new(void)
Definition: trace.c:7
static int sp
Definition: z80asm.c:91

References rz_core_t::analysis, rz_core_t::config, rz_core_t::dbg, eprintf, rz_analysis_t::esil, NULL, rz_analysis_t::reg, rz_analysis_esil_trace_new(), rz_config_hold_i(), rz_config_set(), rz_config_set_i(), rz_debug_trace_new(), rz_reg_get_name(), rz_reg_getv(), RZ_REG_NAME_BP, RZ_REG_NAME_SP, sp, rz_analysis_esil_t::trace, and rz_debug_t::trace.

Referenced by rz_core_analysis_type_match().

◆ analysis_emul_restore()

static void analysis_emul_restore ( RzCore core,
RzConfigHold hc,
RzDebugTrace dt,
RzAnalysisEsilTrace et,
RzAnalysisRzilTrace rt 
)
static

Definition at line 38 of file analysis_tp.c.

38  {
43  core->analysis->esil->trace = et;
44  core->dbg->trace = dt;
45 }
RZ_API void rz_analysis_esil_trace_free(RzAnalysisEsilTrace *trace)
Definition: esil_trace.c:79
RZ_API void rz_config_hold_restore(RzConfigHold *h)
Restore whatever config options were previously saved in h.
Definition: hold.c:132
RZ_API void rz_config_hold_free(RzConfigHold *h)
Free a RzConfigHold object h.
Definition: hold.c:152
RZ_API void rz_debug_trace_free(RzDebugTrace *trace)
Definition: trace.c:29

References rz_core_t::analysis, rz_core_t::dbg, rz_analysis_t::esil, rz_analysis_esil_trace_free(), rz_config_hold_free(), rz_config_hold_restore(), rz_debug_trace_free(), rz_analysis_esil_t::trace, and rz_debug_t::trace.

Referenced by rz_core_analysis_type_match().

◆ bb_cmpaddr()

static int bb_cmpaddr ( const void *  _a,
const void *  _b 
)
static

Definition at line 530 of file analysis_tp.c.

530  {
531  const RzAnalysisBlock *a = _a, *b = _b;
532  return a->addr > b->addr ? 1 : (a->addr < b->addr ? -1 : 0);
533 }
#define b(i)
Definition: sha256.c:42
#define a(i)
Definition: sha256.c:41

References a, and b.

Referenced by rz_core_analysis_type_match(), rz_core_link_stroff(), and rz_core_print_function_disasm_json().

◆ free_op_cache_kv()

void free_op_cache_kv ( HtUPKv *  kv)

Definition at line 535 of file analysis_tp.c.

535  {
536  rz_analysis_op_free(kv->value);
537 }
RZ_API void rz_analysis_op_free(void *op)
Definition: op.c:61

References rz_analysis_op_free().

Referenced by rz_core_analysis_type_match().

◆ function_argument_type_derive()

bool function_argument_type_derive ( RZ_NULLABLE const RzCallable callable,
int  arg_num,
RzType **  type,
char **  name 
)

Definition at line 313 of file analysis_tp.c.

313  {
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 }
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")
int type
Definition: mipsasm.c:17
#define rz_return_val_if_fail(expr, val)
Definition: rz_assert.h:108
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
const char * name
Definition: sparc-opc.c:1838
Definition: z80asm.h:102
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

References arg::name, rz_pvector_index_ptr(), rz_pvector_len(), rz_return_val_if_fail, rz_type_clone(), strdup(), and type.

Referenced by type_match().

◆ function_type_derive()

RzCallable* function_type_derive ( RzAnalysis analysis,
RZ_NONNULL const char *  fcn_name,
bool owned 
)

Definition at line 292 of file analysis_tp.c.

292  {
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 }
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
RzTypeDB * typedb
Definition: rz_analysis.h:602
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

References NULL, rz_analysis_function_derive_type(), rz_analysis_get_function_byname(), rz_return_val_if_fail, rz_type_func_get(), and rz_analysis_t::typedb.

Referenced by type_match().

◆ get_addr()

static ut64 get_addr ( RzAnalysis analysis,
const char *  regname,
int  idx 
)
static

Definition at line 200 of file analysis_tp.c.

200  {
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 }
RZ_API RZ_BORROW RzILTraceInstruction * rz_analysis_esil_get_instruction_trace(RZ_NONNULL RzAnalysisEsilTrace *etrace, int idx)
Definition: esil_trace.c:263
RZ_API RzILTraceRegOp * rz_analysis_il_get_reg_op_trace(RzILTraceInstruction *trace, const char *regname, RzILTraceOpType op_type)
Definition: il_trace.c:172
int idx
Definition: setup.py:197
#define UT64_MAX
Definition: rz_types_base.h:86
static char * regname(int reg)
Definition: dis.c:71

References rz_analysis_t::esil, setup::idx, regname(), rz_analysis_esil_get_instruction_trace(), rz_analysis_il_get_reg_op_trace(), rz_analysis_esil_t::trace, and UT64_MAX.

Referenced by type_match().

◆ get_src_regname()

static void get_src_regname ( RzCore core,
ut64  addr,
char *  regname,
int  size 
)
static

Definition at line 172 of file analysis_tp.c.

172  {
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 }
RZ_API RzAnalysisOp * rz_core_analysis_op(RzCore *core, ut64 addr, int mask)
Definition: canalysis.c:1033
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
voidpf void uLong size
Definition: ioapi.h:138
#define reg(n)
return memset(p, 0, total)
RZ_API RzRegItem * rz_reg_get(RzReg *reg, const char *name, int type)
Definition: reg.c:344
RZ_API const char * rz_reg_32_to_64(RzReg *reg, const char *rreg32)
Definition: reg.c:17
@ RZ_ANALYSIS_OP_MASK_VAL
Definition: rz_analysis.h:442
@ RZ_ANALYSIS_OP_MASK_ESIL
Definition: rz_analysis.h:441
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
int size
in bits> 8,16,32,64 ... 128/256
Definition: rz_reg.h:120
Definition: dis.c:32
static int addr
Definition: z80asm.c:58

References addr, rz_core_t::analysis, rz_analysis_t::bits, free(), memset(), reg, rz_analysis_t::reg, regname(), rz_analysis_op_free(), RZ_ANALYSIS_OP_MASK_ESIL, RZ_ANALYSIS_OP_MASK_VAL, rz_core_analysis_op(), rz_reg_32_to_64(), rz_reg_get(), rz_strbuf_get(), rz_strbuf_is_empty(), rz_reg_item_t::size, strdup(), and autogen_x86imm::tmp.

Referenced by propagate_return_type(), propagate_return_type_pointer(), propagate_types_among_used_variables(), and type_match().

◆ handle_stack_canary()

void handle_stack_canary ( RzCore core,
RzAnalysisOp aop,
int  cur_idx 
)

Definition at line 539 of file analysis_tp.c.

539  {
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 }
static void var_rename(RzAnalysis *analysis, RzAnalysisVar *v, const char *name, ut64 addr)
Definition: analysis_tp.c:68
uint32_t ut32
@ RZ_ANALYSIS_OP_MASK_BASIC
Definition: rz_analysis.h:440
#define RZ_ANALYSIS_OP_TYPE_MASK
Definition: rz_analysis.h:358
@ RZ_ANALYSIS_OP_TYPE_MOV
Definition: rz_analysis.h:390
RZ_DEPRECATE RZ_API RzAnalysisVar * rz_analysis_get_used_function_var(RzAnalysis *analysis, ut64 addr)
Definition: var.c:398
ut64(WINAPI *w32_GetEnabledXStateFeatures)()

References rz_analysis_op_t::addr, rz_core_t::analysis, rz_analysis_t::esil, rz_analysis_esil_get_instruction_trace(), rz_analysis_get_used_function_var(), rz_analysis_op_free(), RZ_ANALYSIS_OP_MASK_BASIC, RZ_ANALYSIS_OP_MASK_VAL, RZ_ANALYSIS_OP_TYPE_MASK, RZ_ANALYSIS_OP_TYPE_MOV, rz_core_analysis_op(), rz_analysis_esil_t::trace, type, rz_analysis_op_t::type, ut64(), and var_rename().

Referenced by propagate_types_among_used_variables().

◆ op_cache_get()

RzAnalysisOp* op_cache_get ( HtUP *  cache,
RzCore core,
ut64  addr 
)

Definition at line 279 of file analysis_tp.c.

279  {
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 }
ut8 op
Definition: 6502dis.c:13

References addr, NULL, op, rz_analysis_op_free(), RZ_ANALYSIS_OP_MASK_BASIC, RZ_ANALYSIS_OP_MASK_VAL, and rz_core_analysis_op().

Referenced by propagate_types_among_used_variables(), rz_core_analysis_type_match(), and type_match().

◆ parse_format()

static RzList* parse_format ( RzCore core,
char *  fmt 
)
static

Definition at line 216 of file analysis_tp.c.

216  {
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 }
RZ_API RZ_BORROW const char * rz_config_get(RzConfig *cfg, RZ_NONNULL const char *name)
Definition: config.c:75
RZ_API char * sdb_fmt(const char *fmt,...)
Definition: fmt.c:26
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 RzListIter * rz_list_append(RZ_NONNULL RzList *list, void *data)
Appends at the end of the list a new element.
Definition: list.c:288
static RzSocket * s
Definition: rtr.c:28
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
#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 const char * sdb_const_get(Sdb *s, const char *key, ut32 *cas)
Definition: sdb.c:279
Definition: sdb.h:63

References rz_core_t::analysis, syscall_preprocessing::arr, rz_core_t::config, IS_DIGIT, IS_LOWER, IS_UPPER, NULL, rz_config_get(), rz_list_append(), rz_list_new(), rz_str_ncpy(), s, sdb_const_get(), sdb_fmt(), rz_analysis_t::sdb_fmts, autogen_x86imm::tmp, and type.

Referenced by type_match().

◆ propagate_return_type()

static void propagate_return_type ( RzCore core,
RzAnalysisOp aop,
RzAnalysisOp next_op,
RzILTraceInstruction *  trace,
struct ReturnTypeAnalysisCtx ctx,
RzPVector used_vars 
)
static

Definition at line 591 of file analysis_tp.c.

591  {
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 }
static void get_src_regname(RzCore *core, ut64 addr, char *regname, int size)
Definition: analysis_tp.c:172
#define REGNAME_SIZE
Definition: analysis_tp.c:331
static void var_type_set(RzAnalysis *analysis, RzAnalysisVar *var, RZ_BORROW RzType *type, bool ref, bool resolve_overlaps)
Definition: analysis_tp.c:112
static void vars_resolve_overlaps(RzPVector *vars)
Definition: analysis_tp.c:151
static void propagate_return_type_pointer(RzCore *core, RzAnalysisOp *aop, RzPVector *used_vars, ut64 addr, struct ReturnTypeAnalysisCtx *ctx)
Definition: analysis_tp.c:573
lzma_index * src
Definition: index.h:567
@ RZ_ANALYSIS_OP_DIR_WRITE
Definition: rz_analysis.h:791
#define RZ_FREE(x)
Definition: rz_types.h:369
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
RzAnalysisOpDirection direction
Definition: rz_analysis.h:831

References rz_analysis_op_t::addr, rz_core_t::analysis, rz_analysis_op_t::direction, get_src_regname(), NULL, propagate_return_type_pointer(), REGNAME_SIZE, RZ_ANALYSIS_OP_DIR_WRITE, RZ_ANALYSIS_OP_TYPE_MASK, RZ_ANALYSIS_OP_TYPE_MOV, RZ_FREE, rz_pvector_at(), rz_pvector_empty(), rz_pvector_foreach, src, strdup(), type, rz_analysis_op_t::type, var_type_set(), and vars_resolve_overlaps().

Referenced by propagate_types_among_used_variables().

◆ propagate_return_type_pointer()

static void propagate_return_type_pointer ( RzCore core,
RzAnalysisOp aop,
RzPVector used_vars,
ut64  addr,
struct ReturnTypeAnalysisCtx ctx 
)
static

Definition at line 573 of file analysis_tp.c.

573  {
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 }
@ RZ_ANALYSIS_OP_DIR_READ
Definition: rz_analysis.h:790

References addr, rz_core_t::analysis, rz_analysis_op_t::direction, get_src_regname(), REGNAME_SIZE, RZ_ANALYSIS_OP_DIR_READ, rz_pvector_empty(), rz_pvector_foreach, var_type_set(), and vars_resolve_overlaps().

Referenced by propagate_return_type().

◆ propagate_types_among_used_variables()

void propagate_types_among_used_variables ( RzCore core,
HtUP *  op_cache,
RzAnalysisFunction fcn,
RzAnalysisBlock bb,
RzAnalysisOp aop,
struct TypeAnalysisCtx ctx 
)

Definition at line 636 of file analysis_tp.c.

636  {
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 }
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
#define jmp
static void var_type_set_sign(RzAnalysis *analysis, RzAnalysisVar *var, bool sign)
Definition: analysis_tp.c:91
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
void handle_stack_canary(RzCore *core, RzAnalysisOp *aop, int cur_idx)
Definition: analysis_tp.c:539
#define MAX_INSTR
Definition: analysis_tp.c:332
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(RzCore *core, RzAnalysisOp *aop, RzAnalysisOp *next_op, RzILTraceInstruction *trace, struct ReturnTypeAnalysisCtx *ctx, RzPVector *used_vars)
Definition: analysis_tp.c:591
lzma_index ** i
Definition: index.h:629
ut16 val
Definition: armass64_const.h:6
RZ_API const char * rz_analysis_cc_func(RzAnalysis *analysis, const char *func_name)
Definition: cc.c:220
RZ_API bool rz_analysis_cc_exist(RzAnalysis *analysis, const char *convention)
Definition: cc.c:116
RZ_API const char * rz_analysis_cc_ret(RzAnalysis *analysis, const char *convention)
Definition: cc.c:194
RZ_API bool rz_config_get_b(RzConfig *cfg, RZ_NONNULL const char *name)
Definition: config.c:142
RZ_DEPRECATE RZ_API RzAnalysisFunction * rz_analysis_get_fcn_in(RzAnalysis *analysis, ut64 addr, int type)
Definition: fcn.c:1687
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 RzTypeCond rz_type_cond_invert(RzTypeCond cond)
return the inverted condition
Definition: helpers.c:504
voidpf void * buf
Definition: ioapi.h:138
uint8_t ut8
Definition: lh5801.h:11
@ RZ_ANALYSIS_OP_TYPE_CMP
Definition: rz_analysis.h:399
@ RZ_ANALYSIS_OP_TYPE_LOAD
Definition: rz_analysis.h:416
@ RZ_ANALYSIS_OP_TYPE_CALL
Definition: rz_analysis.h:378
@ RZ_ANALYSIS_OP_TYPE_STORE
Definition: rz_analysis.h:415
@ RZ_ANALYSIS_OP_TYPE_CJMP
Definition: rz_analysis.h:373
@ 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_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 const char * rz_str_constpool_get(RzStrConstPool *pool, const char *str)
Definition: str_constpool.c:19
#define f(i)
Definition: sha256.c:46
#define cond(bop, top, mask, flags)
Definition: engine.c:71
RzTypeCond cond
Definition: rz_analysis.h:818
RzStrConstPool constpool
Definition: rz_analysis.h:620
RzIO * io
Definition: rz_core.h:313
RzFlag * flags
Definition: rz_core.h:330
RzPrint * print
Definition: rz_core.h:327
char * realname
Definition: rz_flag.h:36
int big_endian
Definition: rz_print.h:124
type constrained by the type conditions
Definition: rz_type.h:209
RzTypeCond cond
Definition: rz_type.h:210
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 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

References rz_analysis_function_t::addr, rz_analysis_op_t::addr, rz_analysis_bb_t::addr, rz_core_t::analysis, rz_print_t::big_endian, rz_analysis_op_t::cond, rz_type_constraint_t::cond, rz_core_t::config, rz_analysis_t::constpool, rz_analysis_op_t::direction, rz_analysis_op_t::disp, rz_analysis_t::esil, f, rz_core_t::flags, free(), get_src_regname(), handle_stack_canary(), i, rz_core_t::io, jmp, rz_analysis_op_t::jump, MAX_INSTR, rz_analysis_function_t::name, NULL, op_cache_get(), rz_core_t::print, propagate_return_type(), rz_analysis_op_t::ptr, rz_flag_item_t::realname, rz_analysis_op_t::refptr, reg, REGNAME_SIZE, return_type_analysis_context_unresolved(), rz_analysis_cc_exist(), rz_analysis_cc_func(), rz_analysis_cc_ret(), rz_analysis_esil_get_instruction_trace(), rz_analysis_fcn_bbget_in(), rz_analysis_function_get_vars_used_at(), rz_analysis_function_name_guess(), rz_analysis_get_fcn_in(), RZ_ANALYSIS_OP_DIR_READ, rz_analysis_op_free(), RZ_ANALYSIS_OP_MASK_BASIC, RZ_ANALYSIS_OP_TYPE_CALL, RZ_ANALYSIS_OP_TYPE_CJMP, RZ_ANALYSIS_OP_TYPE_CMP, RZ_ANALYSIS_OP_TYPE_LEA, RZ_ANALYSIS_OP_TYPE_LOAD, RZ_ANALYSIS_OP_TYPE_MASK, RZ_ANALYSIS_OP_TYPE_MOV, RZ_ANALYSIS_OP_TYPE_RET, RZ_ANALYSIS_OP_TYPE_STORE, RZ_ANALYSIS_OP_TYPE_UCALL, rz_analysis_var_add_constraint(), rz_config_get_b(), rz_core_analysis_op(), rz_flag_exist_at(), rz_flag_get_by_spaces(), RZ_FLAGS_FS_IMPORTS, RZ_FLAGS_FS_STRINGS, RZ_FREE, rz_io_read_at(), rz_pvector_at(), rz_pvector_empty(), rz_pvector_foreach, rz_read_ble(), rz_str_constpool_get(), rz_type_cond_invert(), rz_type_func_exist(), rz_type_func_ret(), rz_analysis_op_t::sign, rz_analysis_op_t::size, strdup(), rz_analysis_esil_t::trace, type, rz_analysis_var_t::type, rz_analysis_op_t::type, type_match(), rz_analysis_t::typedb, ut64(), UT64_MAX, rz_analysis_op_t::val, var_type_set(), var_type_set_sign(), var_type_set_str(), and vars_resolve_overlaps().

Referenced by rz_core_analysis_type_match().

◆ return_type_analysis_context_unresolved()

static bool return_type_analysis_context_unresolved ( struct ReturnTypeAnalysisCtx ctx)
inlinestatic

Definition at line 568 of file analysis_tp.c.

568  {
569  return !ctx->resolved && ctx->ret_type && ctx->ret_reg;
570 }

Referenced by propagate_types_among_used_variables().

◆ retype_callee_arg()

static void retype_callee_arg ( RzAnalysis analysis,
const char *  callee_name,
bool  in_stack,
const char *  place,
int  size,
RZ_BORROW RzType type 
)
static

Definition at line 251 of file analysis_tp.c.

251  {
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 }
static void var_type_set_resolve_overlaps(RzAnalysis *analysis, RzAnalysisVar *var, RZ_BORROW RzType *type, bool ref)
Definition: analysis_tp.c:147
@ RZ_ANALYSIS_VAR_KIND_REG
Definition: rz_analysis.h:703
@ RZ_ANALYSIS_VAR_KIND_BPV
Definition: rz_analysis.h:704
int index
Index in register profile.
Definition: rz_reg.h:126
RZ_API RZ_BORROW RzAnalysisVar * rz_analysis_function_get_var(RzAnalysisFunction *fcn, char kind, int delta)
Definition: var.c:259
RZ_API RzAnalysisVar * rz_analysis_var_get_dst_var(RzAnalysisVar *var)
Definition: var.c:417

References rz_analysis_function_t::bp_off, rz_reg_item_t::index, rz_analysis_t::reg, rz_analysis_function_get_var(), rz_analysis_get_function_byname(), rz_analysis_var_get_dst_var(), RZ_ANALYSIS_VAR_KIND_BPV, RZ_ANALYSIS_VAR_KIND_REG, rz_reg_get(), type, and var_type_set_resolve_overlaps().

Referenced by type_match().

◆ rz_core_analysis_type_match()

RZ_API void rz_core_analysis_type_match ( RzCore core,
RzAnalysisFunction fcn,
HtUU *  loop_table 
)

Definition at line 816 of file analysis_tp.c.

816  {
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 }
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 LOOP_MAX
Definition: analysis_tp.c:10
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
void free_op_cache_kv(HtUPKv *kv)
Definition: analysis_tp.c:535
static bool analysis_emul_init(RzCore *core, RzConfigHold *hc, RzDebugTrace **dt, RzAnalysisEsilTrace **et, RzAnalysisRzilTrace **rt)
Definition: analysis_tp.c:12
static void analysis_emul_restore(RzCore *core, RzConfigHold *hc, RzDebugTrace *dt, RzAnalysisEsilTrace *et, RzAnalysisRzilTrace *rt)
Definition: analysis_tp.c:38
static int bb_cmpaddr(const void *_a, const void *_b)
Definition: analysis_tp.c:530
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 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 r
Definition: crypto_rc6.c:12
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 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 void rz_list_free(RZ_NONNULL RzList *list)
Empties the list and frees the list pointer.
Definition: list.c:137
RZ_API bool rz_analysis_op_nonlinear(int t)
Definition: op.c:177
RZ_API RzRegItem * rz_reg_index_get(RzReg *reg, int idx)
Definition: reg.c:262
RZ_API bool rz_reg_set_value(RzReg *reg, RzRegItem *item, ut64 value)
Definition: rvalue.c:186
#define RZ_ANALYSIS_ARCHINFO_MIN_OP_SIZE
Definition: rz_analysis.h:98
@ RZ_ANALYSIS_OP_TYPE_ILL
Definition: rz_analysis.h:387
#define rz_return_if_fail(expr)
Definition: rz_assert.h:100
@ RZ_REG_NAME_PC
Definition: rz_reg.h:43
#define RZ_MAX(x, y)
struct ReturnTypeAnalysisCtx * retctx
Definition: analysis_tp.c:630
RzAnalysisVarKind kind
Definition: rz_analysis.h:728

References addr, rz_analysis_op_t::addr, rz_analysis_bb_t::addr, rz_core_t::analysis, analysis_emul_init(), analysis_emul_restore(), bb_cmpaddr(), rz_analysis_function_t::bbs, rz_core_t::config, rz_core_t::dbg, rz_analysis_var_t::delta, eprintf, rz_analysis_t::esil, free(), free_op_cache_kv(), rz_debug_trace_t::ht, i, rz_analysis_esil_trace_t::instructions, rz_analysis_var_t::kind, LOOP_MAX, rz_analysis_function_t::ninstr, NULL, op_cache_get(), pc, propagate_types_among_used_variables(), r, reg, rz_analysis_t::reg, ReturnTypeAnalysisCtx::resolved, ReturnTypeAnalysisCtx::ret_reg, TypeAnalysisCtx::retctx, rz_analysis_archinfo(), RZ_ANALYSIS_ARCHINFO_MIN_OP_SIZE, rz_analysis_get_functions_in(), rz_analysis_op_nonlinear(), RZ_ANALYSIS_OP_TYPE_ILL, RZ_ANALYSIS_OP_TYPE_RET, rz_analysis_var_get_dst_var(), RZ_ANALYSIS_VAR_KIND_REG, rz_config_hold_new(), rz_cons_break_pop(), rz_cons_break_push(), rz_cons_is_breaked(), rz_core_esil_step(), rz_list_free(), rz_list_sort(), RZ_MAX, rz_pvector_foreach, rz_pvector_len(), rz_reg_get(), rz_reg_get_name(), rz_reg_getv(), rz_reg_index_get(), RZ_REG_NAME_PC, rz_reg_set_value(), rz_return_if_fail, rz_analysis_op_t::size, rz_analysis_bb_t::size, rz_analysis_esil_t::trace, rz_debug_t::trace, rz_analysis_var_t::type, rz_analysis_op_t::type, ut64(), UT64_MAX, var_type_set(), rz_analysis_function_t::vars, and vars_resolve_overlaps().

Referenced by rz_analysis_function_type_matching_handler(), and rz_core_analysis_types_propagation().

◆ type_match()

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 
)
static

type match at a call instruction inside another function

Parameters
fcn_namename of the callee
addraddr of the call instruction
baddraddr of the caller function
cccc of the callee
prev_idxindex in the esil trace
userfncwhether the callee is a user function (affects propagation direction)
caddraddr of the callee

Definition at line 345 of file analysis_tp.c.

346  {
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 }
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
static ut64 get_addr(RzAnalysis *analysis, const char *regname, int idx)
Definition: analysis_tp.c:200
static RzList * parse_format(RzCore *core, char *fmt)
Definition: analysis_tp.c:216
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 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
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 const char * rz_analysis_cc_arg(RzAnalysis *analysis, const char *convention, int n)
Definition: cc.c:122
RZ_API int rz_analysis_cc_max_arg(RzAnalysis *analysis, const char *cc)
Definition: cc.c:171
RZ_API ut64 rz_config_get_i(RzConfig *cfg, RZ_NONNULL const char *name)
Definition: config.c:119
int max
Definition: enough.c:225
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 bool rz_meta_set_string(RzAnalysis *a, RzAnalysisMetaType type, ut64 addr, const char *s)
Definition: meta.c:141
insn_type_descr_t types[]
Definition: or1k_disas.c:7
@ RZ_META_TYPE_VARTYPE
Definition: rz_analysis.h:297
@ RZ_ANALYSIS_OP_TYPE_JMP
Definition: rz_analysis.h:368
@ RZ_ANALYSIS_OP_TYPE_PUSH
Definition: rz_analysis.h:397
RZ_API int rz_io_nread_at(RzIO *io, ut64 addr, ut8 *buf, int len)
Definition: io.c:338
RZ_API char * rz_str_new(const char *str)
Definition: str.c:865
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_TYPE_KIND_POINTER
Definition: rz_type.h:129
#define RZ_MIN(x, y)
#define ST32_MAX
Definition: rz_types_base.h:97
RzTypeParser * parser
Definition: rz_type.h:37
int pos
Definition: main.c:11
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 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 char * rz_type_as_string(const RzTypeDB *typedb, RZ_NONNULL const RzType *type)
Returns the type C representation.
Definition: type.c:817
static int verbose
Definition: z80asm.c:73
int read(izstream &zs, T *x, Items items)
Definition: zstream.h:115

References addr, rz_core_t::analysis, baddr(), rz_analysis_t::bits, rz_core_t::config, DEFAULT_MAX, eprintf, rz_analysis_t::esil, f, rz_core_t::flags, free(), function_argument_type_derive(), function_type_derive(), get_addr(), get_src_regname(), i, setup::idx, rz_analysis_esil_trace_t::instructions, rz_core_t::io, rz_analysis_var_t::kind, max, NULL, op_cache_get(), parse_format(), rz_type_db_t::parser, pos, read(), regname(), REGNAME_SIZE, retype_callee_arg(), rz_analysis_cc_arg(), rz_analysis_cc_max_arg(), rz_analysis_esil_get_instruction_trace(), rz_analysis_get_used_function_var(), rz_analysis_il_get_reg_op_trace(), RZ_ANALYSIS_OP_TYPE_CALL, RZ_ANALYSIS_OP_TYPE_JMP, RZ_ANALYSIS_OP_TYPE_LEA, RZ_ANALYSIS_OP_TYPE_LOAD, RZ_ANALYSIS_OP_TYPE_MOV, RZ_ANALYSIS_OP_TYPE_PUSH, RZ_ANALYSIS_OP_TYPE_STORE, RZ_ANALYSIS_VAR_KIND_REG, rz_config_get_i(), rz_cons_break_pop(), rz_cons_break_push(), rz_flag_get_by_spaces(), RZ_FLAGS_FS_STRINGS, rz_io_nread_at(), rz_list_free(), rz_list_get_n(), rz_list_length(), rz_meta_set_string(), RZ_META_TYPE_VARTYPE, RZ_MIN, rz_pvector_len(), rz_str_new(), rz_str_startswith(), rz_type_as_string(), rz_type_callable_free(), rz_type_free(), rz_type_func_args_count(), RZ_TYPE_KIND_POINTER, rz_type_parse_string_single(), sdb_fmt(), ST32_MAX, autogen_x86imm::tmp, rz_analysis_esil_t::trace, type, rz_analysis_var_t::type, rz_analysis_op_t::type, type_pos_hit(), rz_analysis_t::typedb, types, ut64(), UT64_MAX, var_rename(), var_type_set_resolve_overlaps(), var_type_set_str(), and verbose.

Referenced by propagate_types_among_used_variables().

◆ type_pos_hit()

static bool type_pos_hit ( RzAnalysis analysis,
RzILTraceInstruction *  instr_trace,
bool  in_stack,
int  size,
const char *  place 
)
static

Definition at line 47 of file analysis_tp.c.

47  {
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 }
RZ_API bool rz_analysis_il_reg_trace_contains(RzILTraceInstruction *trace, const char *regname, RzILTraceOpType op_type)
Definition: il_trace.c:220
void * mem
Definition: libc.cpp:91

References mem, rz_analysis_t::reg, rz_analysis_il_reg_trace_contains(), rz_pvector_at(), rz_reg_get_name(), rz_reg_getv(), RZ_REG_NAME_SP, sp, and ut64().

Referenced by type_match().

◆ var_rename()

static void var_rename ( RzAnalysis analysis,
RzAnalysisVar v,
const char *  name,
ut64  addr 
)
static

Definition at line 68 of file analysis_tp.c.

68  {
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 }
const char * v
Definition: dsignal.c:12
#define VARPREFIX
Definition: rz_analysis.h:708
#define ARGPREFIX
Definition: rz_analysis.h:709
#define rz_warn_if_reached()
Definition: rz_assert.h:29
RZ_API bool rz_analysis_var_rename(RzAnalysisVar *var, const char *new_name, bool verbose)
Definition: var.c:348

References addr, ARGPREFIX, rz_analysis_get_fcn_in(), rz_analysis_var_rename(), rz_str_startswith(), rz_warn_if_reached, v, and VARPREFIX.

Referenced by handle_stack_canary(), and type_match().

◆ var_type_set()

static void var_type_set ( RzAnalysis analysis,
RzAnalysisVar var,
RZ_BORROW RzType type,
bool  ref,
bool  resolve_overlaps 
)
static

Definition at line 112 of file analysis_tp.c.

112  {
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 }
static bool var_type_simple_to_complex(const RzTypeDB *typedb, RzType *a, RzType *b)
Definition: analysis_tp.c:99
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
RzAnalysisFunction * fcn
Definition: rz_analysis.h:726
RZ_API void rz_analysis_var_set_type(RzAnalysisVar *var, RZ_OWN RzType *type, bool resolve_overlaps)
Definition: var.c:170

References eprintf, rz_analysis_var_t::fcn, rz_analysis_function_t::name, rz_analysis_var_t::name, rz_analysis_var_set_type(), rz_return_if_fail, rz_type_atomic_is_void(), rz_type_clone(), rz_type_is_default(), rz_type_is_void_ptr(), rz_type_pointer_of_type(), type, rz_analysis_var_t::type, rz_analysis_t::typedb, and var_type_simple_to_complex().

Referenced by propagate_return_type(), propagate_return_type_pointer(), propagate_types_among_used_variables(), rz_core_analysis_type_match(), and var_type_set_resolve_overlaps().

◆ var_type_set_resolve_overlaps()

static void var_type_set_resolve_overlaps ( RzAnalysis analysis,
RzAnalysisVar var,
RZ_BORROW RzType type,
bool  ref 
)
static

Definition at line 147 of file analysis_tp.c.

147  {
148  var_type_set(analysis, var, type, ref, true);
149 }

References type, and var_type_set().

Referenced by retype_callee_arg(), type_match(), and var_type_set_str().

◆ var_type_set_sign()

static void var_type_set_sign ( RzAnalysis analysis,
RzAnalysisVar var,
bool  sign 
)
static

Definition at line 91 of file analysis_tp.c.

91  {
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 }
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 bool rz_type_is_integral(const RzTypeDB *typedb, RZ_NONNULL const RzType *type)
Checks if the RzType is Integral typeclass.
Definition: typeclass.c:218

References rz_return_if_fail, rz_type_integral_set_sign(), rz_type_is_integral(), rz_analysis_var_t::type, and rz_analysis_t::typedb.

Referenced by propagate_types_among_used_variables().

◆ var_type_set_str()

static void var_type_set_str ( RzAnalysis analysis,
RzAnalysisVar var,
const char *  type,
bool  ref 
)
static

Definition at line 158 of file analysis_tp.c.

158  {
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 }

References eprintf, free(), NULL, rz_type_db_t::parser, rz_return_if_fail, rz_type_free(), rz_type_parse_string_single(), type, rz_analysis_t::typedb, and var_type_set_resolve_overlaps().

Referenced by propagate_types_among_used_variables(), and type_match().

◆ var_type_simple_to_complex()

static bool var_type_simple_to_complex ( const RzTypeDB typedb,
RzType a,
RzType b 
)
static

Definition at line 99 of file analysis_tp.c.

99  {
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 }
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_TYPE_KIND_IDENTIFIER
Definition: rz_type.h:128

References a, b, rz_type_is_char_ptr_nested(), rz_type_is_integral(), and RZ_TYPE_KIND_IDENTIFIER.

Referenced by var_type_set().

◆ vars_resolve_overlaps()

static void vars_resolve_overlaps ( RzPVector vars)
static

Definition at line 151 of file analysis_tp.c.

151  {
152  for (size_t i = 0; i < rz_pvector_len(vars); i++) {
153  RzAnalysisVar *var = rz_pvector_at(vars, i);
155  }
156 }
RZ_API void rz_analysis_var_resolve_overlaps(RzAnalysisVar *var)
Definition: var.c:77

References i, rz_analysis_var_resolve_overlaps(), rz_pvector_at(), and rz_pvector_len().

Referenced by propagate_return_type(), propagate_return_type_pointer(), propagate_types_among_used_variables(), and rz_core_analysis_type_match().