1 /* radare - LGPL - Copyright 2010-2019 - pancake, nibble */
2 
3 #include <r_anal.h>
4 #include <r_util.h>
5 #include <r_list.h>
6 #include <limits.h>
7 
8 typedef struct {
9 	ut64 addr;
10 	RAnalBlock *ret;
11 } BBFromOffsetJmpmidCtx;
12 
bb_from_offset_jmpmid_cb(RAnalBlock * block,void * user)13 static bool bb_from_offset_jmpmid_cb(RAnalBlock *block, void *user) {
14 	BBFromOffsetJmpmidCtx *ctx = user;
15 	// If an instruction starts exactly at the search addr, return that block immediately
16 	if (r_anal_block_op_starts_at (block, ctx->addr)) {
17 		ctx->ret = block;
18 		return false;
19 	}
20 	// else search the closest one
21 	if (!ctx->ret || ctx->ret->addr < block->addr) {
22 		ctx->ret = block;
23 	}
24 	return true;
25 }
26 
bb_from_offset_first_cb(RAnalBlock * block,void * user)27 static bool bb_from_offset_first_cb(RAnalBlock *block, void *user) {
28 	RAnalBlock **ret = user;
29 	*ret = block;
30 	return false;
31 }
32 
r_anal_bb_from_offset(RAnal * anal,ut64 off)33 R_API RAnalBlock *r_anal_bb_from_offset(RAnal *anal, ut64 off) {
34 	const bool x86 = anal->cur->arch && !strcmp (anal->cur->arch, "x86");
35 	if (anal->opt.jmpmid && x86) {
36 		BBFromOffsetJmpmidCtx ctx = { off, NULL };
37 		r_anal_blocks_foreach_in (anal, off, bb_from_offset_jmpmid_cb, &ctx);
38 		return ctx.ret;
39 	}
40 
41 	RAnalBlock *ret = NULL;
42 	r_anal_blocks_foreach_in (anal, off, bb_from_offset_first_cb, &ret);
43 	return ret;
44 }
45 
46 /* return the offset of the i-th instruction in the basicblock bb.
47  * If the index of the instruction is not valid, it returns UT16_MAX */
r_anal_bb_offset_inst(const RAnalBlock * bb,int i)48 R_API ut16 r_anal_bb_offset_inst(const RAnalBlock *bb, int i) {
49 	if (i < 0 || i >= bb->ninstr) {
50 		return UT16_MAX;
51 	}
52 	return (i > 0 && (i - 1) < bb->op_pos_size)? bb->op_pos[i - 1]: 0;
53 }
54 
55 /* return the address of the i-th instruction in the basicblock bb.
56  * If the index of the instruction is not valid, it returns UT64_MAX */
r_anal_bb_opaddr_i(RAnalBlock * bb,int i)57 R_API ut64 r_anal_bb_opaddr_i(RAnalBlock *bb, int i) {
58 	ut16 offset = r_anal_bb_offset_inst (bb, i);
59 	if (offset == UT16_MAX) {
60 		return UT64_MAX;
61 	}
62 	return bb->addr + offset;
63 }
64 
65 /* set the offset of the i-th instruction in the basicblock bb */
r_anal_bb_set_offset(RAnalBlock * bb,int i,ut16 v)66 R_API bool r_anal_bb_set_offset(RAnalBlock *bb, int i, ut16 v) {
67 	// the offset 0 of the instruction 0 is not stored because always 0
68 	if (i > 0 && v > 0) {
69 		if (i >= bb->op_pos_size) {
70 			int new_pos_size = i * 2;
71 			ut16 *tmp_op_pos = realloc (bb->op_pos, new_pos_size * sizeof (*bb->op_pos));
72 			if (!tmp_op_pos) {
73 				return false;
74 			}
75 			bb->op_pos_size = new_pos_size;
76 			bb->op_pos = tmp_op_pos;
77 		}
78 		bb->op_pos[i - 1] = v;
79 		return true;
80 	}
81 	return true;
82 }
83 
84 /* return the address of the instruction that occupy a given offset.
85  * If the offset is not part of the given basicblock, UT64_MAX is returned. */
r_anal_bb_opaddr_at(RAnalBlock * bb,ut64 off)86 R_API ut64 r_anal_bb_opaddr_at(RAnalBlock *bb, ut64 off) {
87 	ut16 delta, delta_off, last_delta;
88 	int i;
89 
90 	if (!r_anal_block_contains (bb, off)) {
91 		return UT64_MAX;
92 	}
93 	last_delta = 0;
94 	delta_off = off - bb->addr;
95 	for (i = 0; i < bb->ninstr; i++) {
96 		delta = r_anal_bb_offset_inst (bb, i);
97 		if (delta > delta_off) {
98 			return bb->addr + last_delta;
99 		}
100 		last_delta = delta;
101 	}
102 	return bb->addr + last_delta;
103 }
104 
105 // returns the size of the i-th instruction in a basic block
r_anal_bb_size_i(RAnalBlock * bb,int i)106 R_API ut64 r_anal_bb_size_i(RAnalBlock *bb, int i) {
107 	if (i < 0 || i >= bb->ninstr) {
108 		return UT64_MAX;
109 	}
110 	ut16 idx_cur = r_anal_bb_offset_inst (bb, i);
111 	ut16 idx_next = r_anal_bb_offset_inst (bb, i + 1);
112 	return idx_next != UT16_MAX? idx_next - idx_cur: bb->size - idx_cur;
113 }
114 
115 /* returns the address of the basic block that contains addr or UT64_MAX if
116  * there is no such basic block */
r_anal_get_bbaddr(RAnal * anal,ut64 addr)117 R_API ut64 r_anal_get_bbaddr(RAnal *anal, ut64 addr) {
118 	RAnalBlock *bb = r_anal_bb_from_offset (anal, addr);
119 	return bb? bb->addr: UT64_MAX;
120 }
121