267 lines
7.4 KiB
C
267 lines
7.4 KiB
C
/* Copyright (c) 2013-2019 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 DEBUGGER_H
|
|
#define DEBUGGER_H
|
|
|
|
#include <mgba-util/common.h>
|
|
|
|
CXX_GUARD_START
|
|
|
|
#define INSN_LENGTH_MAX 4
|
|
|
|
#include <mgba/core/cpu.h>
|
|
#include <mgba/core/log.h>
|
|
#include <mgba-util/table.h>
|
|
#include <mgba-util/vector.h>
|
|
|
|
mLOG_DECLARE_CATEGORY(DEBUGGER);
|
|
|
|
extern const uint32_t DEBUGGER_ID;
|
|
|
|
DECL_BITFIELD(mDebuggerAccessLogFlags, uint8_t);
|
|
DECL_BIT(mDebuggerAccessLogFlags, Read, 0);
|
|
DECL_BIT(mDebuggerAccessLogFlags, Write, 1);
|
|
DECL_BIT(mDebuggerAccessLogFlags, Execute, 2);
|
|
DECL_BIT(mDebuggerAccessLogFlags, Abort, 3);
|
|
DECL_BIT(mDebuggerAccessLogFlags, Access8, 4);
|
|
DECL_BIT(mDebuggerAccessLogFlags, Access16, 5);
|
|
DECL_BIT(mDebuggerAccessLogFlags, Access32, 6);
|
|
DECL_BIT(mDebuggerAccessLogFlags, Access64, 7);
|
|
|
|
DECL_BITFIELD(mDebuggerAccessLogFlagsEx, uint16_t);
|
|
DECL_BIT(mDebuggerAccessLogFlagsEx, AccessProgram, 0);
|
|
DECL_BIT(mDebuggerAccessLogFlagsEx, AccessDMA, 1);
|
|
DECL_BIT(mDebuggerAccessLogFlagsEx, AccessSystem, 2);
|
|
DECL_BIT(mDebuggerAccessLogFlagsEx, AccessDecompress, 3);
|
|
DECL_BIT(mDebuggerAccessLogFlagsEx, AccessCopy, 4);
|
|
|
|
DECL_BIT(mDebuggerAccessLogFlagsEx, ErrorIllegalOpcode, 8);
|
|
DECL_BIT(mDebuggerAccessLogFlagsEx, ErrorAccessRead, 9);
|
|
DECL_BIT(mDebuggerAccessLogFlagsEx, ErrorAccessWrite, 10);
|
|
DECL_BIT(mDebuggerAccessLogFlagsEx, ErrorAccessExecute, 11);
|
|
DECL_BIT(mDebuggerAccessLogFlagsEx, Private0, 12);
|
|
DECL_BIT(mDebuggerAccessLogFlagsEx, Private1, 13);
|
|
DECL_BIT(mDebuggerAccessLogFlagsEx, Private2, 14);
|
|
DECL_BIT(mDebuggerAccessLogFlagsEx, Private3, 15);
|
|
|
|
DECL_BIT(mDebuggerAccessLogFlagsEx, ExecuteARM, 14);
|
|
DECL_BIT(mDebuggerAccessLogFlagsEx, ExecuteThumb, 15);
|
|
|
|
DECL_BIT(mDebuggerAccessLogFlagsEx, ExecuteOpcode, 14);
|
|
DECL_BIT(mDebuggerAccessLogFlagsEx, ExecuteOperand, 15);
|
|
|
|
enum mDebuggerType {
|
|
DEBUGGER_NONE = 0,
|
|
DEBUGGER_CUSTOM,
|
|
DEBUGGER_CLI,
|
|
DEBUGGER_GDB,
|
|
DEBUGGER_ACCESS_LOGGER,
|
|
DEBUGGER_MAX
|
|
};
|
|
|
|
enum mDebuggerState {
|
|
DEBUGGER_CREATED = 0,
|
|
DEBUGGER_PAUSED,
|
|
DEBUGGER_RUNNING,
|
|
DEBUGGER_CALLBACK,
|
|
DEBUGGER_SHUTDOWN
|
|
};
|
|
|
|
enum mWatchpointType {
|
|
WATCHPOINT_WRITE = 1,
|
|
WATCHPOINT_READ = 2,
|
|
WATCHPOINT_RW = 3,
|
|
WATCHPOINT_CHANGE = 4,
|
|
WATCHPOINT_WRITE_CHANGE = 5,
|
|
};
|
|
|
|
enum mBreakpointType {
|
|
BREAKPOINT_HARDWARE,
|
|
BREAKPOINT_SOFTWARE
|
|
};
|
|
|
|
enum mDebuggerEntryReason {
|
|
DEBUGGER_ENTER_MANUAL,
|
|
DEBUGGER_ENTER_ATTACHED,
|
|
DEBUGGER_ENTER_BREAKPOINT,
|
|
DEBUGGER_ENTER_WATCHPOINT,
|
|
DEBUGGER_ENTER_ILLEGAL_OP,
|
|
DEBUGGER_ENTER_STACK
|
|
};
|
|
|
|
enum mStackTraceMode {
|
|
STACK_TRACE_DISABLED = 0,
|
|
STACK_TRACE_ENABLED = 1,
|
|
STACK_TRACE_BREAK_ON_RETURN = 2,
|
|
STACK_TRACE_BREAK_ON_CALL = 4,
|
|
STACK_TRACE_BREAK_ON_BOTH = STACK_TRACE_BREAK_ON_RETURN | STACK_TRACE_BREAK_ON_CALL
|
|
};
|
|
|
|
struct mDebuggerModule;
|
|
struct mDebuggerEntryInfo {
|
|
uint32_t address;
|
|
int segment;
|
|
int width;
|
|
union {
|
|
struct {
|
|
uint32_t oldValue;
|
|
uint32_t newValue;
|
|
enum mWatchpointType watchType;
|
|
enum mWatchpointType accessType;
|
|
enum mMemoryAccessSource accessSource;
|
|
} wp;
|
|
|
|
struct {
|
|
uint32_t opcode;
|
|
enum mBreakpointType breakType;
|
|
} bp;
|
|
|
|
struct {
|
|
enum mStackTraceMode traceType;
|
|
} st;
|
|
} type;
|
|
ssize_t pointId;
|
|
struct mDebuggerModule* target;
|
|
};
|
|
|
|
struct mBreakpoint {
|
|
ssize_t id;
|
|
uint32_t address;
|
|
int segment;
|
|
enum mBreakpointType type;
|
|
struct ParseTree* condition;
|
|
};
|
|
|
|
struct mWatchpoint {
|
|
ssize_t id;
|
|
int segment;
|
|
uint32_t minAddress;
|
|
uint32_t maxAddress;
|
|
enum mWatchpointType type;
|
|
struct ParseTree* condition;
|
|
};
|
|
|
|
struct mDebuggerInstructionInfo {
|
|
uint32_t address;
|
|
int segment;
|
|
unsigned width;
|
|
mDebuggerAccessLogFlags flags[INSN_LENGTH_MAX];
|
|
mDebuggerAccessLogFlagsEx flagsEx[INSN_LENGTH_MAX];
|
|
};
|
|
|
|
DECLARE_VECTOR(mBreakpointList, struct mBreakpoint);
|
|
DECLARE_VECTOR(mWatchpointList, struct mWatchpoint);
|
|
DECLARE_VECTOR(mDebuggerModuleList, struct mDebuggerModule*);
|
|
|
|
struct mStackFrame {
|
|
int callSegment;
|
|
uint32_t callAddress;
|
|
int entrySegment;
|
|
uint32_t entryAddress;
|
|
int frameBaseSegment;
|
|
uint32_t frameBaseAddress;
|
|
void* regs;
|
|
bool finished;
|
|
bool breakWhenFinished;
|
|
bool interrupt;
|
|
};
|
|
|
|
DECLARE_VECTOR(mStackFrames, struct mStackFrame);
|
|
|
|
struct mStackTrace {
|
|
struct mStackFrames stack;
|
|
size_t registersSize;
|
|
|
|
void (*formatRegisters)(struct mStackFrame* frame, char* out, size_t* length);
|
|
};
|
|
|
|
struct mDebugger;
|
|
struct ParseTree;
|
|
struct mDebuggerPlatform {
|
|
struct mDebugger* p;
|
|
|
|
void (*init)(void* cpu, struct mDebuggerPlatform*);
|
|
void (*deinit)(struct mDebuggerPlatform*);
|
|
void (*entered)(struct mDebuggerPlatform*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*);
|
|
|
|
bool (*hasBreakpoints)(struct mDebuggerPlatform*);
|
|
void (*checkBreakpoints)(struct mDebuggerPlatform*);
|
|
bool (*clearBreakpoint)(struct mDebuggerPlatform*, ssize_t id);
|
|
|
|
ssize_t (*setBreakpoint)(struct mDebuggerPlatform*, struct mDebuggerModule*, const struct mBreakpoint*);
|
|
void (*listBreakpoints)(struct mDebuggerPlatform*, struct mDebuggerModule*, struct mBreakpointList*);
|
|
|
|
ssize_t (*setWatchpoint)(struct mDebuggerPlatform*, struct mDebuggerModule*, const struct mWatchpoint*);
|
|
void (*listWatchpoints)(struct mDebuggerPlatform*, struct mDebuggerModule*, struct mWatchpointList*);
|
|
|
|
void (*trace)(struct mDebuggerPlatform*, char* out, size_t* length);
|
|
|
|
bool (*lookupIdentifier)(struct mDebuggerPlatform*, const char* name, int32_t* value, int* segment);
|
|
|
|
enum mStackTraceMode (*getStackTraceMode)(struct mDebuggerPlatform*);
|
|
void (*setStackTraceMode)(struct mDebuggerPlatform*, enum mStackTraceMode mode);
|
|
bool (*updateStackTrace)(struct mDebuggerPlatform* d);
|
|
|
|
void (*nextInstructionInfo)(struct mDebuggerPlatform* d, struct mDebuggerInstructionInfo* info);
|
|
};
|
|
|
|
struct mDebugger {
|
|
struct mCPUComponent d;
|
|
struct mDebuggerPlatform* platform;
|
|
enum mDebuggerState state;
|
|
struct mCore* core;
|
|
struct mScriptBridge* bridge;
|
|
struct mStackTrace stackTrace;
|
|
|
|
struct mDebuggerModuleList modules;
|
|
struct Table pointOwner;
|
|
};
|
|
|
|
struct mDebuggerModule {
|
|
struct mDebugger* p;
|
|
enum mDebuggerType type;
|
|
bool isPaused;
|
|
bool needsCallback;
|
|
|
|
void (*init)(struct mDebuggerModule*);
|
|
void (*deinit)(struct mDebuggerModule*);
|
|
|
|
void (*paused)(struct mDebuggerModule*, int32_t timeoutMs);
|
|
void (*update)(struct mDebuggerModule*);
|
|
void (*entered)(struct mDebuggerModule*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*);
|
|
void (*custom)(struct mDebuggerModule*);
|
|
|
|
void (*interrupt)(struct mDebuggerModule*);
|
|
};
|
|
|
|
void mDebuggerInit(struct mDebugger*);
|
|
void mDebuggerDeinit(struct mDebugger*);
|
|
|
|
void mDebuggerAttach(struct mDebugger*, struct mCore*);
|
|
void mDebuggerAttachModule(struct mDebugger*, struct mDebuggerModule*);
|
|
void mDebuggerDetachModule(struct mDebugger*, struct mDebuggerModule*);
|
|
void mDebuggerRunTimeout(struct mDebugger* debugger, int32_t timeoutMs);
|
|
void mDebuggerRun(struct mDebugger*);
|
|
void mDebuggerRunFrame(struct mDebugger*);
|
|
void mDebuggerEnter(struct mDebugger*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*);
|
|
|
|
void mDebuggerInterrupt(struct mDebugger*);
|
|
void mDebuggerUpdatePaused(struct mDebugger*);
|
|
void mDebuggerShutdown(struct mDebugger*);
|
|
void mDebuggerUpdate(struct mDebugger*);
|
|
|
|
bool mDebuggerIsShutdown(const struct mDebugger*);
|
|
|
|
struct mDebuggerModule* mDebuggerCreateModule(enum mDebuggerType type, struct mCore*);
|
|
void mDebuggerModuleSetNeedsCallback(struct mDebuggerModule*);
|
|
void mDebuggerModuleClearNeedsCallback(struct mDebuggerModule*);
|
|
|
|
bool mDebuggerLookupIdentifier(struct mDebugger* debugger, const char* name, int32_t* value, int* segment);
|
|
|
|
CXX_GUARD_END
|
|
|
|
#endif
|