Rizin
unix-like reverse engineering framework and cli tools
asm_arm_hacks.inc
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2020 phakeobj
2 // SPDX-License-Identifier: LGPL-3.0-only
3 
4 static char *hack_handle_dp_imm(ut32 insn) {
5  char *buf_asm = NULL;
6  char *mnemonic = NULL;
7  const ut8 op0 = (insn >> 23) & 0x7;
8 
9  // Add/subtract (immediate, with tags)
10  if (op0 == 3) {
11  const bool sf = (insn >> 31) & 0x1;
12  const bool op = (insn >> 30) & 0x1;
13  const bool S = (insn >> 29) & 0x1;
14  const bool o2 = (insn >> 22) & 0x1;
15  if (sf && !S && !o2) {
16  if (op) {
17  mnemonic = "subg";
18  } else {
19  mnemonic = "addg";
20  }
21  }
22  if (mnemonic) {
23  const ut8 uimm6 = ((insn >> 16) & 0x3f) << 4;
24  const ut8 uimm4 = (insn >> 10) & 0xf;
25  const ut8 Xn = (insn >> 5) & 0x1f;
26  const ut8 Xd = (insn >> 0) & 0x1f;
27  buf_asm = rz_str_newf("%s x%d, x%d, #0x%x, #0x%x",
28  mnemonic, Xd, Xn, uimm6, uimm4);
29  buf_asm = rz_str_replace(buf_asm, "x31", "sp", 1);
30  return buf_asm;
31  }
32  }
33  return NULL;
34 }
35 
36 static char *hack_handle_br_exc_sys(ut32 insn) {
37  char *buf_asm = NULL;
38  const char *mnemonic = "bti";
39  const ut8 op0 = (insn >> 29) & 0x7;
40  const ut16 op1 = (insn >> 12) & 0x3fff;
41  ut8 op2 = insn & 0x1f;
42 
43  // Hints
44  if (op0 == 6 && op1 == 4146 && op2 == 31) {
45  const ut8 CRm = (insn >> 8) & 0xf;
46  op2 = (insn >> 5) & 0x7;
47  if (CRm == 4 && (op2 & 1) == 0) {
48  switch (op2) {
49  case 0:
50  buf_asm = rz_str_newf("%s", mnemonic);
51  break;
52  case 2:
53  buf_asm = rz_str_newf("%s c", mnemonic);
54  break;
55  case 4:
56  buf_asm = rz_str_newf("%s j", mnemonic);
57  break;
58  case 6:
59  buf_asm = rz_str_newf("%s jc", mnemonic);
60  break;
61  }
62  }
63  }
64  return buf_asm;
65 }
66 
67 static char *hack_handle_dp_reg(ut32 insn) {
68  char *buf_asm = NULL;
69  char *mnemonic = NULL;
70  const bool op0 = (insn >> 30) & 0x1;
71  const bool op1 = (insn >> 28) & 0x1;
72  const ut8 op2 = (insn >> 21) & 0xf;
73 
74  // Data-processing (2 source)
75  if (!op0 && op1 && op2 == 6) {
76  const bool sf = (insn >> 31) & 0x1;
77  const bool S = (insn >> 29) & 0x1;
78  const ut8 opcode = (insn >> 10) & 0x1f;
79  if (sf) {
80  if (!S) {
81  if (opcode == 4) {
82  mnemonic = "irg";
83  } else if (opcode == 0) {
84  mnemonic = "subp";
85  } else if (opcode == 5) {
86  mnemonic = "gmi";
87  }
88  } else if (S && opcode == 0) {
89  mnemonic = "subps";
90  }
91  }
92  if (mnemonic) {
93  const ut8 Xm = (insn >> 16) & 0x1f;
94  const ut8 Xn = (insn >> 5) & 0x1f;
95  const ut8 Xd = (insn >> 0) & 0x1f;
96  if (Xm == 31 && !strcmp(mnemonic, "irg")) {
97  // Xm is xzr, discard it
98  buf_asm = rz_str_newf("%s x%d, x%d", mnemonic, Xd, Xn);
99  } else if (!strcmp(mnemonic, "subps") && S == 1 && Xd == 0x1f) {
100  // ccmp is an alias for subps when S == '1' && Xd == '11111'
101  buf_asm = rz_str_newf("cmpp x%d, x%d", Xn, Xm);
102  } else {
103  buf_asm = rz_str_newf("%s x%d, x%d, x%d", mnemonic, Xd, Xn, Xm);
104  }
105  buf_asm = rz_str_replace(buf_asm, "x31", "sp", 1);
106  return buf_asm;
107  }
108  }
109  return NULL;
110 }
111 
112 static char *hack_handle_ldst(ut32 insn) {
113  char *buf_asm = NULL;
114  char *mnemonic = NULL;
115  bool ignore_imm9 = false;
116  const ut8 op0 = (insn >> 28) & 0xf;
117  const bool op1 = (insn >> 26) & 0x1;
118  ut8 op2 = (insn >> 23) & 0x3;
119  const bool op3 = (insn >> 21) & 0x1;
120 
121  // Load/store memory tags
122  if (op0 == 13 && !op1 && (op2 == 2 || op2 == 3) && op3) {
123  const ut8 opc = (insn >> 22) & 0x3;
124  const ut16 imm9 = ((insn >> 12) & 0x1ff) << 4;
125  op2 = (insn >> 10) & 0x3;
126  const ut8 Xn = (insn >> 5) & 0x1f;
127  const ut8 Xt = (insn >> 0) & 0x1f;
128 
129  if (op2 > 0) {
130  switch (opc) {
131  case 0:
132  mnemonic = "stg";
133  break;
134  case 1:
135  mnemonic = "stzg";
136  break;
137  case 2:
138  mnemonic = "st2g";
139  break;
140  case 3:
141  mnemonic = "stz2g";
142  break;
143  }
144 
145  switch (op2) {
146  case 1:
147  buf_asm = rz_str_newf("%s x%d, [x%d], #0x%x",
148  mnemonic, Xt, Xn, imm9);
149  break;
150  case 2:
151  buf_asm = rz_str_newf("%s x%d, [x%d, #0x%x]",
152  mnemonic, Xt, Xn, imm9);
153  break;
154  case 3:
155  buf_asm = rz_str_newf("%s x%d, [x%d, #0x%x]!",
156  mnemonic, Xt, Xn, imm9);
157  break;
158  }
159  buf_asm = rz_str_replace(buf_asm, "x31", "sp", 1);
160  return buf_asm;
161  } else if (op2 == 0) {
162  switch (opc) {
163  case 0:
164  mnemonic = "stzgm";
165  ignore_imm9 = true;
166  break;
167  case 1:
168  mnemonic = "ldg";
169  break;
170  case 2:
171  mnemonic = "stgm";
172  ignore_imm9 = true;
173  break;
174  case 3:
175  mnemonic = "ldgm";
176  ignore_imm9 = true;
177  break;
178  }
179  if (ignore_imm9) {
180  buf_asm = rz_str_newf("%s x%d, [x%d]",
181  mnemonic, Xt, Xn);
182  } else {
183  buf_asm = rz_str_newf("%s x%d, [x%d, #0x%x]",
184  mnemonic, Xt, Xn, imm9);
185  }
186  buf_asm = rz_str_replace(buf_asm, "x31", "sp", 1);
187  return buf_asm;
188  }
189  // Load/store register pair
190  } else if ((op0 & 0x3) == 2) {
191  const ut8 opc = (insn >> 30) & 0x3;
192  const bool V = (insn >> 26) & 0x1;
193  const bool L = (insn >> 22) & 0x1;
194 
195  if (opc == 1 && !V && !L) {
196  const ut8 imm7 = ((insn >> 15) & 0x7f) << 4;
197  const ut8 Xt2 = (insn >> 10) & 0x1f;
198  const ut8 Xn = (insn >> 5) & 0x1f;
199  const ut8 Xt = (insn >> 0) & 0x1f;
200  switch (op2) {
201  case 1:
202  buf_asm = rz_str_newf("stgp x%d, x%d, [x%d], #0x%x",
203  Xt, Xt2, Xn, imm7);
204  break;
205  case 2:
206  buf_asm = rz_str_newf("stgp x%d, x%d, [x%d, #0x%x]",
207  Xt, Xt2, Xn, imm7);
208  break;
209  case 3:
210  buf_asm = rz_str_newf("stgp x%d, x%d, [x%d, #0x%x]!",
211  Xt, Xt2, Xn, imm7);
212  break;
213  default:
214  return NULL;
215  }
216  buf_asm = rz_str_replace(buf_asm, "x31", "sp", 1);
217  return buf_asm;
218  }
219  }
220  return NULL;
221 }
222 
223 static int hackyArmAsm(RzAsm *a, RzAsmOp *op, const ut8 *buf, int len) {
224  char *buf_asm = NULL;
225  // Hacky support for ARMv8.5
226  if (a->bits == 64 && len >= 4) {
227  ut32 insn = rz_read_ble32(buf, a->big_endian);
228  int insn_class = (insn >> 25) & 0xf;
229  switch (insn_class) {
230  // Data Processing -- Register
231  case 5:
232  case 13:
233  // irg, subp, gmi, subps
234  buf_asm = hack_handle_dp_reg(insn);
235  break;
236  // Data Processing -- Immediate
237  case 8:
238  case 9:
239  // addg, subg
240  buf_asm = hack_handle_dp_imm(insn);
241  break;
242  // Branches, Exception generating, and System instructions
243  case 10:
244  case 11:
245  // bti
246  buf_asm = hack_handle_br_exc_sys(insn);
247  break;
248  // Loads and Stores
249  case 4:
250  case 6:
251  case 12:
252  case 14:
253  // stg, stzgm, ldg, stzg, st2g, stgm, stz2g, ldgm, stgp
254  buf_asm = hack_handle_ldst(insn);
255  break;
256  default:
257  break;
258  }
259 
260  if (buf_asm) {
261  if (!a->immdisp) {
262  rz_str_replace_char(buf_asm, '#', 0);
263  }
264  rz_strbuf_set(&op->buf_asm, buf_asm);
265  free(buf_asm);
266  return op->size = 4;
267  }
268  }
269  return -1;
270 }
size_t len
Definition: 6502dis.c:15
#define NULL
Definition: cris-opc.c:27
uint16_t ut16
uint32_t ut32
static ut64 opc
Definition: desil.c:33
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
voidpf void * buf
Definition: ioapi.h:138
uint8_t ut8
Definition: lh5801.h:11
static ut32 rz_read_ble32(const void *src, bool big_endian)
Definition: rz_endian.h:497
RZ_API char * rz_str_newf(const char *fmt,...) RZ_PRINTF_CHECK(1
RZ_API char * rz_str_replace(char *str, const char *key, const char *val, int g)
Definition: str.c:1110
RZ_API int rz_str_replace_char(char *s, int a, int b)
Definition: str.c:169
RZ_API const char * rz_strbuf_set(RzStrBuf *sb, const char *s)
Definition: strbuf.c:153
#define a(i)
Definition: sha256.c:41
#define V(handle, symbol)
Definition: dis.c:32
mnemonic
Definition: z80asm.h:48
#define L
Definition: zip_err_str.c:7
#define S
Definition: zip_err_str.c:9