gdb: add support to run new processes
Only titleId [mediaType [launchFlags]] is supported, and the launched title shouldn't rely on APT and all 3 parameters should be hex-encoded. usage example, with titleId+mediaType: (gdb) set remote file-exec 0004013000003702 (gdb) r 0
This commit is contained in:
parent
763a1de8d3
commit
e11cc090b2
@ -30,6 +30,7 @@
|
|||||||
#include <3ds/svc.h>
|
#include <3ds/svc.h>
|
||||||
#include <3ds/synchronization.h>
|
#include <3ds/synchronization.h>
|
||||||
#include <3ds/result.h>
|
#include <3ds/result.h>
|
||||||
|
#include "pmdbgext.h"
|
||||||
#include "sock_util.h"
|
#include "sock_util.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
|
||||||
@ -64,17 +65,19 @@ enum
|
|||||||
GDB_FLAG_ALLOCATED_MASK = GDB_FLAG_SELECTED | GDB_FLAG_USED,
|
GDB_FLAG_ALLOCATED_MASK = GDB_FLAG_SELECTED | GDB_FLAG_USED,
|
||||||
GDB_FLAG_EXTENDED_REMOTE = 4,
|
GDB_FLAG_EXTENDED_REMOTE = 4,
|
||||||
GDB_FLAG_NOACK = 8,
|
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_PROCESS_CONTINUING = 16,
|
||||||
GDB_FLAG_TERMINATE_PROCESS = 32,
|
GDB_FLAG_TERMINATE_PROCESS = 32,
|
||||||
GDB_FLAG_ATTACHED_AT_START = 64,
|
GDB_FLAG_ATTACHED_AT_START = 64,
|
||||||
|
GDB_FLAG_CREATED = 128,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum GDBState
|
typedef enum GDBState
|
||||||
{
|
{
|
||||||
GDB_STATE_DISCONNECTED,
|
GDB_STATE_DISCONNECTED,
|
||||||
GDB_STATE_CONNECTED,
|
GDB_STATE_CONNECTED,
|
||||||
GDB_STATE_NOACK_SENT,
|
GDB_STATE_ATTACHED,
|
||||||
GDB_STATE_DETACHING
|
GDB_STATE_DETACHING,
|
||||||
} GDBState;
|
} GDBState;
|
||||||
|
|
||||||
typedef struct ThreadInfo
|
typedef struct ThreadInfo
|
||||||
@ -95,9 +98,15 @@ typedef struct GDBContext
|
|||||||
|
|
||||||
u32 flags;
|
u32 flags;
|
||||||
GDBState state;
|
GDBState state;
|
||||||
|
bool noAckSent;
|
||||||
|
|
||||||
u32 pid;
|
u32 pid;
|
||||||
Handle debug;
|
Handle debug;
|
||||||
|
|
||||||
|
// vRun and R (restart) info:
|
||||||
|
FS_ProgramInfo launchedProgramInfo;
|
||||||
|
u32 launchedProgramLaunchFlags;
|
||||||
|
|
||||||
ThreadInfo threadInfos[MAX_DEBUG_THREAD];
|
ThreadInfo threadInfos[MAX_DEBUG_THREAD];
|
||||||
u32 nbThreads;
|
u32 nbThreads;
|
||||||
u32 currentThreadId, selectedThreadId, selectedThreadIdForContinuing;
|
u32 currentThreadId, selectedThreadId, selectedThreadIdForContinuing;
|
||||||
@ -138,6 +147,7 @@ void GDB_FinalizeContext(GDBContext *ctx);
|
|||||||
|
|
||||||
Result GDB_AttachToProcess(GDBContext *ctx);
|
Result GDB_AttachToProcess(GDBContext *ctx);
|
||||||
void GDB_DetachFromProcess(GDBContext *ctx);
|
void GDB_DetachFromProcess(GDBContext *ctx);
|
||||||
|
Result GDB_CreateProcess(GDBContext *ctx, const FS_ProgramInfo *progInfo, u32 launchFlags);
|
||||||
|
|
||||||
GDB_DECLARE_HANDLER(Unsupported);
|
GDB_DECLARE_HANDLER(Unsupported);
|
||||||
GDB_DECLARE_HANDLER(EnableExtendedMode);
|
GDB_DECLARE_HANDLER(EnableExtendedMode);
|
||||||
|
@ -28,6 +28,8 @@
|
|||||||
|
|
||||||
#include "gdb.h"
|
#include "gdb.h"
|
||||||
|
|
||||||
|
GDB_DECLARE_VERBOSE_HANDLER(Run);
|
||||||
|
GDB_DECLARE_HANDLER(Restart);
|
||||||
GDB_DECLARE_VERBOSE_HANDLER(Attach);
|
GDB_DECLARE_VERBOSE_HANDLER(Attach);
|
||||||
GDB_DECLARE_HANDLER(Detach);
|
GDB_DECLARE_HANDLER(Detach);
|
||||||
GDB_DECLARE_HANDLER(Kill);
|
GDB_DECLARE_HANDLER(Kill);
|
||||||
|
@ -36,6 +36,8 @@ u32 GDB_DecodeHex(void *dst, const char *src, u32 len);
|
|||||||
u32 GDB_UnescapeBinaryData(void *dst, const void *src, u32 len);
|
u32 GDB_UnescapeBinaryData(void *dst, const void *src, u32 len);
|
||||||
const char *GDB_ParseIntegerList(u32 *dst, const char *src, u32 nb, char sep, char lastSep, u32 base, bool allowPrefix);
|
const char *GDB_ParseIntegerList(u32 *dst, const char *src, u32 nb, char sep, char lastSep, u32 base, bool allowPrefix);
|
||||||
const char *GDB_ParseHexIntegerList(u32 *dst, const char *src, u32 nb, char lastSep);
|
const char *GDB_ParseHexIntegerList(u32 *dst, const char *src, u32 nb, char lastSep);
|
||||||
|
const char *GDB_ParseIntegerList64(u64 *dst, const char *src, u32 nb, char sep, char lastSep, u32 base, bool allowPrefix);
|
||||||
|
const char *GDB_ParseHexIntegerList64(u64 *dst, const char *src, u32 nb, char lastSep);
|
||||||
int GDB_ReceivePacket(GDBContext *ctx);
|
int GDB_ReceivePacket(GDBContext *ctx);
|
||||||
int GDB_SendPacket(GDBContext *ctx, const char *packetData, u32 len);
|
int GDB_SendPacket(GDBContext *ctx, const char *packetData, u32 len);
|
||||||
int GDB_SendFormattedPacket(GDBContext *ctx, const char *packetDataFmt, ...);
|
int GDB_SendFormattedPacket(GDBContext *ctx, const char *packetDataFmt, ...);
|
||||||
|
@ -32,3 +32,4 @@
|
|||||||
u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize);
|
u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize);
|
||||||
void hexItoa(u64 number, char *out, u32 digits, bool uppercase);
|
void hexItoa(u64 number, char *out, u32 digits, bool uppercase);
|
||||||
unsigned long int xstrtoul(const char *nptr, char **endptr, int base, bool allowPrefix, bool *ok);
|
unsigned long int xstrtoul(const char *nptr, char **endptr, int base, bool allowPrefix, bool *ok);
|
||||||
|
unsigned long long int xstrtoull(const char *nptr, char **endptr, int base, bool allowPrefix, bool *ok);
|
||||||
|
@ -79,9 +79,7 @@ Result GDB_AttachToProcess(GDBContext *ctx)
|
|||||||
{
|
{
|
||||||
// Note: ctx->pid will be (re)set while processing 'attach process'
|
// Note: ctx->pid will be (re)set while processing 'attach process'
|
||||||
DebugEventInfo *info = &ctx->latestDebugEvent;
|
DebugEventInfo *info = &ctx->latestDebugEvent;
|
||||||
ctx->state = GDB_STATE_CONNECTED;
|
|
||||||
ctx->processExited = ctx->processEnded = false;
|
ctx->processExited = ctx->processEnded = false;
|
||||||
ctx->latestSentPacketSize = 0;
|
|
||||||
if (!(ctx->flags & GDB_FLAG_ATTACHED_AT_START))
|
if (!(ctx->flags & GDB_FLAG_ATTACHED_AT_START))
|
||||||
{
|
{
|
||||||
while(R_SUCCEEDED(svcGetProcessDebugEvent(info, ctx->debug)) &&
|
while(R_SUCCEEDED(svcGetProcessDebugEvent(info, ctx->debug)) &&
|
||||||
@ -115,7 +113,10 @@ Result GDB_AttachToProcess(GDBContext *ctx)
|
|||||||
else
|
else
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
return svcSignalEvent(ctx->processAttachedEvent);
|
r = svcSignalEvent(ctx->processAttachedEvent);
|
||||||
|
if (R_SUCCEEDED(r))
|
||||||
|
ctx->state = GDB_STATE_ATTACHED;
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GDB_DetachFromProcess(GDBContext *ctx)
|
void GDB_DetachFromProcess(GDBContext *ctx)
|
||||||
@ -168,7 +169,8 @@ void GDB_DetachFromProcess(GDBContext *ctx)
|
|||||||
|
|
||||||
svcCloseHandle(ctx->debug);
|
svcCloseHandle(ctx->debug);
|
||||||
ctx->debug = 0;
|
ctx->debug = 0;
|
||||||
|
memset(&ctx->launchedProgramInfo, 0, sizeof(FS_ProgramInfo));
|
||||||
|
ctx->launchedProgramLaunchFlags = 0;
|
||||||
|
|
||||||
ctx->eventToWaitFor = ctx->processAttachedEvent;
|
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);
|
||||||
@ -177,6 +179,24 @@ void GDB_DetachFromProcess(GDBContext *ctx)
|
|||||||
ctx->nbThreads = 0;
|
ctx->nbThreads = 0;
|
||||||
ctx->totalNbCreatedThreads = 0;
|
ctx->totalNbCreatedThreads = 0;
|
||||||
memset(ctx->threadInfos, 0, sizeof(ctx->threadInfos));
|
memset(ctx->threadInfos, 0, sizeof(ctx->threadInfos));
|
||||||
|
|
||||||
|
ctx->state = GDB_STATE_CONNECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
GDB_DECLARE_HANDLER(Unsupported)
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
* reasonable ways as different from the original version.
|
* reasonable ways as different from the original version.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define _GNU_SOURCE // for strchrnul
|
||||||
#include "gdb/debug.h"
|
#include "gdb/debug.h"
|
||||||
#include "gdb/server.h"
|
#include "gdb/server.h"
|
||||||
#include "gdb/verbose.h"
|
#include "gdb/verbose.h"
|
||||||
@ -35,6 +36,105 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include "pmdbgext.h"
|
||||||
|
|
||||||
|
static void GDB_DetachImmediatelyExtended(GDBContext *ctx)
|
||||||
|
{
|
||||||
|
// detach immediately
|
||||||
|
RecursiveLock_Lock(&ctx->lock);
|
||||||
|
svcSignalEvent(ctx->parent->statusUpdated); // note: monitor will be waiting for lock
|
||||||
|
|
||||||
|
ctx->state = GDB_STATE_DETACHING;
|
||||||
|
GDB_DetachFromProcess(ctx);
|
||||||
|
ctx->flags &= GDB_FLAG_PROC_RESTART_MASK;
|
||||||
|
RecursiveLock_Unlock(&ctx->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
GDB_DECLARE_VERBOSE_HANDLER(Run)
|
||||||
|
{
|
||||||
|
// Note: only titleId [mediaType [launchFlags]] is supported, and the launched title shouldn't rely on APT
|
||||||
|
// all 3 parameters should be hex-encoded.
|
||||||
|
|
||||||
|
// Extended remote only
|
||||||
|
if (!(ctx->flags & GDB_FLAG_EXTENDED_REMOTE))
|
||||||
|
return GDB_ReplyErrno(ctx, EPERM);
|
||||||
|
|
||||||
|
u64 titleId;
|
||||||
|
u32 mediaType = MEDIATYPE_NAND;
|
||||||
|
u32 launchFlags = PMLAUNCHFLAG_LOAD_DEPENDENCIES;
|
||||||
|
|
||||||
|
char args[3][32] = {{0}};
|
||||||
|
char *pos = ctx->commandData;
|
||||||
|
for (u32 i = 0; i < 3 && *pos != 0; i++)
|
||||||
|
{
|
||||||
|
char *pos2 = strchrnul(pos, ';');
|
||||||
|
u32 dist = pos2 - pos;
|
||||||
|
if (dist < 2)
|
||||||
|
return GDB_ReplyErrno(ctx, EILSEQ);
|
||||||
|
if (dist % 2 == 1)
|
||||||
|
return GDB_ReplyErrno(ctx, EILSEQ);
|
||||||
|
|
||||||
|
if (dist / 2 > 16) // buffer overflow check
|
||||||
|
return GDB_ReplyErrno(ctx, EINVAL);
|
||||||
|
|
||||||
|
u32 n = GDB_DecodeHex(args[i], pos, dist / 2);
|
||||||
|
if (n == 0)
|
||||||
|
return GDB_ReplyErrno(ctx, EILSEQ);
|
||||||
|
pos = *pos2 == 0 ? pos2 : pos2 + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args[0][0] == 0)
|
||||||
|
return GDB_ReplyErrno(ctx, EINVAL); // first arg mandatory
|
||||||
|
|
||||||
|
if (GDB_ParseIntegerList64(&titleId, args[0], 1, 0, 0, 16, false) == NULL)
|
||||||
|
return GDB_ReplyErrno(ctx, EINVAL);
|
||||||
|
|
||||||
|
if (args[1][0] != 0 && (GDB_ParseIntegerList(&mediaType, args[1], 1, 0, 0, 16, true) == NULL || mediaType >= 0x100))
|
||||||
|
return GDB_ReplyErrno(ctx, EINVAL);
|
||||||
|
|
||||||
|
if (args[2][0] != 0 && GDB_ParseIntegerList(&launchFlags, args[2], 1, 0, 0, 16, true) == NULL)
|
||||||
|
return GDB_ReplyErrno(ctx, EINVAL);
|
||||||
|
|
||||||
|
FS_ProgramInfo progInfo;
|
||||||
|
progInfo.mediaType = (FS_MediaType)mediaType;
|
||||||
|
progInfo.programId = titleId;
|
||||||
|
|
||||||
|
RecursiveLock_Lock(&ctx->lock);
|
||||||
|
Result r = GDB_CreateProcess(ctx, &progInfo, launchFlags);
|
||||||
|
|
||||||
|
if (R_FAILED(r))
|
||||||
|
{
|
||||||
|
if(ctx->debug != 0)
|
||||||
|
GDB_DetachImmediatelyExtended(ctx);
|
||||||
|
RecursiveLock_Unlock(&ctx->lock);
|
||||||
|
return GDB_ReplyErrno(ctx, EPERM);
|
||||||
|
}
|
||||||
|
|
||||||
|
RecursiveLock_Unlock(&ctx->lock);
|
||||||
|
return R_SUCCEEDED(r) ? GDB_SendStopReply(ctx, &ctx->latestDebugEvent) : GDB_ReplyErrno(ctx, EPERM);
|
||||||
|
}
|
||||||
|
|
||||||
|
GDB_DECLARE_HANDLER(Restart)
|
||||||
|
{
|
||||||
|
// Note: removed from gdb
|
||||||
|
// Extended remote only & process must have been created
|
||||||
|
if (!(ctx->flags & GDB_FLAG_EXTENDED_REMOTE) || !(ctx->flags & GDB_FLAG_CREATED))
|
||||||
|
return GDB_ReplyErrno(ctx, EPERM);
|
||||||
|
|
||||||
|
FS_ProgramInfo progInfo = ctx->launchedProgramInfo;
|
||||||
|
u32 launchFlags = ctx->launchedProgramLaunchFlags;
|
||||||
|
|
||||||
|
ctx->flags |= GDB_FLAG_TERMINATE_PROCESS;
|
||||||
|
if (ctx->flags & GDB_FLAG_EXTENDED_REMOTE)
|
||||||
|
GDB_DetachImmediatelyExtended(ctx);
|
||||||
|
|
||||||
|
RecursiveLock_Lock(&ctx->lock);
|
||||||
|
Result r = GDB_CreateProcess(ctx, &progInfo, launchFlags);
|
||||||
|
if (R_FAILED(r) && ctx->debug != 0)
|
||||||
|
GDB_DetachImmediatelyExtended(ctx);
|
||||||
|
RecursiveLock_Unlock(&ctx->lock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
GDB_DECLARE_VERBOSE_HANDLER(Attach)
|
GDB_DECLARE_VERBOSE_HANDLER(Attach)
|
||||||
{
|
{
|
||||||
@ -49,6 +149,8 @@ GDB_DECLARE_VERBOSE_HANDLER(Attach)
|
|||||||
RecursiveLock_Lock(&ctx->lock);
|
RecursiveLock_Lock(&ctx->lock);
|
||||||
ctx->pid = pid;
|
ctx->pid = pid;
|
||||||
Result r = GDB_AttachToProcess(ctx);
|
Result r = GDB_AttachToProcess(ctx);
|
||||||
|
if(R_FAILED(r))
|
||||||
|
GDB_DetachImmediatelyExtended(ctx);
|
||||||
RecursiveLock_Unlock(&ctx->lock);
|
RecursiveLock_Unlock(&ctx->lock);
|
||||||
return R_SUCCEEDED(r) ? GDB_SendStopReply(ctx, &ctx->latestDebugEvent) : GDB_ReplyErrno(ctx, EPERM);
|
return R_SUCCEEDED(r) ? GDB_SendStopReply(ctx, &ctx->latestDebugEvent) : GDB_ReplyErrno(ctx, EPERM);
|
||||||
}
|
}
|
||||||
@ -63,14 +165,7 @@ GDB_DECLARE_HANDLER(Detach)
|
|||||||
{
|
{
|
||||||
ctx->state = GDB_STATE_DETACHING;
|
ctx->state = GDB_STATE_DETACHING;
|
||||||
if (ctx->flags & GDB_FLAG_EXTENDED_REMOTE)
|
if (ctx->flags & GDB_FLAG_EXTENDED_REMOTE)
|
||||||
{
|
GDB_DetachImmediatelyExtended(ctx);
|
||||||
// detach immediately
|
|
||||||
RecursiveLock_Lock(&ctx->lock);
|
|
||||||
svcSignalEvent(ctx->parent->statusUpdated); // note: monitor will be waiting for lock
|
|
||||||
GDB_DetachFromProcess(ctx);
|
|
||||||
ctx->flags = GDB_FLAG_USED;
|
|
||||||
RecursiveLock_Unlock(&ctx->lock);
|
|
||||||
}
|
|
||||||
return GDB_ReplyOk(ctx);
|
return GDB_ReplyOk(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,13 +174,8 @@ GDB_DECLARE_HANDLER(Kill)
|
|||||||
ctx->state = GDB_STATE_DETACHING;
|
ctx->state = GDB_STATE_DETACHING;
|
||||||
ctx->flags |= GDB_FLAG_TERMINATE_PROCESS;
|
ctx->flags |= GDB_FLAG_TERMINATE_PROCESS;
|
||||||
if (ctx->flags & GDB_FLAG_EXTENDED_REMOTE)
|
if (ctx->flags & GDB_FLAG_EXTENDED_REMOTE)
|
||||||
{
|
GDB_DetachImmediatelyExtended(ctx);
|
||||||
// detach & kill immediately
|
|
||||||
RecursiveLock_Lock(&ctx->lock);
|
|
||||||
svcSignalEvent(ctx->parent->statusUpdated); // note: monitor will be waiting for lock
|
|
||||||
GDB_DetachFromProcess(ctx);
|
|
||||||
RecursiveLock_Unlock(&ctx->lock);
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,11 +125,47 @@ const char *GDB_ParseIntegerList(u32 *dst, const char *src, u32 nb, char sep, ch
|
|||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *GDB_ParseIntegerList64(u64 *dst, const char *src, u32 nb, char sep, char lastSep, u32 base, bool allowPrefix)
|
||||||
|
{
|
||||||
|
const char *pos = src;
|
||||||
|
const char *endpos;
|
||||||
|
bool ok;
|
||||||
|
|
||||||
|
for(u32 i = 0; i < nb; i++)
|
||||||
|
{
|
||||||
|
u64 n = xstrtoull(pos, (char **)&endpos, (int) base, allowPrefix, &ok);
|
||||||
|
if(!ok || endpos == pos)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if(i != nb - 1)
|
||||||
|
{
|
||||||
|
if(*endpos != sep)
|
||||||
|
return NULL;
|
||||||
|
pos = endpos + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(*endpos != lastSep && *endpos != 0)
|
||||||
|
return NULL;
|
||||||
|
pos = endpos;
|
||||||
|
}
|
||||||
|
|
||||||
|
dst[i] = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
const char *GDB_ParseHexIntegerList(u32 *dst, const char *src, u32 nb, char lastSep)
|
const char *GDB_ParseHexIntegerList(u32 *dst, const char *src, u32 nb, char lastSep)
|
||||||
{
|
{
|
||||||
return GDB_ParseIntegerList(dst, src, nb, ',', lastSep, 16, false);
|
return GDB_ParseIntegerList(dst, src, nb, ',', lastSep, 16, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *GDB_ParseHexIntegerList64(u64 *dst, const char *src, u32 nb, char lastSep)
|
||||||
|
{
|
||||||
|
return GDB_ParseIntegerList64(dst, src, nb, ',', lastSep, 16, false);
|
||||||
|
}
|
||||||
|
|
||||||
int GDB_ReceivePacket(GDBContext *ctx)
|
int GDB_ReceivePacket(GDBContext *ctx)
|
||||||
{
|
{
|
||||||
char backupbuf[GDB_BUF_LEN + 4];
|
char backupbuf[GDB_BUF_LEN + 4];
|
||||||
@ -200,8 +236,11 @@ int GDB_ReceivePacket(GDBContext *ctx)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ctx->state == GDB_STATE_NOACK_SENT)
|
if(ctx->noAckSent)
|
||||||
|
{
|
||||||
ctx->flags |= GDB_FLAG_NOACK;
|
ctx->flags |= GDB_FLAG_NOACK;
|
||||||
|
ctx->noAckSent = false;
|
||||||
|
}
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -120,13 +120,13 @@ GDB_DECLARE_QUERY_HANDLER(Supported)
|
|||||||
|
|
||||||
GDB_DECLARE_QUERY_HANDLER(StartNoAckMode)
|
GDB_DECLARE_QUERY_HANDLER(StartNoAckMode)
|
||||||
{
|
{
|
||||||
ctx->state = GDB_STATE_NOACK_SENT;
|
ctx->noAckSent = true;
|
||||||
return GDB_ReplyOk(ctx);
|
return GDB_ReplyOk(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
GDB_DECLARE_QUERY_HANDLER(Attached)
|
GDB_DECLARE_QUERY_HANDLER(Attached)
|
||||||
{
|
{
|
||||||
return GDB_SendPacket(ctx, "1", 1);
|
return GDB_SendPacket(ctx, (ctx->flags & GDB_FLAG_CREATED) ? "0" : "1", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
GDB_DECLARE_QUERY_HANDLER(CatchSyscalls)
|
GDB_DECLARE_QUERY_HANDLER(CatchSyscalls)
|
||||||
|
@ -158,7 +158,11 @@ GDBContext *GDB_FindAllocatedContextByPid(GDBServer *server, u32 pid)
|
|||||||
GDBContext *ctx = NULL;
|
GDBContext *ctx = NULL;
|
||||||
for(u32 i = 0; i < MAX_DEBUG; i++)
|
for(u32 i = 0; i < MAX_DEBUG; i++)
|
||||||
{
|
{
|
||||||
if((server->ctxs[i].flags & GDB_FLAG_ALLOCATED_MASK) && server->ctxs[i].pid == pid)
|
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];
|
ctx = &server->ctxs[i];
|
||||||
}
|
}
|
||||||
GDB_UnlockAllContexts(server);
|
GDB_UnlockAllContexts(server);
|
||||||
@ -170,8 +174,12 @@ int GDB_AcceptClient(GDBContext *ctx)
|
|||||||
Result r = 0;
|
Result r = 0;
|
||||||
|
|
||||||
RecursiveLock_Lock(&ctx->lock);
|
RecursiveLock_Lock(&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);
|
r = GDB_AttachToProcess(ctx);
|
||||||
|
|
||||||
RecursiveLock_Unlock(&ctx->lock);
|
RecursiveLock_Unlock(&ctx->lock);
|
||||||
|
|
||||||
return R_SUCCEEDED(r) ? 0 : -1;
|
return R_SUCCEEDED(r) ? 0 : -1;
|
||||||
@ -182,6 +190,7 @@ int GDB_CloseClient(GDBContext *ctx)
|
|||||||
RecursiveLock_Lock(&ctx->lock);
|
RecursiveLock_Lock(&ctx->lock);
|
||||||
svcSignalEvent(ctx->parent->statusUpdated); // note: monitor will be waiting for lock
|
svcSignalEvent(ctx->parent->statusUpdated); // note: monitor will be waiting for lock
|
||||||
GDB_DetachFromProcess(ctx);
|
GDB_DetachFromProcess(ctx);
|
||||||
|
ctx->state = GDB_STATE_DISCONNECTED;
|
||||||
RecursiveLock_Unlock(&ctx->lock);
|
RecursiveLock_Unlock(&ctx->lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -202,7 +211,6 @@ GDBContext *GDB_GetClient(GDBServer *server, u16 port)
|
|||||||
if (ctx != NULL)
|
if (ctx != NULL)
|
||||||
{
|
{
|
||||||
// Context already tied to a port/selected
|
// Context already tied to a port/selected
|
||||||
// Extended remote support disabled
|
|
||||||
if (ctx->flags & GDB_FLAG_USED)
|
if (ctx->flags & GDB_FLAG_USED)
|
||||||
{
|
{
|
||||||
GDB_UnlockAllContexts(server);
|
GDB_UnlockAllContexts(server);
|
||||||
@ -274,6 +282,7 @@ static const struct
|
|||||||
{ 'P', GDB_HANDLER(WriteRegister) },
|
{ 'P', GDB_HANDLER(WriteRegister) },
|
||||||
{ 'q', GDB_HANDLER(ReadQuery) },
|
{ 'q', GDB_HANDLER(ReadQuery) },
|
||||||
{ 'Q', GDB_HANDLER(WriteQuery) },
|
{ 'Q', GDB_HANDLER(WriteQuery) },
|
||||||
|
{ 'R', GDB_HANDLER(Restart) },
|
||||||
{ 'T', GDB_HANDLER(IsThreadAlive) },
|
{ 'T', GDB_HANDLER(IsThreadAlive) },
|
||||||
{ 'v', GDB_HANDLER(VerboseCommand) },
|
{ 'v', GDB_HANDLER(VerboseCommand) },
|
||||||
{ 'X', GDB_HANDLER(WriteMemoryRaw) },
|
{ 'X', GDB_HANDLER(WriteMemoryRaw) },
|
||||||
|
@ -38,6 +38,7 @@ static const struct
|
|||||||
{ "Cont?", GDB_VERBOSE_HANDLER(ContinueSupported) },
|
{ "Cont?", GDB_VERBOSE_HANDLER(ContinueSupported) },
|
||||||
{ "Cont", GDB_VERBOSE_HANDLER(Continue) },
|
{ "Cont", GDB_VERBOSE_HANDLER(Continue) },
|
||||||
{ "MustReplyEmpty", GDB_HANDLER(Unsupported) },
|
{ "MustReplyEmpty", GDB_HANDLER(Unsupported) },
|
||||||
|
{ "Run", GDB_VERBOSE_HANDLER(Run) },
|
||||||
};
|
};
|
||||||
|
|
||||||
GDB_DECLARE_HANDLER(VerboseCommand)
|
GDB_DECLARE_HANDLER(VerboseCommand)
|
||||||
|
@ -152,3 +152,89 @@ unsigned long int xstrtoul(const char *nptr, char **endptr, int base, bool allow
|
|||||||
*endptr = (char *) (any ? (char *)s - 1 : nptr);
|
*endptr = (char *) (any ? (char *)s - 1 : nptr);
|
||||||
return (acc);
|
return (acc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Copied from newlib, without the reent stuff + some other stuff
|
||||||
|
unsigned long long int xstrtoull(const char *nptr, char **endptr, int base, bool allowPrefix, bool *ok)
|
||||||
|
{
|
||||||
|
register const unsigned char *s = (const unsigned char *)nptr;
|
||||||
|
register unsigned long long acc;
|
||||||
|
register int c;
|
||||||
|
register unsigned long long cutoff;
|
||||||
|
register int neg = 0, any, cutlim;
|
||||||
|
|
||||||
|
if(ok != NULL)
|
||||||
|
*ok = true;
|
||||||
|
/*
|
||||||
|
* See strtol for comments as to the logic used.
|
||||||
|
*/
|
||||||
|
do {
|
||||||
|
c = *s++;
|
||||||
|
} while ((c >= 9 && c <= 13) || c == ' ');
|
||||||
|
if (c == '-') {
|
||||||
|
if(!allowPrefix) {
|
||||||
|
if(ok != NULL)
|
||||||
|
*ok = false;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
neg = 1;
|
||||||
|
c = *s++;
|
||||||
|
} else if (c == '+'){
|
||||||
|
if(!allowPrefix) {
|
||||||
|
if(ok != NULL)
|
||||||
|
*ok = false;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
c = *s++;
|
||||||
|
}
|
||||||
|
if ((base == 0 || base == 16) &&
|
||||||
|
c == '0' && (*s == 'x' || *s == 'X')) {
|
||||||
|
|
||||||
|
if(!allowPrefix) {
|
||||||
|
if(ok != NULL)
|
||||||
|
*ok = false;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
c = s[1];
|
||||||
|
s += 2;
|
||||||
|
base = 16;
|
||||||
|
}
|
||||||
|
if (base == 0) {
|
||||||
|
if(!allowPrefix) {
|
||||||
|
if(ok != NULL)
|
||||||
|
*ok = false;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
base = c == '0' ? 8 : 10;
|
||||||
|
}
|
||||||
|
cutoff = (unsigned long long)(-1ull) / (unsigned long long)base;
|
||||||
|
cutlim = (unsigned long long)(-1ull) % (unsigned long long)base;
|
||||||
|
for (acc = 0, any = 0;; c = *s++) {
|
||||||
|
if (c >= '0' && c <= '9')
|
||||||
|
c -= '0';
|
||||||
|
else if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))
|
||||||
|
c -= c >= 'A' && c <= 'Z' ? 'A' - 10 : 'a' - 10;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
if (c >= base)
|
||||||
|
break;
|
||||||
|
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
|
||||||
|
any = -1;
|
||||||
|
else {
|
||||||
|
any = 1;
|
||||||
|
acc *= base;
|
||||||
|
acc += c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (any < 0) {
|
||||||
|
acc = (unsigned long long)-1ull;
|
||||||
|
if(ok != NULL)
|
||||||
|
*ok = false;
|
||||||
|
// rptr->_errno = ERANGE;
|
||||||
|
} else if (neg)
|
||||||
|
acc = -acc;
|
||||||
|
if (endptr != 0)
|
||||||
|
*endptr = (char *) (any ? (char *)s - 1 : nptr);
|
||||||
|
return (acc);
|
||||||
|
}
|
||||||
|
@ -71,13 +71,13 @@ static inline int ProcessListMenu_FormatInfoLine(char *out, const ProcessInfo *i
|
|||||||
|
|
||||||
else if(gdbServer.super.running && ctx != NULL)
|
else if(gdbServer.super.running && ctx != NULL)
|
||||||
{
|
{
|
||||||
if(ctx->state >= GDB_STATE_CONNECTED && ctx->state < GDB_STATE_DETACHING)
|
if(ctx->state >= GDB_STATE_ATTACHED && ctx->state < GDB_STATE_DETACHING)
|
||||||
{
|
{
|
||||||
u8 *addr = (u8 *)&ctx->super.addr_in.sin_addr;
|
u8 *addr = (u8 *)&ctx->super.addr_in.sin_addr;
|
||||||
checkbox = "(A) ";
|
checkbox = "(A) ";
|
||||||
sprintf(commentBuf, "Remote: %hhu.%hhu.%hhu.%hhu", addr[0], addr[1], addr[2], addr[3]);
|
sprintf(commentBuf, "Remote: %hhu.%hhu.%hhu.%hhu", addr[0], addr[1], addr[2], addr[3]);
|
||||||
}
|
}
|
||||||
else if (ctx->localPort >= GDB_PORT_BASE && ctx->localPort < GDB_PORT_BASE + MAX_DEBUG)
|
else if ((ctx->flags & GDB_FLAG_SELECTED) && (ctx->localPort >= GDB_PORT_BASE && ctx->localPort < GDB_PORT_BASE + MAX_DEBUG))
|
||||||
{
|
{
|
||||||
checkbox = "(W) ";
|
checkbox = "(W) ";
|
||||||
sprintf(commentBuf, "Port: %hu", ctx->localPort);
|
sprintf(commentBuf, "Port: %hu", ctx->localPort);
|
||||||
@ -596,7 +596,7 @@ static inline void ProcessListMenu_HandleSelected(const ProcessInfo *info)
|
|||||||
|
|
||||||
if(ctx != NULL)
|
if(ctx != NULL)
|
||||||
{
|
{
|
||||||
if(ctx->flags & GDB_FLAG_USED)
|
if((ctx->flags & GDB_FLAG_USED) && (ctx->flags & GDB_FLAG_SELECTED))
|
||||||
{
|
{
|
||||||
RecursiveLock_Lock(&ctx->lock);
|
RecursiveLock_Lock(&ctx->lock);
|
||||||
ctx->super.should_close = true;
|
ctx->super.should_close = true;
|
||||||
@ -605,7 +605,7 @@ static inline void ProcessListMenu_HandleSelected(const ProcessInfo *info)
|
|||||||
while(ctx->super.should_close)
|
while(ctx->super.should_close)
|
||||||
svcSleepThread(12 * 1000 * 1000LL);
|
svcSleepThread(12 * 1000 * 1000LL);
|
||||||
}
|
}
|
||||||
else if (ctx->localPort >= GDB_PORT_BASE && ctx->localPort < GDB_PORT_BASE + MAX_DEBUG)
|
else if ((ctx->flags & GDB_FLAG_SELECTED) && (ctx->localPort >= GDB_PORT_BASE && ctx->localPort < GDB_PORT_BASE + MAX_DEBUG))
|
||||||
{
|
{
|
||||||
RecursiveLock_Lock(&ctx->lock);
|
RecursiveLock_Lock(&ctx->lock);
|
||||||
ctx->flags &= ~GDB_FLAG_SELECTED;
|
ctx->flags &= ~GDB_FLAG_SELECTED;
|
||||||
|
Reference in New Issue
Block a user