Rizin
unix-like reverse engineering framework and cli tools
il_reg.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2021 Florian Märkl <info@florianmaerkl.de>
2 // SPDX-License-Identifier: LGPL-3.0-only
3 
4 #include <rz_il/rz_il_reg.h>
5 #include <rz_il/rz_il_vm.h>
6 #include <rz_util.h>
7 
8 static int reg_offset_cmp(const void *value, const void *list_data) {
9  return ((RzRegItem *)value)->offset - ((RzRegItem *)list_data)->offset;
10 }
11 
12 static void reg_binding_item_fini(RzILRegBindingItem *item, void *unused) {
13  free(item->name);
14 }
15 
38  if (!rb) {
39  return NULL;
40  }
41  RzVector regs;
43  for (int i = 0; i < RZ_REG_TYPE_LAST; i++) {
44  // bind all flags (1-bit regs) unconditionally
45  RzRegItem *item;
48  if (!flags) {
49  continue;
50  }
51  rz_list_foreach (reg->regset[i].regs, iter, item) {
52  if (item->size != 1) {
53  continue;
54  }
55  // check for same-offset flag
56  RzRegItem *item2;
57  RzListIter *iter2;
58  rz_list_foreach (flags, iter2, item2) {
59  if (item2->offset == item->offset) {
60  goto next_flag;
61  }
62  }
63  // all good, bind it
64  rz_list_push(flags, item);
65  char *name = strdup(item->name);
66  if (!name) {
68  goto err;
69  }
71  if (!bitem) {
72  free(name);
74  goto err;
75  }
76  bitem->name = name;
77  bitem->size = item->size;
78  next_flag:
79  continue;
80  }
81  // for the remaining regs, first filter regs that contain a flag
82  RzList *nonflags = rz_list_new();
83  if (!nonflags) {
85  goto err;
86  }
87  rz_list_foreach (reg->regset[i].regs, iter, item) {
88  RzRegItem *flag;
89  RzListIter *fiter;
90  rz_list_foreach (flags, fiter, flag) {
91  if (flag->offset >= item->offset && flag->offset < item->offset + item->size) {
92  goto next_reg;
93  }
94  }
95  rz_list_push(nonflags, item);
96  next_reg:
97  continue;
98  }
99  // then bind the remaining regs, favoring larger ones on overlaps
100  RzList *items = rz_reg_filter_items_covered(nonflags);
101  rz_list_free(nonflags);
102  if (!items) {
104  continue;
105  }
107  const char *pc = rz_reg_get_name(reg, RZ_REG_NAME_PC);
108  RzRegItem *prev = NULL;
109  rz_list_foreach (items, iter, item) {
110  if (prev && prev->offset + prev->size > item->offset) {
111  // overlap where one reg is not fully contained in another.
112  // this is not supported yet.
113  continue;
114  }
115  if (pc && !strcmp(item->name, pc)) {
116  // pc is handled outside of reg binding
117  continue;
118  }
119  char *name = strdup(item->name);
120  if (!name) {
122  rz_list_free(items);
123  goto err;
124  }
126  if (!bitem) {
127  free(name);
129  rz_list_free(items);
130  goto err;
131  }
132  bitem->name = name;
133  bitem->size = item->size;
134  prev = item;
135  }
136  rz_list_free(items);
138  }
139  // from now on, the array should be treated immutable, so we deliberately don't use RzVector anymore.
140  rb->regs_count = rz_vector_len(&regs);
141  rb->regs = rz_vector_flush(&regs);
143  return rb;
144 err:
146  free(rb);
147  return NULL;
148 }
149 
157  if (!rb) {
158  return NULL;
159  }
160  rb->regs_count = regs_count;
161  rb->regs = RZ_NEWS0(RzILRegBindingItem, regs_count);
162  if (!rb->regs) {
163  goto err_rb;
164  }
165  // all bound items to check for overlaps
166  RzRegItem **items = RZ_NEWS(RzRegItem *, regs_count);
167  if (!items) {
168  goto err_regs;
169  }
170  for (size_t i = 0; i < regs_count; i++) {
172  if (!ri) {
173  goto err_regs;
174  }
175  // Check if this item overlaps any already bound registers.
176  // Overlaps must not happen because they will confuse the VM and analysis.
177  for (size_t j = 0; j < i; j++) {
178  if (items[j]->type != ri->type) {
179  continue;
180  }
181  if (items[j]->offset + items[j]->size <= ri->offset || items[j]->offset >= ri->offset + ri->size) {
182  continue;
183  }
184  // overlap detected
185  goto err_regs;
186  }
187  rb->regs[i].name = strdup(regs[i]);
188  if (!rb->regs[i].name) {
189  goto err_regs;
190  }
191  rb->regs[i].size = ri->size;
192  items[i] = ri;
193  }
194  free(items);
195  return rb;
196 err_regs:
197  for (size_t i = 0; i < regs_count; i++) {
199  }
200  free(rb->regs);
201  free(items);
202 err_rb:
203  free(rb);
204  return NULL;
205 }
206 
208  if (!rb) {
209  return;
210  }
211  for (size_t i = 0; i < rb->regs_count; i++) {
213  }
214  free(rb->regs);
215  free(rb);
216 }
217 
223  rz_return_if_fail(vm && rb);
224  for (size_t i = 0; i < rb->regs_count; i++) {
225  rz_il_vm_create_global_var(vm, rb->regs[i].name,
226  rb->regs[i].size == 1 ? rz_il_sort_pure_bool() : rz_il_sort_pure_bv(rb->regs[i].size));
227  }
228 }
229 
242  rz_return_val_if_fail(vm && rb && reg, false);
243  bool perfect = true;
244  const char *pc = rz_reg_get_name(reg, RZ_REG_NAME_PC);
245  if (pc) {
247  if (ri) {
248  RzBitVector *pcbv = rz_bv_new_zero(ri->size);
249  if (pcbv) {
250  perfect &= rz_bv_len(pcbv) == rz_bv_len(vm->pc);
251  rz_bv_copy_nbits(vm->pc, 0, pcbv, 0, RZ_MIN(rz_bv_len(pcbv), rz_bv_len(vm->pc)));
252  rz_reg_set_bv(reg, ri, pcbv);
253  rz_bv_free(pcbv);
254  } else {
255  perfect = false;
256  }
257  } else {
258  perfect = false;
259  }
260  } else {
261  perfect = false;
262  }
263  for (size_t i = 0; i < rb->regs_count; i++) {
264  RzILRegBindingItem *item = &rb->regs[i];
266  if (!ri) {
267  perfect = false;
268  continue;
269  }
271  if (!val) {
272  perfect = false;
273  RzBitVector *bv = rz_bv_new_zero(ri->size);
274  if (!bv) {
275  break;
276  }
277  if (bv) {
278  rz_reg_set_bv(reg, ri, bv);
279  rz_bv_free(bv);
280  }
281  continue;
282  }
283  RzBitVector *dupped = NULL;
284  const RzBitVector *bv;
285  if (val->type == RZ_IL_TYPE_PURE_BITVECTOR) {
286  bv = val->data.bv;
287  if (rz_bv_len(bv) != ri->size) {
288  perfect = false;
289  dupped = rz_bv_new_zero(ri->size);
290  if (!dupped) {
291  break;
292  }
293  if (ri->size > 1) {
294  rz_bv_copy_nbits(bv, 0, dupped, 0, RZ_MIN(rz_bv_len(bv), ri->size));
295  } else {
296  rz_bv_set_from_ut64(dupped, rz_bv_is_zero_vector(bv) ? 0 : 1);
297  }
298  bv = dupped;
299  }
300  } else { // RZ_IL_VAR_TYPE_BOOL
301  bv = dupped = val->data.b->b ? rz_bv_new_one(ri->size) : rz_bv_new_zero(ri->size);
302  if (!dupped) {
303  break;
304  }
305  }
306  perfect &= rz_reg_set_bv(reg, ri, bv);
307  rz_bv_free(dupped);
308  }
309  return perfect;
310 }
311 
317  rz_return_if_fail(vm && rb && reg);
318  const char *pc = rz_reg_get_name(reg, RZ_REG_NAME_PC);
319  if (pc) {
321  if (ri) {
322  rz_bv_set_all(vm->pc, 0);
323  RzBitVector *pcbv = rz_reg_get_bv(reg, ri);
324  if (pcbv) {
325  rz_bv_copy_nbits(pcbv, 0, vm->pc, 0, RZ_MIN(rz_bv_len(pcbv), rz_bv_len(vm->pc)));
326  rz_bv_free(pcbv);
327  }
328  }
329  }
330  for (size_t i = 0; i < rb->regs_count; i++) {
331  RzILRegBindingItem *item = &rb->regs[i];
333  if (!var) {
334  RZ_LOG_ERROR("IL Variable \"%s\" does not exist for bound register of the same name.\n", item->name);
335  continue;
336  }
338  if (item->size == 1) {
339  bool b = ri ? rz_reg_get_value(reg, ri) != 0 : false;
341  } else {
342  RzBitVector *bv = ri ? rz_reg_get_bv(reg, ri) : rz_bv_new_zero(item->size);
343  if (!bv) {
344  continue;
345  }
346  RzBitVector *dupped = NULL;
347  if (rz_bv_len(bv) != item->size) {
348  RzBitVector *nbv = rz_bv_new_zero(item->size);
349  if (!nbv) {
350  rz_bv_free(bv);
351  break;
352  }
353  rz_bv_copy_nbits(bv, 0, nbv, 0, RZ_MIN(rz_bv_len(bv), item->size));
354  dupped = bv;
355  bv = nbv;
356  }
358  rz_bv_free(dupped);
359  }
360  }
361 }
static char * regs[]
Definition: analysis_sh.c:203
lzma_index ** i
Definition: index.h:629
ut16 val
Definition: armass64_const.h:6
static bool err
Definition: armass.c:435
RZ_API RzILBool * rz_il_bool_new(bool true_or_false)
Definition: bool.c:11
static int value
Definition: cmd_api.c:93
#define RZ_API
#define NULL
Definition: cris-opc.c:27
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
RZ_API RZ_OWN RzILVal * rz_il_value_new_bitv(RZ_NONNULL RzBitVector *bv)
Definition: value.c:28
RZ_API RZ_OWN RzILVal * rz_il_value_new_bool(RZ_NONNULL RzILBool *b)
Definition: value.c:43
RZ_API void rz_il_vm_sync_from_reg(RZ_NONNULL RzILVM *vm, RZ_NONNULL RzILRegBinding *rb, RZ_NONNULL RzReg *reg)
Definition: il_reg.c:316
static void reg_binding_item_fini(RzILRegBindingItem *item, void *unused)
Definition: il_reg.c:12
RZ_API void rz_il_vm_setup_reg_binding(RZ_NONNULL RzILVM *vm, RZ_NONNULL RZ_BORROW RzILRegBinding *rb)
Definition: il_reg.c:222
RZ_API bool rz_il_vm_sync_to_reg(RZ_NONNULL RzILVM *vm, RZ_NONNULL RzILRegBinding *rb, RZ_NONNULL RzReg *reg)
Definition: il_reg.c:241
static int reg_offset_cmp(const void *value, const void *list_data)
Definition: il_reg.c:8
RZ_API RzILRegBinding * rz_il_reg_binding_exactly(RZ_NONNULL RzReg *reg, size_t regs_count, RZ_NONNULL RZ_BORROW const char **regs)
Definition: il_reg.c:154
RZ_API void rz_il_reg_binding_free(RzILRegBinding *rb)
Definition: il_reg.c:207
RZ_API RzILRegBinding * rz_il_reg_binding_derive(RZ_NONNULL RzReg *reg)
Calculate a new binding of IL variables against the profile of the given RzReg.
Definition: il_reg.c:35
RZ_API void rz_il_vm_set_global_var(RZ_NONNULL RzILVM *vm, RZ_NONNULL const char *name, RZ_OWN RzILVal *val)
Definition: il_vm.c:193
RZ_API RZ_BORROW RzILVal * rz_il_vm_get_var_value(RZ_NONNULL RzILVM *vm, RzILVarKind kind, const char *name)
Definition: il_vm.c:264
RZ_API RZ_BORROW RzILVar * rz_il_vm_create_global_var(RZ_NONNULL RzILVM *vm, RZ_NONNULL const char *name, RzILSortPure sort)
Definition: il_vm.c:175
RZ_API RZ_BORROW RzILVar * rz_il_vm_get_var(RZ_NONNULL RzILVM *vm, RzILVarKind kind, const char *name)
Definition: il_vm.c:251
voidpf void uLong size
Definition: ioapi.h:138
voidpf uLong offset
Definition: ioapi.h:144
#define reg(n)
RZ_API RZ_OWN RzList * rz_list_new(void)
Returns a new initialized RzList pointer (free method is not initialized)
Definition: list.c:235
RZ_API void rz_list_sort(RZ_NONNULL RzList *list, RZ_NONNULL RzListComparator cmp)
Sorts via merge sort or via insertion sort a list.
Definition: list.c:743
RZ_API RZ_BORROW RzListIter * rz_list_push(RZ_NONNULL RzList *list, void *item)
Alias for rz_list_append.
Definition: list.c:60
RZ_API void rz_list_free(RZ_NONNULL RzList *list)
Empties the list and frees the list pointer.
Definition: list.c:137
return strdup("=SP r13\n" "=LR r14\n" "=PC r15\n" "=A0 r0\n" "=A1 r1\n" "=A2 r2\n" "=A3 r3\n" "=ZF zf\n" "=SF nf\n" "=OF vf\n" "=CF cf\n" "=SN or0\n" "gpr lr .32 56 0\n" "gpr pc .32 60 0\n" "gpr cpsr .32 64 0 ____tfiae_________________qvczn\n" "gpr or0 .32 68 0\n" "gpr tf .1 64.5 0 thumb\n" "gpr ef .1 64.9 0 endian\n" "gpr jf .1 64.24 0 java\n" "gpr qf .1 64.27 0 sticky_overflow\n" "gpr vf .1 64.28 0 overflow\n" "gpr cf .1 64.29 0 carry\n" "gpr zf .1 64.30 0 zero\n" "gpr nf .1 64.31 0 negative\n" "gpr itc .4 64.10 0 if_then_count\n" "gpr gef .4 64.16 0 great_or_equal\n" "gpr r0 .32 0 0\n" "gpr r1 .32 4 0\n" "gpr r2 .32 8 0\n" "gpr r3 .32 12 0\n" "gpr r4 .32 16 0\n" "gpr r5 .32 20 0\n" "gpr r6 .32 24 0\n" "gpr r7 .32 28 0\n" "gpr r8 .32 32 0\n" "gpr r9 .32 36 0\n" "gpr r10 .32 40 0\n" "gpr r11 .32 44 0\n" "gpr r12 .32 48 0\n" "gpr r13 .32 52 0\n" "gpr r14 .32 56 0\n" "gpr r15 .32 60 0\n" "gpr r16 .32 64 0\n" "gpr r17 .32 68 0\n")
int type
Definition: mipsasm.c:17
const char * name
Definition: op.c:541
RZ_API RzRegItem * rz_reg_get(RzReg *reg, const char *name, int type)
Definition: reg.c:344
RZ_API const char * rz_reg_get_name(RzReg *reg, int role)
Definition: reg.c:147
RZ_API RZ_OWN RzList * rz_reg_filter_items_covered(RZ_BORROW RZ_NONNULL const RzList *regs)
Filter out all register items that are smaller than but covered entirely by some other register.
Definition: reg.c:489
RZ_API bool rz_reg_set_bv(RZ_NONNULL RzReg *reg, RZ_NONNULL RzRegItem *item, RZ_NONNULL const RzBitVector *bv)
Definition: rvalue.c:26
RZ_API RzBitVector * rz_reg_get_bv(RZ_NONNULL RzReg *reg, RZ_NONNULL RzRegItem *item)
Definition: rvalue.c:11
RZ_API ut64 rz_reg_get_value(RzReg *reg, RzRegItem *item)
Definition: rvalue.c:114
#define rz_return_if_fail(expr)
Definition: rz_assert.h:100
#define rz_return_val_if_fail(expr, val)
Definition: rz_assert.h:108
RZ_API bool rz_bv_set_from_ut64(RZ_NONNULL RzBitVector *bv, ut64 value)
Definition: bitvector.c:1222
RZ_API void rz_bv_free(RZ_NULLABLE RzBitVector *bv)
Definition: bitvector.c:85
RZ_API ut32 rz_bv_len(RZ_NONNULL const RzBitVector *bv)
Definition: bitvector.c:1140
RZ_API bool rz_bv_is_zero_vector(RZ_NONNULL const RzBitVector *x)
Definition: bitvector.c:1021
RZ_API bool rz_bv_set_all(RZ_NONNULL RzBitVector *bv, bool b)
Definition: bitvector.c:367
#define rz_bv_new_one(l)
Definition: rz_bitvector.h:106
#define rz_bv_new_zero(l)
Definition: rz_bitvector.h:105
RZ_API ut32 rz_bv_copy_nbits(RZ_NONNULL const RzBitVector *src, ut32 src_start_pos, RZ_NONNULL RzBitVector *dst, ut32 dst_start_pos, ut32 nbit)
Definition: bitvector.c:210
#define RZ_LOG_ERROR(fmtstr,...)
Definition: rz_log.h:58
@ RZ_REG_TYPE_LAST
Definition: rz_reg.h:34
@ RZ_REG_TYPE_ANY
Definition: rz_reg.h:35
@ RZ_REG_NAME_PC
Definition: rz_reg.h:43
#define RZ_NEWS(x, y)
Definition: rz_types.h:283
#define RZ_NEW0(x)
Definition: rz_types.h:284
#define RZ_NONNULL
Definition: rz_types.h:64
#define RZ_NEW(x)
Definition: rz_types.h:285
#define RZ_NEWS0(x, y)
Definition: rz_types.h:282
#define RZ_BORROW
Definition: rz_types.h:63
#define RZ_MIN(x, y)
void(* RzVectorFree)(void *e, void *user)
Definition: rz_vector.h:42
RZ_API void * rz_vector_flush(RzVector *vec)
Turn the vector into a fixed-size array. This will clear the vector and return an array of its origin...
Definition: vector.c:230
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
static size_t rz_vector_len(const RzVector *vec)
Definition: rz_vector.h:82
RZ_API void rz_vector_init(RzVector *vec, size_t elem_size, RzVectorFree free, void *free_user)
Definition: vector.c:33
static struct sockaddr static addrlen static backlog const void static flags void flags
Definition: sfsocketcall.h:123
#define b(i)
Definition: sha256.c:42
static RzILSortPure rz_il_sort_pure_bool()
Definition: sort.h:47
@ RZ_IL_TYPE_PURE_BITVECTOR
Definition: sort.h:25
static RzILSortPure rz_il_sort_pure_bv(ut32 length)
Definition: sort.h:55
structure for bitvector
Definition: rz_bitvector.h:19
Definition: z80asm.h:102
ut32 size
number of bits of the register and variable
Definition: rz_il_reg.h:15
char * name
name of both the register and the variable that binds to it
Definition: rz_il_reg.h:14
RzILRegBindingItem * regs
regs_count registers that are bound to variables
Definition: rz_il_reg.h:24
Definition of a variable inside the vm.
Definition: variable.h:19
char * name
Definition: variable.h:20
Low-level VM to execute raw IL code.
Definition: rz_il_vm.h:37
RzRegisterType type
Register type.
Definition: rz_reg.h:119
int size
in bits> 8,16,32,64 ... 128/256
Definition: rz_reg.h:120
int offset
Offset into register profile in bits.
Definition: rz_reg.h:121
char * name
Definition: rz_reg.h:118
@ RZ_IL_VAR_KIND_GLOBAL
global var, usually bound to a physical representation like a register.
Definition: variable.h:47