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 int written;
168 if (memory.format & ARM_MEMORY_REGISTER_BASE) {
169 if (memory.baseReg == ARM_PC && memory.format & ARM_MEMORY_IMMEDIATE_OFFSET) {
170 uint32_t addrBase = memory.format & ARM_MEMORY_OFFSET_SUBTRACT ? -memory.offset.immediate : memory.offset.immediate;
171 if (!cpu) {
172 strlcpy(buffer, "[", blen);
173 ADVANCE(1);
174 written = _decodePCRelative(addrBase, symbols, pc & 0xFFFFFFFC, false, buffer, blen);
175 ADVANCE(written);
176 } else {
177 uint32_t value;
178 addrBase += pc & 0xFFFFFFFC; // Thumb does not have PC-relative LDRH/LDRB
179 switch (memory.width & 7) {
180 case 1:
181 value = cpu->memory.load8(cpu, addrBase, NULL);
182 break;
183 case 2:
184 value = cpu->memory.load16(cpu, addrBase, NULL);
185 break;
186 case 4:
187 value = cpu->memory.load32(cpu, addrBase, NULL);
188 break;
189 }
190 const char* label = NULL;
191 if (symbols) {
192 label = mDebuggerSymbolReverseLookup(symbols, value, -1);
193 }
194 if (label) {
195 written = snprintf(buffer, blen, "=%s", label);
196 } else {
197 written = snprintf(buffer, blen, "=0x%08X", value);
198 }
199 ADVANCE(written);
200 elideClose = true;
201 }
202 } else {
203 strlcpy(buffer, "[", blen);
204 ADVANCE(1);
205 written = _decodeRegister(memory.baseReg, buffer, blen);
206 ADVANCE(written);
207 if (memory.format & (ARM_MEMORY_REGISTER_OFFSET | ARM_MEMORY_IMMEDIATE_OFFSET) && !(memory.format & ARM_MEMORY_POST_INCREMENT)) {
208 strlcpy(buffer, ", ", blen);
209 ADVANCE(2);
210 }
211 }
212 } else {
213 strlcpy(buffer, "[", blen);
214 ADVANCE(1);
215 }
216 if (memory.format & ARM_MEMORY_POST_INCREMENT) {
217 strlcpy(buffer, "], ", blen);
218 ADVANCE(3);
219 elideClose = true;
220 }
221 if (memory.format & ARM_MEMORY_IMMEDIATE_OFFSET && memory.baseReg != ARM_PC) {
222 if (memory.format & ARM_MEMORY_OFFSET_SUBTRACT) {
223 written = snprintf(buffer, blen, "#-%i", memory.offset.immediate);
224 ADVANCE(written);
225 } else {
226 written = snprintf(buffer, blen, "#%i", memory.offset.immediate);
227 ADVANCE(written);
228 }
229 } else if (memory.format & ARM_MEMORY_REGISTER_OFFSET) {
230 if (memory.format & ARM_MEMORY_OFFSET_SUBTRACT) {
231 strlcpy(buffer, "-", blen);
232 ADVANCE(1);
233 }
234 written = _decodeRegister(memory.offset.reg, buffer, blen);
235 ADVANCE(written);
236 }
237 if (memory.format & ARM_MEMORY_SHIFTED_OFFSET) {
238 written = _decodeShift(memory.offset, false, buffer, blen);
239 ADVANCE(written);
240 }
241
242 if (!elideClose) {
243 strlcpy(buffer, "]", blen);
244 ADVANCE(1);
245 }
246 if ((memory.format & (ARM_MEMORY_PRE_INCREMENT | ARM_MEMORY_WRITEBACK)) == (ARM_MEMORY_PRE_INCREMENT | ARM_MEMORY_WRITEBACK)) {
247 strlcpy(buffer, "!", blen);
248 ADVANCE(1);
249 }
250 return total;
251}
252
253static int _decodeShift(union ARMOperand op, bool reg, char* buffer, int blen) {
254 if (blen <= 1) {
255 return 0;
256 }
257 int total = 0;
258 strlcpy(buffer, ", ", blen);
259 ADVANCE(2);
260 int written;
261 switch (op.shifterOp) {
262 case ARM_SHIFT_LSL:
263 strlcpy(buffer, "lsl ", blen);
264 ADVANCE(4);
265 break;
266 case ARM_SHIFT_LSR:
267 strlcpy(buffer, "lsr ", blen);
268 ADVANCE(4);
269 break;
270 case ARM_SHIFT_ASR:
271 strlcpy(buffer, "asr ", blen);
272 ADVANCE(4);
273 break;
274 case ARM_SHIFT_ROR:
275 strlcpy(buffer, "ror ", blen);
276 ADVANCE(4);
277 break;
278 case ARM_SHIFT_RRX:
279 strlcpy(buffer, "rrx", blen);
280 ADVANCE(3);
281 return total;
282 }
283 if (!reg) {
284 written = snprintf(buffer, blen, "#%i", op.shifterImm);
285 } else {
286 written = _decodeRegister(op.shifterReg, buffer, blen);
287 }
288 ADVANCE(written);
289 return total;
290}
291
292static const char* _armMnemonicStrings[] = {
293 "ill",
294 "adc",
295 "add",
296 "and",
297 "asr",
298 "b",
299 "bic",
300 "bkpt",
301 "bl",
302 "bx",
303 "cmn",
304 "cmp",
305 "eor",
306 "ldm",
307 "ldr",
308 "lsl",
309 "lsr",
310 "mla",
311 "mov",
312 "mrs",
313 "msr",
314 "mul",
315 "mvn",
316 "neg",
317 "orr",
318 "ror",
319 "rsb",
320 "rsc",
321 "sbc",
322 "smlal",
323 "smull",
324 "stm",
325 "str",
326 "sub",
327 "swi",
328 "swp",
329 "teq",
330 "tst",
331 "umlal",
332 "umull",
333
334 "ill"
335};
336
337static const char* _armDirectionStrings[] = {
338 "da",
339 "ia",
340 "db",
341 "ib"
342};
343
344static const char* _armAccessTypeStrings[] = {
345 "",
346 "b",
347 "h",
348 "",
349 "",
350 "",
351 "",
352 "",
353
354 "",
355 "sb",
356 "sh",
357 "",
358 "",
359 "",
360 "",
361 "",
362
363 "",
364 "bt",
365 "",
366 "",
367 "t",
368 "",
369 "",
370 ""
371};
372
373int ARMDisassemble(struct ARMInstructionInfo* info, struct ARMCore* cpu, const struct mDebuggerSymbols* symbols, uint32_t pc, char* buffer, int blen) {
374 const char* mnemonic = _armMnemonicStrings[info->mnemonic];
375 int written;
376 int total = 0;
377 const char* cond = "";
378 if (info->condition != ARM_CONDITION_AL && info->condition < ARM_CONDITION_NV) {
379 cond = _armConditions[info->condition];
380 }
381 const char* flags = "";
382 switch (info->mnemonic) {
383 case ARM_MN_LDM:
384 case ARM_MN_STM:
385 flags = _armDirectionStrings[MEMORY_FORMAT_TO_DIRECTION(info->memory.format)];
386 break;
387 case ARM_MN_LDR:
388 case ARM_MN_STR:
389 case ARM_MN_SWP:
390 flags = _armAccessTypeStrings[info->memory.width];
391 break;
392 case ARM_MN_ADD:
393 case ARM_MN_ADC:
394 case ARM_MN_AND:
395 case ARM_MN_ASR:
396 case ARM_MN_BIC:
397 case ARM_MN_EOR:
398 case ARM_MN_LSL:
399 case ARM_MN_LSR:
400 case ARM_MN_MLA:
401 case ARM_MN_MOV:
402 case ARM_MN_MUL:
403 case ARM_MN_MVN:
404 case ARM_MN_ORR:
405 case ARM_MN_ROR:
406 case ARM_MN_RSB:
407 case ARM_MN_RSC:
408 case ARM_MN_SBC:
409 case ARM_MN_SMLAL:
410 case ARM_MN_SMULL:
411 case ARM_MN_SUB:
412 case ARM_MN_UMLAL:
413 case ARM_MN_UMULL:
414 if (info->affectsCPSR && info->execMode == MODE_ARM) {
415 flags = "s";
416 }
417 break;
418 default:
419 break;
420 }
421 written = snprintf(buffer, blen, "%s%s%s ", mnemonic, cond, flags);
422 ADVANCE(written);
423
424 switch (info->mnemonic) {
425 case ARM_MN_LDM:
426 case ARM_MN_STM:
427 written = _decodeRegister(info->memory.baseReg, buffer, blen);
428 ADVANCE(written);
429 if (info->memory.format & ARM_MEMORY_WRITEBACK) {
430 strlcpy(buffer, "!", blen);
431 ADVANCE(1);
432 }
433 strlcpy(buffer, ", ", blen);
434 ADVANCE(2);
435 written = _decodeRegisterList(info->op1.immediate, buffer, blen);
436 ADVANCE(written);
437 if (info->memory.format & ARM_MEMORY_SPSR_SWAP) {
438 strlcpy(buffer, "^", blen);
439 ADVANCE(1);
440 }
441 break;
442 case ARM_MN_B:
443 case ARM_MN_BL:
444 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_1) {
445 written = _decodePCRelative(info->op1.immediate, symbols, pc, true, buffer, blen);
446 ADVANCE(written);
447 }
448 break;
449 default:
450 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_1) {
451 written = snprintf(buffer, blen, "#%i", info->op1.immediate);
452 ADVANCE(written);
453 } else if (info->operandFormat & ARM_OPERAND_MEMORY_1) {
454 written = _decodeMemory(info->memory, cpu, symbols, pc, buffer, blen);
455 ADVANCE(written);
456 } else if (info->operandFormat & ARM_OPERAND_REGISTER_1) {
457 written = _decodeRegister(info->op1.reg, buffer, blen);
458 ADVANCE(written);
459 if (info->op1.reg > ARM_PC) {
460 written = _decodePSR(info->op1.psrBits, buffer, blen);
461 ADVANCE(written);
462 }
463 }
464 if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_1) {
465 written = _decodeShift(info->op1, true, buffer, blen);
466 ADVANCE(written);
467 } else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_1) {
468 written = _decodeShift(info->op1, false, buffer, blen);
469 ADVANCE(written);
470 }
471 if (info->operandFormat & ARM_OPERAND_2) {
472 strlcpy(buffer, ", ", blen);
473 ADVANCE(2);
474 }
475 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_2) {
476 written = snprintf(buffer, blen, "#%i", info->op2.immediate);
477 ADVANCE(written);
478 } else if (info->operandFormat & ARM_OPERAND_MEMORY_2) {
479 written = _decodeMemory(info->memory, cpu, symbols, pc, buffer, blen);
480 ADVANCE(written);
481 } else if (info->operandFormat & ARM_OPERAND_REGISTER_2) {
482 written = _decodeRegister(info->op2.reg, buffer, blen);
483 ADVANCE(written);
484 }
485 if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_2) {
486 written = _decodeShift(info->op2, true, buffer, blen);
487 ADVANCE(written);
488 } else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_2) {
489 written = _decodeShift(info->op2, false, buffer, blen);
490 ADVANCE(written);
491 }
492 if (info->operandFormat & ARM_OPERAND_3) {
493 strlcpy(buffer, ", ", blen);
494 ADVANCE(2);
495 }
496 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_3) {
497 written = snprintf(buffer, blen, "#%i", info->op3.immediate);
498 ADVANCE(written);
499 } else if (info->operandFormat & ARM_OPERAND_MEMORY_3) {
500 written = _decodeMemory(info->memory, cpu, symbols, pc, buffer, blen);
501 ADVANCE(written);
502 } else if (info->operandFormat & ARM_OPERAND_REGISTER_3) {
503 written = _decodeRegister(info->op3.reg, buffer, blen);
504 ADVANCE(written);
505 }
506 if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_3) {
507 written = _decodeShift(info->op3, true, buffer, blen);
508 ADVANCE(written);
509 } else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_3) {
510 written = _decodeShift(info->op3, false, buffer, blen);
511 ADVANCE(written);
512 }
513 if (info->operandFormat & ARM_OPERAND_4) {
514 strlcpy(buffer, ", ", blen);
515 ADVANCE(2);
516 }
517 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_4) {
518 written = snprintf(buffer, blen, "#%i", info->op4.immediate);
519 ADVANCE(written);
520 } else if (info->operandFormat & ARM_OPERAND_MEMORY_4) {
521 written = _decodeMemory(info->memory, cpu, symbols, pc, buffer, blen);
522 ADVANCE(written);
523 } else if (info->operandFormat & ARM_OPERAND_REGISTER_4) {
524 written = _decodeRegister(info->op4.reg, buffer, blen);
525 ADVANCE(written);
526 }
527 if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_4) {
528 written = _decodeShift(info->op4, true, buffer, blen);
529 ADVANCE(written);
530 } else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_4) {
531 written = _decodeShift(info->op4, false, buffer, blen);
532 ADVANCE(written);
533 }
534 break;
535 }
536 buffer[blen - 1] = '\0';
537 return total;
538}
539
540uint32_t ARMResolveMemoryAccess(struct ARMInstructionInfo* info, struct ARMRegisterFile* regs, uint32_t pc) {
541 uint32_t address = 0;
542 int32_t offset = 0;
543 if (info->memory.format & ARM_MEMORY_REGISTER_BASE) {
544 if (info->memory.baseReg == ARM_PC && info->memory.format & ARM_MEMORY_IMMEDIATE_OFFSET) {
545 address = pc;
546 } else {
547 address = regs->gprs[info->memory.baseReg];
548 }
549 }
550 if (info->memory.format & ARM_MEMORY_POST_INCREMENT) {
551 return address;
552 }
553 if (info->memory.format & ARM_MEMORY_IMMEDIATE_OFFSET) {
554 offset = info->memory.offset.immediate;
555 } else if (info->memory.format & ARM_MEMORY_REGISTER_OFFSET) {
556 offset = info->memory.offset.reg == ARM_PC ? pc : regs->gprs[info->memory.offset.reg];
557 }
558 if (info->memory.format & ARM_MEMORY_SHIFTED_OFFSET) {
559 uint8_t shiftSize = info->memory.offset.shifterImm;
560 switch (info->memory.offset.shifterOp) {
561 case ARM_SHIFT_LSL:
562 offset <<= shiftSize;
563 break;
564 case ARM_SHIFT_LSR:
565 offset = ((uint32_t) offset) >> shiftSize;
566 break;
567 case ARM_SHIFT_ASR:
568 offset >>= shiftSize;
569 break;
570 case ARM_SHIFT_ROR:
571 offset = ROR(offset, shiftSize);
572 break;
573 case ARM_SHIFT_RRX:
574 offset = (regs->cpsr.c << 31) | ((uint32_t) offset >> 1);
575 break;
576 default:
577 break;
578 };
579 }
580 return address + (info->memory.format & ARM_MEMORY_OFFSET_SUBTRACT ? -offset : offset);
581}