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