This repository has been archived on 2022-05-31. You can view files and clone it, but cannot push or open issues or pull requests.
Luma3DS-3GX/sysmodules/rosalina/source/gdb/regs.c
2020-04-25 13:42:10 +01:00

154 lines
4.4 KiB
C

/*
* This file is part of Luma3DS.
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
*/
#include "gdb/regs.h"
#include "gdb/net.h"
GDB_DECLARE_HANDLER(ReadRegisters)
{
if(ctx->selectedThreadId == 0)
ctx->selectedThreadId = ctx->currentThreadId;
ThreadContext regs;
Result r = svcGetDebugThreadContext(&regs, ctx->debug, ctx->selectedThreadId, THREADCONTEXT_CONTROL_ALL);
if(R_FAILED(r))
return GDB_ReplyErrno(ctx, EPERM);
return GDB_SendHexPacket(ctx, &regs, sizeof(ThreadContext));
}
GDB_DECLARE_HANDLER(WriteRegisters)
{
if(ctx->selectedThreadId == 0)
ctx->selectedThreadId = ctx->currentThreadId;
ThreadContext regs;
if(GDB_DecodeHex(&regs, ctx->commandData, sizeof(ThreadContext)) != sizeof(ThreadContext))
return GDB_ReplyErrno(ctx, EPERM);
Result r = svcSetDebugThreadContext(ctx->debug, ctx->selectedThreadId, &regs, THREADCONTEXT_CONTROL_ALL);
if(R_FAILED(r))
return GDB_ReplyErrno(ctx, EPERM);
else
return GDB_ReplyOk(ctx);
}
static u32 GDB_ConvertRegisterNumber(ThreadContextControlFlags *flags, u32 gdbNum)
{
if(gdbNum <= 15)
{
*flags = (gdbNum >= 13) ? THREADCONTEXT_CONTROL_CPU_SPRS : THREADCONTEXT_CONTROL_CPU_GPRS;
return gdbNum;
}
else if(gdbNum == 25)
{
*flags = THREADCONTEXT_CONTROL_CPU_SPRS;
return 16;
}
else if(gdbNum >= 26 && gdbNum <= 41)
{
*flags = THREADCONTEXT_CONTROL_FPU_GPRS;
return gdbNum - 26;
}
else if(gdbNum == 42 || gdbNum == 43)
{
*flags = THREADCONTEXT_CONTROL_FPU_SPRS;
return gdbNum - 42;
}
else
{
*flags = (ThreadContextControlFlags)0;
return 0;
}
}
GDB_DECLARE_HANDLER(ReadRegister)
{
if(ctx->selectedThreadId == 0)
ctx->selectedThreadId = ctx->currentThreadId;
ThreadContext regs;
ThreadContextControlFlags flags;
u32 gdbRegNum;
if(GDB_ParseHexIntegerList(&gdbRegNum, ctx->commandData, 1, 0) == NULL)
return GDB_ReplyErrno(ctx, EILSEQ);
u32 n = GDB_ConvertRegisterNumber(&flags, gdbRegNum);
if(!flags)
return GDB_ReplyErrno(ctx, EINVAL);
Result r = svcGetDebugThreadContext(&regs, ctx->debug, ctx->selectedThreadId, flags);
if(R_FAILED(r))
return GDB_ReplyErrno(ctx, EPERM);
if(flags & THREADCONTEXT_CONTROL_CPU_GPRS)
return GDB_SendHexPacket(ctx, &regs.cpu_registers.r[n], 4);
else if(flags & THREADCONTEXT_CONTROL_CPU_SPRS)
return GDB_SendHexPacket(ctx, &regs.cpu_registers.sp + (n - 13), 4); // hacky
else if(flags & THREADCONTEXT_CONTROL_FPU_GPRS)
return GDB_SendHexPacket(ctx, &regs.fpu_registers.d[n], 8);
else
return GDB_SendHexPacket(ctx, &regs.fpu_registers.fpscr + n, 4); // hacky
}
GDB_DECLARE_HANDLER(WriteRegister)
{
if(ctx->selectedThreadId == 0)
ctx->selectedThreadId = ctx->currentThreadId;
ThreadContext regs;
ThreadContextControlFlags flags;
u32 gdbRegNum;
const char *valueStart = GDB_ParseHexIntegerList(&gdbRegNum, ctx->commandData, 1, '=');
if(valueStart == NULL || *valueStart != '=')
return GDB_ReplyErrno(ctx, EILSEQ);
valueStart++;
u32 n = GDB_ConvertRegisterNumber(&flags, gdbRegNum);
u32 value;
u64 value64;
if(flags & THREADCONTEXT_CONTROL_FPU_GPRS)
{
if(GDB_DecodeHex(&value64, valueStart, 8) != 8 || valueStart[16] != 0)
return GDB_ReplyErrno(ctx, EINVAL);
}
else if(flags)
{
if(GDB_DecodeHex(&value, valueStart, 4) != 4 || valueStart[8] != 0)
return GDB_ReplyErrno(ctx, EINVAL);
}
else
return GDB_ReplyErrno(ctx, EINVAL);
Result r = svcGetDebugThreadContext(&regs, ctx->debug, ctx->selectedThreadId, flags);
if(R_FAILED(r))
return GDB_ReplyErrno(ctx, EPERM);
if(flags & THREADCONTEXT_CONTROL_CPU_GPRS)
regs.cpu_registers.r[n] = value;
else if(flags & THREADCONTEXT_CONTROL_CPU_SPRS)
*(&regs.cpu_registers.sp + (n - 13)) = value; // hacky
else if(flags & THREADCONTEXT_CONTROL_FPU_GPRS)
memcpy(&regs.fpu_registers.d[n], &value64, 8);
else
*(&regs.fpu_registers.fpscr + n) = value; // hacky
r = svcSetDebugThreadContext(ctx->debug, ctx->selectedThreadId, &regs, flags);
if(R_FAILED(r))
return GDB_ReplyErrno(ctx, EPERM);
else
return GDB_ReplyOk(ctx);
}