thermospshere: c++ify xfer, query, etc. More string parsing utilities

This commit is contained in:
TuxSH 2020-02-07 18:28:34 +00:00
parent ff2c835b0a
commit 192d2db4a9
11 changed files with 287 additions and 297 deletions

View file

@ -137,8 +137,8 @@ namespace ams::hvisor::gdb {
COMMAND_CASE('M', WriteMemory) COMMAND_CASE('M', WriteMemory)
COMMAND_CASE('p', ReadRegister) COMMAND_CASE('p', ReadRegister)
COMMAND_CASE('P', WriteRegister) COMMAND_CASE('P', WriteRegister)
COMMAND_CASE('q', ReadQuery) COMMAND_CASE('q', Query)
COMMAND_CASE('Q', WriteQuery) COMMAND_CASE('Q', Query)
//COMMAND_CASE('s', ContinueOrStepDeprecated) //COMMAND_CASE('s', ContinueOrStepDeprecated)
//COMMAND_CASE('S', ContinueOrStepDeprecated) //COMMAND_CASE('S', ContinueOrStepDeprecated)
COMMAND_CASE('T', IsThreadAlive) COMMAND_CASE('T', IsThreadAlive)

View file

@ -36,7 +36,7 @@
#define DECLARE_QUERY_HANDLER(name) DECLARE_HANDLER(Query##name) #define DECLARE_QUERY_HANDLER(name) DECLARE_HANDLER(Query##name)
#define DECLARE_VERBOSE_HANDLER(name) DECLARE_HANDLER(Verbose##name) #define DECLARE_VERBOSE_HANDLER(name) DECLARE_HANDLER(Verbose##name)
#define DECLARE_REMOTE_HANDLER(name) DECLARE_HANDLER(Remote##name) #define DECLARE_REMOTE_HANDLER(name) DECLARE_HANDLER(Remote##name)
#define DECLARE_XFER_HANDLER(name) DECLARE_HANDLER(Xfer##name) #define DECLARE_XFER_HANDLER(name) int HandleXfer##name(bool write, std::string_view annex, size_t offset, size_t length)
struct DebugEventInfo; struct DebugEventInfo;
@ -95,7 +95,7 @@ namespace ams::hvisor::gdb {
uintptr_t m_currentHioRequestTargetAddr = 0ul; uintptr_t m_currentHioRequestTargetAddr = 0ul;
PackedGdbHioRequest m_currentHioRequest{}; PackedGdbHioRequest m_currentHioRequest{};
size_t m_targetXmlLen = 0; std::string_view m_targetXml{};
char m_commandLetter = '\0'; char m_commandLetter = '\0';
std::string_view m_commandData{}; std::string_view m_commandData{};
@ -146,8 +146,7 @@ namespace ams::hvisor::gdb {
private: private:
// Meta // Meta
DECLARE_HANDLER(Unsupported); DECLARE_HANDLER(Unsupported);
DECLARE_HANDLER(ReadQuery); DECLARE_HANDLER(Query);
DECLARE_HANDLER(WriteQuery);
DECLARE_QUERY_HANDLER(Xfer); DECLARE_QUERY_HANDLER(Xfer);
DECLARE_HANDLER(VerboseCommand); DECLARE_HANDLER(VerboseCommand);

View file

@ -43,6 +43,7 @@
#define GDB_DEFINE_QUERY_HANDLER(name) GDB_DEFINE_HANDLER(Query##name) #define GDB_DEFINE_QUERY_HANDLER(name) GDB_DEFINE_HANDLER(Query##name)
#define GDB_DEFINE_VERBOSE_HANDLER(name) GDB_DEFINE_HANDLER(Verbose##name) #define GDB_DEFINE_VERBOSE_HANDLER(name) GDB_DEFINE_HANDLER(Verbose##name)
#define GDB_DEFINE_REMOTE_COMMAND_HANDLER(name) GDB_DEFINE_HANDLER(RemoteCommand##name) #define GDB_DEFINE_REMOTE_COMMAND_HANDLER(name) GDB_DEFINE_HANDLER(RemoteCommand##name)
#define GDB_DECLARE_XFER_HANDLER(name) GDB_DEFINE_HANDLER(Xfer##name) #define GDB_DEFINE_XFER_HANDLER(name)\
int Context::GDB_XFER_HANDLER(name)(bool write, std::string_view annex, size_t offset, size_t length)
#define GDB_TEST_NO_CMD_DATA() do { if (!m_commandData.empty()) return ReplyErrno(EILSEQ); } while (false) #define GDB_CHECK_NO_CMD_DATA() do { if (!m_commandData.empty()) return ReplyErrno(EILSEQ); } while (false)

View file

@ -119,16 +119,16 @@ namespace ams::hvisor::gdb {
// Check separators // Check separators
if (i != N - 1) { if (i != N - 1) {
if (str.empty() || str[0] != sep)) { if (str.empty() || str[0] != sep) {
return res; return res;
} }
str.remove_prefix(1); str.remove_prefix(1);
++total; ++total;
} else if (i == N - 1) { } else if (i == N - 1) {
if (lastSep == '\0') && !str.empty()) { if ((lastSep == '\0') && !str.empty()) {
return res; return res;
} else if (lastSep != '\0') { } else if (lastSep != '\0') {
if (str.empty() || str[0] != lastSep)) { if (str.empty() || str[0] != lastSep) {
return res; return res;
} }
str.remove_prefix(1); str.remove_prefix(1);
@ -150,6 +150,28 @@ namespace ams::hvisor::gdb {
return ParseIntegerList<N>(str, 16, false, ',', lastSep); return ParseIntegerList<N>(str, 16, false, ',', lastSep);
} }
template<size_t N>
constexpr auto SplitString(std::string_view data, char delim)
{
static_assert(N != 0);
std::array<std::string_view, N> res = {};
size_t delimPos = 0;
for (size_t i = 0; i < N - 1; i++) {
delimPos = data.find(delim);
if (delimPos == std::string_view::npos) {
return res;
}
res[i] = std::string_view{data.data(), delimPos};
data.remove_prefix(delimPos + 1);
}
res[N - 1] = data;
return res;
}
constexpr std::optional<u8> DecodeHexByte(std::string_view data) constexpr std::optional<u8> DecodeHexByte(std::string_view data)
{ {
if (data.size() < 2) { if (data.size() < 2) {

View file

@ -0,0 +1,107 @@
/*
* Copyright (c) 2019-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* This file is part of Luma3DS.
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
*
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
*/
#include "hvisor_gdb_defines_internal.hpp"
#include "hvisor_gdb_packet_data.hpp"
namespace ams::hvisor::gdb {
GDB_DEFINE_QUERY_HANDLER(Supported)
{
// Ignore what gdb sent...
return SendFormattedPacket(
"PacketSize=%x;"
"qXfer:features:read+;"
"QStartNoAckMode+;QThreadEvents+"
"vContSupported+;swbreak+;hwbreak+",
GDB_BUF_LEN
);
}
GDB_DEFINE_QUERY_HANDLER(StartNoAckMode)
{
GDB_CHECK_NO_CMD_DATA();
m_noAckSent = true;
return ReplyOk();
}
GDB_DEFINE_QUERY_HANDLER(Attached)
{
GDB_CHECK_NO_CMD_DATA();
return SendPacket("1");
}
#define QUERY_CMD_CASE2(name, fun) if (cmdName==name) { return GDB_QUERY_HANDLER(fun)(); } else
#define QUERY_CMD_CASE(fun) QUERY_CMD_CASE2(STRINGIZE(fun), fun)
GDB_DEFINE_HANDLER(Query)
{
// Extract name
char delim = ':';
size_t delimPos = m_commandData.find_first_of(":,");
std::string_view cmdName = m_commandData;
if (delimPos != std::string_view::npos) {
delim = m_commandData[delimPos];
cmdName.remove_suffix(cmdName.size() - delimPos);
m_commandData.remove_prefix(delimPos + 1);
}
// Only 2 commands are delimited by a comma, all with lowercase 'q' prefix
// We don't handle qP nor qL
if (delim != ':') {
if (m_commandLetter != 'q') {
return ReplyErrno(EILSEQ);
} else if (cmdName != "Rcmd" && cmdName != "ThreadExtraInfo") {
return ReplyErrno(EILSEQ);
}
}
if (m_commandLetter == 'q') {
QUERY_CMD_CASE(Supported)
QUERY_CMD_CASE(Xfer)
QUERY_CMD_CASE(Attached)
QUERY_CMD_CASE(fThreadInfo)
QUERY_CMD_CASE(sThreadInfo)
QUERY_CMD_CASE(ThreadExtraInfo)
QUERY_CMD_CASE2("C", CurrentThreadId)
QUERY_CMD_CASE(Rcmd)
/*default :*/{
return HandleUnsupported();
}
} else {
QUERY_CMD_CASE(StartNoAckMode)
QUERY_CMD_CASE(ThreadEvents)
/*default :*/{
return HandleUnsupported();
}
}
}
#undef QUERY_CMD_CASE
#undef QUERY_CMD_CASE2
}

View file

@ -75,7 +75,7 @@ namespace ams::hvisor::gdb {
GDB_DEFINE_HANDLER(ReadRegisters) GDB_DEFINE_HANDLER(ReadRegisters)
{ {
ENSURE(m_selectedCoreId == currentCoreCtx->coreId); ENSURE(m_selectedCoreId == currentCoreCtx->coreId);
GDB_TEST_NO_CMD_DATA(); GDB_CHECK_NO_CMD_DATA();
ExceptionStackFrame *frame = currentCoreCtx->guestFrame; ExceptionStackFrame *frame = currentCoreCtx->guestFrame;
FpuRegisterCache *fpuRegCache = fpuReadRegisters(); FpuRegisterCache *fpuRegCache = fpuReadRegisters();

View file

@ -96,13 +96,13 @@ namespace ams::hvisor::gdb {
GDB_DEFINE_QUERY_HANDLER(CurrentThreadId) GDB_DEFINE_QUERY_HANDLER(CurrentThreadId)
{ {
GDB_TEST_NO_CMD_DATA(); GDB_CHECK_NO_CMD_DATA();
return SendFormattedPacket("QC%x", 1 + currentCoreCtx->coreId); return SendFormattedPacket("QC%x", 1 + currentCoreCtx->coreId);
} }
GDB_DEFINE_QUERY_HANDLER(fThreadInfo) GDB_DEFINE_QUERY_HANDLER(fThreadInfo)
{ {
GDB_TEST_NO_CMD_DATA(); GDB_CHECK_NO_CMD_DATA();
// We have made our GDB packet big enough to list all the thread ids (coreIds + 1 for each coreId) // We have made our GDB packet big enough to list all the thread ids (coreIds + 1 for each coreId)
char *buf = GetInPlaceOutputBuffer(); char *buf = GetInPlaceOutputBuffer();
@ -120,7 +120,7 @@ namespace ams::hvisor::gdb {
GDB_DEFINE_QUERY_HANDLER(sThreadInfo) GDB_DEFINE_QUERY_HANDLER(sThreadInfo)
{ {
GDB_TEST_NO_CMD_DATA(); GDB_CHECK_NO_CMD_DATA();
// We have made our GDB packet big enough to list all the thread ids (coreIds + 1 for each coreId) in fThreadInfo // We have made our GDB packet big enough to list all the thread ids (coreIds + 1 for each coreId) in fThreadInfo
// Note: we assume GDB doesn't accept notifications during the sequence transfer... // Note: we assume GDB doesn't accept notifications during the sequence transfer...

View file

@ -0,0 +1,143 @@
/*
* Copyright (c) 2019-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* This file is part of Luma3DS.
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
*
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
*/
#include "hvisor_gdb_defines_internal.hpp"
#include "hvisor_gdb_packet_data.hpp"
namespace {
std::string_view GenerateTargetXml(char *buf)
{
int pos;
const char *hdr = "<?xml version=\"1.0\"?><!DOCTYPE feature SYSTEM \"gdb-target.dtd\"><target>";
const char *cpuDescBegin = "<feature name=\"org.gnu.gdb.aarch64.core\">";
const char *cpuDescEnd =
"<reg name=\"sp\" bitsize=\"64\" type=\"data_ptr\"/>"
"<reg name=\"pc\" bitsize=\"64\" type=\"code_ptr\"/>"
"<reg name=\"cpsr\" bitsize=\"32\"/></feature>";
const char *fpuDescBegin =
"<feature name=\"org.gnu.gdb.aarch64.fpu\"><vector id=\"v2d\" type=\"ieee_double\" count=\"2\"/>"
"<vector id=\"v2u\" type=\"uint64\" count=\"2\"/><vector id=\"v2i\" type=\"int64\" count=\"2\"/>"
"<vector id=\"v4f\" type=\"ieee_single\" count=\"4\"/><vector id=\"v4u\" type=\"uint32\" count=\"4\"/>"
"<vector id=\"v4i\" type=\"int32\" count=\"4\"/><vector id=\"v8u\" type=\"uint16\" count=\"8\"/>"
"<vector id=\"v8i\" type=\"int16\" count=\"8\"/><vector id=\"v16u\" type=\"uint8\" count=\"16\"/>"
"<vector id=\"v16i\" type=\"int8\" count=\"16\"/><vector id=\"v1u\" type=\"uint128\" count=\"1\"/>"
"<vector id=\"v1i\" type=\"int128\" count=\"1\"/><union id=\"vnd\"><field name=\"f\" type=\"v2d\"/>"
"<field name=\"u\" type=\"v2u\"/><field name=\"s\" type=\"v2i\"/></union><union id=\"vns\">"
"<field name=\"f\" type=\"v4f\"/><field name=\"u\" type=\"v4u\"/><field name=\"s\" type=\"v4i\"/></union>"
"<union id=\"vnh\"><field name=\"u\" type=\"v8u\"/><field name=\"s\" type=\"v8i\"/></union><union id=\"vnb\">"
"<field name=\"u\" type=\"v16u\"/><field name=\"s\" type=\"v16i\"/></union><union id=\"vnq\">"
"<field name=\"u\" type=\"v1u\"/><field name=\"s\" type=\"v1i\"/></union><union id=\"aarch64v\">"
"<field name=\"d\" type=\"vnd\"/><field name=\"s\" type=\"vns\"/><field name=\"h\" type=\"vnh\"/>"
"<field name=\"b\" type=\"vnb\"/><field name=\"q\" type=\"vnq\"/></union>";
const char *fpuDescEnd = "<reg name=\"fpsr\" bitsize=\"32\"/>\r\n<reg name=\"fpcr\" bitsize=\"32\"/>\r\n</feature>";
const char *footer = "</target>";
std::strcpy(buf, hdr);
// CPU registers
std::strcat(buf, cpuDescBegin);
pos = static_cast<int>(std::strlen(buf));
for (u32 i = 0; i < 31; i++) {
pos += std::sprintf(buf + pos, "<reg name=\"x%u\" bitsize=\"64\"/>", i);
}
std::strcat(buf, cpuDescEnd);
std::strcat(buf, fpuDescBegin);
pos = static_cast<int>(std::strlen(buf));
for (u32 i = 0; i < 32; i++) {
pos += std::sprintf(buf + pos, "<reg name=\"v%u\" bitsize=\"128\" type=\"aarch64v\"/>", i);
}
std::strcat(buf, fpuDescEnd);
std::strcat(buf, footer);
return std::string_view{buf};
}
}
namespace ams::hvisor::gdb {
GDB_DEFINE_XFER_HANDLER(Features)
{
if (write || annex != "target.xml") {
return ReplyEmpty();
}
// 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 (m_targetXml.empty()) {
m_targetXml = GenerateTargetXml(m_workBuffer);
}
int n = SendStreamData(m_targetXml, offset, length, false);
// Transfer ended
if(offset + length >= m_targetXml.size()) {
m_targetXml = {};
}
return n;
}
GDB_DEFINE_QUERY_HANDLER(Xfer)
{
// e.g. qXfer:features:read:annex:offset,length
// Split
auto [cmd, directionStr, annex, offsetlen] = SplitString<4>(m_commandData, ':');
if (offsetlen.empty()) {
return ReplyErrno(EILSEQ);
}
// Check direction
bool isWrite;
if (directionStr == "read") {
isWrite = false;
} else if (directionStr == "write") {
isWrite = true;
} else {
return ReplyErrno(EILSEQ);
}
// Get offset and length
auto [nread, off, len] = ParseHexIntegerList<2>(offsetlen, isWrite ? ':' : '\0');
if (nread == 0) {
return ReplyErrno(EILSEQ);
}
// Get data/nothing
m_commandData = offsetlen;
m_commandData.remove_prefix(nread);
// Run command
if (cmd == "features") {
return HandleXferFeatures(isWrite, annex, off, len);
} else {
return HandleUnsupported();
}
}
}

View file

@ -1,108 +0,0 @@
/*
* This file is part of Luma3DS.
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
*
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
*/
#include <string.h>
#include "../utils.h"
#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;
#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(STRINGIZE(name), name, direction)
static const struct {
const char *name;
GDBCommandHandler handler;
GDBQueryDirection direction;
} gdbQueryHandlers[] =
{
GDB_QUERY_HANDLER_LIST_ITEM(Supported, READ),
GDB_QUERY_HANDLER_LIST_ITEM(Xfer, READ),
GDB_QUERY_HANDLER_LIST_ITEM(StartNoAckMode, WRITE),
GDB_QUERY_HANDLER_LIST_ITEM(Attached, READ),
GDB_QUERY_HANDLER_LIST_ITEM(fThreadInfo, READ),
GDB_QUERY_HANDLER_LIST_ITEM(sThreadInfo, READ),
GDB_QUERY_HANDLER_LIST_ITEM(ThreadEvents, WRITE),
GDB_QUERY_HANDLER_LIST_ITEM(ThreadExtraInfo, READ),
GDB_QUERY_HANDLER_LIST_ITEM_3("C", CurrentThreadId, READ),
GDB_QUERY_HANDLER_LIST_ITEM_3("Search", SearchMemory, READ),
GDB_QUERY_HANDLER_LIST_ITEM(Rcmd, READ),
};
static int GDB_HandleQuery(GDBContext *ctx, GDBQueryDirection direction)
{
char *nameBegin = ctx->commandData; // w/o leading 'q'/'Q'
if(*nameBegin == 0)
return GDB_ReplyErrno(ctx, EILSEQ);
char *nameEnd;
char *queryData = NULL;
for(nameEnd = nameBegin; *nameEnd != 0 && *nameEnd != ':' && *nameEnd != ','; nameEnd++);
if(*nameEnd != 0)
{
*nameEnd = 0;
queryData = nameEnd + 1;
}
else
queryData = nameEnd;
for(u32 i = 0; i < sizeof(gdbQueryHandlers) / sizeof(gdbQueryHandlers[0]); i++)
{
if(strcmp(gdbQueryHandlers[i].name, nameBegin) == 0 && gdbQueryHandlers[i].direction == direction)
{
ctx->commandData = queryData;
return gdbQueryHandlers[i].handler(ctx);
}
}
return GDB_HandleUnsupported(ctx); // No handler found!
}
int GDB_HandleReadQuery(GDBContext *ctx)
{
return GDB_HandleQuery(ctx, GDB_QUERY_DIRECTION_READ);
}
int GDB_HandleWriteQuery(GDBContext *ctx)
{
return GDB_HandleQuery(ctx, GDB_QUERY_DIRECTION_WRITE);
}
GDB_DECLARE_QUERY_HANDLER(Supported)
{
// TODO!
return GDB_SendFormattedPacket(ctx,
"PacketSize=%x;"
"qXfer:features:read+;"
"QStartNoAckMode+;QThreadEvents+"
"vContSupported+;swbreak+;hwbreak+",
GDB_BUF_LEN // should have been sizeof(ctx->buffer) but GDB memory functions are bugged
);
}
GDB_DECLARE_QUERY_HANDLER(StartNoAckMode)
{
ctx->noAckSent = true;
return GDB_ReplyOk(ctx);
}
GDB_DECLARE_QUERY_HANDLER(Attached)
{
return GDB_SendPacket(ctx, "1", 1);
}

View file

@ -1,12 +0,0 @@
/*
* This file is part of Luma3DS.
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
*
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
*/
#pragma once
#include "context.h"

View file

@ -1,162 +0,0 @@
/*
* This file is part of Luma3DS.
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
*
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
*/
#include <string.h>
#include <stdio.h>
#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 = "<?xml version=\"1.0\"?><!DOCTYPE feature SYSTEM \"gdb-target.dtd\"><target>";
const char *cpuDescBegin = "<feature name=\"org.gnu.gdb.aarch64.core\">";
const char *cpuDescEnd =
"<reg name=\"sp\" bitsize=\"64\" type=\"data_ptr\"/>"
"<reg name=\"pc\" bitsize=\"64\" type=\"code_ptr\"/>"
"<reg name=\"cpsr\" bitsize=\"32\"/></feature>";
const char *fpuDescBegin =
"<feature name=\"org.gnu.gdb.aarch64.fpu\"><vector id=\"v2d\" type=\"ieee_double\" count=\"2\"/>"
"<vector id=\"v2u\" type=\"uint64\" count=\"2\"/><vector id=\"v2i\" type=\"int64\" count=\"2\"/>"
"<vector id=\"v4f\" type=\"ieee_single\" count=\"4\"/><vector id=\"v4u\" type=\"uint32\" count=\"4\"/>"
"<vector id=\"v4i\" type=\"int32\" count=\"4\"/><vector id=\"v8u\" type=\"uint16\" count=\"8\"/>"
"<vector id=\"v8i\" type=\"int16\" count=\"8\"/><vector id=\"v16u\" type=\"uint8\" count=\"16\"/>"
"<vector id=\"v16i\" type=\"int8\" count=\"16\"/><vector id=\"v1u\" type=\"uint128\" count=\"1\"/>"
"<vector id=\"v1i\" type=\"int128\" count=\"1\"/><union id=\"vnd\"><field name=\"f\" type=\"v2d\"/>"
"<field name=\"u\" type=\"v2u\"/><field name=\"s\" type=\"v2i\"/></union><union id=\"vns\">"
"<field name=\"f\" type=\"v4f\"/><field name=\"u\" type=\"v4u\"/><field name=\"s\" type=\"v4i\"/></union>"
"<union id=\"vnh\"><field name=\"u\" type=\"v8u\"/><field name=\"s\" type=\"v8i\"/></union><union id=\"vnb\">"
"<field name=\"u\" type=\"v16u\"/><field name=\"s\" type=\"v16i\"/></union><union id=\"vnq\">"
"<field name=\"u\" type=\"v1u\"/><field name=\"s\" type=\"v1i\"/></union><union id=\"aarch64v\">"
"<field name=\"d\" type=\"vnd\"/><field name=\"s\" type=\"vns\"/><field name=\"h\" type=\"vnh\"/>"
"<field name=\"b\" type=\"vnb\"/><field name=\"q\" type=\"vnq\"/></union>";
const char *fpuDescEnd = "<reg name=\"fpsr\" bitsize=\"32\"/>\r\n<reg name=\"fpcr\" bitsize=\"32\"/>\r\n</feature>";
const char *footer = "</target>";
strcpy(buf, hdr);
// CPU registers
strcat(buf, cpuDescBegin);
pos = (int)strlen(buf);
for (u32 i = 0; i < 31; i++) {
pos += sprintf(buf + pos, "<reg name=\"x%u\" bitsize=\"64\"/>", i);
}
strcat(buf, cpuDescEnd);
strcat(buf, fpuDescBegin);
pos = (int)strlen(buf);
for (u32 i = 0; i < 32; i++) {
pos += sprintf(buf + pos, "<reg name=\"v%u\" bitsize=\"128\" type=\"aarch64v\"/>", i);
}
strcat(buf, fpuDescEnd);
strcat(buf, footer);
DEBUG("target.xml length is 0x%x\n", strlen(buf));
}
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);
}