Rizin
unix-like reverse engineering framework and cli tools
jmptbl.c File Reference
#include <rz_analysis.h>
#include <rz_parse.h>
#include <rz_util.h>
#include <rz_list.h>
#include <rz_types_overflow.h>

Go to the source code of this file.

Macros

#define aprintf(format, ...)    RZ_LOG_DEBUG(format, __VA_ARGS__)
 

Functions

static void apply_case (RzAnalysis *analysis, RzAnalysisBlock *block, ut64 switch_addr, ut64 offset_sz, ut64 case_addr, ut64 id, ut64 case_addr_loc)
 
static void apply_switch (RzAnalysis *analysis, ut64 switch_addr, ut64 jmptbl_addr, ut64 cases_count, ut64 default_case_addr)
 
RZ_API bool rz_analysis_jmptbl (RzAnalysis *analysis, RzAnalysisFunction *fcn, RzAnalysisBlock *block, ut64 jmpaddr, ut64 table, ut64 tablesize, ut64 default_addr)
 
static bool jmptable_size_is_invalid (RzAnalysisJmpTableParams *params)
 
RZ_API bool rz_analysis_walkthrough_casetbl (RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisFunction *fcn, RZ_NONNULL RzAnalysisBlock *block, RZ_NONNULL RzAnalysisJmpTableParams *params)
 Marks for analysis jump table cases with a space optimization for multiple cases corresponding to the same address. More...
 
RZ_API bool rz_analysis_walkthrough_jmptbl (RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisFunction *fcn, RZ_NONNULL RzAnalysisBlock *block, RZ_NONNULL RzAnalysisJmpTableParams *params)
 Marks the jump table cases for analysis. More...
 
static bool detect_casenum_shift (RzAnalysisOp *op, RzRegItem **cmp_reg, st64 *start_casenum_shift)
 
RZ_API bool rz_analysis_get_delta_jmptbl_info (RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisFunction *fcn, ut64 jmp_address, ut64 lea_address, RZ_NONNULL RzAnalysisJmpTableParams *params)
 Gets some necessary information about a jump table to perform analysis on. More...
 
RZ_API bool rz_analysis_walkthrough_arm_jmptbl_style (RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisFunction *fcn, RZ_NONNULL RzAnalysisBlock *block, RZ_NONNULL RzAnalysisJmpTableParams *params)
 Marks for analysis ARM specific jump table cases. More...
 
RZ_API bool rz_analysis_get_jmptbl_info (RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisFunction *fcn, RZ_NONNULL RzAnalysisBlock *block, ut64 jmp_address, RZ_NONNULL RzAnalysisJmpTableParams *params)
 Gets some necessary information about a jump table to perform analysis on. More...
 

Macro Definition Documentation

◆ aprintf

#define aprintf (   format,
  ... 
)     RZ_LOG_DEBUG(format, __VA_ARGS__)

Definition at line 12 of file jmptbl.c.

Function Documentation

◆ apply_case()

static void apply_case ( RzAnalysis analysis,
RzAnalysisBlock block,
ut64  switch_addr,
ut64  offset_sz,
ut64  case_addr,
ut64  id,
ut64  case_addr_loc 
)
static

Definition at line 15 of file jmptbl.c.

15  {
16  // eprintf ("** apply_case: 0x%"PFMT64x " from 0x%"PFMT64x "\n", case_addr, case_addr_loc);
17  rz_meta_set_data_at(analysis, case_addr_loc, offset_sz);
18  rz_analysis_hint_set_immbase(analysis, case_addr_loc, 10);
19  rz_analysis_xrefs_set(analysis, switch_addr, case_addr, RZ_ANALYSIS_XREF_TYPE_CODE);
20  if (block) {
21  rz_analysis_block_add_switch_case(block, switch_addr, id, case_addr);
22  }
23  if (analysis->flb.set) {
24  char flagname[0x30];
25  snprintf(flagname, sizeof(flagname), "case.0x%" PFMT64x ".%d", (ut64)switch_addr, (int)id);
26  analysis->flb.set(analysis->flb.f, flagname, case_addr, 1);
27  }
28 }
RZ_API void rz_analysis_block_add_switch_case(RzAnalysisBlock *block, ut64 switch_addr, ut64 case_value, ut64 case_addr)
Definition: block.c:575
RZ_API void rz_analysis_hint_set_immbase(RzAnalysis *a, ut64 addr, int base)
Definition: hint.c:229
snprintf
Definition: kernel.h:364
RZ_API void rz_meta_set_data_at(RzAnalysis *a, ut64 addr, ut64 wordsz)
Definition: meta.c:307
@ RZ_ANALYSIS_XREF_TYPE_CODE
Definition: rz_analysis.h:900
#define PFMT64x
Definition: rz_types.h:393
RzFlagBind flb
Definition: rz_analysis.h:575
RzFlagSet set
Definition: rz_flag.h:84
RzFlag * f
Definition: rz_flag.h:78
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
RZ_API bool rz_analysis_xrefs_set(RzAnalysis *analysis, ut64 from, ut64 to, RzAnalysisXRefType type)
Definition: xrefs.c:117

References rz_flag_bind_t::f, rz_analysis_t::flb, PFMT64x, rz_analysis_block_add_switch_case(), rz_analysis_hint_set_immbase(), RZ_ANALYSIS_XREF_TYPE_CODE, rz_analysis_xrefs_set(), rz_meta_set_data_at(), rz_flag_bind_t::set, snprintf, and ut64().

