Refactor process detaching code
This commit is contained in:
parent
fb800bd4c9
commit
63736d7873
@ -72,7 +72,7 @@ typedef enum GDBState
|
|||||||
GDB_STATE_CONNECTED,
|
GDB_STATE_CONNECTED,
|
||||||
GDB_STATE_NOACK_SENT,
|
GDB_STATE_NOACK_SENT,
|
||||||
GDB_STATE_NOACK,
|
GDB_STATE_NOACK,
|
||||||
GDB_STATE_CLOSING
|
GDB_STATE_DETACHING
|
||||||
} GDBState;
|
} GDBState;
|
||||||
|
|
||||||
typedef struct ThreadInfo
|
typedef struct ThreadInfo
|
||||||
@ -81,9 +81,12 @@ typedef struct ThreadInfo
|
|||||||
u32 tls;
|
u32 tls;
|
||||||
} ThreadInfo;
|
} ThreadInfo;
|
||||||
|
|
||||||
|
struct GDBServer;
|
||||||
|
|
||||||
typedef struct GDBContext
|
typedef struct GDBContext
|
||||||
{
|
{
|
||||||
sock_ctx super;
|
sock_ctx super;
|
||||||
|
struct GDBServer *parent;
|
||||||
|
|
||||||
RecursiveLock lock;
|
RecursiveLock lock;
|
||||||
u16 localPort;
|
u16 localPort;
|
||||||
@ -98,7 +101,7 @@ typedef struct GDBContext
|
|||||||
u32 currentThreadId, selectedThreadId, selectedThreadIdForContinuing;
|
u32 currentThreadId, selectedThreadId, selectedThreadIdForContinuing;
|
||||||
u32 totalNbCreatedThreads;
|
u32 totalNbCreatedThreads;
|
||||||
|
|
||||||
Handle clientAcceptedEvent, continuedEvent;
|
Handle processAttachedEvent, continuedEvent;
|
||||||
Handle eventToWaitFor;
|
Handle eventToWaitFor;
|
||||||
|
|
||||||
bool catchThreadEvents;
|
bool catchThreadEvents;
|
||||||
@ -130,4 +133,8 @@ typedef int (*GDBCommandHandler)(GDBContext *ctx);
|
|||||||
|
|
||||||
void GDB_InitializeContext(GDBContext *ctx);
|
void GDB_InitializeContext(GDBContext *ctx);
|
||||||
void GDB_FinalizeContext(GDBContext *ctx);
|
void GDB_FinalizeContext(GDBContext *ctx);
|
||||||
|
|
||||||
|
Result GDB_AttachToProcess(GDBContext *ctx);
|
||||||
|
void GDB_DetachFromProcess(GDBContext *ctx);
|
||||||
|
|
||||||
GDB_DECLARE_HANDLER(Unsupported);
|
GDB_DECLARE_HANDLER(Unsupported);
|
||||||
|
@ -27,6 +27,12 @@
|
|||||||
#include "gdb.h"
|
#include "gdb.h"
|
||||||
#include "gdb/net.h"
|
#include "gdb/net.h"
|
||||||
|
|
||||||
|
#include "gdb/debug.h"
|
||||||
|
|
||||||
|
#include "gdb/watchpoints.h"
|
||||||
|
#include "gdb/breakpoints.h"
|
||||||
|
#include "gdb/stop_point.h"
|
||||||
|
|
||||||
void GDB_InitializeContext(GDBContext *ctx)
|
void GDB_InitializeContext(GDBContext *ctx)
|
||||||
{
|
{
|
||||||
memset(ctx, 0, sizeof(GDBContext));
|
memset(ctx, 0, sizeof(GDBContext));
|
||||||
@ -35,9 +41,9 @@ void GDB_InitializeContext(GDBContext *ctx)
|
|||||||
RecursiveLock_Lock(&ctx->lock);
|
RecursiveLock_Lock(&ctx->lock);
|
||||||
|
|
||||||
svcCreateEvent(&ctx->continuedEvent, RESET_ONESHOT);
|
svcCreateEvent(&ctx->continuedEvent, RESET_ONESHOT);
|
||||||
svcCreateEvent(&ctx->clientAcceptedEvent, RESET_STICKY);
|
svcCreateEvent(&ctx->processAttachedEvent, RESET_STICKY);
|
||||||
|
|
||||||
ctx->eventToWaitFor = ctx->clientAcceptedEvent;
|
ctx->eventToWaitFor = ctx->processAttachedEvent;
|
||||||
ctx->continueFlags = (DebugFlags)(DBG_SIGNAL_FAULT_EXCEPTION_EVENTS | DBG_INHIBIT_USER_CPU_EXCEPTION_HANDLERS);
|
ctx->continueFlags = (DebugFlags)(DBG_SIGNAL_FAULT_EXCEPTION_EVENTS | DBG_INHIBIT_USER_CPU_EXCEPTION_HANDLERS);
|
||||||
|
|
||||||
RecursiveLock_Unlock(&ctx->lock);
|
RecursiveLock_Unlock(&ctx->lock);
|
||||||
@ -47,14 +53,134 @@ void GDB_FinalizeContext(GDBContext *ctx)
|
|||||||
{
|
{
|
||||||
RecursiveLock_Lock(&ctx->lock);
|
RecursiveLock_Lock(&ctx->lock);
|
||||||
|
|
||||||
svcClearEvent(ctx->clientAcceptedEvent);
|
svcClearEvent(ctx->processAttachedEvent);
|
||||||
|
|
||||||
svcCloseHandle(ctx->clientAcceptedEvent);
|
svcCloseHandle(ctx->processAttachedEvent);
|
||||||
svcCloseHandle(ctx->continuedEvent);
|
svcCloseHandle(ctx->continuedEvent);
|
||||||
|
|
||||||
RecursiveLock_Unlock(&ctx->lock);
|
RecursiveLock_Unlock(&ctx->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result GDB_AttachToProcess(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))
|
||||||
|
svcDebugActiveProcess(&ctx->debug, ctx->pid);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
r = 0;
|
||||||
|
}
|
||||||
|
if(R_SUCCEEDED(r))
|
||||||
|
{
|
||||||
|
// Note: ctx->pid will be (re)set while processing 'attach process'
|
||||||
|
DebugEventInfo *info = &ctx->latestDebugEvent;
|
||||||
|
ctx->state = GDB_STATE_CONNECTED;
|
||||||
|
ctx->processExited = ctx->processEnded = false;
|
||||||
|
ctx->latestSentPacketSize = 0;
|
||||||
|
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;
|
||||||
|
|
||||||
|
return svcSignalEvent(ctx->processAttachedEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GDB_DetachFromProcess(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;
|
||||||
|
|
||||||
|
for(u32 i = 0; i < ctx->nbWatchpoints; i++)
|
||||||
|
{
|
||||||
|
GDB_RemoveWatchpoint(ctx, ctx->watchpoints[i], WATCHPOINT_DISABLED);
|
||||||
|
ctx->watchpoints[i] = 0;
|
||||||
|
}
|
||||||
|
ctx->nbWatchpoints = 0;
|
||||||
|
|
||||||
|
svcKernelSetState(0x10002, ctx->pid, false);
|
||||||
|
memset(ctx->svcMask, 0, 32);
|
||||||
|
|
||||||
|
memset(ctx->memoryOsInfoXmlData, 0, sizeof(ctx->memoryOsInfoXmlData));
|
||||||
|
memset(ctx->processesOsInfoXmlData, 0, sizeof(ctx->processesOsInfoXmlData));
|
||||||
|
memset(ctx->threadListData, 0, sizeof(ctx->threadListData));
|
||||||
|
ctx->threadListDataPos = 0;
|
||||||
|
|
||||||
|
svcClearEvent(ctx->processAttachedEvent);
|
||||||
|
ctx->eventToWaitFor = ctx->processAttachedEvent;
|
||||||
|
|
||||||
|
//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);
|
||||||
|
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;
|
||||||
|
|
||||||
|
|
||||||
|
ctx->eventToWaitFor = ctx->processAttachedEvent;
|
||||||
|
ctx->continueFlags = (DebugFlags)(DBG_SIGNAL_FAULT_EXCEPTION_EVENTS | DBG_INHIBIT_USER_CPU_EXCEPTION_HANDLERS);
|
||||||
|
ctx->pid = 0;
|
||||||
|
ctx->currentThreadId = ctx->selectedThreadId = ctx->selectedThreadIdForContinuing = 0;
|
||||||
|
ctx->nbThreads = 0;
|
||||||
|
ctx->totalNbCreatedThreads = 0;
|
||||||
|
memset(ctx->threadInfos, 0, sizeof(ctx->threadInfos));
|
||||||
|
ctx->catchThreadEvents = false;
|
||||||
|
}
|
||||||
|
|
||||||
GDB_DECLARE_HANDLER(Unsupported)
|
GDB_DECLARE_HANDLER(Unsupported)
|
||||||
{
|
{
|
||||||
return GDB_ReplyEmpty(ctx);
|
return GDB_ReplyEmpty(ctx);
|
||||||
|
@ -43,13 +43,13 @@
|
|||||||
|
|
||||||
GDB_DECLARE_HANDLER(Detach)
|
GDB_DECLARE_HANDLER(Detach)
|
||||||
{
|
{
|
||||||
ctx->state = GDB_STATE_CLOSING;
|
ctx->state = GDB_STATE_DETACHING;
|
||||||
return GDB_ReplyOk(ctx);
|
return GDB_ReplyOk(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
GDB_DECLARE_HANDLER(Kill)
|
GDB_DECLARE_HANDLER(Kill)
|
||||||
{
|
{
|
||||||
ctx->state = GDB_STATE_CLOSING;
|
ctx->state = GDB_STATE_DETACHING;
|
||||||
ctx->flags |= GDB_FLAG_TERMINATE_PROCESS;
|
ctx->flags |= GDB_FLAG_TERMINATE_PROCESS;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -480,7 +480,7 @@ int GDB_SendStopReply(GDBContext *ctx, const DebugEventInfo *info)
|
|||||||
*/
|
*/
|
||||||
int GDB_HandleDebugEvents(GDBContext *ctx)
|
int GDB_HandleDebugEvents(GDBContext *ctx)
|
||||||
{
|
{
|
||||||
if(ctx->state == GDB_STATE_CLOSING)
|
if(ctx->state == GDB_STATE_DETACHING)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
DebugEventInfo info;
|
DebugEventInfo info;
|
||||||
|
@ -42,11 +42,13 @@ void GDB_RunMonitor(GDBServer *server)
|
|||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
GDB_LockAllContexts(server);
|
||||||
for(int i = 0; i < MAX_DEBUG; i++)
|
for(int i = 0; i < MAX_DEBUG; i++)
|
||||||
{
|
{
|
||||||
GDBContext *ctx = &server->ctxs[i];
|
GDBContext *ctx = &server->ctxs[i];
|
||||||
handles[3 + i] = ctx->eventToWaitFor;
|
handles[3 + i] = ctx->eventToWaitFor;
|
||||||
}
|
}
|
||||||
|
GDB_UnlockAllContexts(server);
|
||||||
|
|
||||||
s32 idx = -1;
|
s32 idx = -1;
|
||||||
r = svcWaitSynchronizationN(&idx, handles, 3 + MAX_DEBUG, false, -1LL);
|
r = svcWaitSynchronizationN(&idx, handles, 3 + MAX_DEBUG, false, -1LL);
|
||||||
@ -60,15 +62,15 @@ void GDB_RunMonitor(GDBServer *server)
|
|||||||
GDBContext *ctx = &server->ctxs[idx - 3];
|
GDBContext *ctx = &server->ctxs[idx - 3];
|
||||||
|
|
||||||
RecursiveLock_Lock(&ctx->lock);
|
RecursiveLock_Lock(&ctx->lock);
|
||||||
if(ctx->state == GDB_STATE_DISCONNECTED || ctx->state == GDB_STATE_CLOSING)
|
if(ctx->state == GDB_STATE_DISCONNECTED || ctx->state == GDB_STATE_DETACHING)
|
||||||
{
|
{
|
||||||
svcClearEvent(ctx->clientAcceptedEvent);
|
svcClearEvent(ctx->processAttachedEvent);
|
||||||
ctx->eventToWaitFor = ctx->clientAcceptedEvent;
|
ctx->eventToWaitFor = ctx->processAttachedEvent;
|
||||||
RecursiveLock_Unlock(&ctx->lock);
|
RecursiveLock_Unlock(&ctx->lock);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ctx->eventToWaitFor == ctx->clientAcceptedEvent)
|
if(ctx->eventToWaitFor == ctx->processAttachedEvent)
|
||||||
ctx->eventToWaitFor = ctx->continuedEvent;
|
ctx->eventToWaitFor = ctx->continuedEvent;
|
||||||
else if(ctx->eventToWaitFor == ctx->continuedEvent)
|
else if(ctx->eventToWaitFor == ctx->continuedEvent)
|
||||||
ctx->eventToWaitFor = ctx->debug;
|
ctx->eventToWaitFor = ctx->debug;
|
||||||
@ -82,8 +84,8 @@ void GDB_RunMonitor(GDBServer *server)
|
|||||||
while(GDB_HandleDebugEvents(ctx) != -1) // until we've got all the remaining debug events
|
while(GDB_HandleDebugEvents(ctx) != -1) // until we've got all the remaining debug events
|
||||||
svcSleepThread(1 * 1000 * 1000LL); // sleep just in case
|
svcSleepThread(1 * 1000 * 1000LL); // sleep just in case
|
||||||
|
|
||||||
svcClearEvent(ctx->clientAcceptedEvent);
|
svcClearEvent(ctx->processAttachedEvent);
|
||||||
ctx->eventToWaitFor = ctx->clientAcceptedEvent;
|
ctx->eventToWaitFor = ctx->processAttachedEvent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,7 +291,7 @@ int GDB_SendStreamData(GDBContext *ctx, const char *streamData, u32 offset, u32
|
|||||||
|
|
||||||
int GDB_SendDebugString(GDBContext *ctx, const char *fmt, ...) // unsecure
|
int GDB_SendDebugString(GDBContext *ctx, const char *fmt, ...) // unsecure
|
||||||
{
|
{
|
||||||
if(ctx->state == GDB_STATE_CLOSING || !(ctx->flags & GDB_FLAG_PROCESS_CONTINUING))
|
if(ctx->state == GDB_STATE_DETACHING || !(ctx->flags & GDB_FLAG_PROCESS_CONTINUING))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
char formatted[(GDB_BUF_LEN - 1) / 2 + 1];
|
char formatted[(GDB_BUF_LEN - 1) / 2 + 1];
|
||||||
|
@ -154,98 +154,22 @@ GDBContext *GDB_SelectAvailableContext(GDBServer *server, u16 minPort, u16 maxPo
|
|||||||
|
|
||||||
int GDB_AcceptClient(GDBContext *ctx)
|
int GDB_AcceptClient(GDBContext *ctx)
|
||||||
{
|
{
|
||||||
RecursiveLock_Lock(&ctx->lock);
|
|
||||||
Result r;
|
Result r;
|
||||||
|
|
||||||
// Two cases: attached during execution, or started attached
|
RecursiveLock_Lock(&ctx->lock);
|
||||||
// The second case will have, after RunQueuedProcess: attach process, debugger break, attach thread (with creator = 0)
|
r = GDB_AttachToProcess(ctx);
|
||||||
|
|
||||||
if (!(ctx->flags & GDB_FLAG_ATTACHED_AT_START))
|
|
||||||
svcDebugActiveProcess(&ctx->debug, ctx->pid);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
r = 0;
|
|
||||||
}
|
|
||||||
if(R_SUCCEEDED(r))
|
|
||||||
{
|
|
||||||
// Note: ctx->pid will be (re)set while processing 'attach process'
|
|
||||||
DebugEventInfo *info = &ctx->latestDebugEvent;
|
|
||||||
ctx->state = GDB_STATE_CONNECTED;
|
|
||||||
ctx->processExited = ctx->processEnded = false;
|
|
||||||
ctx->latestSentPacketSize = 0;
|
|
||||||
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(svcGetProcessDebugEvent(info, ctx->debug)))
|
|
||||||
return -1;
|
|
||||||
GDB_PreprocessDebugEvent(ctx, info);
|
|
||||||
if (R_FAILED(svcContinueDebugEvent(ctx->debug, ctx->continueFlags)))
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
svcWaitSynchronization(ctx->debug, -1LL);
|
|
||||||
if (R_FAILED(svcGetProcessDebugEvent(info, ctx->debug)))
|
|
||||||
return -1; //svcBreak(0);
|
|
||||||
// Attach thread
|
|
||||||
GDB_PreprocessDebugEvent(ctx, info);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
RecursiveLock_Unlock(&ctx->lock);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
svcSignalEvent(ctx->clientAcceptedEvent);
|
|
||||||
RecursiveLock_Unlock(&ctx->lock);
|
RecursiveLock_Unlock(&ctx->lock);
|
||||||
|
|
||||||
return 0;
|
return R_SUCCEEDED(r) ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GDB_CloseClient(GDBContext *ctx)
|
int GDB_CloseClient(GDBContext *ctx)
|
||||||
{
|
{
|
||||||
RecursiveLock_Lock(&ctx->lock);
|
RecursiveLock_Lock(&ctx->lock);
|
||||||
|
svcSignalEvent(ctx->parent->statusUpdated); // note: monitor will be waiting for lock
|
||||||
for(u32 i = 0; i < ctx->nbBreakpoints; i++)
|
GDB_DetachFromProcess(ctx);
|
||||||
{
|
|
||||||
if(!ctx->breakpoints[i].persistent)
|
|
||||||
GDB_DisableBreakpointById(ctx, i);
|
|
||||||
}
|
|
||||||
memset(&ctx->breakpoints, 0, sizeof(ctx->breakpoints));
|
|
||||||
ctx->nbBreakpoints = 0;
|
|
||||||
|
|
||||||
for(u32 i = 0; i < ctx->nbWatchpoints; i++)
|
|
||||||
{
|
|
||||||
GDB_RemoveWatchpoint(ctx, ctx->watchpoints[i], WATCHPOINT_DISABLED);
|
|
||||||
ctx->watchpoints[i] = 0;
|
|
||||||
}
|
|
||||||
ctx->nbWatchpoints = 0;
|
|
||||||
|
|
||||||
svcKernelSetState(0x10002, ctx->pid, false);
|
|
||||||
memset(ctx->svcMask, 0, 32);
|
|
||||||
|
|
||||||
memset(ctx->memoryOsInfoXmlData, 0, sizeof(ctx->memoryOsInfoXmlData));
|
|
||||||
memset(ctx->processesOsInfoXmlData, 0, sizeof(ctx->processesOsInfoXmlData));
|
|
||||||
memset(ctx->threadListData, 0, sizeof(ctx->threadListData));
|
|
||||||
ctx->threadListDataPos = 0;
|
|
||||||
|
|
||||||
svcClearEvent(ctx->clientAcceptedEvent);
|
|
||||||
ctx->eventToWaitFor = ctx->clientAcceptedEvent;
|
|
||||||
|
|
||||||
ctx->localPort = 0;
|
|
||||||
RecursiveLock_Unlock(&ctx->lock);
|
RecursiveLock_Unlock(&ctx->lock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -266,6 +190,7 @@ GDBContext *GDB_GetClient(GDBServer *server, u16 port)
|
|||||||
{
|
{
|
||||||
ctx->flags |= GDB_FLAG_USED;
|
ctx->flags |= GDB_FLAG_USED;
|
||||||
ctx->state = GDB_STATE_CONNECTED;
|
ctx->state = GDB_STATE_CONNECTED;
|
||||||
|
ctx->parent = server;
|
||||||
}
|
}
|
||||||
|
|
||||||
GDB_UnlockAllContexts(server);
|
GDB_UnlockAllContexts(server);
|
||||||
@ -274,46 +199,12 @@ GDBContext *GDB_GetClient(GDBServer *server, u16 port)
|
|||||||
|
|
||||||
void GDB_ReleaseClient(GDBServer *server, GDBContext *ctx)
|
void GDB_ReleaseClient(GDBServer *server, GDBContext *ctx)
|
||||||
{
|
{
|
||||||
DebugEventInfo dummy;
|
(void)server;
|
||||||
|
|
||||||
svcSignalEvent(server->statusUpdated);
|
|
||||||
|
|
||||||
RecursiveLock_Lock(&ctx->lock);
|
RecursiveLock_Lock(&ctx->lock);
|
||||||
|
ctx->localPort = 0;
|
||||||
/*
|
ctx->enableExternalMemoryAccess = false;
|
||||||
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);
|
|
||||||
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;
|
|
||||||
|
|
||||||
ctx->flags = (GDBFlags)0;
|
ctx->flags = (GDBFlags)0;
|
||||||
ctx->state = GDB_STATE_DISCONNECTED;
|
ctx->state = GDB_STATE_DISCONNECTED;
|
||||||
|
|
||||||
ctx->eventToWaitFor = ctx->clientAcceptedEvent;
|
|
||||||
ctx->continueFlags = (DebugFlags)(DBG_SIGNAL_FAULT_EXCEPTION_EVENTS | DBG_INHIBIT_USER_CPU_EXCEPTION_HANDLERS);
|
|
||||||
ctx->pid = 0;
|
|
||||||
ctx->currentThreadId = ctx->selectedThreadId = ctx->selectedThreadIdForContinuing = 0;
|
|
||||||
ctx->nbThreads = 0;
|
|
||||||
ctx->totalNbCreatedThreads = 0;
|
|
||||||
memset(ctx->threadInfos, 0, sizeof(ctx->threadInfos));
|
|
||||||
ctx->catchThreadEvents = false;
|
|
||||||
ctx->enableExternalMemoryAccess = false;
|
|
||||||
RecursiveLock_Unlock(&ctx->lock);
|
RecursiveLock_Unlock(&ctx->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -384,7 +275,7 @@ int GDB_DoPacket(GDBContext *ctx)
|
|||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
RecursiveLock_Unlock(&ctx->lock);
|
RecursiveLock_Unlock(&ctx->lock);
|
||||||
if(ctx->state == GDB_STATE_CLOSING)
|
if(ctx->state == GDB_STATE_DETACHING)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if((oldFlags & GDB_FLAG_PROCESS_CONTINUING) && !(ctx->flags & GDB_FLAG_PROCESS_CONTINUING))
|
if((oldFlags & GDB_FLAG_PROCESS_CONTINUING) && !(ctx->flags & GDB_FLAG_PROCESS_CONTINUING))
|
||||||
|
@ -71,7 +71,7 @@ static inline int ProcessListMenu_FormatInfoLine(char *out, const ProcessInfo *i
|
|||||||
|
|
||||||
else if(gdbServer.super.running && id < MAX_DEBUG)
|
else if(gdbServer.super.running && id < MAX_DEBUG)
|
||||||
{
|
{
|
||||||
if(gdbServer.ctxs[id].state >= GDB_STATE_CONNECTED && gdbServer.ctxs[id].state < GDB_STATE_CLOSING)
|
if(gdbServer.ctxs[id].state >= GDB_STATE_CONNECTED && gdbServer.ctxs[id].state < GDB_STATE_DETACHING)
|
||||||
{
|
{
|
||||||
u8 *addr = (u8 *)&gdbServer.ctxs[id].super.addr_in.sin_addr;
|
u8 *addr = (u8 *)&gdbServer.ctxs[id].super.addr_in.sin_addr;
|
||||||
checkbox = "(A) ";
|
checkbox = "(A) ";
|
||||||
|
Reference in New Issue
Block a user