/* * This file is part of Luma3DS. * Copyright (C) 2016-2019 Aurora Wright, TuxSH * * SPDX-License-Identifier: (MIT OR GPL-2.0-or-later) */ #include #include #include "../utils.h" #include "xfer.h" #include "net.h" struct { const char *name; int (*handler)(GDBContext *ctx, bool write, const char *annex, size_t offset, size_t length); } xferCommandHandlers[] = { { "features", GDB_XFER_HANDLER(Features) }, }; 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) { return GDB_ReplyEmpty(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; } *objectEnd = 0; char *opStart = objectEnd + 1; char *opEnd = (char*)strchr(opStart, ':'); if(opEnd == NULL) { return -1; } *opEnd = 0; char *annexStart = opEnd + 1; char *annexEnd = (char*)strchr(annexStart, ':'); if(annexEnd == NULL) { return -1; } *annexEnd = 0; const char *offStart = annexEnd + 1; size_t offset, length; bool write; const char *pos; if (strcmp(opStart, "read") == 0) { unsigned long 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) { pos = GDB_ParseHexIntegerList(&offset, offStart, 1, ':'); if (pos == NULL || *pos++ != ':') { return GDB_ReplyErrno(ctx, EILSEQ); } size_t len = strlen(pos); if (len == 0 || (len % 2) != 0) { return GDB_ReplyErrno(ctx, EILSEQ); } length = len / 2; write = true; } else { return GDB_ReplyErrno(ctx, EILSEQ); } 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); } } return GDB_HandleUnsupported(ctx); }