Referenced by rz_analysis_walkthrough_arm_jmptbl_style(), rz_analysis_walkthrough_casetbl(), and rz_analysis_walkthrough_jmptbl().

◆ apply_switch()

static void apply_switch ( RzAnalysis analysis,
ut64  switch_addr,
ut64  jmptbl_addr,
ut64  cases_count,
ut64  default_case_addr 
)
static

Definition at line 30 of file jmptbl.c.

30  {
31  char tmp[0x30];
32  snprintf(tmp, sizeof(tmp), "switch table (%" PFMT64u " cases) at 0x%" PFMT64x, cases_count, jmptbl_addr);
33  rz_meta_set_string(analysis, RZ_META_TYPE_COMMENT, switch_addr, tmp);
34  if (analysis->flb.set) {
35  snprintf(tmp, sizeof(tmp), "switch.0x%08" PFMT64x, switch_addr);
36  analysis->flb.set(analysis->flb.f, tmp, switch_addr, 1);
37  if (default_case_addr != UT64_MAX) {
38  rz_analysis_xrefs_set(analysis, switch_addr, default_case_addr, RZ_ANALYSIS_XREF_TYPE_CODE);
39  snprintf(tmp, sizeof(tmp), "case.default.0x%" PFMT64x, switch_addr);
40  analysis->flb.set(analysis->flb.f, tmp, default_case_addr, 1);
41  }
42  }
43 }
RZ_API bool rz_meta_set_string(RzAnalysis *a, RzAnalysisMetaType type, ut64 addr, const char *s)
Definition: meta.c:141
@ RZ_META_TYPE_COMMENT
Definition: rz_analysis.h:295
#define PFMT64u
Definition: rz_types.h:395
#define UT64_MAX
Definition: rz_types_base.h:86

References rz_flag_bind_t::f, rz_analysis_t::flb, PFMT64u, PFMT64x, RZ_ANALYSIS_XREF_TYPE_CODE, rz_analysis_xrefs_set(), rz_meta_set_string(), RZ_META_TYPE_COMMENT, rz_flag_bind_t::set, snprintf, autogen_x86imm::tmp, and UT64_MAX.

Referenced by rz_analysis_walkthrough_arm_jmptbl_style(), rz_analysis_walkthrough_casetbl(), and rz_analysis_walkthrough_jmptbl().

◆ detect_casenum_shift()

static bool detect_casenum_shift ( RzAnalysisOp op,
RzRegItem **  cmp_reg,
st64 start_casenum_shift 
)
static

Definition at line 255 of file jmptbl.c.

255  {
256  if (!*cmp_reg) {
257  return true;
258  }
259  if (op->dst && op->dst->reg && op->dst->reg->offset == (*cmp_reg)->offset) {
260  if (op->type == RZ_ANALYSIS_OP_TYPE_LEA && op->ptr == UT64_MAX) {
261  *start_casenum_shift = -(st64)op->disp;
262  } else if (op->val != UT64_MAX) {
263  if (op->type == RZ_ANALYSIS_OP_TYPE_ADD) {
264  *start_casenum_shift = -(st64)op->val;
265  } else if (op->type == RZ_ANALYSIS_OP_TYPE_SUB) {
266  *start_casenum_shift = op->val;
267  }
268  } else if (op->type == RZ_ANALYSIS_OP_TYPE_MOV) {
269  *cmp_reg = op->src[0]->reg;
270  return false;
271  }
272  return true;
273  }
274  return false;
275 }
@ RZ_ANALYSIS_OP_TYPE_SUB
Definition: rz_analysis.h:402
@ RZ_ANALYSIS_OP_TYPE_ADD
Definition: rz_analysis.h:401
@ RZ_ANALYSIS_OP_TYPE_MOV
Definition: rz_analysis.h:390
@ RZ_ANALYSIS_OP_TYPE_LEA
Definition: rz_analysis.h:417
#define st64
Definition: rz_types_base.h:10
Definition: dis.c:32

References RZ_ANALYSIS_OP_TYPE_ADD, RZ_ANALYSIS_OP_TYPE_LEA, RZ_ANALYSIS_OP_TYPE_MOV, RZ_ANALYSIS_OP_TYPE_SUB, st64, and UT64_MAX.

Referenced by rz_analysis_get_delta_jmptbl_info(), and rz_analysis_get_jmptbl_info().

◆ jmptable_size_is_invalid()

static bool jmptable_size_is_invalid ( RzAnalysisJmpTableParams *  params)
inlinestatic

Definition at line 60 of file jmptbl.c.

60  {
61  return UT64_MUL_OVFCHK(params->table_count, params->entry_size) ||
62  params->table_count * params->entry_size > ST32_MAX;
63 }
#define ST32_MAX
Definition: rz_types_base.h:97

References ST32_MAX.

Referenced by rz_analysis_walkthrough_casetbl(), and rz_analysis_walkthrough_jmptbl().

◆ rz_analysis_get_delta_jmptbl_info()

RZ_API bool rz_analysis_get_delta_jmptbl_info ( RZ_NONNULL RzAnalysis analysis,
RZ_NONNULL RzAnalysisFunction fcn,
ut64  jmp_address,
ut64  lea_address,
RZ_NONNULL RzAnalysisJmpTableParams *  params 
)

