mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 20:31:14 +00:00
thermospshere: c++ify xfer, query, etc. More string parsing utilities
This commit is contained in:
parent
ff2c835b0a
commit
192d2db4a9
11 changed files with 287 additions and 297 deletions
|
@ -137,8 +137,8 @@ namespace ams::hvisor::gdb {
|
|||
COMMAND_CASE('M', WriteMemory)
|
||||
COMMAND_CASE('p', ReadRegister)
|
||||
COMMAND_CASE('P', WriteRegister)
|
||||
COMMAND_CASE('q', ReadQuery)
|
||||
COMMAND_CASE('Q', WriteQuery)
|
||||
COMMAND_CASE('q', Query)
|
||||
COMMAND_CASE('Q', Query)
|
||||
//COMMAND_CASE('s', ContinueOrStepDeprecated)
|
||||
//COMMAND_CASE('S', ContinueOrStepDeprecated)
|
||||
COMMAND_CASE('T', IsThreadAlive)
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
#define DECLARE_QUERY_HANDLER(name) DECLARE_HANDLER(Query##name)
|
||||
#define DECLARE_VERBOSE_HANDLER(name) DECLARE_HANDLER(Verbose##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;
|
||||
|
||||
|
@ -95,7 +95,7 @@ namespace ams::hvisor::gdb {
|
|||
uintptr_t m_currentHioRequestTargetAddr = 0ul;
|
||||
PackedGdbHioRequest m_currentHioRequest{};
|
||||
|
||||
size_t m_targetXmlLen = 0;
|
||||
std::string_view m_targetXml{};
|
||||
|
||||
char m_commandLetter = '\0';
|
||||
std::string_view m_commandData{};
|
||||
|
@ -146,8 +146,7 @@ namespace ams::hvisor::gdb {
|
|||
private:
|
||||
// Meta
|
||||
DECLARE_HANDLER(Unsupported);
|
||||
DECLARE_HANDLER(ReadQuery);
|
||||
DECLARE_HANDLER(WriteQuery);
|
||||
DECLARE_HANDLER(Query);
|
||||
DECLARE_QUERY_HANDLER(Xfer);
|
||||
DECLARE_HANDLER(VerboseCommand);
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#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_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)
|
||||
|
|
|
@ -119,16 +119,16 @@ namespace ams::hvisor::gdb {
|
|||
|
||||
// Check separators
|
||||
if (i != N - 1) {
|
||||
if (str.empty() || str[0] != sep)) {
|
||||
if (str.empty() || str[0] != sep) {
|
||||
return res;
|
||||
}
|
||||
str.remove_prefix(1);
|
||||
++total;
|
||||
} else if (i == N - 1) {
|
||||
if (lastSep == '\0') && !str.empty()) {
|
||||
if ((lastSep == '\0') && !str.empty()) {
|
||||
return res;
|
||||
} else if (lastSep != '\0') {
|
||||
if (str.empty() || str[0] != lastSep)) {
|
||||
if (str.empty() || str[0] != lastSep) {
|
||||
return res;
|
||||
}
|
||||
str.remove_prefix(1);
|
||||
|
@ -150,6 +150,28 @@ namespace ams::hvisor::gdb {
|
|||
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)
|
||||
{
|
||||
if (data.size() < 2) {
|
||||
|
|
107
thermosphere/src/gdb/hvisor_gdb_query.cpp
Normal file
107
thermosphere/src/gdb/hvisor_gdb_query.cpp
Normal 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
|
||||
|
||||
}
|
|
@ -75,7 +75,7 @@ namespace ams::hvisor::gdb {
|
|||
GDB_DEFINE_HANDLER(ReadRegisters)
|
||||
{
|
||||
ENSURE(m_selectedCoreId == currentCoreCtx->coreId);
|
||||
GDB_TEST_NO_CMD_DATA();
|
||||
GDB_CHECK_NO_CMD_DATA();
|
||||
|
||||
ExceptionStackFrame *frame = currentCoreCtx->guestFrame;
|
||||
FpuRegisterCache *fpuRegCache = fpuReadRegisters();
|
||||
|
|
|
@ -96,13 +96,13 @@ namespace ams::hvisor::gdb {
|
|||
|
||||
GDB_DEFINE_QUERY_HANDLER(CurrentThreadId)
|
||||
{
|
||||
GDB_TEST_NO_CMD_DATA();
|
||||
GDB_CHECK_NO_CMD_DATA();
|
||||
return SendFormattedPacket("QC%x", 1 + currentCoreCtx->coreId);
|
||||
}
|
||||
|
||||
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)
|
||||
char *buf = GetInPlaceOutputBuffer();
|
||||
|
@ -120,7 +120,7 @@ namespace ams::hvisor::gdb {
|
|||
|
||||
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
|
||||
// Note: we assume GDB doesn't accept notifications during the sequence transfer...
|
||||
|
|
143
thermosphere/src/gdb/hvisor_gdb_xfer.cpp
Normal file
143
thermosphere/src/gdb/hvisor_gdb_xfer.cpp
Normal 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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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"
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
Loading…
Reference in a new issue