Debugger: Refactor large portions of debugger to allow for multiplatform

This commit is contained in:
Jeffrey Pfau 2016-04-25 21:47:40 -07:00
parent a4e29886c9
commit 1cc0bdeec1
30 changed files with 933 additions and 576 deletions

View File

@ -316,7 +316,7 @@ find_feature(USE_MAGICK "MagickWand")
find_feature(USE_EPOXY "epoxy") find_feature(USE_EPOXY "epoxy")
# Features # 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(FEATURE_SRC)
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6") set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6")
@ -326,9 +326,9 @@ endif()
if(USE_CLI_DEBUGGER) if(USE_CLI_DEBUGGER)
list(APPEND FEATURES CLI_DEBUGGER) list(APPEND FEATURES CLI_DEBUGGER)
list(APPEND FEATURE_SRC ${CMAKE_SOURCE_DIR}/src/debugger/cli-debugger.c) list(APPEND DEBUGGER_SRC ${CMAKE_SOURCE_DIR}/src/debugger/cli-debugger.c)
list(APPEND FEATURE_SRC ${CMAKE_SOURCE_DIR}/src/debugger/parser.c) list(APPEND DEBUGGER_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/gba/supervisor/cli.c)
include_directories(AFTER ${LIBEDIT_INCLUDE_DIRS}) include_directories(AFTER ${LIBEDIT_INCLUDE_DIRS})
link_directories(${LIBEDIT_LIBRARY_DIRS}) link_directories(${LIBEDIT_LIBRARY_DIRS})
set(DEBUGGER_LIB ${LIBEDIT_LIBRARIES}) set(DEBUGGER_LIB ${LIBEDIT_LIBRARIES})

225
src/arm/cli-debugger.c Normal file
View File

@ -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

14
src/arm/cli-debugger.h Normal file
View File

@ -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

172
src/arm/debugger.c Normal file
View File

@ -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);
}
}

41
src/arm/debugger.h Normal file
View File

@ -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);

View File