Gets some necessary information about a jump table to perform analysis on.

Gets amount of cases inside a jump table, the default case address and the case shift amount

Parameters
analysisPointer to RzAnalysis instance
fcnPointer to RzAnalysisFunction where jump table ocurred
jmp_addressAddress of jump intruction that uses the table
lea_addrAddress of lea instruction that loads the address of the jump table base
paramsPointer to RzAnalysisJmpTableParams where the results of the function are stored

Definition at line 288 of file jmptbl.c.

288  {
289  rz_return_val_if_fail(analysis && fcn && params, false);
290  bool isValid = false;
291  bool foundCmp = false;
292  ut64 i;
293 
294  RzAnalysisOp tmp_aop = { 0 };
295  if (lea_address > jmp_address) {
296  return false;
297  }
298 
299  params->jmp_address = jmp_address;
300 
301  int search_sz = jmp_address - lea_address;
302  ut8 *buf = malloc(search_sz);
303  if (!buf) {
304  return false;
305  }
306  // search for a cmp register with a reasonable size
307  analysis->iob.read_at(analysis->iob.io, lea_address, (ut8 *)buf, search_sz);
308  RzVector v;
309  rz_vector_init(&v, sizeof(ut64), NULL, NULL);
310  int len = 0;
311  RzRegItem *cmp_reg = NULL;
312  for (i = 0; i + 8 < search_sz; i += len) {
313  len = rz_analysis_op(analysis, &tmp_aop, lea_address + i, buf + i, search_sz - i, RZ_ANALYSIS_OP_MASK_BASIC);
314  if (len < 1) {
315  len = 1;
316  }
317 
318  if (foundCmp) {
319  if (tmp_aop.type != RZ_ANALYSIS_OP_TYPE_CJMP) {
320  continue;
321  }
322 
323  params->default_case = tmp_aop.jump == tmp_aop.jump + len ? tmp_aop.fail : tmp_aop.jump;
324  break;
325  }
326 
328  if (type != RZ_ANALYSIS_OP_TYPE_CMP) {
329  continue;
330  }
331  // get the value of the cmp
332  // for operands in op, check if type is immediate and val is sane
333  // TODO: How? opex?
334 
335  // for the time being, this seems to work
336  // might not actually have a value, let the next step figure out the size then
337  if (tmp_aop.val == UT64_MAX && tmp_aop.refptr == 0) {
338  isValid = true;
339  params->table_count = 0;
340  } else if (tmp_aop.refptr == 0) {
341  isValid = tmp_aop.val < 0x200;
342  params->table_count = tmp_aop.val + 1;
343  } else {
344  isValid = tmp_aop.refptr < 0x200;
345  params->table_count = tmp_aop.refptr + 1;
346  }
347  rz_vector_push(&v, &i);
348  rz_analysis_op(analysis, &tmp_aop, lea_address + i, buf + i, search_sz - i, RZ_ANALYSIS_OP_MASK_VAL);
349  if (tmp_aop.dst && tmp_aop.dst->reg) {
350  cmp_reg = tmp_aop.dst->reg;
351  } else if (tmp_aop.reg) {
352  cmp_reg = rz_reg_get(analysis->reg, tmp_aop.reg, RZ_REG_TYPE_ANY);
353  } else if (tmp_aop.src[0] && tmp_aop.src[0]->reg) {
354  cmp_reg = tmp_aop.src[0]->reg;
355  }
356  rz_analysis_op_fini(&tmp_aop);
357  // TODO: check the jmp for whether val is included in valid range or not (ja vs jae)
358  foundCmp = true;
359  }
360  if (isValid) {
361  params->case_shift = 0;
362  void **it;
363  rz_vector_foreach_prev(&v, it) {
364  const ut64 op_off = *(ut64 *)it;
365  ut64 op_addr = lea_address + op_off;
366  rz_analysis_op(analysis, &tmp_aop, op_addr,
367  buf + op_off, search_sz - op_off,
369  if (detect_casenum_shift(&tmp_aop, &cmp_reg, &params->case_shift)) {
370  rz_analysis_op_fini(&tmp_aop);
371  break;
372  }
373  rz_analysis_op_fini(&tmp_aop);
374  }
375  }
376  rz_vector_fini(&v);
377  free(buf);
378  return isValid;
379 }
size_t len
Definition: 6502dis.c:15
static bool isValid(ut64 addr)
Definition: analysis_objc.c:51
lzma_index ** i
Definition: index.h:629
#define NULL
Definition: cris-opc.c:27
uint32_t ut32
const char * v
Definition: dsignal.c:12
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
voidpf void * buf
Definition: ioapi.h:138
static bool detect_casenum_shift(RzAnalysisOp *op, RzRegItem **cmp_reg, st64 *start_casenum_shift)
Definition: jmptbl.c:255
uint8_t ut8
Definition: lh5801.h:11
void * malloc(size_t size)
Definition: malloc.c:123
int type
Definition: mipsasm.c:17
RZ_API bool rz_analysis_op_fini(RzAnalysisOp *op)
Definition: op.c:37
RZ_API int rz_analysis_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, const ut8 *data, int len, RzAnalysisOpMask mask)
Definition: op.c:96
RZ_API RzRegItem * rz_reg_get(RzReg *reg, const char *name, int type)
Definition: reg.c:344
@ RZ_ANALYSIS_OP_MASK_BASIC
Definition: rz_analysis.h:440
@ RZ_ANALYSIS_OP_MASK_VAL
Definition: rz_analysis.h:442
#define RZ_ANALYSIS_OP_TYPE_MASK
Definition: rz_analysis.h:358
@ RZ_ANALYSIS_OP_TYPE_CMP
Definition: rz_analysis.h:399
@ RZ_ANALYSIS_OP_TYPE_CJMP
Definition: rz_analysis.h:373
#define rz_return_val_if_fail(expr, val)
Definition: rz_assert.h:108
@ RZ_REG_TYPE_ANY
Definition: rz_reg.h:35
RZ_API void * rz_vector_push(RzVector *vec, void *x)
Definition: vector.c:197
RZ_API void rz_vector_fini(RzVector *vec)
Definition: vector.c:61
#define rz_vector_foreach_prev(vec, it)
Definition: rz_vector.h:173
RZ_API void rz_vector_init(RzVector *vec, size_t elem_size, RzVectorFree free, void *free_user)
Definition: vector.c:33
RzAnalysisValue * dst
Definition: rz_analysis.h:840
RzAnalysisValue * src[3]
Definition: rz_analysis.h:839
const char * reg
Definition: rz_analysis.h:845

