Restore extended-remote support & map <GDB PID>-><1 + 3DS PID> (breaking change)
Once more, the "official" gdb client is the one than is the least compliant to its very own stub specs (compared to, say, IDA)
This commit is contained in:
parent
2b5da40a1d
commit
01ebbf114c
@ -124,6 +124,7 @@ typedef struct GDBContext
|
|||||||
Handle processAttachedEvent, continuedEvent;
|
Handle processAttachedEvent, continuedEvent;
|
||||||
Handle eventToWaitFor;
|
Handle eventToWaitFor;
|
||||||
|
|
||||||
|
bool multiprocessExtEnabled;
|
||||||
bool catchThreadEvents;
|
bool catchThreadEvents;
|
||||||
bool processEnded, processExited;
|
bool processEnded, processExited;
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ 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);
|
||||||
|
GDB_DECLARE_VERBOSE_HANDLER(Kill);
|
||||||
GDB_DECLARE_HANDLER(Break);
|
GDB_DECLARE_HANDLER(Break);
|
||||||
GDB_DECLARE_HANDLER(Continue);
|
GDB_DECLARE_HANDLER(Continue);
|
||||||
GDB_DECLARE_VERBOSE_HANDLER(Continue);
|
GDB_DECLARE_VERBOSE_HANDLER(Continue);
|
||||||
|
@ -9,6 +9,20 @@
|
|||||||
|
|
||||||
#include "gdb.h"
|
#include "gdb.h"
|
||||||
|
|
||||||
|
static inline u32 GDB_ConvertFromRealPid(u32 pid)
|
||||||
|
{
|
||||||
|
return pid + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u32 GDB_ConvertToRealPid(u32 pid)
|
||||||
|
{
|
||||||
|
return pid - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *GDB_ParseThreadId(GDBContext *ctx, u32 *outPid, u32 *outTid, const char *str, char lastSep);
|
||||||
|
u32 GDB_ParseDecodeSingleThreadId(GDBContext *ctx, const char *str, char lastSep);
|
||||||
|
int GDB_EncodeThreadId(GDBContext *ctx, char *outbuf, u32 tid);
|
||||||
|
|
||||||
u32 GDB_GetCurrentThreadFromList(GDBContext *ctx, u32 *threadIds, u32 nbThreads);
|
u32 GDB_GetCurrentThreadFromList(GDBContext *ctx, u32 *threadIds, u32 nbThreads);
|
||||||
u32 GDB_GetCurrentThread(GDBContext *ctx);
|
u32 GDB_GetCurrentThread(GDBContext *ctx);
|
||||||
|
|
||||||
|
@ -138,7 +138,7 @@ GDB_DECLARE_VERBOSE_HANDLER(Attach)
|
|||||||
return GDB_ReplyErrno(ctx, EILSEQ);
|
return GDB_ReplyErrno(ctx, EILSEQ);
|
||||||
|
|
||||||
RecursiveLock_Lock(&ctx->lock);
|
RecursiveLock_Lock(&ctx->lock);
|
||||||
ctx->pid = pid;
|
ctx->pid = GDB_ConvertToRealPid(pid);
|
||||||
Result r = GDB_AttachToProcess(ctx);
|
Result r = GDB_AttachToProcess(ctx);
|
||||||
if(R_FAILED(r))
|
if(R_FAILED(r))
|
||||||
GDB_DetachImmediatelyExtended(ctx);
|
GDB_DetachImmediatelyExtended(ctx);
|
||||||
@ -154,6 +154,16 @@ GDB_DECLARE_VERBOSE_HANDLER(Attach)
|
|||||||
|
|
||||||
GDB_DECLARE_HANDLER(Detach)
|
GDB_DECLARE_HANDLER(Detach)
|
||||||
{
|
{
|
||||||
|
if (ctx->multiprocessExtEnabled)
|
||||||
|
{
|
||||||
|
//;pid
|
||||||
|
u32 pid;
|
||||||
|
if(ctx->commandData[0] != ';' || GDB_ParseHexIntegerList(&pid, ctx->commandData + 1, 1, 0) == NULL)
|
||||||
|
return GDB_ReplyErrno(ctx, EILSEQ);
|
||||||
|
pid = GDB_ConvertToRealPid(pid);
|
||||||
|
if (pid != ctx->pid)
|
||||||
|
return GDB_ReplyErrno(ctx, EPERM);
|
||||||
|
}
|
||||||
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);
|
GDB_DetachImmediatelyExtended(ctx);
|
||||||
@ -170,6 +180,29 @@ GDB_DECLARE_HANDLER(Kill)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GDB_DECLARE_VERBOSE_HANDLER(Kill)
|
||||||
|
{
|
||||||
|
if (ctx->multiprocessExtEnabled)
|
||||||
|
{
|
||||||
|
//;pid . ';' is already consumed by our caller
|
||||||
|
u32 pid;
|
||||||
|
if(GDB_ParseHexIntegerList(&pid, ctx->commandData, 1, 0) == NULL)
|
||||||
|
return GDB_ReplyErrno(ctx, EILSEQ);
|
||||||
|
pid = GDB_ConvertToRealPid(pid);
|
||||||
|
if (pid != ctx->pid)
|
||||||
|
return GDB_ReplyErrno(ctx, EPERM);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret = GDB_ReplyOk(ctx);
|
||||||
|
|
||||||
|
ctx->state = GDB_STATE_DETACHING;
|
||||||
|
ctx->flags |= GDB_FLAG_TERMINATE_PROCESS;
|
||||||
|
if (ctx->flags & GDB_FLAG_EXTENDED_REMOTE)
|
||||||
|
GDB_DetachImmediatelyExtended(ctx);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
GDB_DECLARE_HANDLER(Break)
|
GDB_DECLARE_HANDLER(Break)
|
||||||
{
|
{
|
||||||
if(!(ctx->flags & GDB_FLAG_PROCESS_CONTINUING))
|
if(!(ctx->flags & GDB_FLAG_PROCESS_CONTINUING))
|
||||||
@ -232,7 +265,7 @@ GDB_DECLARE_HANDLER(Continue)
|
|||||||
|
|
||||||
GDB_DECLARE_VERBOSE_HANDLER(Continue)
|
GDB_DECLARE_VERBOSE_HANDLER(Continue)
|
||||||
{
|
{
|
||||||
char *pos = ctx->commandData;
|
const char *pos = ctx->commandData;
|
||||||
bool currentThreadFound = false;
|
bool currentThreadFound = false;
|
||||||
while(pos != NULL && *pos != 0 && !currentThreadFound)
|
while(pos != NULL && *pos != 0 && !currentThreadFound)
|
||||||
{
|
{
|
||||||
@ -247,18 +280,21 @@ GDB_DECLARE_VERBOSE_HANDLER(Continue)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *nextpos = (char *)strchr(pos, ';');
|
u32 pid, tid;
|
||||||
if(strncmp(pos, "-1", 2) == 0)
|
|
||||||
currentThreadFound = true;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
u32 threadId;
|
|
||||||
if(GDB_ParseHexIntegerList(&threadId, pos, 1, ';') == NULL)
|
|
||||||
return GDB_ReplyErrno(ctx, EILSEQ);
|
|
||||||
currentThreadFound = currentThreadFound || threadId == ctx->currentThreadId;
|
|
||||||
}
|
|
||||||
|
|
||||||
pos = nextpos;
|
const char *nextpos = GDB_ParseThreadId(ctx, &pid, &tid, pos, ';');
|
||||||
|
if (nextpos == NULL)
|
||||||
|
return GDB_ReplyErrno(ctx, EILSEQ);
|
||||||
|
|
||||||
|
if (tid == 0)
|
||||||
|
currentThreadFound = true;
|
||||||
|
if (pid != (u32)-1 && pid != ctx->pid)
|
||||||
|
return GDB_ReplyErrno(ctx, EPERM);
|
||||||
|
else
|
||||||
|
currentThreadFound = currentThreadFound || tid == ctx->currentThreadId;
|
||||||
|
|
||||||
|
if (nextpos != NULL && *nextpos != '\0')
|
||||||
|
pos = nextpos + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ctx->currentThreadId == 0 || currentThreadFound)
|
if(ctx->currentThreadId == 0 || currentThreadFound)
|
||||||
@ -269,12 +305,18 @@ GDB_DECLARE_VERBOSE_HANDLER(Continue)
|
|||||||
|
|
||||||
GDB_DECLARE_HANDLER(GetStopReason)
|
GDB_DECLARE_HANDLER(GetStopReason)
|
||||||
{
|
{
|
||||||
|
char pidbuf[32];
|
||||||
|
if (ctx->multiprocessExtEnabled && ctx->state == GDB_STATE_ATTACHED)
|
||||||
|
sprintf(pidbuf, ";process:%lx", GDB_ConvertFromRealPid(ctx->pid));
|
||||||
|
else
|
||||||
|
pidbuf[0] = '\0';
|
||||||
|
|
||||||
if (ctx->processEnded && ctx->processExited) {
|
if (ctx->processEnded && ctx->processExited) {
|
||||||
return GDB_SendPacket(ctx, "W00", 3);
|
return GDB_SendFormattedPacket(ctx, "W00%s", pidbuf);
|
||||||
} else if (ctx->processEnded && !ctx->processExited) {
|
} else if (ctx->processEnded && !ctx->processExited) {
|
||||||
return GDB_SendPacket(ctx, "X0f", 3);
|
return GDB_SendFormattedPacket(ctx, "X0f%s", pidbuf);
|
||||||
} else if (ctx->debug == 0) {
|
} else if (ctx->debug == 0) {
|
||||||
return GDB_SendPacket(ctx, "W00", 3);
|
return GDB_SendFormattedPacket(ctx, "W00%s", pidbuf);
|
||||||
} else {
|
} else {
|
||||||
return GDB_SendStopReply(ctx, &ctx->latestDebugEvent);
|
return GDB_SendStopReply(ctx, &ctx->latestDebugEvent);
|
||||||
}
|
}
|
||||||
@ -287,7 +329,10 @@ static int GDB_ParseCommonThreadInfo(char *out, GDBContext *ctx, int sig)
|
|||||||
s64 dummy;
|
s64 dummy;
|
||||||
u32 core;
|
u32 core;
|
||||||
Result r = svcGetDebugThreadContext(®s, ctx->debug, threadId, THREADCONTEXT_CONTROL_ALL);
|
Result r = svcGetDebugThreadContext(®s, ctx->debug, threadId, THREADCONTEXT_CONTROL_ALL);
|
||||||
int n = sprintf(out, "T%02xthread:%lx;", sig, threadId);
|
|
||||||
|
char tidbuf[32];
|
||||||
|
GDB_EncodeThreadId(ctx, tidbuf, ctx->currentThreadId);
|
||||||
|
int n = sprintf(out, "T%02xthread:%s;", sig, tidbuf);
|
||||||
|
|
||||||
if(R_FAILED(r))
|
if(R_FAILED(r))
|
||||||
return n;
|
return n;
|
||||||
@ -450,7 +495,12 @@ int GDB_SendStopReply(GDBContext *ctx, const DebugEventInfo *info)
|
|||||||
{
|
{
|
||||||
// exited (no error / unhandled exception), SIGTERM (process terminated) * 2
|
// exited (no error / unhandled exception), SIGTERM (process terminated) * 2
|
||||||
static const char *processExitReplies[] = { "W00", "X0f", "X0f" };
|
static const char *processExitReplies[] = { "W00", "X0f", "X0f" };
|
||||||
return GDB_SendPacket(ctx, processExitReplies[(u32)info->exit_process.reason], 3);
|
char pidbuf[32];
|
||||||
|
if (ctx->multiprocessExtEnabled && ctx->state == GDB_STATE_ATTACHED)
|
||||||
|
sprintf(pidbuf, ";process:%lx", GDB_ConvertFromRealPid(ctx->pid));
|
||||||
|
else
|
||||||
|
pidbuf[0] = '\0';
|
||||||
|
return GDB_SendFormattedPacket(ctx, "%s%s", processExitReplies[(u32)info->exit_process.reason], pidbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
case DBGEVENT_EXCEPTION:
|
case DBGEVENT_EXCEPTION:
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
|
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
#include "gdb/query.h"
|
#include "gdb/query.h"
|
||||||
#include "gdb/xfer.h"
|
#include "gdb/xfer.h"
|
||||||
#include "gdb/thread.h"
|
#include "gdb/thread.h"
|
||||||
@ -89,11 +90,23 @@ int GDB_HandleWriteQuery(GDBContext *ctx)
|
|||||||
|
|
||||||
GDB_DECLARE_QUERY_HANDLER(Supported)
|
GDB_DECLARE_QUERY_HANDLER(Supported)
|
||||||
{
|
{
|
||||||
|
const char *pos = ctx->commandData, *nextpos = pos;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
pos = nextpos;
|
||||||
|
nextpos = strchrnul(pos, ';');
|
||||||
|
if (*nextpos != ';' && *nextpos != '\0')
|
||||||
|
return GDB_ReplyErrno(ctx, EILSEQ);
|
||||||
|
|
||||||
|
if (strncmp(pos, "multiprocess+", nextpos - pos) == 0)
|
||||||
|
ctx->multiprocessExtEnabled = true;
|
||||||
|
} while (*nextpos++ != '\0');
|
||||||
|
|
||||||
return GDB_SendFormattedPacket(ctx,
|
return GDB_SendFormattedPacket(ctx,
|
||||||
"PacketSize=%x;"
|
"PacketSize=%x;"
|
||||||
"qXfer:features:read+;qXfer:osdata:read+;"
|
"qXfer:features:read+;qXfer:osdata:read+;"
|
||||||
"QStartNoAckMode+;QThreadEvents+;QCatchSyscalls+;"
|
"QStartNoAckMode+;QThreadEvents+;QCatchSyscalls+;"
|
||||||
"vContSupported+;swbreak+",
|
"vContSupported+;swbreak+;multiprocess+",
|
||||||
|
|
||||||
GDB_BUF_LEN // should have been sizeof(ctx->buffer) but GDB memory functions are bugged
|
GDB_BUF_LEN // should have been sizeof(ctx->buffer) but GDB memory functions are bugged
|
||||||
);
|
);
|
||||||
|
@ -199,6 +199,7 @@ int GDB_CloseClient(GDBContext *ctx)
|
|||||||
ctx->state = GDB_STATE_DISCONNECTED;
|
ctx->state = GDB_STATE_DISCONNECTED;
|
||||||
|
|
||||||
ctx->catchThreadEvents = false;
|
ctx->catchThreadEvents = false;
|
||||||
|
ctx->multiprocessExtEnabled = false;
|
||||||
|
|
||||||
memset(&ctx->latestDebugEvent, 0, sizeof(DebugEventInfo));
|
memset(&ctx->latestDebugEvent, 0, sizeof(DebugEventInfo));
|
||||||
memset(ctx->memoryOsInfoXmlData, 0, sizeof(ctx->memoryOsInfoXmlData));
|
memset(ctx->memoryOsInfoXmlData, 0, sizeof(ctx->memoryOsInfoXmlData));
|
||||||
|
@ -10,6 +10,103 @@
|
|||||||
#include "fmt.h"
|
#include "fmt.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
const char *GDB_ParseThreadId(GDBContext *ctx, u32 *outPid, u32 *outTid, const char *str, char lastSep)
|
||||||
|
{
|
||||||
|
const char *pos = str;
|
||||||
|
u32 pid = ctx->pid;
|
||||||
|
u32 tid = 0;
|
||||||
|
|
||||||
|
// pPID.TID | PID
|
||||||
|
if (ctx->multiprocessExtEnabled)
|
||||||
|
{
|
||||||
|
// Check for 'p'
|
||||||
|
if (*pos != 'p')
|
||||||
|
{
|
||||||
|
// Test -1 first.
|
||||||
|
// Note: this means we parse -1, p-1.0, p0.0 the same which is a bug
|
||||||
|
if (strcmp(pos, "-1") == 0)
|
||||||
|
{
|
||||||
|
pid = (u32)-1;
|
||||||
|
tid = 0;
|
||||||
|
pos += 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pos = GDB_ParseHexIntegerList(&pid, pos, 1, 0);
|
||||||
|
if (pos == NULL)
|
||||||
|
return NULL;
|
||||||
|
pid = GDB_ConvertToRealPid(pid);
|
||||||
|
tid = 0;
|
||||||
|
}
|
||||||
|
*outPid = pid;
|
||||||
|
*outTid = 0;
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
++pos;
|
||||||
|
|
||||||
|
// -1 pid?
|
||||||
|
if (strncmp(pos, "-1.", 3) == 0)
|
||||||
|
{
|
||||||
|
pid = (u32)-1; // Should encode as 0 but oh well
|
||||||
|
pos += 3;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pos = GDB_ParseHexIntegerList(&pid, pos, 1, '.');
|
||||||
|
if (pos == NULL)
|
||||||
|
return NULL;
|
||||||
|
pid = GDB_ConvertToRealPid(pid);
|
||||||
|
++pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallthrough
|
||||||
|
// TID
|
||||||
|
if (strncmp(pos, "-1", 2) == 0)
|
||||||
|
{
|
||||||
|
tid = 0; // TID 0 is always invalid
|
||||||
|
pos += 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pos = GDB_ParseHexIntegerList(&tid, pos, 1, lastSep);
|
||||||
|
if (pos == NULL)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pid == (u32)-1 && tid != 0)
|
||||||
|
return NULL; // this is never allowed
|
||||||
|
|
||||||
|
if (pos != NULL)
|
||||||
|
{
|
||||||
|
*outPid = pid;
|
||||||
|
*outTid = tid;
|
||||||
|
}
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
u32 GDB_ParseDecodeSingleThreadId(GDBContext *ctx, const char *str, char lastSep)
|
||||||
|
{
|
||||||
|
u32 pid, tid;
|
||||||
|
if (GDB_ParseThreadId(ctx, &pid, &tid, str, lastSep) == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (pid != ctx->pid)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return tid;
|
||||||
|
}
|
||||||
|
|
||||||
|
int GDB_EncodeThreadId(GDBContext *ctx, char *outbuf, u32 tid)
|
||||||
|
{
|
||||||
|
if (ctx->multiprocessExtEnabled)
|
||||||
|
return sprintf(outbuf, "p%lx.%lx", GDB_ConvertFromRealPid(ctx->pid), tid);
|
||||||
|
else
|
||||||
|
return sprintf(outbuf, "%lx", tid);
|
||||||
|
}
|
||||||
|
|
||||||
static s32 GDB_GetDynamicThreadPriority(GDBContext *ctx, u32 threadId)
|
static s32 GDB_GetDynamicThreadPriority(GDBContext *ctx, u32 threadId)
|
||||||
{
|
{
|
||||||
Handle process, thread;
|
Handle process, thread;
|
||||||
@ -95,27 +192,30 @@ GDB_DECLARE_HANDLER(SetThreadId)
|
|||||||
{
|
{
|
||||||
if(ctx->commandData[0] == 'g')
|
if(ctx->commandData[0] == 'g')
|
||||||
{
|
{
|
||||||
if(strncmp(ctx->commandData + 1, "-1", 2) == 0)
|
u32 pid = 0, tid = 0;
|
||||||
return GDB_ReplyErrno(ctx, EILSEQ); // a thread must be specified
|
if (GDB_ParseThreadId(ctx, &pid, &tid, ctx->commandData + 1, 0) == NULL)
|
||||||
|
|
||||||
u32 id;
|
|
||||||
if(GDB_ParseHexIntegerList(&id, ctx->commandData + 1, 1, 0) == NULL)
|
|
||||||
return GDB_ReplyErrno(ctx, EILSEQ);
|
return GDB_ReplyErrno(ctx, EILSEQ);
|
||||||
ctx->selectedThreadId = id;
|
|
||||||
|
// Allow ptid = p0.0; note that this catches some -1 forms, which is a bug
|
||||||
|
if (pid != (u32)-1 && pid != ctx->pid)
|
||||||
|
return GDB_ReplyErrno(ctx, EILSEQ);
|
||||||
|
|
||||||
|
ctx->selectedThreadId = tid;
|
||||||
return GDB_ReplyOk(ctx);
|
return GDB_ReplyOk(ctx);
|
||||||
}
|
}
|
||||||
else if(ctx->commandData[0] == 'c')
|
else if(ctx->commandData[0] == 'c')
|
||||||
{
|
{
|
||||||
// We can't stop/continue particular threads (uncompliant behavior)
|
// We can't stop/continue particular threads (uncompliant behavior)
|
||||||
if(strncmp(ctx->commandData + 1, "-1", 2) == 0)
|
|
||||||
ctx->selectedThreadIdForContinuing = 0;
|
u32 pid, tid;
|
||||||
else
|
if (GDB_ParseThreadId(ctx, &pid, &tid, ctx->commandData + 1, 0) == NULL)
|
||||||
{
|
return GDB_ReplyErrno(ctx, EILSEQ);
|
||||||
u32 id;
|
|
||||||
if(GDB_ParseHexIntegerList(&id, ctx->commandData + 1, 1, 0) == NULL)
|
// Allow gdb pid.tid = -1.-1, (we're also accepting pid = 0 but that's a bug)
|
||||||
return GDB_ReplyErrno(ctx, EILSEQ);
|
if (pid != (u32)-1 && pid != ctx->pid)
|
||||||
ctx->selectedThreadIdForContinuing = id;
|
return GDB_ReplyErrno(ctx, EPERM);
|
||||||
}
|
|
||||||
|
ctx->selectedThreadIdForContinuing = tid;
|
||||||
|
|
||||||
return GDB_ReplyOk(ctx);
|
return GDB_ReplyOk(ctx);
|
||||||
}
|
}
|
||||||
@ -125,14 +225,14 @@ GDB_DECLARE_HANDLER(SetThreadId)
|
|||||||
|
|
||||||
GDB_DECLARE_HANDLER(IsThreadAlive)
|
GDB_DECLARE_HANDLER(IsThreadAlive)
|
||||||
{
|
{
|
||||||
u32 threadId;
|
|
||||||
s64 dummy;
|
s64 dummy;
|
||||||
u32 mask;
|
u32 mask;
|
||||||
|
|
||||||
if(GDB_ParseHexIntegerList(&threadId, ctx->commandData, 1, 0) == NULL)
|
u32 tid = GDB_ParseDecodeSingleThreadId(ctx, ctx->commandData, 0);
|
||||||
|
if (tid == 0)
|
||||||
return GDB_ReplyErrno(ctx, EILSEQ);
|
return GDB_ReplyErrno(ctx, EILSEQ);
|
||||||
|
|
||||||
Result r = svcGetDebugThreadParam(&dummy, &mask, ctx->debug, threadId, DBGTHREAD_PARAMETER_SCHEDULING_MASK_LOW);
|
Result r = svcGetDebugThreadParam(&dummy, &mask, ctx->debug, tid, DBGTHREAD_PARAMETER_SCHEDULING_MASK_LOW);
|
||||||
if(R_SUCCEEDED(r) && mask != 2)
|
if(R_SUCCEEDED(r) && mask != 2)
|
||||||
return GDB_ReplyOk(ctx);
|
return GDB_ReplyOk(ctx);
|
||||||
else
|
else
|
||||||
@ -144,7 +244,9 @@ GDB_DECLARE_QUERY_HANDLER(CurrentThreadId)
|
|||||||
if(ctx->currentThreadId == 0)
|
if(ctx->currentThreadId == 0)
|
||||||
ctx->currentThreadId = GDB_GetCurrentThread(ctx);
|
ctx->currentThreadId = GDB_GetCurrentThread(ctx);
|
||||||
|
|
||||||
return ctx->currentThreadId != 0 ? GDB_SendFormattedPacket(ctx, "QC%lx", ctx->currentThreadId) : GDB_ReplyErrno(ctx, EPERM);
|
char buf[32];
|
||||||
|
GDB_EncodeThreadId(ctx, buf, ctx->currentThreadId);
|
||||||
|
return ctx->currentThreadId != 0 ? GDB_SendFormattedPacket(ctx, "QC%s", buf) : GDB_ReplyErrno(ctx, EPERM);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void GDB_GenerateThreadListData(GDBContext *ctx)
|
static void GDB_GenerateThreadListData(GDBContext *ctx)
|
||||||
@ -168,7 +270,11 @@ static void GDB_GenerateThreadListData(GDBContext *ctx)
|
|||||||
char *bufptr = ctx->threadListData;
|
char *bufptr = ctx->threadListData;
|
||||||
|
|
||||||
for(u32 i = 0; i < nbAliveThreads; i++)
|
for(u32 i = 0; i < nbAliveThreads; i++)
|
||||||
bufptr += sprintf(bufptr, i == (nbAliveThreads - 1) ? "%lx" : "%lx,", aliveThreadIds[i]);
|
{
|
||||||
|
bufptr += GDB_EncodeThreadId(ctx, bufptr, aliveThreadIds[i]);
|
||||||
|
if (i < nbAliveThreads - 1)
|
||||||
|
*bufptr++ = ',';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int GDB_SendThreadData(GDBContext *ctx)
|
static int GDB_SendThreadData(GDBContext *ctx)
|
||||||
@ -242,7 +348,8 @@ GDB_DECLARE_QUERY_HANDLER(ThreadExtraInfo)
|
|||||||
|
|
||||||
u32 tls = 0;
|
u32 tls = 0;
|
||||||
|
|
||||||
if(GDB_ParseHexIntegerList(&id, ctx->commandData, 1, 0) == NULL)
|
id = GDB_ParseDecodeSingleThreadId(ctx, ctx->commandData, 0);
|
||||||
|
if (id == 0)
|
||||||
return GDB_ReplyErrno(ctx, EILSEQ);
|
return GDB_ReplyErrno(ctx, EILSEQ);
|
||||||
|
|
||||||
for(u32 i = 0; i < MAX_DEBUG_THREAD; i++)
|
for(u32 i = 0; i < MAX_DEBUG_THREAD; i++)
|
||||||
|
@ -22,6 +22,7 @@ static const struct
|
|||||||
{ "File", GDB_VERBOSE_HANDLER(File) },
|
{ "File", GDB_VERBOSE_HANDLER(File) },
|
||||||
{ "MustReplyEmpty", GDB_HANDLER(Unsupported) },
|
{ "MustReplyEmpty", GDB_HANDLER(Unsupported) },
|
||||||
{ "Run", GDB_VERBOSE_HANDLER(Run) },
|
{ "Run", GDB_VERBOSE_HANDLER(Run) },
|
||||||
|
{ "Kill", GDB_VERBOSE_HANDLER(Kill) },
|
||||||
};
|
};
|
||||||
|
|
||||||
GDB_DECLARE_HANDLER(VerboseCommand)
|
GDB_DECLARE_HANDLER(VerboseCommand)
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include "gdb/xfer.h"
|
#include "gdb/xfer.h"
|
||||||
#include "gdb/net.h"
|
#include "gdb/net.h"
|
||||||
|
#include "gdb/thread.h"
|
||||||
#include "fmt.h"
|
#include "fmt.h"
|
||||||
|
|
||||||
#include "osdata_cfw_version_template_xml.h"
|
#include "osdata_cfw_version_template_xml.h"
|
||||||
@ -161,7 +162,7 @@ GDB_DECLARE_XFER_OSDATA_HANDLER(Processes)
|
|||||||
memcpy(name, &out, 8);
|
memcpy(name, &out, 8);
|
||||||
svcCloseHandle(processHandle);
|
svcCloseHandle(processHandle);
|
||||||
|
|
||||||
n = sprintf(ctx->processesOsInfoXmlData + pos, item, pid, name);
|
n = sprintf(ctx->processesOsInfoXmlData + pos, item, GDB_ConvertFromRealPid(pid), name);
|
||||||
pos += (u32)n;
|
pos += (u32)n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user