@ -5,13 +5,13 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "memory-debugger.h" #include "memory-debugger.h"
#include "debugger.h" #include "arm/debugger.h"
#include "util/math.h" #include "util/math.h"
#include <string.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) \ #define FIND_DEBUGGER(DEBUGGER, CPU) \
{ \ { \
@ -19,7 +19,7 @@ static bool _checkWatchpoints(struct Debugger* debugger, uint32_t address, struc
size_t i; \ size_t i; \
for (i = 0; i < CPU->numComponents; ++i) { \ for (i = 0; i < CPU->numComponents; ++i) { \
if (CPU->components[i]->id == DEBUGGER_ID) { \ if (CPU->components[i]->id == DEBUGGER_ID) { \
DEBUGGER = (struct Debugger*) cpu->components[i]; \ DEBUGGER = (struct ARMDebugger*) cpu->components[i]; \
break; \ break; \
} \ } \
} \ } \
@ -27,36 +27,36 @@ static bool _checkWatchpoints(struct Debugger* debugger, uint32_t address, struc
#define CREATE_SHIM(NAME, RETURN, TYPES, ...) \ #define CREATE_SHIM(NAME, RETURN, TYPES, ...) \
static RETURN DebuggerShim_ ## NAME TYPES { \ static RETURN DebuggerShim_ ## NAME TYPES { \
struct Debugger* debugger; \ struct ARMDebugger* debugger; \
FIND_DEBUGGER(debugger, cpu); \ FIND_DEBUGGER(debugger, cpu); \
return debugger->originalMemory.NAME(cpu, __VA_ARGS__); \ return debugger->originalMemory.NAME(cpu, __VA_ARGS__); \
} }
#define CREATE_WATCHPOINT_READ_SHIM(NAME, WIDTH, RETURN, TYPES, ...) \ #define CREATE_WATCHPOINT_READ_SHIM(NAME, WIDTH, RETURN, TYPES, ...) \
static RETURN DebuggerShim_ ## NAME TYPES { \ static RETURN DebuggerShim_ ## NAME TYPES { \
struct Debugger* debugger; \ struct ARMDebugger* debugger; \
FIND_DEBUGGER(debugger, cpu); \ FIND_DEBUGGER(debugger, cpu); \
struct DebuggerEntryInfo info; \ struct mDebuggerEntryInfo info; \
if (_checkWatchpoints(debugger, address, &info, WATCHPOINT_READ, 0, WIDTH)) { \ 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__); \ return debugger->originalMemory.NAME(cpu, __VA_ARGS__); \
} }
#define CREATE_WATCHPOINT_WRITE_SHIM(NAME, WIDTH, RETURN, TYPES, ...) \ #define CREATE_WATCHPOINT_WRITE_SHIM(NAME, WIDTH, RETURN, TYPES, ...) \
static RETURN DebuggerShim_ ## NAME TYPES { \ static RETURN DebuggerShim_ ## NAME TYPES { \
struct Debugger* debugger; \ struct ARMDebugger* debugger; \
FIND_DEBUGGER(debugger, cpu); \ FIND_DEBUGGER(debugger, cpu); \
struct DebuggerEntryInfo info; \ struct mDebuggerEntryInfo info; \
if (_checkWatchpoints(debugger, address, &info, WATCHPOINT_WRITE, value, WIDTH)) { \ 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__); \ return debugger->originalMemory.NAME(cpu, __VA_ARGS__); \
} }
#define CREATE_MULTIPLE_WATCHPOINT_SHIM(NAME, ACCESS_TYPE) \ #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) { \ 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); \ FIND_DEBUGGER(debugger, cpu); \
uint32_t popcount = popcount32(mask); \ uint32_t popcount = popcount32(mask); \
int offset = 4; \ int offset = 4; \
@ -70,9 +70,9 @@ static bool _checkWatchpoints(struct Debugger* debugger, uint32_t address, struc
} \ } \
unsigned i; \ unsigned i; \
for (i = 0; i < popcount; ++i) { \ for (i = 0; i < popcount; ++i) { \
struct DebuggerEntryInfo info; \ struct mDebuggerEntryInfo info; \
if (_checkWatchpoints(debugger, base + 4 * i, &info, ACCESS_TYPE, 0, 4)) { \ 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); \ 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_MULTIPLE_WATCHPOINT_SHIM(storeMultiple, WATCHPOINT_WRITE)
CREATE_SHIM(setActiveRegion, void, (struct ARMCore* cpu, uint32_t address), address) 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; --width;
struct DebugWatchpoint* watchpoint; struct ARMDebugWatchpoint* watchpoint;
size_t i; size_t i;
for (i = 0; i < DebugWatchpointListSize(&debugger->watchpoints); ++i) { for (i = 0; i < ARMDebugWatchpointListSize(&debugger->watchpoints); ++i) {
watchpoint = DebugWatchpointListGetPointer(&debugger->watchpoints, i); watchpoint = ARMDebugWatchpointListGetPointer(&debugger->watchpoints, i);
if (!((watchpoint->address ^ address) & ~width) && watchpoint->type & type) { if (!((watchpoint->address ^ address) & ~width) && watchpoint->type & type) {
switch (width + 1) { switch (width + 1) {
case 1: case 1:
@ -116,7 +116,7 @@ static bool _checkWatchpoints(struct Debugger* debugger, uint32_t address, struc
return false; return false;
} }
void DebuggerInstallMemoryShim(struct Debugger* debugger) { void ARMDebuggerInstallMemoryShim(struct ARMDebugger* debugger) {
debugger->originalMemory = debugger->cpu->memory; debugger->originalMemory = debugger->cpu->memory;
debugger->cpu->memory.store32 = DebuggerShim_store32; debugger->cpu->memory.store32 = DebuggerShim_store32;
debugger->cpu->memory.store16 = DebuggerShim_store16; debugger->cpu->memory.store16 = DebuggerShim_store16;
@ -129,7 +129,7 @@ void DebuggerInstallMemoryShim(struct Debugger* debugger) {
debugger->cpu->memory.setActiveRegion = DebuggerShim_setActiveRegion; 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.store32 = debugger->originalMemory.store32;
debugger->cpu->memory.store16 = debugger->originalMemory.store16; debugger->cpu->memory.store16 = debugger->originalMemory.store16;
debugger->cpu->memory.store8 = debugger->originalMemory.store8; debugger->cpu->memory.store8 = debugger->originalMemory.store8;

View File

@ -8,11 +8,9 @@
#include "util/common.h" #include "util/common.h"
#include "arm.h" struct ARMDebugger;
struct Debugger; void ARMDebuggerInstallMemoryShim(struct ARMDebugger* debugger);
void ARMDebuggerRemoveMemoryShim(struct ARMDebugger* debugger);
void DebuggerInstallMemoryShim(struct Debugger* debugger);
void DebuggerRemoveMemoryShim(struct Debugger* debugger);
#endif #endif

View File

@ -16,6 +16,7 @@
#include "core/input.h" #include "core/input.h"
#endif #endif
#include "core/interface.h" #include "core/interface.h"
#include "debugger/debugger.h"
enum mPlatform { enum mPlatform {
PLATFORM_NONE = -1, PLATFORM_NONE = -1,
@ -33,6 +34,7 @@ struct mCoreSync;
struct mCore { struct mCore {
void* cpu; void* cpu;
void* board; void* board;
struct mDebugger* debugger;
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 #if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
struct mDirectorySet dirs; struct mDirectorySet dirs;
@ -93,6 +95,20 @@ struct mCore {
void (*setRTC)(struct mCore*, struct mRTCSource*); void (*setRTC)(struct mCore*, struct mRTCSource*);
void (*setRotation)(struct mCore*, struct mRotationSource*); void (*setRotation)(struct mCore*, struct mRotationSource*);
void (*setRumble)(struct mCore*, struct mRumble*); 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 #if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2

View File

@ -8,6 +8,12 @@
#include "util/common.h" #include "util/common.h"
enum mCPUComponentType {
CPU_COMPONENT_DEBUGGER,
CPU_COMPONENT_CHEAT_DEVICE,
CPU_COMPONENT_MAX
};
struct mCPUComponent { struct mCPUComponent {
uint32_t id; uint32_t id;
void (*init)(void* cpu, struct mCPUComponent* component); void (*init)(void* cpu, struct mCPUComponent* component);

View File

@ -116,7 +116,17 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) {
_changeState(threadContext, THREAD_RUNNING, true); _changeState(threadContext, THREAD_RUNNING, true);
while (threadContext->state < THREAD_EXITING) { 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; int resetScheduled = 0;
MutexLock(&threadContext->stateMutex); MutexLock(&threadContext->stateMutex);

View File

@ -4,7 +4,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "cli-debugger.h" #include "cli-debugger.h"
#include "decoder.h"
#ifdef USE_CLI_DEBUGGER
#include "core/core.h"
#include "parser.h" #include "parser.h"
#include <signal.h> #include <signal.h>
@ -13,8 +16,8 @@
#include <pthread.h> #include <pthread.h>
#endif #endif
static const char* ERROR_MISSING_ARGS = "Arguments missing"; // TODO: share const char* ERROR_MISSING_ARGS = "Arguments missing"; // TODO: share
static const char* ERROR_OVERFLOW = "Arguments overflow"; const char* ERROR_OVERFLOW = "Arguments overflow";
static struct CLIDebugger* _activeDebugger; static struct CLIDebugger* _activeDebugger;
@ -23,8 +26,6 @@ static void _breakInto(struct CLIDebugger*, struct CLIDebugVector*);
#endif #endif
static void _continue(struct CLIDebugger*, struct CLIDebugVector*); static void _continue(struct CLIDebugger*, struct CLIDebugVector*);
static void _disassemble(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 _next(struct CLIDebugger*, struct CLIDebugVector*);
static void _print(struct CLIDebugger*, struct CLIDebugVector*); static void _print(struct CLIDebugger*, struct CLIDebugVector*);
static void _printBin(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 _readHalfword(struct CLIDebugger*, struct CLIDebugVector*);
static void _readWord(struct CLIDebugger*, struct CLIDebugVector*); static void _readWord(struct CLIDebugger*, struct CLIDebugVector*);
static void _setBreakpoint(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 _clearBreakpoint(struct CLIDebugger*, struct CLIDebugVector*);
static void _setWatchpoint(struct CLIDebugger*, struct CLIDebugVector*); static void _setWatchpoint(struct CLIDebugger*, struct CLIDebugVector*);
static void _writeByte(struct CLIDebugger*, struct CLIDebugVector*); static void _writeByte(struct CLIDebugger*, struct CLIDebugVector*);
static void _writeHalfword(struct CLIDebugger*, struct CLIDebugVector*); static void _writeHalfword(struct CLIDebugger*, struct CLIDebugVector*);
static void _writeWord(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 _dumpByte(struct CLIDebugger*, struct CLIDebugVector*);
static void _dumpHalfword(struct CLIDebugger*, struct CLIDebugVector*); static void _dumpHalfword(struct CLIDebugger*, struct CLIDebugVector*);
static void _dumpWord(struct CLIDebugger*, struct CLIDebugVector*); static void _dumpWord(struct CLIDebugger*, struct CLIDebugVector*);
static void _breakIntoDefault(int signal); 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[] = { static struct CLIDebuggerCommandSummary _debuggerCommands[] = {
{ "b", _setBreakpoint, CLIDVParse, "Set a breakpoint" }, { "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", _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" }, { "c", _continue, 0, "Continue execution" },
{ "continue", _continue, 0, "Continue execution" }, { "continue", _continue, 0, "Continue execution" },
{ "d", _clearBreakpoint, CLIDVParse, "Delete a breakpoint" }, { "d", _clearBreakpoint, CLIDVParse, "Delete a breakpoint" },
{ "delete", _clearBreakpoint, CLIDVParse, "Delete a breakpoint" }, { "delete", _clearBreakpoint, CLIDVParse, "Delete a breakpoint" },
{ "dis", _disassemble, CLIDVParse, "Disassemble instructions" }, { "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", _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", _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" }, { "h", _printHelp, CLIDVStringParse, "Print help" },
{ "help", _printHelp, CLIDVStringParse, "Print help" }, { "help", _printHelp, CLIDVStringParse, "Print help" },
{ "i", _printStatus, 0, "Print the current status" }, { "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" }, { "r/4", _readWord, CLIDVParse, "Read a word from a specified offset" },
{ "status", _printStatus, 0, "Print the current status" }, { "status", _printStatus, 0, "Print the current status" },
{ "w", _setWatchpoint, CLIDVParse, "Set a watchpoint" }, { "w", _setWatchpoint, CLIDVParse, "Set a watchpoint" },
{ "watch", _setWatchpoint, CLIDVParse, "Set a watchpoint" },
{ "w/1", _writeByte, CLIDVParse, "Write a byte at a specified offset" }, { "w/1", _writeByte, CLIDVParse, "Write a byte at a specified offset" },
{ "w/2", _writeHalfword, CLIDVParse, "Write a halfword 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/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/1", _dumpByte, CLIDVParse, "Examine bytes at a specified offset" },
{ "x/2", _dumpHalfword, CLIDVParse, "Examine halfwords at a specified offset" }, { "x/2", _dumpHalfword, CLIDVParse, "Examine halfwords at a specified offset" },
{ "x/4", _dumpWord, CLIDVParse, "Examine words 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 } { 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 #ifndef NDEBUG
static void _handleDeath(int sig) { static void _handleDeath(int sig) {
UNUSED(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) { static void _next(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
UNUSED(dv); UNUSED(dv);
if (debugger->d.currentBreakpoint) { debugger->d.core->step(debugger->d.core);
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);
_printStatus(debugger, 0); _printStatus(debugger, 0);
} }
static void _disassemble(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { static void _disassemble(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
_disassembleMode(debugger, dv, debugger->d.cpu->executionMode); debugger->system->disassemble(debugger->system, dv);
}
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);;
}
} }
static void _print(struct CLIDebugger* debugger, struct CLIDebugVector* 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(debugger);
UNUSED(dv); UNUSED(dv);
if (!dv) { if (!dv) {
puts("ARM commands:"); puts("Generic commands:");
int i; int i;
for (i = 0; _debuggerCommands[i].name; ++i) { for (i = 0; _debuggerCommands[i].name; ++i) {
printf("%-10s %s\n", _debuggerCommands[i].name, _debuggerCommands[i].summary); printf("%-10s %s\n", _debuggerCommands[i].name, _debuggerCommands[i].summary);
} }
if (debugger->system) { 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); printf("%s commands:\n", debugger->system->name);
for (i = 0; debugger->system->commands[i].name; ++i) { for (i = 0; debugger->system->commands[i].name; ++i) {
printf("%-10s %s\n", debugger->system->commands[i].name, debugger->system->commands[i].summary); 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) { 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) { for (i = 0; debugger->system->commands[i].name; ++i) {
if (strcmp(debugger->system->commands[i].name, dv->charValue) == 0) { if (strcmp(debugger->system->commands[i].name, dv->charValue) == 0) {
printf(" %s\n", debugger->system->commands[i].summary); 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) { static void _quit(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
UNUSED(dv); UNUSED(dv);
debugger->d.state = DEBUGGER_SHUTDOWN; debugger->d.state = DEBUGGER_SHUTDOWN;
@ -324,13 +211,13 @@ static void _readByte(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
return; return;
} }
uint32_t address = dv->intValue; 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); printf(" 0x%02X\n", value);
} }
static void _reset(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { static void _reset(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
UNUSED(dv); UNUSED(dv);
ARMReset(debugger->d.cpu); debugger->d.core->reset(debugger->d.core);
_printStatus(debugger, 0); _printStatus(debugger, 0);
} }
@ -340,7 +227,7 @@ static void _readHalfword(struct CLIDebugger* debugger, struct CLIDebugVector* d
return; return;
} }
uint32_t address = dv->intValue; 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); printf(" 0x%04X\n", value);
} }
@ -350,7 +237,7 @@ static void _readWord(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
return; return;
} }
uint32_t address = dv->intValue; 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); printf(" 0x%08X\n", value);
} }
@ -369,7 +256,7 @@ static void _writeByte(struct CLIDebugger* debugger, struct CLIDebugVector* dv)
printf("%s\n", ERROR_OVERFLOW); printf("%s\n", ERROR_OVERFLOW);
return; 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) { 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); printf("%s\n", ERROR_OVERFLOW);
return; 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) { 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 address = dv->intValue;
uint32_t value = dv->next->intValue; uint32_t value = dv->next->intValue;
debugger->d.cpu->memory.store32(debugger->d.cpu, address, value, 0); debugger->d.core->busWrite32(debugger->d.core, address, value);
}
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;
} }
static void _dumpByte(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { 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); printf("0x%08X:", address);
for (; line > 0; --line, ++address, --words) { 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(" %02X", value);
} }
printf("\n"); printf("\n");
@ -462,7 +332,7 @@ static void _dumpHalfword(struct CLIDebugger* debugger, struct CLIDebugVector* d
} }
printf("0x%08X:", address); printf("0x%08X:", address);
for (; line > 0; --line, address += 2, --words) { 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(" %04X", value);
} }
printf("\n"); printf("\n");
@ -486,7 +356,7 @@ static void _dumpWord(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
} }
printf("0x%08X:", address); printf("0x%08X:", address);
for (; line > 0; --line, address += 4, --words) { 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(" %08X", value);
} }
printf("\n"); printf("\n");
@ -499,35 +369,7 @@ static void _setBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector*
return; return;
} }
uint32_t address = dv->intValue; uint32_t address = dv->intValue;
DebuggerSetBreakpoint(&debugger->d, address); debugger->d.platform->setBreakpoint(debugger->d.platform, 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);
} }
static void _setWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { static void _setWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
@ -536,12 +378,27 @@ static void _setWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector*
return; return;
} }
uint32_t address = dv->intValue; 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) { static void _breakIntoDefault(int signal) {
UNUSED(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) { 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; 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; 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) { if (cliDebugger->system) {
uint32_t value = cliDebugger->system->lookupIdentifier(cliDebugger->system, name, dv); uint32_t value = cliDebugger->system->lookupIdentifier(cliDebugger->system, name, dv);
if (dv->type != CLIDV_ERROR_TYPE) { if (dv->type != CLIDV_ERROR_TYPE) {
@ -605,7 +440,7 @@ static uint32_t _lookupIdentifier(struct Debugger* debugger, const char* name, s
return 0; 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) { switch (tree->token.type) {
case TOKEN_UINT_TYPE: case TOKEN_UINT_TYPE:
return tree->token.uintValue; 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); int result = _tryCommands(debugger, _debuggerCommands, line, cmdLength, args, count - cmdLength - 1);
if (result < 0 && debugger->system) { if (result < 0 && debugger->system) {
result = _tryCommands(debugger, debugger->system->commands, line, cmdLength, args, count - cmdLength - 1); 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) { if (result < 0) {
printf("Command not found\n"); printf("Command not found\n");
@ -765,7 +603,7 @@ static char* _prompt(EditLine* el) {
return "> "; return "> ";
} }
static void _commandLine(struct Debugger* debugger) { static void _commandLine(struct mDebugger* debugger) {
struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger; struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
const char* line; const char* line;
_printStatus(cliDebugger, 0); _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); UNUSED(debugger);
switch (reason) { switch (reason) {
case DEBUGGER_ENTER_MANUAL: case DEBUGGER_ENTER_MANUAL:
@ -874,7 +712,7 @@ static unsigned char _tabComplete(EditLine* elstate, int ch) {
return CC_REDISPLAY; return CC_REDISPLAY;
} }
static void _cliDebuggerInit(struct Debugger* debugger) { static void _cliDebuggerInit(struct mDebugger* debugger) {
struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger; struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
// TODO: get argv[0] // TODO: get argv[0]
cliDebugger->elstate = el_init(binaryName, stdin, stdout, stderr); cliDebugger->elstate = el_init(binaryName, stdin, stdout, stderr);
@ -892,7 +730,7 @@ static void _cliDebuggerInit(struct Debugger* debugger) {
signal(SIGINT, _breakIntoDefault); signal(SIGINT, _breakIntoDefault);
} }
static void _cliDebuggerDeinit(struct Debugger* debugger) { static void _cliDebuggerDeinit(struct mDebugger* debugger) {
struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger; struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
history_end(cliDebugger->histate); history_end(cliDebugger->histate);
el_end(cliDebugger->elstate); 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; struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
bool retain = false; bool retain = false;
if (cliDebugger->system) { if (cliDebugger->system) {
@ -916,7 +754,6 @@ static void _cliDebuggerCustom(struct Debugger* debugger) {
} }
void CLIDebuggerCreate(struct CLIDebugger* debugger) { void CLIDebuggerCreate(struct CLIDebugger* debugger) {
DebuggerCreate(&debugger->d);
debugger->d.init = _cliDebuggerInit; debugger->d.init = _cliDebuggerInit;
debugger->d.deinit = _cliDebuggerDeinit; debugger->d.deinit = _cliDebuggerDeinit;
debugger->d.custom = _cliDebuggerCustom; debugger->d.custom = _cliDebuggerCustom;
@ -935,3 +772,5 @@ void CLIDebuggerAttachSystem(struct CLIDebugger* debugger, struct CLIDebuggerSys
debugger->system = system; debugger->system = system;
system->p = debugger; system->p = debugger;
} }
#endif

View File

@ -45,14 +45,18 @@ struct CLIDebuggerSystem {
void (*deinit)(struct CLIDebuggerSystem*); void (*deinit)(struct CLIDebuggerSystem*);
bool (*custom)(struct CLIDebuggerSystem*); bool (*custom)(struct CLIDebuggerSystem*);
void (*disassemble)(struct CLIDebuggerSystem*, struct CLIDebugVector* dv);
uint32_t (*lookupIdentifier)(struct CLIDebuggerSystem*, const char* name, struct CLIDebugVector* dv); uint32_t (*lookupIdentifier)(struct CLIDebuggerSystem*, const char* name, struct CLIDebugVector* dv);
void (*printStatus)(struct CLIDebuggerSystem*);
struct CLIDebuggerCommandSummary* commands; struct CLIDebuggerCommandSummary* commands;
const char* name; const char* name;
struct CLIDebuggerCommandSummary* platformCommands;
const char* platformName;
}; };
struct CLIDebugger { struct CLIDebugger {
struct Debugger d; struct mDebugger d;
struct CLIDebuggerSystem* system; struct CLIDebuggerSystem* system;

View File

@ -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 * 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 * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "debugger.h" #include "debugger.h"
#include "arm.h" #include "core/core.h"
#include "isa-inlines.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; const uint32_t DEBUGGER_ID = 0xDEADBEEF;
DEFINE_VECTOR(DebugBreakpointList, struct DebugBreakpoint);
DEFINE_VECTOR(DebugWatchpointList, struct DebugWatchpoint);
mLOG_DEFINE_CATEGORY(DEBUGGER, "Debugger"); mLOG_DEFINE_CATEGORY(DEBUGGER, "Debugger");
static struct DebugBreakpoint* _lookupBreakpoint(struct DebugBreakpointList* breakpoints, uint32_t address) { static void mDebuggerInit(void* cpu, struct mCPUComponent* component);
size_t i; static void mDebuggerDeinit(struct mCPUComponent* component);
for (i = 0; i < DebugBreakpointListSize(breakpoints); ++i) {
if (DebugBreakpointListGetPointer(breakpoints, i)->address == address) {
return DebugBreakpointListGetPointer(breakpoints, i);
}
}
return 0;
}
static void _checkBreakpoints(struct Debugger* debugger) { struct mDebugger* mDebuggerCreate(enum mDebuggerType type, struct mCore* core) {
int instructionLength; if (!core->supportsDebuggerType(core, type)) {
enum ExecutionMode mode = debugger->cpu->cpsr.t; return NULL;
if (mode == MODE_ARM) {
instructionLength = WORD_SIZE_ARM;
} else {
instructionLength = WORD_SIZE_THUMB;
} }
struct DebugBreakpoint* breakpoint = _lookupBreakpoint(&debugger->breakpoints, debugger->cpu->gprs[ARM_PC] - instructionLength);
if (!breakpoint) { union DebugUnion {
return; struct mDebugger d;
} #ifdef USE_CLI_DEBUGGER
struct DebuggerEntryInfo info = { struct CLIDebugger cli;
.address = breakpoint->address #endif
#ifdef USE_GDB_STUB
struct GDBStub gdb;
#endif
}; };
DebuggerEnter(debugger, DEBUGGER_ENTER_BREAKPOINT, &info);
}
static void DebuggerInit(void* cpu, struct mCPUComponent*); union DebugUnion* debugger = malloc(sizeof(union DebugUnion));
static void DebuggerDeinit(struct mCPUComponent*);
void DebuggerCreate(struct Debugger* debugger) { switch (type) {
debugger->d.id = DEBUGGER_ID; #ifdef USE_CLI_DEBUGGER
debugger->d.init = DebuggerInit; case DEBUGGER_CLI:
debugger->d.deinit = DebuggerDeinit; CLIDebuggerCreate(&debugger->cli);
} struct CLIDebuggerSystem* sys = core->cliDebuggerSystem(core);
CLIDebuggerAttachSystem(&debugger->cli, sys);
void DebuggerInit(void* cpu, struct mCPUComponent* component) { break;
struct Debugger* debugger = (struct Debugger*) component; #endif
debugger->cpu = cpu; #ifdef USE_GDB_STUB
debugger->state = DEBUGGER_RUNNING; case DEBUGGER_GDB:
debugger->originalMemory = debugger->cpu->memory; GDBStubCreate(&debugger->gdb);
debugger->currentBreakpoint = 0; GDBStubListen(&debugger->gdb, 2345, 0);
DebugBreakpointListInit(&debugger->breakpoints, 0); break;
DebugBreakpointListInit(&debugger->swBreakpoints, 0); #endif
DebugWatchpointListInit(&debugger->watchpoints, 0); case DEBUGGER_NONE:
if (debugger->init) { case DEBUGGER_MAX:
debugger->init(debugger); free(debugger);
return 0;
break;
} }
return &debugger->d;
} }
void DebuggerDeinit(struct mCPUComponent* component) { void mDebuggerAttach(struct mDebugger* debugger, struct mCore* core) {
struct Debugger* debugger = (struct Debugger*) component; debugger->d.id = DEBUGGER_ID;
debugger->deinit(debugger); debugger->d.init = mDebuggerInit;
DebugBreakpointListDeinit(&debugger->breakpoints); debugger->d.deinit = mDebuggerDeinit;
DebugBreakpointListDeinit(&debugger->swBreakpoints); debugger->core = core;
DebugWatchpointListDeinit(&debugger->watchpoints); 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) { switch (debugger->state) {
case DEBUGGER_RUNNING: case DEBUGGER_RUNNING:
if (!DebugBreakpointListSize(&debugger->breakpoints) && !DebugWatchpointListSize(&debugger->watchpoints)) { if (!debugger->platform->hasBreakpoints(debugger->platform)) {
ARMRunLoop(debugger->cpu); debugger->core->runLoop(debugger->core);
} else { } else {
ARMRun(debugger->cpu); debugger->core->step(debugger->core);
_checkBreakpoints(debugger); debugger->platform->checkBreakpoints(debugger->platform);
} }
break; break;
case DEBUGGER_CUSTOM: case DEBUGGER_CUSTOM:
ARMRun(debugger->cpu); debugger->core->step(debugger->core);
_checkBreakpoints(debugger); debugger->platform->checkBreakpoints(debugger->platform);
debugger->custom(debugger); debugger->custom(debugger);
break; break;
case DEBUGGER_PAUSED: case DEBUGGER_PAUSED:
@ -97,89 +95,32 @@ void DebuggerRun(struct Debugger* debugger) {
} else { } else {
debugger->state = DEBUGGER_RUNNING; 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; break;
case DEBUGGER_SHUTDOWN: case DEBUGGER_SHUTDOWN:
return; 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; 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) { if (debugger->entered) {
debugger->entered(debugger, reason, info); debugger->entered(debugger, reason, info);
} }
} }
void DebuggerSetBreakpoint(struct Debugger* debugger, uint32_t address) { static void mDebuggerInit(void* cpu, struct mCPUComponent* component) {
struct DebugBreakpoint* breakpoint = DebugBreakpointListAppend(&debugger->breakpoints); struct mDebugger* debugger = (struct mDebugger*) component;
breakpoint->address = address; debugger->state = DEBUGGER_RUNNING;
breakpoint->isSw = false; debugger->platform->init(cpu, debugger->platform);
} if (debugger->init) {
debugger->init(debugger);
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 mDebuggerDeinit(struct mCPUComponent* component) {
struct mDebugger* debugger = (struct mDebugger*) component;
if (debugger->deinit) {
debugger->deinit(debugger);
}
debugger->platform->deinit(debugger->platform);
}

View File

@ -16,7 +16,7 @@ mLOG_DECLARE_CATEGORY(DEBUGGER);
extern const uint32_t DEBUGGER_ID; extern const uint32_t DEBUGGER_ID;
enum DebuggerType { enum mDebuggerType {
DEBUGGER_NONE = 0, DEBUGGER_NONE = 0,
#ifdef USE_CLI_DEBUGGER #ifdef USE_CLI_DEBUGGER
DEBUGGER_CLI, DEBUGGER_CLI,
@ -27,37 +27,20 @@ enum DebuggerType {
DEBUGGER_MAX DEBUGGER_MAX
}; };
enum DebuggerState { enum mDebuggerState {
DEBUGGER_PAUSED, DEBUGGER_PAUSED,
DEBUGGER_RUNNING, DEBUGGER_RUNNING,
DEBUGGER_CUSTOM, DEBUGGER_CUSTOM,
DEBUGGER_SHUTDOWN DEBUGGER_SHUTDOWN
}; };
struct DebugBreakpoint { enum mWatchpointType {
uint32_t address;
bool isSw;
struct {
uint32_t opcode;
enum ExecutionMode mode;
} sw;
};
enum WatchpointType {
WATCHPOINT_WRITE = 1, WATCHPOINT_WRITE = 1,
WATCHPOINT_READ = 2, WATCHPOINT_READ = 2,
WATCHPOINT_RW = WATCHPOINT_WRITE | WATCHPOINT_READ WATCHPOINT_RW = WATCHPOINT_WRITE | WATCHPOINT_READ
}; };
struct DebugWatchpoint { enum mDebuggerEntryReason {
uint32_t address;
enum WatchpointType type;
};
DECLARE_VECTOR(DebugBreakpointList, struct DebugBreakpoint);
DECLARE_VECTOR(DebugWatchpointList, struct DebugWatchpoint);
enum DebuggerEntryReason {
DEBUGGER_ENTER_MANUAL, DEBUGGER_ENTER_MANUAL,
DEBUGGER_ENTER_ATTACHED, DEBUGGER_ENTER_ATTACHED,
DEBUGGER_ENTER_BREAKPOINT, DEBUGGER_ENTER_BREAKPOINT,
@ -65,14 +48,17 @@ enum DebuggerEntryReason {
DEBUGGER_ENTER_ILLEGAL_OP DEBUGGER_ENTER_ILLEGAL_OP
}; };
struct DebuggerEntryInfo { extern const char* ERROR_MISSING_ARGS;
extern const char* ERROR_OVERFLOW;
struct mDebuggerEntryInfo {
uint32_t address; uint32_t address;
union { union {
struct { struct {
uint32_t oldValue; uint32_t oldValue;
uint32_t newValue; uint32_t newValue;
enum WatchpointType watchType; enum mWatchpointType watchType;
enum WatchpointType accessType; enum mWatchpointType accessType;
}; };
struct { struct {
@ -81,35 +67,40 @@ struct DebuggerEntryInfo {
}; };
}; };
struct Debugger { struct mDebugger;
struct mCPUComponent d; struct mDebuggerPlatform {
enum DebuggerState state; struct mDebugger* p;
struct ARMCore* cpu;
struct DebugBreakpointList breakpoints; void (*init)(void* cpu, struct mDebuggerPlatform*);
struct DebugBreakpointList swBreakpoints; void (*deinit)(struct mDebuggerPlatform*);
struct DebugWatchpointList watchpoints; void (*entered)(struct mDebuggerPlatform*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*);
struct ARMMemory originalMemory;
struct DebugBreakpoint* currentBreakpoint; bool (*hasBreakpoints)(struct mDebuggerPlatform*);
void (*setBreakpoint)(struct mDebuggerPlatform*, uint32_t address);
void (*init)(struct Debugger*); void (*clearBreakpoint)(struct mDebuggerPlatform*, uint32_t address);
void (*deinit)(struct Debugger*); void (*setWatchpoint)(struct mDebuggerPlatform*, uint32_t address, enum mWatchpointType type);
void (*paused)(struct Debugger*); void (*clearWatchpoint)(struct mDebuggerPlatform*, uint32_t address);
void (*entered)(struct Debugger*, enum DebuggerEntryReason, struct DebuggerEntryInfo*); void (*checkBreakpoints)(struct mDebuggerPlatform*);
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);
}; };
void DebuggerCreate(struct Debugger*); struct mDebugger {
void DebuggerRun(struct Debugger*); struct mCPUComponent d;
void DebuggerEnter(struct Debugger*, enum DebuggerEntryReason, struct DebuggerEntryInfo*); struct mDebuggerPlatform* platform;
void DebuggerSetBreakpoint(struct Debugger* debugger, uint32_t address); enum mDebuggerState state;
bool DebuggerSetSoftwareBreakpoint(struct Debugger* debugger, uint32_t address, enum ExecutionMode mode); struct mCore* core;
void DebuggerClearBreakpoint(struct Debugger* debugger, uint32_t address);
void DebuggerSetWatchpoint(struct Debugger* debugger, uint32_t address, enum WatchpointType type); void (*init)(struct mDebugger*);
void DebuggerClearWatchpoint(struct Debugger* debugger, uint32_t address); 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 #endif

View File

@ -5,6 +5,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "gdb-stub.h" #include "gdb-stub.h"
#include "core/core.h"
#include <signal.h> #include <signal.h>
#ifndef SIGTRAP #ifndef SIGTRAP
@ -26,14 +28,14 @@ enum {
static void _sendMessage(struct GDBStub* stub); static void _sendMessage(struct GDBStub* stub);
static void _gdbStubDeinit(struct Debugger* debugger) { static void _gdbStubDeinit(struct mDebugger* debugger) {
struct GDBStub* stub = (struct GDBStub*) debugger; struct GDBStub* stub = (struct GDBStub*) debugger;
if (!SOCKET_FAILED(stub->socket)) { if (!SOCKET_FAILED(stub->socket)) {
GDBStubShutdown(stub); 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; struct GDBStub* stub = (struct GDBStub*) debugger;
switch (reason) { switch (reason) {
case DEBUGGER_ENTER_MANUAL: case DEBUGGER_ENTER_MANUAL:
@ -76,7 +78,7 @@ static void _gdbStubEntered(struct Debugger* debugger, enum DebuggerEntryReason
_sendMessage(stub); _sendMessage(stub);
} }
static void _gdbStubPoll(struct Debugger* debugger) { static void _gdbStubPoll(struct mDebugger* debugger) {
struct GDBStub* stub = (struct GDBStub*) debugger; struct GDBStub* stub = (struct GDBStub*) debugger;
--stub->untilPoll; --stub->untilPoll;
if (stub->untilPoll > 0) { if (stub->untilPoll > 0) {
@ -87,7 +89,7 @@ static void _gdbStubPoll(struct Debugger* debugger) {
GDBStubUpdate(stub); GDBStubUpdate(stub);
} }
static void _gdbStubWait(struct Debugger* debugger) { static void _gdbStubWait(struct mDebugger* debugger) {
struct GDBStub* stub = (struct GDBStub*) debugger; struct GDBStub* stub = (struct GDBStub*) debugger;
stub->shouldBlock = true; stub->shouldBlock = true;
GDBStubUpdate(stub); GDBStubUpdate(stub);
@ -201,7 +203,7 @@ static void _continue(struct GDBStub* stub, const char* message) {
} }
static void _step(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); snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "S%02x", SIGTRAP);
_sendMessage(stub); _sendMessage(stub);
// TODO: parse message // TODO: parse message
@ -218,7 +220,7 @@ static void _readMemory(struct GDBStub* stub, const char* message) {
_error(stub, GDB_BAD_ARGUMENTS); _error(stub, GDB_BAD_ARGUMENTS);
return; return;
} }
struct ARMCore* cpu = stub->d.cpu; struct ARMCore* cpu = stub->d.core->cpu;
int writeAddress = 0; int writeAddress = 0;
for (i = 0; i < size; ++i, writeAddress += 2) { for (i = 0; i < size; ++i, writeAddress += 2) {
uint8_t byte = cpu->memory.load8(cpu, address + i, 0); 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) { static void _readGPRs(struct GDBStub* stub, const char* message) {
struct ARMCore* cpu = stub->d.core->cpu;
UNUSED(message); UNUSED(message);
int r; int r;
int i = 0; int i = 0;
for (r = 0; r < 16; ++r) { for (r = 0; r < 16; ++r) {
_int2hex32(stub->d.cpu->gprs[r], &stub->outgoing[i]); _int2hex32(cpu->gprs[r], &stub->outgoing[i]);
i += 8; i += 8;
} }
stub->outgoing[i] = 0; 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) { static void _readRegister(struct GDBStub* stub, const char* message) {
struct ARMCore* cpu = stub->d.core->cpu;
const char* readAddress = message; const char* readAddress = message;
unsigned i = 0; unsigned i = 0;
uint32_t reg = _readHex(readAddress, &i); uint32_t reg = _readHex(readAddress, &i);
uint32_t value; uint32_t value;
if (reg < 0x10) { if (reg < 0x10) {
value = stub->d.cpu->gprs[reg]; value = cpu->gprs[reg];
} else if (reg == 0x19) { } else if (reg == 0x19) {
value = stub->d.cpu->cpsr.packed; value = cpu->cpsr.packed;
} else { } else {
stub->outgoing[0] = '\0'; stub->outgoing[0] = '\0';
_sendMessage(stub); _sendMessage(stub);
@ -298,7 +302,7 @@ static void _processVReadCommand(struct GDBStub* stub, const char* message) {
stub->outgoing[0] = '\0'; stub->outgoing[0] = '\0';
if (!strncmp("Attach", message, 6)) { if (!strncmp("Attach", message, 6)) {
strncpy(stub->outgoing, "1", GDB_STUB_MAX_LINE - 4); 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); _sendMessage(stub);
} }
@ -314,22 +318,22 @@ static void _setBreakpoint(struct GDBStub* stub, const char* message) {
switch (message[0]) { switch (message[0]) {
case '0': // Memory breakpoints are not currently supported case '0': // Memory breakpoints are not currently supported
case '1': case '1':
DebuggerSetBreakpoint(&stub->d, address); stub->d.platform->setBreakpoint(stub->d.platform, address);
strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4); strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4);
_sendMessage(stub); _sendMessage(stub);
break; break;
case '2': 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); strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4);
_sendMessage(stub); _sendMessage(stub);
break; break;
case '3': 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); strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4);
_sendMessage(stub); _sendMessage(stub);
break; break;
case '4': 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); strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4);
_sendMessage(stub); _sendMessage(stub);
break; break;
@ -347,12 +351,12 @@ static void _clearBreakpoint(struct GDBStub* stub, const char* message) {
switch (message[0]) { switch (message[0]) {
case '0': // Memory breakpoints are not currently supported case '0': // Memory breakpoints are not currently supported
case '1': case '1':
DebuggerClearBreakpoint(&stub->d, address); stub->d.platform->clearBreakpoint(stub->d.platform, address);
break; break;
case '2': case '2':
case '3': case '3':
case '4': case '4':
DebuggerClearWatchpoint(&stub->d, address); stub->d.platform->clearWatchpoint(stub->d.platform, address);
break; break;
default: default:
break; break;
@ -375,7 +379,7 @@ size_t _parseGDBMessage(struct GDBStub* stub, const char* message) {
++message; ++message;
break; break;
case '\x03': case '\x03':
DebuggerEnter(&stub->d, DEBUGGER_ENTER_MANUAL, 0); mDebuggerEnter(&stub->d, DEBUGGER_ENTER_MANUAL, 0);
return parsed; return parsed;
default: default:
_nak(stub); _nak(stub);
@ -462,7 +466,6 @@ size_t _parseGDBMessage(struct GDBStub* stub, const char* message) {
} }
void GDBStubCreate(struct GDBStub* stub) { void GDBStubCreate(struct GDBStub* stub) {
DebuggerCreate(&stub->d);
stub->socket = INVALID_SOCKET; stub->socket = INVALID_SOCKET;
stub->connection = INVALID_SOCKET; stub->connection = INVALID_SOCKET;
stub->d.init = 0; stub->d.init = 0;
@ -536,7 +539,7 @@ void GDBStubUpdate(struct GDBStub* stub) {
if (!SocketSetBlocking(stub->connection, false)) { if (!SocketSetBlocking(stub->connection, false)) {
goto connectionLost; goto connectionLost;
} }
DebuggerEnter(&stub->d, DEBUGGER_ENTER_ATTACHED, 0); mDebuggerEnter(&stub->d, DEBUGGER_ENTER_ATTACHED, 0);
} else if (SocketWouldBlock()) { } else if (SocketWouldBlock()) {
return; return;
} else { } else {

View File

@ -23,7 +23,7 @@ enum GDBStubAckState {
}; };
struct GDBStub { struct GDBStub {
struct Debugger d; struct mDebugger d;
char line[GDB_STUB_MAX_LINE]; char line[GDB_STUB_MAX_LINE];
char outgoing[GDB_STUB_MAX_LINE]; char outgoing[GDB_STUB_MAX_LINE];

View File

@ -254,12 +254,56 @@ static void _GBCoreSetRumble(struct mCore* core, struct mRumble* rumble) {
gb->memory.rumble = 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 mCore* GBCoreCreate(void) {
struct GBCore* gbcore = malloc(sizeof(*gbcore)); struct GBCore* gbcore = malloc(sizeof(*gbcore));
struct mCore* core = &gbcore->d; struct mCore* core = &gbcore->d;
memset(&core->opts, 0, sizeof(core->opts)); memset(&core->opts, 0, sizeof(core->opts));
core->cpu = 0; core->cpu = NULL;
core->board = 0; core->board = NULL;
core->debugger = NULL;
core->init = _GBCoreInit; core->init = _GBCoreInit;
core->deinit = _GBCoreDeinit; core->deinit = _GBCoreDeinit;
core->platform = _GBCorePlatform; core->platform = _GBCorePlatform;
@ -295,5 +339,13 @@ struct mCore* GBCoreCreate(void) {
core->setRTC = _GBCoreSetRTC; core->setRTC = _GBCoreSetRTC;
core->setRotation = _GBCoreSetRotation; core->setRotation = _GBCoreSetRotation;
core->setRumble = _GBCoreSetRumble; 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; return core;
} }

View File

@ -165,11 +165,12 @@ void GBACheatSetDeinit(struct GBACheatSet* set) {
} }
void GBACheatAttachDevice(struct GBA* gba, struct GBACheatDevice* device) { void GBACheatAttachDevice(struct GBA* gba, struct GBACheatDevice* device) {
if (gba->cpu->components[GBA_COMPONENT_CHEAT_DEVICE]) { // TODO: Remove this function
ARMHotplugDetach(gba->cpu, GBA_COMPONENT_CHEAT_DEVICE); if (gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE]) {
ARMHotplugDetach(gba->cpu, CPU_COMPONENT_CHEAT_DEVICE);
} }
gba->cpu->components[GBA_COMPONENT_CHEAT_DEVICE] = &device->d; gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE] = &device->d;
ARMHotplugAttach(gba->cpu, GBA_COMPONENT_CHEAT_DEVICE); ARMHotplugAttach(gba->cpu, CPU_COMPONENT_CHEAT_DEVICE);
} }
void GBACheatAddSet(struct GBACheatDevice* device, struct GBACheatSet* cheats) { void GBACheatAddSet(struct GBACheatDevice* device, struct GBACheatSet* cheats) {

View File

@ -11,6 +11,7 @@
#include "gba/context/overrides.h" #include "gba/context/overrides.h"
#include "gba/renderers/video-software.h" #include "gba/renderers/video-software.h"
#include "gba/serialize.h" #include "gba/serialize.h"
#include "gba/supervisor/cli.h"
#include "util/memory.h" #include "util/memory.h"
#include "util/patch.h" #include "util/patch.h"
#include "util/vfs.h" #include "util/vfs.h"
@ -19,8 +20,9 @@ struct GBACore {
struct mCore d; struct mCore d;
struct GBAVideoSoftwareRenderer renderer; struct GBAVideoSoftwareRenderer renderer;
int keys; int keys;
struct mCPUComponent* components[GBA_COMPONENT_MAX]; struct mCPUComponent* components[CPU_COMPONENT_MAX];
const struct Configuration* overrides; const struct Configuration* overrides;
struct mDebuggerPlatform* debuggerPlatform;
}; };
static bool _GBACoreInit(struct mCore* core) { static bool _GBACoreInit(struct mCore* core) {
@ -35,12 +37,14 @@ static bool _GBACoreInit(struct mCore* core) {
} }
core->cpu = cpu; core->cpu = cpu;
core->board = gba; core->board = gba;
core->debugger = NULL;
gbacore->debuggerPlatform = NULL;
gbacore->overrides = 0; gbacore->overrides = 0;
GBACreate(gba); GBACreate(gba);
// TODO: Restore debugger and cheats // TODO: Restore debugger and cheats
memset(gbacore->components, 0, sizeof(gbacore->components)); 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); ARMInit(cpu);
GBAVideoSoftwareRendererCreate(&gbacore->renderer); GBAVideoSoftwareRendererCreate(&gbacore->renderer);
@ -288,12 +292,90 @@ static void _GBACoreSetRumble(struct mCore* core, struct mRumble* rumble) {
gba->rumble = 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 mCore* GBACoreCreate(void) {
struct GBACore* gbacore = malloc(sizeof(*gbacore)); struct GBACore* gbacore = malloc(sizeof(*gbacore));
struct mCore* core = &gbacore->d; struct mCore* core = &gbacore->d;
memset(&core->opts, 0, sizeof(core->opts)); memset(&core->opts, 0, sizeof(core->opts));
core->cpu = 0; core->cpu = NULL;
core->board = 0; core->board = NULL;
core->debugger = NULL;
core->init = _GBACoreInit; core->init = _GBACoreInit;
core->deinit = _GBACoreDeinit; core->deinit = _GBACoreDeinit;
core->platform = _GBACorePlatform; core->platform = _GBACorePlatform;
@ -329,5 +411,16 @@ struct mCore* GBACoreCreate(void) {
core->setRTC = _GBACoreSetRTC; core->setRTC = _GBACoreSetRTC;
core->setRotation = _GBACoreSetRotation; core->setRotation = _GBACoreSetRotation;
core->setRumble = _GBACoreSetRumble; 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; return core;
} }

View File

@ -42,8 +42,8 @@ static void GBAHitStub(struct ARMCore* cpu, uint32_t opcode);
static void GBAIllegal(struct ARMCore* cpu, uint32_t opcode); static void GBAIllegal(struct ARMCore* cpu, uint32_t opcode);
static void GBABreakpoint(struct ARMCore* cpu, int immediate); static void GBABreakpoint(struct ARMCore* cpu, int immediate);
static bool _setSoftwareBreakpoint(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 Debugger*, 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 #ifdef _3DS
@ -403,18 +403,18 @@ static int32_t GBATimersProcessEvents(struct GBA* gba, int32_t cycles) {
return nextEvent; return nextEvent;
} }
void GBAAttachDebugger(struct GBA* gba, struct Debugger* debugger) { void GBAAttachDebugger(struct GBA* gba, struct mDebugger* debugger) {
debugger->setSoftwareBreakpoint = _setSoftwareBreakpoint; gba->debugger = (struct ARMDebugger*) debugger->platform;
debugger->clearSoftwareBreakpoint = _clearSoftwareBreakpoint; gba->debugger->setSoftwareBreakpoint = _setSoftwareBreakpoint;
gba->debugger = debugger; gba->debugger->clearSoftwareBreakpoint = _clearSoftwareBreakpoint;
gba->cpu->components[GBA_COMPONENT_DEBUGGER] = &debugger->d; gba->cpu->components[CPU_COMPONENT_DEBUGGER] = &debugger->d;
ARMHotplugAttach(gba->cpu, GBA_COMPONENT_DEBUGGER); ARMHotplugAttach(gba->cpu, CPU_COMPONENT_DEBUGGER);
} }
void GBADetachDebugger(struct GBA* gba) { void GBADetachDebugger(struct GBA* gba) {
gba->debugger = 0; gba->debugger = 0;
ARMHotplugDetach(gba->cpu, GBA_COMPONENT_DEBUGGER); ARMHotplugDetach(gba->cpu, CPU_COMPONENT_DEBUGGER);
gba->cpu->components[GBA_COMPONENT_DEBUGGER] = 0; gba->cpu->components[CPU_COMPONENT_DEBUGGER] = 0;
} }
bool GBALoadMB(struct GBA* gba, struct VFile* vf) { 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) { void GBAHitStub(struct ARMCore* cpu, uint32_t opcode) {
struct GBA* gba = (struct GBA*) cpu->master; struct GBA* gba = (struct GBA*) cpu->master;
if (gba->debugger) { if (gba->debugger) {
struct DebuggerEntryInfo info = { struct mDebuggerEntryInfo info = {
.address = _ARMPCAddress(cpu), .address = _ARMPCAddress(cpu),
.opcode = opcode .opcode = opcode
}; };
DebuggerEnter(gba->debugger, DEBUGGER_ENTER_ILLEGAL_OP, &info); mDebuggerEnter(gba->debugger->d.p, DEBUGGER_ENTER_ILLEGAL_OP, &info);
} }
// TODO: More sensible category? // TODO: More sensible category?
mLOG(GBA, ERROR, "Stub opcode: %08x", opcode); 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); mLOG(GBA, WARN, "Illegal opcode: %08x", opcode);
} }
if (gba->debugger) { if (gba->debugger) {
struct DebuggerEntryInfo info = { struct mDebuggerEntryInfo info = {
.address = _ARMPCAddress(cpu), .address = _ARMPCAddress(cpu),
.opcode = opcode .opcode = opcode
}; };
DebuggerEnter(gba->debugger, DEBUGGER_ENTER_ILLEGAL_OP, &info); mDebuggerEnter(gba->debugger->d.p, DEBUGGER_ENTER_ILLEGAL_OP, &info);
} else { } else {
ARMRaiseUndefined(cpu); ARMRaiseUndefined(cpu);
} }
@ -760,21 +760,21 @@ void GBAIllegal(struct ARMCore* cpu, uint32_t opcode) {
void GBABreakpoint(struct ARMCore* cpu, int immediate) { void GBABreakpoint(struct ARMCore* cpu, int immediate) {
struct GBA* gba = (struct GBA*) cpu->master; struct GBA* gba = (struct GBA*) cpu->master;
if (immediate >= GBA_COMPONENT_MAX) { if (immediate >= CPU_COMPONENT_MAX) {
return; return;
} }
switch (immediate) { switch (immediate) {
case GBA_COMPONENT_DEBUGGER: case CPU_COMPONENT_DEBUGGER:
if (gba->debugger) { if (gba->debugger) {
struct DebuggerEntryInfo info = { struct mDebuggerEntryInfo info = {
.address = _ARMPCAddress(cpu) .address = _ARMPCAddress(cpu)
}; };
DebuggerEnter(gba->debugger, DEBUGGER_ENTER_BREAKPOINT, &info); mDebuggerEnter(gba->debugger->d.p, DEBUGGER_ENTER_BREAKPOINT, &info);
} }
break; break;
case GBA_COMPONENT_CHEAT_DEVICE: case CPU_COMPONENT_CHEAT_DEVICE:
if (gba->cpu->components[GBA_COMPONENT_CHEAT_DEVICE]) { if (gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE]) {
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 GBACheatHook* hook = 0; struct GBACheatHook* hook = 0;
size_t i; size_t i;
for (i = 0; i < GBACheatSetsSize(&device->cheats); ++i) { for (i = 0; i < GBACheatSetsSize(&device->cheats); ++i) {
@ -807,8 +807,8 @@ void GBAFrameEnded(struct GBA* gba) {
gba->rr->nextFrame(gba->rr); gba->rr->nextFrame(gba->rr);
} }
if (gba->cpu->components && 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[GBA_COMPONENT_CHEAT_DEVICE]; struct GBACheatDevice* device = (struct GBACheatDevice*) gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE];
size_t i; size_t i;
for (i = 0; i < GBACheatSetsSize(&device->cheats); ++i) { for (i = 0; i < GBACheatSetsSize(&device->cheats); ++i) {
struct GBACheatSet* cheats = *GBACheatSetsGetPointer(&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) { static bool _setSoftwareBreakpoint(struct ARMDebugger* debugger, uint32_t address, enum ExecutionMode mode, uint32_t* opcode) {
GBASetBreakpoint((struct GBA*) debugger->cpu->master, &debugger->d, address, mode, opcode); GBASetBreakpoint((struct GBA*) debugger->cpu->master, &debugger->d.p->d, address, mode, opcode);
return true; 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); GBAClearBreakpoint((struct GBA*) debugger->cpu->master, address, mode, opcode);
return true; return true;
} }

View File

@ -9,8 +9,8 @@
#include "util/common.h" #include "util/common.h"
#include "arm/arm.h" #include "arm/arm.h"
#include "arm/debugger.h"
#include "core/log.h" #include "core/log.h"
#include "debugger/debugger.h"
#include "gba/interface.h" #include "gba/interface.h"
#include "gba/memory.h" #include "gba/memory.h"
@ -37,12 +37,6 @@ enum GBAIRQ {
IRQ_GAMEPAK = 0xD IRQ_GAMEPAK = 0xD
}; };
enum GBAComponent {
GBA_COMPONENT_DEBUGGER,
GBA_COMPONENT_CHEAT_DEVICE,
GBA_COMPONENT_MAX
};
enum GBAIdleLoopOptimization { enum GBAIdleLoopOptimization {
IDLE_LOOP_IGNORE = -1, IDLE_LOOP_IGNORE = -1,
IDLE_LOOP_REMOVE = 0, IDLE_LOOP_REMOVE = 0,
@ -87,7 +81,7 @@ struct GBA {
struct mCoreSync* sync; struct mCoreSync* sync;
struct Debugger* debugger; struct ARMDebugger* debugger;
uint32_t bus; uint32_t bus;
int performingDMA; int performingDMA;
@ -161,7 +155,7 @@ void GBATestIRQ(struct ARMCore* cpu);
void GBAHalt(struct GBA* gba); void GBAHalt(struct GBA* gba);
void GBAStop(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 GBADetachDebugger(struct GBA* gba);
void GBASetBreakpoint(struct GBA* gba, struct mCPUComponent* component, uint32_t address, enum ExecutionMode mode, void GBASetBreakpoint(struct GBA* gba, struct mCPUComponent* component, uint32_t address, enum ExecutionMode mode,

View File

@ -382,8 +382,8 @@ bool GBASaveStateNamed(struct GBA* gba, struct VFile* vf, int flags) {
svf->close(svf); svf->close(svf);
} }
struct VFile* cheatVf = 0; struct VFile* cheatVf = 0;
if (flags & SAVESTATE_CHEATS && gba->cpu->components && 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[GBA_COMPONENT_CHEAT_DEVICE]; struct GBACheatDevice* device = (struct GBACheatDevice*) gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE];
cheatVf = VFileMemChunk(0, 0); cheatVf = VFileMemChunk(0, 0);
if (cheatVf) { if (cheatVf) {
GBACheatSaveFile(device, cheatVf); GBACheatSaveFile(device, cheatVf);
@ -477,9 +477,9 @@ bool GBALoadStateNamed(struct GBA* gba, struct VFile* vf, int flags) {
svf->close(svf); 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) { 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); struct VFile* svf = VFileFromMemory(item.data, item.size);
if (svf) { if (svf) {
GBACheatDeviceClear(device); GBACheatDeviceClear(device);

View File

@ -5,13 +5,12 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "cli.h" #include "cli.h"
#include "arm/cli-debugger.h"
#include "gba/io.h" #include "gba/io.h"
#include "gba/serialize.h" #include "gba/serialize.h"
#ifdef USE_CLI_DEBUGGER #ifdef USE_CLI_DEBUGGER
static const char* ERROR_MISSING_ARGS = "Arguments missing"; // TODO: share
static void _GBACLIDebuggerInit(struct CLIDebuggerSystem*); static void _GBACLIDebuggerInit(struct CLIDebuggerSystem*);
static void _GBACLIDebuggerDeinit(struct CLIDebuggerSystem*); static void _GBACLIDebuggerDeinit(struct CLIDebuggerSystem*);
static bool _GBACLIDebuggerCustom(struct CLIDebuggerSystem*); static bool _GBACLIDebuggerCustom(struct CLIDebuggerSystem*);
@ -32,6 +31,7 @@ struct CLIDebuggerCommandSummary _GBACLIDebuggerCommands[] = {
struct GBACLIDebugger* GBACLIDebuggerCreate(struct mCore* core) { struct GBACLIDebugger* GBACLIDebuggerCreate(struct mCore* core) {
struct GBACLIDebugger* debugger = malloc(sizeof(struct GBACLIDebugger)); struct GBACLIDebugger* debugger = malloc(sizeof(struct GBACLIDebugger));
ARMCLIDebuggerCreate(&debugger->d);
debugger->d.init = _GBACLIDebuggerInit; debugger->d.init = _GBACLIDebuggerInit;
debugger->d.deinit = _GBACLIDebuggerDeinit; debugger->d.deinit = _GBACLIDebuggerDeinit;
debugger->d.custom = _GBACLIDebuggerCustom; debugger->d.custom = _GBACLIDebuggerCustom;
@ -60,7 +60,7 @@ static bool _GBACLIDebuggerCustom(struct CLIDebuggerSystem* debugger) {
if (gbaDebugger->frameAdvance) { if (gbaDebugger->frameAdvance) {
if (!gbaDebugger->inVblank && GBARegisterDISPSTATIsInVblank(((struct GBA*) gbaDebugger->core->board)->memory.io[REG_DISPSTAT >> 1])) { 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; gbaDebugger->frameAdvance = false;
return false; return false;
} }

View File

@ -4,19 +4,6 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "commandline.h" #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 "util/string.h"
#include <fcntl.h> #include <fcntl.h>
@ -211,46 +198,6 @@ void _applyGraphicsArgs(struct mSubParser* parser, struct mCoreConfig* config) {
mCoreConfigSetOverrideIntValue(config, "fullscreen", graphicsOpts->fullscreen); 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) { void usage(const char* arg0, const char* extraOptions) {
printf("usage: %s [option ...] file\n", arg0); printf("usage: %s [option ...] file\n", arg0);
puts("\nGeneric options:"); puts("\nGeneric options:");

View File

@ -19,7 +19,7 @@ struct mArguments {
int logLevel; int logLevel;
int frameskip; int frameskip;
enum DebuggerType debuggerType; enum mDebuggerType debuggerType;
bool debugAtStart; bool debugAtStart;
bool showHelp; bool showHelp;
bool showVersion; bool showVersion;
@ -48,7 +48,5 @@ void usage(const char* arg0, const char* extraOptions);
void version(const char* arg0); void version(const char* arg0);
void initParserForGraphics(struct mSubParser* parser, struct mGraphicsOpts* opts); void initParserForGraphics(struct mSubParser* parser, struct mGraphicsOpts* opts);
struct mCore;
struct Debugger* createDebugger(struct mArguments* opts, struct mCore* core);
#endif #endif

View File

@ -41,12 +41,12 @@ void GDBController::attach() {
} }
m_gameController->setDebugger(&m_gdbStub.d); m_gameController->setDebugger(&m_gdbStub.d);
if (m_gameController->isLoaded()) { if (m_gameController->isLoaded()) {
DebuggerEnter(&m_gdbStub.d, DEBUGGER_ENTER_ATTACHED, 0); mDebuggerEnter(&m_gdbStub.d, DEBUGGER_ENTER_ATTACHED, 0);
} else { } else {
QObject::disconnect(m_autoattach); QObject::disconnect(m_autoattach);
m_autoattach = connect(m_gameController, &GameController::gameStarted, [this]() { m_autoattach = connect(m_gameController, &GameController::gameStarted, [this]() {
QObject::disconnect(m_autoattach); 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; return;
} }
m_gameController->threadInterrupt(); m_gameController->threadInterrupt();
DebuggerEnter(&m_gdbStub.d, DEBUGGER_ENTER_MANUAL, 0); mDebuggerEnter(&m_gdbStub.d, DEBUGGER_ENTER_MANUAL, 0);
m_gameController->threadContinue(); m_gameController->threadContinue();
} }

View File

@ -271,14 +271,20 @@ void GameController::setConfig(const mCoreConfig* config) {
} }
#ifdef USE_GDB_STUB #ifdef USE_GDB_STUB
Debugger* GameController::debugger() { mDebugger* GameController::debugger() {
// TODO: Put back debugger if (!isLoaded()) {
return nullptr; return nullptr;
}
return m_threadContext.core->debugger;
} }
void GameController::setDebugger(Debugger* debugger) { void GameController::setDebugger(mDebugger* debugger) {
threadInterrupt(); threadInterrupt();
// TODO: Put back debugger if (debugger) {
mDebuggerAttach(debugger, m_threadContext.core);
} else {
m_threadContext.core->detachDebugger(m_threadContext.core);
}
threadContinue(); threadContinue();
} }
#endif #endif

View File

@ -30,7 +30,7 @@ extern "C" {
struct GBAAudio; struct GBAAudio;
struct mCoreConfig; struct mCoreConfig;
struct Configuration; struct Configuration;
struct Debugger; struct mDebugger;
class QThread; class QThread;
@ -79,8 +79,8 @@ public:
int stateSlot() const { return m_stateSlot; } int stateSlot() const { return m_stateSlot; }
#ifdef USE_GDB_STUB #ifdef USE_GDB_STUB
Debugger* debugger(); mDebugger* debugger();
void setDebugger(Debugger*); void setDebugger(mDebugger*);
#endif #endif
signals: signals:

View File

@ -158,7 +158,11 @@ int mSDLRun(struct mSDLRenderer* renderer, struct mArguments* args) {
return 1; return 1;
} }
mCoreAutoloadSave(renderer->core); 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) { if (args->patch) {
struct VFile* patch = VFileOpen(args->patch, O_RDONLY); struct VFile* patch = VFileOpen(args->patch, O_RDONLY);

View File

@ -407,7 +407,9 @@ static void _mSDLHandleKeypress(struct mCoreThread* context, struct mSDLPlayer*
if (event->type == SDL_KEYDOWN) { if (event->type == SDL_KEYDOWN) {
switch (event->keysym.sym) { switch (event->keysym.sym) {
case SDLK_F11: case SDLK_F11:
// TODO: Put back debugger if (context->core->debugger) {
mDebuggerEnter(context->core->debugger, DEBUGGER_ENTER_MANUAL, NULL);
}
return; return;
#ifdef USE_PNG #ifdef USE_PNG
case SDLK_F12: case SDLK_F12: