From 78723164c10e9e4fa4470f65908de40463d37927 Mon Sep 17 00:00:00 2001 From: TuxSH <1922548+TuxSH@users.noreply.github.com> Date: Fri, 24 Jan 2020 20:24:05 +0000 Subject: [PATCH] thermosphere: gdb: target xml + various refactoring --- thermosphere/src/gdb.h | 2 + thermosphere/src/gdb/query.c | 69 ++---- thermosphere/src/gdb/remote_command.c | 309 +------------------------- thermosphere/src/gdb/remote_command.h | 7 - thermosphere/src/gdb/verbose.c | 35 ++- thermosphere/src/gdb/xfer.c | 296 +++++++++--------------- thermosphere/src/gdb/xfer.h | 11 +- 7 files changed, 143 insertions(+), 586 deletions(-) diff --git a/thermosphere/src/gdb.h b/thermosphere/src/gdb.h index 982f03305..866e973c6 100644 --- a/thermosphere/src/gdb.h +++ b/thermosphere/src/gdb.h @@ -99,6 +99,8 @@ typedef struct GDBContext int latestSentPacketSize; char buffer[GDB_BUF_LEN + 4]; char *workBuffer; + + size_t targetXmlLen; } GDBContext; typedef int (*GDBCommandHandler)(GDBContext *ctx); diff --git a/thermosphere/src/gdb/query.c b/thermosphere/src/gdb/query.c index 4c39b0414..26ee915f4 100644 --- a/thermosphere/src/gdb/query.c +++ b/thermosphere/src/gdb/query.c @@ -5,28 +5,24 @@ * SPDX-License-Identifier: (MIT OR GPL-2.0-or-later) */ -#include "gdb/query.h" -#include "gdb/xfer.h" -#include "gdb/thread.h" -#include "gdb/mem.h" -#include "gdb/net.h" -#include "gdb/remote_command.h" +#include "../utils.h" -typedef enum GDBQueryDirection -{ +#include "query.h" +#include "xfer.h" +#include "thread.h" +#include "mem.h" +#include "net.h" +#include "remote_command.h" + +typedef enum GDBQueryDirection { GDB_QUERY_DIRECTION_READ, GDB_QUERY_DIRECTION_WRITE } GDBQueryDirection; -// https://gcc.gnu.org/onlinedocs/gcc-5.3.0/cpp/Stringification.html -#define xstr(s) str(s) -#define str(s) #s - #define GDB_QUERY_HANDLER_LIST_ITEM_3(name, name2, direction) { name, GDB_QUERY_HANDLER(name2), GDB_QUERY_DIRECTION_##direction } -#define GDB_QUERY_HANDLER_LIST_ITEM(name, direction) GDB_QUERY_HANDLER_LIST_ITEM_3(xstr(name), name, direction) +#define GDB_QUERY_HANDLER_LIST_ITEM(name, direction) GDB_QUERY_HANDLER_LIST_ITEM_3(STRINGIZE(name), name, direction) -static const struct -{ +static const struct { const char *name; GDBCommandHandler handler; GDBQueryDirection direction; @@ -43,7 +39,6 @@ static const struct GDB_QUERY_HANDLER_LIST_ITEM(GetTLSAddr, READ), GDB_QUERY_HANDLER_LIST_ITEM_3("C", CurrentThreadId, READ), GDB_QUERY_HANDLER_LIST_ITEM_3("Search", SearchMemory, READ), - GDB_QUERY_HANDLER_LIST_ITEM(CatchSyscalls, WRITE), GDB_QUERY_HANDLER_LIST_ITEM(Rcmd, READ), }; @@ -89,11 +84,12 @@ int GDB_HandleWriteQuery(GDBContext *ctx) GDB_DECLARE_QUERY_HANDLER(Supported) { + // TODO! return GDB_SendFormattedPacket(ctx, "PacketSize=%x;" "qXfer:features:read+;qXfer:osdata:read+;" - "QStartNoAckMode+;QThreadEvents+;QCatchSyscalls+;" - "vContSupported+;swbreak+", + "QStartNoAckMode+;QThreadEvents+" + "vContSupported+;swbreak+;hwbreak+", GDB_BUF_LEN // should have been sizeof(ctx->buffer) but GDB memory functions are bugged ); @@ -107,40 +103,5 @@ GDB_DECLARE_QUERY_HANDLER(StartNoAckMode) GDB_DECLARE_QUERY_HANDLER(Attached) { - return GDB_SendPacket(ctx, (ctx->flags & GDB_FLAG_CREATED) ? "0" : "1", 1); -} - -GDB_DECLARE_QUERY_HANDLER(CatchSyscalls) -{ - if(ctx->commandData[0] == '0') - { - memset(ctx->svcMask, 0, 32); - return R_SUCCEEDED(svcKernelSetState(0x10002, ctx->pid, false)) ? GDB_ReplyOk(ctx) : GDB_ReplyErrno(ctx, EPERM); - } - else if(ctx->commandData[0] == '1') - { - if(ctx->commandData[1] == ';') - { - u32 id; - const char *pos = ctx->commandData + 1; - memset(ctx->svcMask, 0, 32); - - do - { - pos = GDB_ParseHexIntegerList(&id, pos + 1, 1, ';'); - if(pos == NULL) - return GDB_ReplyErrno(ctx, EILSEQ); - - if(id < 0xFE) - ctx->svcMask[id / 32] |= 1 << (31 - (id % 32)); - } - while(*pos != 0); - } - else - memset(ctx->svcMask, 0xFF, 32); - - return R_SUCCEEDED(svcKernelSetState(0x10002, ctx->pid, true, ctx->svcMask)) ? GDB_ReplyOk(ctx) : GDB_ReplyErrno(ctx, EPERM); - } - else - return GDB_ReplyErrno(ctx, EILSEQ); + return GDB_SendPacket(ctx, "1", 1); } diff --git a/thermosphere/src/gdb/remote_command.c b/thermosphere/src/gdb/remote_command.c index f6937cfca..cb36a9bd0 100644 --- a/thermosphere/src/gdb/remote_command.c +++ b/thermosphere/src/gdb/remote_command.c @@ -5,330 +5,43 @@ * SPDX-License-Identifier: (MIT OR GPL-2.0-or-later) */ -#include "gdb/remote_command.h" -#include "gdb/net.h" -#include "csvc.h" -#include "fmt.h" -#include "gdb/breakpoints.h" +#include +#include "remote_command.h" +#include "net.h" struct { const char *name; GDBCommandHandler handler; -} remoteCommandHandlers[] = -{ - { "syncrequestinfo" , GDB_REMOTE_COMMAND_HANDLER(SyncRequestInfo) }, - { "translatehandle" , GDB_REMOTE_COMMAND_HANDLER(TranslateHandle) }, - { "getmmuconfig" , GDB_REMOTE_COMMAND_HANDLER(GetMmuConfig) }, - { "getmemregions" , GDB_REMOTE_COMMAND_HANDLER(GetMemRegions) }, - { "flushcaches" , GDB_REMOTE_COMMAND_HANDLER(FlushCaches) }, - { "toggleextmemaccess", GDB_REMOTE_COMMAND_HANDLER(ToggleExternalMemoryAccess) }, +} remoteCommandHandlers[] = { }; static const char *GDB_SkipSpaces(const char *pos) { const char *nextpos; - for(nextpos = pos; *nextpos != 0 && ((*nextpos >= 9 && *nextpos <= 13) || *nextpos == ' '); nextpos++); + for (nextpos = pos; *nextpos != 0 && ((*nextpos >= 9 && *nextpos <= 13) || *nextpos == ' '); nextpos++); return nextpos; } -GDB_DECLARE_REMOTE_COMMAND_HANDLER(SyncRequestInfo) -{ - char outbuf[GDB_BUF_LEN / 2 + 1]; - Result r; - int n; - - if(ctx->commandData[0] != 0) - return GDB_ReplyErrno(ctx, EILSEQ); - - if(ctx->selectedThreadId == 0) - ctx->selectedThreadId = ctx->currentThreadId; - - if(ctx->selectedThreadId == 0) - { - n = sprintf(outbuf, "Cannot run this command without a selected thread.\n"); - goto end; - } - - u32 id; - u32 cmdId; - ThreadContext regs; - u32 instr; - Handle process; - r = svcOpenProcess(&process, ctx->pid); - if(R_FAILED(r)) - { - n = sprintf(outbuf, "Invalid process (wtf?)\n"); - goto end; - } - - for(id = 0; id < MAX_DEBUG_THREAD && ctx->threadInfos[id].id != ctx->selectedThreadId; id++); - - r = svcGetDebugThreadContext(®s, ctx->debug, ctx->selectedThreadId, THREADCONTEXT_CONTROL_CPU_REGS); - - if(R_FAILED(r) || id == MAX_DEBUG_THREAD) - { - n = sprintf(outbuf, "Invalid or running thread.\n"); - goto end; - } - - r = svcReadProcessMemory(&cmdId, ctx->debug, ctx->threadInfos[id].tls + 0x80, 4); - if(R_FAILED(r)) - { - n = sprintf(outbuf, "Invalid or running thread.\n"); - goto end; - } - - r = svcReadProcessMemory(&instr, ctx->debug, regs.cpu_registers.pc, (regs.cpu_registers.cpsr & 0x20) ? 2 : 4); - - if(R_SUCCEEDED(r) && (((regs.cpu_registers.cpsr & 0x20) && instr == BREAKPOINT_INSTRUCTION_THUMB) || instr == BREAKPOINT_INSTRUCTION_ARM)) - { - u32 savedInstruction; - if(GDB_GetBreakpointInstruction(&savedInstruction, ctx, regs.cpu_registers.pc) == 0) - instr = savedInstruction; - } - - if(R_FAILED(r) || ((regs.cpu_registers.cpsr & 0x20) && !(instr == 0xDF32 || (instr == 0xDFFE && regs.cpu_registers.r[12] == 0x32))) - || (!(regs.cpu_registers.cpsr & 0x20) && !(instr == 0xEF000032 || (instr == 0xEF0000FE && regs.cpu_registers.r[12] == 0x32)))) - { - n = sprintf(outbuf, "The selected thread is not currently performing a sync request (svc 0x32).\n"); - goto end; - } - - char name[12]; - Handle handle; - r = svcCopyHandle(&handle, CUR_PROCESS_HANDLE, (Handle)regs.cpu_registers.r[0], process); - if(R_FAILED(r)) - { - n = sprintf(outbuf, "Invalid handle.\n"); - goto end; - } - - r = svcControlService(SERVICEOP_GET_NAME, name, handle); - if(R_FAILED(r)) - name[0] = 0; - - n = sprintf(outbuf, "%s 0x%lx, 0x%08lx\n", name, cmdId, ctx->threadInfos[id].tls + 0x80); - -end: - svcCloseHandle(handle); - svcCloseHandle(process); - return GDB_SendHexPacket(ctx, outbuf, n); -} - -GDB_DECLARE_REMOTE_COMMAND_HANDLER(TranslateHandle) -{ - bool ok; - u32 val; - char *end; - int n; - Result r; - u32 kernelAddr; - Handle handle, process; - s64 refcountRaw; - u32 refcount; - char classBuf[32], serviceBuf[12] = { 0 }; - char outbuf[GDB_BUF_LEN / 2 + 1]; - - if(ctx->commandData[0] == 0) - return GDB_ReplyErrno(ctx, EILSEQ); - - val = xstrtoul(ctx->commandData, &end, 0, true, &ok); - - if(!ok) - return GDB_ReplyErrno(ctx, EILSEQ); - - end = (char *)GDB_SkipSpaces(end); - - if(*end != 0) - return GDB_ReplyErrno(ctx, EILSEQ); - - r = svcOpenProcess(&process, ctx->pid); - if(R_FAILED(r)) - { - n = sprintf(outbuf, "Invalid process (wtf?)\n"); - goto end; - } - - r = svcCopyHandle(&handle, CUR_PROCESS_HANDLE, (Handle)val, process); - if(R_FAILED(r)) - { - n = sprintf(outbuf, "Invalid handle.\n"); - goto end; - } - - svcTranslateHandle(&kernelAddr, classBuf, handle); - svcGetHandleInfo(&refcountRaw, handle, 1); - svcControlService(SERVICEOP_GET_NAME, serviceBuf, handle); - refcount = (u32)(refcountRaw - 1); - if(serviceBuf[0] != 0) - n = sprintf(outbuf, "(%s *)0x%08lx /* %s handle, %lu %s */\n", classBuf, kernelAddr, serviceBuf, refcount, refcount == 1 ? "reference" : "references"); - else - n = sprintf(outbuf, "(%s *)0x%08lx /* %lu %s */\n", classBuf, kernelAddr, refcount, refcount == 1 ? "reference" : "references"); - -end: - svcCloseHandle(handle); - svcCloseHandle(process); - return GDB_SendHexPacket(ctx, outbuf, n); -} - -extern bool isN3DS; -GDB_DECLARE_REMOTE_COMMAND_HANDLER(GetMmuConfig) -{ - int n; - char outbuf[GDB_BUF_LEN / 2 + 1]; - Result r; - Handle process; - - if(ctx->commandData[0] != 0) - return GDB_ReplyErrno(ctx, EILSEQ); - - r = svcOpenProcess(&process, ctx->pid); - if(R_FAILED(r)) - n = sprintf(outbuf, "Invalid process (wtf?)\n"); - else - { - s64 TTBCR, TTBR0; - svcGetSystemInfo(&TTBCR, 0x10002, 0); - svcGetProcessInfo(&TTBR0, process, 0x10008); - n = sprintf(outbuf, "TTBCR = %lu\nTTBR0 = 0x%08lx\nTTBR1 =", (u32)TTBCR, (u32)TTBR0); - for(u32 i = 0; i < (isN3DS ? 4 : 2); i++) - { - s64 TTBR1; - svcGetSystemInfo(&TTBR1, 0x10002, 1 + i); - - if(i == (isN3DS ? 3 : 1)) - n += sprintf(outbuf + n, " 0x%08lx\n", (u32)TTBR1); - else - n += sprintf(outbuf + n, " 0x%08lx /", (u32)TTBR1); - } - svcCloseHandle(process); - } - - return GDB_SendHexPacket(ctx, outbuf, n); -} - -static const char *FormatMemPerm(u32 perm) -{ - if (perm == MEMPERM_DONTCARE) - return "???"; - - static char buf[4] = {0}; - - buf[0] = perm & MEMPERM_READ ? 'r' : '-'; - buf[1] = perm & MEMPERM_WRITE ? 'w' : '-'; - buf[2] = perm & MEMPERM_EXECUTE ? 'x' : '-'; - - return buf; -} - -static const char *FormatMemState(u32 state) -{ - if (state > 11) - return "Unknown"; - - static const char *states[12] = - { - "Free", - "Reserved", - "IO", - "Static", - "Code", - "Private", - "Shared", - "Continuous", - "Aliased", - "Alias", - "AliasCode", - "Locked" - }; - - return states[state]; -} - -GDB_DECLARE_REMOTE_COMMAND_HANDLER(GetMemRegions) -{ - u32 address = 0; - u32 posInBuffer = 0; - u32 maxPosInBuffer = GDB_BUF_LEN / 2 - 35; ///< 35 is the maximum length of a formatted region - Handle handle; - MemInfo memi; - PageInfo pagei; - char outbuf[GDB_BUF_LEN / 2 + 1]; - - if(R_FAILED(svcOpenProcess(&handle, ctx->pid))) - { - posInBuffer = sprintf(outbuf, "Invalid process (wtf?)\n"); - goto end; - } - - while (address < 0x40000000 ///< Limit to check for regions - && posInBuffer < maxPosInBuffer - && R_SUCCEEDED(svcQueryProcessMemory(&memi, &pagei, handle, address))) - { - // Update the address for next region - address = memi.base_addr + memi.size; - - // If region isn't FREE then add it to the list - if (memi.state != MEMSTATE_FREE) - { - const char *perm = FormatMemPerm(memi.perm); - const char *state = FormatMemState(memi.state); - - posInBuffer += sprintf(outbuf + posInBuffer, "%08lx - %08lx %s %s\n", - memi.base_addr, address, perm, state); - } - } - - svcCloseHandle(handle); - -end: - return GDB_SendHexPacket(ctx, outbuf, posInBuffer); -} - -GDB_DECLARE_REMOTE_COMMAND_HANDLER(FlushCaches) -{ - if(ctx->commandData[0] != 0) - return GDB_ReplyErrno(ctx, EILSEQ); - - svcFlushEntireDataCache(); - svcInvalidateEntireInstructionCache(); - - return GDB_ReplyOk(ctx); -} - -GDB_DECLARE_REMOTE_COMMAND_HANDLER(ToggleExternalMemoryAccess) -{ - int n; - char outbuf[GDB_BUF_LEN / 2 + 1]; - - ctx->enableExternalMemoryAccess = !ctx->enableExternalMemoryAccess; - - n = sprintf(outbuf, "External memory access %s successfully.\n", ctx->enableExternalMemoryAccess ? "enabled" : "disabled"); - - return GDB_SendHexPacket(ctx, outbuf, n); -} - GDB_DECLARE_QUERY_HANDLER(Rcmd) { char commandData[GDB_BUF_LEN / 2 + 1]; char *endpos; const char *errstr = "Unrecognized command.\n"; - u32 len = strlen(ctx->commandData); + size_t len = strlen(ctx->commandData); - if(len == 0 || (len % 2) == 1 || GDB_DecodeHex(commandData, ctx->commandData, len / 2) != len / 2) + if(len == 0 || (len % 2) == 1 || GDB_DecodeHex(commandData, ctx->commandData, len / 2) != len / 2) { return GDB_ReplyErrno(ctx, EILSEQ); + } commandData[len / 2] = 0; - for(endpos = commandData; !(*endpos >= 9 && *endpos <= 13) && *endpos != ' ' && *endpos != 0; endpos++); + for (endpos = commandData; !(*endpos >= 9 && *endpos <= 13) && *endpos != ' ' && *endpos != 0; endpos++); char *nextpos = (char *)GDB_SkipSpaces(endpos); *endpos = 0; - for(u32 i = 0; i < sizeof(remoteCommandHandlers) / sizeof(remoteCommandHandlers[0]); i++) - { - if(strcmp(commandData, remoteCommandHandlers[i].name) == 0) - { + for (size_t i = 0; i < sizeof(remoteCommandHandlers) / sizeof(remoteCommandHandlers[0]); i++) { + if (strcmp(commandData, remoteCommandHandlers[i].name) == 0) { ctx->commandData = nextpos; return remoteCommandHandlers[i].handler(ctx); } diff --git a/thermosphere/src/gdb/remote_command.h b/thermosphere/src/gdb/remote_command.h index d719a2559..a33327328 100644 --- a/thermosphere/src/gdb/remote_command.h +++ b/thermosphere/src/gdb/remote_command.h @@ -12,11 +12,4 @@ #define GDB_REMOTE_COMMAND_HANDLER(name) GDB_HANDLER(RemoteCommand##name) #define GDB_DECLARE_REMOTE_COMMAND_HANDLER(name) GDB_DECLARE_HANDLER(RemoteCommand##name) -GDB_DECLARE_REMOTE_COMMAND_HANDLER(SyncRequestInfo); -GDB_DECLARE_REMOTE_COMMAND_HANDLER(TranslateHandle); -GDB_DECLARE_REMOTE_COMMAND_HANDLER(GetMmuConfig); -GDB_DECLARE_REMOTE_COMMAND_HANDLER(GetMemRegions); -GDB_DECLARE_REMOTE_COMMAND_HANDLER(FlushCaches); -GDB_DECLARE_REMOTE_COMMAND_HANDLER(ToggleExternalMemoryAccess); - GDB_DECLARE_QUERY_HANDLER(Rcmd); diff --git a/thermosphere/src/gdb/verbose.c b/thermosphere/src/gdb/verbose.c index c95066dbc..6d5c8e57d 100644 --- a/thermosphere/src/gdb/verbose.c +++ b/thermosphere/src/gdb/verbose.c @@ -5,45 +5,39 @@ * SPDX-License-Identifier: (MIT OR GPL-2.0-or-later) */ -#include "gdb/verbose.h" -#include "gdb/net.h" -#include "gdb/debug.h" -#include "gdb/tio.h" +#include -static const struct -{ +#include "verbose.h" +#include "net.h" +#include "debug.h" + +static const struct { const char *name; GDBCommandHandler handler; -} gdbVerboseCommandHandlers[] = -{ - { "Attach", GDB_VERBOSE_HANDLER(Attach) }, +} gdbVerboseCommandHandlers[] = { { "Cont?", GDB_VERBOSE_HANDLER(ContinueSupported) }, { "Cont", GDB_VERBOSE_HANDLER(Continue) }, - { "File", GDB_VERBOSE_HANDLER(File) }, { "MustReplyEmpty", GDB_HANDLER(Unsupported) }, - { "Run", GDB_VERBOSE_HANDLER(Run) }, }; GDB_DECLARE_HANDLER(VerboseCommand) { char *nameBegin = ctx->commandData; // w/o leading 'v' - if(*nameBegin == 0) + if (*nameBegin == 0) { return GDB_ReplyErrno(ctx, EILSEQ); + } char *nameEnd; char *vData = NULL; - for(nameEnd = nameBegin; *nameEnd != 0 && *nameEnd != ';' && *nameEnd != ':'; nameEnd++); - if(*nameEnd != 0) - { + for (nameEnd = nameBegin; *nameEnd != 0 && *nameEnd != ';' && *nameEnd != ':'; nameEnd++); + if (*nameEnd != 0) { *nameEnd = 0; vData = nameEnd + 1; } - for(u32 i = 0; i < sizeof(gdbVerboseCommandHandlers) / sizeof(gdbVerboseCommandHandlers[0]); i++) - { - if(strcmp(gdbVerboseCommandHandlers[i].name, nameBegin) == 0) - { + for (size_t i = 0; i < sizeof(gdbVerboseCommandHandlers) / sizeof(gdbVerboseCommandHandlers[0]); i++) { + if (strcmp(gdbVerboseCommandHandlers[i].name, nameBegin) == 0) { ctx->commandData = vData; return gdbVerboseCommandHandlers[i].handler(ctx); } @@ -54,5 +48,6 @@ GDB_DECLARE_HANDLER(VerboseCommand) GDB_DECLARE_VERBOSE_HANDLER(ContinueSupported) { - return GDB_SendPacket(ctx, "vCont;c;C", 9); + const char *supported = "vCont;c;C;s;S;t;r"; + return GDB_SendPacket(ctx, supported, strlen(supported)); } diff --git a/thermosphere/src/gdb/xfer.c b/thermosphere/src/gdb/xfer.c index e6a1fcdea..b9d374d01 100644 --- a/thermosphere/src/gdb/xfer.c +++ b/thermosphere/src/gdb/xfer.c @@ -5,249 +5,151 @@ * SPDX-License-Identifier: (MIT OR GPL-2.0-or-later) */ -#include <3ds/os.h> +#include +#include -#include "gdb/xfer.h" -#include "gdb/net.h" -#include "fmt.h" +#include "../utils.h" -#include "osdata_cfw_version_template_xml.h" -#include "osdata_memory_template_xml.h" -#include "osdata_xml.h" -#include "target_xml.h" +#include "xfer.h" +#include "net.h" -struct -{ + +struct { const char *name; - int (*handler)(GDBContext *ctx, bool write, const char *annex, u32 offset, u32 length); -} xferCommandHandlers[] = -{ + int (*handler)(GDBContext *ctx, bool write, const char *annex, size_t offset, size_t length); +} xferCommandHandlers[] = { { "features", GDB_XFER_HANDLER(Features) }, - { "osdata", GDB_XFER_HANDLER(OsData) }, }; +static void GDB_GenerateTargetXml(char *buf) +{ + int pos; + const char *hdr = ""; + const char *cpuDescBegin = ""; + const char *cpuDescEnd = + ""; + + const char *fpuDescBegin = + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + ""; + + const char *fpuDescEnd = "\r\n \r\n"; + const char *footer = ""; + + strcpy(buf, hdr); + + // CPU registers + strcat(buf, cpuDescBegin); + pos = (int)strlen(buf); + for (u32 i = 0; i < 31; i++) { + pos += sprintf(buf + pos, "", i); + } + strcat(buf, cpuDescEnd); + + strcat(buf, fpuDescBegin); + pos = (int)strlen(buf); + for (u32 i = i; i < 32; i++) { + pos += sprintf(buf + pos, "", i); + } + strcat(buf, fpuDescEnd); + + strcat(buf, footer); +} + GDB_DECLARE_XFER_HANDLER(Features) { - if(strcmp(annex, "target.xml") != 0 || write) + if(strcmp(annex, "target.xml") != 0 || write) { return GDB_ReplyEmpty(ctx); - else - return GDB_SendStreamData(ctx, (const char *)target_xml, offset, length, target_xml_size, false); -} - -struct -{ - const char *name; - int (*handler)(GDBContext *ctx, bool write, u32 offset, u32 length); -} xferOsDataCommandHandlers[] = -{ - { "cfwversion", GDB_XFER_OSDATA_HANDLER(CfwVersion) }, - { "memory", GDB_XFER_OSDATA_HANDLER(Memory) }, - { "processes", GDB_XFER_OSDATA_HANDLER(Processes) }, -}; - -GDB_DECLARE_XFER_OSDATA_HANDLER(CfwVersion) -{ - if(write) - return GDB_HandleUnsupported(ctx); - else - { - char buf[512]; // Make sure this doesn't overflow - char versionString[16]; - s64 out; - u32 version, commitHash; - bool isRelease; - u32 sz; - - svcGetSystemInfo(&out, 0x10000, 0); - version = (u32)out; - - svcGetSystemInfo(&out, 0x10000, 1); - commitHash = (u32)out; - - svcGetSystemInfo(&out, 0x10000, 0x200); - isRelease = (bool)out; - - if(GET_VERSION_REVISION(version) == 0) - sprintf(versionString, "v%lu.%lu", GET_VERSION_MAJOR(version), GET_VERSION_MINOR(version)); - else - sprintf(versionString, "v%lu.%lu.%lu", GET_VERSION_MAJOR(version), GET_VERSION_MINOR(version), GET_VERSION_REVISION(version)); - - sz = (u32)sprintf(buf, (const char *)osdata_cfw_version_template_xml, versionString, commitHash, isRelease ? "Yes" : "No"); - - return GDB_SendStreamData(ctx, buf, offset, length, sz, false); - } -} - -GDB_DECLARE_XFER_OSDATA_HANDLER(Memory) -{ - if(write) - return GDB_HandleUnsupported(ctx); - else - { - if(ctx->memoryOsInfoXmlData[0] == 0) - { - s64 out; - u32 applicationUsed, systemUsed, baseUsed; - u32 applicationTotal = *(vu32 *)0x1FF80040, systemTotal = *(vu32 *)0x1FF80044, baseTotal = *(vu32 *)0x1FF80048; - - svcGetSystemInfo(&out, 0, 1); - applicationUsed = (u32)out; - - svcGetSystemInfo(&out, 0, 2); - systemUsed = (u32)out; - - svcGetSystemInfo(&out, 0, 3); - baseUsed = (u32)out; - - sprintf(ctx->memoryOsInfoXmlData, (const char *)osdata_memory_template_xml, - applicationUsed, applicationTotal - applicationUsed, applicationTotal, (u32)((5ULL + ((1000ULL * applicationUsed) / applicationTotal)) / 10ULL), - systemUsed, systemTotal - systemUsed, systemTotal, (u32)((5ULL + ((1000ULL * systemUsed) / systemTotal)) / 10ULL), - baseUsed, baseTotal - baseUsed, baseTotal, (u32)((5ULL + ((1000ULL * baseUsed) / baseTotal)) / 10ULL) - ); - } - - u32 size = strlen(ctx->memoryOsInfoXmlData); - int n = GDB_SendStreamData(ctx, ctx->memoryOsInfoXmlData, offset, length, size, false); - - if(offset + length >= size) - ctx->memoryOsInfoXmlData[0] = 0; // we're done, invalidate - - return n; - } -} - -GDB_DECLARE_XFER_OSDATA_HANDLER(Processes) -{ - if(write) - return GDB_HandleUnsupported(ctx); - else - { - if(ctx->processesOsInfoXmlData[0] == 0) - { - static const char header[] = - /*"" - "" IDA rejects the xml header*/ - ""; - - static const char item[] = - "" - "%lu" - "%s" - ""; - - static const char footer[] = ""; - - int n; - u32 pos = 0; - - u32 pidList[0x40]; - s32 processAmount; - - strcpy(ctx->processesOsInfoXmlData, header); - pos = sizeof(header) - 1; - svcGetProcessList(&processAmount, pidList, 0x40); - - for(s32 i = 0; i < processAmount; i++) - { - u32 pid = pidList[i]; - char name[9] = { 0 }; - s64 out; - Handle processHandle; - Result res = svcOpenProcess(&processHandle, pidList[i]); - if(R_FAILED(res)) - continue; - - svcGetProcessInfo(&out, processHandle, 0x10000); - memcpy(name, &out, 8); - svcCloseHandle(processHandle); - - n = sprintf(ctx->processesOsInfoXmlData + pos, item, pid, name); - pos += (u32)n; - } - - strcpy(ctx->processesOsInfoXmlData + pos, footer); - pos = sizeof(footer) - 1; - } - - u32 size = strlen(ctx->processesOsInfoXmlData); - int n = GDB_SendStreamData(ctx, ctx->processesOsInfoXmlData, offset, length, size, false); - - if(offset + length >= size) - ctx->processesOsInfoXmlData[0] = 0; // we're done, invalidate - - return n; - } -} - -GDB_DECLARE_XFER_HANDLER(OsData) -{ - if(strcmp(annex, "") == 0 && !write) - return GDB_SendStreamData(ctx, (const char *)osdata_xml, offset, length, osdata_xml_size, false); - else - { - for(u32 i = 0; i < sizeof(xferOsDataCommandHandlers) / sizeof(xferOsDataCommandHandlers[0]); i++) - { - if(strcmp(annex, xferOsDataCommandHandlers[i].name) == 0) - return xferOsDataCommandHandlers[i].handler(ctx, write, offset, length); - } } - return GDB_HandleUnsupported(ctx); + // Generate the target xml on-demand + // This is a bit whack, we rightfully assume that GDB won't sent any other command during the stream transfer + if (ctx->targetXmlLen == 0) { + GDB_GenerateTargetXml(ctx->workBuffer); + ctx->targetXmlLen = strlen(ctx->workBuffer); + } + + int n = GDB_SendStreamData(ctx, ctx->workBuffer, offset, length, ctx->targetXmlLen, false); + + // Transfer ended + if(offset + length >= ctx->targetXmlLen) { + ctx->targetXmlLen = 0; + } + + return n; } GDB_DECLARE_QUERY_HANDLER(Xfer) { const char *objectStart = ctx->commandData; char *objectEnd = (char*)strchr(objectStart, ':'); - if(objectEnd == NULL) return -1; + if (objectEnd == NULL) { + return -1; + } *objectEnd = 0; char *opStart = objectEnd + 1; char *opEnd = (char*)strchr(opStart, ':'); - if(opEnd == NULL) return -1; + if(opEnd == NULL) { + return -1; + } *opEnd = 0; char *annexStart = opEnd + 1; char *annexEnd = (char*)strchr(annexStart, ':'); - if(annexEnd == NULL) return -1; + if(annexEnd == NULL) { + return -1; + } *annexEnd = 0; const char *offStart = annexEnd + 1; - u32 offset, length; + size_t offset, length; bool write; const char *pos; - if(strcmp(opStart, "read") == 0) - { - u32 lst[2]; - if(GDB_ParseHexIntegerList(lst, offStart, 2, 0) == NULL) + if (strcmp(opStart, "read") == 0) { + unsigned int lst[2]; + if(GDB_ParseHexIntegerList(lst, offStart, 2, 0) == NULL) { return GDB_ReplyErrno(ctx, EILSEQ); + } offset = lst[0]; length = lst[1]; write = false; - } - else if(strcmp(opStart, "write") == 0) - { + } else if (strcmp(opStart, "write") == 0) { pos = GDB_ParseHexIntegerList(&offset, offStart, 1, ':'); - if(pos == NULL || *pos++ != ':') + if (pos == NULL || *pos++ != ':') { return GDB_ReplyErrno(ctx, EILSEQ); + } - u32 len = strlen(pos); - if(len == 0 || (len % 2) != 0) + size_t len = strlen(pos); + if (len == 0 || (len % 2) != 0) { return GDB_ReplyErrno(ctx, EILSEQ); + } length = len / 2; write = true; - } - else + } else { return GDB_ReplyErrno(ctx, EILSEQ); + } - for(u32 i = 0; i < sizeof(xferCommandHandlers) / sizeof(xferCommandHandlers[0]); i++) - { - if(strcmp(objectStart, xferCommandHandlers[i].name) == 0) - { - if(write) + for (size_t i = 0; i < sizeof(xferCommandHandlers) / sizeof(xferCommandHandlers[0]); i++) { + if (strcmp(objectStart, xferCommandHandlers[i].name) == 0) { + if(write) { ctx->commandData = (char *)pos; + } return xferCommandHandlers[i].handler(ctx, write, annexStart, offset, length); } diff --git a/thermosphere/src/gdb/xfer.h b/thermosphere/src/gdb/xfer.h index 68556a251..c4a82ce68 100644 --- a/thermosphere/src/gdb/xfer.h +++ b/thermosphere/src/gdb/xfer.h @@ -10,17 +10,8 @@ #include "gdb.h" #define GDB_XFER_HANDLER(name) GDB_HANDLER(Xfer##name) -#define GDB_DECLARE_XFER_HANDLER(name) int GDB_XFER_HANDLER(name)(GDBContext *ctx, bool write, const char *annex, u32 offset, u32 length) - -#define GDB_XFER_OSDATA_HANDLER(name) GDB_XFER_HANDLER(OsData##name) -#define GDB_DECLARE_XFER_OSDATA_HANDLER(name) int GDB_XFER_OSDATA_HANDLER(name)(GDBContext *ctx, bool write, u32 offset, u32 length) +#define GDB_DECLARE_XFER_HANDLER(name) int GDB_XFER_HANDLER(name)(GDBContext *ctx, bool write, const char *annex, size_t offset, size_t length) GDB_DECLARE_XFER_HANDLER(Features); -GDB_DECLARE_XFER_OSDATA_HANDLER(CfwVersion); -GDB_DECLARE_XFER_OSDATA_HANDLER(Memory); -GDB_DECLARE_XFER_OSDATA_HANDLER(Processes); - -GDB_DECLARE_XFER_HANDLER(OsData); - GDB_DECLARE_QUERY_HANDLER(Xfer);