References detect_casenum_shift(), rz_analysis_op_t::dst, rz_analysis_op_t::fail, free(), i, isValid(), rz_analysis_op_t::jump, len, malloc(), NULL, rz_analysis_op_t::refptr, rz_analysis_value_t::reg, rz_analysis_op_t::reg, rz_analysis_op(), rz_analysis_op_fini(), RZ_ANALYSIS_OP_MASK_BASIC, RZ_ANALYSIS_OP_MASK_VAL, RZ_ANALYSIS_OP_TYPE_CJMP, RZ_ANALYSIS_OP_TYPE_CMP, RZ_ANALYSIS_OP_TYPE_MASK, rz_reg_get(), RZ_REG_TYPE_ANY, rz_return_val_if_fail, rz_vector_fini(), rz_vector_foreach_prev, rz_vector_init(), rz_vector_push(), rz_analysis_op_t::src, type, rz_analysis_op_t::type, ut64(), UT64_MAX, v, and rz_analysis_op_t::val.

Referenced by run_basic_block_analysis().

◆ rz_analysis_get_jmptbl_info()

RZ_API bool rz_analysis_get_jmptbl_info ( RZ_NONNULL RzAnalysis analysis,
RZ_NONNULL RzAnalysisFunction fcn,
RZ_NONNULL RzAnalysisBlock block,
ut64  jmp_address,
RZ_NONNULL RzAnalysisJmpTableParams *  params 
)

Gets some necessary information about a jump table to perform analysis on.

Gets amount of cases inside a jump table, the default case address and the case shift amount

Parameters
analysisPointer to RzAnalysis instance
fcnPointer to RzAnalysisFunction where jump table ocurred
blockPointer to RzAnalysisBlock where the jump instruction related to the jump table ocurred
jmp_addressAddress of jump intruction that uses the table
paramsPointer to RzAnalysisJmpTableParams where the results of the function are stored

Definition at line 443 of file jmptbl.c.

