all repos — mgba @ 238c68f080cd13f3c8ca8b11f744216e4f296c78

mGBA Game Boy Advance Emulator

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

  1/* Copyright (c) 2013-2016 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	memcpy(frame->regs, regs, stack->registersSize);
 50	return frame;
 51}
 52
 53struct mStackFrame* mStackTraceGetFrame(struct mStackTrace* stack, uint32_t frame) {
 54	size_t depth = mStackTraceGetDepth(stack);
 55	if (frame >= depth) {
 56		return NULL;
 57	}
 58	return mStackFramesGetPointer(&stack->stack, depth - frame - 1);
 59}
 60
 61void mStackTraceFormatFrame(struct mStackTrace* stack, uint32_t frame, char* out, size_t* length) {
 62	struct mStackFrame* stackFrame = mStackTraceGetFrame(stack, frame);
 63	struct mStackFrame* prevFrame = mStackTraceGetFrame(stack, frame + 1);
 64	size_t written = snprintf(out, *length, "#%d  ", frame);
 65	CHECK_LENGTH();
 66	if (prevFrame) {
 67		written += snprintf(out + written, *length - written, "%08X ", prevFrame->entryAddress);
 68		CHECK_LENGTH();
 69	}
 70	if (!stackFrame) {
 71		written += snprintf(out + written, *length - written, "no stack frame available)\n");
 72		*length = written;
 73		return;
 74	} else if (stack->formatRegisters) {
 75		written += snprintf(out + written, *length - written, "(");
 76		CHECK_LENGTH();
 77		size_t formattedSize = *length - written;
 78		stack->formatRegisters(stackFrame, out + written, &formattedSize);
 79		written += formattedSize;
 80		CHECK_LENGTH();
 81		written += snprintf(out + written, *length - written, ")\n    ");
 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 < 1) {
 96		return;
 97	}
 98	struct mStackFrame* frame = mStackFramesGetPointer(&stack->stack, depth - 1);
 99	free(frame->regs);
100	mStackFramesResize(&stack->stack, -1);
101}