From 9ebf3c95800cc2b0a3dcae87e0b34cf7b7bc1576 Mon Sep 17 00:00:00 2001 From: TuxSH <1922548+TuxSH@users.noreply.github.com> Date: Wed, 22 Jan 2020 01:50:03 +0000 Subject: [PATCH] thermosphere: wip gdb --- thermosphere/src/gdb.c | 171 +++--------------- thermosphere/src/gdb.h | 100 +++-------- thermosphere/src/gdb/debug.c | 36 ++-- thermosphere/src/gdb/net.c | 2 +- thermosphere/src/gdb/server.c | 279 ++++++----------------------- thermosphere/src/gdb/server.h | 29 ++- thermosphere/src/gdb/watchpoints.c | 16 +- thermosphere/src/utils.h | 1 + 8 files changed, 134 insertions(+), 500 deletions(-) diff --git a/thermosphere/src/gdb.c b/thermosphere/src/gdb.c index c45ec17bc..2154f354b 100644 --- a/thermosphere/src/gdb.c +++ b/thermosphere/src/gdb.c @@ -5,182 +5,61 @@ * SPDX-License-Identifier: (MIT OR GPL-2.0-or-later) */ -#if 0 +#if 1 #include "gdb.h" #include "gdb/net.h" #include "gdb/server.h" #include "gdb/debug.h" -#include "gdb/watchpoints.h" -#include "gdb/breakpoints.h" #include "gdb/stop_point.h" +#include "breakpoints.h" +#include "software_breakpoints.h" +#include "watchpoints.h" + void GDB_InitializeContext(GDBContext *ctx) { memset(ctx, 0, sizeof(GDBContext)); - RecursiveLock_Init(&ctx->lock); - - RecursiveLock_Lock(&ctx->lock); - - svcCreateEvent(&ctx->continuedEvent, RESET_ONESHOT); - svcCreateEvent(&ctx->processAttachedEvent, RESET_STICKY); - - ctx->eventToWaitFor = ctx->processAttachedEvent; - ctx->continueFlags = (DebugFlags)(DBG_SIGNAL_FAULT_EXCEPTION_EVENTS | DBG_INHIBIT_USER_CPU_EXCEPTION_HANDLERS); - - RecursiveLock_Unlock(&ctx->lock); } void GDB_FinalizeContext(GDBContext *ctx) { - RecursiveLock_Lock(&ctx->lock); - - svcClearEvent(ctx->processAttachedEvent); - - svcCloseHandle(ctx->processAttachedEvent); - svcCloseHandle(ctx->continuedEvent); - - RecursiveLock_Unlock(&ctx->lock); + (void)ctx; } -Result GDB_AttachToProcess(GDBContext *ctx) +void GDB_Attach(GDBContext *ctx) { - Result r; - - // Two cases: attached during execution, or started attached - // The second case will have, after RunQueuedProcess: attach process, debugger break, attach thread (with creator = 0) - - if (!(ctx->flags & GDB_FLAG_ATTACHED_AT_START)) - r = svcDebugActiveProcess(&ctx->debug, ctx->pid); - else - { - r = 0; + if (!(ctx->flags & GDB_FLAG_ATTACHED_AT_START)) { + // TODO: debug pause } - if(R_SUCCEEDED(r)) - { - // Note: ctx->pid will be (re)set while processing 'attach process' - DebugEventInfo *info = &ctx->latestDebugEvent; - ctx->processExited = ctx->processEnded = false; - if (!(ctx->flags & GDB_FLAG_ATTACHED_AT_START)) - { - while(R_SUCCEEDED(svcGetProcessDebugEvent(info, ctx->debug)) && - info->type != DBGEVENT_EXCEPTION && - info->exception.type != EXCEVENT_ATTACH_BREAK) - { - GDB_PreprocessDebugEvent(ctx, info); - svcContinueDebugEvent(ctx->debug, ctx->continueFlags); - } - } - else - { - // Attach process, debugger break - for(u32 i = 0; i < 2; i++) - { - if (R_FAILED(r = svcGetProcessDebugEvent(info, ctx->debug))) - return r; - GDB_PreprocessDebugEvent(ctx, info); - if (R_FAILED(r = svcContinueDebugEvent(ctx->debug, ctx->continueFlags))) - return r; - } - if(R_FAILED(r = svcWaitSynchronization(ctx->debug, -1LL))) - return r; - if (R_FAILED(r = svcGetProcessDebugEvent(info, ctx->debug))) - return r; - // Attach thread - GDB_PreprocessDebugEvent(ctx, info); - } - } - else - return r; + // TODO: move the debug traps enable here? + // TODO: process the event - r = svcSignalEvent(ctx->processAttachedEvent); - if (R_SUCCEEDED(r)) - ctx->state = GDB_STATE_ATTACHED; - return r; + ctx->state = GDB_STATE_ATTACHED; } -void GDB_DetachFromProcess(GDBContext *ctx) +void GDB_Detach(GDBContext *ctx) { - DebugEventInfo dummy; - for(u32 i = 0; i < ctx->nbBreakpoints; i++) - { - if(!ctx->breakpoints[i].persistent) - GDB_DisableBreakpointById(ctx, i); - } - memset(&ctx->breakpoints, 0, sizeof(ctx->breakpoints)); - ctx->nbBreakpoints = 0; + removeAllWatchpoints(); + removeAllBreakpoints(); + removeAllSoftwareBreakpoints(true); - for(u32 i = 0; i < ctx->nbWatchpoints; i++) - { - GDB_RemoveWatchpoint(ctx, ctx->watchpoints[i], WATCHPOINT_DISABLED); - ctx->watchpoints[i] = 0; - } - ctx->nbWatchpoints = 0; + // Reports to gdb are prevented because of "detaching" state? - svcKernelSetState(0x10002, ctx->pid, false); - memset(ctx->svcMask, 0, 32); + // TODO: disable debug traps - memset(ctx->threadListData, 0, sizeof(ctx->threadListData)); - ctx->threadListDataPos = 0; - - //svcSignalEvent(server->statusUpdated); - - /* - There's a possibility of a race condition with a possible user exception handler, but you shouldn't - use 'kill' on APPLICATION titles in the first place (reboot hanging because the debugger is still running, etc). - */ - - ctx->continueFlags = (DebugFlags)0; - - while(R_SUCCEEDED(svcGetProcessDebugEvent(&dummy, ctx->debug))); - while(R_SUCCEEDED(svcContinueDebugEvent(ctx->debug, ctx->continueFlags))); - if(ctx->flags & GDB_FLAG_TERMINATE_PROCESS) - { - svcTerminateDebugProcess(ctx->debug); + if(ctx->flags & GDB_FLAG_TERMINATE) { + // TODO: redefine what it means for thermosphère, if anything. ctx->processEnded = true; ctx->processExited = false; } - while(R_SUCCEEDED(svcGetProcessDebugEvent(&dummy, ctx->debug))); - while(R_SUCCEEDED(svcContinueDebugEvent(ctx->debug, ctx->continueFlags))); - - svcCloseHandle(ctx->debug); - ctx->debug = 0; - memset(&ctx->launchedProgramInfo, 0, sizeof(FS_ProgramInfo)); - ctx->launchedProgramLaunchFlags = 0; - - ctx->eventToWaitFor = ctx->processAttachedEvent; - ctx->continueFlags = (DebugFlags)(DBG_SIGNAL_FAULT_EXCEPTION_EVENTS | DBG_INHIBIT_USER_CPU_EXCEPTION_HANDLERS); - ctx->pid = 0; - ctx->currentThreadId = 0; - ctx->selectedThreadId = 0; - ctx->selectedThreadIdForContinuing = 0; - ctx->nbThreads = 0; - ctx->totalNbCreatedThreads = 0; - memset(ctx->threadInfos, 0, sizeof(ctx->threadInfos)); - ctx->currentHioRequestTargetAddr = 0; memset(&ctx->currentHioRequest, 0, sizeof(PackedGdbHioRequest)); } -Result GDB_CreateProcess(GDBContext *ctx, const FS_ProgramInfo *progInfo, u32 launchFlags) -{ - Handle debug = 0; - ctx->debug = 0; - Result r = PMDBG_LaunchTitleDebug(&debug, progInfo, launchFlags); - if(R_FAILED(r)) - return r; - - ctx->flags |= GDB_FLAG_CREATED | GDB_FLAG_ATTACHED_AT_START; - ctx->debug = debug; - ctx->launchedProgramInfo = *progInfo; - ctx->launchedProgramLaunchFlags = launchFlags; - r = GDB_AttachToProcess(ctx); - return r; -} - GDB_DECLARE_HANDLER(Unsupported) { return GDB_ReplyEmpty(ctx); @@ -188,12 +67,8 @@ GDB_DECLARE_HANDLER(Unsupported) GDB_DECLARE_HANDLER(EnableExtendedMode) { - if (ctx->localPort >= GDB_PORT_BASE && ctx->localPort < GDB_PORT_BASE + MAX_DEBUG) - { - ctx->flags |= GDB_FLAG_EXTENDED_REMOTE; - return GDB_ReplyOk(ctx); - } - else - return GDB_ReplyEmpty(ctx); + // We don't support it for now... + return GDB_HandleUnsupported(ctx); } + #endif diff --git a/thermosphere/src/gdb.h b/thermosphere/src/gdb.h index aa1499f32..2bad5eb46 100644 --- a/thermosphere/src/gdb.h +++ b/thermosphere/src/gdb.h @@ -7,20 +7,10 @@ #pragma once -#include <3ds/types.h> -#include <3ds/svc.h> -#include <3ds/synchronization.h> -#include <3ds/result.h> -#include "pmdbgext.h" -#include "sock_util.h" -#include "memory.h" -#include "ifile.h" +#include "utils.h" +#include "spinlock.h" -#define MAX_DEBUG 3 -#define MAX_DEBUG_THREAD 127 -#define MAX_BREAKPOINT 256 - -#define MAX_TIO_OPEN_FILE 32 +#define MAX_CTX 3 // 512+24 is the ideal size as IDA will try to read exactly 0x100 bytes at a time. Add 4 to this, for $#, see below. // IDA seems to want additional bytes as well. @@ -35,14 +25,6 @@ #define GDB_DECLARE_QUERY_HANDLER(name) GDB_DECLARE_HANDLER(Query##name) #define GDB_DECLARE_VERBOSE_HANDLER(name) GDB_DECLARE_HANDLER(Verbose##name) -typedef struct Breakpoint -{ - u32 address; - u32 savedInstruction; - u8 instructionSize; - bool persistent; -} Breakpoint; - typedef struct PackedGdbHioRequest { char magic[4]; // "GDB\x00" @@ -61,24 +43,17 @@ typedef struct PackedGdbHioRequest bool ctrlC; } PackedGdbHioRequest; -typedef struct GdbTioFileInfo -{ - IFile f; - int flags; -} GdbTioFileInfo; - -enum -{ - GDB_FLAG_SELECTED = 1, - GDB_FLAG_USED = 2, - GDB_FLAG_ALLOCATED_MASK = GDB_FLAG_SELECTED | GDB_FLAG_USED, - GDB_FLAG_EXTENDED_REMOTE = 4, - GDB_FLAG_NOACK = 8, - GDB_FLAG_PROC_RESTART_MASK = GDB_FLAG_NOACK | GDB_FLAG_EXTENDED_REMOTE | GDB_FLAG_USED, - GDB_FLAG_PROCESS_CONTINUING = 16, - GDB_FLAG_TERMINATE_PROCESS = 32, - GDB_FLAG_ATTACHED_AT_START = 64, - GDB_FLAG_CREATED = 128, +enum { + GDB_FLAG_SELECTED = BIT(0), + GDB_FLAG_USED = BIT(1), + GDB_FLAG_ALLOCATED_MASK = GDB_FLAG_SELECTED | GDB_FLAG_USED, + GDB_FLAG_EXTENDED_REMOTE = BIT(2), // unused here + GDB_FLAG_NOACK = BIT(3), + GDB_FLAG_RESTART_MASK = GDB_FLAG_NOACK | GDB_FLAG_EXTENDED_REMOTE | GDB_FLAG_USED, + GDB_FLAG_CONTINUING = BIT(4), + GDB_FLAG_TERMINATE = BIT(5), + GDB_FLAG_ATTACHED_AT_START = BIT(6), + GDB_FLAG_CREATED = BIT(7), }; typedef enum GDBState @@ -99,60 +74,28 @@ struct GDBServer; typedef struct GDBContext { - sock_ctx super; + TransportInterface *transportIface; struct GDBServer *parent; - RecursiveLock lock; - u16 localPort; + RecursiveSpinlock lock; u32 flags; GDBState state; bool noAckSent; - u32 pid; - Handle debug; - - // vRun and R (restart) info: - FS_ProgramInfo launchedProgramInfo; - u32 launchedProgramLaunchFlags; - - ThreadInfo threadInfos[MAX_DEBUG_THREAD]; - u32 nbThreads; - u32 currentThreadId, selectedThreadId, selectedThreadIdForContinuing; - u32 totalNbCreatedThreads; - - Handle processAttachedEvent, continuedEvent; - Handle eventToWaitFor; + u32 currentThreadId; bool catchThreadEvents; bool processEnded, processExited; - DebugEventInfo latestDebugEvent; - DebugFlags continueFlags; - u32 svcMask[8]; + //DebugEventInfo latestDebugEvent; FIXME - u32 nbBreakpoints; - Breakpoint breakpoints[MAX_BREAKPOINT]; - - u32 nbWatchpoints; - u32 watchpoints[2]; - - u32 currentHioRequestTargetAddr; + uintptr_t currentHioRequestTargetAddr; PackedGdbHioRequest currentHioRequest; - GdbTioFileInfo openTioFileInfos[MAX_TIO_OPEN_FILE]; - u32 numOpenTioFiles; - - bool enableExternalMemoryAccess; char *commandData, *commandEnd; int latestSentPacketSize; char buffer[GDB_BUF_LEN + 4]; - - char threadListData[0x800]; - u32 threadListDataPos; - - char memoryOsInfoXmlData[0x800]; - char processesOsInfoXmlData[0x1800]; } GDBContext; typedef int (*GDBCommandHandler)(GDBContext *ctx); @@ -160,9 +103,8 @@ typedef int (*GDBCommandHandler)(GDBContext *ctx); void GDB_InitializeContext(GDBContext *ctx); void GDB_FinalizeContext(GDBContext *ctx); -Result GDB_AttachToProcess(GDBContext *ctx); -void GDB_DetachFromProcess(GDBContext *ctx); -Result GDB_CreateProcess(GDBContext *ctx, const FS_ProgramInfo *progInfo, u32 launchFlags); +void GDB_Attach(GDBContext *ctx); +void GDB_Detach(GDBContext *ctx); GDB_DECLARE_HANDLER(Unsupported); GDB_DECLARE_HANDLER(EnableExtendedMode); diff --git a/thermosphere/src/gdb/debug.c b/thermosphere/src/gdb/debug.c index 47d8477d9..2f2baed3d 100644 --- a/thermosphere/src/gdb/debug.c +++ b/thermosphere/src/gdb/debug.c @@ -23,7 +23,7 @@ static void GDB_DetachImmediatelyExtended(GDBContext *ctx) { // detach immediately - RecursiveLock_Lock(&ctx->lock); + recursiveSpinlockLock(&ctx->lock); ctx->state = GDB_STATE_DETACHING; svcClearEvent(ctx->processAttachedEvent); @@ -31,14 +31,14 @@ static void GDB_DetachImmediatelyExtended(GDBContext *ctx) svcClearEvent(ctx->parent->statusUpdateReceived); svcSignalEvent(ctx->parent->statusUpdated); - RecursiveLock_Unlock(&ctx->lock); + recursiveSpinlockUnlock(&ctx->lock); svcWaitSynchronization(ctx->parent->statusUpdateReceived, -1LL); - RecursiveLock_Lock(&ctx->lock); + recursiveSpinlockLock(&ctx->lock); GDB_DetachFromProcess(ctx); - ctx->flags &= GDB_FLAG_PROC_RESTART_MASK; - RecursiveLock_Unlock(&ctx->lock); + ctx->flags &= GDB_FLAG_RESTART_MASK; + recursiveSpinlockUnlock(&ctx->lock); } GDB_DECLARE_VERBOSE_HANDLER(Run) @@ -90,18 +90,18 @@ GDB_DECLARE_VERBOSE_HANDLER(Run) progInfo.mediaType = (FS_MediaType)mediaType; progInfo.programId = titleId; - RecursiveLock_Lock(&ctx->lock); + recursiveSpinlockLock(&ctx->lock); Result r = GDB_CreateProcess(ctx, &progInfo, launchFlags); if (R_FAILED(r)) { if(ctx->debug != 0) GDB_DetachImmediatelyExtended(ctx); - RecursiveLock_Unlock(&ctx->lock); + recursiveSpinlockUnlock(&ctx->lock); return GDB_ReplyErrno(ctx, EPERM); } - RecursiveLock_Unlock(&ctx->lock); + recursiveSpinlockUnlock(&ctx->lock); return R_SUCCEEDED(r) ? GDB_SendStopReply(ctx, &ctx->latestDebugEvent) : GDB_ReplyErrno(ctx, EPERM); } @@ -115,15 +115,15 @@ GDB_DECLARE_HANDLER(Restart) FS_ProgramInfo progInfo = ctx->launchedProgramInfo; u32 launchFlags = ctx->launchedProgramLaunchFlags; - ctx->flags |= GDB_FLAG_TERMINATE_PROCESS; + ctx->flags |= GDB_FLAG_TERMINATE; if (ctx->flags & GDB_FLAG_EXTENDED_REMOTE) GDB_DetachImmediatelyExtended(ctx); - RecursiveLock_Lock(&ctx->lock); + recursiveSpinlockLock(&ctx->lock); Result r = GDB_CreateProcess(ctx, &progInfo, launchFlags); if (R_FAILED(r) && ctx->debug != 0) GDB_DetachImmediatelyExtended(ctx); - RecursiveLock_Unlock(&ctx->lock); + recursiveSpinlockUnlock(&ctx->lock); return 0; } @@ -137,12 +137,12 @@ GDB_DECLARE_VERBOSE_HANDLER(Attach) if(GDB_ParseHexIntegerList(&pid, ctx->commandData, 1, 0) == NULL) return GDB_ReplyErrno(ctx, EILSEQ); - RecursiveLock_Lock(&ctx->lock); + recursiveSpinlockLock(&ctx->lock); ctx->pid = pid; Result r = GDB_AttachToProcess(ctx); if(R_FAILED(r)) GDB_DetachImmediatelyExtended(ctx); - RecursiveLock_Unlock(&ctx->lock); + recursiveSpinlockUnlock(&ctx->lock); return R_SUCCEEDED(r) ? GDB_SendStopReply(ctx, &ctx->latestDebugEvent) : GDB_ReplyErrno(ctx, EPERM); } @@ -163,7 +163,7 @@ GDB_DECLARE_HANDLER(Detach) GDB_DECLARE_HANDLER(Kill) { ctx->state = GDB_STATE_DETACHING; - ctx->flags |= GDB_FLAG_TERMINATE_PROCESS; + ctx->flags |= GDB_FLAG_TERMINATE; if (ctx->flags & GDB_FLAG_EXTENDED_REMOTE) GDB_DetachImmediatelyExtended(ctx); @@ -172,11 +172,11 @@ GDB_DECLARE_HANDLER(Kill) GDB_DECLARE_HANDLER(Break) { - if(!(ctx->flags & GDB_FLAG_PROCESS_CONTINUING)) + if(!(ctx->flags & GDB_FLAG_CONTINUING)) // Is this ever reached? return GDB_SendPacket(ctx, "S02", 3); else { - ctx->flags &= ~GDB_FLAG_PROCESS_CONTINUING; + ctx->flags &= ~GDB_FLAG_CONTINUING; return 0; } } @@ -185,7 +185,7 @@ void GDB_ContinueExecution(GDBContext *ctx) { ctx->selectedThreadId = ctx->selectedThreadIdForContinuing = 0; svcContinueDebugEvent(ctx->debug, ctx->continueFlags); - ctx->flags |= GDB_FLAG_PROCESS_CONTINUING; + ctx->flags |= GDB_FLAG_CONTINUING; } GDB_DECLARE_HANDLER(Continue) @@ -654,7 +654,7 @@ int GDB_HandleDebugEvents(GDBContext *ctx) ctx->latestDebugEvent = info; ret = GDB_SendStopReply(ctx, &info); - ctx->flags &= ~GDB_FLAG_PROCESS_CONTINUING; + ctx->flags &= ~GDB_FLAG_CONTINUING; return ret; } } diff --git a/thermosphere/src/gdb/net.c b/thermosphere/src/gdb/net.c index b328b4b83..bc9082f8f 100644 --- a/thermosphere/src/gdb/net.c +++ b/thermosphere/src/gdb/net.c @@ -335,7 +335,7 @@ int GDB_SendStreamData(GDBContext *ctx, const char *streamData, u32 offset, u32 int GDB_SendDebugString(GDBContext *ctx, const char *fmt, ...) // unsecure { - /*if(ctx->state == GDB_STATE_DETACHING || !(ctx->flags & GDB_FLAG_PROCESS_CONTINUING)) + /*if(ctx->state == GDB_STATE_DETACHING || !(ctx->flags & GDB_FLAG_CONTINUING)) return 0;*/ char formatted[(GDB_BUF_LEN - 1) / 2 + 1]; diff --git a/thermosphere/src/gdb/server.c b/thermosphere/src/gdb/server.c index 0536f9295..e6f80c89f 100644 --- a/thermosphere/src/gdb/server.c +++ b/thermosphere/src/gdb/server.c @@ -17,266 +17,98 @@ #include "gdb/watchpoints.h" #include "gdb/breakpoints.h" #include "gdb/stop_point.h" -#include "task_runner.h" -Result GDB_InitializeServer(GDBServer *server) +void GDB_InitializeServer(GDBServer *server) { - Result ret = server_init(&server->super); - if(ret != 0) - return ret; - - server->super.host = 0; - - server->super.accept_cb = (sock_accept_cb)GDB_AcceptClient; - server->super.data_cb = (sock_data_cb) GDB_DoPacket; - server->super.close_cb = (sock_close_cb) GDB_CloseClient; - - server->super.alloc = (sock_alloc_func) GDB_GetClient; - server->super.free = (sock_free_func) GDB_ReleaseClient; - - server->super.clients_per_server = 1; - - server->referenceCount = 0; - svcCreateEvent(&server->statusUpdated, RESET_ONESHOT); - svcCreateEvent(&server->statusUpdateReceived, RESET_STICKY); - - for(u32 i = 0; i < sizeof(server->ctxs) / sizeof(GDBContext); i++) + for(u32 i = 0; i < sizeof(server->ctxs) / sizeof(GDBContext); i++) { GDB_InitializeContext(server->ctxs + i); - - GDB_ResetWatchpoints(); + } return 0; } void GDB_FinalizeServer(GDBServer *server) { - server_finalize(&server->super); - // Kill the "next application" context if needed - for (u32 i = 0; i < MAX_DEBUG; i++) { - if (server->ctxs[i].debug != 0) + for (u32 i = 0; i < MAX_CTX; i++) { + if (server->ctxs[i].state != GDB_STATE_DISCONNECTED) { GDB_CloseClient(&server->ctxs[i]); + } } - svcCloseHandle(server->statusUpdated); - svcCloseHandle(server->statusUpdateReceived); -} - -void GDB_IncrementServerReferenceCount(GDBServer *server) -{ - AtomicPostIncrement(&server->referenceCount); -} - -void GDB_DecrementServerReferenceCount(GDBServer *server) -{ - if(AtomicDecrement(&server->referenceCount) == 0) - GDB_FinalizeServer(server); } void GDB_RunServer(GDBServer *server) { - server_bind(&server->super, GDB_PORT_BASE); - server_bind(&server->super, GDB_PORT_BASE + 1); - server_bind(&server->super, GDB_PORT_BASE + 2); - - server_bind(&server->super, GDB_PORT_BASE + 3); // next application - - server_run(&server->super); + // TODO transport iface + (void)server; } void GDB_LockAllContexts(GDBServer *server) { - for (u32 i = 0; i < MAX_DEBUG; i++) - RecursiveLock_Lock(&server->ctxs[i].lock); + for (u32 i = 0; i < MAX_CTX; i++) { + recursiveSpinlockLock(&server->ctxs[i].lock); + } } void GDB_UnlockAllContexts(GDBServer *server) { - for (u32 i = MAX_DEBUG; i > 0; i--) - RecursiveLock_Unlock(&server->ctxs[i - 1].lock); + for (u32 i = MAX_CTX; i > 0; i--) { + recursiveSpinlockUnlock(&server->ctxs[i - 1].lock); + } } -GDBContext *GDB_SelectAvailableContext(GDBServer *server, u16 minPort, u16 maxPort) +GDBContext *GDB_SelectAvailableContext(GDBServer *server) { GDBContext *ctx; - u16 port; GDB_LockAllContexts(server); // Get a context - u32 id; - for(id = 0; id < MAX_DEBUG && (server->ctxs[id].flags & GDB_FLAG_ALLOCATED_MASK); id++); - if(id < MAX_DEBUG) - ctx = &server->ctxs[id]; - else - { - GDB_UnlockAllContexts(server); - return NULL; - } + size_t id; + for (id = 0; id < MAX_CTX && (server->ctxs[id].flags & GDB_FLAG_ALLOCATED_MASK); id++); + ctx = id < MAX_CTX ? &server->ctxs[id] : NULL; - // Get a port - for (port = minPort; port < maxPort; port++) - { - bool portUsed = false; - for(id = 0; id < MAX_DEBUG; id++) - { - if((server->ctxs[id].flags & GDB_FLAG_ALLOCATED_MASK) && server->ctxs[id].localPort == port) - portUsed = true; - } - - if (!portUsed) - break; - } - - if (port >= maxPort) - { - ctx->flags = ~GDB_FLAG_SELECTED; - ctx = NULL; - } - else - { - ctx->flags |= GDB_FLAG_SELECTED; - ctx->localPort = port; - ctx->parent = server; - } - - GDB_UnlockAllContexts(server); - return ctx; -} - -GDBContext *GDB_FindAllocatedContextByPid(GDBServer *server, u32 pid) -{ - GDB_LockAllContexts(server); - GDBContext *ctx = NULL; - for(u32 i = 0; i < MAX_DEBUG; i++) - { - if( - ((server->ctxs[i].flags & GDB_FLAG_SELECTED) || - (server->ctxs[i].state >= GDB_STATE_ATTACHED && server->ctxs[i].state < GDB_STATE_DETACHING)) - && server->ctxs[i].pid == pid - ) - ctx = &server->ctxs[i]; - } GDB_UnlockAllContexts(server); return ctx; } int GDB_AcceptClient(GDBContext *ctx) { - Result r = 0; - - RecursiveLock_Lock(&ctx->lock); + recursiveSpinlockLock(&ctx->lock); ctx->state = GDB_STATE_CONNECTED; ctx->latestSentPacketSize = 0; - if (ctx->flags & GDB_FLAG_SELECTED) + /*if (ctx->flags & GDB_FLAG_SELECTED) r = GDB_AttachToProcess(ctx); + */ + recursiveSpinlockUnlock(&ctx->lock); - RecursiveLock_Unlock(&ctx->lock); - - return R_SUCCEEDED(r) ? 0 : -1; + return 0; } int GDB_CloseClient(GDBContext *ctx) { - RecursiveLock_Lock(&ctx->lock); - svcClearEvent(ctx->processAttachedEvent); - ctx->eventToWaitFor = ctx->processAttachedEvent; - svcClearEvent(ctx->parent->statusUpdateReceived); - svcSignalEvent(ctx->parent->statusUpdated); // note: monitor will be waiting for lock - RecursiveLock_Unlock(&ctx->lock); + // currently unused + recursiveSpinlockLock(&ctx->lock); - if(ctx->parent->referenceCount >= 2) - svcWaitSynchronization(ctx->parent->statusUpdateReceived, -1LL); - - RecursiveLock_Lock(&ctx->lock); - if (ctx->state >= GDB_STATE_ATTACHED || ctx->debug != 0) + if (ctx->state >= GDB_STATE_ATTACHED) { GDB_DetachFromProcess(ctx); + } - ctx->localPort = 0; - ctx->enableExternalMemoryAccess = false; ctx->flags = 0; ctx->state = GDB_STATE_DISCONNECTED; ctx->catchThreadEvents = false; - memset(&ctx->latestDebugEvent, 0, sizeof(DebugEventInfo)); - memset(ctx->memoryOsInfoXmlData, 0, sizeof(ctx->memoryOsInfoXmlData)); - memset(ctx->processesOsInfoXmlData, 0, sizeof(ctx->processesOsInfoXmlData)); + // memset(&ctx->latestDebugEvent, 0, sizeof(DebugEventInfo)); TODO - for (u32 i = 0; i < MAX_TIO_OPEN_FILE; i++) - IFile_Close(&ctx->openTioFileInfos[i].f); - memset(ctx->openTioFileInfos, 0, sizeof(ctx->openTioFileInfos)); - ctx->numOpenTioFiles = 0; - - RecursiveLock_Unlock(&ctx->lock); + recursiveSpinlockUnlock(&ctx->lock); return 0; } -GDBContext *GDB_GetClient(GDBServer *server, u16 port) -{ - GDB_LockAllContexts(server); - GDBContext *ctx = NULL; - for (u32 i = 0; i < MAX_DEBUG; i++) - { - if (server->ctxs[i].localPort == port) - { - ctx = &server->ctxs[i]; - break; - } - } - - if (ctx != NULL) - { - // Context already tied to a port/selected - if (ctx->flags & GDB_FLAG_USED) - { - GDB_UnlockAllContexts(server); - return NULL; - } - - ctx->flags |= GDB_FLAG_USED; - ctx->state = GDB_STATE_CONNECTED; - ctx->parent = server; - } - else if (port >= GDB_PORT_BASE && port < GDB_PORT_BASE + MAX_DEBUG) - { - // Grab a free context - u32 id; - for(id = 0; id < MAX_DEBUG && (server->ctxs[id].flags & GDB_FLAG_ALLOCATED_MASK); id++); - if(id < MAX_DEBUG) - ctx = &server->ctxs[id]; - else - { - GDB_UnlockAllContexts(server); - return NULL; - } - - ctx->localPort = port; - ctx->flags |= GDB_FLAG_USED; - ctx->state = GDB_STATE_CONNECTED; - ctx->parent = server; - } - - GDB_UnlockAllContexts(server); - if (port == GDB_PORT_BASE + MAX_DEBUG && ctx != NULL) - { - // this is not sufficient/foolproof and is buggy: TaskRunner_WaitReady(); // Finish grabbing new process debug, if anything... - bool ok = false; - do - { - svcSleepThread(5 * 1000 * 1000LL); - RecursiveLock_Lock(&ctx->lock); - ok = ctx->debug != 0; - RecursiveLock_Unlock(&ctx->lock); - } - while (!ok); - } - - return ctx; -} - void GDB_ReleaseClient(GDBServer *server, GDBContext *ctx) { + // same thing (void)server; (void)ctx; } @@ -315,8 +147,8 @@ static inline GDBCommandHandler GDB_GetCommandHandler(char command) { static const u32 nbHandlers = sizeof(gdbCommandHandlers) / sizeof(gdbCommandHandlers[0]); - u32 i; - for(i = 0; i < nbHandlers && gdbCommandHandlers[i].command != command; i++); + size_t i; + for (i = 0; i < nbHandlers && gdbCommandHandlers[i].command != command; i++); return i < nbHandlers ? gdbCommandHandlers[i].handler : GDB_HANDLER(Unsupported); } @@ -325,54 +157,47 @@ int GDB_DoPacket(GDBContext *ctx) { int ret; - RecursiveLock_Lock(&ctx->lock); + recursiveSpinlockLock(&ctx->lock); u32 oldFlags = ctx->flags; - if(ctx->state == GDB_STATE_DISCONNECTED) + if(ctx->state == GDB_STATE_DISCONNECTED) { return -1; + } int r = GDB_ReceivePacket(ctx); - if(r == 0) + if (r == 0) { ret = 0; - else if(r == -1) + } else if (r == -1) { ret = -1; - else if(ctx->buffer[0] == '\x03') - { + } else if (ctx->buffer[0] == '\x03') { GDB_HandleBreak(ctx); ret = 0; - } - else if(ctx->buffer[0] == '$') - { + } else if (ctx->buffer[0] == '$') { GDBCommandHandler handler = GDB_GetCommandHandler(ctx->buffer[1]); ctx->commandData = ctx->buffer + 2; ret = handler(ctx); - } - else + } else { ret = 0; + } - if(ctx->state == GDB_STATE_DETACHING) - { - if(ctx->flags & GDB_FLAG_EXTENDED_REMOTE) - { + if (ctx->state == GDB_STATE_DETACHING) { + if (ctx->flags & GDB_FLAG_EXTENDED_REMOTE) { ctx->state = GDB_STATE_CONNECTED; - RecursiveLock_Unlock(&ctx->lock); + recursiveSpinlockUnlock(&ctx->lock); return ret; - } - else - { - RecursiveLock_Unlock(&ctx->lock); + } else { + recursiveSpinlockUnlock(&ctx->lock); return -1; } } - if((oldFlags & GDB_FLAG_PROCESS_CONTINUING) && !(ctx->flags & GDB_FLAG_PROCESS_CONTINUING)) - { - if(R_FAILED(svcBreakDebugProcess(ctx->debug))) - ctx->flags |= GDB_FLAG_PROCESS_CONTINUING; + if ((oldFlags & GDB_FLAG_CONTINUING) && !(ctx->flags & GDB_FLAG_CONTINUING)) { + // TODO + } + else if (!(oldFlags & GDB_FLAG_CONTINUING) && (ctx->flags & GDB_FLAG_CONTINUING)) { + // TODO } - else if(!(oldFlags & GDB_FLAG_PROCESS_CONTINUING) && (ctx->flags & GDB_FLAG_PROCESS_CONTINUING)) - svcSignalEvent(ctx->continuedEvent); - RecursiveLock_Unlock(&ctx->lock); + recursiveSpinlockUnlock(&ctx->lock); return ret; } diff --git a/thermosphere/src/gdb/server.h b/thermosphere/src/gdb/server.h index 5e2354c75..ac28ef2d9 100644 --- a/thermosphere/src/gdb/server.h +++ b/thermosphere/src/gdb/server.h @@ -7,37 +7,28 @@ #pragma once -#include "gdb.h" +#include "../gdb.h" +#include "../transport_interface.h" -#ifndef GDB_PORT_BASE -#define GDB_PORT_BASE 4000 -#endif - -typedef struct GDBServer -{ - sock_server super; - s32 referenceCount; - Handle statusUpdated; - Handle statusUpdateReceived; - GDBContext ctxs[MAX_DEBUG]; +typedef struct GDBServer { + TransportInterface *transportIfaces[MAX_CTX]; + GDBContext ctxs[MAX_CTX]; } GDBServer; -Result GDB_InitializeServer(GDBServer *server); +void GDB_InitializeServer(GDBServer *server); void GDB_FinalizeServer(GDBServer *server); -void GDB_IncrementServerReferenceCount(GDBServer *server); -void GDB_DecrementServerReferenceCount(GDBServer *server); - void GDB_RunServer(GDBServer *server); void GDB_LockAllContexts(GDBServer *server); void GDB_UnlockAllContexts(GDBServer *server); -GDBContext *GDB_SelectAvailableContext(GDBServer *server, u16 minPort, u16 maxPort); -GDBContext *GDB_FindAllocatedContextByPid(GDBServer *server, u32 pid); +// Currently, transport ifaces are tied to client + +GDBContext *GDB_SelectAvailableContext(GDBServer *server); int GDB_AcceptClient(GDBContext *ctx); int GDB_CloseClient(GDBContext *ctx); -GDBContext *GDB_GetClient(GDBServer *server, u16 port); +GDBContext *GDB_GetClient(GDBServer *server, TransportInterface *iface); void GDB_ReleaseClient(GDBServer *server, GDBContext *ctx); int GDB_DoPacket(GDBContext *ctx); diff --git a/thermosphere/src/gdb/watchpoints.c b/thermosphere/src/gdb/watchpoints.c index 54762f6f6..e289332f7 100644 --- a/thermosphere/src/gdb/watchpoints.c +++ b/thermosphere/src/gdb/watchpoints.c @@ -44,7 +44,7 @@ void GDB_ResetWatchpoints(void) RecursiveLock_Init(&watchpointManagerLock); lockInitialized = true; } - RecursiveLock_Lock(&watchpointManagerLock); + recursiveSpinlockLock(&watchpointManagerLock); svcKernelSetState(0x10003); // enable monitor mode debugging svcKernelSetState(0x10004, 0); // disable watchpoint 0 @@ -52,12 +52,12 @@ void GDB_ResetWatchpoints(void) memset(&manager, 0, sizeof(WatchpointManager)); - RecursiveLock_Unlock(&watchpointManagerLock); + recursiveSpinlockUnlock(&watchpointManagerLock); } int GDB_AddWatchpoint(GDBContext *ctx, u32 address, u32 size, WatchpointKind kind) { - RecursiveLock_Lock(&watchpointManagerLock); + recursiveSpinlockLock(&watchpointManagerLock); u32 offset = address - (address & ~3); @@ -95,26 +95,26 @@ int GDB_AddWatchpoint(GDBContext *ctx, u32 address, u32 size, WatchpointKind kin watchpoint->kind = kind; watchpoint->debug = ctx->debug; ctx->watchpoints[ctx->nbWatchpoints++] = address; - RecursiveLock_Unlock(&watchpointManagerLock); + recursiveSpinlockUnlock(&watchpointManagerLock); return 0; } else { - RecursiveLock_Unlock(&watchpointManagerLock); + recursiveSpinlockUnlock(&watchpointManagerLock); return -EINVAL; } } int GDB_RemoveWatchpoint(GDBContext *ctx, u32 address, WatchpointKind kind) { - RecursiveLock_Lock(&watchpointManagerLock); + recursiveSpinlockLock(&watchpointManagerLock); u32 id; for(id = 0; id < 2 && manager.watchpoints[id].address != address && manager.watchpoints[id].debug != ctx->debug; id++); if(id == 2 || (kind != WATCHPOINT_DISABLED && manager.watchpoints[id].kind != kind)) { - RecursiveLock_Unlock(&watchpointManagerLock); + recursiveSpinlockUnlock(&watchpointManagerLock); return -EINVAL; } else @@ -136,7 +136,7 @@ int GDB_RemoveWatchpoint(GDBContext *ctx, u32 address, WatchpointKind kind) ctx->nbWatchpoints--; } - RecursiveLock_Unlock(&watchpointManagerLock); + recursiveSpinlockUnlock(&watchpointManagerLock); return 0; } diff --git a/thermosphere/src/utils.h b/thermosphere/src/utils.h index 7ea9f4bf0..f0a35a86c 100644 --- a/thermosphere/src/utils.h +++ b/thermosphere/src/utils.h @@ -20,6 +20,7 @@ #include "preprocessor.h" #include "debug_log.h" +#define MAX_CORE 4 #define BIT(n) (1u << (n)) #define BITL(n) (1ull << (n)) #define MASK(n) (BIT(n) - 1)