all repos — mgba @ ee3969ad020e4f13459bc55214f36455b6bc0e01

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 <mgba/internal/arm/debugger/cli-debugger.h>
  7
  8#include <mgba/core/core.h>
  9#include <mgba/internal/arm/debugger/debugger.h>
 10#include <mgba/internal/arm/debugger/memory-debugger.h>
 11#include <mgba/internal/arm/decoder.h>
 12#include <mgba/internal/debugger/cli-debugger.h>
 13
 14static void _printStatus(struct CLIDebuggerSystem*);
 15
 16static void _disassembleArm(struct CLIDebugger*, struct CLIDebugVector*);
 17static void _disassembleThumb(struct CLIDebugger*, struct CLIDebugVector*);
 18static void _setBreakpointARM(struct CLIDebugger*, struct CLIDebugVector*);
 19static void _setBreakpointThumb(struct CLIDebugger*, struct CLIDebugVector*);
 20
 21static void _disassembleMode(struct CLIDebugger*, struct CLIDebugVector*, enum ExecutionMode mode);
 22static uint32_t _printLine(struct CLIDebugger* debugger, uint32_t address, enum ExecutionMode mode);
 23
 24static struct CLIDebuggerCommandSummary _armCommands[] = {
 25	{ "b/a", _setBreakpointARM, "I", "Set a software breakpoint as ARM" },
 26	{ "b/t", _setBreakpointThumb, "I", "Set a software breakpoint as Thumb" },
 27	{ "break/a", _setBreakpointARM, "I", "Set a software breakpoint as ARM" },
 28	{ "break/t", _setBreakpointThumb, "I", "Set a software breakpoint as Thumb" },
 29	{ "dis/a", _disassembleArm, "Ii", "Disassemble instructions as ARM" },
 30	{ "dis/t", _disassembleThumb, "Ii", "Disassemble instructions as Thumb" },
 31	{ "disasm/a", _disassembleArm, "Ii", "Disassemble instructions as ARM" },
 32	{ "disasm/t", _disassembleThumb, "Ii", "Disassemble instructions as Thumb" },
 33	{ "disassemble/a", _disassembleArm, "Ii", "Disassemble instructions as ARM" },
 34	{ "disassemble/t", _disassembleThumb, "Ii", "Disassemble instructions as Thumb" },
 35	{ 0, 0, 0, 0 }
 36};
 37
 38static inline void _printPSR(struct CLIDebuggerBackend* be, union PSR psr) {
 39	be->printf(be, "%08X [%c%c%c%c%c%c%c]\n", psr.packed,
 40	           psr.n ? 'N' : '-',
 41	           psr.z ? 'Z' : '-',
 42	           psr.c ? 'C' : '-',
 43	           psr.v ? 'V' : '-',
 44	           psr.i ? 'I' : '-',
 45	           psr.f ? 'F' : '-',
 46	           psr.t ? 'T' : '-');
 47}
 48
 49static void _disassemble(struct CLIDebuggerSystem* debugger, struct CLIDebugVector* dv) {
 50	struct ARMCore* cpu = debugger->p->d.core->cpu;
 51	_disassembleMode(debugger->p, dv, cpu->executionMode);
 52}
 53
 54static void _disassembleArm(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
 55	_disassembleMode(debugger, dv, MODE_ARM);
 56}
 57
 58static void _disassembleThumb(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
 59	_disassembleMode(debugger, dv, MODE_THUMB);
 60}
 61
 62static void _disassembleMode(struct CLIDebugger* debugger, struct CLIDebugVector* dv, enum ExecutionMode mode) {
 63	struct ARMCore* cpu = debugger->d.core->cpu;
 64	uint32_t address;
 65	int size;
 66	int wordSize;
 67
 68	if (mode == MODE_ARM) {
 69		wordSize = WORD_SIZE_ARM;
 70	} else {
 71		wordSize = WORD_SIZE_THUMB;
 72	}
 73
 74	if (!dv || dv->type != CLIDV_INT_TYPE) {
 75		address = cpu->gprs[ARM_PC] - wordSize;
 76	} else {
 77		address = dv->intValue;
 78		dv = dv->next;
 79	}
 80
 81	if (!dv || dv->type != CLIDV_INT_TYPE) {
 82		size = 1;
 83	} else {
 84		size = dv->intValue;
 85		dv = dv->next; // TODO: Check for excess args
 86	}
 87
 88	int i;
 89	for (i = 0; i < size; ++i) {
 90		address += _printLine(debugger, address, mode);
 91	}
 92}
 93
 94static inline uint32_t _printLine(struct CLIDebugger* debugger, uint32_t address, enum ExecutionMode mode) {
 95	struct CLIDebuggerBackend* be = debugger->backend;
 96	char disassembly[64];
 97	struct ARMInstructionInfo info;
 98	be->printf(be, "%08X:  ", address);
 99	if (mode == MODE_ARM) {
100		uint32_t instruction = debugger->d.core->busRead32(debugger->d.core, address);
101		ARMDecodeARM(instruction, &info);
102		ARMDisassemble(&info, address + WORD_SIZE_ARM * 2, disassembly, sizeof(disassembly));
103		be->printf(be, "%08X\t%s\n", instruction, disassembly);
104		return WORD_SIZE_ARM;
105	} else {
106		struct ARMInstructionInfo info2;
107		struct ARMInstructionInfo combined;
108		uint16_t instruction = debugger->d.core->busRead16(debugger->d.core, address);
109		uint16_t instruction2 = debugger->d.core->busRead16(debugger->d.core, address + WORD_SIZE_THUMB);
110		ARMDecodeThumb(instruction, &info);
111		ARMDecodeThumb(instruction2, &info2);
112		if (ARMDecodeThumbCombine(&info, &info2, &combined)) {
113			ARMDisassemble(&combined, address + WORD_SIZE_THUMB * 2, disassembly, sizeof(disassembly));
114			be->printf(be, "%04X %04X\t%s\n", instruction, instruction2, disassembly);
115			return WORD_SIZE_THUMB * 2;
116		} else {
117			ARMDisassemble(&info, address + WORD_SIZE_THUMB * 2, disassembly, sizeof(disassembly));
118			be->printf(be, "%04X     \t%s\n", instruction, disassembly);
119			return WORD_SIZE_THUMB;
120		}
121	}
122}
123
124static void _printStatus(struct CLIDebuggerSystem* debugger) {
125	struct CLIDebuggerBackend* be = debugger->p->backend;
126	struct ARMCore* cpu = debugger->p->d.core->cpu;
127	int r;
128	for (r = 0; r < 4; ++r) {
129		be->printf(be, "%08X %08X %08X %08X\n",
130		    cpu->gprs[r << 2],
131		    cpu->gprs[(r << 2) + 1],
132		    cpu->gprs[(r << 2) + 2],
133		    cpu->gprs[(r << 2) + 3]);
134	}
135	_printPSR(be, cpu->cpsr);
136	int instructionLength;
137	enum ExecutionMode mode = cpu->cpsr.t;
138	if (mode == MODE_ARM) {
139		instructionLength = WORD_SIZE_ARM;
140	} else {
141		instructionLength = WORD_SIZE_THUMB;
142	}
143	_printLine(debugger->p, cpu->gprs[ARM_PC] - instructionLength, mode);
144}
145
146static void _setBreakpointARM(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
147	struct CLIDebuggerBackend* be = debugger->backend;
148	if (!dv || dv->type != CLIDV_INT_TYPE) {
149		be->printf(be, "%s\n", ERROR_MISSING_ARGS);
150		return;
151	}
152	uint32_t address = dv->intValue;
153	ARMDebuggerSetSoftwareBreakpoint(debugger->d.platform, address, MODE_ARM);
154}
155
156static void _setBreakpointThumb(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
157	struct CLIDebuggerBackend* be = debugger->backend;
158	if (!dv || dv->type != CLIDV_INT_TYPE) {
159		be->printf(be, "%s\n", ERROR_MISSING_ARGS);
160		return;
161	}
162	uint32_t address = dv->intValue;
163	ARMDebuggerSetSoftwareBreakpoint(debugger->d.platform, address, MODE_THUMB);
164}
165
166void ARMCLIDebuggerCreate(struct CLIDebuggerSystem* debugger) {
167	debugger->printStatus = _printStatus;
168	debugger->disassemble = _disassemble;
169	debugger->platformName = "ARM";
170	debugger->platformCommands = _armCommands;
171}