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