Rizin
unix-like reverse engineering framework and cli tools
arm_it.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2022 Florian Märkl <info@florianmaerkl.de>
2 // SPDX-FileCopyrightText: 2013-2018 pancake <pancake@nopcode.org>
3 // SPDX-License-Identifier: LGPL-3.0-only
4 
5 #include "arm_it.h"
6 
7 typedef union arm_cs_itblock_t {
8  ut8 off[4];
11 
12 typedef union arm_cs_itcond_t {
13  struct {
15  ut8 off;
16  };
19 
21  ctx->ht_itcond = ht_uu_new0();
22  ctx->ht_itblock = ht_uu_new0();
23 }
24 
26  ht_uu_free(ctx->ht_itblock);
27  ht_uu_free(ctx->ht_itcond);
28 }
29 
35  rz_return_if_fail(ctx && insn && insn->id == ARM_INS_IT);
36  bool found;
37  ht_uu_find(ctx->ht_itblock, insn->address, &found);
38  if (found) {
39  return;
40  }
41  ArmCSITBlock block = { 0 };
42  size_t size = rz_str_nlen(insn->mnemonic, 5);
43  for (size_t i = 1; i < size; i++) {
44  // At this point, we can't know whether each instruction in the block
45  // is 2 or 4 bytes. We build up everything for 2 bytes for now and if
46  // we later encounter a 4 byte instruction with a condition inside of it,
47  // we readjust everything accordingly.
48  ArmCSITCond cond = { 0 };
49  cond.off = block.off[i - 1] = 2 * i;
50  switch (insn->mnemonic[i]) {
51  case 0x74: //'t'
52  cond.cond = insn->detail->arm.cc;
53  break;
54  case 0x65: //'e'
55  cond.cond = (insn->detail->arm.cc % 2) ? insn->detail->arm.cc + 1 : insn->detail->arm.cc - 1;
56  break;
57  default:
58  break;
59  }
60  RZ_STATIC_ASSERT(sizeof(cond) == sizeof(cond.packed));
61  ht_uu_update(ctx->ht_itcond, insn->address + cond.off, cond.packed);
62  }
63  RZ_STATIC_ASSERT(sizeof(block) == sizeof(block.packed));
64  ht_uu_update(ctx->ht_itblock, insn->address, block.packed);
65 }
66 
71  rz_return_if_fail(ctx && insn);
72  bool found;
73  ArmCSITBlock block = { .packed = ht_uu_find(ctx->ht_itblock, insn->address, &found) };
74  if (!found) {
75  return;
76  }
77  for (size_t i = 0; i < 4 && block.off[i]; i++) {
78  ht_uu_delete(ctx->ht_itcond, insn->address + block.off[i]);
79  }
80  ht_uu_delete(ctx->ht_itblock, insn->address);
81 }
82 
88  const ut64 addr = insn->address;
89  bool found;
90  ArmCSITCond cond = { .packed = ht_uu_find(ctx->ht_itcond, addr, &found) };
91  if (!found) {
92  return false;
93  }
94  insn->detail->arm.cc = cond.cond;
95  insn->detail->arm.update_flags = 0;
96 
97  // Readjust if we detected that the previous assumption of all-2-byte instructions in
98  // analysis_itblock() was incorrect. See also the comment there.
99  if (insn->size != 4) {
100  return true;
101  }
102  cond.packed = ht_uu_find(ctx->ht_itcond, addr + 2, &found);
103  if (!found) {
104  // Everything fine, nothing to adjust
105  return true;
106  }
107  // Now readjust everything starting with the addr+2 cond
108  ut64 blockaddr = addr + 2 - cond.off;
109  ArmCSITBlock itblock = { .packed = ht_uu_find(ctx->ht_itblock, blockaddr, &found) };
110  if (!found) {
111  return true;
112  }
113  for (size_t i = 0; i < 4; i++) {
114  size_t idx = 3 - i; // Reverse loop so we don't overwrite anything by accident
115  if (!itblock.off[idx]) {
116  continue;
117  }
118  if (itblock.off[idx] < cond.off) {
119  break;
120  }
121  ArmCSITCond adjcond = { .packed = ht_uu_find(ctx->ht_itcond, blockaddr + itblock.off[idx], &found) };
122  if (!found) {
123  continue;
124  }
125  ht_uu_delete(ctx->ht_itcond, blockaddr + itblock.off[idx]);
126  adjcond.off = itblock.off[idx] += 2;
127  ht_uu_update(ctx->ht_itcond, blockaddr + itblock.off[idx], adjcond.packed);
128  }
129  ht_uu_update(ctx->ht_itblock, blockaddr, itblock.packed);
130  return true;
131 }
lzma_index ** i
Definition: index.h:629
RZ_API void rz_arm_it_context_fini(RzArmITContext *ctx)
Definition: arm_it.c:25
union arm_cs_itcond_t ArmCSITCond
union arm_cs_itblock_t ArmCSITBlock
RZ_API void rz_arm_it_context_init(RzArmITContext *ctx)
Definition: arm_it.c:20
RZ_API void rz_arm_it_update_nonblock(RzArmITContext *ctx, cs_insn *insn)
Definition: arm_it.c:70
RZ_API bool rz_arm_it_apply_cond(RzArmITContext *ctx, cs_insn *insn)
Definition: arm_it.c:87
RZ_API void rz_arm_it_update_block(RzArmITContext *ctx, cs_insn *insn)
Definition: arm_it.c:34
@ ARM_INS_IT
Definition: arm.h:857
#define RZ_API
uint32_t ut32
RZ_API const KEY_TYPE bool * found
Definition: ht_inc.h:130
voidpf void uLong size
Definition: ioapi.h:138
uint8_t ut8
Definition: lh5801.h:11
int idx
Definition: setup.py:197
#define rz_return_if_fail(expr)
Definition: rz_assert.h:100
#define RZ_STATIC_ASSERT(x)
Definition: rz_assert.h:10
RZ_API size_t rz_str_nlen(const char *s, size_t n)
Definition: str.c:1949
#define cond(bop, top, mask, flags)
ut64 packed
for putting into HtUU
Definition: arm_it.c:9
ut8 off[4]
offsets of the up to 4 conditioned instructions from the addr of the it, 0-terminated if less than 4.
Definition: arm_it.c:8
ut32 cond
arm_cc
Definition: arm_it.c:14
ut64 packed
for putting into HtUU
Definition: arm_it.c:17
ut8 off
offset of this instruction from the it, for back-referencing to the ArmCSITBlock
Definition: arm_it.c:15
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
static int addr
Definition: z80asm.c:58