all repos — mgba @ dec8a1223c5199c632b89d659dfc28e7f2bee8fb

mGBA Game Boy Advance Emulator

src/arm/debugger/cli-debugger.c (view raw)

  1/* Copyright (c) 2013-2016 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 "cli-debugger.h"
  7
  8#ifdef USE_CLI_DEBUGGER
  9#include "arm/debugger/debugger.h"
 10#include "arm/debugger/memory-debugger.h"
 11#include "arm/decoder.h"
 12#include "core/core.h"
 13#include "debugger/cli-debugger.h"
 14
 15static void _printStatus(struct CLIDebuggerSystem*);
 16
 17static void _disassembleArm(struct CLIDebugger*, struct CLIDebugVector*);
 18static void _disassembleThumb(struct CLIDebugger*, struct CLIDebugVector*);
 19static void _setBreakpointARM(struct CLIDebugger*, struct CLIDebugVector*);
 20static void _setBreakpointThumb(struct CLIDebugger*, struct CLIDebugVector*);
 21static void _writeRegister(struct CLIDebugger*, struct CLIDebugVector*);
 22
 23static void _disassembleMode(struct CLIDebugger*, struct CLIDebugVector*, enum ExecutionMode mode);
 24static uint32_t _printLine(struct CLIDebugger* debugger, uint32_t address, enum ExecutionMode mode);
 25
 26static struct CLIDebuggerCommandSummary _armCommands[] = {
 27	{ "b/a", _setBreakpointARM, CLIDVParse, "Set a software breakpoint as ARM" },
 28	{ "b/t", _setBreakpointThumb, CLIDVParse, "Set a software breakpoint as Thumb" },
 29	{ "break/a", _setBreakpointARM, CLIDVParse, "Set a software breakpoint as ARM" },
 30	{ "break/t", _setBreakpointThumb, CLIDVParse, "Set a software breakpoint as Thumb" },
 31	{ "dis/a", _disassembleArm, CLIDVParse, "Disassemble instructions as ARM" },
 32	{ "dis/t", _disassembleThumb, CLIDVParse, "Disassemble instructions as Thumb" },
 33	{ "disasm/a", _disassembleArm, CLIDVParse, "Disassemble instructions as ARM" },
 34	{ "disasm/t", _disassembleThumb, CLIDVParse, "Disassemble instructions as Thumb" },
 35	{ "disassemble/a", _disassembleArm, CLIDVParse, "Disassemble instructions as ARM" },
 36	{ "disassemble/t", _disassembleThumb, CLIDVParse, "Disassemble instructions as Thumb" },
 37	{ "w/r", _writeRegister, CLIDVParse, "Write a register" },
 38	{ 0, 0, 0, 0 }
 39};
 40
 41static inline void _printPSR(union PSR psr) {
 42	printf("%08X [%c%c%c%c%c%c%c]\n", psr.packed,
 43	       psr.n ? 'N' : '-',
 44	       psr.z ? 'Z' : '-',
 45	       psr.c ? 'C' : '-',
 46	       psr.v ? 'V' : '-',
 47	       psr.i ? 'I' : '-',
 48	       psr.f ? 'F' : '-',
 49	       psr.t ? 'T' : '-');
 50}
 51
 52static void _disassemble(struct CLIDebuggerSystem* debugger, struct CLIDebugVector* dv) {
 53	struct ARMCore* cpu = debugger->p->d.core->cpu;
 54	_disassembleMode(debugger->p, dv, cpu->executionMode);
 55}
 56
 57static void _disassembleArm(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
 58	_disassembleMode(debugger, dv, MODE_ARM);
 59}
 60
 61static void _disassembleThumb(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
 62	_disassembleMode(debugger, dv, MODE_THUMB);
 63}
 64
 65static void _disassembleMode(struct CLIDebugger* debugger, struct CLIDebugVector* dv, enum ExecutionMode mode) {
 66	struct ARMCore* cpu = debugger->d.core->cpu;
 67	uint32_t address;
 68	int size;
 69	int wordSize;
 70
 71	if (mode == MODE_ARM) {
 72		wordSize = WORD_SIZE_ARM;
 73	} else {
 74		wordSize = WORD_SIZE_THUMB;
 75	}
 76
 77	if (!dv || dv->type != CLIDV_INT_TYPE) {
 78		address = cpu->gprs[ARM_PC] - wordSize;
 79	} else {
 80		address = dv->intValue;
 81		dv = dv->next;
 82	}
 83
 84	if (!dv || dv->type != CLIDV_INT_TYPE) {
 85		size = 1;
 86	} else {
 87		size = dv->intValue;
 88		dv = dv->next; // TODO: Check for excess args
 89	}
 90
 91	int i;
 92	for (i = 0; i < size; ++i) {
 93		address += _printLine(debugger, address, mode);
 94	}
 95}
 96
 97static inline uint32_t _printLine(struct CLIDebugger* debugger, uint32_t address, enum ExecutionMode mode) {
 98	char disassembly[48];
 99	struct ARMInstructionInfo info;
100	printf("%08X:  ", address);
101	if (mode == MODE_ARM) {
102		uint32_t instruction = debugger->d.core->busRead32(debugger->d.core, address);
103		ARMDecodeARM(instruction, &info);
104		ARMDisassemble(&info, address + WORD_SIZE_ARM * 2, disassembly, sizeof(disassembly));
105		printf("%08X\t%s\n", instruction, disassembly);
106		return WORD_SIZE_ARM;
107	} else {
108		struct ARMInstructionInfo info2;
109		struct ARMInstructionInfo combined;
110		uint16_t instruction = debugger->d.core->busRead16(debugger->d.core, address);
111		uint16_t instruction2 = debugger->d.core->busRead16(debugger->d.core, address + WORD_SIZE_THUMB);
112		ARMDecodeThumb(instruction, &info);
113		ARMDecodeThumb(instruction2, &info2);
114		if (ARMDecodeThumbCombine(&info, &info2, &combined)) {
115			ARMDisassemble(&combined, address + WORD_SIZE_THUMB * 2, disassembly, sizeof(disassembly));
116			printf("%04X %04X\t%s\n", instruction, instruction2, disassembly);
117			return WORD_SIZE_THUMB * 2;
118		} else {
119			ARMDisassemble(&info, address + WORD_SIZE_THUMB * 2, disassembly, sizeof(disassembly));
120			printf("%04X     \t%s\n", instruction, disassembly);
121			return WORD_SIZE_THUMB;
122		}
123	}
124}
125
126static void _printStatus(struct CLIDebuggerSystem* debugger) {
127	struct ARMCore* cpu = debugger->p->d.core->cpu;
128	int r;
129	for (r = 0; r < 4; ++r) {
130		printf("%08X %08X %08X %08X\n",
131		    cpu->gprs[r << 2],
132		    cpu->gprs[(r << 2) + 1],
133		    cpu->gprs[(r << 2) + 2],
134		    cpu->gprs[(r << 2) + 3]);
135	}
136	_printPSR(cpu->cpsr);
137	int instructionLength;
138	enum ExecutionMode mode = cpu->cpsr.t;
139	if (mode == MODE_ARM) {
140		instructionLength = WORD_SIZE_ARM;
141	} else {
142		instructionLength = WORD_SIZE_THUMB;
143	}
144	_printLine(debugger->p, cpu->gprs[ARM_PC] - instructionLength, mode);
145}
146
147static void _writeRegister(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
148	struct ARMCore* cpu = debugger->d.core->cpu;
149	if (!dv || dv->type != CLIDV_INT_TYPE) {
150		printf("%s\n", ERROR_MISSING_ARGS);
151		return;
152	}
153	if (!dv->next || dv->next->type != CLIDV_INT_TYPE) {
154		printf("%s\n", ERROR_MISSING_ARGS);
155		return;
156	}
157	uint32_t regid = dv->intValue;
158	uint32_t value = dv->next->intValue;
159	if (regid >= ARM_PC) {
160		return;
161	}
162	cpu->gprs[regid] = value;
163}
164
165static void _setBreakpointARM(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
166	if (!dv || dv->type != CLIDV_INT_TYPE) {
167		printf("%s\n", ERROR_MISSING_ARGS);
168		return;
169	}
170	uint32_t address = dv->intValue;
171	ARMDebuggerSetSoftwareBreakpoint(debugger->d.platform, address, MODE_ARM);
172}
173
174static void _setBreakpointThumb(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
175	if (!dv || dv->type != CLIDV_INT_TYPE) {
176		printf("%s\n", ERROR_MISSING_ARGS);
177		return;
178	}
179	uint32_t address = dv->intValue;
180	ARMDebuggerSetSoftwareBreakpoint(debugger->d.platform, address, MODE_THUMB);
181}
182
183static uint32_t _lookupPlatformIdentifier(struct CLIDebuggerSystem* debugger, const char* name, struct CLIDebugVector* dv) {
184	struct ARMCore* cpu = debugger->p->d.core->cpu;
185	if (strcmp(name, "sp") == 0) {
186		return cpu->gprs[ARM_SP];
187	}
188	if (strcmp(name, "lr") == 0) {
189		return cpu->gprs[ARM_LR];
190	}
191	if (strcmp(name, "pc") == 0) {
192		return cpu->gprs[ARM_PC];
193	}
194	if (strcmp(name, "cpsr") == 0) {
195		return cpu->cpsr.packed;
196	}
197	// TODO: test if mode has SPSR
198	if (strcmp(name, "spsr") == 0) {
199		return cpu->spsr.packed;
200	}
201	if (name[0] == 'r' && name[1] >= '0' && name[1] <= '9') {
202		int reg = atoi(&name[1]);
203		if (reg < 16) {
204			return cpu->gprs[reg];
205		}
206	}
207	dv->type = CLIDV_ERROR_TYPE;
208	return 0;
209}
210
211void ARMCLIDebuggerCreate(struct CLIDebuggerSystem* debugger) {
212	debugger->printStatus = _printStatus;
213	debugger->disassemble = _disassemble;
214	debugger->lookupPlatformIdentifier = _lookupPlatformIdentifier;
215	debugger->platformName = "ARM";
216	debugger->platformCommands = _armCommands;
217}
218
219#endif