Reduce analysis recursion (#1284)

* Reduce recursion when analyzing function control-flow
* Jump table refactoring
* Use rz_ prefix for the API
* Use struct instead of long parameter list
* Add `analysis.jmp.tblmax` to configure maximun amount of cases to analyze
* Remove recursion
This commit is contained in:
GustavoLCR 2021-07-10 08:52:31 -03:00 committed by GitHub
parent f340b90fd7
commit 146d3b5d4f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 478 additions and 297 deletions

View file

@ -11,7 +11,6 @@
#define READ_AHEAD 1
#define SDB_KEY_BB "bb.0x%" PFMT64x ".0x%" PFMT64x
// XXX must be configurable by the user
#define JMPTBLSZ 512
#define JMPTBL_LEA_SEARCH_SZ 64
#define JMPTBL_MAXFCNSIZE 4096
#define BB_ALIGN 0x10
@ -521,12 +520,31 @@ static inline bool does_arch_destroys_dst(const char *arch) {
return arch && (!strncmp(arch, "arm", 3) || !strcmp(arch, "riscv") || !strcmp(arch, "ppc"));
}
static int fcn_recurse(RzAnalysis *analysis, RzAnalysisFunction *fcn, ut64 addr, ut64 len, int depth) {
static int analyze_function_locally(RzAnalysis *analysis, RzAnalysisFunction *fcn, ut64 address) {
rz_return_val_if_fail(analysis && fcn, RZ_ANALYSIS_RET_ERROR);
RzVector tasks;
rz_vector_init(&tasks, sizeof(RzAnalysisTaskItem), NULL, NULL);
RzAnalysisTaskItem item = { fcn, NULL, fcn->stack, address };
rz_vector_push(&tasks, &item);
int saved_stack = fcn->stack; // TODO: DO NOT use fcn->stack to keep track of stack during analysis
int ret = rz_analysis_run_tasks(&tasks);
rz_vector_fini(&tasks);
fcn->stack = saved_stack;
return ret;
}
static int run_basic_block_analysis(RzAnalysisTaskItem *item, RzVector *tasks) {
rz_return_val_if_fail(item && tasks, RZ_ANALYSIS_RET_ERROR);
RzAnalysis *analysis = item->fcn->analysis;
RzAnalysisFunction *fcn = item->fcn;
fcn->stack = item->stack;
ut64 addr = item->start_address;
ut64 len = analysis->opt.bb_max_size;
const int continue_after_jump = analysis->opt.afterjmp;
const int addrbytes = analysis->iob.io ? analysis->iob.io->addrbytes : 1;
char *last_reg_mov_lea_name = NULL;
char *movbasereg = NULL;
RzAnalysisBlock *bb = NULL;
RzAnalysisBlock *bb = item->block;
RzAnalysisBlock *bbg = NULL;
int ret = RZ_ANALYSIS_RET_END, skip_ret = 0;
bool overlapped = false;
@ -558,19 +576,13 @@ static int fcn_recurse(RzAnalysis *analysis, RzAnalysisFunction *fcn, ut64 addr,
bool has_variadic_reg = !!variadic_reg;
if (rz_cons_is_breaked()) {
rz_analysis_task_item_new(analysis, tasks, fcn, bb, addr);
return RZ_ANALYSIS_RET_END;
}
if (analysis->sleep) {
rz_sys_usleep(analysis->sleep);
}
if (depth < 1) {
if (analysis->verbose) {
eprintf("Analysis went too deep at address 0x%" PFMT64x ".\n", addr);
}
return RZ_ANALYSIS_RET_ERROR; // MUST BE TOO DEEP
}
// check if address is readable //:
if (!analysis->iob.is_valid_offset(analysis->iob.io, addr, 0)) {
if (addr != UT64_MAX && !analysis->iob.io->va) {
@ -586,31 +598,33 @@ static int fcn_recurse(RzAnalysis *analysis, RzAnalysisFunction *fcn, ut64 addr,
return RZ_ANALYSIS_RET_ERROR; // MUST BE NOT FOUND
}
RzAnalysisBlock *existing_bb = bbget(analysis, addr, analysis->opt.jmpmid && is_x86);
if (existing_bb) {
bool existing_in_fcn = rz_list_contains(existing_bb->fcns, fcn);
existing_bb = rz_analysis_block_split(existing_bb, addr);
if (!existing_in_fcn && existing_bb) {
if (existing_bb->addr == fcn->addr) {
// our function starts directly there, so we steal what is ours!
fcn_takeover_block_recursive(fcn, existing_bb);
}
}
if (!bb) {
RzAnalysisBlock *existing_bb = bbget(analysis, addr, analysis->opt.jmpmid && is_x86);
if (existing_bb) {
rz_analysis_block_unref(existing_bb);
bool existing_in_fcn = rz_list_contains(existing_bb->fcns, fcn);
existing_bb = rz_analysis_block_split(existing_bb, addr);
if (!existing_in_fcn && existing_bb) {
if (existing_bb->addr == fcn->addr) {
// our function starts directly there, so we steal what is ours!
fcn_takeover_block_recursive(fcn, existing_bb);
}
}
if (existing_bb) {
rz_analysis_block_unref(existing_bb);
}
if (analysis->opt.recont) {
return RZ_ANALYSIS_RET_END;
}
if (analysis->verbose) {
eprintf("rz_analysis_fcn_bb() fails at 0x%" PFMT64x ".\n", addr);
}
return RZ_ANALYSIS_RET_ERROR; // MUST BE NOT DUP
}
if (analysis->opt.recont) {
return RZ_ANALYSIS_RET_END;
}
if (analysis->verbose) {
eprintf("rz_analysis_fcn_bb() fails at 0x%" PFMT64x ".\n", addr);
}
return RZ_ANALYSIS_RET_ERROR; // MUST BE NOT DUP
}
bb = fcn_append_basic_block(analysis, fcn, addr);
// we checked before whether there is a bb at addr, so the create should have succeeded
rz_return_val_if_fail(bb, RZ_ANALYSIS_RET_ERROR);
item->block = bb = fcn_append_basic_block(analysis, fcn, addr);
// we checked before whether there is a bb at addr, so the create should have succeeded
rz_return_val_if_fail(bb, RZ_ANALYSIS_RET_ERROR);
}
if (!analysis->leaddrs) {
analysis->leaddrs = rz_list_newf(free_leaddr_pair);
@ -662,6 +676,8 @@ static int fcn_recurse(RzAnalysis *analysis, RzAnalysisFunction *fcn, ut64 addr,
}
while (addrbytes * idx < maxlen) {
ut32 at_delta;
ut64 at;
if (!last_is_reg_mov_lea) {
free(last_reg_mov_lea_name);
last_reg_mov_lea_name = NULL;
@ -670,11 +686,12 @@ static int fcn_recurse(RzAnalysis *analysis, RzAnalysisFunction *fcn, ut64 addr,
break;
}
repeat:
at_delta = addrbytes * idx;
at = addr + at_delta;
if (rz_cons_is_breaked()) {
rz_analysis_task_item_new(analysis, tasks, fcn, bb, at);
break;
}
ut32 at_delta = addrbytes * idx;
ut64 at = addr + at_delta;
ut64 bytes_read = RZ_MIN(len - at_delta, sizeof(buf));
ret = read_ahead(analysis, at, buf, bytes_read);
@ -764,7 +781,7 @@ static int fcn_recurse(RzAnalysis *analysis, RzAnalysisFunction *fcn, ut64 addr,
bb->jump = at + oplen;
if (from_addr != bb->addr) {
bb->fail = handle_addr;
ret = rz_analysis_fcn_bb(analysis, fcn, handle_addr, depth);
ret = analyze_function_locally(analysis, fcn, handle_addr);
eprintf("(%s) 0x%08" PFMT64x "\n", handle, handle_addr);
if (bb->size == 0) {
rz_analysis_function_remove_block(fcn, bb);
@ -941,18 +958,24 @@ static int fcn_recurse(RzAnalysis *analysis, RzAnalysisFunction *fcn, ut64 addr,
ut64 jmptbl_addr = op.ptr;
ut64 casetbl_addr = op.ptr;
if (is_delta_pointer_table(analysis, fcn, op.addr, op.ptr, &jmptbl_addr, &casetbl_addr, &jmp_aop)) {
ut64 table_size, default_case = 0;
st64 case_shift;
// we require both checks here since try_get_jmptbl_info uses
// we require both checks here since rz_analysis_get_jmptbl_info uses
// BB info of the final jmptbl jump, which is no present with
// is_delta_pointer_table just scanning ahead
// try_get_delta_jmptbl_info doesn't work at times where the
// rz_analysis_get_delta_jmptbl_info doesn't work at times where the
// lea comes after the cmp/default case cjmp, which can be
// handled with try_get_jmptbl_info
if (try_get_jmptbl_info(analysis, fcn, jmp_aop.addr, bb, &table_size, &default_case, &case_shift) || try_get_delta_jmptbl_info(analysis, fcn, jmp_aop.addr, op.addr, &table_size, &default_case, &case_shift)) {
// handled with rz_analysis_get_jmptbl_info
RzAnalysisJmpTableParams params = {
.jmp_address = jmp_aop.addr,
.jmptbl_loc = jmptbl_addr,
.casetbl_loc = casetbl_addr,
.entry_size = 4,
.jmptbl_off = op.ptr,
.tasks = tasks
};
if (rz_analysis_get_jmptbl_info(analysis, fcn, bb, jmp_aop.addr, &params) || rz_analysis_get_delta_jmptbl_info(analysis, fcn, jmp_aop.addr, op.addr, &params)) {
ret = casetbl_addr == op.ptr
? try_walkthrough_jmptbl(analysis, fcn, bb, depth, jmp_aop.addr, case_shift, jmptbl_addr, op.ptr, 4, table_size, default_case, 4)
: try_walkthrough_casetbl(analysis, fcn, bb, depth, jmp_aop.addr, case_shift, jmptbl_addr, casetbl_addr, op.ptr, 4, table_size, default_case, 4);
? rz_analysis_walkthrough_jmptbl(analysis, fcn, bb, &params)
: rz_analysis_walkthrough_casetbl(analysis, fcn, bb, &params);
if (ret) {
lea_jmptbl_ip = jmp_aop.addr;
}
@ -1028,7 +1051,7 @@ static int fcn_recurse(RzAnalysis *analysis, RzAnalysisFunction *fcn, ut64 addr,
bb->jump = op.jump;
bb->fail = UT64_MAX;
}
ret = rz_analysis_fcn_bb(analysis, fcn, op.jump, depth);
rz_analysis_task_item_new(analysis, tasks, fcn, NULL, op.jump);
int tc = analysis->opt.tailcall;
if (tc) {
// eprintf ("TAIL CALL AT 0x%llx\n", op.addr);
@ -1037,11 +1060,11 @@ static int fcn_recurse(RzAnalysis *analysis, RzAnalysisFunction *fcn, ut64 addr,
ut8 buf[32];
(void)analysis->iob.read_at(analysis->iob.io, op.jump, (ut8 *)buf, sizeof(buf));
if (rz_analysis_is_prelude(analysis, buf, sizeof(buf))) {
fcn_recurse(analysis, fcn, op.jump, analysis->opt.bb_max_size, depth - 1);
rz_analysis_task_item_new(analysis, tasks, fcn, NULL, op.jump);
}
} else if (RZ_ABS(diff) > tc) {
(void)rz_analysis_xrefs_set(analysis, op.addr, op.jump, RZ_ANALYSIS_REF_TYPE_CALL);
fcn_recurse(analysis, fcn, op.jump, analysis->opt.bb_max_size, depth - 1);
rz_analysis_task_item_new(analysis, tasks, fcn, NULL, op.jump);
gotoBeach(RZ_ANALYSIS_RET_END);
}
}
@ -1080,14 +1103,22 @@ static int fcn_recurse(RzAnalysis *analysis, RzAnalysisFunction *fcn, ut64 addr,
}
if (analysis->opt.jmptbl) {
if (op.ptr != UT64_MAX) {
ut64 table_size, default_case;
table_size = cmpval + 1;
default_case = op.fail; // is this really default case?
if (cmpval != UT64_MAX && default_case != UT64_MAX && (op.reg || op.ireg)) {
if (cmpval != UT64_MAX && op.fail != UT64_MAX && (op.reg || op.ireg)) {
RzAnalysisJmpTableParams params = {
.jmp_address = op.addr,
.case_shift = 0,
.jmptbl_loc = op.ptr,
.casetbl_loc = UT64_MAX,
.entry_size = analysis->bits >> 3,
.table_count = cmpval + 1,
.jmptbl_off = op.ptr,
.default_case = op.fail,
.tasks = tasks
};
if (op.ireg) {
try_walkthrough_jmptbl(analysis, fcn, bb, depth, op.addr, 0, op.ptr, op.ptr, analysis->bits >> 3, table_size, default_case, ret);
rz_analysis_walkthrough_jmptbl(analysis, fcn, bb, &params);
} else { // op.reg
walkthrough_arm_jmptbl_style(analysis, fcn, bb, depth, op.addr, op.ptr, analysis->bits >> 3, table_size, default_case, ret);
rz_analysis_walkthrough_arm_jmptbl_style(analysis, fcn, bb, &params);
}
// check if op.jump and op.fail contain jump table location
// clear jump address, because it's jump table location
@ -1100,17 +1131,9 @@ static int fcn_recurse(RzAnalysis *analysis, RzAnalysisFunction *fcn, ut64 addr,
}
}
}
int saved_stack = fcn->stack;
if (continue_after_jump) {
rz_analysis_fcn_bb(analysis, fcn, op.jump, depth);
fcn->stack = saved_stack;
ret = rz_analysis_fcn_bb(analysis, fcn, op.fail, depth);
fcn->stack = saved_stack;
} else {
rz_analysis_fcn_bb(analysis, fcn, op.jump, depth);
fcn->stack = saved_stack;
ret = rz_analysis_fcn_bb(analysis, fcn, op.fail, depth);
fcn->stack = saved_stack;
rz_analysis_task_item_new(analysis, tasks, fcn, NULL, op.fail);
rz_analysis_task_item_new(analysis, tasks, fcn, NULL, op.jump);
if (!continue_after_jump) {
if (op.jump < fcn->addr) {
if (!overlapped) {
bb->jump = op.jump;
@ -1172,12 +1195,17 @@ static int fcn_recurse(RzAnalysis *analysis, RzAnalysisFunction *fcn, ut64 addr,
}
// switch statement
if (analysis->opt.jmptbl && lea_jmptbl_ip != op.addr) {
RzAnalysisJmpTableParams params = {
.jmp_address = op.addr,
.entry_size = analysis->bits >> 3,
.jmptbl_loc = op.ptr,
.jmptbl_off = op.ptr,
.tasks = tasks
};
// op.ireg since rip relative addressing produces way too many false positives otherwise
// op.ireg is 0 for rip relative, "rax", etc otherwise
if (op.ptr != UT64_MAX && op.ireg) { // direct jump
ut64 table_size, default_case;
st64 case_shift;
if (try_get_jmptbl_info(analysis, fcn, op.addr, bb, &table_size, &default_case, &case_shift)) {
if (rz_analysis_get_jmptbl_info(analysis, fcn, bb, op.addr, &params)) {
bool case_table = false;
RzAnalysisOp prev_op;
analysis->iob.read_at(analysis->iob.io, op.addr - op.size, buf, sizeof(buf));
@ -1188,30 +1216,26 @@ static int fcn_recurse(RzAnalysis *analysis, RzAnalysisFunction *fcn, ut64 addr,
if (prev_op.type == RZ_ANALYSIS_OP_TYPE_MOV && prev_op.disp && prev_op.disp != UT64_MAX && same_reg) {
// movzx reg, byte [reg + case_table]
// jmp dword [reg*4 + jump_table]
if (try_walkthrough_casetbl(analysis, fcn, bb, depth, op.addr, case_shift, op.ptr, prev_op.disp, op.ptr, analysis->bits >> 3, table_size, default_case, ret)) {
params.casetbl_loc = prev_op.disp;
if (rz_analysis_walkthrough_casetbl(analysis, fcn, bb, &params)) {
ret = case_table = true;
}
}
}
rz_analysis_op_fini(&prev_op);
if (!case_table) {
ret = try_walkthrough_jmptbl(analysis, fcn, bb, depth, op.addr, case_shift, op.ptr, op.ptr, analysis->bits >> 3, table_size, default_case, ret);
ret = rz_analysis_walkthrough_jmptbl(analysis, fcn, bb, &params);
}
}
} else if (op.ptr != UT64_MAX && op.reg) { // direct jump
ut64 table_size, default_case;
st64 case_shift;
if (try_get_jmptbl_info(analysis, fcn, op.addr, bb, &table_size, &default_case, &case_shift)) {
ret = try_walkthrough_jmptbl(analysis, fcn, bb, depth, op.addr, case_shift, op.ptr, op.ptr, analysis->bits >> 3, table_size, default_case, ret);
if (rz_analysis_get_jmptbl_info(analysis, fcn, bb, op.addr, &params)) {
ret = rz_analysis_walkthrough_jmptbl(analysis, fcn, bb, &params);
}
} else if (movdisp != UT64_MAX) {
ut64 table_size;
ut64 default_case;
ut64 jmptbl_base = 0;
ut64 lea_op_off = UT64_MAX;
st64 case_shift;
RzListIter *iter;
leaddr_pair *pair;
params.jmptbl_off = 0;
if (movbasereg) {
// find nearest candidate leaddr before op.addr
rz_list_foreach_prev(analysis->leaddrs, iter, pair) {
@ -1220,42 +1244,46 @@ static int fcn_recurse(RzAnalysis *analysis, RzAnalysisFunction *fcn, ut64 addr,
}
if ((lea_op_off == UT64_MAX || lea_op_off > op.addr - pair->op_addr) && pair->reg && !strcmp(movbasereg, pair->reg)) {
lea_op_off = op.addr - pair->op_addr;
jmptbl_base = pair->leaddr;
params.jmptbl_off = pair->leaddr;
}
}
}
if (!try_get_jmptbl_info(analysis, fcn, op.addr, bb, &table_size, &default_case, &case_shift)) {
table_size = cmpval + 1;
default_case = -1;
if (!rz_analysis_get_jmptbl_info(analysis, fcn, bb, op.addr, &params)) {
params.table_count = cmpval + 1;
params.default_case = -1;
}
ret = try_walkthrough_jmptbl(analysis, fcn, bb, depth, op.addr, case_shift, jmptbl_base + movdisp, jmptbl_base, movscale, table_size, default_case, ret);
params.jmptbl_loc = params.jmptbl_off + movdisp;
params.entry_size = movscale;
ret = rz_analysis_walkthrough_jmptbl(analysis, fcn, bb, &params);
cmpval = UT64_MAX;
} else if (is_arm) {
params.jmptbl_loc = op.addr + op.size;
params.jmptbl_off = op.addr + 4;
params.default_case = UT64_MAX;
if (op.ptrsize == 1) { // TBB
ut64 pred_cmpval = try_get_cmpval_from_parents(analysis, fcn, bb, op.ireg);
ut64 table_size = 0;
params.table_count = 0;
if (pred_cmpval != UT64_MAX) {
table_size += pred_cmpval;
params.table_count += pred_cmpval;
} else {
table_size += cmpval;
params.table_count += cmpval;
}
ret = try_walkthrough_jmptbl(analysis, fcn, bb, depth, op.addr, 0, op.addr + op.size,
op.addr + 4, 1, table_size, UT64_MAX, ret);
params.entry_size = 1;
ret = rz_analysis_walkthrough_jmptbl(analysis, fcn, bb, &params);
// skip inlined jumptable
idx += table_size;
}
if (op.ptrsize == 2) { // LDRH on thumb/arm
idx += params.table_count;
} else if (op.ptrsize == 2) { // LDRH on thumb/arm
ut64 pred_cmpval = try_get_cmpval_from_parents(analysis, fcn, bb, op.ireg);
int tablesize = 1;
params.table_count = 1;
if (pred_cmpval != UT64_MAX) {
tablesize += pred_cmpval;
params.table_count += pred_cmpval;
} else {
tablesize += cmpval;
params.table_count += cmpval;
}
ret = try_walkthrough_jmptbl(analysis, fcn, bb, depth, op.addr, 0, op.addr + op.size,
op.addr + 4, 2, tablesize, UT64_MAX, ret);
params.entry_size = 2;
ret = rz_analysis_walkthrough_jmptbl(analysis, fcn, bb, &params);
// skip inlined jumptable
idx += (tablesize * 2);
idx += (params.table_count * 2);
}
}
}
@ -1264,8 +1292,8 @@ static int fcn_recurse(RzAnalysis *analysis, RzAnalysisFunction *fcn, ut64 addr,
}
if (analysis->opt.ijmp) {
if (continue_after_jump) {
rz_analysis_fcn_bb(analysis, fcn, op.jump, depth);
ret = rz_analysis_fcn_bb(analysis, fcn, op.fail, depth);
rz_analysis_task_item_new(analysis, tasks, fcn, NULL, op.fail);
rz_analysis_task_item_new(analysis, tasks, fcn, NULL, op.jump);
if (overlapped) {
goto analopfinish;
}
@ -1282,7 +1310,6 @@ static int fcn_recurse(RzAnalysis *analysis, RzAnalysisFunction *fcn, ut64 addr,
}
}
break;
/* fallthru */
case RZ_ANALYSIS_OP_TYPE_PUSH:
last_is_push = true;
last_push_addr = op.val;
@ -1307,7 +1334,7 @@ static int fcn_recurse(RzAnalysis *analysis, RzAnalysisFunction *fcn, ut64 addr,
op.type = RZ_ANALYSIS_OP_TYPE_JMP;
op.jump = last_push_addr;
bb->jump = op.jump;
ret = rz_analysis_fcn_bb(analysis, fcn, op.jump, depth);
rz_analysis_task_item_new(analysis, tasks, fcn, NULL, op.jump);
goto beach;
}
if (!op.cond) {
@ -1358,10 +1385,6 @@ static int fcn_recurse(RzAnalysis *analysis, RzAnalysisFunction *fcn, ut64 addr,
}
}
beach:
while (lea_cnt > 0) {
rz_list_delete(analysis->leaddrs, rz_list_tail(analysis->leaddrs));
lea_cnt--;
}
rz_analysis_op_fini(&op);
RZ_FREE(last_reg_mov_lea_name);
if (bb && bb->size == 0) {
@ -1373,8 +1396,65 @@ beach:
return ret;
}
RZ_API int rz_analysis_fcn_bb(RzAnalysis *analysis, RzAnalysisFunction *fcn, ut64 addr, int depth) {
return fcn_recurse(analysis, fcn, addr, analysis->opt.bb_max_size, depth - 1);
/**
* \brief Adds a new task item to the `tasks` parameter.
*
* Used to create a new item to the `tasks` parameter
* that can be worked on later by the `rz_analysis_run_tasks` function.
*
* \param analysis Pointer to RzAnalysis instance.
* \param tasks Pointer to RzVector to add a new RzAnalysisTaskItem to.
* \param fcn Pointer to RzAnalysisFunction in which analysis will be performed on.
* \param block Pointer to RzAnalysisBlock in which analysis will be performed on. If null, analysis will take care of block creation.
* \param address Address where analysis will start from
*/
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) {
rz_return_val_if_fail(analysis && tasks && fcn, false);
RzAnalysisTaskItem item = { fcn, block, fcn->stack, address };
RzAnalysisTaskItem *it;
rz_vector_foreach(tasks, it) {
if (item.start_address == it->start_address) {
return true;
}
}
return rz_vector_push(tasks, &item);
}
/**
* \brief Runs analysis on the task items.
*
* Runs control-flow and variable usage analysis on each of the task items until tasks vector becomes empty.
* Items are removed from the tasks vector as they are processed.
* Items are added to the tasks vector as new basic blocks are found to be analyzed.
*
* \param tasks Pointer to RzVector of RzAnalysisTaskItem to be performed analysis on.
*/
RZ_API int rz_analysis_run_tasks(RZ_NONNULL RzVector *tasks) {
rz_return_val_if_fail(tasks, RZ_ANALYSIS_RET_ERROR);
int ret = RZ_ANALYSIS_RET_ERROR;
while (!rz_vector_empty(tasks)) {
RzAnalysisTaskItem item;
rz_vector_pop(tasks, &item);
int r = run_basic_block_analysis(&item, tasks);
switch (r) {
case RZ_ANALYSIS_RET_NOP:
case RZ_ANALYSIS_RET_ERROR:
case RZ_ANALYSIS_RET_DUP:
case RZ_ANALYSIS_RET_NEW:
if (ret != RZ_ANALYSIS_RET_END) {
ret = r;
}
break;
case RZ_ANALYSIS_RET_END:
default:
ret = r;
break;
}
if (rz_cons_is_breaked()) {
break;
}
}
return ret;
}
RZ_API bool rz_analysis_check_fcn(RzAnalysis *analysis, ut8 *buf, ut16 bufsz, ut64 addr, ut64 low, ut64 high) {
@ -1487,12 +1567,11 @@ RZ_API int rz_analysis_fcn(RzAnalysis *analysis, RzAnalysisFunction *fcn, ut64 a
const int shadow_store = 0x28; // First 4 args + retaddr
fcn->stack = fcn->maxstack = fcn->reg_save_area = shadow_store;
}
int ret = rz_analysis_fcn_bb(analysis, fcn, addr, analysis->opt.depth);
if (ret < 0) {
if (analysis->verbose) {
eprintf("Failed to analyze basic block at 0x%" PFMT64x "\n", addr);
}
}
RzVector tasks;
rz_vector_init(&tasks, sizeof(RzAnalysisTaskItem), NULL, NULL);
rz_analysis_task_item_new(analysis, &tasks, fcn, NULL, addr);
int ret = rz_analysis_run_tasks(&tasks);
rz_vector_fini(&tasks);
if (analysis->opt.endsize && ret == RZ_ANALYSIS_RET_END && rz_analysis_function_realsize(fcn)) { // cfg analysis completed
RzListIter *iter;
RzAnalysisBlock *bb;
@ -2033,7 +2112,7 @@ static bool analize_addr_cb(ut64 addr, void *user) {
RzAnalysisBlock *existing_bb = rz_analysis_get_block_at(analysis, addr);
if (!existing_bb || !rz_list_contains(ctx->fcn->bbs, existing_bb)) {
int old_len = rz_list_length(ctx->fcn->bbs);
rz_analysis_fcn_bb(ctx->fcn->analysis, ctx->fcn, addr, analysis->opt.depth);
analyze_function_locally(ctx->fcn->analysis, ctx->fcn, addr);
if (old_len != rz_list_length(ctx->fcn->bbs)) {
rz_analysis_block_recurse(rz_analysis_get_block_at(analysis, addr), mark_as_visited, user);
}
@ -2118,7 +2197,7 @@ static void update_analysis(RzAnalysis *analysis, RzList *fcns, HtUP *reachable)
// analyze edges that don't have a block
RzAnalysisBlock *bb = rz_analysis_get_block_at(analysis, fcn->addr);
if (!bb) {
rz_analysis_fcn_bb(analysis, fcn, fcn->addr, analysis->opt.depth);
analyze_function_locally(analysis, fcn, fcn->addr);
bb = rz_analysis_get_block_at(analysis, fcn->addr);
if (!bb) {
continue;

View file

@ -12,8 +12,6 @@
if (analysis->verbose) \
eprintf(format, __VA_ARGS__)
#define JMPTBL_MAXSZ 512
static void apply_case(RzAnalysis *analysis, RzAnalysisBlock *block, ut64 switch_addr, ut64 offset_sz, ut64 case_addr, ut64 id, ut64 case_addr_loc) {
// eprintf ("** apply_case: 0x%"PFMT64x " from 0x%"PFMT64x "\n", case_addr, case_addr_loc);
rz_meta_set_data_at(analysis, case_addr_loc, offset_sz);
@ -46,64 +44,69 @@ static void apply_switch(RzAnalysis *analysis, ut64 switch_addr, ut64 jmptbl_add
// analyze a jmptablle inside a function // maybe rename to rz_analysis_fcn_jmptbl() ?
RZ_API bool rz_analysis_jmptbl(RzAnalysis *analysis, RzAnalysisFunction *fcn, RzAnalysisBlock *block, ut64 jmpaddr, ut64 table, ut64 tablesize, ut64 default_addr) {
const int depth = 50;
return try_walkthrough_jmptbl(analysis, fcn, block, depth, jmpaddr, 0, table, table, tablesize, tablesize, default_addr, false);
RzAnalysisJmpTableParams params = {
.jmp_address = jmpaddr,
.case_shift = 0,
.jmptbl_loc = table,
.casetbl_loc = UT64_MAX,
.jmptbl_off = table,
.entry_size = tablesize,
.table_count = tablesize,
.default_case = default_addr,
};
return rz_analysis_walkthrough_jmptbl(analysis, fcn, block, &params);
}
static inline void analyze_new_case(RzAnalysis *analysis, RzAnalysisFunction *fcn, RzAnalysisBlock *block, ut64 ip, ut64 jmpptr, int depth) {
const ut64 block_size = block->size;
(void)rz_analysis_fcn_bb(analysis, fcn, jmpptr, depth - 1);
if (block->size != block_size) {
// block was be split during analysis and does not contain the
// jmp instruction anymore, so we need to search for it and get it again
RzAnalysisSwitchOp *sop = block->switch_op;
block = rz_analysis_find_most_relevant_block_in(analysis, ip);
if (!block) {
rz_warn_if_reached();
return;
}
block->switch_op = sop;
/**
* \brief 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
*
* \param analysis Pointer to RzAnalysis instance
* \param fcn Pointer to RzAnalysisFunction to add the new cases
* \param block Pointer to RzAnalysisBlock that originates the switch table
* \param params Pointer to RzAnalysisJmpTableParams necessary to analyze the jump table
*/
RZ_API bool rz_analysis_walkthrough_casetbl(RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisFunction *fcn, RZ_NONNULL RzAnalysisBlock *block, RZ_NONNULL RzAnalysisJmpTableParams *params) {
rz_return_val_if_fail(analysis && fcn && block && params, false);
bool ret = true;
if (params->table_count == 0) {
params->table_count = analysis->opt.jmptbl_maxcount;
}
}
RZ_API bool try_walkthrough_casetbl(RzAnalysis *analysis, RzAnalysisFunction *fcn, RzAnalysisBlock *block, int depth, ut64 ip, st64 start_casenum_shift, ut64 jmptbl_loc, ut64 casetbl_loc, ut64 jmptbl_off, ut64 sz, ut64 jmptbl_size, ut64 default_case, bool ret0) {
bool ret = ret0;
if (jmptbl_size == 0) {
jmptbl_size = JMPTBL_MAXSZ;
}
if (jmptbl_loc == UT64_MAX) {
aprintf("Warning: Invalid JumpTable location 0x%08" PFMT64x "\n", jmptbl_loc);
if (params->jmptbl_loc == UT64_MAX) {
aprintf("Warning: Invalid JumpTable location 0x%08" PFMT64x "\n", params->jmptbl_loc);
return false;
}
if (casetbl_loc == UT64_MAX) {
aprintf("Warning: Invalid CaseTable location 0x%08" PFMT64x "\n", jmptbl_loc);
if (params->casetbl_loc == UT64_MAX) {
aprintf("Warning: Invalid CaseTable location 0x%08" PFMT64x "\n", params->jmptbl_loc);
return false;
}
if (jmptbl_size < 1 || jmptbl_size > ST32_MAX) {
aprintf("Warning: Invalid JumpTable size at 0x%08" PFMT64x "\n", ip);
if (params->table_count < 1 || params->table_count > ST32_MAX) {
aprintf("Warning: Invalid JumpTable size at 0x%08" PFMT64x "\n", params->jmp_address);
return false;
}
ut64 jmpptr, case_idx, jmpptr_idx;
ut8 *jmptbl = calloc(jmptbl_size, sz);
if (!jmptbl || !analysis->iob.read_at(analysis->iob.io, jmptbl_loc, jmptbl, jmptbl_size * sz)) {
ut8 *jmptbl = calloc(params->table_count, params->entry_size);
if (!jmptbl || !analysis->iob.read_at(analysis->iob.io, params->jmptbl_loc, jmptbl, params->table_count * params->entry_size)) {
free(jmptbl);
return false;
}
ut8 *casetbl = calloc(jmptbl_size, sizeof(ut8));
if (!casetbl || !analysis->iob.read_at(analysis->iob.io, casetbl_loc, casetbl, jmptbl_size)) {
ut8 *casetbl = calloc(params->table_count, sizeof(ut8));
if (!casetbl || !analysis->iob.read_at(analysis->iob.io, params->casetbl_loc, casetbl, params->table_count)) {
free(jmptbl);
free(casetbl);
return false;
}
for (case_idx = 0; case_idx < jmptbl_size; case_idx++) {
for (case_idx = 0; case_idx < params->table_count; case_idx++) {
jmpptr_idx = casetbl[case_idx];
if (jmpptr_idx >= jmptbl_size) {
if (jmpptr_idx >= params->table_count) {
ret = false;
break;
}
switch (sz) {
switch (params->entry_size) {
case 1:
jmpptr = rz_read_le8(jmptbl + jmpptr_idx);
break;
@ -123,7 +126,7 @@ RZ_API bool try_walkthrough_casetbl(RzAnalysis *analysis, RzAnalysisFunction *fc
if (!analysis->iob.is_valid_offset(analysis->iob.io, jmpptr, 0)) {
st32 jmpdelta = (st32)jmpptr;
// jump tables where sign extended movs are used
jmpptr = jmptbl_off + jmpdelta;
jmpptr = params->jmptbl_off + jmpdelta;
if (!analysis->iob.is_valid_offset(analysis->iob.io, jmpptr, 0)) {
break;
}
@ -134,19 +137,19 @@ RZ_API bool try_walkthrough_casetbl(RzAnalysis *analysis, RzAnalysisFunction *fc
}
}
const ut64 jmpptr_idx_off = casetbl_loc + case_idx;
const ut64 jmpptr_idx_off = params->casetbl_loc + case_idx;
rz_meta_set_data_at(analysis, jmpptr_idx_off, 1);
rz_analysis_hint_set_immbase(analysis, jmpptr_idx_off, 10);
apply_case(analysis, block, ip, sz, jmpptr, case_idx + start_casenum_shift, jmptbl_loc + jmpptr_idx * sz);
analyze_new_case(analysis, fcn, block, ip, jmpptr, depth);
apply_case(analysis, block, params->jmp_address, params->entry_size, jmpptr, case_idx + params->case_shift, params->jmptbl_loc + jmpptr_idx * params->entry_size);
rz_analysis_task_item_new(analysis, params->tasks, fcn, NULL, jmpptr);
}
if (case_idx > 0) {
if (default_case == 0) {
default_case = UT64_MAX;
if (params->default_case == 0) {
params->default_case = UT64_MAX;
}
apply_switch(analysis, ip, jmptbl_loc, case_idx, default_case);
apply_switch(analysis, params->jmp_address, params->jmptbl_loc, case_idx, params->default_case);
}
free(jmptbl);
@ -154,30 +157,41 @@ RZ_API bool try_walkthrough_casetbl(RzAnalysis *analysis, RzAnalysisFunction *fc
return ret;
}
RZ_API bool try_walkthrough_jmptbl(RzAnalysis *analysis, RzAnalysisFunction *fcn, RzAnalysisBlock *block, int depth, ut64 ip, st64 start_casenum_shift, ut64 jmptbl_loc, ut64 jmptbl_off, ut64 sz, ut64 jmptbl_size, ut64 default_case, bool ret0) {
bool ret = ret0;
// jmptbl_size can not always be determined
if (jmptbl_size == 0) {
jmptbl_size = JMPTBL_MAXSZ;
/**
* \brief 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.
*
* \param analysis Pointer to RzAnalysis instance
* \param fcn Pointer to RzAnalysisFunction to add the new cases
* \param block Pointer to RzAnalysisBlock that originates the switch table
* \param params Pointer to RzAnalysisJmpTableParams necessary to analyze the jump table
*/
RZ_API bool rz_analysis_walkthrough_jmptbl(RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisFunction *fcn, RZ_NONNULL RzAnalysisBlock *block, RZ_NONNULL RzAnalysisJmpTableParams *params) {
rz_return_val_if_fail(analysis && fcn && block && params, false);
// table_count can not always be determined
if (params->table_count == 0) {
params->table_count = analysis->opt.jmptbl_maxcount;
}
if (jmptbl_loc == UT64_MAX) {
aprintf("Warning: Invalid JumpTable location 0x%08" PFMT64x "\n", jmptbl_loc);
if (params->jmptbl_loc == UT64_MAX) {
aprintf("Warning: Invalid JumpTable location 0x%08" PFMT64x "\n", params->jmptbl_loc);
return false;
}
if (jmptbl_size < 1 || jmptbl_size > ST32_MAX) {
aprintf("Warning: Invalid JumpTable size at 0x%08" PFMT64x "\n", ip);
if (params->table_count < 1 || params->table_count > ST32_MAX) {
aprintf("Warning: Invalid JumpTable size at 0x%08" PFMT64x "\n", params->jmp_address);
return false;
}
ut64 jmpptr, offs;
ut8 *jmptbl = calloc(jmptbl_size, sz);
ut8 *jmptbl = calloc(params->table_count, params->entry_size);
if (!jmptbl) {
return false;
}
bool is_arm = analysis->cur->arch && !strncmp(analysis->cur->arch, "arm", 3);
// eprintf ("JMPTBL AT 0x%"PFMT64x"\n", jmptbl_loc);
analysis->iob.read_at(analysis->iob.io, jmptbl_loc, jmptbl, jmptbl_size * sz);
for (offs = 0; offs + sz - 1 < jmptbl_size * sz; offs += sz) {
switch (sz) {
analysis->iob.read_at(analysis->iob.io, params->jmptbl_loc, jmptbl, params->table_count * params->entry_size);
for (offs = 0; offs + params->entry_size - 1 < params->table_count * params->entry_size; offs += params->entry_size) {
switch (params->entry_size) {
case 1:
jmpptr = (ut64)(ut8)rz_read_le8(jmptbl + offs);
break;
@ -201,14 +215,14 @@ RZ_API bool try_walkthrough_jmptbl(RzAnalysis *analysis, RzAnalysisFunction *fcn
if (jmpptr == 0 || jmpptr == UT32_MAX || jmpptr == UT64_MAX) {
break;
}
if (sz == 2 && is_arm) {
jmpptr = ip + 4 + (jmpptr * 2); // tbh [pc, r2, lsl 1] // assume lsl 1
} else if (sz == 1 && is_arm) {
jmpptr = ip + 4 + (jmpptr * 2); // lbb [pc, r2] // assume lsl 1
if (params->entry_size == 2 && is_arm) {
jmpptr = params->jmp_address + 4 + (jmpptr * 2); // tbh [pc, r2, lsl 1] // assume lsl 1
} else if (params->entry_size == 1 && is_arm) {
jmpptr = params->jmp_address + 4 + (jmpptr * 2); // lbb [pc, r2] // assume lsl 1
} else if (!analysis->iob.is_valid_offset(analysis->iob.io, jmpptr, 0)) {
st32 jmpdelta = (st32)jmpptr;
// jump tables where sign extended movs are used
jmpptr = jmptbl_off + jmpdelta;
jmpptr = params->jmptbl_off + jmpdelta;
if (!analysis->iob.is_valid_offset(analysis->iob.io, jmpptr, 0)) {
break;
}
@ -218,19 +232,19 @@ RZ_API bool try_walkthrough_jmptbl(RzAnalysis *analysis, RzAnalysisFunction *fcn
break;
}
}
apply_case(analysis, block, ip, sz, jmpptr, (offs / sz) + start_casenum_shift, jmptbl_loc + offs);
analyze_new_case(analysis, fcn, block, ip, jmpptr, depth);
apply_case(analysis, block, params->jmp_address, params->entry_size, jmpptr, (offs / params->entry_size) + params->case_shift, params->jmptbl_loc + offs);
rz_analysis_task_item_new(analysis, params->tasks, fcn, NULL, jmpptr);
}
if (offs > 0) {
if (default_case == 0) {
default_case = UT64_MAX;
if (params->default_case == 0) {
params->default_case = UT64_MAX;
}
apply_switch(analysis, ip, jmptbl_loc, offs / sz, default_case);
apply_switch(analysis, params->jmp_address, params->jmptbl_loc, offs / params->entry_size, params->default_case);
}
free(jmptbl);
return ret;
return true;
}
static bool detect_casenum_shift(RzAnalysisOp *op, RzRegItem **cmp_reg, st64 *start_casenum_shift) {
@ -255,29 +269,43 @@ static bool detect_casenum_shift(RzAnalysisOp *op, RzRegItem **cmp_reg, st64 *st
return false;
}
// TODO: RENAME
RZ_API bool try_get_delta_jmptbl_info(RzAnalysis *analysis, RzAnalysisFunction *fcn, ut64 jmp_addr, ut64 lea_addr, ut64 *table_size, ut64 *default_case, st64 *start_casenum_shift) {
/**
* \brief 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
*
* \param analysis Pointer to RzAnalysis instance
* \param fcn Pointer to RzAnalysisFunction where jump table ocurred
* \param jmp_address Address of jump intruction that uses the table
* \param lea_addr Address of lea instruction that loads the address of the jump table base
* \param params Pointer to RzAnalysisJmpTableParams where the results of the function are stored
*/
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) {
rz_return_val_if_fail(analysis && fcn && params, false);
bool isValid = false;
bool foundCmp = false;
int i;
RzAnalysisOp tmp_aop = { 0 };
if (lea_addr > jmp_addr) {
if (lea_address > jmp_address) {
return false;
}
int search_sz = jmp_addr - lea_addr;
params->jmp_address = jmp_address;
int search_sz = jmp_address - lea_address;
ut8 *buf = malloc(search_sz);
if (!buf) {
return false;
}
// search for a cmp register with a reasonable size
analysis->iob.read_at(analysis->iob.io, lea_addr, (ut8 *)buf, search_sz);
analysis->iob.read_at(analysis->iob.io, lea_address, (ut8 *)buf, search_sz);
RzVector v;
rz_vector_init(&v, sizeof(ut64), NULL, NULL);
int len = 0;
RzRegItem *cmp_reg = NULL;
for (i = 0; i + 8 < search_sz; i += len) {
len = rz_analysis_op(analysis, &tmp_aop, lea_addr + i, buf + i, search_sz - i, RZ_ANALYSIS_OP_MASK_BASIC);
len = rz_analysis_op(analysis, &tmp_aop, lea_address + i, buf + i, search_sz - i, RZ_ANALYSIS_OP_MASK_BASIC);
if (len < 1) {
len = 1;
}
@ -287,7 +315,7 @@ RZ_API bool try_get_delta_jmptbl_info(RzAnalysis *analysis, RzAnalysisFunction *
continue;
}
*default_case = tmp_aop.jump == tmp_aop.jump + len ? tmp_aop.fail : tmp_aop.jump;
params->default_case = tmp_aop.jump == tmp_aop.jump + len ? tmp_aop.fail : tmp_aop.jump;
break;
}
@ -303,16 +331,16 @@ RZ_API bool try_get_delta_jmptbl_info(RzAnalysis *analysis, RzAnalysisFunction *
// might not actually have a value, let the next step figure out the size then
if (tmp_aop.val == UT64_MAX && tmp_aop.refptr == 0) {
isValid = true;
*table_size = 0;
params->table_count = 0;
} else if (tmp_aop.refptr == 0) {
isValid = tmp_aop.val < 0x200;
*table_size = tmp_aop.val + 1;
params->table_count = tmp_aop.val + 1;
} else {
isValid = tmp_aop.refptr < 0x200;
*table_size = tmp_aop.refptr + 1;
params->table_count = tmp_aop.refptr + 1;
}
rz_vector_push(&v, &i);
rz_analysis_op(analysis, &tmp_aop, lea_addr + i, buf + i, search_sz - i, RZ_ANALYSIS_OP_MASK_VAL);
rz_analysis_op(analysis, &tmp_aop, lea_address + i, buf + i, search_sz - i, RZ_ANALYSIS_OP_MASK_VAL);
if (tmp_aop.dst && tmp_aop.dst->reg) {
cmp_reg = tmp_aop.dst->reg;
} else if (tmp_aop.reg) {
@ -325,15 +353,15 @@ RZ_API bool try_get_delta_jmptbl_info(RzAnalysis *analysis, RzAnalysisFunction *
foundCmp = true;
}
if (isValid) {
*start_casenum_shift = 0;
params->case_shift = 0;
void **it;
rz_vector_foreach_prev(&v, it) {
const ut64 op_off = *(ut64 *)it;
ut64 op_addr = lea_addr + op_off;
ut64 op_addr = lea_address + op_off;
rz_analysis_op(analysis, &tmp_aop, op_addr,
buf + op_off, search_sz - op_off,
RZ_ANALYSIS_OP_MASK_VAL);
if (detect_casenum_shift(&tmp_aop, &cmp_reg, start_casenum_shift)) {
if (detect_casenum_shift(&tmp_aop, &cmp_reg, &params->case_shift)) {
rz_analysis_op_fini(&tmp_aop);
break;
}
@ -345,8 +373,17 @@ RZ_API bool try_get_delta_jmptbl_info(RzAnalysis *analysis, RzAnalysisFunction *
return isValid;
}
// TODO: find a better function name
RZ_API int walkthrough_arm_jmptbl_style(RzAnalysis *analysis, RzAnalysisFunction *fcn, RzAnalysisBlock *block, int depth, ut64 ip, ut64 jmptbl_loc, ut64 sz, ut64 jmptbl_size, ut64 default_case, int ret0) {
/**
* \brief Marks for analysis ARM specific jump table cases
*
* This function works similarly to `rz_analysis_walkthrough_jmptbl`, but is specific to ARM
*
* \param analysis Pointer to RzAnalysis instance
* \param fcn Pointer to RzAnalysisFunction to add the new cases
* \param block Pointer to RzAnalysisBlock that originates the switch table
* \param params Pointer to RzAnalysisJmpTableParams necessary to analyze the jump table
*/
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) {
/*
* Example about arm jump table
*
@ -365,30 +402,41 @@ RZ_API int walkthrough_arm_jmptbl_style(RzAnalysis *analysis, RzAnalysisFunction
* ; CODE XREF from loc._a_7 (+0x18)
* 0x000105e8 bbffffea b sym.input_3
*/
rz_return_val_if_fail(analysis && fcn && block && params, false);
ut64 offs, jmpptr;
int ret = ret0;
if (jmptbl_size == 0) {
jmptbl_size = JMPTBL_MAXSZ;
if (params->table_count == 0) {
params->table_count = analysis->opt.jmptbl_maxcount;
}
for (offs = 0; offs + sz - 1 < jmptbl_size * sz; offs += sz) {
jmpptr = jmptbl_loc + offs;
apply_case(analysis, block, ip, sz, jmpptr, offs / sz, jmptbl_loc + offs);
analyze_new_case(analysis, fcn, block, ip, jmpptr, depth);
for (offs = 0; offs + params->entry_size - 1 < params->table_count * params->entry_size; offs += params->entry_size) {
jmpptr = params->jmptbl_loc + offs;
apply_case(analysis, block, params->jmp_address, params->entry_size, jmpptr, offs / params->entry_size, params->jmptbl_loc + offs);
rz_analysis_task_item_new(analysis, params->tasks, fcn, NULL, jmpptr);
}
if (offs > 0) {
if (default_case == 0 || default_case == UT32_MAX) {
default_case = UT64_MAX;
if (params->default_case == 0 || params->default_case == UT32_MAX) {
params->default_case = UT64_MAX;
}
apply_switch(analysis, ip, jmptbl_loc, offs / sz, default_case);
apply_switch(analysis, params->jmp_address, params->jmptbl_loc, offs / params->entry_size, params->default_case);
}
return ret;
return true;
}
RZ_API bool try_get_jmptbl_info(RzAnalysis *analysis, RzAnalysisFunction *fcn, ut64 addr, RzAnalysisBlock *my_bb, ut64 *table_size, ut64 *default_case, st64 *start_casenum_shift) {
/**
* \brief 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
*
* \param analysis Pointer to RzAnalysis instance
* \param fcn Pointer to RzAnalysisFunction where jump table ocurred
* \param block Pointer to RzAnalysisBlock where the jump instruction related to the jump table ocurred
* \param jmp_address Address of jump intruction that uses the table
* \param params Pointer to RzAnalysisJmpTableParams where the results of the function are stored
*/
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) {
rz_return_val_if_fail(analysis && fcn && params && block, false);
bool isValid = false;
int i;
RzListIter *iter;
@ -398,8 +446,10 @@ RZ_API bool try_get_jmptbl_info(RzAnalysis *analysis, RzAnalysisFunction *fcn, u
return false;
}
params->jmp_address = jmp_address;
/* if UJMP is in .plt section just skip it */
RzBinSection *s = analysis->binb.get_vsect_at(analysis->binb.bin, addr);
RzBinSection *s = analysis->binb.get_vsect_at(analysis->binb.bin, jmp_address);
if (s && s->name[0]) {
bool in_plt = strstr(s->name, ".plt") != NULL;
if (!in_plt && strstr(s->name, "_stubs") != NULL) {
@ -413,19 +463,19 @@ RZ_API bool try_get_jmptbl_info(RzAnalysis *analysis, RzAnalysisFunction *fcn, u
// search for the predecessor bb
rz_list_foreach (fcn->bbs, iter, tmp_bb) {
if (tmp_bb->jump == my_bb->addr || tmp_bb->fail == my_bb->addr) {
if (tmp_bb->jump == block->addr || tmp_bb->fail == block->addr) {
prev_bb = tmp_bb;
break;
}
}
// predecessor must be a conditional jump
if (!prev_bb || !prev_bb->jump || !prev_bb->fail) {
aprintf("Warning: [analysis.jmp.tbl] Missing predecesessor cjmp bb at 0x%08" PFMT64x "\n", addr);
aprintf("Warning: [analysis.jmp.tbl] Missing predecesessor cjmp bb at 0x%08" PFMT64x "\n", jmp_address);
return false;
}
// default case is the jump target of the unconditional jump
*default_case = prev_bb->jump == my_bb->addr ? prev_bb->fail : prev_bb->jump;
params->default_case = prev_bb->jump == block->addr ? prev_bb->fail : prev_bb->jump;
RzAnalysisOp tmp_aop = { 0 };
ut8 *bb_buf = calloc(1, prev_bb->size);
@ -436,12 +486,12 @@ RZ_API bool try_get_jmptbl_info(RzAnalysis *analysis, RzAnalysisFunction *fcn, u
analysis->iob.read_at(analysis->iob.io, prev_bb->addr, (ut8 *)bb_buf, prev_bb->size);
isValid = false;
RzAnalysisHint *hint = rz_analysis_hint_get(analysis, addr);
RzAnalysisHint *hint = rz_analysis_hint_get(analysis, jmp_address);
if (hint) {
ut64 val = hint->val;
rz_analysis_hint_free(hint);
if (val != UT64_MAX) {
*table_size = val;
params->table_count = val;
return true;
}
}
@ -470,13 +520,13 @@ RZ_API bool try_get_jmptbl_info(RzAnalysis *analysis, RzAnalysisFunction *fcn, u
// might not actually have a value, let the next step figure out the size then
if (tmp_aop.val == UT64_MAX && tmp_aop.refptr == 0) {
isValid = true;
*table_size = 0;
params->table_count = 0;
} else if (tmp_aop.refptr == 0 || tmp_aop.val != UT64_MAX) {
isValid = tmp_aop.val < 0x200;
*table_size = tmp_aop.val + 1;
params->table_count = tmp_aop.val + 1;
} else {
isValid = tmp_aop.refptr < 0x200;
*table_size = tmp_aop.refptr + 1;
params->table_count = tmp_aop.refptr + 1;
}
if (isValid) {
rz_analysis_op_fini(&tmp_aop);
@ -496,7 +546,7 @@ RZ_API bool try_get_jmptbl_info(RzAnalysis *analysis, RzAnalysisFunction *fcn, u
break;
}
if (isValid) {
*start_casenum_shift = 0;
params->case_shift = 0;
for (i--; i >= 0; i--) {
const ut64 prev_pos = rz_analysis_block_get_op_offset(prev_bb, i);
const ut64 op_addr = rz_analysis_block_get_op_addr(prev_bb, i);
@ -507,7 +557,7 @@ RZ_API bool try_get_jmptbl_info(RzAnalysis *analysis, RzAnalysisFunction *fcn, u
rz_analysis_op(analysis, &tmp_aop, op_addr,
bb_buf + prev_pos, buflen,
RZ_ANALYSIS_OP_MASK_VAL);
if (detect_casenum_shift(&tmp_aop, &cmp_reg, start_casenum_shift)) {
if (detect_casenum_shift(&tmp_aop, &cmp_reg, &params->case_shift)) {
rz_analysis_op_fini(&tmp_aop);
break;
}
@ -516,9 +566,5 @@ RZ_API bool try_get_jmptbl_info(RzAnalysis *analysis, RzAnalysisFunction *fcn, u
}
}
free(bb_buf);
// eprintf ("switch at 0x%" PFMT64x "\n\tdefault case 0x%" PFMT64x "\n\t#cases: %d\n",
// addr,
// *default_case,
// *table_size);
return isValid;
}

View file

@ -2593,6 +2593,13 @@ static bool cb_analysis_jmptbl(void *user, void *data) {
return true;
}
static bool cb_analysis_jmptblmax(void *user, void *data) {
RzCore *core = (RzCore *)user;
RzConfigNode *node = (RzConfigNode *)data;
core->analysis->opt.jmptbl_maxcount = node->i_value;
return true;
}
static bool cb_analysis_cjmpref(void *user, void *data) {
RzCore *core = (RzCore *)user;
RzConfigNode *node = (RzConfigNode *)data;
@ -2874,6 +2881,7 @@ RZ_API int rz_core_config_init(RzCore *core) {
SETICB("asm.lines.maxref", 0, &cb_analysis_maxrefs, "Maximum number of reflines to be analyzed and displayed in asm.lines with pd");
SETCB("analysis.jmp.tbl", "true", &cb_analysis_jmptbl, "Analyze jump tables in switch statements");
SETICB("analysis.jmp.tblmax", 512, &cb_analysis_jmptblmax, "Maximum amount of entries to analyze in jump tables");
SETCB("analysis.jmp.cref", "false", &cb_analysis_cjmpref, "Create references for conditional jumps");
SETCB("analysis.jmp.ref", "true", &cb_analysis_jmpref, "Create references for unconditional jumps");

View file

@ -542,6 +542,7 @@ typedef struct rz_analysis_options_t {
int nopskip; // skip nops at the beginning of functions
int hpskip; // skip `mov reg,reg` and `lea reg,[reg]`
int jmptbl; // analyze jump tables
int jmptbl_maxcount; // maximum amount of entries to analyse in a jump table
int nonull;
bool pushret; // analyze push+ret as jmp
bool armthumb; //
@ -887,6 +888,13 @@ typedef struct rz_analysis_bb_t {
#undef RzAnalysisBlock
} RzAnalysisBlock;
typedef struct rz_analysis_task_item {
RzAnalysisFunction *fcn; // current function
RzAnalysisBlock *block; // block being analyzed
st64 stack; // stack pointer value for variable analysis
ut64 start_address; // if block = NULL, creates block at address, else continues analysis from here
} RzAnalysisTaskItem;
typedef enum {
RZ_ANALYSIS_REF_TYPE_NULL = 0,
RZ_ANALYSIS_REF_TYPE_CODE = 'c', // code ref
@ -1426,7 +1434,6 @@ RZ_API int rz_analysis_set_big_endian(RzAnalysis *analysis, int boolean);
RZ_API ut8 *rz_analysis_mask(RzAnalysis *analysis, int size, const ut8 *data, ut64 at);
RZ_API void rz_analysis_trace_bb(RzAnalysis *analysis, ut64 addr);
RZ_API const char *rz_analysis_fcntype_tostring(int type);
RZ_API int rz_analysis_fcn_bb(RzAnalysis *analysis, RzAnalysisFunction *fcn, ut64 addr, int depth);
RZ_API void rz_analysis_bind(RzAnalysis *b, RzAnalysisBind *bnd);
RZ_API bool rz_analysis_set_triplet(RzAnalysis *analysis, const char *os, const char *arch, int bits);
RZ_API void rz_analysis_add_import(RzAnalysis *analysis, const char *imp);
@ -1520,6 +1527,9 @@ RZ_API void rz_analysis_function_check_bp_use(RzAnalysisFunction *fcn);
RZ_API void rz_analysis_update_analysis_range(RzAnalysis *analysis, ut64 addr, int size);
RZ_API void rz_analysis_function_update_analysis(RzAnalysisFunction *fcn);
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);
RZ_API int rz_analysis_run_tasks(RZ_NONNULL RzVector *tasks);
#define RZ_ANALYSIS_FCN_VARKIND_LOCAL 'v'
RZ_API int rz_analysis_fcn_var_del_byindex(RzAnalysis *a, ut64 fna, const char kind, int scope, ut32 idx);
@ -1652,12 +1662,23 @@ RZ_API const char *rz_analysis_cond_tostring(int cc);
/* jmptbl */
RZ_API bool rz_analysis_jmptbl(RzAnalysis *analysis, RzAnalysisFunction *fcn, RzAnalysisBlock *block, ut64 jmpaddr, ut64 table, ut64 tablesize, ut64 default_addr);
// TODO: should be renamed
RZ_API bool try_get_delta_jmptbl_info(RzAnalysis *analysis, RzAnalysisFunction *fcn, ut64 jmp_addr, ut64 lea_addr, ut64 *table_size, ut64 *default_case, st64 *start_casenum_shift);
RZ_API bool try_walkthrough_jmptbl(RzAnalysis *analysis, RzAnalysisFunction *fcn, RzAnalysisBlock *block, int depth, ut64 ip, st64 start_casenum_shift, ut64 jmptbl_loc, ut64 jmptbl_off, ut64 sz, ut64 jmptbl_size, ut64 default_case, bool ret0);
RZ_API bool try_walkthrough_casetbl(RzAnalysis *analysis, RzAnalysisFunction *fcn, RzAnalysisBlock *block, int depth, ut64 ip, st64 start_casenum_shift, ut64 jmptbl_loc, ut64 casetbl_loc, ut64 jmptbl_off, ut64 sz, ut64 jmptbl_size, ut64 default_case, bool ret0);
RZ_API bool try_get_jmptbl_info(RzAnalysis *analysis, RzAnalysisFunction *fcn, ut64 addr, RzAnalysisBlock *my_bb, ut64 *table_size, ut64 *default_case, st64 *start_casenum_shift);
RZ_API int walkthrough_arm_jmptbl_style(RzAnalysis *analysis, RzAnalysisFunction *fcn, RzAnalysisBlock *block, int depth, ut64 ip, ut64 jmptbl_loc, ut64 sz, ut64 jmptbl_size, ut64 default_case, int ret0);
typedef struct rz_jmptable_params_t {
ut64 jmp_address; /// Address of the jump instruction
st64 case_shift; /// Shift that is added to get the real number of the case.
ut64 jmptbl_loc; /// Address of the jump table
ut64 casetbl_loc; /// Address of the indirect case table
ut64 jmptbl_off; /// Base of the jump table
ut64 entry_size; /// Size in bytes of each case entry inside the jump table
ut64 table_count; /// Count of cases inside the jump table
ut64 default_case; /// Code address of the default case of the switch
RzVector *tasks; /// RzVector of RzAnalysisTaskItem to add new tasks to
} RzAnalysisJmpTableParams;
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);
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);
RZ_API bool rz_analysis_walkthrough_jmptbl(RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisFunction *fcn, RZ_NONNULL RzAnalysisBlock *block, RZ_NONNULL 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);
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);
/* reflines.c */
RZ_API RzList * /*<RzAnalysisRefline>*/ rz_analysis_reflines_get(RzAnalysis *analysis,

View file

@ -847,7 +847,7 @@ EXPECT=<<EOF
0x00002818 78 fcn.00002818
0x00002a54 770 fcn.00002a54
0x00002d56 286 fcn.00002d56
0x00002ec8 1682 fcn.00002ec8
0x00002ec8 16 fcn.00002ec8
0x00002ed8 16 fcn.00002ed8
0x00002ee8 16 fcn.00002ee8
0x00002ef8 18 fcn.00002ef8
@ -885,6 +885,7 @@ EXPECT=<<EOF
0x00003486 4 fcn.00003486
0x0000349e 174 fcn.0000349e
0x0000354c 8 fcn.0000354c
0x00003554 6 loc.00003554
0x0000357a 68 fcn.0000357a
0x000035be 22 fcn.000035be
0x000035d4 8 fcn.000035d4

View file

@ -262,7 +262,6 @@ fcn.1000ef70:
sym.imp.__assert_fail
sym.imp.elf_getdata
sym.imp.error
sym.imp.elf_flagscn
fcn.10004120:
sym.imp.__assert_fail

View file

@ -59,7 +59,7 @@ afi~complex[1]
afbi@main
EOF
EXPECT=<<EOF
165
167
0x0002bca0 0x0002bccc 00:0000 44 j 0x0002c534 f 0x0002bccc
EOF
RUN
@ -163,7 +163,7 @@ af
afl
EOF
EXPECT=<<EOF
0x00018c08 350 8388 -> 7132 main
0x00018c08 357 8388 -> 7340 main
EOF
RUN
@ -176,7 +176,7 @@ af
afb
EOF
EXPECT=<<EOF
0x0002bca0 0x0002bccc 00:0000 44 f 0x0002bccc
0x0002bca0 0x0002bccc 00:0000 44 j 0x0002c534 f 0x0002bccc
0x0002bccc 0x0002bcec 00:0000 32 j 0x0002bd04 f 0x0002bcec
0x0002bcec 0x0002bd04 00:0000 24 j 0x0002bcec f 0x0002bd04
0x0002bd04 0x0002bd2c 00:0000 40 j 0x0002bd90 f 0x0002bd2c
@ -187,55 +187,55 @@ EXPECT=<<EOF
0x0002bd64 0x0002bd74 00:0000 16 j 0x0002bd80 f 0x0002bd74
0x0002bd74 0x0002bd80 00:0000 12 j 0x0002bd80
0x0002bd80 0x0002bd90 00:0000 16 j 0x0002bd90
0x0002bd90 0x0002bdc8 00:0000 56 f 0x0002bdc8
0x0002bd90 0x0002bdc8 00:0000 56 j 0x0002c5dc f 0x0002bdc8
0x0002bdc8 0x0002bde8 00:0000 32 f 0x0002bde8
0x0002bde8 0x0002bdec 00:0000 4 j 0x0002bdec
0x0002bdec 0x0002bdf8 00:0000 12 j 0x0002bdf8
0x0002bdf8 0x0002be10 00:0000 24 j 0x0002be40 f 0x0002be10
0x0002be10 0x0002be40 00:0000 48 j 0x0002be40
0x0002be40 0x0002be60 00:0000 32 j 0x0002be60 f 0x0002be60
0x0002be60 0x0002bebc 00:0000 92 f 0x0002bebc
0x0002bebc 0x0002bed4 00:0000 24 f 0x0002bed4
0x0002be60 0x0002bebc 00:0000 92 j 0x0002c53c f 0x0002bebc
0x0002bebc 0x0002bed4 00:0000 24 j 0x0002c564 f 0x0002bed4
0x0002bed4 0x0002bed8 00:0000 4 j 0x0002bed8
0x0002bed8 0x0002bfdc 00:0000 260 f 0x0002bfdc
0x0002bed8 0x0002bfdc 00:0000 260 j 0x0002c534 f 0x0002bfdc
0x0002bfdc 0x0002bff4 00:0000 24 f 0x0002bff4
0x0002bff4 0x0002c014 00:0000 32 f 0x0002c014
0x0002bff4 0x0002c014 00:0000 32 j 0x0002c644 f 0x0002c014
0x0002c014 0x0002c024 00:0000 16 f 0x0002c024
0x0002c024 0x0002c028 00:0000 4 j 0x0002c028
0x0002c028 0x0002c030 00:0000 8 f 0x0002c030
0x0002c030 0x0002c048 00:0000 24 j 0x0002c054 f 0x0002c048
0x0002c048 0x0002c054 00:0000 12 j 0x0002c054
0x0002c054 0x0002c084 00:0000 48 j 0x0002c094 f 0x0002c084
0x0002c084 0x0002c094 00:0000 16 f 0x0002c094
0x0002c084 0x0002c094 00:0000 16 j 0x0002c614 f 0x0002c094
0x0002c094 0x0002c098 00:0000 4 j 0x0002c098
0x0002c098 0x0002c0a4 00:0000 12 j 0x0002c0a4
0x0002c0a4 0x0002c0c4 00:0000 32 f 0x0002c0c4
0x0002c0c4 0x0002c0dc 00:0000 24 j 0x0002c200 f 0x0002c0dc
0x0002c0dc 0x0002c0ec 00:0000 16 j 0x0002c200 f 0x0002c0ec
0x0002c0ec 0x0002c108 00:0000 28 j 0x0002c108
0x0002c108 0x0002c118 00:0000 16 f 0x0002c118
0x0002c118 0x0002c128 00:0000 16 f 0x0002c128
0x0002c108 0x0002c118 00:0000 16 j 0x0002c570 f 0x0002c118
0x0002c118 0x0002c128 00:0000 16 j 0x0002c58c f 0x0002c128
0x0002c128 0x0002c12c 00:0000 4 j 0x0002c12c
0x0002c12c 0x0002c13c 00:0000 16 j 0x0002c14c
0x0002c13c 0x0002c14c 00:0000 16 f 0x0002c14c
0x0002c13c 0x0002c14c 00:0000 16 j 0x0002c58c f 0x0002c14c
0x0002c14c 0x0002c15c 00:0000 16 j 0x0002c13c f 0x0002c15c
0x0002c15c 0x0002c174 00:0000 24 j 0x0002c13c f 0x0002c174
0x0002c174 0x0002c18c 00:0000 24 f 0x0002c18c
0x0002c174 0x0002c18c 00:0000 24 j 0x0002c5c4 f 0x0002c18c
0x0002c18c 0x0002c1a4 00:0000 24 f 0x0002c1a4
0x0002c1a4 0x0002c1b8 00:0000 20 j 0x0002c1b8
0x0002c1b8 0x0002c1cc 00:0000 20 f 0x0002c1cc
0x0002c1b8 0x0002c1cc 00:0000 20 j 0x0002c58c f 0x0002c1cc
0x0002c1cc 0x0002c1dc 00:0000 16 f 0x0002c1dc
0x0002c1dc 0x0002c1f0 00:0000 20 j 0x0002c200 f 0x0002c1f0
0x0002c1f0 0x0002c200 00:0000 16 j 0x0002c108 f 0x0002c200
0x0002c200 0x0002c218 00:0000 24 f 0x0002c218
0x0002c218 0x0002c228 00:0000 16 f 0x0002c228
0x0002c218 0x0002c228 00:0000 16 j 0x0002c634 f 0x0002c228
0x0002c228 0x0002c244 00:0000 28 f 0x0002c244
0x0002c244 0x0002c25c 00:0000 24 j 0x0002c384 f 0x0002c25c
0x0002c25c 0x0002c284 00:0000 40 j 0x0002c380 f 0x0002c284
0x0002c284 0x0002c2b8 00:0000 52 j 0x0002c340
0x0002c2b8 0x0002c2c0 00:0000 8 j 0x0002c2c0
0x0002c2c0 0x0002c2e0 00:0000 32 j 0x0002c2e0
0x0002c2e0 0x0002c2f4 00:0000 20 f 0x0002c2f4
0x0002c2e0 0x0002c2f4 00:0000 20 j 0x0002c66c f 0x0002c2f4
0x0002c2f4 0x0002c304 00:0000 16 j 0x0002c380 f 0x0002c304
0x0002c304 0x0002c318 00:0000 20 j 0x0002c384 f 0x0002c318
0x0002c318 0x0002c340 00:0000 40 j 0x0002c380 f 0x0002c340
@ -264,7 +264,33 @@ EXPECT=<<EOF
0x0002c4b4 0x0002c4c4 00:0000 16 f 0x0002c4c4
0x0002c4c4 0x0002c4c8 00:0000 4 j 0x0002c4c8
0x0002c4c8 0x0002c4d8 00:0000 16 f 0x0002c4d8
0x0002c4d8 0x0002c4e8 00:0000 16
0x0002c4d8 0x0002c4e8 00:0000 16 f 0x0002c4e8
0x0002c4e8 0x0002c4f8 00:0000 16 j 0x0002c50c
0x0002c4f8 0x0002c508 00:0000 16 f 0x0002c508
0x0002c508 0x0002c50c 00:0000 4 j 0x0002c50c
0x0002c50c 0x0002c534 00:0000 40 j 0x0002c4f8 f 0x0002c534
0x0002c534 0x0002c53c 00:0000 8
0x0002c53c 0x0002c550 00:0000 20 j 0x0002bfdc f 0x0002c550
0x0002c550 0x0002c560 00:0000 16 j 0x0002bed8 f 0x0002c560
0x0002c560 0x0002c564 00:0000 4 j 0x0002c564
0x0002c564 0x0002c570 00:0000 12 j 0x0002bed4
0x0002c570 0x0002c580 00:0000 16 j 0x0002c118 f 0x0002c580
0x0002c580 0x0002c58c 00:0000 12 j 0x0002c12c f 0x0002c58c
0x0002c58c 0x0002c598 00:0000 12 j 0x0002c200 f 0x0002c598
0x0002c598 0x0002c5c4 00:0000 44
0x0002c5c4 0x0002c5dc 00:0000 24 j 0x0002c1b8
0x0002c5dc 0x0002c60c 00:0000 48 j 0x0002bdec f 0x0002c60c
0x0002c60c 0x0002c614 00:0000 8
0x0002c614 0x0002c61c 00:0000 8 j 0x0002c0a4 f 0x0002c61c
0x0002c61c 0x0002c62c 00:0000 16 j 0x0002c098 f 0x0002c62c
0x0002c62c 0x0002c634 00:0000 8 j 0x0002c0a4
0x0002c634 0x0002c644 00:0000 16
0x0002c644 0x0002c650 00:0000 12 f 0x0002c650
0x0002c650 0x0002c66c 00:0000 28 j 0x0002c014
0x0002c66c 0x0002c67c 00:0000 16 j 0x0002c69c f 0x0002c67c
0x0002c67c 0x0002c694 00:0000 24 f 0x0002c694
0x0002c694 0x0002c69c 00:0000 8 j 0x0002c2e0
0x0002c69c 0x0002c6a8 00:0000 12
EOF
RUN

View file

@ -83,7 +83,7 @@ EXPECT=<<EOF
0x00106cd0 4 50 fcn.00106cd0
0x00106d02 1 22 sym.__realloc_r
0x0010722c 12 150 sym.__sbrk
0x001072c2 15 240 -> 198 sym.___swbuf_r
0x001072c2 11 142 sym.___swbuf_r
0x001073ba 1 18 sym.___swbuf
0x001073d0 5 70 sym.__wcrtomb_r
0x00107416 1 20 sym._wcrtomb
@ -280,7 +280,7 @@ EXPECT=<<EOF
0x00114130 1 36 fcn.00114130
0x00114afc 1 20 sym._vfiprintf
0x00114b14 1 90 sym.___sbprintf_1
0x00114ba8 15 240 -> 198 sym.___swbuf_r
0x00114ba8 11 142 sym.___swbuf_r
0x00114ca0 1 18 sym.___swbuf
0x00114cb6 5 58 sym.__wctomb_r
0x00114cf0 1 18 sym.__write
@ -340,7 +340,7 @@ EXPECT=<<EOF
0x00102ec0 7 158 sym._cmd_print
0x00102f5e 7 180 sym._cmd_bytedump
0x00103012 8 236 sym._cmd_search
0x0010333c 10 318 -> 242 sym._cmd_bsize
0x0010333c 4 116 sym._cmd_bsize
0x0010347a 2 46 sym._cmd_seek
0x00103674 10 244 sym._cmd_dump
0x00103768 5 190 sym._cmd_load

View file

@ -5,7 +5,7 @@ aap
aflc
EOF
EXPECT=<<EOF
440
445
EOF
RUN
@ -109,24 +109,24 @@ afb+ 0x100000da0 0x100000e9e 24 0x100000db6 0x100000eb6
afb+ 0x100000da0 0x100000db6 26 0x100000e99 0x100000dd0
afb+ 0x100000da0 0x100000eb6 4 0x100000eba 0xffffffffffffffff
afb+ 0x100000da0 0x100000dd0 20 0xffffffffffffffff 0xffffffffffffffff
afb+ 0x100000da0 0x100000de4 16 0x100000dfb 0x100000df4
afb+ 0x100000da0 0x100000dfb 5 0x100000e99 0xffffffffffffffff
afb+ 0x100000da0 0x100000df4 7 0x100000dfb 0xffffffffffffffff
afb+ 0x100000da0 0x100000e00 16 0x100000e1c 0x100000e10
afb+ 0x100000da0 0x100000e1c 9 0x100000eba 0xffffffffffffffff
afb+ 0x100000da0 0x100000e90 9 0x100000eba 0xffffffffffffffff
afb+ 0x100000da0 0x100000eba 6 0xffffffffffffffff 0xffffffffffffffff
afb+ 0x100000da0 0x100000e10 12 0x100000e25 0xffffffffffffffff
afb+ 0x100000da0 0x100000e25 5 0x100000e99 0xffffffffffffffff
afb+ 0x100000da0 0x100000e2a 16 0x100000e46 0x100000e3a
afb+ 0x100000da0 0x100000e46 9 0x100000eba 0xffffffffffffffff
afb+ 0x100000da0 0x100000e3a 12 0x100000e4f 0xffffffffffffffff
afb+ 0x100000da0 0x100000e4f 5 0x100000e99 0xffffffffffffffff
afb+ 0x100000da0 0x100000e54 16 0x100000e82 0x100000e64
afb+ 0x100000da0 0x100000e82 9 0x100000eba 0xffffffffffffffff
afb+ 0x100000da0 0x100000e64 16 0x100000e82 0x100000e74
afb+ 0x100000da0 0x100000e74 14 0x100000e8b 0xffffffffffffffff
afb+ 0x100000da0 0x100000e8b 5 0x100000e99 0xffffffffffffffff
afb+ 0x100000da0 0x100000e90 9 0x100000eba 0xffffffffffffffff
afb+ 0x100000da0 0x100000e2a 16 0x100000e46 0x100000e3a
afb+ 0x100000da0 0x100000e46 9 0x100000eba 0xffffffffffffffff
afb+ 0x100000da0 0x100000e3a 12 0x100000e4f 0xffffffffffffffff
afb+ 0x100000da0 0x100000e4f 5 0x100000e99 0xffffffffffffffff
afb+ 0x100000da0 0x100000e00 16 0x100000e1c 0x100000e10
afb+ 0x100000da0 0x100000e1c 9 0x100000eba 0xffffffffffffffff
afb+ 0x100000da0 0x100000e10 12 0x100000e25 0xffffffffffffffff
afb+ 0x100000da0 0x100000e25 5 0x100000e99 0xffffffffffffffff
afb+ 0x100000da0 0x100000de4 16 0x100000dfb 0x100000df4
afb+ 0x100000da0 0x100000dfb 5 0x100000e99 0xffffffffffffffff
afb+ 0x100000da0 0x100000df4 7 0x100000dfb 0xffffffffffffffff
afB 64 @ 0x100000da0
afc amd64 @ 0x100000da0
afvb -40 var_28h int64_t @ 0x100000da0
@ -650,7 +650,7 @@ aac
afl~?
EOF
EXPECT=<<EOF
1268
1270
EOF
RUN

View file

@ -11,6 +11,7 @@ EXPECT=<<EOF
0x00015dc0 8 55 -> 45 sym._obstack_allocated_p
0x00015e70 5 41 -> 36 sym._obstack_memory_used
0x00015e00 9 73225 -> 102 sym._obstack_free
0x00015bd0 3 21 fcn.00015bd0
0x00015cc0 8 256 -> 250 sym._obstack_newchunk
0x00004070 300 6757 -> 6739 main
0x00005bd0 5 153 -> 60 entry.init0
@ -23,6 +24,11 @@ EXPECT=<<EOF
0x00015100 95 1137 -> 1129 fcn.00015100
0x00013c30 1 17 fcn.00013c30
0x0000c940 3 112 -> 109 fcn.0000c940
0x0000c790 4 124 -> 117 fcn.0000c790
0x00014370 1 19 fcn.00014370
0x00013f90 5 65498 -> 148 fcn.00013f90
0x00013a40 14 64434 -> 438 fcn.00013a40
0x0000c810 50 95704 -> 612 fcn.0000c810
0x00014c00 7 82 fcn.00014c00
0x0000fcc0 28 485 -> 456 fcn.0000fcc0
0x00005f20 8 128 -> 114 fcn.00005f20
@ -42,21 +48,18 @@ EXPECT=<<EOF
0x0000e8c0 21 217 -> 211 fcn.0000e8c0
0x00006200 5 105 fcn.00006200
0x00007250 1 40 fcn.00007250
0x00007180 3 85 -> 76 fcn.00007180
0x00006fa0 20 473 -> 448 fcn.00006fa0
0x00014e40 1 20 fcn.00014e40
0x00005c40 45 634 -> 527 fcn.00005c40
0x000063e0 18 401 -> 395 fcn.000063e0
0x00009380 104 109608 -> 1589 fcn.00009380
0x00009380 64 1388 -> 1269 fcn.00009380
0x00015020 10 210 -> 199 fcn.00015020
0x00006840 9 197 fcn.00006840
0x00005fa0 34 596 -> 585 fcn.00005fa0
0x00005ec0 6 89 -> 80 fcn.00005ec0
0x000065f0 22 379 -> 375 fcn.000065f0
0x0000bde0 18 1924 -> 1917 fcn.0000bde0
0x0000c790 4 124 -> 117 fcn.0000c790
0x00014370 1 19 fcn.00014370
0x00013f90 5 65498 -> 148 fcn.00013f90
0x00013a40 14 64434 -> 438 fcn.00013a40
0x00015580 12 193 -> 186 fcn.00015580
0x00014e60 1 56 fcn.00014e60
0x00015650 98 1137 -> 1135 fcn.00015650
@ -72,7 +75,6 @@ EXPECT=<<EOF
0x000140b0 1 12 fcn.000140b0
0x00006c60 22 233 -> 190 fcn.00006c60
0x000071e0 37 118072 -> 402 fcn.000071e0
0x00007180 3 85 -> 76 fcn.00007180
0x00015ad0 7 136 -> 132 fcn.00015ad0
0x00010740 40 480 -> 447 fcn.00010740
0x000073d0 67 1135 -> 1075 fcn.000073d0
@ -87,6 +89,11 @@ EXPECT=<<EOF
0x0000f270 141 2626 -> 2515 fcn.0000f270
0x0000d6b0 17 392 -> 366 fcn.0000d6b0
0x00016270 12 166 -> 152 fcn.00016270
0x000161a0 12 176 -> 164 fcn.000161a0
0x00015ea0 6 72 -> 71 fcn.00015ea0
0x00015ef0 5 41 -> 36 fcn.00015ef0
0x00016010 25 397 -> 361 fcn.00016010
0x00015f20 3 66 fcn.00015f20
0x00012530 3 71 fcn.00012530
0x00010c30 310 6399 -> 6311 fcn.00010c30
0x00006910 8 188 -> 175 fcn.00006910
@ -112,13 +119,14 @@ EXPECT=<<EOF
0x00009b00 9 204 -> 194 fcn.00009b00
0x0000ee80 7 90 -> 82 fcn.0000ee80
0x00006580 1 42 fcn.00006580
0x0000c810 10 297 -> 292 fcn.0000c810
0x00014fe0 4 64 -> 56 fcn.00014fe0
0x0000d4d0 5 88 fcn.0000d4d0
0x0000d440 7 144 -> 133 fcn.0000d440
0x0000f190 1 23 loc.0000f190
0x000164a0 8 102 -> 96 fcn.000164a0
0x000165b0 24 55032 -> 248 fcn.000165b0
0x000165b0 9 139 -> 128 fcn.000165b0
0x00016640 5 66 -> 63 fcn.00016640
0x00016690 7 89 fcn.00016690
0x00014180 4 193 -> 170 fcn.00014180
0x0000e3f0 9 83 -> 75 fcn.0000e3f0
0x0000d7e0 17 195 -> 166 fcn.0000d7e0
@ -142,14 +150,6 @@ EXPECT=<<EOF
0x000145b0 20 67969 -> 1004 fcn.000145b0
0x00014d60 8 120 -> 114 fcn.00014d60
0x00015bb0 3 21 fcn.00015bb0
0x00015bd0 3 21 fcn.00015bd0
0x00015ea0 6 72 -> 71 fcn.00015ea0
0x00015ef0 5 41 -> 36 fcn.00015ef0
0x000161a0 12 176 -> 164 fcn.000161a0
0x00016010 25 397 -> 361 fcn.00016010
0x00015f20 3 66 fcn.00015f20
0x00016640 5 66 -> 63 fcn.00016640
0x00016690 7 89 fcn.00016690
0x00004000 3 27 fcn.00004000
EOF
RUN

View file

@ -8,6 +8,7 @@ sym._obstack_begin_1
sym._obstack_allocated_p
sym._obstack_memory_used
sym._obstack_free
fcn.00015bd0
sym._obstack_newchunk
main
entry.init0

View file

@ -902,7 +902,7 @@ EXPECT=<<EOF
0x0045a8c0 132 flirt.__sigsetjmp
0x0045abc0 6232 flirt._quicksort
0x0045c620 19 flirt.__libc_secure_getenv
0x0045ce30 10673 flirt.group_number
0x0045ce30 10704 flirt.group_number
0x0045f800 13172 flirt._IO_vfprintf_internal
0x00462b80 976 flirt.hack_digit
0x00465a50 11033 flirt.___printf_fp

View file

@ -1764,7 +1764,7 @@ aaa
pd 20 @ dbg.palya
EOF
EXPECT=<<EOF
; CALL XREFS from sym.main @ +0x1a87, +0x1c7d, +0x23f3, +0x3679
; CALL XREFS from dbg.$main @ 0x405237, 0x40542d, 0x405ba3, 0x406e29
;-- P$MOZGKIGYO_$$_PALYA$SMALLINT$SMALLINT:
/ dbg.palya ();
| ; var int64_t var_28h @ rbp-0x28

View file

@ -1848,9 +1848,9 @@ char *
uint32_t
int64_t
char *
size_t *
size_t
void *
size_t
size_t *
wint_t
=
fcn.0000f770

View file

@ -399,7 +399,7 @@ aac
aflc
EOF
EXPECT=<<EOF
794
802
EOF
RUN

File diff suppressed because one or more lines are too long