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