src/arm/decoder.c (view raw)
1#include "decoder.h"
2
3#include "decoder-inlines.h"
4
5#define ADVANCE(AMOUNT) \
6 if (AMOUNT > blen) { \
7 buffer[blen - 1] = '\0'; \
8 return total; \
9 } \
10 total += AMOUNT; \
11 buffer += AMOUNT; \
12 blen -= AMOUNT;
13
14static int _decodeRegister(int reg, char* buffer, int blen);
15static int _decodeRegisterList(int list, char* buffer, int blen);
16static int _decodePCRelative(uint32_t address, uint32_t pc, char* buffer, int blen);
17static int _decodeMemory(struct ARMMemoryAccess memory, int pc, char* buffer, int blen);
18static int _decodeShift(union ARMOperand operand, bool reg, char* buffer, int blen);
19
20static const char* _armConditions[] = {
21 "eq",
22 "ne",
23 "cs",
24 "cc",
25 "mi",
26 "pl",
27 "vs",
28 "vc",
29 "hi",
30 "ls",
31 "ge",
32 "lt",
33 "gt",
34 "le",
35 "al",
36 "nv"
37};
38
39static int _decodeRegister(int reg, char* buffer, int blen) {
40 switch (reg) {
41 case ARM_SP:
42 strncpy(buffer, "sp", blen - 1);
43 return 2;
44 case ARM_LR:
45 strncpy(buffer, "lr", blen - 1);
46 return 2;
47 case ARM_PC:
48 strncpy(buffer, "pc", blen - 1);
49 return 2;
50 case ARM_CPSR:
51 strncpy(buffer, "cpsr", blen - 1);
52 return 4;
53 case ARM_SPSR:
54 strncpy(buffer, "spsr", blen - 1);
55 return 4;
56 default:
57 return snprintf(buffer, blen - 1, "r%i", reg);
58 }
59}
60
61static int _decodeRegisterList(int list, char* buffer, int blen) {
62 if (blen <= 0) {
63 return 0;
64 }
65 int total = 0;
66 strncpy(buffer, "{", blen - 1);
67 ADVANCE(1);
68 int i;
69 int start = -1;
70 int end = -1;
71 int written;
72 for (i = 0; i <= ARM_PC; ++i) {
73 if (list & 1) {
74 if (start < 0) {
75 start = i;
76 end = i;
77 } else if (end + 1 == i) {
78 end = i;
79 } else {
80 if (end > start) {
81 written = _decodeRegister(start, buffer, blen);
82 ADVANCE(written);
83 strncpy(buffer, "-", blen - 1);
84 ADVANCE(1);
85 }
86 written = _decodeRegister(end, buffer, blen);
87 ADVANCE(written);
88 strncpy(buffer, ",", blen - 1);
89 ADVANCE(1);
90 start = i;
91 end = i;
92 }
93 }
94 list >>= 1;
95 }
96 if (start >= 0) {
97 if (end > start) {
98 written = _decodeRegister(start, buffer, blen);
99 ADVANCE(written);
100 strncpy(buffer, "-", blen - 1);
101 ADVANCE(1);
102 }
103 written = _decodeRegister(end, buffer, blen);
104 ADVANCE(written);
105 }
106 strncpy(buffer, "}", blen - 1);
107 ADVANCE(1);
108 return total;
109}
110
111static int _decodePCRelative(uint32_t address, uint32_t pc, char* buffer, int blen) {
112 return snprintf(buffer, blen - 1, "$%08X", address + pc);
113}
114
115static int _decodeMemory(struct ARMMemoryAccess memory, int pc, char* buffer, int blen) {
116 if (blen <= 1) {
117 return 0;
118 }
119 int total = 0;
120 strncpy(buffer, "[", blen - 1);
121 ADVANCE(1);
122 int written;
123 if (memory.format & ARM_MEMORY_REGISTER_BASE) {
124 if (memory.baseReg == ARM_PC && memory.format & ARM_MEMORY_IMMEDIATE_OFFSET) {
125 written = _decodePCRelative(memory.offset.immediate, pc, buffer, blen);
126 ADVANCE(written);
127 } else {
128 written = _decodeRegister(memory.baseReg, buffer, blen);
129 ADVANCE(written);
130 if (memory.format & (ARM_MEMORY_REGISTER_OFFSET | ARM_MEMORY_IMMEDIATE_OFFSET) && !(memory.format & ARM_MEMORY_POST_INCREMENT)) {
131 strncpy(buffer, ", ", blen - 1);
132 ADVANCE(2);
133 }
134 }
135 }
136 if (memory.format & ARM_MEMORY_POST_INCREMENT) {
137 strncpy(buffer, "], ", blen - 1);
138 ADVANCE(3);
139 }
140 if (memory.format & ARM_MEMORY_IMMEDIATE_OFFSET && memory.baseReg != ARM_PC) {
141 if (memory.format & ARM_MEMORY_OFFSET_SUBTRACT) {
142 written = snprintf(buffer, blen - 1, "#-%i", memory.offset.immediate);
143 ADVANCE(written);
144 } else {
145 written = snprintf(buffer, blen - 1, "#%i", memory.offset.immediate);
146 ADVANCE(written);
147 }
148 } else if (memory.format & ARM_MEMORY_REGISTER_OFFSET) {
149 if (memory.format & ARM_MEMORY_OFFSET_SUBTRACT) {
150 strncpy(buffer, "-", blen - 1);
151 ADVANCE(1);
152 }
153 written = _decodeRegister(memory.offset.reg, buffer, blen);
154 ADVANCE(written);
155 }
156 // TODO: shifted registers
157
158 if (!(memory.format & ARM_MEMORY_POST_INCREMENT)) {
159 strncpy(buffer, "]", blen - 1);
160 ADVANCE(1);
161 }
162 if ((memory.format & (ARM_MEMORY_PRE_INCREMENT | ARM_MEMORY_WRITEBACK)) == (ARM_MEMORY_PRE_INCREMENT | ARM_MEMORY_WRITEBACK)) {
163 strncpy(buffer, "!", blen - 1);
164 ADVANCE(1);
165 }
166 return total;
167}
168
169static int _decodeShift(union ARMOperand op, bool reg, char* buffer, int blen) {
170 if (blen <= 1) {
171 return 0;
172 }
173 int total = 0;
174 strncpy(buffer, ", ", blen - 1);
175 ADVANCE(2);
176 int written;
177 switch (op.shifterOp) {
178 case ARM_SHIFT_LSL:
179 strncpy(buffer, "lsl ", blen - 1);
180 ADVANCE(4);
181 break;
182 case ARM_SHIFT_LSR:
183 strncpy(buffer, "lsr ", blen - 1);
184 ADVANCE(4);
185 break;
186 case ARM_SHIFT_ASR:
187 strncpy(buffer, "asr ", blen - 1);
188 ADVANCE(4);
189 break;
190 case ARM_SHIFT_ROR:
191 strncpy(buffer, "ror ", blen - 1);
192 ADVANCE(4);
193 break;
194 case ARM_SHIFT_RRX:
195 strncpy(buffer, "rrx", blen - 1);
196 ADVANCE(3);
197 return total;
198 }
199 if (!reg) {
200 written = snprintf(buffer, blen - 1, "#%i", op.shifterImm);
201 } else {
202 written = _decodeRegister(op.shifterReg, buffer, blen);
203 }
204 ADVANCE(written);
205 return total;
206}
207
208static const char* _armMnemonicStrings[] = {
209 "ill",
210 "adc",
211 "add",
212 "and",
213 "asr",
214 "b",
215 "bic",
216 "bkpt",
217 "bl",
218 "blh",
219 "bx",
220 "cmn",
221 "cmp",
222 "eor",
223 "ldm",
224 "ldr",
225 "lsl",
226 "lsr",
227 "mla",
228 "mov",
229 "mrs",
230 "msr",
231 "mul",
232 "mvn",
233 "neg",
234 "orr",
235 "ror",
236 "rsb",
237 "rsc",
238 "sbc",
239 "smlal",
240 "smull",
241 "stm",
242 "str",
243 "sub",
244 "swi",
245 "swp",
246 "teq",
247 "tst",
248 "umlal",
249 "umull",
250
251 "ill"
252};
253
254static const char* _armDirectionStrings[] = {
255 "da",
256 "ia",
257 "db",
258 "ib"
259};
260
261static const char* _armAccessTypeStrings[] = {
262 "",
263 "b",
264 "h",
265 "",
266 "",
267 "",
268 "",
269 "",
270
271 "",
272 "sb",
273 "sh",
274 "",
275 "",
276 "",
277 "",
278 "",
279
280 "",
281 "bt",
282 "",
283 "",
284 "t",
285 "",
286 "",
287 ""
288};
289
290int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, int blen) {
291 const char* mnemonic = _armMnemonicStrings[info->mnemonic];
292 int written;
293 int total = 0;
294 const char* cond = "";
295 if (info->condition != ARM_CONDITION_AL && info->condition < ARM_CONDITION_NV) {
296 cond = _armConditions[info->condition];
297 }
298 const char* flags = "";
299 switch (info->mnemonic) {
300 case ARM_MN_LDM:
301 case ARM_MN_STM:
302 flags = _armDirectionStrings[MEMORY_FORMAT_TO_DIRECTION(info->memory.format)];
303 break;
304 case ARM_MN_LDR:
305 case ARM_MN_STR:
306 case ARM_MN_SWP:
307 flags = _armAccessTypeStrings[info->memory.width];
308 break;
309 case ARM_MN_ADD:
310 case ARM_MN_ADC:
311 case ARM_MN_AND:
312 case ARM_MN_BIC:
313 case ARM_MN_EOR:
314 case ARM_MN_MOV:
315 case ARM_MN_MVN:
316 case ARM_MN_ORR:
317 case ARM_MN_RSB:
318 case ARM_MN_RSC:
319 case ARM_MN_SBC:
320 case ARM_MN_SUB:
321 if (info->affectsCPSR && info->execMode == MODE_ARM) {
322 flags = "s";
323 }
324 break;
325 default:
326 break;
327 }
328 written = snprintf(buffer, blen - 1, "%s%s%s ", mnemonic, cond, flags);
329 ADVANCE(written);
330
331 switch (info->mnemonic) {
332 case ARM_MN_LDM:
333 case ARM_MN_STM:
334 written = _decodeRegister(info->memory.baseReg, buffer, blen);
335 ADVANCE(written);
336 if (info->memory.format & ARM_MEMORY_WRITEBACK) {
337 strncpy(buffer, "!", blen - 1);
338 ADVANCE(1);
339 }
340 strncpy(buffer, ", ", blen - 1);
341 ADVANCE(2);
342 written = _decodeRegisterList(info->op1.immediate, buffer, blen);
343 ADVANCE(written);
344 if (info->memory.format & ARM_MEMORY_SPSR_SWAP) {
345 strncpy(buffer, "^", blen - 1);
346 ADVANCE(1);
347 }
348 break;
349 case ARM_MN_B:
350 written = _decodePCRelative(info->op1.immediate, pc, buffer, blen);
351 ADVANCE(written);
352 break;
353 default:
354 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_1) {
355 written = snprintf(buffer, blen - 1, "#%i", info->op1.immediate);
356 ADVANCE(written);
357 } else if (info->operandFormat & ARM_OPERAND_MEMORY_1) {
358 written = _decodeMemory(info->memory, pc, buffer, blen);
359 ADVANCE(written);
360 } else if (info->operandFormat & ARM_OPERAND_REGISTER_1) {
361 written = _decodeRegister(info->op1.reg, buffer, blen);
362 ADVANCE(written);
363 }
364 if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_1) {
365 written = _decodeShift(info->op1, true, buffer, blen);
366 ADVANCE(written);
367 } else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_1) {
368 written = _decodeShift(info->op1, false, buffer, blen);
369 ADVANCE(written);
370 }
371 if (info->operandFormat & ARM_OPERAND_2) {
372 strncpy(buffer, ", ", blen);
373 ADVANCE(2);
374 }
375 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_2) {
376 written = snprintf(buffer, blen - 1, "#%i", info->op2.immediate);
377 ADVANCE(written);
378 } else if (info->operandFormat & ARM_OPERAND_MEMORY_2) {
379 written = _decodeMemory(info->memory, pc, buffer, blen);
380 ADVANCE(written);
381 } else if (info->operandFormat & ARM_OPERAND_REGISTER_2) {
382 written = _decodeRegister(info->op2.reg, buffer, blen);
383 ADVANCE(written);
384 }
385 if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_2) {
386 written = _decodeShift(info->op2, true, buffer, blen);
387 ADVANCE(written);
388 } else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_2) {
389 written = _decodeShift(info->op2, false, buffer, blen);
390 ADVANCE(written);
391 }
392 if (info->operandFormat & ARM_OPERAND_3) {
393 strncpy(buffer, ", ", blen - 1);
394 ADVANCE(2);
395 }
396 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_3) {
397 written = snprintf(buffer, blen - 1, "#%i", info->op3.immediate);
398 ADVANCE(written);
399 } else if (info->operandFormat & ARM_OPERAND_MEMORY_3) {
400 written = _decodeMemory(info->memory, pc, buffer, blen);
401 ADVANCE(written);
402 } else if (info->operandFormat & ARM_OPERAND_REGISTER_3) {
403 written = _decodeRegister(info->op3.reg, buffer, blen);
404 ADVANCE(written);
405 }
406 if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_3) {
407 written = _decodeShift(info->op3, true, buffer, blen);
408 ADVANCE(written);
409 } else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_3) {
410 written = _decodeShift(info->op3, false, buffer, blen);
411 ADVANCE(written);
412 }
413 if (info->operandFormat & ARM_OPERAND_4) {
414 strncpy(buffer, ", ", blen - 1);
415 ADVANCE(2);
416 }
417 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_4) {
418 written = snprintf(buffer, blen - 1, "#%i", info->op4.immediate);
419 ADVANCE(written);
420 } else if (info->operandFormat & ARM_OPERAND_MEMORY_4) {
421 written = _decodeMemory(info->memory, pc, buffer, blen);
422 ADVANCE(written);
423 } else if (info->operandFormat & ARM_OPERAND_REGISTER_4) {
424 written = _decodeRegister(info->op4.reg, buffer, blen);
425 ADVANCE(written);
426 }
427 if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_4) {
428 written = _decodeShift(info->op4, true, buffer, blen);
429 ADVANCE(written);
430 } else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_4) {
431 written = _decodeShift(info->op4, false, buffer, blen);
432 ADVANCE(written);
433 }
434 break;
435 }
436 buffer[blen - 1] = '\0';
437 return total;
438}