443  {
444  rz_return_val_if_fail(analysis && fcn && params && block, false);
445  bool isValid = false;
446  int i;
447  RzListIter *iter;
448  RzAnalysisBlock *tmp_bb, *prev_bb;
449  prev_bb = 0;
450  if (!fcn->bbs) {
451  return false;
452  }
453 
454  params->jmp_address = jmp_address;
455 
456  /* if UJMP is in .plt section just skip it */
457  RzBinSection *s = analysis->binb.get_vsect_at(analysis->binb.bin, jmp_address);
458  if (s && s->name[0]) {
459  bool in_plt = strstr(s->name, ".plt") != NULL;
460  if (!in_plt && strstr(s->name, "_stubs") != NULL) {
461  /* for mach0 */
462  in_plt = true;
463  }
464  if (in_plt) {
465  return false;
466  }
467  }
468 
469  // search for the predecessor bb
470  rz_list_foreach (fcn->bbs, iter, tmp_bb) {
471  if (tmp_bb->jump == block->addr || tmp_bb->fail == block->addr) {
472  prev_bb = tmp_bb;
473  break;
474  }
475  }
476  // predecessor must be a conditional jump
477  if (!prev_bb || !prev_bb->jump || !prev_bb->fail) {
478  aprintf("Missing predecesessor on basic block conditional jump at 0x%08" PFMT64x ", required by jump table\n", jmp_address);
479  return false;
480  }
481 
482  // default case is the jump target of the unconditional jump
483  params->default_case = prev_bb->jump == block->addr ? prev_bb->fail : prev_bb->jump;
484 
485  RzAnalysisOp tmp_aop = { 0 };
486  ut8 *bb_buf = calloc(1, prev_bb->size);
487  if (!bb_buf) {
488  return false;
489  }
490  // search for a cmp register with a reasonable size
491  analysis->iob.read_at(analysis->iob.io, prev_bb->addr, (ut8 *)bb_buf, prev_bb->size);
492  isValid = false;
493 
494  RzAnalysisHint *hint = rz_analysis_hint_get(analysis, jmp_address);
495  if (hint) {
496  ut64 val = hint->val;
497  rz_analysis_hint_free(hint);
498  if (val != UT64_MAX) {
499  params->table_count = val;
500  return true;
501  }
502  }
503 
504  RzRegItem *cmp_reg = NULL;
505  for (i = prev_bb->ninstr - 1; i >= 0; i--) {
506  const ut64 prev_pos = rz_analysis_block_get_op_offset(prev_bb, i);
507  const ut64 op_addr = rz_analysis_block_get_op_addr(prev_bb, i);
508  if (prev_pos >= prev_bb->size) {
509  continue;
510  }
511  int buflen = prev_bb->size - prev_pos;
512  int len = rz_analysis_op(analysis, &tmp_aop, op_addr,
513  bb_buf + prev_pos, buflen,
516  if (len < 1 || type != RZ_ANALYSIS_OP_TYPE_CMP) {
517  rz_analysis_op_fini(&tmp_aop);
518  continue;
519  }
520  // get the value of the cmp
521  // for operands in op, check if type is immediate and val is sane
522  // TODO: How? opex?
523 
524  // for the time being, this seems to work
525  // might not actually have a value, let the next step figure out the size then
526  if (tmp_aop.val == UT64_MAX && tmp_aop.refptr == 0) {
527  isValid = true;
528  params->table_count = 0;
529  } else if (tmp_aop.refptr == 0 || tmp_aop.val != UT64_MAX) {
530  isValid = tmp_aop.val < 0x200;
531  params->table_count = tmp_aop.val + 1;
532  } else {
533  isValid = tmp_aop.refptr < 0x200;
534  params->table_count = tmp_aop.refptr + 1;
535  }
536  if (isValid) {
537  rz_analysis_op_fini(&tmp_aop);
538  rz_analysis_op(analysis, &tmp_aop, op_addr,
539  bb_buf + prev_pos, buflen,
541  if (tmp_aop.dst && tmp_aop.dst->reg) {
542  cmp_reg = tmp_aop.dst->reg;
543  } else if (tmp_aop.reg) {
544  cmp_reg = rz_reg_get(analysis->reg, tmp_aop.reg, RZ_REG_TYPE_ANY);
545  } else if (tmp_aop.src[0] && tmp_aop.src[0]->reg) {
546  cmp_reg = tmp_aop.src[0]->reg;
547  }
548  }
549  rz_analysis_op_fini(&tmp_aop);
550  // TODO: check the jmp for whether val is included in valid range or not (ja vs jae)
551  break;
552  }
553  if (isValid) {
554  params->case_shift = 0;
555  for (i--; i >= 0; i--) {
556  const ut64 prev_pos = rz_analysis_block_get_op_offset(prev_bb, i);
557  const ut64 op_addr = rz_analysis_block_get_op_addr(prev_bb, i);
558  if (prev_pos >= prev_bb->size) {
559  continue;
560  }
561  int buflen = prev_bb->size - prev_pos;
562  rz_analysis_op(analysis, &tmp_aop, op_addr,
563  bb_buf + prev_pos, buflen,
565  if (detect_casenum_shift(&tmp_aop, &cmp_reg, &params->case_shift)) {
566  rz_analysis_op_fini(&tmp_aop);
567  break;
568  }
569 
570  rz_analysis_op_fini(&tmp_aop);
571  }
572  }
573  free(bb_buf);
574  return isValid;
575 }
ut16 val
Definition: armass64_const.h:6
RZ_API ut64 rz_analysis_block_get_op_addr(RzAnalysisBlock *block, size_t i)
Definition: block.c:1016
RZ_API ut16 rz_analysis_block_get_op_offset(RzAnalysisBlock *block, size_t i)
Definition: block.c:1006
RZ_API RzAnalysisHint * rz_analysis_hint_get(RzAnalysis *a, ut64 addr)
Definition: hint.c:506
RZ_API void rz_analysis_hint_free(RzAnalysisHint *h)
Definition: hint.c:371
#define aprintf(format,...)
Definition: jmptbl.c:12
void * calloc(size_t number, size_t size)
Definition: malloc.c:102
static RzSocket * s
Definition: rtr.c:28
@ RZ_ANALYSIS_OP_MASK_HINT
Definition: rz_analysis.h:443
ut64 buflen
Definition: core.c:76

References rz_analysis_bb_t::addr, aprintf, buflen, calloc(), detect_casenum_shift(), rz_analysis_op_t::dst, rz_analysis_bb_t::fail, free(), i, isValid(), rz_analysis_bb_t::jump, len, rz_analysis_bb_t::ninstr, NULL, PFMT64x, rz_analysis_op_t::refptr, rz_analysis_value_t::reg, rz_analysis_op_t::reg, rz_analysis_block_get_op_addr(), rz_analysis_block_get_op_offset(), rz_analysis_hint_free(), rz_analysis_hint_get(), rz_analysis_op(), rz_analysis_op_fini(), RZ_ANALYSIS_OP_MASK_BASIC, RZ_ANALYSIS_OP_MASK_HINT, RZ_ANALYSIS_OP_MASK_VAL, RZ_ANALYSIS_OP_TYPE_CMP, RZ_ANALYSIS_OP_TYPE_MASK, rz_reg_get(), RZ_REG_TYPE_ANY, rz_return_val_if_fail, s, rz_analysis_bb_t::size, rz_analysis_op_t::src, type, rz_analysis_op_t::type, ut64(), UT64_MAX, val, rz_analysis_hint_t::val, and rz_analysis_op_t::val.

Referenced by run_basic_block_analysis().

◆ rz_analysis_jmptbl()

RZ_API bool rz_analysis_jmptbl ( RzAnalysis analysis,
RzAnalysisFunction fcn,
RzAnalysisBlock block,
ut64  jmpaddr,
ut64  table,
ut64  tablesize,
ut64  default_addr 
)

Definition at line 46 of file jmptbl.c.

46  {
47  RzAnalysisJmpTableParams params = {
48  .jmp_address = jmpaddr,
49  .case_shift = 0,
50  .jmptbl_loc = table,
51  .casetbl_loc = UT64_MAX,
52  .jmptbl_off = table,
53  .entry_size = tablesize,
54  .table_count = tablesize,
55  .default_case = default_addr,
56  };
57  return rz_analysis_walkthrough_jmptbl(analysis, fcn, block, &params);
58 }
RZ_API bool rz_analysis_walkthrough_jmptbl(RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisFunction *fcn, RZ_NONNULL RzAnalysisBlock *block, RZ_NONNULL RzAnalysisJmpTableParams *params)
Marks the jump table cases for analysis.
Definition: jmptbl.c:176

References rz_analysis_walkthrough_jmptbl(), and UT64_MAX.

Referenced by rz_analysis_function_analyze_jmptable_handler().

◆ rz_analysis_walkthrough_arm_jmptbl_style()

RZ_API bool rz_analysis_walkthrough_arm_jmptbl_style ( RZ_NONNULL RzAnalysis analysis,
RZ_NONNULL RzAnalysisFunction fcn,
RZ_NONNULL RzAnalysisBlock block,
RZ_NONNULL RzAnalysisJmpTableParams *  params 
)

Marks for analysis ARM specific jump table cases.

This function works similarly to rz_analysis_walkthrough_jmptbl, but is specific to ARM

Parameters
analysisPointer to RzAnalysis instance
fcnPointer to RzAnalysisFunction to add the new cases
blockPointer to RzAnalysisBlock that originates the switch table
paramsPointer to RzAnalysisJmpTableParams necessary to analyze the jump table

Definition at line 391 of file jmptbl.c.

391  {
392  /*
393  * Example about arm jump table
394  *
395  * 0x000105b4 060050e3 cmp r0, 3
396  * 0x000105b8 00f18f90 addls pc, pc, r0, lsl 2
397  * 0x000105bc 0d0000ea b loc.000105f8
398  * 0x000105c0 050000ea b 0x105dc
399  * 0x000105c4 050000ea b 0x105e0
400  * 0x000105c8 060000ea b 0x105e8
401  * ; CODE XREF from loc._a_7 (+0x10)
402  * 0x000105dc b6ffffea b sym.input_1
403  * ; CODE XREF from loc._a_7 (+0x14)
404  * 0x000105e0 b9ffffea b sym.input_2
405  * ; CODE XREF from loc._a_7 (+0x28)
406  * 0x000105e4 ccffffea b sym.input_7
407  * ; CODE XREF from loc._a_7 (+0x18)
408  * 0x000105e8 bbffffea b sym.input_3
409  */
410  rz_return_val_if_fail(analysis && fcn && block && params, false);
411  ut64 offs, jmpptr;
412 
413  if (params->table_count == 0) {
414  params->table_count = analysis->opt.jmptbl_maxcount;
415  }
416 
417  for (offs = 0; offs + params->entry_size - 1 < params->table_count * params->entry_size; offs += params->entry_size) {
418  jmpptr = params->jmptbl_loc + offs;
419  apply_case(analysis, block, params->jmp_address, params->entry_size, jmpptr, offs / params->entry_size, params->jmptbl_loc + offs);
420  rz_analysis_task_item_new(analysis, params->tasks, fcn, NULL, jmpptr);
421  }
422 
423  if (offs > 0) {
424  if (params->default_case == 0 || params->default_case == UT32_MAX) {
425  params->default_case = UT64_MAX;
426  }
427  apply_switch(analysis, params->jmp_address, params->jmptbl_loc, offs / params->entry_size, params->default_case);
428  }
429  return true;
430 }
RZ_API bool rz_analysis_task_item_new(RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzVector *tasks, RZ_NONNULL RzAnalysisFunction *fcn, RZ_NULLABLE RzAnalysisBlock *block, ut64 address)
Adds a new task item to the tasks parameter.
Definition: fcn.c:1488
static void apply_switch(RzAnalysis *analysis, ut64 switch_addr, ut64 jmptbl_addr, ut64 cases_count, ut64 default_case_addr)
Definition: jmptbl.c:30
static void apply_case(RzAnalysis *analysis, RzAnalysisBlock *block, ut64 switch_addr, ut64 offset_sz, ut64 case_addr, ut64 id, ut64 case_addr_loc)
Definition: jmptbl.c:15
#define UT32_MAX
Definition: rz_types_base.h:99

References apply_case(), apply_switch(), NULL, rz_analysis_task_item_new(), rz_return_val_if_fail, UT32_MAX, ut64(), and UT64_MAX.

Referenced by run_basic_block_analysis().

◆ rz_analysis_walkthrough_casetbl()

RZ_API bool rz_analysis_walkthrough_casetbl ( RZ_NONNULL RzAnalysis analysis,
RZ_NONNULL RzAnalysisFunction fcn,
RZ_NONNULL RzAnalysisBlock block,
RZ_NONNULL RzAnalysisJmpTableParams *  params 
)

Marks for analysis jump table cases with a space optimization for multiple cases corresponding to the same address.

This function works similarly to rz_analysis_walkthrough_jmptbl, with the difference that jump targets are hidden behind a indirection in the case table

Parameters
analysisPointer to RzAnalysis instance
fcnPointer to RzAnalysisFunction to add the new cases
blockPointer to RzAnalysisBlock that originates the switch table
paramsPointer to RzAnalysisJmpTableParams necessary to analyze the jump table

Definition at line 76 of file jmptbl.c.

76  {
77  rz_return_val_if_fail(analysis && fcn && block && params, false);
78  bool ret = true;
79  if (params->table_count == 0) {
80  params->table_count = analysis->opt.jmptbl_maxcount;
81  }
82  if (params->jmptbl_loc == UT64_MAX) {
83  aprintf("Invalid jump table location 0x%08" PFMT64x "\n", params->jmptbl_loc);
84  return false;
85  }
86  if (params->casetbl_loc == UT64_MAX) {
87  aprintf("Invalid case table location 0x%08" PFMT64x "\n", params->jmptbl_loc);
88  return false;
89  }
90  if (jmptable_size_is_invalid(params)) {
91  aprintf("Invalid jump table size at 0x%08" PFMT64x "\n", params->jmp_address);
92  return false;
93  }
94  ut64 jmpptr, case_idx, jmpptr_idx;
95  ut8 *jmptbl = calloc(params->table_count, params->entry_size);
96  if (!jmptbl || !analysis->iob.read_at(analysis->iob.io, params->jmptbl_loc, jmptbl, params->table_count * params->entry_size)) {
97  free(jmptbl);
98  return false;
99  }
100  ut8 *casetbl = calloc(params->table_count, sizeof(ut8));
101  if (!casetbl || !analysis->iob.read_at(analysis->iob.io, params->casetbl_loc, casetbl, params->table_count)) {
102  free(jmptbl);
103  free(casetbl);
104  return false;
105  }
106  for (case_idx = 0; case_idx < params->table_count; case_idx++) {
107  jmpptr_idx = casetbl[case_idx];
108 
109  if (jmpptr_idx >= params->table_count) {
110  ret = false;
111  break;
112  }
113 
114  switch (params->entry_size) {
115  case 1:
116  jmpptr = rz_read_le8(jmptbl + jmpptr_idx);
117  break;
118  case 2:
119  jmpptr = rz_read_le16(jmptbl + jmpptr_idx * 2);
120  break;
121  case 4:
122  jmpptr = rz_read_le32(jmptbl + jmpptr_idx * 4);
123  break;
124  default:
125  jmpptr = rz_read_le64(jmptbl + jmpptr_idx * 8);
126  break;
127  }
128  if (jmpptr == 0 || jmpptr == UT32_MAX || jmpptr == UT64_MAX) {
129  break;
130  }
131  if (!analysis->iob.is_valid_offset(analysis->iob.io, jmpptr, 0)) {
132  st32 jmpdelta = (st32)jmpptr;
133  // jump tables where sign extended movs are used
134  jmpptr = params->jmptbl_off + jmpdelta;
135  if (!analysis->iob.is_valid_offset(analysis->iob.io, jmpptr, 0)) {
136  break;
137  }
138  }
139  if (analysis->limit) {
140  if (jmpptr < analysis->limit->from || jmpptr > analysis->limit->to) {
141  break;
142  }
143  }
144 
145  const ut64 jmpptr_idx_off = params->casetbl_loc + case_idx;
146  rz_meta_set_data_at(analysis, jmpptr_idx_off, 1);
147  rz_analysis_hint_set_immbase(analysis, jmpptr_idx_off, 10);
148 
149  apply_case(analysis, block, params->jmp_address, params->entry_size, jmpptr, case_idx + params->case_shift, params->jmptbl_loc + jmpptr_idx * params->entry_size);
150  rz_analysis_task_item_new(analysis, params->tasks, fcn, NULL, jmpptr);
151  }
152 
153  if (case_idx > 0) {
154  if (params->default_case == 0) {
155  params->default_case = UT64_MAX;
156  }
157  apply_switch(analysis, params->jmp_address, params->jmptbl_loc, case_idx, params->default_case);
158  }
159 
160  free(jmptbl);
161  free(casetbl);
162  return ret;
163 }
static bool jmptable_size_is_invalid(RzAnalysisJmpTableParams *params)
Definition: jmptbl.c:60
static uint32_t const uint8_t uint32_t uint32_t limit
Definition: memcmplen.h:45
static ut16 rz_read_le16(const void *src)
Definition: rz_endian.h:206
static ut32 rz_read_le32(const void *src)
Definition: rz_endian.h:239
static ut8 rz_read_le8(const void *src)
Definition: rz_endian.h:187
static ut64 rz_read_le64(const void *src)
Definition: rz_endian.h:266
#define st32
Definition: rz_types_base.h:12

References apply_case(), apply_switch(), aprintf, calloc(), free(), jmptable_size_is_invalid(), limit, NULL, PFMT64x, rz_analysis_hint_set_immbase(), rz_analysis_task_item_new(), rz_meta_set_data_at(), rz_read_le16(), rz_read_le32(), rz_read_le64(), rz_read_le8(), rz_return_val_if_fail, st32, UT32_MAX, ut64(), and UT64_MAX.

Referenced by run_basic_block_analysis().

◆ rz_analysis_walkthrough_jmptbl()

RZ_API bool rz_analysis_walkthrough_jmptbl ( RZ_NONNULL RzAnalysis analysis,
RZ_NONNULL RzAnalysisFunction fcn,
RZ_NONNULL RzAnalysisBlock block,
RZ_NONNULL RzAnalysisJmpTableParams *  params 
)

Marks the jump table cases for analysis.

Goes through each case on the jump table, adds necessary flags/metadata and a new RzAnalysisTaskItem to params->tasks to be analyzed later.

Parameters
analysisPointer to RzAnalysis instance
fcnPointer to RzAnalysisFunction to add the new cases
blockPointer to RzAnalysisBlock that originates the switch table
paramsPointer to RzAnalysisJmpTableParams necessary to analyze the jump table

Definition at line 176 of file jmptbl.c.

176  {
177  rz_return_val_if_fail(analysis && fcn && block && params, false);
178  // table_count can not always be determined
179  if (params->table_count == 0) {
180  params->table_count = analysis->opt.jmptbl_maxcount;
181  }
182  if (params->jmptbl_loc == UT64_MAX) {
183  aprintf("Invalid jump table location 0x%08" PFMT64x "\n", params->jmptbl_loc);
184  return false;
185  }
186  if (jmptable_size_is_invalid(params)) {
187  aprintf("Invalid jump table size at 0x%08" PFMT64x "\n", params->jmp_address);
188  return false;
189  }
190  ut64 jmpptr, offs;
191  ut8 *jmptbl = calloc(params->table_count, params->entry_size);
192  if (!jmptbl) {
193  return false;
194  }
195  bool is_arm = analysis->cur->arch && !strncmp(analysis->cur->arch, "arm", 3);
196  // eprintf ("JMPTBL AT 0x%"PFMT64x"\n", jmptbl_loc);
197  analysis->iob.read_at(analysis->iob.io, params->jmptbl_loc, jmptbl, params->table_count * params->entry_size);
198  for (offs = 0; offs + params->entry_size - 1 < params->table_count * params->entry_size; offs += params->entry_size) {
199  switch (params->entry_size) {
200  case 1:
201  jmpptr = (ut64)(ut8)rz_read_le8(jmptbl + offs);
202  break;
203  case 2:
204  jmpptr = (ut64)rz_read_le16(jmptbl + offs);
205  break;
206  case 4:
207  jmpptr = rz_read_le32(jmptbl + offs);
208  break;
209  case 8:
210  jmpptr = rz_read_le64(jmptbl + offs);
211  break; // XXX
212  default:
213  jmpptr = rz_read_le64(jmptbl + offs);
214  break;
215  }
216  // eprintf ("WALKING %llx\n", jmpptr);
217  // if we don't check for 0 here, the next check with ptr+jmpptr
218  // will obviously be a good offset since it will be the start
219  // of the table, which is not what we want
220  if (jmpptr == 0 || jmpptr == UT32_MAX || jmpptr == UT64_MAX) {
221  break;
222  }
223  if (params->entry_size == 2 && is_arm) {
224  jmpptr = params->jmp_address + 4 + (jmpptr * 2); // tbh [pc, r2, lsl 1] // assume lsl 1
225  } else if (params->entry_size == 1 && is_arm) {
226  jmpptr = params->jmp_address + 4 + (jmpptr * 2); // lbb [pc, r2] // assume lsl 1
227  } else if (!analysis->iob.is_valid_offset(analysis->iob.io, jmpptr, 0)) {
228  st32 jmpdelta = (st32)jmpptr;
229  // jump tables where sign extended movs are used
230  jmpptr = params->jmptbl_off + jmpdelta;
231  if (!analysis->iob.is_valid_offset(analysis->iob.io, jmpptr, 0)) {
232  break;
233  }
234  }
235  if (analysis->limit) {
236  if (jmpptr < analysis->limit->from || jmpptr > analysis->limit->to) {
237  break;
238  }
239  }
240  apply_case(analysis, block, params->jmp_address, params->entry_size, jmpptr, (offs / params->entry_size) + params->case_shift, params->jmptbl_loc + offs);
241  rz_analysis_task_item_new(analysis, params->tasks, fcn, NULL, jmpptr);
242  }
243 
244  if (offs > 0) {
245  if (params->default_case == 0) {
246  params->default_case = UT64_MAX;
247  }
248  apply_switch(analysis, params->jmp_address, params->jmptbl_loc, offs / params->entry_size, params->default_case);
249  }
250 
251  free(jmptbl);
252  return true;
253 }
static int is_arm(RzBinPEObj *bin)
Definition: pe_info.c:12

References apply_case(), apply_switch(), aprintf, calloc(), free(), is_arm(), jmptable_size_is_invalid(), limit, NULL, PFMT64x, rz_analysis_task_item_new(), rz_read_le16(), rz_read_le32(), rz_read_le64(), rz_read_le8(), rz_return_val_if_fail, st32, UT32_MAX, ut64(), and UT64_MAX.

Referenced by run_basic_block_analysis(), and rz_analysis_jmptbl().