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

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/. */
#include "memory-debugger.h"
#include "debugger.h"
#include "arm/debugger.h"
#include "util/math.h"
#include <string.h>
static bool _checkWatchpoints(struct Debugger* debugger, uint32_t address, struct DebuggerEntryInfo* info, enum WatchpointType type, uint32_t newValue, int width);
static bool _checkWatchpoints(struct ARMDebugger* debugger, uint32_t address, struct mDebuggerEntryInfo* info, enum mWatchpointType type, uint32_t newValue, int width);
#define FIND_DEBUGGER(DEBUGGER, CPU) \
{ \
@ -19,7 +19,7 @@ static bool _checkWatchpoints(struct Debugger* debugger, uint32_t address, struc
size_t i; \
for (i = 0; i < CPU->numComponents; ++i) { \
if (CPU->components[i]->id == DEBUGGER_ID) { \
DEBUGGER = (struct Debugger*) cpu->components[i]; \
DEBUGGER = (struct ARMDebugger*) cpu->components[i]; \
break; \
} \
} \
@ -27,36 +27,36 @@ static bool _checkWatchpoints(struct Debugger* debugger, uint32_t address, struc
#define CREATE_SHIM(NAME, RETURN, TYPES, ...) \
static RETURN DebuggerShim_ ## NAME TYPES { \
struct Debugger* debugger; \
struct ARMDebugger* debugger; \
FIND_DEBUGGER(debugger, cpu); \
return debugger->originalMemory.NAME(cpu, __VA_ARGS__); \
}
#define CREATE_WATCHPOINT_READ_SHIM(NAME, WIDTH, RETURN, TYPES, ...) \
static RETURN DebuggerShim_ ## NAME TYPES { \
struct Debugger* debugger; \
struct ARMDebugger* debugger; \
FIND_DEBUGGER(debugger, cpu); \
struct DebuggerEntryInfo info; \
struct mDebuggerEntryInfo info; \
if (_checkWatchpoints(debugger, address, &info, WATCHPOINT_READ, 0, WIDTH)) { \
DebuggerEnter(debugger, DEBUGGER_ENTER_WATCHPOINT, &info); \
mDebuggerEnter(debugger->d.p, DEBUGGER_ENTER_WATCHPOINT, &info); \
} \
return debugger->originalMemory.NAME(cpu, __VA_ARGS__); \
}
#define CREATE_WATCHPOINT_WRITE_SHIM(NAME, WIDTH, RETURN, TYPES, ...) \
static RETURN DebuggerShim_ ## NAME TYPES { \
struct Debugger* debugger; \
struct ARMDebugger* debugger; \
FIND_DEBUGGER(debugger, cpu); \
struct DebuggerEntryInfo info; \
struct mDebuggerEntryInfo info; \
if (_checkWatchpoints(debugger, address, &info, WATCHPOINT_WRITE, value, WIDTH)) { \
DebuggerEnter(debugger, DEBUGGER_ENTER_WATCHPOINT, &info); \
mDebuggerEnter(debugger->d.p, DEBUGGER_ENTER_WATCHPOINT, &info); \
} \
return debugger->originalMemory.NAME(cpu, __VA_ARGS__); \
}
#define CREATE_MULTIPLE_WATCHPOINT_SHIM(NAME, ACCESS_TYPE) \
static uint32_t DebuggerShim_ ## NAME (struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) { \
struct Debugger* debugger; \
struct ARMDebugger* debugger; \
FIND_DEBUGGER(debugger, cpu); \
uint32_t popcount = popcount32(mask); \
int offset = 4; \
@ -70,9 +70,9 @@ static bool _checkWatchpoints(struct Debugger* debugger, uint32_t address, struc
} \
unsigned i; \
for (i = 0; i < popcount; ++i) { \
struct DebuggerEntryInfo info; \
struct mDebuggerEntryInfo info; \
if (_checkWatchpoints(debugger, base + 4 * i, &info, ACCESS_TYPE, 0, 4)) { \
DebuggerEnter(debugger, DEBUGGER_ENTER_WATCHPOINT, &info); \
mDebuggerEnter(debugger->d.p, DEBUGGER_ENTER_WATCHPOINT, &info); \
} \
} \
return debugger->originalMemory.NAME(cpu, address, mask, direction, cycleCounter); \
@ -88,12 +88,12 @@ CREATE_MULTIPLE_WATCHPOINT_SHIM(loadMultiple, WATCHPOINT_READ)
CREATE_MULTIPLE_WATCHPOINT_SHIM(storeMultiple, WATCHPOINT_WRITE)
CREATE_SHIM(setActiveRegion, void, (struct ARMCore* cpu, uint32_t address), address)
static bool _checkWatchpoints(struct Debugger* debugger, uint32_t address, struct DebuggerEntryInfo* info, enum WatchpointType type, uint32_t newValue, int width) {
static bool _checkWatchpoints(struct ARMDebugger* debugger, uint32_t address, struct mDebuggerEntryInfo* info, enum mWatchpointType type, uint32_t newValue, int width) {
--width;
struct DebugWatchpoint* watchpoint;
struct ARMDebugWatchpoint* watchpoint;
size_t i;
for (i = 0; i < DebugWatchpointListSize(&debugger->watchpoints); ++i) {
watchpoint = DebugWatchpointListGetPointer(&debugger->watchpoints, i);
for (i = 0; i < ARMDebugWatchpointListSize(&debugger->watchpoints); ++i) {
watchpoint = ARMDebugWatchpointListGetPointer(&debugger->watchpoints, i);
if (!((watchpoint->address ^ address) & ~width) && watchpoint->type & type) {
switch (width + 1) {
case 1:
@ -116,7 +116,7 @@ static bool _checkWatchpoints(struct Debugger* debugger, uint32_t address, struc
return false;
}
void DebuggerInstallMemoryShim(struct Debugger* debugger) {
void ARMDebuggerInstallMemoryShim(struct ARMDebugger* debugger) {
debugger->originalMemory = debugger->cpu->memory;
debugger->cpu->memory.store32 = DebuggerShim_store32;
debugger->cpu->memory.store16 = DebuggerShim_store16;
@ -129,7 +129,7 @@ void DebuggerInstallMemoryShim(struct Debugger* debugger) {
debugger->cpu->memory.setActiveRegion = DebuggerShim_setActiveRegion;
}
void DebuggerRemoveMemoryShim(struct Debugger* debugger) {
void ARMDebuggerRemoveMemoryShim(struct ARMDebugger* debugger) {
debugger->cpu->memory.store32 = debugger->originalMemory.store32;
debugger->cpu->memory.store16 = debugger->originalMemory.store16;
debugger->cpu->memory.store8 = debugger->originalMemory.store8;

View File

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

View File

@ -16,6 +16,7 @@
#include "core/input.h"
#endif
#include "core/interface.h"
#include "debugger/debugger.h"
enum mPlatform {
PLATFORM_NONE = -1,
@ -33,6 +34,7 @@ struct mCoreSync;
struct mCore {
void* cpu;
void* board;
struct mDebugger* debugger;
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
struct mDirectorySet dirs;
@ -93,6 +95,20 @@ struct mCore {
void (*setRTC)(struct mCore*, struct mRTCSource*);
void (*setRotation)(struct mCore*, struct mRotationSource*);
void (*setRumble)(struct mCore*, struct mRumble*);
uint32_t (*busRead8)(struct mCore*, uint32_t address);
uint32_t (*busRead16)(struct mCore*, uint32_t address);
uint32_t (*busRead32)(struct mCore*, uint32_t address);
void (*busWrite8)(struct mCore*, uint32_t address, uint8_t);
void (*busWrite16)(struct mCore*, uint32_t address, uint16_t);
void (*busWrite32)(struct mCore*, uint32_t address, uint32_t);
bool (*supportsDebuggerType)(struct mCore*, enum mDebuggerType);
struct mDebuggerPlatform* (*debuggerPlatform)(struct mCore*);
struct CLIDebuggerSystem* (*cliDebuggerSystem)(struct mCore*);
void (*attachDebugger)(struct mCore*, struct mDebugger*);
void (*detachDebugger)(struct mCore*);
};
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2

View File

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

View File

@ -116,7 +116,17 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) {
_changeState(threadContext, THREAD_RUNNING, true);
while (threadContext->state < THREAD_EXITING) {
core->runLoop(core);
struct mDebugger* debugger = core->debugger;
if (debugger) {
mDebuggerRun(debugger);
if (debugger->state == DEBUGGER_SHUTDOWN) {
_changeState(threadContext, THREAD_EXITING, false);
}
} else {
while (threadContext->state == THREAD_RUNNING) {
core->runLoop(core);
}
}
int resetScheduled = 0;
MutexLock(&threadContext->stateMutex);

View File

@ -4,7 +4,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "cli-debugger.h"
#include "decoder.h"
#ifdef USE_CLI_DEBUGGER
#include "core/core.h"
#include "parser.h"
#include <signal.h>
@ -13,8 +16,8 @@
#include <pthread.h>
#endif
static const char* ERROR_MISSING_ARGS = "Arguments missing"; // TODO: share
static const char* ERROR_OVERFLOW = "Arguments overflow";
const char* ERROR_MISSING_ARGS = "Arguments missing"; // TODO: share
const char* ERROR_OVERFLOW = "Arguments overflow";
static struct CLIDebugger* _activeDebugger;
@ -23,8 +26,6 @@ static void _breakInto(struct CLIDebugger*, struct CLIDebugVector*);
#endif
static void _continue(struct CLIDebugger*, struct CLIDebugVector*);
static void _disassemble(struct CLIDebugger*, struct CLIDebugVector*);
static void _disassembleArm(struct CLIDebugger*, struct CLIDebugVector*);
static void _disassembleThumb(struct CLIDebugger*, struct CLIDebugVector*);
static void _next(struct CLIDebugger*, struct CLIDebugVector*);
static void _print(struct CLIDebugger*, struct CLIDebugVector*);
static void _printBin(struct CLIDebugger*, struct CLIDebugVector*);
@ -37,42 +38,27 @@ static void _reset(struct CLIDebugger*, struct CLIDebugVector*);
static void _readHalfword(struct CLIDebugger*, struct CLIDebugVector*);
static void _readWord(struct CLIDebugger*, struct CLIDebugVector*);
static void _setBreakpoint(struct CLIDebugger*, struct CLIDebugVector*);
static void _setBreakpointARM(struct CLIDebugger*, struct CLIDebugVector*);
static void _setBreakpointThumb(struct CLIDebugger*, struct CLIDebugVector*);
static void _clearBreakpoint(struct CLIDebugger*, struct CLIDebugVector*);
static void _setWatchpoint(struct CLIDebugger*, struct CLIDebugVector*);
static void _writeByte(struct CLIDebugger*, struct CLIDebugVector*);
static void _writeHalfword(struct CLIDebugger*, struct CLIDebugVector*);
static void _writeWord(struct CLIDebugger*, struct CLIDebugVector*);
static void _writeRegister(struct CLIDebugger*, struct CLIDebugVector*);
static void _dumpByte(struct CLIDebugger*, struct CLIDebugVector*);
static void _dumpHalfword(struct CLIDebugger*, struct CLIDebugVector*);
static void _dumpWord(struct CLIDebugger*, struct CLIDebugVector*);
static void _breakIntoDefault(int signal);
static void _disassembleMode(struct CLIDebugger*, struct CLIDebugVector*, enum ExecutionMode mode);
static uint32_t _printLine(struct CLIDebugger* debugger, uint32_t address, enum ExecutionMode mode);
static struct CLIDebuggerCommandSummary _debuggerCommands[] = {
{ "b", _setBreakpoint, CLIDVParse, "Set a breakpoint" },
{ "b/a", _setBreakpointARM, CLIDVParse, "Set a software breakpoint as ARM" },
{ "b/t", _setBreakpointThumb, CLIDVParse, "Set a software breakpoint as Thumb" },
{ "break", _setBreakpoint, CLIDVParse, "Set a breakpoint" },
{ "break/a", _setBreakpointARM, CLIDVParse, "Set a software breakpoint as ARM" },
{ "break/t", _setBreakpointThumb, CLIDVParse, "Set a software breakpoint as Thumb" },
{ "c", _continue, 0, "Continue execution" },
{ "continue", _continue, 0, "Continue execution" },
{ "d", _clearBreakpoint, CLIDVParse, "Delete a breakpoint" },
{ "delete", _clearBreakpoint, CLIDVParse, "Delete a breakpoint" },
{ "dis", _disassemble, CLIDVParse, "Disassemble instructions" },
{ "dis/a", _disassembleArm, CLIDVParse, "Disassemble instructions as ARM" },
{ "dis/t", _disassembleThumb, CLIDVParse, "Disassemble instructions as Thumb" },
{ "disasm", _disassemble, CLIDVParse, "Disassemble instructions" },
{ "disasm/a", _disassembleArm, CLIDVParse, "Disassemble instructions as ARM" },
{ "disasm/t", _disassembleThumb, CLIDVParse, "Disassemble instructions as Thumb" },
{ "disassemble", _disassemble, CLIDVParse, "Disassemble instructions" },
{ "disassemble/a", _disassembleArm, CLIDVParse, "Disassemble instructions as ARM" },
{ "disassemble/t", _disassembleThumb, CLIDVParse, "Disassemble instructions as Thumb" },
{ "h", _printHelp, CLIDVStringParse, "Print help" },
{ "help", _printHelp, CLIDVStringParse, "Print help" },
{ "i", _printStatus, 0, "Print the current status" },
@ -93,11 +79,10 @@ static struct CLIDebuggerCommandSummary _debuggerCommands[] = {
{ "r/4", _readWord, CLIDVParse, "Read a word from a specified offset" },
{ "status", _printStatus, 0, "Print the current status" },
{ "w", _setWatchpoint, CLIDVParse, "Set a watchpoint" },
{ "watch", _setWatchpoint, CLIDVParse, "Set a watchpoint" },
{ "w/1", _writeByte, CLIDVParse, "Write a byte at a specified offset" },
{ "w/2", _writeHalfword, CLIDVParse, "Write a halfword at a specified offset" },
{ "w/4", _writeWord, CLIDVParse, "Write a word at a specified offset" },
{ "w/r", _writeRegister, CLIDVParse, "Write a register" },
{ "watch", _setWatchpoint, CLIDVParse, "Set a watchpoint" },
{ "x/1", _dumpByte, CLIDVParse, "Examine bytes at a specified offset" },
{ "x/2", _dumpHalfword, CLIDVParse, "Examine halfwords at a specified offset" },
{ "x/4", _dumpWord, CLIDVParse, "Examine words at a specified offset" },
@ -107,17 +92,6 @@ static struct CLIDebuggerCommandSummary _debuggerCommands[] = {
{ 0, 0, 0, 0 }
};
static inline void _printPSR(union PSR psr) {
printf("%08X [%c%c%c%c%c%c%c]\n", psr.packed,
psr.n ? 'N' : '-',
psr.z ? 'Z' : '-',
psr.c ? 'C' : '-',
psr.v ? 'V' : '-',
psr.i ? 'I' : '-',
psr.f ? 'F' : '-',
psr.t ? 'T' : '-');
}
#ifndef NDEBUG
static void _handleDeath(int sig) {
UNUSED(sig);
@ -149,57 +123,12 @@ static void _continue(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
static void _next(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
UNUSED(dv);
if (debugger->d.currentBreakpoint) {
if (debugger->d.currentBreakpoint->isSw && debugger->d.setSoftwareBreakpoint) {
debugger->d.setSoftwareBreakpoint(&debugger->d, debugger->d.currentBreakpoint->address, debugger->d.currentBreakpoint->sw.mode, &debugger->d.currentBreakpoint->sw.opcode);
}
debugger->d.currentBreakpoint = 0;
}
ARMRun(debugger->d.cpu);
debugger->d.core->step(debugger->d.core);
_printStatus(debugger, 0);
}
static void _disassemble(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
_disassembleMode(debugger, dv, debugger->d.cpu->executionMode);
}
static void _disassembleArm(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
_disassembleMode(debugger, dv, MODE_ARM);
}
static void _disassembleThumb(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
_disassembleMode(debugger, dv, MODE_THUMB);
}
static void _disassembleMode(struct CLIDebugger* debugger, struct CLIDebugVector* dv, enum ExecutionMode mode) {
uint32_t address;
int size;
int wordSize;
if (mode == MODE_ARM) {
wordSize = WORD_SIZE_ARM;
} else {
wordSize = WORD_SIZE_THUMB;
}
if (!dv || dv->type != CLIDV_INT_TYPE) {
address = debugger->d.cpu->gprs[ARM_PC] - wordSize;
} else {
address = dv->intValue;
dv = dv->next;
}
if (!dv || dv->type != CLIDV_INT_TYPE) {
size = 1;
} else {
size = dv->intValue;
dv = dv->next; // TODO: Check for excess args
}
int i;
for (i = 0; i < size; ++i) {
address += _printLine(debugger, address, mode);;
}
debugger->system->disassemble(debugger->system, dv);
}
static void _print(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
@ -234,12 +163,16 @@ static void _printHelp(struct CLIDebugger* debugger, struct CLIDebugVector* dv)
UNUSED(debugger);
UNUSED(dv);
if (!dv) {
puts("ARM commands:");
puts("Generic commands:");
int i;
for (i = 0; _debuggerCommands[i].name; ++i) {
printf("%-10s %s\n", _debuggerCommands[i].name, _debuggerCommands[i].summary);
}
if (debugger->system) {
printf("%s commands:\n", debugger->system->platformName);
for (i = 0; debugger->system->platformCommands[i].name; ++i) {
printf("%-10s %s\n", debugger->system->platformCommands[i].name, debugger->system->platformCommands[i].summary);
}
printf("%s commands:\n", debugger->system->name);
for (i = 0; debugger->system->commands[i].name; ++i) {
printf("%-10s %s\n", debugger->system->commands[i].name, debugger->system->commands[i].summary);
@ -253,7 +186,11 @@ static void _printHelp(struct CLIDebugger* debugger, struct CLIDebugVector* dv)
}
}
if (debugger->system) {
printf("\n%s commands:\n", debugger->system->name);
for (i = 0; debugger->system->platformCommands[i].name; ++i) {
if (strcmp(debugger->system->platformCommands[i].name, dv->charValue) == 0) {
printf(" %s\n", debugger->system->platformCommands[i].summary);
}
}
for (i = 0; debugger->system->commands[i].name; ++i) {
if (strcmp(debugger->system->commands[i].name, dv->charValue) == 0) {
printf(" %s\n", debugger->system->commands[i].summary);
@ -263,56 +200,6 @@ static void _printHelp(struct CLIDebugger* debugger, struct CLIDebugVector* dv)
}
}
static inline uint32_t _printLine(struct CLIDebugger* debugger, uint32_t address, enum ExecutionMode mode) {
char disassembly[48];
struct ARMInstructionInfo info;
printf("%08X: ", address);
if (mode == MODE_ARM) {
uint32_t instruction = debugger->d.cpu->memory.load32(debugger->d.cpu, address, 0);
ARMDecodeARM(instruction, &info);
ARMDisassemble(&info, address + WORD_SIZE_ARM * 2, disassembly, sizeof(disassembly));
printf("%08X\t%s\n", instruction, disassembly);
return WORD_SIZE_ARM;
} else {
struct ARMInstructionInfo info2;
struct ARMInstructionInfo combined;
uint16_t instruction = debugger->d.cpu->memory.load16(debugger->d.cpu, address, 0);
uint16_t instruction2 = debugger->d.cpu->memory.load16(debugger->d.cpu, address + WORD_SIZE_THUMB, 0);
ARMDecodeThumb(instruction, &info);
ARMDecodeThumb(instruction2, &info2);
if (ARMDecodeThumbCombine(&info, &info2, &combined)) {
ARMDisassemble(&combined, address + WORD_SIZE_THUMB * 2, disassembly, sizeof(disassembly));
printf("%04X %04X\t%s\n", instruction, instruction2, disassembly);
return WORD_SIZE_THUMB * 2;
} else {
ARMDisassemble(&info, address + WORD_SIZE_THUMB * 2, disassembly, sizeof(disassembly));
printf("%04X \t%s\n", instruction, disassembly);
return WORD_SIZE_THUMB;
}
}
}
static void _printStatus(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
UNUSED(dv);
int r;
for (r = 0; r < 4; ++r) {
printf("%08X %08X %08X %08X\n",
debugger->d.cpu->gprs[r << 2],
debugger->d.cpu->gprs[(r << 2) + 1],
debugger->d.cpu->gprs[(r << 2) + 2],
debugger->d.cpu->gprs[(r << 2) + 3]);
}
_printPSR(debugger->d.cpu->cpsr);
int instructionLength;
enum ExecutionMode mode = debugger->d.cpu->cpsr.t;
if (mode == MODE_ARM) {
instructionLength = WORD_SIZE_ARM;
} else {
instructionLength = WORD_SIZE_THUMB;
}
_printLine(debugger, debugger->d.cpu->gprs[ARM_PC] - instructionLength, mode);
}
static void _quit(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
UNUSED(dv);
debugger->d.state = DEBUGGER_SHUTDOWN;
@ -324,13 +211,13 @@ static void _readByte(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
return;
}
uint32_t address = dv->intValue;
uint8_t value = debugger->d.cpu->memory.load8(debugger->d.cpu, address, 0);
uint8_t value = debugger->d.core->busRead8(debugger->d.core, address);
printf(" 0x%02X\n", value);
}
static void _reset(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
UNUSED(dv);
ARMReset(debugger->d.cpu);
debugger->d.core->reset(debugger->d.core);
_printStatus(debugger, 0);
}
@ -340,7 +227,7 @@ static void _readHalfword(struct CLIDebugger* debugger, struct CLIDebugVector* d
return;
}
uint32_t address = dv->intValue;
uint16_t value = debugger->d.cpu->memory.load16(debugger->d.cpu, address & ~1, 0);
uint16_t value = debugger->d.core->busRead16(debugger->d.core, address & ~1);
printf(" 0x%04X\n", value);
}
@ -350,7 +237,7 @@ static void _readWord(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
return;
}
uint32_t address = dv->intValue;
uint32_t value = debugger->d.cpu->memory.load32(debugger->d.cpu, address & ~3, 0);
uint32_t value = debugger->d.core->busRead32(debugger->d.core, address & ~3);
printf(" 0x%08X\n", value);
}
@ -369,7 +256,7 @@ static void _writeByte(struct CLIDebugger* debugger, struct CLIDebugVector* dv)
printf("%s\n", ERROR_OVERFLOW);
return;
}
debugger->d.cpu->memory.store8(debugger->d.cpu, address, value, 0);
debugger->d.core->busWrite8(debugger->d.core, address, value);
}
static void _writeHalfword(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
@ -387,7 +274,7 @@ static void _writeHalfword(struct CLIDebugger* debugger, struct CLIDebugVector*
printf("%s\n", ERROR_OVERFLOW);
return;
}
debugger->d.cpu->memory.store16(debugger->d.cpu, address, value, 0);
debugger->d.core->busWrite16(debugger->d.core, address, value);
}
static void _writeWord(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
@ -401,24 +288,7 @@ static void _writeWord(struct CLIDebugger* debugger, struct CLIDebugVector* dv)
}
uint32_t address = dv->intValue;
uint32_t value = dv->next->intValue;
debugger->d.cpu->memory.store32(debugger->d.cpu, address, value, 0);
}
static void _writeRegister(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
if (!dv || dv->type != CLIDV_INT_TYPE) {
printf("%s\n", ERROR_MISSING_ARGS);
return;
}
if (!dv->next || dv->next->type != CLIDV_INT_TYPE) {
printf("%s\n", ERROR_MISSING_ARGS);
return;
}
uint32_t regid = dv->intValue;
uint32_t value = dv->next->intValue;
if (regid >= ARM_PC) {
return;
}
debugger->d.cpu->gprs[regid] = value;
debugger->d.core->busWrite32(debugger->d.core, address, value);
}
static void _dumpByte(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
@ -438,7 +308,7 @@ static void _dumpByte(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
}
printf("0x%08X:", address);
for (; line > 0; --line, ++address, --words) {
uint32_t value = debugger->d.cpu->memory.load8(debugger->d.cpu, address, 0);
uint32_t value = debugger->d.core->busRead8(debugger->d.core, address);
printf(" %02X", value);
}
printf("\n");
@ -462,7 +332,7 @@ static void _dumpHalfword(struct CLIDebugger* debugger, struct CLIDebugVector* d
}
printf("0x%08X:", address);
for (; line > 0; --line, address += 2, --words) {
uint32_t value = debugger->d.cpu->memory.load16(debugger->d.cpu, address, 0);
uint32_t value = debugger->d.core->busRead16(debugger->d.core, address);
printf(" %04X", value);
}
printf("\n");
@ -486,7 +356,7 @@ static void _dumpWord(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
}
printf("0x%08X:", address);
for (; line > 0; --line, address += 4, --words) {
uint32_t value = debugger->d.cpu->memory.load32(debugger->d.cpu, address, 0);
uint32_t value = debugger->d.core->busRead32(debugger->d.core, address);
printf(" %08X", value);
}
printf("\n");
@ -499,35 +369,7 @@ static void _setBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector*
return;
}
uint32_t address = dv->intValue;
DebuggerSetBreakpoint(&debugger->d, address);
}
static void _setBreakpointARM(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
if (!dv || dv->type != CLIDV_INT_TYPE) {
printf("%s\n", ERROR_MISSING_ARGS);
return;
}
uint32_t address = dv->intValue;
DebuggerSetSoftwareBreakpoint(&debugger->d, address, MODE_ARM);
}
static void _setBreakpointThumb(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
if (!dv || dv->type != CLIDV_INT_TYPE) {
printf("%s\n", ERROR_MISSING_ARGS);
return;
}
uint32_t address = dv->intValue;
DebuggerSetSoftwareBreakpoint(&debugger->d, address, MODE_THUMB);
}
static void _clearBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
if (!dv || dv->type != CLIDV_INT_TYPE) {
printf("%s\n", ERROR_MISSING_ARGS);
return;
}
uint32_t address = dv->intValue;
DebuggerClearBreakpoint(&debugger->d, address);
DebuggerClearWatchpoint(&debugger->d, address);
debugger->d.platform->setBreakpoint(debugger->d.platform, address);
}
static void _setWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
@ -536,12 +378,27 @@ static void _setWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector*
return;
}
uint32_t address = dv->intValue;
DebuggerSetWatchpoint(&debugger->d, address, WATCHPOINT_RW); // TODO: ro/wo
debugger->d.platform->setWatchpoint(debugger->d.platform, address, WATCHPOINT_RW); // TODO: ro/wo
}
static void _clearBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
if (!dv || dv->type != CLIDV_INT_TYPE) {
printf("%s\n", ERROR_MISSING_ARGS);
return;
}
uint32_t address = dv->intValue;
debugger->d.platform->clearBreakpoint(debugger->d.platform, address);
debugger->d.platform->clearWatchpoint(debugger->d.platform, address);
}
static void _breakIntoDefault(int signal) {
UNUSED(signal);
DebuggerEnter(&_activeDebugger->d, DEBUGGER_ENTER_MANUAL, 0);
mDebuggerEnter(&_activeDebugger->d, DEBUGGER_ENTER_MANUAL, 0);
}
static void _printStatus(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
UNUSED(dv);
debugger->system->printStatus(debugger->system);
}
static uint32_t _performOperation(enum Operation operation, uint32_t current, uint32_t next, struct CLIDebugVector* dv) {
@ -570,30 +427,8 @@ static uint32_t _performOperation(enum Operation operation, uint32_t current, ui
return current;
}
static uint32_t _lookupIdentifier(struct Debugger* debugger, const char* name, struct CLIDebugVector* dv) {
static uint32_t _lookupIdentifier(struct mDebugger* debugger, const char* name, struct CLIDebugVector* dv) {
struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
if (strcmp(name, "sp") == 0) {
return debugger->cpu->gprs[ARM_SP];
}
if (strcmp(name, "lr") == 0) {
return debugger->cpu->gprs[ARM_LR];
}
if (strcmp(name, "pc") == 0) {
return debugger->cpu->gprs[ARM_PC];
}
if (strcmp(name, "cpsr") == 0) {
return debugger->cpu->cpsr.packed;
}
// TODO: test if mode has SPSR
if (strcmp(name, "spsr") == 0) {
return debugger->cpu->spsr.packed;
}
if (name[0] == 'r' && name[1] >= '0' && name[1] <= '9') {
int reg = atoi(&name[1]);
if (reg < 16) {
return debugger->cpu->gprs[reg];
}
}
if (cliDebugger->system) {
uint32_t value = cliDebugger->system->lookupIdentifier(cliDebugger->system, name, dv);
if (dv->type != CLIDV_ERROR_TYPE) {
@ -605,7 +440,7 @@ static uint32_t _lookupIdentifier(struct Debugger* debugger, const char* name, s
return 0;
}
static uint32_t _evaluateParseTree(struct Debugger* debugger, struct ParseTree* tree, struct CLIDebugVector* dv) {
static uint32_t _evaluateParseTree(struct mDebugger* debugger, struct ParseTree* tree, struct CLIDebugVector* dv) {
switch (tree->token.type) {
case TOKEN_UINT_TYPE:
return tree->token.uintValue;
@ -753,6 +588,9 @@ static bool _parse(struct CLIDebugger* debugger, const char* line, size_t count)
int result = _tryCommands(debugger, _debuggerCommands, line, cmdLength, args, count - cmdLength - 1);
if (result < 0 && debugger->system) {
result = _tryCommands(debugger, debugger->system->commands, line, cmdLength, args, count - cmdLength - 1);
if (result < 0) {
result = _tryCommands(debugger, debugger->system->platformCommands, line, cmdLength, args, count - cmdLength - 1);
}
}
if (result < 0) {
printf("Command not found\n");
@ -765,7 +603,7 @@ static char* _prompt(EditLine* el) {
return "> ";
}
static void _commandLine(struct Debugger* debugger) {
static void _commandLine(struct mDebugger* debugger) {
struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
const char* line;
_printStatus(cliDebugger, 0);
@ -787,7 +625,7 @@ static void _commandLine(struct Debugger* debugger) {
}
}
static void _reportEntry(struct Debugger* debugger, enum DebuggerEntryReason reason, struct DebuggerEntryInfo* info) {
static void _reportEntry(struct mDebugger* debugger, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) {
UNUSED(debugger);
switch (reason) {
case DEBUGGER_ENTER_MANUAL:
@ -874,7 +712,7 @@ static unsigned char _tabComplete(EditLine* elstate, int ch) {
return CC_REDISPLAY;
}
static void _cliDebuggerInit(struct Debugger* debugger) {
static void _cliDebuggerInit(struct mDebugger* debugger) {
struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
// TODO: get argv[0]
cliDebugger->elstate = el_init(binaryName, stdin, stdout, stderr);
@ -892,7 +730,7 @@ static void _cliDebuggerInit(struct Debugger* debugger) {
signal(SIGINT, _breakIntoDefault);
}
static void _cliDebuggerDeinit(struct Debugger* debugger) {
static void _cliDebuggerDeinit(struct mDebugger* debugger) {
struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
history_end(cliDebugger->histate);
el_end(cliDebugger->elstate);
@ -904,7 +742,7 @@ static void _cliDebuggerDeinit(struct Debugger* debugger) {
}
}
static void _cliDebuggerCustom(struct Debugger* debugger) {
static void _cliDebuggerCustom(struct mDebugger* debugger) {
struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
bool retain = false;
if (cliDebugger->system) {
@ -916,7 +754,6 @@ static void _cliDebuggerCustom(struct Debugger* debugger) {
}
void CLIDebuggerCreate(struct CLIDebugger* debugger) {
DebuggerCreate(&debugger->d);
debugger->d.init = _cliDebuggerInit;
debugger->d.deinit = _cliDebuggerDeinit;
debugger->d.custom = _cliDebuggerCustom;
@ -935,3 +772,5 @@ void CLIDebuggerAttachSystem(struct CLIDebugger* debugger, struct CLIDebuggerSys
debugger->system = system;
system->p = debugger;
}
#endif

View File

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

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
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "debugger.h"
#include "arm.h"
#include "isa-inlines.h"
#include "core/core.h"
#include "memory-debugger.h"
#ifdef USE_CLI_DEBUGGER
#include "debugger/cli-debugger.h"
#include "gba/supervisor/cli.h"
#endif
#ifdef USE_GDB_STUB
#include "debugger/gdb-stub.h"
#endif
const uint32_t DEBUGGER_ID = 0xDEADBEEF;
DEFINE_VECTOR(DebugBreakpointList, struct DebugBreakpoint);
DEFINE_VECTOR(DebugWatchpointList, struct DebugWatchpoint);
mLOG_DEFINE_CATEGORY(DEBUGGER, "Debugger");
static struct DebugBreakpoint* _lookupBreakpoint(struct DebugBreakpointList* breakpoints, uint32_t address) {
size_t i;
for (i = 0; i < DebugBreakpointListSize(breakpoints); ++i) {
if (DebugBreakpointListGetPointer(breakpoints, i)->address == address) {
return DebugBreakpointListGetPointer(breakpoints, i);
}
}
return 0;
}
static void mDebuggerInit(void* cpu, struct mCPUComponent* component);
static void mDebuggerDeinit(struct mCPUComponent* component);
static void _checkBreakpoints(struct Debugger* debugger) {
int instructionLength;
enum ExecutionMode mode = debugger->cpu->cpsr.t;
if (mode == MODE_ARM) {
instructionLength = WORD_SIZE_ARM;
} else {
instructionLength = WORD_SIZE_THUMB;
struct mDebugger* mDebuggerCreate(enum mDebuggerType type, struct mCore* core) {
if (!core->supportsDebuggerType(core, type)) {
return NULL;
}
struct DebugBreakpoint* breakpoint = _lookupBreakpoint(&debugger->breakpoints, debugger->cpu->gprs[ARM_PC] - instructionLength);
if (!breakpoint) {
return;
}
struct DebuggerEntryInfo info = {
.address = breakpoint->address
union DebugUnion {
struct mDebugger d;
#ifdef USE_CLI_DEBUGGER
struct CLIDebugger cli;
#endif
#ifdef USE_GDB_STUB
struct GDBStub gdb;
#endif
};
DebuggerEnter(debugger, DEBUGGER_ENTER_BREAKPOINT, &info);
}
static void DebuggerInit(void* cpu, struct mCPUComponent*);
static void DebuggerDeinit(struct mCPUComponent*);
union DebugUnion* debugger = malloc(sizeof(union DebugUnion));
void DebuggerCreate(struct Debugger* debugger) {
debugger->d.id = DEBUGGER_ID;
debugger->d.init = DebuggerInit;
debugger->d.deinit = DebuggerDeinit;
}
void DebuggerInit(void* cpu, struct mCPUComponent* component) {
struct Debugger* debugger = (struct Debugger*) component;
debugger->cpu = cpu;
debugger->state = DEBUGGER_RUNNING;
debugger->originalMemory = debugger->cpu->memory;
debugger->currentBreakpoint = 0;
DebugBreakpointListInit(&debugger->breakpoints, 0);
DebugBreakpointListInit(&debugger->swBreakpoints, 0);
DebugWatchpointListInit(&debugger->watchpoints, 0);
if (debugger->init) {
debugger->init(debugger);
switch (type) {
#ifdef USE_CLI_DEBUGGER
case DEBUGGER_CLI:
CLIDebuggerCreate(&debugger->cli);
struct CLIDebuggerSystem* sys = core->cliDebuggerSystem(core);
CLIDebuggerAttachSystem(&debugger->cli, sys);
break;
#endif
#ifdef USE_GDB_STUB
case DEBUGGER_GDB:
GDBStubCreate(&debugger->gdb);
GDBStubListen(&debugger->gdb, 2345, 0);
break;
#endif
case DEBUGGER_NONE:
case DEBUGGER_MAX:
free(debugger);
return 0;
break;
}
return &debugger->d;
}
void DebuggerDeinit(struct mCPUComponent* component) {
struct Debugger* debugger = (struct Debugger*) component;
debugger->deinit(debugger);
DebugBreakpointListDeinit(&debugger->breakpoints);
DebugBreakpointListDeinit(&debugger->swBreakpoints);
DebugWatchpointListDeinit(&debugger->watchpoints);
void mDebuggerAttach(struct mDebugger* debugger, struct mCore* core) {
debugger->d.id = DEBUGGER_ID;
debugger->d.init = mDebuggerInit;
debugger->d.deinit = mDebuggerDeinit;
debugger->core = core;
debugger->platform = core->debuggerPlatform(core);
debugger->platform->p = debugger;
core->attachDebugger(core, debugger);
}
void DebuggerRun(struct Debugger* debugger) {
void mDebuggerRun(struct mDebugger* debugger) {
switch (debugger->state) {
case DEBUGGER_RUNNING:
if (!DebugBreakpointListSize(&debugger->breakpoints) && !DebugWatchpointListSize(&debugger->watchpoints)) {
ARMRunLoop(debugger->cpu);
if (!debugger->platform->hasBreakpoints(debugger->platform)) {
debugger->core->runLoop(debugger->core);
} else {
ARMRun(debugger->cpu);
_checkBreakpoints(debugger);
debugger->core->step(debugger->core);
debugger->platform->checkBreakpoints(debugger->platform);
}
break;
case DEBUGGER_CUSTOM:
ARMRun(debugger->cpu);
_checkBreakpoints(debugger);
debugger->core->step(debugger->core);
debugger->platform->checkBreakpoints(debugger->platform);
debugger->custom(debugger);
break;
case DEBUGGER_PAUSED:
@ -97,89 +95,32 @@ void DebuggerRun(struct Debugger* debugger) {
} else {
debugger->state = DEBUGGER_RUNNING;
}
if (debugger->state != DEBUGGER_PAUSED && debugger->currentBreakpoint) {
if (debugger->currentBreakpoint->isSw && debugger->setSoftwareBreakpoint) {
debugger->setSoftwareBreakpoint(debugger, debugger->currentBreakpoint->address, debugger->currentBreakpoint->sw.mode, &debugger->currentBreakpoint->sw.opcode);
}
debugger->currentBreakpoint = 0;
}
break;
case DEBUGGER_SHUTDOWN:
return;
}
}
void DebuggerEnter(struct Debugger* debugger, enum DebuggerEntryReason reason, struct DebuggerEntryInfo* info) {
void mDebuggerEnter(struct mDebugger* debugger, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) {
debugger->state = DEBUGGER_PAUSED;
struct ARMCore* cpu = debugger->cpu;
cpu->nextEvent = cpu->cycles;
if (reason == DEBUGGER_ENTER_BREAKPOINT) {
struct DebugBreakpoint* breakpoint = _lookupBreakpoint(&debugger->swBreakpoints, _ARMPCAddress(cpu));
debugger->currentBreakpoint = breakpoint;
if (breakpoint && breakpoint->isSw) {
info->address = breakpoint->address;
if (debugger->clearSoftwareBreakpoint) {
debugger->clearSoftwareBreakpoint(debugger, breakpoint->address, breakpoint->sw.mode, breakpoint->sw.opcode);
}
ARMRunFake(cpu, breakpoint->sw.opcode);
}
}
if (debugger->entered) {
debugger->entered(debugger, reason, info);
}
}
void DebuggerSetBreakpoint(struct Debugger* debugger, uint32_t address) {
struct DebugBreakpoint* breakpoint = DebugBreakpointListAppend(&debugger->breakpoints);
breakpoint->address = address;
breakpoint->isSw = false;
}
bool DebuggerSetSoftwareBreakpoint(struct Debugger* debugger, uint32_t address, enum ExecutionMode mode) {
uint32_t opcode;
if (!debugger->setSoftwareBreakpoint || !debugger->setSoftwareBreakpoint(debugger, address, mode, &opcode)) {
return false;
}
struct DebugBreakpoint* breakpoint = DebugBreakpointListAppend(&debugger->swBreakpoints);
breakpoint->address = address;
breakpoint->isSw = true;
breakpoint->sw.opcode = opcode;
breakpoint->sw.mode = mode;
return true;
}
void DebuggerClearBreakpoint(struct Debugger* debugger, uint32_t address) {
struct DebugBreakpointList* breakpoints = &debugger->breakpoints;
size_t i;
for (i = 0; i < DebugBreakpointListSize(breakpoints); ++i) {
if (DebugBreakpointListGetPointer(breakpoints, i)->address == address) {
DebugBreakpointListShift(breakpoints, i, 1);
}
}
}
void DebuggerSetWatchpoint(struct Debugger* debugger, uint32_t address, enum WatchpointType type) {
if (!DebugWatchpointListSize(&debugger->watchpoints)) {
DebuggerInstallMemoryShim(debugger);
}
struct DebugWatchpoint* watchpoint = DebugWatchpointListAppend(&debugger->watchpoints);
watchpoint->address = address;
watchpoint->type = type;
}
void DebuggerClearWatchpoint(struct Debugger* debugger, uint32_t address) {
struct DebugWatchpointList* watchpoints = &debugger->watchpoints;
size_t i;
for (i = 0; i < DebugWatchpointListSize(watchpoints); ++i) {
if (DebugWatchpointListGetPointer(watchpoints, i)->address == address) {
DebugWatchpointListShift(watchpoints, i, 1);
}
}
if (!DebugWatchpointListSize(&debugger->watchpoints)) {
DebuggerRemoveMemoryShim(debugger);
static void mDebuggerInit(void* cpu, struct mCPUComponent* component) {
struct mDebugger* debugger = (struct mDebugger*) component;
debugger->state = DEBUGGER_RUNNING;
debugger->platform->init(cpu, debugger->platform);
if (debugger->init) {
debugger->init(debugger);
}
}
static void mDebuggerDeinit(struct mCPUComponent* component) {
struct mDebugger* debugger = (struct mDebugger*) component;
if (debugger->deinit) {
debugger->deinit(debugger);
}
debugger->platform->deinit(debugger->platform);
}

View File

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

View File

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

View File

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

View File

@ -254,12 +254,56 @@ static void _GBCoreSetRumble(struct mCore* core, struct mRumble* rumble) {
gb->memory.rumble = rumble;
}
static uint32_t _GBCoreBusRead8(struct mCore* core, uint32_t address) {
struct LR35902Core* cpu = core->cpu;
return cpu->memory.load8(cpu, address);
}
static uint32_t _GBCoreBusRead16(struct mCore* core, uint32_t address) {
struct LR35902Core* cpu = core->cpu;
return cpu->memory.load8(cpu, address) | (cpu->memory.load8(cpu, address + 1) << 8);
}
static uint32_t _GBCoreBusRead32(struct mCore* core, uint32_t address) {
struct LR35902Core* cpu = core->cpu;
return cpu->memory.load8(cpu, address) | (cpu->memory.load8(cpu, address + 1) << 8) |
(cpu->memory.load8(cpu, address + 2) << 16) | (cpu->memory.load8(cpu, address + 3) << 24);
}
static void _GBCoreBusWrite8(struct mCore* core, uint32_t address, uint8_t value) {
struct LR35902Core* cpu = core->cpu;
cpu->memory.store8(cpu, address, value);
}
static void _GBCoreBusWrite16(struct mCore* core, uint32_t address, uint16_t value) {
struct LR35902Core* cpu = core->cpu;
cpu->memory.store8(cpu, address, value);
cpu->memory.store8(cpu, address + 1, value >> 8);
}
static void _GBCoreBusWrite32(struct mCore* core, uint32_t address, uint32_t value) {
struct LR35902Core* cpu = core->cpu;
cpu->memory.store8(cpu, address, value);
cpu->memory.store8(cpu, address + 1, value >> 8);
cpu->memory.store8(cpu, address + 2, value >> 16);
cpu->memory.store8(cpu, address + 3, value >> 24);
}
static bool _GBCoreSupportsDebuggerType(struct mCore* core, enum mDebuggerType type) {
return false;
}
static struct mDebuggerPlatform* _GBCoreDebuggerPlatform(struct mCore* core) {
return 0;
}
struct mCore* GBCoreCreate(void) {
struct GBCore* gbcore = malloc(sizeof(*gbcore));
struct mCore* core = &gbcore->d;
memset(&core->opts, 0, sizeof(core->opts));
core->cpu = 0;
core->board = 0;
core->cpu = NULL;
core->board = NULL;
core->debugger = NULL;
core->init = _GBCoreInit;
core->deinit = _GBCoreDeinit;
core->platform = _GBCorePlatform;
@ -295,5 +339,13 @@ struct mCore* GBCoreCreate(void) {
core->setRTC = _GBCoreSetRTC;
core->setRotation = _GBCoreSetRotation;
core->setRumble = _GBCoreSetRumble;
core->busRead8 = _GBCoreBusRead8;
core->busRead16 = _GBCoreBusRead16;
core->busRead32 = _GBCoreBusRead32;
core->busWrite8 = _GBCoreBusWrite8;
core->busWrite16 = _GBCoreBusWrite16;
core->busWrite32 = _GBCoreBusWrite32;
core->supportsDebuggerType = _GBCoreSupportsDebuggerType;
core->debuggerPlatform = _GBCoreDebuggerPlatform;
return core;
}

View File

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

View File

@ -11,6 +11,7 @@
#include "gba/context/overrides.h"
#include "gba/renderers/video-software.h"
#include "gba/serialize.h"
#include "gba/supervisor/cli.h"
#include "util/memory.h"
#include "util/patch.h"
#include "util/vfs.h"
@ -19,8 +20,9 @@ struct GBACore {
struct mCore d;
struct GBAVideoSoftwareRenderer renderer;
int keys;
struct mCPUComponent* components[GBA_COMPONENT_MAX];
struct mCPUComponent* components[CPU_COMPONENT_MAX];
const struct Configuration* overrides;
struct mDebuggerPlatform* debuggerPlatform;
};
static bool _GBACoreInit(struct mCore* core) {
@ -35,12 +37,14 @@ static bool _GBACoreInit(struct mCore* core) {
}
core->cpu = cpu;
core->board = gba;
core->debugger = NULL;
gbacore->debuggerPlatform = NULL;
gbacore->overrides = 0;
GBACreate(gba);
// TODO: Restore debugger and cheats
memset(gbacore->components, 0, sizeof(gbacore->components));
ARMSetComponents(cpu, &gba->d, GBA_COMPONENT_MAX, gbacore->components);
ARMSetComponents(cpu, &gba->d, CPU_COMPONENT_MAX, gbacore->components);
ARMInit(cpu);
GBAVideoSoftwareRendererCreate(&gbacore->renderer);
@ -288,12 +292,90 @@ static void _GBACoreSetRumble(struct mCore* core, struct mRumble* rumble) {
gba->rumble = rumble;
}
static uint32_t _GBACoreBusRead8(struct mCore* core, uint32_t address) {
struct ARMCore* cpu = core->cpu;
return cpu->memory.load8(cpu, address, 0);
}
static uint32_t _GBACoreBusRead16(struct mCore* core, uint32_t address) {
struct ARMCore* cpu = core->cpu;
return cpu->memory.load8(cpu, address, 0);
}
static uint32_t _GBACoreBusRead32(struct mCore* core, uint32_t address) {
struct ARMCore* cpu = core->cpu;
return cpu->memory.load32(cpu, address, 0);
}
static void _GBACoreBusWrite8(struct mCore* core, uint32_t address, uint8_t value) {
struct ARMCore* cpu = core->cpu;
cpu->memory.store8(cpu, address, value, 0);
}
static void _GBACoreBusWrite16(struct mCore* core, uint32_t address, uint16_t value) {
struct ARMCore* cpu = core->cpu;
cpu->memory.store16(cpu, address, value, 0);
}
static void _GBACoreBusWrite32(struct mCore* core, uint32_t address, uint32_t value) {
struct ARMCore* cpu = core->cpu;
cpu->memory.store32(cpu, address, value, 0);
}
static bool _GBACoreSupportsDebuggerType(struct mCore* core, enum mDebuggerType type) {
UNUSED(core);
switch (type) {
#ifdef USE_CLI_DEBUGGER
case DEBUGGER_CLI:
return true;
#endif
#ifdef USE_GDB_STUB
case DEBUGGER_GDB:
return true;
#endif
default:
return false;
}
}
static struct mDebuggerPlatform* _GBACoreDebuggerPlatform(struct mCore* core) {
struct GBACore* gbacore = (struct GBACore*) core;
if (!gbacore->debuggerPlatform) {
gbacore->debuggerPlatform = ARMDebuggerPlatformCreate();
}
return gbacore->debuggerPlatform;
}
static struct CLIDebuggerSystem* _GBACoreCliDebuggerSystem(struct mCore* core) {
#ifdef USE_CLI_DEBUGGER
return &GBACLIDebuggerCreate(core)->d;
#else
UNUSED(core);
return NULL;
#endif
}
static void _GBACoreAttachDebugger(struct mCore* core, struct mDebugger* debugger) {
if (core->debugger) {
GBADetachDebugger(core->board);
}
GBAAttachDebugger(core->board, debugger);
core->debugger = debugger;
}
static void _GBACoreDetachDebugger(struct mCore* core) {
GBADetachDebugger(core->board);
core->debugger = NULL;
}
struct mCore* GBACoreCreate(void) {
struct GBACore* gbacore = malloc(sizeof(*gbacore));
struct mCore* core = &gbacore->d;
memset(&core->opts, 0, sizeof(core->opts));
core->cpu = 0;
core->board = 0;
core->cpu = NULL;
core->board = NULL;
core->debugger = NULL;
core->init = _GBACoreInit;
core->deinit = _GBACoreDeinit;
core->platform = _GBACorePlatform;
@ -329,5 +411,16 @@ struct mCore* GBACoreCreate(void) {
core->setRTC = _GBACoreSetRTC;
core->setRotation = _GBACoreSetRotation;
core->setRumble = _GBACoreSetRumble;
core->busRead8 = _GBACoreBusRead8;
core->busRead16 = _GBACoreBusRead16;
core->busRead32 = _GBACoreBusRead32;
core->busWrite8 = _GBACoreBusWrite8;
core->busWrite16 = _GBACoreBusWrite16;
core->busWrite32 = _GBACoreBusWrite32;
core->supportsDebuggerType = _GBACoreSupportsDebuggerType;
core->debuggerPlatform = _GBACoreDebuggerPlatform;
core->cliDebuggerSystem = _GBACoreCliDebuggerSystem;
core->attachDebugger = _GBACoreAttachDebugger;
core->detachDebugger = _GBACoreDetachDebugger;
return core;
}

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

View File

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

View File

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

View File

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

View File

@ -4,19 +4,6 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "commandline.h"
#include "debugger/debugger.h"
#ifdef USE_CLI_DEBUGGER
#include "debugger/cli-debugger.h"
#include "gba/supervisor/cli.h"
#endif
#ifdef USE_GDB_STUB
#include "debugger/gdb-stub.h"
#endif
#include "gba/video.h"
#include "util/string.h"
#include <fcntl.h>
@ -211,46 +198,6 @@ void _applyGraphicsArgs(struct mSubParser* parser, struct mCoreConfig* config) {
mCoreConfigSetOverrideIntValue(config, "fullscreen", graphicsOpts->fullscreen);
}
struct Debugger* createDebugger(struct mArguments* opts, struct mCore* core) {
#ifndef USE_CLI_DEBUGGER
UNUSED(core);
#endif
union DebugUnion {
struct Debugger d;
#ifdef USE_CLI_DEBUGGER
struct CLIDebugger cli;
#endif
#ifdef USE_GDB_STUB
struct GDBStub gdb;
#endif
};
union DebugUnion* debugger = malloc(sizeof(union DebugUnion));
switch (opts->debuggerType) {
#ifdef USE_CLI_DEBUGGER
case DEBUGGER_CLI:
CLIDebuggerCreate(&debugger->cli);
struct GBACLIDebugger* gbaDebugger = GBACLIDebuggerCreate(core);
CLIDebuggerAttachSystem(&debugger->cli, &gbaDebugger->d);
break;
#endif
#ifdef USE_GDB_STUB
case DEBUGGER_GDB:
GDBStubCreate(&debugger->gdb);
GDBStubListen(&debugger->gdb, 2345, 0);
break;
#endif
case DEBUGGER_NONE:
case DEBUGGER_MAX:
free(debugger);
return 0;
break;
}
return &debugger->d;
}
void usage(const char* arg0, const char* extraOptions) {
printf("usage: %s [option ...] file\n", arg0);
puts("\nGeneric options:");

View File

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

View File

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

View File

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

View File

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

View File

@ -158,7 +158,11 @@ int mSDLRun(struct mSDLRenderer* renderer, struct mArguments* args) {
return 1;
}
mCoreAutoloadSave(renderer->core);
// TODO: Put back debugger
struct mDebugger* debugger = mDebuggerCreate(args->debuggerType, renderer->core);
if (debugger) {
mDebuggerAttach(debugger, renderer->core);
mDebuggerEnter(debugger, DEBUGGER_ENTER_MANUAL, NULL);
}
if (args->patch) {
struct VFile* patch = VFileOpen(args->patch, O_RDONLY);

View File

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