Stack trace: implement data structures
Adam Higerd chighland@gmail.com
Sun, 26 Jul 2020 23:45:51 -0500
3 files changed,
121 insertions(+),
2 deletions(-)
A
include/mgba/internal/debugger/stack-trace.h
@@ -0,0 +1,56 @@
+/* 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 STACK_TRACE_H +#define STACK_TRACE_H + +#include <mgba-util/common.h> + +CXX_GUARD_START + +#include <mgba/core/cpu.h> +#include <mgba/core/log.h> +#include <mgba-util/vector.h> + +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, + STACK_TRACE_RUN_TO_FINISH = 8 +}; + +struct mStackFrame { + uint32_t instruction; + uint32_t callAddress; + uint32_t entryAddress; + uint32_t frameBaseAddress; + void* regs; + bool finished; + bool breakWhenFinished; +}; + +DECLARE_VECTOR(mStackFrames, struct mStackFrame); + +struct mStackTrace { + struct mStackFrames stack; + size_t registersSize; + + void (*formatRegisters)(struct mStackFrame* frame, char* out, size_t* length); +}; + +void mStackTraceInit(struct mStackTrace* stack, size_t registersSize); +void mStackTraceDeinit(struct mStackTrace* stack); + +void mStackTraceClear(struct mStackTrace* stack); +size_t mStackTraceGetDepth(struct mStackTrace* stack); +struct mStackFrame* mStackTracePush(struct mStackTrace* stack, uint32_t instruction, uint32_t pc, uint32_t destAddress, uint32_t sp, void* regs); +struct mStackFrame* mStackTraceGetFrame(struct mStackTrace* stack, size_t frame); +void mStackTracePop(struct mStackTrace* stack); + +CXX_GUARD_END + +#endif
M
src/debugger/CMakeLists.txt
→
src/debugger/CMakeLists.txt
@@ -3,7 +3,8 @@ set(SOURCE_FILES
cli-debugger.c debugger.c parser.c - symbols.c) + symbols.c + stack-trace.c) set(TEST_FILES test/lexer.c@@ -13,4 +14,4 @@ source_group("Debugger" FILES ${SOURCE_FILES})
source_group("Debugger tests" FILES ${TEST_FILES}) export_directory(DEBUGGER SOURCE_FILES) -export_directory(DEBUGGER_TEST TEST_FILES)+export_directory(DEBUGGER_TEST TEST_FILES)
A
src/debugger/stack-trace.c
@@ -0,0 +1,62 @@
+/* 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 <mgba/internal/debugger/stack-trace.h> + +#include <mgba/core/core.h> + +DEFINE_VECTOR(mStackFrames, struct mStackFrame); + +void mStackTraceInit(struct mStackTrace* stack, size_t registersSize) { + mStackFramesInit(&stack->stack, 0); +} + +void mStackTraceDeinit(struct mStackTrace* stack) { + mStackTraceClear(stack); + mStackFramesDeinit(&stack->stack); +} + +void mStackTraceClear(struct mStackTrace* stack) { + ssize_t i = mStackTraceGetDepth(stack) - 1; + while (i >= 0) { + free(mStackTraceGetFrame(stack, i)->regs); + --i; + } +} + +size_t mStackTraceGetDepth(struct mStackTrace* stack) { + return mStackFramesSize(&stack->stack); +} + +struct mStackFrame* mStackTracePush(struct mStackTrace* stack, uint32_t instruction, uint32_t pc, uint32_t destAddress, uint32_t sp, void* regs) { + struct mStackFrame* frame = mStackFramesAppend(&stack->stack); + frame->instruction = instruction; + frame->callAddress = pc; + frame->entryAddress = destAddress; + frame->frameBaseAddress = sp; + frame->regs = malloc(stack->registersSize); + frame->finished = false; + frame->breakWhenFinished = false; + memcpy(frame->regs, regs, stack->registersSize); + return frame; +} + +struct mStackFrame* mStackTraceGetFrame(struct mStackTrace* stack, size_t frame) { + size_t depth = mStackTraceGetDepth(stack); + if (frame >= depth) { + return NULL; + } + return mStackFramesGetPointer(&stack->stack, depth - frame - 1); +} + +void mStackTracePop(struct mStackTrace* stack) { + size_t depth = mStackTraceGetDepth(stack); + if (depth == 0) { + return; + } + struct mStackFrame* frame = mStackFramesGetPointer(&stack->stack, depth - 1); + free(frame->regs); + mStackFramesResize(&stack->stack, depth - 1); +}