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 <mgba/internal/arm/decoder.h>
7
8#include <mgba/internal/arm/decoder-inlines.h>
9#include <mgba/internal/debugger/symbols.h>
10#include <mgba-util/string.h>
11
12#define ADVANCE(AMOUNT) \
13 if (AMOUNT >= blen) { \
14 buffer[blen - 1] = '\0'; \
15 return total; \
16 } \
17 total += AMOUNT; \
18 buffer += AMOUNT; \
19 blen -= AMOUNT;
20
21static int _decodeRegister(int reg, char* buffer, int blen);
22static int _decodeRegisterList(int list, char* buffer, int blen);
23static int _decodePSR(int bits, char* buffer, int blen);
24static int _decodePCRelative(uint32_t address, const struct mDebuggerSymbols* symbols, uint32_t pc, bool thumbBranch, char* buffer, int blen);
25static int _decodeMemory(struct ARMMemoryAccess memory, struct ARMCore* cpu, const struct mDebuggerSymbols* symbols, int pc, char* buffer, int blen);
26static int _decodeShift(union ARMOperand operand, bool reg, char* buffer, int blen);
27
28static const char* _armConditions[] = {
29 "eq",
30 "ne",
31 "cs",
32 "cc",
33 "mi",
34 "pl",
35 "vs",
36 "vc",
37 "hi",
38 "ls",
39 "ge",
40 "lt",
41 "gt",
42 "le",
43 "al",
44 "nv"
45};
46
47static int _decodeRegister(int reg, char* buffer, int blen) {
48 switch (reg) {
49 case ARM_SP:
50 strlcpy(buffer, "sp", blen);
51 return 2;
52 case ARM_LR:
53 strlcpy(buffer, "lr", blen);
54 return 2;
55 case ARM_PC:
56 strlcpy(buffer, "pc", blen);
57 return 2;
58 case ARM_CPSR:
59 strlcpy(buffer, "cpsr", blen);
60 return 4;
61 case ARM_SPSR:
62 strlcpy(buffer, "spsr", blen);
63 return 4;
64 default:
65 return snprintf(buffer, blen, "r%i", reg);
66 }
67}
68
69static int _decodeRegisterList(int list, char* buffer, int blen) {
70 if (blen <= 0) {
71 return 0;
72 }
73 int total = 0;
74 strlcpy(buffer, "{", blen);
75 ADVANCE(1);
76 int i;
77 int start = -1;
78 int end = -1;
79 int written;
80 for (i = 0; i <= ARM_PC; ++i) {
81 if (list & 1) {
82 if (start < 0) {
83 start = i;
84 end = i;
85 } else if (end + 1 == i) {
86 end = i;
87 } else {
88 if (end > start) {
89 written = _decodeRegister(start, buffer, blen);
90 ADVANCE(written);
91 strlcpy(buffer, "-", blen);
92 ADVANCE(1);
93 }
94 written = _decodeRegister(end, buffer, blen);
95 ADVANCE(written);
96 strlcpy(buffer, ",", blen);
97 ADVANCE(1);
98 start = i;
99 end = i;
100 }
101 }
102 list >>= 1;
103 }
104 if (start >= 0) {
105 if (end > start) {
106 written = _decodeRegister(start, buffer, blen);
107 ADVANCE(written);
108 strlcpy(buffer, "-", blen);
109 ADVANCE(1);
110 }
111 written = _decodeRegister(end, buffer, blen);
112 ADVANCE(written);
113 }
114 strlcpy(buffer, "}", blen);
115 ADVANCE(1);
116 return total;
117}
118
119static int _decodePSR(int psrBits, char* buffer, int blen) {
120 if (!psrBits) {
121 return 0;
122 }
123 int total = 0;
124 strlcpy(buffer, "_", blen);
125 ADVANCE(1);
126 if (psrBits & ARM_PSR_C) {
127 strlcpy(buffer, "c", blen);
128 ADVANCE(1);
129 }
130 if (psrBits & ARM_PSR_X) {
131 strlcpy(buffer, "x", blen);
132 ADVANCE(1);
133 }
134 if (psrBits & ARM_PSR_S) {
135 strlcpy(buffer, "s", blen);
136 ADVANCE(1);
137 }
138 if (psrBits & ARM_PSR_F) {
139 strlcpy(buffer, "f", blen);
140 ADVANCE(1);
141 }
142 return total;
143}
144
145static int _decodePCRelative(uint32_t address, const struct mDebuggerSymbols* symbols, uint32_t pc, bool thumbBranch, char* buffer, int blen) {
146 address += pc;
147 const char* label = NULL;
148 if (symbols) {
149 label = mDebuggerSymbolReverseLookup(symbols, address, -1);
150 if (!label && thumbBranch) {
151 label = mDebuggerSymbolReverseLookup(symbols, address | 1, -1);
152 }
153 }
154 if (label) {
155 return strlcpy(buffer, label, blen);
156 } else {
157 return snprintf(buffer, blen, "0x%08X", address);
158 }
159}
160
161static int _decodeMemory(struct ARMMemoryAccess memory, struct ARMCore* cpu, const struct mDebuggerSymbols* symbols, int pc, char* buffer, int blen) {
162 if (blen <= 1) {
163 return 0;
164 }
165 int total = 0;
166 bool elideClose = false;
167 char comment[64];
168 int written;
169 comment[0] = '\0';
170 if (memory.format & ARM_MEMORY_REGISTER_BASE) {
171 if (memory.baseReg == ARM_PC && memory.format & ARM_MEMORY_IMMEDIATE_OFFSET) {
172 uint32_t addrBase = memory.format & ARM_MEMORY_OFFSET_SUBTRACT ? -memory.offset.immediate : memory.offset.immediate;
173 if (!cpu || memory.format & ARM_MEMORY_STORE) {
174 strlcpy(buffer, "[", blen);
175 ADVANCE(1);
176 written = _decodePCRelative(addrBase, symbols, pc & 0xFFFFFFFC, false, buffer, blen);
177 ADVANCE(written);
178 } else {
179 uint32_t value;
180 _decodePCRelative(addrBase, symbols, pc & 0xFFFFFFFC, false, comment, sizeof(comment));
181 addrBase += pc & 0xFFFFFFFC; // Thumb does not have PC-relative LDRH/LDRB
182 switch (memory.width & 7) {
183 case 1:
184 value = cpu->memory.load8(cpu, addrBase, NULL);
185 break;
186 case 2:
187 value = cpu->memory.load16(cpu, addrBase, NULL);
188 break;
189 case 4:
190 value = cpu->memory.load32(cpu, addrBase, NULL);
191 break;
192 }
193 const char* label = NULL;
194 if (symbols) {
195 label = mDebuggerSymbolReverseLookup(symbols, value, -1);
196 }
197 if (label) {
198 written = snprintf(buffer, blen, "=%s", label);
199 } else {
200 written = snprintf(buffer, blen, "=0x%08X", value);
201 }
202 ADVANCE(written);
203 elideClose = true;
204 }
205 } else {
206 strlcpy(buffer, "[", blen);
207 ADVANCE(1);
208 written = _decodeRegister(memory.baseReg, buffer, blen);
209 ADVANCE(written);
210 if (memory.format & (ARM_MEMORY_REGISTER_OFFSET | ARM_MEMORY_IMMEDIATE_OFFSET) && !(memory.format & ARM_MEMORY_POST_INCREMENT)) {
211 strlcpy(buffer, ", ", blen);
212 ADVANCE(2);
213 }
214 }
215 } else {
216 strlcpy(buffer, "[", blen);
217 ADVANCE(1);
218 }
219 if (memory.format & ARM_MEMORY_POST_INCREMENT) {
220 strlcpy(buffer, "], ", blen);
221 ADVANCE(3);
222 elideClose = true;
223 }
224 if (memory.format & ARM_MEMORY_IMMEDIATE_OFFSET && memory.baseReg != ARM_PC) {
225 if (memory.format & ARM_MEMORY_OFFSET_SUBTRACT) {
226 written = snprintf(buffer, blen, "#-%i", memory.offset.immediate);
227 ADVANCE(written);
228 } else {
229 written = snprintf(buffer, blen, "#%i", memory.offset.immediate);
230 ADVANCE(written);
231 }
232 } else if (memory.format & ARM_MEMORY_REGISTER_OFFSET) {
233 if (memory.format & ARM_MEMORY_OFFSET_SUBTRACT) {
234 strlcpy(buffer, "-", blen);
235 ADVANCE(1);
236 }
237 written = _decodeRegister(memory.offset.reg, buffer, blen);
238 ADVANCE(written);
239 }
240 if (memory.format & ARM_MEMORY_SHIFTED_OFFSET) {
241 written = _decodeShift(memory.offset, false, buffer, blen);
242 ADVANCE(written);
243 }
244
245 if (!elideClose) {
246 strlcpy(buffer, "]", blen);
247 ADVANCE(1);
248 }
249 if ((memory.format & (ARM_MEMORY_PRE_INCREMENT | ARM_MEMORY_WRITEBACK)) == (ARM_MEMORY_PRE_INCREMENT | ARM_MEMORY_WRITEBACK)) {
250 strlcpy(buffer, "!", blen);
251 ADVANCE(1);
252 }
253 if (comment[0]) {
254 written = snprintf(buffer, blen, " @ %s", comment);
255 ADVANCE(written);
256 }
257 return total;
258}
259
260static int _decodeShift(union ARMOperand op, bool reg, char* buffer, int blen) {
261 if (blen <= 1) {
262 return 0;
263 }
264 int total = 0;
265 strlcpy(buffer, ", ", blen);
266 ADVANCE(2);
267 int written;
268 switch (op.shifterOp) {
269 case ARM_SHIFT_LSL:
270 strlcpy(buffer, "lsl ", blen);
271 ADVANCE(4);
272 break;
273 case ARM_SHIFT_LSR:
274 strlcpy(buffer, "lsr ", blen);
275 ADVANCE(4);
276 break;
277 case ARM_SHIFT_ASR:
278 strlcpy(buffer, "asr ", blen);
279 ADVANCE(4);
280 break;
281 case ARM_SHIFT_ROR:
282 strlcpy(buffer, "ror ", blen);
283 ADVANCE(4);
284 break;
285 case ARM_SHIFT_RRX:
286 strlcpy(buffer, "rrx", blen);
287 ADVANCE(3);
288 return total;
289 }
290 if (!reg) {
291 written = snprintf(buffer, blen, "#%i", op.shifterImm);
292 } else {
293 written = _decodeRegister(op.shifterReg, buffer, blen);
294 }
295 ADVANCE(written);
296 return total;
297}
298
299static const char* _armMnemonicStrings[] = {
300 "ill",
301 "adc",
302 "add",
303 "and",
304 "asr",
305 "b",
306 "bic",
307 "bkpt",
308 "bl",
309 "bx",
310 "cmn",
311 "cmp",
312 "eor",
313 "ldm",
314 "ldr",
315 "lsl",
316 "lsr",
317 "mla",
318 "mov",
319 "mrs",
320 "msr",
321 "mul",
322 "mvn",
323 "neg",
324 "orr",
325 "ror",
326 "rsb",
327 "rsc",
328 "sbc",
329 "smlal",
330 "smull",
331 "stm",
332 "str",
333 "sub",
334 "swi",
335 "swp",
336 "teq",
337 "tst",
338 "umlal",
339 "umull",
340
341 "ill"
342};
343
344static const char* _armDirectionStrings[] = {
345 "da",
346 "ia",
347 "db",
348 "ib"
349};
350
351static const char* _armAccessTypeStrings[] = {
352 "",
353 "b",
354 "h",
355 "",
356 "",
357 "",
358 "",
359 "",
360
361 "",
362 "sb",
363 "sh",
364 "",
365 "",
366 "",
367 "",
368 "",
369
370 "",
371 "bt",
372 "",
373 "",
374 "t",
375 "",
376 "",
377 ""
378};
379
380int ARMDisassemble(struct ARMInstructionInfo* info, struct ARMCore* cpu, const struct mDebuggerSymbols* symbols, uint32_t pc, char* buffer, int blen) {
381 const char* mnemonic = _armMnemonicStrings[info->mnemonic];
382 int written;
383 int total = 0;
384 const char* cond = "";
385 if (info->condition != ARM_CONDITION_AL && info->condition < ARM_CONDITION_NV) {
386 cond = _armConditions[info->condition];
387 }
388 const char* flags = "";
389 switch (info->mnemonic) {
390 case ARM_MN_LDM:
391 case ARM_MN_STM:
392 flags = _armDirectionStrings[MEMORY_FORMAT_TO_DIRECTION(info->memory.format)];
393 break;
394 case ARM_MN_LDR:
395 case ARM_MN_STR:
396 case ARM_MN_SWP:
397 flags = _armAccessTypeStrings[info->memory.width];
398 break;
399 case ARM_MN_ADD:
400 case ARM_MN_ADC:
401 case ARM_MN_AND:
402 case ARM_MN_ASR:
403 case ARM_MN_BIC:
404 case ARM_MN_EOR:
405 case ARM_MN_LSL:
406 case ARM_MN_LSR:
407 case ARM_MN_MLA:
408 case ARM_MN_MOV:
409 case ARM_MN_MUL:
410 case ARM_MN_MVN:
411 case ARM_MN_ORR:
412 case ARM_MN_ROR:
413 case ARM_MN_RSB:
414 case ARM_MN_RSC:
415 case ARM_MN_SBC:
416 case ARM_MN_SMLAL:
417 case ARM_MN_SMULL:
418 case ARM_MN_SUB:
419 case ARM_MN_UMLAL:
420 case ARM_MN_UMULL:
421 if (info->affectsCPSR && info->execMode == MODE_ARM) {
422 flags = "s";
423 }
424 break;
425 default:
426 break;
427 }
428 written = snprintf(buffer, blen, "%s%s%s ", mnemonic, cond, flags);
429 ADVANCE(written);
430
431 switch (info->mnemonic) {
432 case ARM_MN_LDM:
433 case ARM_MN_STM:
434 written = _decodeRegister(info->memory.baseReg, buffer, blen);
435 ADVANCE(written);
436 if (info->memory.format & ARM_MEMORY_WRITEBACK) {
437 strlcpy(buffer, "!", blen);
438 ADVANCE(1);
439 }
440 strlcpy(buffer, ", ", blen);
441 ADVANCE(2);
442 written = _decodeRegisterList(info->op1.immediate, buffer, blen);
443 ADVANCE(written);
444 if (info->memory.format & ARM_MEMORY_SPSR_SWAP) {
445 strlcpy(buffer, "^", blen);
446 ADVANCE(1);
447 }
448 break;
449 case ARM_MN_B:
450 case ARM_MN_BL:
451 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_1) {
452 written = _decodePCRelative(info->op1.immediate, symbols, pc, true, buffer, blen);
453 ADVANCE(written);
454 }
455 break;
456 default:
457 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_1) {
458 written = snprintf(buffer, blen, "#%i", info->op1.immediate);
459 ADVANCE(written);
460 } else if (info->operandFormat & ARM_OPERAND_MEMORY_1) {
461 written = _decodeMemory(info->memory, cpu, symbols, pc, buffer, blen);
462 ADVANCE(written);
463 } else if (info->operandFormat & ARM_OPERAND_REGISTER_1) {
464 written = _decodeRegister(info->op1.reg, buffer, blen);
465 ADVANCE(written);
466 if (info->op1.reg > ARM_PC) {
467 written = _decodePSR(info->op1.psrBits, buffer, blen);
468 ADVANCE(written);
469 }
470 }
471 if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_1) {
472 written = _decodeShift(info->op1, true, buffer, blen);
473 ADVANCE(written);
474 } else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_1) {
475 written = _decodeShift(info->op1, false, buffer, blen);
476 ADVANCE(written);
477 }
478 if (info->operandFormat & ARM_OPERAND_2) {
479 strlcpy(buffer, ", ", blen);
480 ADVANCE(2);
481 }
482 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_2) {
483 written = snprintf(buffer, blen, "#%i", info->op2.immediate);
484 ADVANCE(written);
485 } else if (info->operandFormat & ARM_OPERAND_MEMORY_2) {
486 written = _decodeMemory(info->memory, cpu, symbols, pc, buffer, blen);
487 ADVANCE(written);
488 } else if (info->operandFormat & ARM_OPERAND_REGISTER_2) {
489 written = _decodeRegister(info->op2.reg, buffer, blen);
490 ADVANCE(written);
491 }
492 if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_2) {
493 written = _decodeShift(info->op2, true, buffer, blen);
494 ADVANCE(written);
495 } else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_2) {
496 written = _decodeShift(info->op2, false, buffer, blen);
497 ADVANCE(written);
498 }
499 if (info->operandFormat & ARM_OPERAND_3) {
500 strlcpy(buffer, ", ", blen);
501 ADVANCE(2);
502 }
503 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_3) {
504 written = snprintf(buffer, blen, "#%i", info->op3.immediate);
505 ADVANCE(written);
506 } else if (info->operandFormat & ARM_OPERAND_MEMORY_3) {
507 written = _decodeMemory(info->memory, cpu, symbols, pc, buffer, blen);
508 ADVANCE(written);
509 } else if (info->operandFormat & ARM_OPERAND_REGISTER_3) {
510 written = _decodeRegister(info->op3.reg, buffer, blen);
511 ADVANCE(written);
512 }
513 if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_3) {
514 written = _decodeShift(info->op3, true, buffer, blen);
515 ADVANCE(written);
516 } else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_3) {
517 written = _decodeShift(info->op3, false, buffer, blen);
518 ADVANCE(written);
519 }
520 if (info->operandFormat & ARM_OPERAND_4) {
521 strlcpy(buffer, ", ", blen);
522 ADVANCE(2);
523 }
524 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_4) {
525 written = snprintf(buffer, blen, "#%i", info->op4.immediate);
526 ADVANCE(written);
527 } else if (info->operandFormat & ARM_OPERAND_MEMORY_4) {
528 written = _decodeMemory(info->memory, cpu, symbols, pc, buffer, blen);
529 ADVANCE(written);
530 } else if (info->operandFormat & ARM_OPERAND_REGISTER_4) {
531 written = _decodeRegister(info->op4.reg, buffer, blen);
532 ADVANCE(written);
533 }
534 if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_4) {
535 written = _decodeShift(info->op4, true, buffer, blen);
536 ADVANCE(written);
537 } else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_4) {
538 written = _decodeShift(info->op4, false, buffer, blen);
539 ADVANCE(written);
540 }
541 break;
542 }
543 buffer[blen - 1] = '\0';
544 return total;
545}
546
547uint32_t ARMResolveMemoryAccess(struct ARMInstructionInfo* info, struct ARMRegisterFile* regs, uint32_t pc) {
548 uint32_t address = 0;
549 int32_t offset = 0;
550 if (info->memory.format & ARM_MEMORY_REGISTER_BASE) {
551 if (info->memory.baseReg == ARM_PC && info->memory.format & ARM_MEMORY_IMMEDIATE_OFFSET) {
552 address = pc;
553 } else {
554 address = regs->gprs[info->memory.baseReg];
555 }
556 }
557 if (info->memory.format & ARM_MEMORY_POST_INCREMENT) {
558 return address;
559 }
560 if (info->memory.format & ARM_MEMORY_IMMEDIATE_OFFSET) {
561 offset = info->memory.offset.immediate;
562 } else if (info->memory.format & ARM_MEMORY_REGISTER_OFFSET) {
563 offset = info->memory.offset.reg == ARM_PC ? pc : regs->gprs[info->memory.offset.reg];
564 }
565 if (info->memory.format & ARM_MEMORY_SHIFTED_OFFSET) {
566 uint8_t shiftSize = info->memory.offset.shifterImm;
567 switch (info->memory.offset.shifterOp) {
568 case ARM_SHIFT_LSL:
569 offset <<= shiftSize;
570 break;
571 case ARM_SHIFT_LSR:
572 offset = ((uint32_t) offset) >> shiftSize;
573 break;
574 case ARM_SHIFT_ASR:
575 offset >>= shiftSize;
576 break;
577 case ARM_SHIFT_ROR:
578 offset = ROR(offset, shiftSize);
579 break;
580 case ARM_SHIFT_RRX:
581 offset = (regs->cpsr.c << 31) | ((uint32_t) offset >> 1);
582 break;
583 default:
584 break;
585 };
586 }
587 return address + (info->memory.format & ARM_MEMORY_OFFSET_SUBTRACT ? -offset : offset);
588}