mirror of https://github.com/mgba-emu/mgba.git
Debugger: Refactor large portions of debugger to allow for multiplatform
This commit is contained in:
parent
a4e29886c9
commit
1cc0bdeec1
|
@ -316,7 +316,7 @@ find_feature(USE_MAGICK "MagickWand")
|
|||
find_feature(USE_EPOXY "epoxy")
|
||||
|
||||
# Features
|
||||
set(DEBUGGER_SRC ${CMAKE_SOURCE_DIR}/src/debugger/debugger.c ${CMAKE_SOURCE_DIR}/src/debugger/memory-debugger.c)
|
||||
set(DEBUGGER_SRC ${CMAKE_SOURCE_DIR}/src/debugger/debugger.c)
|
||||
set(FEATURE_SRC)
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6")
|
||||
|
||||
|
@ -326,9 +326,9 @@ endif()
|
|||
|
||||
if(USE_CLI_DEBUGGER)
|
||||
list(APPEND FEATURES CLI_DEBUGGER)
|
||||
list(APPEND FEATURE_SRC ${CMAKE_SOURCE_DIR}/src/debugger/cli-debugger.c)
|
||||
list(APPEND FEATURE_SRC ${CMAKE_SOURCE_DIR}/src/debugger/parser.c)
|
||||
list(APPEND FEATURE_SRC ${CMAKE_SOURCE_DIR}/src/gba/supervisor/cli.c)
|
||||
list(APPEND DEBUGGER_SRC ${CMAKE_SOURCE_DIR}/src/debugger/cli-debugger.c)
|
||||
list(APPEND DEBUGGER_SRC ${CMAKE_SOURCE_DIR}/src/debugger/parser.c)
|
||||
list(APPEND DEBUGGER_SRC ${CMAKE_SOURCE_DIR}/src/gba/supervisor/cli.c)
|
||||
include_directories(AFTER ${LIBEDIT_INCLUDE_DIRS})
|
||||
link_directories(${LIBEDIT_LIBRARY_DIRS})
|
||||
set(DEBUGGER_LIB ${LIBEDIT_LIBRARIES})
|
||||
|
|
|
@ -0,0 +1,225 @@
|
|||
/* Copyright (c) 2013-2016 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "cli-debugger.h"
|
||||
|
||||
#ifdef USE_CLI_DEBUGGER
|
||||
#include "arm/memory-debugger.h"
|
||||
#include "arm/decoder.h"
|
||||
#include "core/core.h"
|
||||
#include "debugger/cli-debugger.h"
|
||||
|
||||
static void _printStatus(struct CLIDebuggerSystem*);
|
||||
|
||||
static void _disassembleArm(struct CLIDebugger*, struct CLIDebugVector*);
|
||||
static void _disassembleThumb(struct CLIDebugger*, struct CLIDebugVector*);
|
||||
static void _setBreakpointARM(struct CLIDebugger*, struct CLIDebugVector*);
|
||||
static void _setBreakpointThumb(struct CLIDebugger*, struct CLIDebugVector*);
|
||||
static void _writeRegister(struct CLIDebugger*, struct CLIDebugVector*);
|
||||
|
||||
static void _disassembleMode(struct CLIDebugger*, struct CLIDebugVector*, enum ExecutionMode mode);
|
||||
static uint32_t _printLine(struct CLIDebugger* debugger, uint32_t address, enum ExecutionMode mode);
|
||||
|
||||
static struct CLIDebuggerCommandSummary _armCommands[] = {
|
||||
{ "b/a", _setBreakpointARM, CLIDVParse, "Set a software breakpoint as ARM" },
|
||||
{ "b/t", _setBreakpointThumb, CLIDVParse, "Set a software breakpoint as Thumb" },
|
||||
{ "break/a", _setBreakpointARM, CLIDVParse, "Set a software breakpoint as ARM" },
|
||||
{ "break/t", _setBreakpointThumb, CLIDVParse, "Set a software breakpoint as Thumb" },
|
||||
{ "dis/a", _disassembleArm, CLIDVParse, "Disassemble instructions as ARM" },
|
||||
{ "dis/t", _disassembleThumb, CLIDVParse, "Disassemble instructions as Thumb" },
|
||||
{ "disasm/a", _disassembleArm, CLIDVParse, "Disassemble instructions as ARM" },
|
||||
{ "disasm/t", _disassembleThumb, CLIDVParse, "Disassemble instructions as Thumb" },
|
||||
{ "disassemble/a", _disassembleArm, CLIDVParse, "Disassemble instructions as ARM" },
|
||||
{ "disassemble/t", _disassembleThumb, CLIDVParse, "Disassemble instructions as Thumb" },
|
||||
{ "w/r", _writeRegister, CLIDVParse, "Write a register" },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
static inline void _printPSR(union PSR psr) {
|
||||
printf("%08X [%c%c%c%c%c%c%c]\n", psr.packed,
|
||||
psr.n ? 'N' : '-',
|
||||
psr.z ? 'Z' : '-',
|
||||
psr.c ? 'C' : '-',
|
||||
psr.v ? 'V' : '-',
|
||||
psr.i ? 'I' : '-',
|
||||
psr.f ? 'F' : '-',
|
||||
psr.t ? 'T' : '-');
|
||||
}
|
||||
|
||||
static void _disassemble(struct CLIDebuggerSystem* debugger, struct CLIDebugVector* dv) {
|
||||
struct ARMCore* cpu = debugger->p->d.core->cpu;
|
||||
_disassembleMode(debugger->p, dv, cpu->executionMode);
|
||||
}
|
||||
|
||||
static void _disassembleArm(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||
_disassembleMode(debugger, dv, MODE_ARM);
|
||||
}
|
||||
|
||||
static void _disassembleThumb(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||
_disassembleMode(debugger, dv, MODE_THUMB);
|
||||
}
|
||||
|
||||
static void _disassembleMode(struct CLIDebugger* debugger, struct CLIDebugVector* dv, enum ExecutionMode mode) {
|
||||
struct ARMCore* cpu = debugger->d.core->cpu;
|
||||
uint32_t address;
|
||||
int size;
|
||||
int wordSize;
|
||||
|
||||
if (mode == MODE_ARM) {
|
||||
wordSize = WORD_SIZE_ARM;
|
||||
} else {
|
||||
wordSize = WORD_SIZE_THUMB;
|
||||
}
|
||||
|
||||
if (!dv || dv->type != CLIDV_INT_TYPE) {
|
||||
address = cpu->gprs[ARM_PC] - wordSize;
|
||||
} else {
|
||||
address = dv->intValue;
|
||||
dv = dv->next;
|
||||
}
|
||||
|
||||
if (!dv || dv->type != CLIDV_INT_TYPE) {
|
||||
size = 1;
|
||||
} else {
|
||||
size = dv->intValue;
|
||||
dv = dv->next; // TODO: Check for excess args
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i = 0; i < size; ++i) {
|
||||
address += _printLine(debugger, address, mode);
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32_t _printLine(struct CLIDebugger* debugger, uint32_t address, enum ExecutionMode mode) {
|
||||
char disassembly[48];
|
||||
struct ARMInstructionInfo info;
|
||||
printf("%08X: ", address);
|
||||
if (mode == MODE_ARM) {
|
||||
uint32_t instruction = debugger->d.core->busRead32(debugger->d.core, address);
|
||||
ARMDecodeARM(instruction, &info);
|
||||
ARMDisassemble(&info, address + WORD_SIZE_ARM * 2, disassembly, sizeof(disassembly));
|
||||
printf("%08X\t%s\n", instruction, disassembly);
|
||||
return WORD_SIZE_ARM;
|
||||
} else {
|
||||
struct ARMInstructionInfo info2;
|
||||
struct ARMInstructionInfo combined;
|
||||
uint16_t instruction = debugger->d.core->busRead16(debugger->d.core, address);
|
||||
uint16_t instruction2 = debugger->d.core->busRead16(debugger->d.core, address + WORD_SIZE_THUMB);
|
||||
ARMDecodeThumb(instruction, &info);
|
||||
ARMDecodeThumb(instruction2, &info2);
|
||||
if (ARMDecodeThumbCombine(&info, &info2, &combined)) {
|
||||
ARMDisassemble(&combined, address + WORD_SIZE_THUMB * 2, disassembly, sizeof(disassembly));
|
||||
printf("%04X %04X\t%s\n", instruction, instruction2, disassembly);
|
||||
return WORD_SIZE_THUMB * 2;
|
||||
} else {
|
||||
ARMDisassemble(&info, address + WORD_SIZE_THUMB * 2, disassembly, sizeof(disassembly));
|
||||
printf("%04X \t%s\n", instruction, disassembly);
|
||||
return WORD_SIZE_THUMB;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void _printStatus(struct CLIDebuggerSystem* debugger) {
|
||||
struct ARMCore* cpu = debugger->p->d.core->cpu;
|
||||
int r;
|
||||
for (r = 0; r < 4; ++r) {
|
||||
printf("%08X %08X %08X %08X\n",
|
||||
cpu->gprs[r << 2],
|
||||
cpu->gprs[(r << 2) + 1],
|
||||
cpu->gprs[(r << 2) + 2],
|
||||
cpu->gprs[(r << 2) + 3]);
|
||||
}
|
||||
_printPSR(cpu->cpsr);
|
||||
int instructionLength;
|
||||
enum ExecutionMode mode = cpu->cpsr.t;
|
||||
if (mode == MODE_ARM) {
|
||||
instructionLength = WORD_SIZE_ARM;
|
||||
} else {
|
||||
instructionLength = WORD_SIZE_THUMB;
|
||||
}
|
||||
_printLine(debugger->p, cpu->gprs[ARM_PC] - instructionLength, mode);
|
||||
}
|
||||
|
||||
static void _writeRegister(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||
struct ARMCore* cpu = debugger->d.core->cpu;
|
||||
if (!dv || dv->type != CLIDV_INT_TYPE) {
|
||||
printf("%s\n", ERROR_MISSING_ARGS);
|
||||
return;
|
||||
}
|
||||
if (!dv->next || dv->next->type != CLIDV_INT_TYPE) {
|
||||
printf("%s\n", ERROR_MISSING_ARGS);
|
||||
return;
|
||||
}
|
||||
uint32_t regid = dv->intValue;
|
||||
uint32_t value = dv->next->intValue;
|
||||
if (regid >= ARM_PC) {
|
||||
return;
|
||||
}
|
||||
cpu->gprs[regid] = value;
|
||||
}
|
||||
|
||||
static void _setBreakpointARM(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||
if (!dv || dv->type != CLIDV_INT_TYPE) {
|
||||
printf("%s\n", ERROR_MISSING_ARGS);
|
||||
return;
|
||||
}
|
||||
uint32_t address = dv->intValue;
|
||||
ARMDebuggerSetSoftwareBreakpoint(&debugger->d, address, MODE_ARM);
|
||||
}
|
||||
|
||||
static void _setBreakpointThumb(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||
if (!dv || dv->type != CLIDV_INT_TYPE) {
|
||||
printf("%s\n", ERROR_MISSING_ARGS);
|
||||
return;
|
||||
}
|
||||
uint32_t address = dv->intValue;
|
||||
ARMDebuggerSetSoftwareBreakpoint(&debugger->d, address, MODE_THUMB);
|
||||
}
|
||||
|
||||
static uint32_t _lookupIdentifier(struct mDebugger* debugger, const char* name, struct CLIDebugVector* dv) {
|
||||
struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
|
||||
struct ARMCore* cpu = debugger->core->cpu;
|
||||
if (strcmp(name, "sp") == 0) {
|
||||
return cpu->gprs[ARM_SP];
|
||||
}
|
||||
if (strcmp(name, "lr") == 0) {
|
||||
return cpu->gprs[ARM_LR];
|
||||
}
|
||||
if (strcmp(name, "pc") == 0) {
|
||||
return cpu->gprs[ARM_PC];
|
||||
}
|
||||
if (strcmp(name, "cpsr") == 0) {
|
||||
return cpu->cpsr.packed;
|
||||
}
|
||||
// TODO: test if mode has SPSR
|
||||
if (strcmp(name, "spsr") == 0) {
|
||||
return cpu->spsr.packed;
|
||||
}
|
||||
if (name[0] == 'r' && name[1] >= '0' && name[1] <= '9') {
|
||||
int reg = atoi(&name[1]);
|
||||
if (reg < 16) {
|
||||
return cpu->gprs[reg];
|
||||
}
|
||||
}
|
||||
if (cliDebugger->system) {
|
||||
uint32_t value = cliDebugger->system->lookupIdentifier(cliDebugger->system, name, dv);
|
||||
if (dv->type != CLIDV_ERROR_TYPE) {
|
||||
return value;
|
||||
}
|
||||
} else {
|
||||
dv->type = CLIDV_ERROR_TYPE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ARMCLIDebuggerCreate(struct CLIDebuggerSystem* debugger) {
|
||||
debugger->printStatus = _printStatus;
|
||||
debugger->disassemble = _disassemble;
|
||||
debugger->platformName = "ARM";
|
||||
debugger->platformCommands = _armCommands;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,14 @@
|
|||
/* Copyright (c) 2013-2016 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#ifndef ARM_CLI_DEBUGGER_H
|
||||
#define ARM_CLI_DEBUGGER_H
|
||||
|
||||
#include "util/common.h"
|
||||
|
||||
struct CLIDebuggerSystem;
|
||||
void ARMCLIDebuggerCreate(struct CLIDebuggerSystem* debugger);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,172 @@
|
|||
/* Copyright (c) 2013-2014 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "debugger.h"
|
||||
|
||||
#include "arm/arm.h"
|
||||
#include "arm/isa-inlines.h"
|
||||
#include "arm/memory-debugger.h"
|
||||
#include "core/core.h"
|
||||
|
||||
DEFINE_VECTOR(ARMDebugBreakpointList, struct ARMDebugBreakpoint);
|
||||
DEFINE_VECTOR(ARMDebugWatchpointList, struct ARMDebugWatchpoint);
|
||||
|
||||
static struct ARMDebugBreakpoint* _lookupBreakpoint(struct ARMDebugBreakpointList* breakpoints, uint32_t address) {
|
||||
size_t i;
|
||||
for (i = 0; i < ARMDebugBreakpointListSize(breakpoints); ++i) {
|
||||
if (ARMDebugBreakpointListGetPointer(breakpoints, i)->address == address) {
|
||||
return ARMDebugBreakpointListGetPointer(breakpoints, i);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ARMDebuggerCheckBreakpoints(struct mDebuggerPlatform* d) {
|
||||
struct ARMDebugger* debugger = (struct ARMDebugger*) d;
|
||||
int instructionLength;
|
||||
enum ExecutionMode mode = debugger->cpu->cpsr.t;
|
||||
if (mode == MODE_ARM) {
|
||||
instructionLength = WORD_SIZE_ARM;
|
||||
} else {
|
||||
instructionLength = WORD_SIZE_THUMB;
|
||||
}
|
||||
struct ARMDebugBreakpoint* breakpoint = _lookupBreakpoint(&debugger->breakpoints, debugger->cpu->gprs[ARM_PC] - instructionLength);
|
||||
if (!breakpoint) {
|
||||
return;
|
||||
}
|
||||
struct mDebuggerEntryInfo info = {
|
||||
.address = breakpoint->address
|
||||
};
|
||||
mDebuggerEnter(d->p, DEBUGGER_ENTER_BREAKPOINT, &info);
|
||||
}
|
||||
|
||||
static void ARMDebuggerInit(void* cpu, struct mDebuggerPlatform* platform);
|
||||
static void ARMDebuggerDeinit(struct mDebuggerPlatform* platform);
|
||||
|
||||
static void ARMDebuggerEnter(struct mDebuggerPlatform* d, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info);
|
||||
|
||||
static void ARMDebuggerSetBreakpoint(struct mDebuggerPlatform*, uint32_t address);
|
||||
static void ARMDebuggerClearBreakpoint(struct mDebuggerPlatform*, uint32_t address);
|
||||
static void ARMDebuggerSetWatchpoint(struct mDebuggerPlatform*, uint32_t address, enum mWatchpointType type);
|
||||
static void ARMDebuggerClearWatchpoint(struct mDebuggerPlatform*, uint32_t address);
|
||||
static void ARMDebuggerCheckBreakpoints(struct mDebuggerPlatform*);
|
||||
static bool ARMDebuggerHasBreakpoints(struct mDebuggerPlatform*);
|
||||
|
||||
struct mDebuggerPlatform* ARMDebuggerPlatformCreate(void) {
|
||||
struct mDebuggerPlatform* platform = malloc(sizeof(struct ARMDebugger));
|
||||
platform->entered = ARMDebuggerEnter;
|
||||
platform->init = ARMDebuggerInit;
|
||||
platform->deinit = ARMDebuggerDeinit;
|
||||
platform->setBreakpoint = ARMDebuggerSetBreakpoint;
|
||||
platform->clearBreakpoint = ARMDebuggerClearBreakpoint;
|
||||
platform->setWatchpoint = ARMDebuggerSetWatchpoint;
|
||||
platform->clearWatchpoint = ARMDebuggerClearWatchpoint;
|
||||
platform->checkBreakpoints = ARMDebuggerCheckBreakpoints;
|
||||
platform->hasBreakpoints = ARMDebuggerHasBreakpoints;
|
||||
return platform;
|
||||
}
|
||||
|
||||
void ARMDebuggerInit(void* cpu, struct mDebuggerPlatform* platform) {
|
||||
struct ARMDebugger* debugger = (struct ARMDebugger*) platform;
|
||||
debugger->cpu = cpu;
|
||||
debugger->originalMemory = debugger->cpu->memory;
|
||||
ARMDebugBreakpointListInit(&debugger->breakpoints, 0);
|
||||
ARMDebugBreakpointListInit(&debugger->swBreakpoints, 0);
|
||||
ARMDebugWatchpointListInit(&debugger->watchpoints, 0);
|
||||
}
|
||||
|
||||
void ARMDebuggerDeinit(struct mDebuggerPlatform* platform) {
|
||||
struct ARMDebugger* debugger = (struct ARMDebugger*) platform;
|
||||
ARMDebugBreakpointListDeinit(&debugger->breakpoints);
|
||||
ARMDebugBreakpointListDeinit(&debugger->swBreakpoints);
|
||||
ARMDebugWatchpointListDeinit(&debugger->watchpoints);
|
||||
}
|
||||
|
||||
static void ARMDebuggerEnter(struct mDebuggerPlatform* platform, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) {
|
||||
struct ARMDebugger* debugger = (struct ARMDebugger*) platform;
|
||||
struct ARMCore* cpu = debugger->cpu;
|
||||
cpu->nextEvent = cpu->cycles;
|
||||
if (reason == DEBUGGER_ENTER_BREAKPOINT) {
|
||||
struct ARMDebugBreakpoint* breakpoint = _lookupBreakpoint(&debugger->swBreakpoints, _ARMPCAddress(cpu));
|
||||
if (breakpoint && breakpoint->isSw) {
|
||||
info->address = breakpoint->address;
|
||||
if (debugger->clearSoftwareBreakpoint) {
|
||||
debugger->clearSoftwareBreakpoint(debugger, breakpoint->address, breakpoint->sw.mode, breakpoint->sw.opcode);
|
||||
}
|
||||
|
||||
ARMRunFake(cpu, breakpoint->sw.opcode);
|
||||
|
||||
if (debugger->setSoftwareBreakpoint) {
|
||||
debugger->setSoftwareBreakpoint(debugger, breakpoint->address, breakpoint->sw.mode, &breakpoint->sw.opcode);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (debugger->entered) {
|
||||
debugger->entered(debugger->d.p, reason, info);
|
||||
}
|
||||
}
|
||||
|
||||
bool ARMDebuggerSetSoftwareBreakpoint(struct mDebuggerPlatform* d, uint32_t address, enum ExecutionMode mode) {
|
||||
struct ARMDebugger* debugger = (struct ARMDebugger*) d;
|
||||
uint32_t opcode;
|
||||
if (!debugger->setSoftwareBreakpoint || !debugger->setSoftwareBreakpoint(debugger, address, mode, &opcode)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ARMDebugBreakpoint* breakpoint = ARMDebugBreakpointListAppend(&debugger->swBreakpoints);
|
||||
breakpoint->address = address;
|
||||
breakpoint->isSw = true;
|
||||
breakpoint->sw.opcode = opcode;
|
||||
breakpoint->sw.mode = mode;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ARMDebuggerSetBreakpoint(struct mDebuggerPlatform* d, uint32_t address) {
|
||||
struct ARMDebugger* debugger = (struct ARMDebugger*) d;
|
||||
struct ARMDebugBreakpoint* breakpoint = ARMDebugBreakpointListAppend(&debugger->breakpoints);
|
||||
breakpoint->address = address;
|
||||
breakpoint->isSw = false;
|
||||
}
|
||||
|
||||
static void ARMDebuggerClearBreakpoint(struct mDebuggerPlatform* d, uint32_t address) {
|
||||
struct ARMDebugger* debugger = (struct ARMDebugger*) d;
|
||||
struct ARMDebugBreakpointList* breakpoints = &debugger->breakpoints;
|
||||
size_t i;
|
||||
for (i = 0; i < ARMDebugBreakpointListSize(breakpoints); ++i) {
|
||||
if (ARMDebugBreakpointListGetPointer(breakpoints, i)->address == address) {
|
||||
ARMDebugBreakpointListShift(breakpoints, i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool ARMDebuggerHasBreakpoints(struct mDebuggerPlatform* d) {
|
||||
struct ARMDebugger* debugger = (struct ARMDebugger*) d;
|
||||
return ARMDebugBreakpointListSize(&debugger->breakpoints) || ARMDebugWatchpointListSize(&debugger->watchpoints);
|
||||
}
|
||||
|
||||
static void ARMDebuggerSetWatchpoint(struct mDebuggerPlatform* d, uint32_t address, enum mWatchpointType type) {
|
||||
struct ARMDebugger* debugger = (struct ARMDebugger*) d;
|
||||
if (!ARMDebugWatchpointListSize(&debugger->watchpoints)) {
|
||||
ARMDebuggerInstallMemoryShim(debugger);
|
||||
}
|
||||
struct ARMDebugWatchpoint* watchpoint = ARMDebugWatchpointListAppend(&debugger->watchpoints);
|
||||
watchpoint->address = address;
|
||||
watchpoint->type = type;
|
||||
}
|
||||
|
||||
static void ARMDebuggerClearWatchpoint(struct mDebuggerPlatform* d, uint32_t address) {
|
||||
struct ARMDebugger* debugger = (struct ARMDebugger*) d;
|
||||
struct ARMDebugWatchpointList* watchpoints = &debugger->watchpoints;
|
||||
size_t i;
|
||||
for (i = 0; i < ARMDebugWatchpointListSize(watchpoints); ++i) {
|
||||
if (ARMDebugWatchpointListGetPointer(watchpoints, i)->address == address) {
|
||||
ARMDebugWatchpointListShift(watchpoints, i, 1);
|
||||
}
|
||||
}
|
||||
if (!ARMDebugWatchpointListSize(&debugger->watchpoints)) {
|
||||
ARMDebuggerRemoveMemoryShim(debugger);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/* Copyright (c) 2013-2014 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "debugger/debugger.h"
|
||||
|
||||
struct ARMDebugBreakpoint {
|
||||
uint32_t address;
|
||||
bool isSw;
|
||||
struct {
|
||||
uint32_t opcode;
|
||||
enum ExecutionMode mode;
|
||||
} sw;
|
||||
};
|
||||
|
||||
struct ARMDebugWatchpoint {
|
||||
uint32_t address;
|
||||
enum mWatchpointType type;
|
||||
};
|
||||
|
||||
DECLARE_VECTOR(ARMDebugBreakpointList, struct ARMDebugBreakpoint);
|
||||
DECLARE_VECTOR(ARMDebugWatchpointList, struct ARMDebugWatchpoint);
|
||||
|
||||
struct ARMDebugger {
|
||||
struct mDebuggerPlatform d;
|
||||
struct ARMCore* cpu;
|
||||
|
||||
struct ARMDebugBreakpointList breakpoints;
|
||||
struct ARMDebugBreakpointList swBreakpoints;
|
||||
struct ARMDebugWatchpointList watchpoints;
|
||||
struct ARMMemory originalMemory;
|
||||
|
||||
void (*entered)(struct mDebugger*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*);
|
||||
|
||||
bool (*setSoftwareBreakpoint)(struct ARMDebugger*, uint32_t address, enum ExecutionMode mode, uint32_t* opcode);
|
||||
bool (*clearSoftwareBreakpoint)(struct ARMDebugger*, uint32_t address, enum ExecutionMode mode, uint32_t opcode);
|
||||
};
|
||||
|
||||
struct mDebuggerPlatform* ARMDebuggerPlatformCreate(void);
|
||||
bool ARMDebuggerSetSoftwareBreakpoint(struct mDebuggerPlatform* debugger, uint32_t address, enum ExecutionMode mode);
|
|
@ -5,13 +5,13 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "memory-debugger.h"
|
||||
|
||||
#include "debugger.h"
|
||||
#include "arm/debugger.h"
|
||||
|
||||
#include "util/math.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
static bool _checkWatchpoints(struct Debugger* debugger, uint32_t address, struct DebuggerEntryInfo* info, enum WatchpointType type, uint32_t newValue, int width);
|
||||
static bool _checkWatchpoints(struct ARMDebugger* debugger, uint32_t address, struct mDebuggerEntryInfo* info, enum mWatchpointType type, uint32_t newValue, int width);
|
||||
|
||||
#define FIND_DEBUGGER(DEBUGGER, CPU) \
|
||||
{ \
|
||||
|
@ -19,7 +19,7 @@ static bool _checkWatchpoints(struct Debugger* debugger, uint32_t address, struc
|
|||
size_t i; \
|
||||
for (i = 0; i < CPU->numComponents; ++i) { \
|
||||
if (CPU->components[i]->id == DEBUGGER_ID) { \
|
||||
DEBUGGER = (struct Debugger*) cpu->components[i]; \
|
||||
DEBUGGER = (struct ARMDebugger*) cpu->components[i]; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
|
@ -27,36 +27,36 @@ static bool _checkWatchpoints(struct Debugger* debugger, uint32_t address, struc
|
|||
|
||||
#define CREATE_SHIM(NAME, RETURN, TYPES, ...) \
|
||||
static RETURN DebuggerShim_ ## NAME TYPES { \
|
||||
struct Debugger* debugger; \
|
||||
struct ARMDebugger* debugger; \
|
||||
FIND_DEBUGGER(debugger, cpu); \
|
||||
return debugger->originalMemory.NAME(cpu, __VA_ARGS__); \
|
||||
}
|
||||
|
||||
#define CREATE_WATCHPOINT_READ_SHIM(NAME, WIDTH, RETURN, TYPES, ...) \
|
||||
static RETURN DebuggerShim_ ## NAME TYPES { \
|
||||
struct Debugger* debugger; \
|
||||
struct ARMDebugger* debugger; \
|
||||
FIND_DEBUGGER(debugger, cpu); \
|
||||
struct DebuggerEntryInfo info; \
|
||||
struct mDebuggerEntryInfo info; \
|
||||
if (_checkWatchpoints(debugger, address, &info, WATCHPOINT_READ, 0, WIDTH)) { \
|
||||
DebuggerEnter(debugger, DEBUGGER_ENTER_WATCHPOINT, &info); \
|
||||
mDebuggerEnter(debugger->d.p, DEBUGGER_ENTER_WATCHPOINT, &info); \
|
||||
} \
|
||||
return debugger->originalMemory.NAME(cpu, __VA_ARGS__); \
|
||||
}
|
||||
|
||||
#define CREATE_WATCHPOINT_WRITE_SHIM(NAME, WIDTH, RETURN, TYPES, ...) \
|
||||
static RETURN DebuggerShim_ ## NAME TYPES { \
|
||||
struct Debugger* debugger; \
|
||||
struct ARMDebugger* debugger; \
|
||||
FIND_DEBUGGER(debugger, cpu); \
|
||||
struct DebuggerEntryInfo info; \
|
||||
struct mDebuggerEntryInfo info; \
|
||||
if (_checkWatchpoints(debugger, address, &info, WATCHPOINT_WRITE, value, WIDTH)) { \
|
||||
DebuggerEnter(debugger, DEBUGGER_ENTER_WATCHPOINT, &info); \
|
||||
mDebuggerEnter(debugger->d.p, DEBUGGER_ENTER_WATCHPOINT, &info); \
|
||||
} \
|
||||
return debugger->originalMemory.NAME(cpu, __VA_ARGS__); \
|
||||
}
|
||||
|
||||
#define CREATE_MULTIPLE_WATCHPOINT_SHIM(NAME, ACCESS_TYPE) \
|
||||
static uint32_t DebuggerShim_ ## NAME (struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) { \
|
||||
struct Debugger* debugger; \
|
||||
struct ARMDebugger* debugger; \
|
||||
FIND_DEBUGGER(debugger, cpu); \
|
||||
uint32_t popcount = popcount32(mask); \
|
||||
int offset = 4; \
|
||||
|
@ -70,9 +70,9 @@ static bool _checkWatchpoints(struct Debugger* debugger, uint32_t address, struc
|
|||
} \
|
||||
unsigned i; \
|
||||
for (i = 0; i < popcount; ++i) { \
|
||||
struct DebuggerEntryInfo info; \
|
||||
struct mDebuggerEntryInfo info; \
|
||||
if (_checkWatchpoints(debugger, base + 4 * i, &info, ACCESS_TYPE, 0, 4)) { \
|
||||
DebuggerEnter(debugger, DEBUGGER_ENTER_WATCHPOINT, &info); \
|
||||
mDebuggerEnter(debugger->d.p, DEBUGGER_ENTER_WATCHPOINT, &info); \
|
||||
} \
|
||||
} \
|
||||
return debugger->originalMemory.NAME(cpu, address, mask, direction, cycleCounter); \
|
||||
|
@ -88,12 +88,12 @@ CREATE_MULTIPLE_WATCHPOINT_SHIM(loadMultiple, WATCHPOINT_READ)
|
|||
CREATE_MULTIPLE_WATCHPOINT_SHIM(storeMultiple, WATCHPOINT_WRITE)
|
||||
CREATE_SHIM(setActiveRegion, void, (struct ARMCore* cpu, uint32_t address), address)
|
||||
|
||||
static bool _checkWatchpoints(struct Debugger* debugger, uint32_t address, struct DebuggerEntryInfo* info, enum WatchpointType type, uint32_t newValue, int width) {
|
||||
static bool _checkWatchpoints(struct ARMDebugger* debugger, uint32_t address, struct mDebuggerEntryInfo* info, enum mWatchpointType type, uint32_t newValue, int width) {
|
||||
--width;
|
||||
struct DebugWatchpoint* watchpoint;
|
||||
struct ARMDebugWatchpoint* watchpoint;
|
||||
size_t i;
|
||||
for (i = 0; i < DebugWatchpointListSize(&debugger->watchpoints); ++i) {
|
||||
watchpoint = DebugWatchpointListGetPointer(&debugger->watchpoints, i);
|
||||
for (i = 0; i < ARMDebugWatchpointListSize(&debugger->watchpoints); ++i) {
|
||||
watchpoint = ARMDebugWatchpointListGetPointer(&debugger->watchpoints, i);
|
||||
if (!((watchpoint->address ^ address) & ~width) && watchpoint->type & type) {
|
||||
switch (width + 1) {
|
||||
case 1:
|
||||
|
@ -116,7 +116,7 @@ static bool _checkWatchpoints(struct Debugger* debugger, uint32_t address, struc
|
|||
return false;
|
||||
}
|
||||
|
||||
void DebuggerInstallMemoryShim(struct Debugger* debugger) {
|
||||
void ARMDebuggerInstallMemoryShim(struct ARMDebugger* debugger) {
|
||||
debugger->originalMemory = debugger->cpu->memory;
|
||||
debugger->cpu->memory.store32 = DebuggerShim_store32;
|
||||
debugger->cpu->memory.store16 = DebuggerShim_store16;
|
||||
|
@ -129,7 +129,7 @@ void DebuggerInstallMemoryShim(struct Debugger* debugger) {
|
|||
debugger->cpu->memory.setActiveRegion = DebuggerShim_setActiveRegion;
|
||||
}
|
||||
|
||||
void DebuggerRemoveMemoryShim(struct Debugger* debugger) {
|
||||
void ARMDebuggerRemoveMemoryShim(struct ARMDebugger* debugger) {
|
||||
debugger->cpu->memory.store32 = debugger->originalMemory.store32;
|
||||
debugger->cpu->memory.store16 = debugger->originalMemory.store16;
|
||||
debugger->cpu->memory.store8 = debugger->originalMemory.store8;
|
|
@ -8,11 +8,9 @@
|
|||
|
||||
#include "util/common.h"
|
||||
|
||||
#include "arm.h"
|
||||
struct ARMDebugger;
|
||||
|
||||
struct Debugger;
|
||||
|
||||
void DebuggerInstallMemoryShim(struct Debugger* debugger);
|
||||
void DebuggerRemoveMemoryShim(struct Debugger* debugger);
|
||||
void ARMDebuggerInstallMemoryShim(struct ARMDebugger* debugger);
|
||||
void ARMDebuggerRemoveMemoryShim(struct ARMDebugger* debugger);
|
||||
|
||||
#endif
|
|
@ -16,6 +16,7 @@
|
|||
#include "core/input.h"
|
||||
#endif
|
||||
#include "core/interface.h"
|
||||
#include "debugger/debugger.h"
|
||||
|
||||
enum mPlatform {
|
||||
PLATFORM_NONE = -1,
|
||||
|
@ -33,6 +34,7 @@ struct mCoreSync;
|
|||
struct mCore {
|
||||
void* cpu;
|
||||
void* board;
|
||||
struct mDebugger* debugger;
|
||||
|
||||
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
|
||||
struct mDirectorySet dirs;
|
||||
|
@ -93,6 +95,20 @@ struct mCore {
|
|||
void (*setRTC)(struct mCore*, struct mRTCSource*);
|
||||
void (*setRotation)(struct mCore*, struct mRotationSource*);
|
||||
void (*setRumble)(struct mCore*, struct mRumble*);
|
||||
|
||||
uint32_t (*busRead8)(struct mCore*, uint32_t address);
|
||||
uint32_t (*busRead16)(struct mCore*, uint32_t address);
|
||||
uint32_t (*busRead32)(struct mCore*, uint32_t address);
|
||||
|
||||
void (*busWrite8)(struct mCore*, uint32_t address, uint8_t);
|
||||
void (*busWrite16)(struct mCore*, uint32_t address, uint16_t);
|
||||
void (*busWrite32)(struct mCore*, uint32_t address, uint32_t);
|
||||
|
||||
bool (*supportsDebuggerType)(struct mCore*, enum mDebuggerType);
|
||||
struct mDebuggerPlatform* (*debuggerPlatform)(struct mCore*);
|
||||
struct CLIDebuggerSystem* (*cliDebuggerSystem)(struct mCore*);
|
||||
void (*attachDebugger)(struct mCore*, struct mDebugger*);
|
||||
void (*detachDebugger)(struct mCore*);
|
||||
};
|
||||
|
||||
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
|
||||
|
|
|
@ -8,6 +8,12 @@
|
|||
|
||||
#include "util/common.h"
|
||||
|
||||
enum mCPUComponentType {
|
||||
CPU_COMPONENT_DEBUGGER,
|
||||
CPU_COMPONENT_CHEAT_DEVICE,
|
||||
CPU_COMPONENT_MAX
|
||||
};
|
||||
|
||||
struct mCPUComponent {
|
||||
uint32_t id;
|
||||
void (*init)(void* cpu, struct mCPUComponent* component);
|
||||
|
|
|
@ -116,7 +116,17 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) {
|
|||
_changeState(threadContext, THREAD_RUNNING, true);
|
||||
|
||||
while (threadContext->state < THREAD_EXITING) {
|
||||
core->runLoop(core);
|
||||
struct mDebugger* debugger = core->debugger;
|
||||
if (debugger) {
|
||||
mDebuggerRun(debugger);
|
||||
if (debugger->state == DEBUGGER_SHUTDOWN) {
|
||||
_changeState(threadContext, THREAD_EXITING, false);
|
||||
}
|
||||
} else {
|
||||
while (threadContext->state == THREAD_RUNNING) {
|
||||
core->runLoop(core);
|
||||
}
|
||||
}
|
||||
|
||||
int resetScheduled = 0;
|
||||
MutexLock(&threadContext->stateMutex);
|
||||
|
|
|
@ -4,7 +4,10 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "cli-debugger.h"
|
||||
#include "decoder.h"
|
||||
|
||||
#ifdef USE_CLI_DEBUGGER
|
||||
|
||||
#include "core/core.h"
|
||||
#include "parser.h"
|
||||
|
||||
#include <signal.h>
|
||||
|
@ -13,8 +16,8 @@
|
|||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
static const char* ERROR_MISSING_ARGS = "Arguments missing"; // TODO: share
|
||||
static const char* ERROR_OVERFLOW = "Arguments overflow";
|
||||
const char* ERROR_MISSING_ARGS = "Arguments missing"; // TODO: share
|
||||
const char* ERROR_OVERFLOW = "Arguments overflow";
|
||||
|
||||
static struct CLIDebugger* _activeDebugger;
|
||||
|
||||
|
@ -23,8 +26,6 @@ static void _breakInto(struct CLIDebugger*, struct CLIDebugVector*);
|
|||
#endif
|
||||
static void _continue(struct CLIDebugger*, struct CLIDebugVector*);
|
||||
static void _disassemble(struct CLIDebugger*, struct CLIDebugVector*);
|
||||
static void _disassembleArm(struct CLIDebugger*, struct CLIDebugVector*);
|
||||
static void _disassembleThumb(struct CLIDebugger*, struct CLIDebugVector*);
|
||||
static void _next(struct CLIDebugger*, struct CLIDebugVector*);
|
||||
static void _print(struct CLIDebugger*, struct CLIDebugVector*);
|
||||
static void _printBin(struct CLIDebugger*, struct CLIDebugVector*);
|
||||
|
@ -37,42 +38,27 @@ static void _reset(struct CLIDebugger*, struct CLIDebugVector*);
|
|||
static void _readHalfword(struct CLIDebugger*, struct CLIDebugVector*);
|
||||
static void _readWord(struct CLIDebugger*, struct CLIDebugVector*);
|
||||
static void _setBreakpoint(struct CLIDebugger*, struct CLIDebugVector*);
|
||||
static void _setBreakpointARM(struct CLIDebugger*, struct CLIDebugVector*);
|
||||
static void _setBreakpointThumb(struct CLIDebugger*, struct CLIDebugVector*);
|
||||
static void _clearBreakpoint(struct CLIDebugger*, struct CLIDebugVector*);
|
||||
static void _setWatchpoint(struct CLIDebugger*, struct CLIDebugVector*);
|
||||
static void _writeByte(struct CLIDebugger*, struct CLIDebugVector*);
|
||||
static void _writeHalfword(struct CLIDebugger*, struct CLIDebugVector*);
|
||||
static void _writeWord(struct CLIDebugger*, struct CLIDebugVector*);
|
||||
static void _writeRegister(struct CLIDebugger*, struct CLIDebugVector*);
|
||||
static void _dumpByte(struct CLIDebugger*, struct CLIDebugVector*);
|
||||
static void _dumpHalfword(struct CLIDebugger*, struct CLIDebugVector*);
|
||||
static void _dumpWord(struct CLIDebugger*, struct CLIDebugVector*);
|
||||
|
||||
static void _breakIntoDefault(int signal);
|
||||
static void _disassembleMode(struct CLIDebugger*, struct CLIDebugVector*, enum ExecutionMode mode);
|
||||
static uint32_t _printLine(struct CLIDebugger* debugger, uint32_t address, enum ExecutionMode mode);
|
||||
|
||||
static struct CLIDebuggerCommandSummary _debuggerCommands[] = {
|
||||
{ "b", _setBreakpoint, CLIDVParse, "Set a breakpoint" },
|
||||
{ "b/a", _setBreakpointARM, CLIDVParse, "Set a software breakpoint as ARM" },
|
||||
{ "b/t", _setBreakpointThumb, CLIDVParse, "Set a software breakpoint as Thumb" },
|
||||
{ "break", _setBreakpoint, CLIDVParse, "Set a breakpoint" },
|
||||
{ "break/a", _setBreakpointARM, CLIDVParse, "Set a software breakpoint as ARM" },
|
||||
{ "break/t", _setBreakpointThumb, CLIDVParse, "Set a software breakpoint as Thumb" },
|
||||
{ "c", _continue, 0, "Continue execution" },
|
||||
{ "continue", _continue, 0, "Continue execution" },
|
||||
{ "d", _clearBreakpoint, CLIDVParse, "Delete a breakpoint" },
|
||||
{ "delete", _clearBreakpoint, CLIDVParse, "Delete a breakpoint" },
|
||||
{ "dis", _disassemble, CLIDVParse, "Disassemble instructions" },
|
||||
{ "dis/a", _disassembleArm, CLIDVParse, "Disassemble instructions as ARM" },
|
||||
{ "dis/t", _disassembleThumb, CLIDVParse, "Disassemble instructions as Thumb" },
|
||||
{ "disasm", _disassemble, CLIDVParse, "Disassemble instructions" },
|
||||
{ "disasm/a", _disassembleArm, CLIDVParse, "Disassemble instructions as ARM" },
|
||||
{ "disasm/t", _disassembleThumb, CLIDVParse, "Disassemble instructions as Thumb" },
|
||||
{ "disassemble", _disassemble, CLIDVParse, "Disassemble instructions" },
|
||||
{ "disassemble/a", _disassembleArm, CLIDVParse, "Disassemble instructions as ARM" },
|
||||
{ "disassemble/t", _disassembleThumb, CLIDVParse, "Disassemble instructions as Thumb" },
|
||||
{ "h", _printHelp, CLIDVStringParse, "Print help" },
|
||||
{ "help", _printHelp, CLIDVStringParse, "Print help" },
|
||||
{ "i", _printStatus, 0, "Print the current status" },
|
||||
|
@ -93,11 +79,10 @@ static struct CLIDebuggerCommandSummary _debuggerCommands[] = {
|
|||
{ "r/4", _readWord, CLIDVParse, "Read a word from a specified offset" },
|
||||
{ "status", _printStatus, 0, "Print the current status" },
|
||||
{ "w", _setWatchpoint, CLIDVParse, "Set a watchpoint" },
|
||||
{ "watch", _setWatchpoint, CLIDVParse, "Set a watchpoint" },
|
||||
{ "w/1", _writeByte, CLIDVParse, "Write a byte at a specified offset" },
|
||||
{ "w/2", _writeHalfword, CLIDVParse, "Write a halfword at a specified offset" },
|
||||
{ "w/4", _writeWord, CLIDVParse, "Write a word at a specified offset" },
|
||||
{ "w/r", _writeRegister, CLIDVParse, "Write a register" },
|
||||
{ "watch", _setWatchpoint, CLIDVParse, "Set a watchpoint" },
|
||||
{ "x/1", _dumpByte, CLIDVParse, "Examine bytes at a specified offset" },
|
||||
{ "x/2", _dumpHalfword, CLIDVParse, "Examine halfwords at a specified offset" },
|
||||
{ "x/4", _dumpWord, CLIDVParse, "Examine words at a specified offset" },
|
||||
|
@ -107,17 +92,6 @@ static struct CLIDebuggerCommandSummary _debuggerCommands[] = {
|
|||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
static inline void _printPSR(union PSR psr) {
|
||||
printf("%08X [%c%c%c%c%c%c%c]\n", psr.packed,
|
||||
psr.n ? 'N' : '-',
|
||||
psr.z ? 'Z' : '-',
|
||||
psr.c ? 'C' : '-',
|
||||
psr.v ? 'V' : '-',
|
||||
psr.i ? 'I' : '-',
|
||||
psr.f ? 'F' : '-',
|
||||
psr.t ? 'T' : '-');
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
static void _handleDeath(int sig) {
|
||||
UNUSED(sig);
|
||||
|
@ -149,57 +123,12 @@ static void _continue(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
|||
|
||||
static void _next(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||
UNUSED(dv);
|
||||
if (debugger->d.currentBreakpoint) {
|
||||
if (debugger->d.currentBreakpoint->isSw && debugger->d.setSoftwareBreakpoint) {
|
||||
debugger->d.setSoftwareBreakpoint(&debugger->d, debugger->d.currentBreakpoint->address, debugger->d.currentBreakpoint->sw.mode, &debugger->d.currentBreakpoint->sw.opcode);
|
||||
}
|
||||
debugger->d.currentBreakpoint = 0;
|
||||
}
|
||||
ARMRun(debugger->d.cpu);
|
||||
debugger->d.core->step(debugger->d.core);
|
||||
_printStatus(debugger, 0);
|
||||
}
|
||||
|
||||
static void _disassemble(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||
_disassembleMode(debugger, dv, debugger->d.cpu->executionMode);
|
||||
}
|
||||
|
||||
static void _disassembleArm(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||
_disassembleMode(debugger, dv, MODE_ARM);
|
||||
}
|
||||
|
||||
static void _disassembleThumb(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||
_disassembleMode(debugger, dv, MODE_THUMB);
|
||||
}
|
||||
|
||||
static void _disassembleMode(struct CLIDebugger* debugger, struct CLIDebugVector* dv, enum ExecutionMode mode) {
|
||||
uint32_t address;
|
||||
int size;
|
||||
int wordSize;
|
||||
|
||||
if (mode == MODE_ARM) {
|
||||
wordSize = WORD_SIZE_ARM;
|
||||
} else {
|
||||
wordSize = WORD_SIZE_THUMB;
|
||||
}
|
||||
|
||||
if (!dv || dv->type != CLIDV_INT_TYPE) {
|
||||
address = debugger->d.cpu->gprs[ARM_PC] - wordSize;
|
||||
} else {
|
||||
address = dv->intValue;
|
||||
dv = dv->next;
|
||||
}
|
||||
|
||||
if (!dv || dv->type != CLIDV_INT_TYPE) {
|
||||
size = 1;
|
||||
} else {
|
||||
size = dv->intValue;
|
||||
dv = dv->next; // TODO: Check for excess args
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i = 0; i < size; ++i) {
|
||||
address += _printLine(debugger, address, mode);;
|
||||
}
|
||||
debugger->system->disassemble(debugger->system, dv);
|
||||
}
|
||||
|
||||
static void _print(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||
|
@ -234,12 +163,16 @@ static void _printHelp(struct CLIDebugger* debugger, struct CLIDebugVector* dv)
|
|||
UNUSED(debugger);
|
||||
UNUSED(dv);
|
||||
if (!dv) {
|
||||
puts("ARM commands:");
|
||||
puts("Generic commands:");
|
||||
int i;
|
||||
for (i = 0; _debuggerCommands[i].name; ++i) {
|
||||
printf("%-10s %s\n", _debuggerCommands[i].name, _debuggerCommands[i].summary);
|
||||
}
|
||||
if (debugger->system) {
|
||||
printf("%s commands:\n", debugger->system->platformName);
|
||||
for (i = 0; debugger->system->platformCommands[i].name; ++i) {
|
||||
printf("%-10s %s\n", debugger->system->platformCommands[i].name, debugger->system->platformCommands[i].summary);
|
||||
}
|
||||
printf("%s commands:\n", debugger->system->name);
|
||||
for (i = 0; debugger->system->commands[i].name; ++i) {
|
||||
printf("%-10s %s\n", debugger->system->commands[i].name, debugger->system->commands[i].summary);
|
||||
|
@ -253,7 +186,11 @@ static void _printHelp(struct CLIDebugger* debugger, struct CLIDebugVector* dv)
|
|||
}
|
||||
}
|
||||
if (debugger->system) {
|
||||
printf("\n%s commands:\n", debugger->system->name);
|
||||
for (i = 0; debugger->system->platformCommands[i].name; ++i) {
|
||||
if (strcmp(debugger->system->platformCommands[i].name, dv->charValue) == 0) {
|
||||
printf(" %s\n", debugger->system->platformCommands[i].summary);
|
||||
}
|
||||
}
|
||||
for (i = 0; debugger->system->commands[i].name; ++i) {
|
||||
if (strcmp(debugger->system->commands[i].name, dv->charValue) == 0) {
|
||||
printf(" %s\n", debugger->system->commands[i].summary);
|
||||
|
@ -263,56 +200,6 @@ static void _printHelp(struct CLIDebugger* debugger, struct CLIDebugVector* dv)
|
|||
}
|
||||
}
|
||||
|
||||
static inline uint32_t _printLine(struct CLIDebugger* debugger, uint32_t address, enum ExecutionMode mode) {
|
||||
char disassembly[48];
|
||||
struct ARMInstructionInfo info;
|
||||
printf("%08X: ", address);
|
||||
if (mode == MODE_ARM) {
|
||||
uint32_t instruction = debugger->d.cpu->memory.load32(debugger->d.cpu, address, 0);
|
||||
ARMDecodeARM(instruction, &info);
|
||||
ARMDisassemble(&info, address + WORD_SIZE_ARM * 2, disassembly, sizeof(disassembly));
|
||||
printf("%08X\t%s\n", instruction, disassembly);
|
||||
return WORD_SIZE_ARM;
|
||||
} else {
|
||||
struct ARMInstructionInfo info2;
|
||||
struct ARMInstructionInfo combined;
|
||||
uint16_t instruction = debugger->d.cpu->memory.load16(debugger->d.cpu, address, 0);
|
||||
uint16_t instruction2 = debugger->d.cpu->memory.load16(debugger->d.cpu, address + WORD_SIZE_THUMB, 0);
|
||||
ARMDecodeThumb(instruction, &info);
|
||||
ARMDecodeThumb(instruction2, &info2);
|
||||
if (ARMDecodeThumbCombine(&info, &info2, &combined)) {
|
||||
ARMDisassemble(&combined, address + WORD_SIZE_THUMB * 2, disassembly, sizeof(disassembly));
|
||||
printf("%04X %04X\t%s\n", instruction, instruction2, disassembly);
|
||||
return WORD_SIZE_THUMB * 2;
|
||||
} else {
|
||||
ARMDisassemble(&info, address + WORD_SIZE_THUMB * 2, disassembly, sizeof(disassembly));
|
||||
printf("%04X \t%s\n", instruction, disassembly);
|
||||
return WORD_SIZE_THUMB;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void _printStatus(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||
UNUSED(dv);
|
||||
int r;
|
||||
for (r = 0; r < 4; ++r) {
|
||||
printf("%08X %08X %08X %08X\n",
|
||||
debugger->d.cpu->gprs[r << 2],
|
||||
debugger->d.cpu->gprs[(r << 2) + 1],
|
||||
debugger->d.cpu->gprs[(r << 2) + 2],
|
||||
debugger->d.cpu->gprs[(r << 2) + 3]);
|
||||
}
|
||||
_printPSR(debugger->d.cpu->cpsr);
|
||||
int instructionLength;
|
||||
enum ExecutionMode mode = debugger->d.cpu->cpsr.t;
|
||||
if (mode == MODE_ARM) {
|
||||
instructionLength = WORD_SIZE_ARM;
|
||||
} else {
|
||||
instructionLength = WORD_SIZE_THUMB;
|
||||
}
|
||||
_printLine(debugger, debugger->d.cpu->gprs[ARM_PC] - instructionLength, mode);
|
||||
}
|
||||
|
||||
static void _quit(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||
UNUSED(dv);
|
||||
debugger->d.state = DEBUGGER_SHUTDOWN;
|
||||
|
@ -324,13 +211,13 @@ static void _readByte(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
|||
return;
|
||||
}
|
||||
uint32_t address = dv->intValue;
|
||||
uint8_t value = debugger->d.cpu->memory.load8(debugger->d.cpu, address, 0);
|
||||
uint8_t value = debugger->d.core->busRead8(debugger->d.core, address);
|
||||
printf(" 0x%02X\n", value);
|
||||
}
|
||||
|
||||
static void _reset(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||
UNUSED(dv);
|
||||
ARMReset(debugger->d.cpu);
|
||||
debugger->d.core->reset(debugger->d.core);
|
||||
_printStatus(debugger, 0);
|
||||
}
|
||||
|
||||
|
@ -340,7 +227,7 @@ static void _readHalfword(struct CLIDebugger* debugger, struct CLIDebugVector* d
|
|||
return;
|
||||
}
|
||||
uint32_t address = dv->intValue;
|
||||
uint16_t value = debugger->d.cpu->memory.load16(debugger->d.cpu, address & ~1, 0);
|
||||
uint16_t value = debugger->d.core->busRead16(debugger->d.core, address & ~1);
|
||||
printf(" 0x%04X\n", value);
|
||||
}
|
||||
|
||||
|
@ -350,7 +237,7 @@ static void _readWord(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
|||
return;
|
||||
}
|
||||
uint32_t address = dv->intValue;
|
||||
uint32_t value = debugger->d.cpu->memory.load32(debugger->d.cpu, address & ~3, 0);
|
||||
uint32_t value = debugger->d.core->busRead32(debugger->d.core, address & ~3);
|
||||
printf(" 0x%08X\n", value);
|
||||
}
|
||||
|
||||
|
@ -369,7 +256,7 @@ static void _writeByte(struct CLIDebugger* debugger, struct CLIDebugVector* dv)
|
|||
printf("%s\n", ERROR_OVERFLOW);
|
||||
return;
|
||||
}
|
||||
debugger->d.cpu->memory.store8(debugger->d.cpu, address, value, 0);
|
||||
debugger->d.core->busWrite8(debugger->d.core, address, value);
|
||||
}
|
||||
|
||||
static void _writeHalfword(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||
|
@ -387,7 +274,7 @@ static void _writeHalfword(struct CLIDebugger* debugger, struct CLIDebugVector*
|
|||
printf("%s\n", ERROR_OVERFLOW);
|
||||
return;
|
||||
}
|
||||
debugger->d.cpu->memory.store16(debugger->d.cpu, address, value, 0);
|
||||
debugger->d.core->busWrite16(debugger->d.core, address, value);
|
||||
}
|
||||
|
||||
static void _writeWord(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||
|
@ -401,24 +288,7 @@ static void _writeWord(struct CLIDebugger* debugger, struct CLIDebugVector* dv)
|
|||
}
|
||||
uint32_t address = dv->intValue;
|
||||
uint32_t value = dv->next->intValue;
|
||||
debugger->d.cpu->memory.store32(debugger->d.cpu, address, value, 0);
|
||||
}
|
||||
|
||||
static void _writeRegister(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||
if (!dv || dv->type != CLIDV_INT_TYPE) {
|
||||
printf("%s\n", ERROR_MISSING_ARGS);
|
||||
return;
|
||||
}
|
||||
if (!dv->next || dv->next->type != CLIDV_INT_TYPE) {
|
||||
printf("%s\n", ERROR_MISSING_ARGS);
|
||||
return;
|
||||
}
|
||||
uint32_t regid = dv->intValue;
|
||||
uint32_t value = dv->next->intValue;
|
||||
if (regid >= ARM_PC) {
|
||||
return;
|
||||
}
|
||||
debugger->d.cpu->gprs[regid] = value;
|
||||
debugger->d.core->busWrite32(debugger->d.core, address, value);
|
||||
}
|
||||
|
||||
static void _dumpByte(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||
|
@ -438,7 +308,7 @@ static void _dumpByte(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
|||
}
|
||||
printf("0x%08X:", address);
|
||||
for (; line > 0; --line, ++address, --words) {
|
||||
uint32_t value = debugger->d.cpu->memory.load8(debugger->d.cpu, address, 0);
|
||||
uint32_t value = debugger->d.core->busRead8(debugger->d.core, address);
|
||||
printf(" %02X", value);
|
||||
}
|
||||
printf("\n");
|
||||
|
@ -462,7 +332,7 @@ static void _dumpHalfword(struct CLIDebugger* debugger, struct CLIDebugVector* d
|
|||
}
|
||||
printf("0x%08X:", address);
|
||||
for (; line > 0; --line, address += 2, --words) {
|
||||
uint32_t value = debugger->d.cpu->memory.load16(debugger->d.cpu, address, 0);
|
||||
uint32_t value = debugger->d.core->busRead16(debugger->d.core, address);
|
||||
printf(" %04X", value);
|
||||
}
|
||||
printf("\n");
|
||||
|
@ -486,7 +356,7 @@ static void _dumpWord(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
|||
}
|
||||
printf("0x%08X:", address);
|
||||
for (; line > 0; --line, address += 4, --words) {
|
||||
uint32_t value = debugger->d.cpu->memory.load32(debugger->d.cpu, address, 0);
|
||||
uint32_t value = debugger->d.core->busRead32(debugger->d.core, address);
|
||||
printf(" %08X", value);
|
||||
}
|
||||
printf("\n");
|
||||
|
@ -499,35 +369,7 @@ static void _setBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector*
|
|||
return;
|
||||
}
|
||||
uint32_t address = dv->intValue;
|
||||
DebuggerSetBreakpoint(&debugger->d, address);
|
||||
}
|
||||
|
||||
static void _setBreakpointARM(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||
if (!dv || dv->type != CLIDV_INT_TYPE) {
|
||||
printf("%s\n", ERROR_MISSING_ARGS);
|
||||
return;
|
||||
}
|
||||
uint32_t address = dv->intValue;
|
||||
DebuggerSetSoftwareBreakpoint(&debugger->d, address, MODE_ARM);
|
||||
}
|
||||
|
||||
static void _setBreakpointThumb(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||
if (!dv || dv->type != CLIDV_INT_TYPE) {
|
||||
printf("%s\n", ERROR_MISSING_ARGS);
|
||||
return;
|
||||
}
|
||||
uint32_t address = dv->intValue;
|
||||
DebuggerSetSoftwareBreakpoint(&debugger->d, address, MODE_THUMB);
|
||||
}
|
||||
|
||||
static void _clearBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||
if (!dv || dv->type != CLIDV_INT_TYPE) {
|
||||
printf("%s\n", ERROR_MISSING_ARGS);
|
||||
return;
|
||||
}
|
||||
uint32_t address = dv->intValue;
|
||||
DebuggerClearBreakpoint(&debugger->d, address);
|
||||
DebuggerClearWatchpoint(&debugger->d, address);
|
||||
debugger->d.platform->setBreakpoint(debugger->d.platform, address);
|
||||
}
|
||||
|
||||
static void _setWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||
|
@ -536,12 +378,27 @@ static void _setWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector*
|
|||
return;
|
||||
}
|
||||
uint32_t address = dv->intValue;
|
||||
DebuggerSetWatchpoint(&debugger->d, address, WATCHPOINT_RW); // TODO: ro/wo
|
||||
debugger->d.platform->setWatchpoint(debugger->d.platform, address, WATCHPOINT_RW); // TODO: ro/wo
|
||||
}
|
||||
|
||||
static void _clearBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||
if (!dv || dv->type != CLIDV_INT_TYPE) {
|
||||
printf("%s\n", ERROR_MISSING_ARGS);
|
||||
return;
|
||||
}
|
||||
uint32_t address = dv->intValue;
|
||||
debugger->d.platform->clearBreakpoint(debugger->d.platform, address);
|
||||
debugger->d.platform->clearWatchpoint(debugger->d.platform, address);
|
||||
}
|
||||
|
||||
static void _breakIntoDefault(int signal) {
|
||||
UNUSED(signal);
|
||||
DebuggerEnter(&_activeDebugger->d, DEBUGGER_ENTER_MANUAL, 0);
|
||||
mDebuggerEnter(&_activeDebugger->d, DEBUGGER_ENTER_MANUAL, 0);
|
||||
}
|
||||
|
||||
static void _printStatus(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||
UNUSED(dv);
|
||||
debugger->system->printStatus(debugger->system);
|
||||
}
|
||||
|
||||
static uint32_t _performOperation(enum Operation operation, uint32_t current, uint32_t next, struct CLIDebugVector* dv) {
|
||||
|
@ -570,30 +427,8 @@ static uint32_t _performOperation(enum Operation operation, uint32_t current, ui
|
|||
return current;
|
||||
}
|
||||
|
||||
static uint32_t _lookupIdentifier(struct Debugger* debugger, const char* name, struct CLIDebugVector* dv) {
|
||||
static uint32_t _lookupIdentifier(struct mDebugger* debugger, const char* name, struct CLIDebugVector* dv) {
|
||||
struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
|
||||
if (strcmp(name, "sp") == 0) {
|
||||
return debugger->cpu->gprs[ARM_SP];
|
||||
}
|
||||
if (strcmp(name, "lr") == 0) {
|
||||
return debugger->cpu->gprs[ARM_LR];
|
||||
}
|
||||
if (strcmp(name, "pc") == 0) {
|
||||
return debugger->cpu->gprs[ARM_PC];
|
||||
}
|
||||
if (strcmp(name, "cpsr") == 0) {
|
||||
return debugger->cpu->cpsr.packed;
|
||||
}
|
||||
// TODO: test if mode has SPSR
|
||||
if (strcmp(name, "spsr") == 0) {
|
||||
return debugger->cpu->spsr.packed;
|
||||
}
|
||||
if (name[0] == 'r' && name[1] >= '0' && name[1] <= '9') {
|
||||
int reg = atoi(&name[1]);
|
||||
if (reg < 16) {
|
||||
return debugger->cpu->gprs[reg];
|
||||
}
|
||||
}
|
||||
if (cliDebugger->system) {
|
||||
uint32_t value = cliDebugger->system->lookupIdentifier(cliDebugger->system, name, dv);
|
||||
if (dv->type != CLIDV_ERROR_TYPE) {
|
||||
|
@ -605,7 +440,7 @@ static uint32_t _lookupIdentifier(struct Debugger* debugger, const char* name, s
|
|||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t _evaluateParseTree(struct Debugger* debugger, struct ParseTree* tree, struct CLIDebugVector* dv) {
|
||||
static uint32_t _evaluateParseTree(struct mDebugger* debugger, struct ParseTree* tree, struct CLIDebugVector* dv) {
|
||||
switch (tree->token.type) {
|
||||
case TOKEN_UINT_TYPE:
|
||||
return tree->token.uintValue;
|
||||
|
@ -753,6 +588,9 @@ static bool _parse(struct CLIDebugger* debugger, const char* line, size_t count)
|
|||
int result = _tryCommands(debugger, _debuggerCommands, line, cmdLength, args, count - cmdLength - 1);
|
||||
if (result < 0 && debugger->system) {
|
||||
result = _tryCommands(debugger, debugger->system->commands, line, cmdLength, args, count - cmdLength - 1);
|
||||
if (result < 0) {
|
||||
result = _tryCommands(debugger, debugger->system->platformCommands, line, cmdLength, args, count - cmdLength - 1);
|
||||
}
|
||||
}
|
||||
if (result < 0) {
|
||||
printf("Command not found\n");
|
||||
|
@ -765,7 +603,7 @@ static char* _prompt(EditLine* el) {
|
|||
return "> ";
|
||||
}
|
||||
|
||||
static void _commandLine(struct Debugger* debugger) {
|
||||
static void _commandLine(struct mDebugger* debugger) {
|
||||
struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
|
||||
const char* line;
|
||||
_printStatus(cliDebugger, 0);
|
||||
|
@ -787,7 +625,7 @@ static void _commandLine(struct Debugger* debugger) {
|
|||
}
|
||||
}
|
||||
|
||||
static void _reportEntry(struct Debugger* debugger, enum DebuggerEntryReason reason, struct DebuggerEntryInfo* info) {
|
||||
static void _reportEntry(struct mDebugger* debugger, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) {
|
||||
UNUSED(debugger);
|
||||
switch (reason) {
|
||||
case DEBUGGER_ENTER_MANUAL:
|
||||
|
@ -874,7 +712,7 @@ static unsigned char _tabComplete(EditLine* elstate, int ch) {
|
|||
return CC_REDISPLAY;
|
||||
}
|
||||
|
||||
static void _cliDebuggerInit(struct Debugger* debugger) {
|
||||
static void _cliDebuggerInit(struct mDebugger* debugger) {
|
||||
struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
|
||||
// TODO: get argv[0]
|
||||
cliDebugger->elstate = el_init(binaryName, stdin, stdout, stderr);
|
||||
|
@ -892,7 +730,7 @@ static void _cliDebuggerInit(struct Debugger* debugger) {
|
|||
signal(SIGINT, _breakIntoDefault);
|
||||
}
|
||||
|
||||
static void _cliDebuggerDeinit(struct Debugger* debugger) {
|
||||
static void _cliDebuggerDeinit(struct mDebugger* debugger) {
|
||||
struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
|
||||
history_end(cliDebugger->histate);
|
||||
el_end(cliDebugger->elstate);
|
||||
|
@ -904,7 +742,7 @@ static void _cliDebuggerDeinit(struct Debugger* debugger) {
|
|||
}
|
||||
}
|
||||
|
||||
static void _cliDebuggerCustom(struct Debugger* debugger) {
|
||||
static void _cliDebuggerCustom(struct mDebugger* debugger) {
|
||||
struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
|
||||
bool retain = false;
|
||||
if (cliDebugger->system) {
|
||||
|
@ -916,7 +754,6 @@ static void _cliDebuggerCustom(struct Debugger* debugger) {
|
|||
}
|
||||
|
||||
void CLIDebuggerCreate(struct CLIDebugger* debugger) {
|
||||
DebuggerCreate(&debugger->d);
|
||||
debugger->d.init = _cliDebuggerInit;
|
||||
debugger->d.deinit = _cliDebuggerDeinit;
|
||||
debugger->d.custom = _cliDebuggerCustom;
|
||||
|
@ -935,3 +772,5 @@ void CLIDebuggerAttachSystem(struct CLIDebugger* debugger, struct CLIDebuggerSys
|
|||
debugger->system = system;
|
||||
system->p = debugger;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -45,14 +45,18 @@ struct CLIDebuggerSystem {
|
|||
void (*deinit)(struct CLIDebuggerSystem*);
|
||||
bool (*custom)(struct CLIDebuggerSystem*);
|
||||
|
||||
void (*disassemble)(struct CLIDebuggerSystem*, struct CLIDebugVector* dv);
|
||||
uint32_t (*lookupIdentifier)(struct CLIDebuggerSystem*, const char* name, struct CLIDebugVector* dv);
|
||||
void (*printStatus)(struct CLIDebuggerSystem*);
|
||||
|
||||
struct CLIDebuggerCommandSummary* commands;
|
||||
const char* name;
|
||||
struct CLIDebuggerCommandSummary* platformCommands;
|
||||
const char* platformName;
|
||||
};
|
||||
|
||||
struct CLIDebugger {
|
||||
struct Debugger d;
|
||||
struct mDebugger d;
|
||||
|
||||
struct CLIDebuggerSystem* system;
|
||||
|
||||
|
|
|
@ -1,94 +1,92 @@
|
|||
/* Copyright (c) 2013-2014 Jeffrey Pfau
|
||||
/* Copyright (c) 2013-2016 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "debugger.h"
|
||||
|
||||
#include "arm.h"
|
||||
#include "isa-inlines.h"
|
||||
#include "core/core.h"
|
||||
|
||||
#include "memory-debugger.h"
|
||||
#ifdef USE_CLI_DEBUGGER
|
||||
#include "debugger/cli-debugger.h"
|
||||
#include "gba/supervisor/cli.h"
|
||||
#endif
|
||||
|
||||
#ifdef USE_GDB_STUB
|
||||
#include "debugger/gdb-stub.h"
|
||||
#endif
|
||||
|
||||
const uint32_t DEBUGGER_ID = 0xDEADBEEF;
|
||||
|
||||
DEFINE_VECTOR(DebugBreakpointList, struct DebugBreakpoint);
|
||||
DEFINE_VECTOR(DebugWatchpointList, struct DebugWatchpoint);
|
||||
|
||||
mLOG_DEFINE_CATEGORY(DEBUGGER, "Debugger");
|
||||
|
||||
static struct DebugBreakpoint* _lookupBreakpoint(struct DebugBreakpointList* breakpoints, uint32_t address) {
|
||||
size_t i;
|
||||
for (i = 0; i < DebugBreakpointListSize(breakpoints); ++i) {
|
||||
if (DebugBreakpointListGetPointer(breakpoints, i)->address == address) {
|
||||
return DebugBreakpointListGetPointer(breakpoints, i);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static void mDebuggerInit(void* cpu, struct mCPUComponent* component);
|
||||
static void mDebuggerDeinit(struct mCPUComponent* component);
|
||||
|
||||
static void _checkBreakpoints(struct Debugger* debugger) {
|
||||
int instructionLength;
|
||||
enum ExecutionMode mode = debugger->cpu->cpsr.t;
|
||||
if (mode == MODE_ARM) {
|
||||
instructionLength = WORD_SIZE_ARM;
|
||||
} else {
|
||||
instructionLength = WORD_SIZE_THUMB;
|
||||
struct mDebugger* mDebuggerCreate(enum mDebuggerType type, struct mCore* core) {
|
||||
if (!core->supportsDebuggerType(core, type)) {
|
||||
return NULL;
|
||||
}
|
||||
struct DebugBreakpoint* breakpoint = _lookupBreakpoint(&debugger->breakpoints, debugger->cpu->gprs[ARM_PC] - instructionLength);
|
||||
if (!breakpoint) {
|
||||
return;
|
||||
}
|
||||
struct DebuggerEntryInfo info = {
|
||||
.address = breakpoint->address
|
||||
|
||||
union DebugUnion {
|
||||
struct mDebugger d;
|
||||
#ifdef USE_CLI_DEBUGGER
|
||||
struct CLIDebugger cli;
|
||||
#endif
|
||||
#ifdef USE_GDB_STUB
|
||||
struct GDBStub gdb;
|
||||
#endif
|
||||
};
|
||||
DebuggerEnter(debugger, DEBUGGER_ENTER_BREAKPOINT, &info);
|
||||
}
|
||||
|
||||
static void DebuggerInit(void* cpu, struct mCPUComponent*);
|
||||
static void DebuggerDeinit(struct mCPUComponent*);
|
||||
union DebugUnion* debugger = malloc(sizeof(union DebugUnion));
|
||||
|
||||
void DebuggerCreate(struct Debugger* debugger) {
|
||||
debugger->d.id = DEBUGGER_ID;
|
||||
debugger->d.init = DebuggerInit;
|
||||
debugger->d.deinit = DebuggerDeinit;
|
||||
}
|
||||
|
||||
void DebuggerInit(void* cpu, struct mCPUComponent* component) {
|
||||
struct Debugger* debugger = (struct Debugger*) component;
|
||||
debugger->cpu = cpu;
|
||||
debugger->state = DEBUGGER_RUNNING;
|
||||
debugger->originalMemory = debugger->cpu->memory;
|
||||
debugger->currentBreakpoint = 0;
|
||||
DebugBreakpointListInit(&debugger->breakpoints, 0);
|
||||
DebugBreakpointListInit(&debugger->swBreakpoints, 0);
|
||||
DebugWatchpointListInit(&debugger->watchpoints, 0);
|
||||
if (debugger->init) {
|
||||
debugger->init(debugger);
|
||||
switch (type) {
|
||||
#ifdef USE_CLI_DEBUGGER
|
||||
case DEBUGGER_CLI:
|
||||
CLIDebuggerCreate(&debugger->cli);
|
||||
struct CLIDebuggerSystem* sys = core->cliDebuggerSystem(core);
|
||||
CLIDebuggerAttachSystem(&debugger->cli, sys);
|
||||
break;
|
||||
#endif
|
||||
#ifdef USE_GDB_STUB
|
||||
case DEBUGGER_GDB:
|
||||
GDBStubCreate(&debugger->gdb);
|
||||
GDBStubListen(&debugger->gdb, 2345, 0);
|
||||
break;
|
||||
#endif
|
||||
case DEBUGGER_NONE:
|
||||
case DEBUGGER_MAX:
|
||||
free(debugger);
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return &debugger->d;
|
||||
}
|
||||
|
||||
void DebuggerDeinit(struct mCPUComponent* component) {
|
||||
struct Debugger* debugger = (struct Debugger*) component;
|
||||
debugger->deinit(debugger);
|
||||
DebugBreakpointListDeinit(&debugger->breakpoints);
|
||||
DebugBreakpointListDeinit(&debugger->swBreakpoints);
|
||||
DebugWatchpointListDeinit(&debugger->watchpoints);
|
||||
void mDebuggerAttach(struct mDebugger* debugger, struct mCore* core) {
|
||||
debugger->d.id = DEBUGGER_ID;
|
||||
debugger->d.init = mDebuggerInit;
|
||||
debugger->d.deinit = mDebuggerDeinit;
|
||||
debugger->core = core;
|
||||
debugger->platform = core->debuggerPlatform(core);
|
||||
debugger->platform->p = debugger;
|
||||
core->attachDebugger(core, debugger);
|
||||
}
|
||||
|
||||
void DebuggerRun(struct Debugger* debugger) {
|
||||
void mDebuggerRun(struct mDebugger* debugger) {
|
||||
switch (debugger->state) {
|
||||
case DEBUGGER_RUNNING:
|
||||
if (!DebugBreakpointListSize(&debugger->breakpoints) && !DebugWatchpointListSize(&debugger->watchpoints)) {
|
||||
ARMRunLoop(debugger->cpu);
|
||||
if (!debugger->platform->hasBreakpoints(debugger->platform)) {
|
||||
debugger->core->runLoop(debugger->core);
|
||||
} else {
|
||||
ARMRun(debugger->cpu);
|
||||
_checkBreakpoints(debugger);
|
||||
debugger->core->step(debugger->core);
|
||||
debugger->platform->checkBreakpoints(debugger->platform);
|
||||
}
|
||||
break;
|
||||
case DEBUGGER_CUSTOM:
|
||||
ARMRun(debugger->cpu);
|
||||
_checkBreakpoints(debugger);
|
||||
debugger->core->step(debugger->core);
|
||||
debugger->platform->checkBreakpoints(debugger->platform);
|
||||
debugger->custom(debugger);
|
||||
break;
|
||||
case DEBUGGER_PAUSED:
|
||||
|
@ -97,89 +95,32 @@ void DebuggerRun(struct Debugger* debugger) {
|
|||
} else {
|
||||
debugger->state = DEBUGGER_RUNNING;
|
||||
}
|
||||
if (debugger->state != DEBUGGER_PAUSED && debugger->currentBreakpoint) {
|
||||
if (debugger->currentBreakpoint->isSw && debugger->setSoftwareBreakpoint) {
|
||||
debugger->setSoftwareBreakpoint(debugger, debugger->currentBreakpoint->address, debugger->currentBreakpoint->sw.mode, &debugger->currentBreakpoint->sw.opcode);
|
||||
}
|
||||
debugger->currentBreakpoint = 0;
|
||||
}
|
||||
break;
|
||||
case DEBUGGER_SHUTDOWN:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void DebuggerEnter(struct Debugger* debugger, enum DebuggerEntryReason reason, struct DebuggerEntryInfo* info) {
|
||||
void mDebuggerEnter(struct mDebugger* debugger, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) {
|
||||
debugger->state = DEBUGGER_PAUSED;
|
||||
struct ARMCore* cpu = debugger->cpu;
|
||||
cpu->nextEvent = cpu->cycles;
|
||||
if (reason == DEBUGGER_ENTER_BREAKPOINT) {
|
||||
struct DebugBreakpoint* breakpoint = _lookupBreakpoint(&debugger->swBreakpoints, _ARMPCAddress(cpu));
|
||||
debugger->currentBreakpoint = breakpoint;
|
||||
if (breakpoint && breakpoint->isSw) {
|
||||
info->address = breakpoint->address;
|
||||
if (debugger->clearSoftwareBreakpoint) {
|
||||
debugger->clearSoftwareBreakpoint(debugger, breakpoint->address, breakpoint->sw.mode, breakpoint->sw.opcode);
|
||||
}
|
||||
|
||||
ARMRunFake(cpu, breakpoint->sw.opcode);
|
||||
}
|
||||
}
|
||||
if (debugger->entered) {
|
||||
debugger->entered(debugger, reason, info);
|
||||
}
|
||||
}
|
||||
|
||||
void DebuggerSetBreakpoint(struct Debugger* debugger, uint32_t address) {
|
||||
struct DebugBreakpoint* breakpoint = DebugBreakpointListAppend(&debugger->breakpoints);
|
||||
breakpoint->address = address;
|
||||
breakpoint->isSw = false;
|
||||
}
|
||||
|
||||
bool DebuggerSetSoftwareBreakpoint(struct Debugger* debugger, uint32_t address, enum ExecutionMode mode) {
|
||||
uint32_t opcode;
|
||||
if (!debugger->setSoftwareBreakpoint || !debugger->setSoftwareBreakpoint(debugger, address, mode, &opcode)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct DebugBreakpoint* breakpoint = DebugBreakpointListAppend(&debugger->swBreakpoints);
|
||||
breakpoint->address = address;
|
||||
breakpoint->isSw = true;
|
||||
breakpoint->sw.opcode = opcode;
|
||||
breakpoint->sw.mode = mode;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DebuggerClearBreakpoint(struct Debugger* debugger, uint32_t address) {
|
||||
struct DebugBreakpointList* breakpoints = &debugger->breakpoints;
|
||||
size_t i;
|
||||
for (i = 0; i < DebugBreakpointListSize(breakpoints); ++i) {
|
||||
if (DebugBreakpointListGetPointer(breakpoints, i)->address == address) {
|
||||
DebugBreakpointListShift(breakpoints, i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void DebuggerSetWatchpoint(struct Debugger* debugger, uint32_t address, enum WatchpointType type) {
|
||||
if (!DebugWatchpointListSize(&debugger->watchpoints)) {
|
||||
DebuggerInstallMemoryShim(debugger);
|
||||
}
|
||||
struct DebugWatchpoint* watchpoint = DebugWatchpointListAppend(&debugger->watchpoints);
|
||||
watchpoint->address = address;
|
||||
watchpoint->type = type;
|
||||
}
|
||||
|
||||
void DebuggerClearWatchpoint(struct Debugger* debugger, uint32_t address) {
|
||||
struct DebugWatchpointList* watchpoints = &debugger->watchpoints;
|
||||
size_t i;
|
||||
for (i = 0; i < DebugWatchpointListSize(watchpoints); ++i) {
|
||||
if (DebugWatchpointListGetPointer(watchpoints, i)->address == address) {
|
||||
DebugWatchpointListShift(watchpoints, i, 1);
|
||||
}
|
||||
}
|
||||
if (!DebugWatchpointListSize(&debugger->watchpoints)) {
|
||||
DebuggerRemoveMemoryShim(debugger);
|
||||
static void mDebuggerInit(void* cpu, struct mCPUComponent* component) {
|
||||
struct mDebugger* debugger = (struct mDebugger*) component;
|
||||
debugger->state = DEBUGGER_RUNNING;
|
||||
debugger->platform->init(cpu, debugger->platform);
|
||||
if (debugger->init) {
|
||||
debugger->init(debugger);
|
||||
}
|
||||
}
|
||||
|
||||
static void mDebuggerDeinit(struct mCPUComponent* component) {
|
||||
struct mDebugger* debugger = (struct mDebugger*) component;
|
||||
if (debugger->deinit) {
|
||||
debugger->deinit(debugger);
|
||||
}
|
||||
debugger->platform->deinit(debugger->platform);
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ mLOG_DECLARE_CATEGORY(DEBUGGER);
|
|||
|
||||
extern const uint32_t DEBUGGER_ID;
|
||||
|
||||
enum DebuggerType {
|
||||
enum mDebuggerType {
|
||||
DEBUGGER_NONE = 0,
|
||||
#ifdef USE_CLI_DEBUGGER
|
||||
DEBUGGER_CLI,
|
||||
|
@ -27,37 +27,20 @@ enum DebuggerType {
|
|||
DEBUGGER_MAX
|
||||
};
|
||||
|
||||
enum DebuggerState {
|
||||
enum mDebuggerState {
|
||||
DEBUGGER_PAUSED,
|
||||
DEBUGGER_RUNNING,
|
||||
DEBUGGER_CUSTOM,
|
||||
DEBUGGER_SHUTDOWN
|
||||
};
|
||||
|
||||
struct DebugBreakpoint {
|
||||
uint32_t address;
|
||||
bool isSw;
|
||||
struct {
|
||||
uint32_t opcode;
|
||||
enum ExecutionMode mode;
|
||||
} sw;
|
||||
};
|
||||
|
||||
enum WatchpointType {
|
||||
enum mWatchpointType {
|
||||
WATCHPOINT_WRITE = 1,
|
||||
WATCHPOINT_READ = 2,
|
||||
WATCHPOINT_RW = WATCHPOINT_WRITE | WATCHPOINT_READ
|
||||
};
|
||||
|
||||
struct DebugWatchpoint {
|
||||
uint32_t address;
|
||||
enum WatchpointType type;
|
||||
};
|
||||
|
||||
DECLARE_VECTOR(DebugBreakpointList, struct DebugBreakpoint);
|
||||
DECLARE_VECTOR(DebugWatchpointList, struct DebugWatchpoint);
|
||||
|
||||
enum DebuggerEntryReason {
|
||||
enum mDebuggerEntryReason {
|
||||
DEBUGGER_ENTER_MANUAL,
|
||||
DEBUGGER_ENTER_ATTACHED,
|
||||
DEBUGGER_ENTER_BREAKPOINT,
|
||||
|
@ -65,14 +48,17 @@ enum DebuggerEntryReason {
|
|||
DEBUGGER_ENTER_ILLEGAL_OP
|
||||
};
|
||||
|
||||
struct DebuggerEntryInfo {
|
||||
extern const char* ERROR_MISSING_ARGS;
|
||||
extern const char* ERROR_OVERFLOW;
|
||||
|
||||
struct mDebuggerEntryInfo {
|
||||
uint32_t address;
|
||||
union {
|
||||
struct {
|
||||
uint32_t oldValue;
|
||||
uint32_t newValue;
|
||||
enum WatchpointType watchType;
|
||||
enum WatchpointType accessType;
|
||||
enum mWatchpointType watchType;
|
||||
enum mWatchpointType accessType;
|
||||
};
|
||||
|
||||
struct {
|
||||
|
@ -81,35 +67,40 @@ struct DebuggerEntryInfo {
|
|||
};
|
||||
};
|
||||
|
||||
struct Debugger {
|
||||
struct mCPUComponent d;
|
||||
enum DebuggerState state;
|
||||
struct ARMCore* cpu;
|
||||
struct mDebugger;
|
||||
struct mDebuggerPlatform {
|
||||
struct mDebugger* p;
|
||||
|
||||
struct DebugBreakpointList breakpoints;
|
||||
struct DebugBreakpointList swBreakpoints;
|
||||
struct DebugWatchpointList watchpoints;
|
||||
struct ARMMemory originalMemory;
|
||||
void (*init)(void* cpu, struct mDebuggerPlatform*);
|
||||
void (*deinit)(struct mDebuggerPlatform*);
|
||||
void (*entered)(struct mDebuggerPlatform*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*);
|
||||
|
||||
struct DebugBreakpoint* currentBreakpoint;
|
||||
|
||||
void (*init)(struct Debugger*);
|
||||
void (*deinit)(struct Debugger*);
|
||||
void (*paused)(struct Debugger*);
|
||||
void (*entered)(struct Debugger*, enum DebuggerEntryReason, struct DebuggerEntryInfo*);
|
||||
void (*custom)(struct Debugger*);
|
||||
|
||||
bool (*setSoftwareBreakpoint)(struct Debugger*, uint32_t address, enum ExecutionMode mode, uint32_t* opcode);
|
||||
bool (*clearSoftwareBreakpoint)(struct Debugger*, uint32_t address, enum ExecutionMode mode, uint32_t opcode);
|
||||
bool (*hasBreakpoints)(struct mDebuggerPlatform*);
|
||||
void (*setBreakpoint)(struct mDebuggerPlatform*, uint32_t address);
|
||||
void (*clearBreakpoint)(struct mDebuggerPlatform*, uint32_t address);
|
||||
void (*setWatchpoint)(struct mDebuggerPlatform*, uint32_t address, enum mWatchpointType type);
|
||||
void (*clearWatchpoint)(struct mDebuggerPlatform*, uint32_t address);
|
||||
void (*checkBreakpoints)(struct mDebuggerPlatform*);
|
||||
};
|
||||
|
||||
void DebuggerCreate(struct Debugger*);
|
||||
void DebuggerRun(struct Debugger*);
|
||||
void DebuggerEnter(struct Debugger*, enum DebuggerEntryReason, struct DebuggerEntryInfo*);
|
||||
void DebuggerSetBreakpoint(struct Debugger* debugger, uint32_t address);
|
||||
bool DebuggerSetSoftwareBreakpoint(struct Debugger* debugger, uint32_t address, enum ExecutionMode mode);
|
||||
void DebuggerClearBreakpoint(struct Debugger* debugger, uint32_t address);
|
||||
void DebuggerSetWatchpoint(struct Debugger* debugger, uint32_t address, enum WatchpointType type);
|
||||
void DebuggerClearWatchpoint(struct Debugger* debugger, uint32_t address);
|
||||
struct mDebugger {
|
||||
struct mCPUComponent d;
|
||||
struct mDebuggerPlatform* platform;
|
||||
enum mDebuggerState state;
|
||||
struct mCore* core;
|
||||
|
||||
void (*init)(struct mDebugger*);
|
||||
void (*deinit)(struct mDebugger*);
|
||||
|
||||
void (*paused)(struct mDebugger*);
|
||||
void (*entered)(struct mDebugger*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*);
|
||||
void (*custom)(struct mDebugger*);
|
||||
};
|
||||
|
||||
struct mDebugger* mDebuggerCreate(enum mDebuggerType type, struct mCore*);
|
||||
void mDebuggerAttach(struct mDebugger*, struct mCore*);
|
||||
void mDebuggerRun(struct mDebugger*);
|
||||
void mDebuggerEnter(struct mDebugger*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "gdb-stub.h"
|
||||
|
||||
#include "core/core.h"
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#ifndef SIGTRAP
|
||||
|
@ -26,14 +28,14 @@ enum {
|
|||
|
||||
static void _sendMessage(struct GDBStub* stub);
|
||||
|
||||
static void _gdbStubDeinit(struct Debugger* debugger) {
|
||||
static void _gdbStubDeinit(struct mDebugger* debugger) {
|
||||
struct GDBStub* stub = (struct GDBStub*) debugger;
|
||||
if (!SOCKET_FAILED(stub->socket)) {
|
||||
GDBStubShutdown(stub);
|
||||
}
|
||||
}
|
||||
|
||||
static void _gdbStubEntered(struct Debugger* debugger, enum DebuggerEntryReason reason, struct DebuggerEntryInfo* info) {
|
||||
static void _gdbStubEntered(struct mDebugger* debugger, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) {
|
||||
struct GDBStub* stub = (struct GDBStub*) debugger;
|
||||
switch (reason) {
|
||||
case DEBUGGER_ENTER_MANUAL:
|
||||
|
@ -76,7 +78,7 @@ static void _gdbStubEntered(struct Debugger* debugger, enum DebuggerEntryReason
|
|||
_sendMessage(stub);
|
||||
}
|
||||
|
||||
static void _gdbStubPoll(struct Debugger* debugger) {
|
||||
static void _gdbStubPoll(struct mDebugger* debugger) {
|
||||
struct GDBStub* stub = (struct GDBStub*) debugger;
|
||||
--stub->untilPoll;
|
||||
if (stub->untilPoll > 0) {
|
||||
|
@ -87,7 +89,7 @@ static void _gdbStubPoll(struct Debugger* debugger) {
|
|||
GDBStubUpdate(stub);
|
||||
}
|
||||
|
||||
static void _gdbStubWait(struct Debugger* debugger) {
|
||||
static void _gdbStubWait(struct mDebugger* debugger) {
|
||||
struct GDBStub* stub = (struct GDBStub*) debugger;
|
||||
stub->shouldBlock = true;
|
||||
GDBStubUpdate(stub);
|
||||
|
@ -201,7 +203,7 @@ static void _continue(struct GDBStub* stub, const char* message) {
|
|||
}
|
||||
|
||||
static void _step(struct GDBStub* stub, const char* message) {
|
||||
ARMRun(stub->d.cpu);
|
||||
stub->d.core->step(stub->d.core);
|
||||
snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "S%02x", SIGTRAP);
|
||||
_sendMessage(stub);
|
||||
// TODO: parse message
|
||||
|
@ -218,7 +220,7 @@ static void _readMemory(struct GDBStub* stub, const char* message) {
|
|||
_error(stub, GDB_BAD_ARGUMENTS);
|
||||
return;
|
||||
}
|
||||
struct ARMCore* cpu = stub->d.cpu;
|
||||
struct ARMCore* cpu = stub->d.core->cpu;
|
||||
int writeAddress = 0;
|
||||
for (i = 0; i < size; ++i, writeAddress += 2) {
|
||||
uint8_t byte = cpu->memory.load8(cpu, address + i, 0);
|
||||
|
@ -229,11 +231,12 @@ static void _readMemory(struct GDBStub* stub, const char* message) {
|
|||
}
|
||||
|
||||
static void _readGPRs(struct GDBStub* stub, const char* message) {
|
||||
struct ARMCore* cpu = stub->d.core->cpu;
|
||||
UNUSED(message);
|
||||
int r;
|
||||
int i = 0;
|
||||
for (r = 0; r < 16; ++r) {
|
||||
_int2hex32(stub->d.cpu->gprs[r], &stub->outgoing[i]);
|
||||
_int2hex32(cpu->gprs[r], &stub->outgoing[i]);
|
||||
i += 8;
|
||||
}
|
||||
stub->outgoing[i] = 0;
|
||||
|
@ -241,14 +244,15 @@ static void _readGPRs(struct GDBStub* stub, const char* message) {
|
|||
}
|
||||
|
||||
static void _readRegister(struct GDBStub* stub, const char* message) {
|
||||
struct ARMCore* cpu = stub->d.core->cpu;
|
||||
const char* readAddress = message;
|
||||
unsigned i = 0;
|
||||
uint32_t reg = _readHex(readAddress, &i);
|
||||
uint32_t value;
|
||||
if (reg < 0x10) {
|
||||
value = stub->d.cpu->gprs[reg];
|
||||
value = cpu->gprs[reg];
|
||||
} else if (reg == 0x19) {
|
||||
value = stub->d.cpu->cpsr.packed;
|
||||
value = cpu->cpsr.packed;
|
||||
} else {
|
||||
stub->outgoing[0] = '\0';
|
||||
_sendMessage(stub);
|
||||
|
@ -298,7 +302,7 @@ static void _processVReadCommand(struct GDBStub* stub, const char* message) {
|
|||
stub->outgoing[0] = '\0';
|
||||
if (!strncmp("Attach", message, 6)) {
|
||||
strncpy(stub->outgoing, "1", GDB_STUB_MAX_LINE - 4);
|
||||
DebuggerEnter(&stub->d, DEBUGGER_ENTER_MANUAL, 0);
|
||||
mDebuggerEnter(&stub->d, DEBUGGER_ENTER_MANUAL, 0);
|
||||
}
|
||||
_sendMessage(stub);
|
||||
}
|
||||
|
@ -314,22 +318,22 @@ static void _setBreakpoint(struct GDBStub* stub, const char* message) {
|
|||
switch (message[0]) {
|
||||
case '0': // Memory breakpoints are not currently supported
|
||||
case '1':
|
||||
DebuggerSetBreakpoint(&stub->d, address);
|
||||
stub->d.platform->setBreakpoint(stub->d.platform, address);
|
||||
strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4);
|
||||
_sendMessage(stub);
|
||||
break;
|
||||
case '2':
|
||||
DebuggerSetWatchpoint(&stub->d, address, WATCHPOINT_WRITE);
|
||||
stub->d.platform->setWatchpoint(stub->d.platform, address, WATCHPOINT_WRITE);
|
||||
strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4);
|
||||
_sendMessage(stub);
|
||||
break;
|
||||
case '3':
|
||||
DebuggerSetWatchpoint(&stub->d, address, WATCHPOINT_READ);
|
||||
stub->d.platform->setWatchpoint(stub->d.platform, address, WATCHPOINT_READ);
|
||||
strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4);
|
||||
_sendMessage(stub);
|
||||
break;
|
||||
case '4':
|
||||
DebuggerSetWatchpoint(&stub->d, address, WATCHPOINT_RW);
|
||||
stub->d.platform->setWatchpoint(stub->d.platform, address, WATCHPOINT_RW);
|
||||
strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4);
|
||||
_sendMessage(stub);
|
||||
break;
|
||||
|
@ -347,12 +351,12 @@ static void _clearBreakpoint(struct GDBStub* stub, const char* message) {
|
|||
switch (message[0]) {
|
||||
case '0': // Memory breakpoints are not currently supported
|
||||
case '1':
|
||||
DebuggerClearBreakpoint(&stub->d, address);
|
||||
stub->d.platform->clearBreakpoint(stub->d.platform, address);
|
||||
break;
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
DebuggerClearWatchpoint(&stub->d, address);
|
||||
stub->d.platform->clearWatchpoint(stub->d.platform, address);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -375,7 +379,7 @@ size_t _parseGDBMessage(struct GDBStub* stub, const char* message) {
|
|||
++message;
|
||||
break;
|
||||
case '\x03':
|
||||
DebuggerEnter(&stub->d, DEBUGGER_ENTER_MANUAL, 0);
|
||||
mDebuggerEnter(&stub->d, DEBUGGER_ENTER_MANUAL, 0);
|
||||
return parsed;
|
||||
default:
|
||||
_nak(stub);
|
||||
|
@ -462,7 +466,6 @@ size_t _parseGDBMessage(struct GDBStub* stub, const char* message) {
|
|||
}
|
||||
|
||||
void GDBStubCreate(struct GDBStub* stub) {
|
||||
DebuggerCreate(&stub->d);
|
||||
stub->socket = INVALID_SOCKET;
|
||||
stub->connection = INVALID_SOCKET;
|
||||
stub->d.init = 0;
|
||||
|
@ -536,7 +539,7 @@ void GDBStubUpdate(struct GDBStub* stub) {
|
|||
if (!SocketSetBlocking(stub->connection, false)) {
|
||||
goto connectionLost;
|
||||
}
|
||||
DebuggerEnter(&stub->d, DEBUGGER_ENTER_ATTACHED, 0);
|
||||
mDebuggerEnter(&stub->d, DEBUGGER_ENTER_ATTACHED, 0);
|
||||
} else if (SocketWouldBlock()) {
|
||||
return;
|
||||
} else {
|
||||
|
|
|
@ -23,7 +23,7 @@ enum GDBStubAckState {
|
|||
};
|
||||
|
||||
struct GDBStub {
|
||||
struct Debugger d;
|
||||
struct mDebugger d;
|
||||
|
||||
char line[GDB_STUB_MAX_LINE];
|
||||
char outgoing[GDB_STUB_MAX_LINE];
|
||||
|
|
|
@ -254,12 +254,56 @@ static void _GBCoreSetRumble(struct mCore* core, struct mRumble* rumble) {
|
|||
gb->memory.rumble = rumble;
|
||||
}
|
||||
|
||||
static uint32_t _GBCoreBusRead8(struct mCore* core, uint32_t address) {
|
||||
struct LR35902Core* cpu = core->cpu;
|
||||
return cpu->memory.load8(cpu, address);
|
||||
}
|
||||
|
||||
static uint32_t _GBCoreBusRead16(struct mCore* core, uint32_t address) {
|
||||
struct LR35902Core* cpu = core->cpu;
|
||||
return cpu->memory.load8(cpu, address) | (cpu->memory.load8(cpu, address + 1) << 8);
|
||||
}
|
||||
|
||||
static uint32_t _GBCoreBusRead32(struct mCore* core, uint32_t address) {
|
||||
struct LR35902Core* cpu = core->cpu;
|
||||
return cpu->memory.load8(cpu, address) | (cpu->memory.load8(cpu, address + 1) << 8) |
|
||||
(cpu->memory.load8(cpu, address + 2) << 16) | (cpu->memory.load8(cpu, address + 3) << 24);
|
||||
}
|
||||
|
||||
static void _GBCoreBusWrite8(struct mCore* core, uint32_t address, uint8_t value) {
|
||||
struct LR35902Core* cpu = core->cpu;
|
||||
cpu->memory.store8(cpu, address, value);
|
||||
}
|
||||
|
||||
static void _GBCoreBusWrite16(struct mCore* core, uint32_t address, uint16_t value) {
|
||||
struct LR35902Core* cpu = core->cpu;
|
||||
cpu->memory.store8(cpu, address, value);
|
||||
cpu->memory.store8(cpu, address + 1, value >> 8);
|
||||
}
|
||||
|
||||
static void _GBCoreBusWrite32(struct mCore* core, uint32_t address, uint32_t value) {
|
||||
struct LR35902Core* cpu = core->cpu;
|
||||
cpu->memory.store8(cpu, address, value);
|
||||
cpu->memory.store8(cpu, address + 1, value >> 8);
|
||||
cpu->memory.store8(cpu, address + 2, value >> 16);
|
||||
cpu->memory.store8(cpu, address + 3, value >> 24);
|
||||
}
|
||||
|
||||
static bool _GBCoreSupportsDebuggerType(struct mCore* core, enum mDebuggerType type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static struct mDebuggerPlatform* _GBCoreDebuggerPlatform(struct mCore* core) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct mCore* GBCoreCreate(void) {
|
||||
struct GBCore* gbcore = malloc(sizeof(*gbcore));
|
||||
struct mCore* core = &gbcore->d;
|
||||
memset(&core->opts, 0, sizeof(core->opts));
|
||||
core->cpu = 0;
|
||||
core->board = 0;
|
||||
core->cpu = NULL;
|
||||
core->board = NULL;
|
||||
core->debugger = NULL;
|
||||
core->init = _GBCoreInit;
|
||||
core->deinit = _GBCoreDeinit;
|
||||
core->platform = _GBCorePlatform;
|
||||
|
@ -295,5 +339,13 @@ struct mCore* GBCoreCreate(void) {
|
|||
core->setRTC = _GBCoreSetRTC;
|
||||
core->setRotation = _GBCoreSetRotation;
|
||||
core->setRumble = _GBCoreSetRumble;
|
||||
core->busRead8 = _GBCoreBusRead8;
|
||||
core->busRead16 = _GBCoreBusRead16;
|
||||
core->busRead32 = _GBCoreBusRead32;
|
||||
core->busWrite8 = _GBCoreBusWrite8;
|
||||
core->busWrite16 = _GBCoreBusWrite16;
|
||||
core->busWrite32 = _GBCoreBusWrite32;
|
||||
core->supportsDebuggerType = _GBCoreSupportsDebuggerType;
|
||||
core->debuggerPlatform = _GBCoreDebuggerPlatform;
|
||||
return core;
|
||||
}
|
||||
|
|
|
@ -165,11 +165,12 @@ void GBACheatSetDeinit(struct GBACheatSet* set) {
|
|||
}
|
||||
|
||||
void GBACheatAttachDevice(struct GBA* gba, struct GBACheatDevice* device) {
|
||||
if (gba->cpu->components[GBA_COMPONENT_CHEAT_DEVICE]) {
|
||||
ARMHotplugDetach(gba->cpu, GBA_COMPONENT_CHEAT_DEVICE);
|
||||
// TODO: Remove this function
|
||||
if (gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE]) {
|
||||
ARMHotplugDetach(gba->cpu, CPU_COMPONENT_CHEAT_DEVICE);
|
||||
}
|
||||
gba->cpu->components[GBA_COMPONENT_CHEAT_DEVICE] = &device->d;
|
||||
ARMHotplugAttach(gba->cpu, GBA_COMPONENT_CHEAT_DEVICE);
|
||||
gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE] = &device->d;
|
||||
ARMHotplugAttach(gba->cpu, CPU_COMPONENT_CHEAT_DEVICE);
|
||||
}
|
||||
|
||||
void GBACheatAddSet(struct GBACheatDevice* device, struct GBACheatSet* cheats) {
|
||||
|
|
101
src/gba/core.c
101
src/gba/core.c
|
@ -11,6 +11,7 @@
|
|||
#include "gba/context/overrides.h"
|
||||
#include "gba/renderers/video-software.h"
|
||||
#include "gba/serialize.h"
|
||||
#include "gba/supervisor/cli.h"
|
||||
#include "util/memory.h"
|
||||
#include "util/patch.h"
|
||||
#include "util/vfs.h"
|
||||
|
@ -19,8 +20,9 @@ struct GBACore {
|
|||
struct mCore d;
|
||||
struct GBAVideoSoftwareRenderer renderer;
|
||||
int keys;
|
||||
struct mCPUComponent* components[GBA_COMPONENT_MAX];
|
||||
struct mCPUComponent* components[CPU_COMPONENT_MAX];
|
||||
const struct Configuration* overrides;
|
||||
struct mDebuggerPlatform* debuggerPlatform;
|
||||
};
|
||||
|
||||
static bool _GBACoreInit(struct mCore* core) {
|
||||
|
@ -35,12 +37,14 @@ static bool _GBACoreInit(struct mCore* core) {
|
|||
}
|
||||
core->cpu = cpu;
|
||||
core->board = gba;
|
||||
core->debugger = NULL;
|
||||
gbacore->debuggerPlatform = NULL;
|
||||
gbacore->overrides = 0;
|
||||
|
||||
GBACreate(gba);
|
||||
// TODO: Restore debugger and cheats
|
||||
memset(gbacore->components, 0, sizeof(gbacore->components));
|
||||
ARMSetComponents(cpu, &gba->d, GBA_COMPONENT_MAX, gbacore->components);
|
||||
ARMSetComponents(cpu, &gba->d, CPU_COMPONENT_MAX, gbacore->components);
|
||||
ARMInit(cpu);
|
||||
|
||||
GBAVideoSoftwareRendererCreate(&gbacore->renderer);
|
||||
|
@ -288,12 +292,90 @@ static void _GBACoreSetRumble(struct mCore* core, struct mRumble* rumble) {
|
|||
gba->rumble = rumble;
|
||||
}
|
||||
|
||||
static uint32_t _GBACoreBusRead8(struct mCore* core, uint32_t address) {
|
||||
struct ARMCore* cpu = core->cpu;
|
||||
return cpu->memory.load8(cpu, address, 0);
|
||||
}
|
||||
|
||||
static uint32_t _GBACoreBusRead16(struct mCore* core, uint32_t address) {
|
||||
struct ARMCore* cpu = core->cpu;
|
||||
return cpu->memory.load8(cpu, address, 0);
|
||||
|
||||
}
|
||||
|
||||
static uint32_t _GBACoreBusRead32(struct mCore* core, uint32_t address) {
|
||||
struct ARMCore* cpu = core->cpu;
|
||||
return cpu->memory.load32(cpu, address, 0);
|
||||
}
|
||||
|
||||
static void _GBACoreBusWrite8(struct mCore* core, uint32_t address, uint8_t value) {
|
||||
struct ARMCore* cpu = core->cpu;
|
||||
cpu->memory.store8(cpu, address, value, 0);
|
||||
}
|
||||
|
||||
static void _GBACoreBusWrite16(struct mCore* core, uint32_t address, uint16_t value) {
|
||||
struct ARMCore* cpu = core->cpu;
|
||||
cpu->memory.store16(cpu, address, value, 0);
|
||||
}
|
||||
|
||||
static void _GBACoreBusWrite32(struct mCore* core, uint32_t address, uint32_t value) {
|
||||
struct ARMCore* cpu = core->cpu;
|
||||
cpu->memory.store32(cpu, address, value, 0);
|
||||
}
|
||||
|
||||
static bool _GBACoreSupportsDebuggerType(struct mCore* core, enum mDebuggerType type) {
|
||||
UNUSED(core);
|
||||
switch (type) {
|
||||
#ifdef USE_CLI_DEBUGGER
|
||||
case DEBUGGER_CLI:
|
||||
return true;
|
||||
#endif
|
||||
#ifdef USE_GDB_STUB
|
||||
case DEBUGGER_GDB:
|
||||
return true;
|
||||
#endif
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static struct mDebuggerPlatform* _GBACoreDebuggerPlatform(struct mCore* core) {
|
||||
struct GBACore* gbacore = (struct GBACore*) core;
|
||||
if (!gbacore->debuggerPlatform) {
|
||||
gbacore->debuggerPlatform = ARMDebuggerPlatformCreate();
|
||||
}
|
||||
return gbacore->debuggerPlatform;
|
||||
}
|
||||
|
||||
static struct CLIDebuggerSystem* _GBACoreCliDebuggerSystem(struct mCore* core) {
|
||||
#ifdef USE_CLI_DEBUGGER
|
||||
return &GBACLIDebuggerCreate(core)->d;
|
||||
#else
|
||||
UNUSED(core);
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void _GBACoreAttachDebugger(struct mCore* core, struct mDebugger* debugger) {
|
||||
if (core->debugger) {
|
||||
GBADetachDebugger(core->board);
|
||||
}
|
||||
GBAAttachDebugger(core->board, debugger);
|
||||
core->debugger = debugger;
|
||||
}
|
||||
|
||||
static void _GBACoreDetachDebugger(struct mCore* core) {
|
||||
GBADetachDebugger(core->board);
|
||||
core->debugger = NULL;
|
||||
}
|
||||
|
||||
struct mCore* GBACoreCreate(void) {
|
||||
struct GBACore* gbacore = malloc(sizeof(*gbacore));
|
||||
struct mCore* core = &gbacore->d;
|
||||
memset(&core->opts, 0, sizeof(core->opts));
|
||||
core->cpu = 0;
|
||||
core->board = 0;
|
||||
core->cpu = NULL;
|
||||
core->board = NULL;
|
||||
core->debugger = NULL;
|
||||
core->init = _GBACoreInit;
|
||||
core->deinit = _GBACoreDeinit;
|
||||
core->platform = _GBACorePlatform;
|
||||
|
@ -329,5 +411,16 @@ struct mCore* GBACoreCreate(void) {
|
|||
core->setRTC = _GBACoreSetRTC;
|
||||
core->setRotation = _GBACoreSetRotation;
|
||||
core->setRumble = _GBACoreSetRumble;
|
||||
core->busRead8 = _GBACoreBusRead8;
|
||||
core->busRead16 = _GBACoreBusRead16;
|
||||
core->busRead32 = _GBACoreBusRead32;
|
||||
core->busWrite8 = _GBACoreBusWrite8;
|
||||
core->busWrite16 = _GBACoreBusWrite16;
|
||||
core->busWrite32 = _GBACoreBusWrite32;
|
||||
core->supportsDebuggerType = _GBACoreSupportsDebuggerType;
|
||||
core->debuggerPlatform = _GBACoreDebuggerPlatform;
|
||||
core->cliDebuggerSystem = _GBACoreCliDebuggerSystem;
|
||||
core->attachDebugger = _GBACoreAttachDebugger;
|
||||
core->detachDebugger = _GBACoreDetachDebugger;
|
||||
return core;
|
||||
}
|
||||
|
|
|
@ -42,8 +42,8 @@ static void GBAHitStub(struct ARMCore* cpu, uint32_t opcode);
|
|||
static void GBAIllegal(struct ARMCore* cpu, uint32_t opcode);
|
||||
static void GBABreakpoint(struct ARMCore* cpu, int immediate);
|
||||
|
||||
static bool _setSoftwareBreakpoint(struct Debugger*, uint32_t address, enum ExecutionMode mode, uint32_t* opcode);
|
||||
static bool _clearSoftwareBreakpoint(struct Debugger*, uint32_t address, enum ExecutionMode mode, uint32_t opcode);
|
||||
static bool _setSoftwareBreakpoint(struct ARMDebugger*, uint32_t address, enum ExecutionMode mode, uint32_t* opcode);
|
||||
static bool _clearSoftwareBreakpoint(struct ARMDebugger*, uint32_t address, enum ExecutionMode mode, uint32_t opcode);
|
||||
|
||||
|
||||
#ifdef _3DS
|
||||
|
@ -403,18 +403,18 @@ static int32_t GBATimersProcessEvents(struct GBA* gba, int32_t cycles) {
|
|||
return nextEvent;
|
||||
}
|
||||
|
||||
void GBAAttachDebugger(struct GBA* gba, struct Debugger* debugger) {
|
||||
debugger->setSoftwareBreakpoint = _setSoftwareBreakpoint;
|
||||
debugger->clearSoftwareBreakpoint = _clearSoftwareBreakpoint;
|
||||
gba->debugger = debugger;
|
||||
gba->cpu->components[GBA_COMPONENT_DEBUGGER] = &debugger->d;
|
||||
ARMHotplugAttach(gba->cpu, GBA_COMPONENT_DEBUGGER);
|
||||
void GBAAttachDebugger(struct GBA* gba, struct mDebugger* debugger) {
|
||||
gba->debugger = (struct ARMDebugger*) debugger->platform;
|
||||
gba->debugger->setSoftwareBreakpoint = _setSoftwareBreakpoint;
|
||||
gba->debugger->clearSoftwareBreakpoint = _clearSoftwareBreakpoint;
|
||||
gba->cpu->components[CPU_COMPONENT_DEBUGGER] = &debugger->d;
|
||||
ARMHotplugAttach(gba->cpu, CPU_COMPONENT_DEBUGGER);
|
||||
}
|
||||
|
||||
void GBADetachDebugger(struct GBA* gba) {
|
||||
gba->debugger = 0;
|
||||
ARMHotplugDetach(gba->cpu, GBA_COMPONENT_DEBUGGER);
|
||||
gba->cpu->components[GBA_COMPONENT_DEBUGGER] = 0;
|
||||
ARMHotplugDetach(gba->cpu, CPU_COMPONENT_DEBUGGER);
|
||||
gba->cpu->components[CPU_COMPONENT_DEBUGGER] = 0;
|
||||
}
|
||||
|
||||
bool GBALoadMB(struct GBA* gba, struct VFile* vf) {
|
||||
|
@ -731,11 +731,11 @@ void GBAGetGameTitle(struct GBA* gba, char* out) {
|
|||
void GBAHitStub(struct ARMCore* cpu, uint32_t opcode) {
|
||||
struct GBA* gba = (struct GBA*) cpu->master;
|
||||
if (gba->debugger) {
|
||||
struct DebuggerEntryInfo info = {
|
||||
struct mDebuggerEntryInfo info = {
|
||||
.address = _ARMPCAddress(cpu),
|
||||
.opcode = opcode
|
||||
};
|
||||
DebuggerEnter(gba->debugger, DEBUGGER_ENTER_ILLEGAL_OP, &info);
|
||||
mDebuggerEnter(gba->debugger->d.p, DEBUGGER_ENTER_ILLEGAL_OP, &info);
|
||||
}
|
||||
// TODO: More sensible category?
|
||||
mLOG(GBA, ERROR, "Stub opcode: %08x", opcode);
|
||||
|
@ -748,11 +748,11 @@ void GBAIllegal(struct ARMCore* cpu, uint32_t opcode) {
|
|||
mLOG(GBA, WARN, "Illegal opcode: %08x", opcode);
|
||||
}
|
||||
if (gba->debugger) {
|
||||
struct DebuggerEntryInfo info = {
|
||||
struct mDebuggerEntryInfo info = {
|
||||
.address = _ARMPCAddress(cpu),
|
||||
.opcode = opcode
|
||||
};
|
||||
DebuggerEnter(gba->debugger, DEBUGGER_ENTER_ILLEGAL_OP, &info);
|
||||
mDebuggerEnter(gba->debugger->d.p, DEBUGGER_ENTER_ILLEGAL_OP, &info);
|
||||
} else {
|
||||
ARMRaiseUndefined(cpu);
|
||||
}
|
||||
|
@ -760,21 +760,21 @@ void GBAIllegal(struct ARMCore* cpu, uint32_t opcode) {
|
|||
|
||||
void GBABreakpoint(struct ARMCore* cpu, int immediate) {
|
||||
struct GBA* gba = (struct GBA*) cpu->master;
|
||||
if (immediate >= GBA_COMPONENT_MAX) {
|
||||
if (immediate >= CPU_COMPONENT_MAX) {
|
||||
return;
|
||||
}
|
||||
switch (immediate) {
|
||||
case GBA_COMPONENT_DEBUGGER:
|
||||
case CPU_COMPONENT_DEBUGGER:
|
||||
if (gba->debugger) {
|
||||
struct DebuggerEntryInfo info = {
|
||||
struct mDebuggerEntryInfo info = {
|
||||
.address = _ARMPCAddress(cpu)
|
||||
};
|
||||
DebuggerEnter(gba->debugger, DEBUGGER_ENTER_BREAKPOINT, &info);
|
||||
mDebuggerEnter(gba->debugger->d.p, DEBUGGER_ENTER_BREAKPOINT, &info);
|
||||
}
|
||||
break;
|
||||
case GBA_COMPONENT_CHEAT_DEVICE:
|
||||
if (gba->cpu->components[GBA_COMPONENT_CHEAT_DEVICE]) {
|
||||
struct GBACheatDevice* device = (struct GBACheatDevice*) gba->cpu->components[GBA_COMPONENT_CHEAT_DEVICE];
|
||||
case CPU_COMPONENT_CHEAT_DEVICE:
|
||||
if (gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE]) {
|
||||
struct GBACheatDevice* device = (struct GBACheatDevice*) gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE];
|
||||
struct GBACheatHook* hook = 0;
|
||||
size_t i;
|
||||
for (i = 0; i < GBACheatSetsSize(&device->cheats); ++i) {
|
||||
|
@ -807,8 +807,8 @@ void GBAFrameEnded(struct GBA* gba) {
|
|||
gba->rr->nextFrame(gba->rr);
|
||||
}
|
||||
|
||||
if (gba->cpu->components && gba->cpu->components[GBA_COMPONENT_CHEAT_DEVICE]) {
|
||||
struct GBACheatDevice* device = (struct GBACheatDevice*) gba->cpu->components[GBA_COMPONENT_CHEAT_DEVICE];
|
||||
if (gba->cpu->components && gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE]) {
|
||||
struct GBACheatDevice* device = (struct GBACheatDevice*) gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE];
|
||||
size_t i;
|
||||
for (i = 0; i < GBACheatSetsSize(&device->cheats); ++i) {
|
||||
struct GBACheatSet* cheats = *GBACheatSetsGetPointer(&device->cheats, i);
|
||||
|
@ -877,12 +877,12 @@ void GBAClearBreakpoint(struct GBA* gba, uint32_t address, enum ExecutionMode mo
|
|||
}
|
||||
}
|
||||
|
||||
static bool _setSoftwareBreakpoint(struct Debugger* debugger, uint32_t address, enum ExecutionMode mode, uint32_t* opcode) {
|
||||
GBASetBreakpoint((struct GBA*) debugger->cpu->master, &debugger->d, address, mode, opcode);
|
||||
static bool _setSoftwareBreakpoint(struct ARMDebugger* debugger, uint32_t address, enum ExecutionMode mode, uint32_t* opcode) {
|
||||
GBASetBreakpoint((struct GBA*) debugger->cpu->master, &debugger->d.p->d, address, mode, opcode);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _clearSoftwareBreakpoint(struct Debugger* debugger, uint32_t address, enum ExecutionMode mode, uint32_t opcode) {
|
||||
static bool _clearSoftwareBreakpoint(struct ARMDebugger* debugger, uint32_t address, enum ExecutionMode mode, uint32_t opcode) {
|
||||
GBAClearBreakpoint((struct GBA*) debugger->cpu->master, address, mode, opcode);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
#include "util/common.h"
|
||||
|
||||
#include "arm/arm.h"
|
||||
#include "arm/debugger.h"
|
||||
#include "core/log.h"
|
||||
#include "debugger/debugger.h"
|
||||
|
||||
#include "gba/interface.h"
|
||||
#include "gba/memory.h"
|
||||
|
@ -37,12 +37,6 @@ enum GBAIRQ {
|
|||
IRQ_GAMEPAK = 0xD
|
||||
};
|
||||
|
||||
enum GBAComponent {
|
||||
GBA_COMPONENT_DEBUGGER,
|
||||
GBA_COMPONENT_CHEAT_DEVICE,
|
||||
GBA_COMPONENT_MAX
|
||||
};
|
||||
|
||||
enum GBAIdleLoopOptimization {
|
||||
IDLE_LOOP_IGNORE = -1,
|
||||
IDLE_LOOP_REMOVE = 0,
|
||||
|
@ -87,7 +81,7 @@ struct GBA {
|
|||
|
||||
struct mCoreSync* sync;
|
||||
|
||||
struct Debugger* debugger;
|
||||
struct ARMDebugger* debugger;
|
||||
|
||||
uint32_t bus;
|
||||
int performingDMA;
|
||||
|
@ -161,7 +155,7 @@ void GBATestIRQ(struct ARMCore* cpu);
|
|||
void GBAHalt(struct GBA* gba);
|
||||
void GBAStop(struct GBA* gba);
|
||||
|
||||
void GBAAttachDebugger(struct GBA* gba, struct Debugger* debugger);
|
||||
void GBAAttachDebugger(struct GBA* gba, struct mDebugger* debugger);
|
||||
void GBADetachDebugger(struct GBA* gba);
|
||||
|
||||
void GBASetBreakpoint(struct GBA* gba, struct mCPUComponent* component, uint32_t address, enum ExecutionMode mode,
|
||||
|
|
|
@ -382,8 +382,8 @@ bool GBASaveStateNamed(struct GBA* gba, struct VFile* vf, int flags) {
|
|||
svf->close(svf);
|
||||
}
|
||||
struct VFile* cheatVf = 0;
|
||||
if (flags & SAVESTATE_CHEATS && gba->cpu->components && gba->cpu->components[GBA_COMPONENT_CHEAT_DEVICE]) {
|
||||
struct GBACheatDevice* device = (struct GBACheatDevice*) gba->cpu->components[GBA_COMPONENT_CHEAT_DEVICE];
|
||||
if (flags & SAVESTATE_CHEATS && gba->cpu->components && gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE]) {
|
||||
struct GBACheatDevice* device = (struct GBACheatDevice*) gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE];
|
||||
cheatVf = VFileMemChunk(0, 0);
|
||||
if (cheatVf) {
|
||||
GBACheatSaveFile(device, cheatVf);
|
||||
|
@ -477,9 +477,9 @@ bool GBALoadStateNamed(struct GBA* gba, struct VFile* vf, int flags) {
|
|||
svf->close(svf);
|
||||
}
|
||||
}
|
||||
if (flags & SAVESTATE_CHEATS && gba->cpu->components && gba->cpu->components[GBA_COMPONENT_CHEAT_DEVICE] && GBAExtdataGet(&extdata, EXTDATA_CHEATS, &item)) {
|
||||
if (flags & SAVESTATE_CHEATS && gba->cpu->components && gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE] && GBAExtdataGet(&extdata, EXTDATA_CHEATS, &item)) {
|
||||
if (item.size) {
|
||||
struct GBACheatDevice* device = (struct GBACheatDevice*) gba->cpu->components[GBA_COMPONENT_CHEAT_DEVICE];
|
||||
struct GBACheatDevice* device = (struct GBACheatDevice*) gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE];
|
||||
struct VFile* svf = VFileFromMemory(item.data, item.size);
|
||||
if (svf) {
|
||||
GBACheatDeviceClear(device);
|
||||
|
|
|
@ -5,13 +5,12 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "cli.h"
|
||||
|
||||
#include "arm/cli-debugger.h"
|
||||
#include "gba/io.h"
|
||||
#include "gba/serialize.h"
|
||||
|
||||
#ifdef USE_CLI_DEBUGGER
|
||||
|
||||
static const char* ERROR_MISSING_ARGS = "Arguments missing"; // TODO: share
|
||||
|
||||
static void _GBACLIDebuggerInit(struct CLIDebuggerSystem*);
|
||||
static void _GBACLIDebuggerDeinit(struct CLIDebuggerSystem*);
|
||||
static bool _GBACLIDebuggerCustom(struct CLIDebuggerSystem*);
|
||||
|
@ -32,6 +31,7 @@ struct CLIDebuggerCommandSummary _GBACLIDebuggerCommands[] = {
|
|||
|
||||
struct GBACLIDebugger* GBACLIDebuggerCreate(struct mCore* core) {
|
||||
struct GBACLIDebugger* debugger = malloc(sizeof(struct GBACLIDebugger));
|
||||
ARMCLIDebuggerCreate(&debugger->d);
|
||||
debugger->d.init = _GBACLIDebuggerInit;
|
||||
debugger->d.deinit = _GBACLIDebuggerDeinit;
|
||||
debugger->d.custom = _GBACLIDebuggerCustom;
|
||||
|
@ -60,7 +60,7 @@ static bool _GBACLIDebuggerCustom(struct CLIDebuggerSystem* debugger) {
|
|||
|
||||
if (gbaDebugger->frameAdvance) {
|
||||
if (!gbaDebugger->inVblank && GBARegisterDISPSTATIsInVblank(((struct GBA*) gbaDebugger->core->board)->memory.io[REG_DISPSTAT >> 1])) {
|
||||
DebuggerEnter(&gbaDebugger->d.p->d, DEBUGGER_ENTER_MANUAL, 0);
|
||||
mDebuggerEnter(&gbaDebugger->d.p->d, DEBUGGER_ENTER_MANUAL, 0);
|
||||
gbaDebugger->frameAdvance = false;
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -4,19 +4,6 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "commandline.h"
|
||||
|
||||
#include "debugger/debugger.h"
|
||||
|
||||
#ifdef USE_CLI_DEBUGGER
|
||||
#include "debugger/cli-debugger.h"
|
||||
#include "gba/supervisor/cli.h"
|
||||
#endif
|
||||
|
||||
#ifdef USE_GDB_STUB
|
||||
#include "debugger/gdb-stub.h"
|
||||
#endif
|
||||
|
||||
#include "gba/video.h"
|
||||
#include "util/string.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
|
@ -211,46 +198,6 @@ void _applyGraphicsArgs(struct mSubParser* parser, struct mCoreConfig* config) {
|
|||
mCoreConfigSetOverrideIntValue(config, "fullscreen", graphicsOpts->fullscreen);
|
||||
}
|
||||
|
||||
struct Debugger* createDebugger(struct mArguments* opts, struct mCore* core) {
|
||||
#ifndef USE_CLI_DEBUGGER
|
||||
UNUSED(core);
|
||||
#endif
|
||||
union DebugUnion {
|
||||
struct Debugger d;
|
||||
#ifdef USE_CLI_DEBUGGER
|
||||
struct CLIDebugger cli;
|
||||
#endif
|
||||
#ifdef USE_GDB_STUB
|
||||
struct GDBStub gdb;
|
||||
#endif
|
||||
};
|
||||
|
||||
union DebugUnion* debugger = malloc(sizeof(union DebugUnion));
|
||||
|
||||
switch (opts->debuggerType) {
|
||||
#ifdef USE_CLI_DEBUGGER
|
||||
case DEBUGGER_CLI:
|
||||
CLIDebuggerCreate(&debugger->cli);
|
||||
struct GBACLIDebugger* gbaDebugger = GBACLIDebuggerCreate(core);
|
||||
CLIDebuggerAttachSystem(&debugger->cli, &gbaDebugger->d);
|
||||
break;
|
||||
#endif
|
||||
#ifdef USE_GDB_STUB
|
||||
case DEBUGGER_GDB:
|
||||
GDBStubCreate(&debugger->gdb);
|
||||
GDBStubListen(&debugger->gdb, 2345, 0);
|
||||
break;
|
||||
#endif
|
||||
case DEBUGGER_NONE:
|
||||
case DEBUGGER_MAX:
|
||||
free(debugger);
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return &debugger->d;
|
||||
}
|
||||
|
||||
void usage(const char* arg0, const char* extraOptions) {
|
||||
printf("usage: %s [option ...] file\n", arg0);
|
||||
puts("\nGeneric options:");
|
||||
|
|
|
@ -19,7 +19,7 @@ struct mArguments {
|
|||
int logLevel;
|
||||
int frameskip;
|
||||
|
||||
enum DebuggerType debuggerType;
|
||||
enum mDebuggerType debuggerType;
|
||||
bool debugAtStart;
|
||||
bool showHelp;
|
||||
bool showVersion;
|
||||
|
@ -48,7 +48,5 @@ void usage(const char* arg0, const char* extraOptions);
|
|||
void version(const char* arg0);
|
||||
|
||||
void initParserForGraphics(struct mSubParser* parser, struct mGraphicsOpts* opts);
|
||||
struct mCore;
|
||||
struct Debugger* createDebugger(struct mArguments* opts, struct mCore* core);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -41,12 +41,12 @@ void GDBController::attach() {
|
|||
}
|
||||
m_gameController->setDebugger(&m_gdbStub.d);
|
||||
if (m_gameController->isLoaded()) {
|
||||
DebuggerEnter(&m_gdbStub.d, DEBUGGER_ENTER_ATTACHED, 0);
|
||||
mDebuggerEnter(&m_gdbStub.d, DEBUGGER_ENTER_ATTACHED, 0);
|
||||
} else {
|
||||
QObject::disconnect(m_autoattach);
|
||||
m_autoattach = connect(m_gameController, &GameController::gameStarted, [this]() {
|
||||
QObject::disconnect(m_autoattach);
|
||||
DebuggerEnter(&m_gdbStub.d, DEBUGGER_ENTER_ATTACHED, 0);
|
||||
mDebuggerEnter(&m_gdbStub.d, DEBUGGER_ENTER_ATTACHED, 0);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -81,6 +81,6 @@ void GDBController::breakInto() {
|
|||
return;
|
||||
}
|
||||
m_gameController->threadInterrupt();
|
||||
DebuggerEnter(&m_gdbStub.d, DEBUGGER_ENTER_MANUAL, 0);
|
||||
mDebuggerEnter(&m_gdbStub.d, DEBUGGER_ENTER_MANUAL, 0);
|
||||
m_gameController->threadContinue();
|
||||
}
|
||||
|
|
|
@ -271,14 +271,20 @@ void GameController::setConfig(const mCoreConfig* config) {
|
|||
}
|
||||
|
||||
#ifdef USE_GDB_STUB
|
||||
Debugger* GameController::debugger() {
|
||||
// TODO: Put back debugger
|
||||
return nullptr;
|
||||
mDebugger* GameController::debugger() {
|
||||
if (!isLoaded()) {
|
||||
return nullptr;
|
||||
}
|
||||
return m_threadContext.core->debugger;
|
||||
}
|
||||
|
||||
void GameController::setDebugger(Debugger* debugger) {
|
||||
void GameController::setDebugger(mDebugger* debugger) {
|
||||
threadInterrupt();
|
||||
// TODO: Put back debugger
|
||||
if (debugger) {
|
||||
mDebuggerAttach(debugger, m_threadContext.core);
|
||||
} else {
|
||||
m_threadContext.core->detachDebugger(m_threadContext.core);
|
||||
}
|
||||
threadContinue();
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -30,7 +30,7 @@ extern "C" {
|
|||
struct GBAAudio;
|
||||
struct mCoreConfig;
|
||||
struct Configuration;
|
||||
struct Debugger;
|
||||
struct mDebugger;
|
||||
|
||||
class QThread;
|
||||
|
||||
|
@ -79,8 +79,8 @@ public:
|
|||
int stateSlot() const { return m_stateSlot; }
|
||||
|
||||
#ifdef USE_GDB_STUB
|
||||
Debugger* debugger();
|
||||
void setDebugger(Debugger*);
|
||||
mDebugger* debugger();
|
||||
void setDebugger(mDebugger*);
|
||||
#endif
|
||||
|
||||
signals:
|
||||
|
|
|
@ -158,7 +158,11 @@ int mSDLRun(struct mSDLRenderer* renderer, struct mArguments* args) {
|
|||
return 1;
|
||||
}
|
||||
mCoreAutoloadSave(renderer->core);
|
||||
// TODO: Put back debugger
|
||||
struct mDebugger* debugger = mDebuggerCreate(args->debuggerType, renderer->core);
|
||||
if (debugger) {
|
||||
mDebuggerAttach(debugger, renderer->core);
|
||||
mDebuggerEnter(debugger, DEBUGGER_ENTER_MANUAL, NULL);
|
||||
}
|
||||
|
||||
if (args->patch) {
|
||||
struct VFile* patch = VFileOpen(args->patch, O_RDONLY);
|
||||
|
|
|
@ -407,7 +407,9 @@ static void _mSDLHandleKeypress(struct mCoreThread* context, struct mSDLPlayer*
|
|||
if (event->type == SDL_KEYDOWN) {
|
||||
switch (event->keysym.sym) {
|
||||
case SDLK_F11:
|
||||
// TODO: Put back debugger
|
||||
if (context->core->debugger) {
|
||||
mDebuggerEnter(context->core->debugger, DEBUGGER_ENTER_MANUAL, NULL);
|
||||
}
|
||||
return;
|
||||
#ifdef USE_PNG
|
||||
case SDLK_F12:
|
||||
|
|
Loading…
Reference in New Issue