all repos — mgba @ fb267a32ff4b9ff6dc8688610b936cb8450edd8e

mGBA Game Boy Advance Emulator

src/debugger/stack-trace.c (view raw)

  1/* Copyright (c) 2013-2020 Jeffrey Pfau
  2 *
  3 * This Source Code Form is subject to the terms of the Mozilla Public
  4 * License, v. 2.0. If a copy of the MPL was not distributed with this
  5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6#include <mgba/internal/debugger/stack-trace.h>
  7
  8#include <mgba/core/core.h>
  9
 10#define CHECK_LENGTH() \
 11	if (written >= *length) { \
 12		*length = written; \
 13		return; \
 14	}
 15
 16DEFINE_VECTOR(mStackFrames, struct mStackFrame);
 17
 18void mStackTraceInit(struct mStackTrace* stack, size_t registersSize) {
 19	mStackFramesInit(&stack->stack, 0);
 20	stack->registersSize = registersSize;
 21}
 22
 23void mStackTraceDeinit(struct mStackTrace* stack) {
 24	mStackTraceClear(stack);
 25	mStackFramesDeinit(&stack->stack);
 26}
 27
 28void mStackTraceClear(struct mStackTrace* stack) {
 29	ssize_t i = mStackTraceGetDepth(stack) - 1;
 30	while (i >= 0) {
 31		free(mStackTraceGetFrame(stack, i)->regs);
 32		--i;
 33	}
 34	mStackFramesClear(&stack->stack);
 35}
 36
 37size_t mStackTraceGetDepth(struct mStackTrace* stack) {
 38	return mStackFramesSize(&stack->stack);
 39}
 40
 41struct mStackFrame* mStackTracePush(struct mStackTrace* stack, uint32_t pc, uint32_t destAddress, uint32_t sp, void* regs) {
 42	struct mStackFrame* frame = mStackFramesAppend(&stack->stack);
 43	frame->callAddress = pc;
 44	frame->entryAddress = destAddress;
 45	frame->frameBaseAddress = sp;
 46	frame->regs = malloc(stack->registersSize);
 47	frame->finished = false;
 48	frame->breakWhenFinished = false;
 49	frame->interrupt = false;
 50	memcpy(frame->regs, regs, stack->registersSize);
 51	return frame;
 52}
 53
 54struct mStackFrame* mStackTraceGetFrame(struct mStackTrace* stack, uint32_t frame) {
 55	size_t depth = mStackTraceGetDepth(stack);
 56	if (frame >= depth) {
 57		return NULL;
 58	}
 59	return mStackFramesGetPointer(&stack->stack, depth - frame - 1);
 60}
 61
 62void mStackTraceFormatFrame(struct mStackTrace* stack, uint32_t frame, char* out, size_t* length) {
 63	struct mStackFrame* stackFrame = mStackTraceGetFrame(stack, frame);
 64	struct mStackFrame* prevFrame = mStackTraceGetFrame(stack, frame + 1);
 65	size_t written = snprintf(out, *length, "#%d  ", frame);
 66	CHECK_LENGTH();
 67	if (prevFrame) {
 68		written += snprintf(out + written, *length - written, "%08X ", prevFrame->entryAddress);
 69		CHECK_LENGTH();
 70	}
 71	if (!stackFrame) {
 72		written += snprintf(out + written, *length - written, "no stack frame available)\n");
 73		*length = written;
 74		return;
 75	} else if (stack->formatRegisters) {
 76		written += snprintf(out + written, *length - written, "(");
 77		CHECK_LENGTH();
 78		char buffer[1024];
 79		size_t formattedSize = sizeof(buffer) - 2;
 80		stack->formatRegisters(stackFrame, buffer, &formattedSize);
 81		written += snprintf(out + written, *length - written, "%s)\n    ", buffer);
 82		CHECK_LENGTH();
 83	}
 84	if (prevFrame) {
 85		int32_t offset = stackFrame->callAddress - prevFrame->entryAddress;
 86		written += snprintf(out + written, *length - written, "at %08X [%08X+%d]\n", stackFrame->callAddress, prevFrame->entryAddress, offset);
 87	} else {
 88		written += snprintf(out + written, *length - written, "at %08X\n", stackFrame->callAddress);
 89	}
 90	*length = written;
 91}
 92
 93void mStackTracePop(struct mStackTrace* stack) {
 94	size_t depth = mStackTraceGetDepth(stack);
 95	if (depth > 0) {
 96		struct mStackFrame* frame = mStackFramesGetPointer(&stack->stack, depth - 1);
 97		free(frame->regs);
 98		mStackFramesResize(&stack->stack, -1);
 99	}
100}