thermosphere: cpp rewrite: constexpr string parsing, rewrote gdb/thread

This commit is contained in:
TuxSH 2020-02-05 18:26:19 +00:00
parent b445fe1bf4
commit 2077062b79
9 changed files with 252 additions and 168 deletions

View file

@ -27,6 +27,8 @@
#include "../defines.hpp"
#include "../transport_interface.h"
#include <string_view>
#define _REENT_ONLY
#include <cerrno>
@ -35,7 +37,7 @@
#define DECLARE_VERBOSE_HANDLER(name) DECLARE_HANDLER(Verbose##name)
#define DECLARE_XFER_HANDLER(name) DECLARE_HANDLER(Xfer##name)
namespace ams::hyp::gdb {
namespace ams::hvisor::gdb {
struct PackedGdbHioRequest {
// TODO revamp
@ -79,8 +81,8 @@ namespace ams::hyp::gdb {
u32 m_attachedCoreList = 0;
int m_selectedThreadId = 0;
int m_selectedThreadIdForContinuing = 0;
int m_selectedCoreId = 0;
int m_selectedCoreIdForContinuing = 0;
u32 m_sentDebugEventCoreList = 0;
u32 m_acknowledgedDebugEventCoreList = 0;
@ -97,8 +99,8 @@ namespace ams::hyp::gdb {
size_t m_targetXmlLen = 0;
char *m_commandData = nullptr;
char *m_commandEnd = nullptr;
char m_commandLetter = '\0';
std::string_view m_commandData{};
size_t m_lastSentPacketSize = 0ul;
char *m_buffer = nullptr;
char *m_workBuffer = nullptr;
@ -109,11 +111,12 @@ namespace ams::hyp::gdb {
// Comms
int ReceivePacket();
int DoSendPacket();
int SendPacket(const char *packetData, size_t len);
int SendPacket(std::string_view packetData);
int SendFormattedPacket(const char *packetDataFmt, ...);
int SendHexPacket(const void *packetData, size_t len);
int SendNotificationPacket(const char *packetData, size_t len);
int SendStreamData(const char *streamData, size_t offset, size_t length, size_t totalSize, bool forceEmptyLast);
int SendNotificationPacket(std::string_view packetData);
int SendStreamData(std::string_view streamData, size_t offset, size_t length, bool forceEmptyLast);
int ReplyOk();
int ReplyEmpty();
int ReplyErrno(int no);

View file

@ -24,7 +24,7 @@
#pragma once
#include "hyp_gdb_context.hpp"
#include "hvisor_gdb_context.hpp"
// 512+24 is the ideal size as IDA will try to read exactly 0x100 bytes at a time.
// IDA seems to want additional bytes as well.
@ -38,7 +38,7 @@
#define GDB_VERBOSE_HANDLER(name) GDB_HANDLER(Verbose##name)
#define GDB_XFER_HANDLER(name) GDB_HANDLER(Xfer##name)
#define GDB_DEFINE_HANDLER(name) int Context::HANDLER(name)()
#define GDB_DEFINE_QUERY_HANDLER(name) DEFINE_HANDLER(Query##name)
#define GDB_DECLARE_VERBOSE_HANDLER(name) DEFINE_HANDLER(Verbose##name)
#define GDB_DECLARE_Xfer_HANDLER(name) DEFINE_HANDLER(Xfer##name)
#define GDB_DEFINE_HANDLER(name) int Context::GDB_HANDLER(name)()
#define GDB_DEFINE_QUERY_HANDLER(name) GDB_DEFINE_HANDLER(Query##name)
#define GDB_DECLARE_VERBOSE_HANDLER(name) GDB_DEFINE_HANDLER(Verbose##name)
#define GDB_DECLARE_XFER_HANDLER(name) GDB_DEFINE_HANDLER(Xfer##name)

View file

@ -16,10 +16,11 @@
#pragma once
#include "hyp_gdb_packet_data.hpp"
#include "hvisor_gdb_packet_data.hpp"
#include <cctype>
namespace ams::hyp::gdb {
namespace ams::hvisor::gdb {
u8 ComputeChecksum(std::string_view packetData)
{
return std::accumulate(packetData.cbegin(), packetData.cend(), u8{0u});
@ -98,4 +99,5 @@ namespace ams::hyp::gdb {
return dst8 - reinterpret_cast<u8 *>(dst);
}
}

View file

@ -19,7 +19,7 @@
#include "../defines.hpp"
#include <string_view>
namespace ams::hyp::gdb {
namespace ams::hvisor::gdb {
constexpr unsigned long DecodeHexDigit(char src)
{
@ -36,7 +36,9 @@ namespace ams::hyp::gdb {
{
unsigned long res = 0;
long mult = 1;
auto errval = std::tuple{false, 0ul, str.end()};
auto errval = std::tuple{0ul, 0ul};
size_t total = 0;
if ((base == 0 && !allowPrefix) || base > 16 || str.empty()) {
return errval;
@ -48,12 +50,14 @@ namespace ams::hyp::gdb {
return errval;
}
str.remove_prefix(1);
++total;
} else if (str[0] == '-') {
if (!allowPrefix) {
return errval;
}
str.remove_prefix(1);
mult = -1;
++total;
}
if (str.empty()) {
@ -68,11 +72,9 @@ namespace ams::hyp::gdb {
} else {
str.remove_prefix(2);
base = 16;
total += 2;
}
} else if (base == 0 || str[0] == '0') {
if (!allowPrefix) {
return errval;
}
} else if (base == 0 && str[0] == '0') {
base = 8;
} else if (base == 0) {
base = 10;
@ -92,13 +94,61 @@ namespace ams::hyp::gdb {
res *= base;
res += v;
++total;
}
return std::tuple{true, res * mult, it};
return std::tuple{total, res * mult};
}
std::string_view::iterator ParseIntegerList(unsigned long *dst, std::string_view str, size_t nb, char sep, char lastSep, u32 base, bool allowPrefix);
std::string_view::iterator ParseHexIntegerList(unsigned long *dst, std::string_view str, size_t nb, char lastSep);
template<size_t N>
constexpr auto ParseIntegerList(std::string_view str, u32 base, bool allowPrefix, char sep, char lastSep = '\0')
{
// First element is parsed size
std::array<unsigned long, 1+N> res{ 0 };
size_t total = 0;
for (size_t i = 0; i < N && !str.empty(); i++) {
auto [nread, val] = ParseInteger(str, base, allowPrefix);
// Parse failure
if (nread == 0) {
return res;
}
str.remove_prefix(nread);
// Check separators
if (i != N - 1) {
if (str.empty() || str[0] != sep)) {
return res;
}
str.remove_prefix(1);
++total;
} else if (i == N - 1) {
if (lastSep == '\0') && !str.empty()) {
return res;
} else if (lastSep != '\0') {
if (str.empty() || str[0] != lastSep)) {
return res;
}
str.remove_prefix(1);
++total;
}
}
total += nread;
res[1 + i] = val;
}
res[0] = total;
return res;
}
template<size_t N>
constexpr auto ParseHexIntegerList(std::string_view str, char lastSep = '\0')
{
return ParseIntegerList<N>(str, 16, false, ',', lastSep);
}
u8 ComputeChecksum(std::string_view packetData);
size_t EncodeHex(char *dst, const void *src, size_t len);

View file

@ -0,0 +1,147 @@
/*
* This file is part of Luma3DS.
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
*
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
*/
#include <cstdio>
#include "hvisor_gdb_defines_internal.hpp"
#include "hvisor_gdb_packet_data.hpp"
#include "../core_ctx.h"
namespace {
}
namespace ams::hvisor::gdb {
int ConvertTidToCoreId(unsigned long tid)
{
switch (tid) {
case ULONG_MAX:
return -1;
case 0:
return currentCoreCtx->coreId;
default:
return currentCoreCtx->coreId - 1;
}
}
std::optional<int> ParseConvertExactlyOneTid(std::string_view str)
{
if (str.size() == 2 && str[0] == '-' && str[1] == '1') {
return -1;
} else {
auto [n, tid] = ParseHexIntegerList<1>(str);
if (n != 0 && tid < MAX_CORE + 1) {
return ConvertTidToCoreId(tid);
} else {
return {};
}
}
}
// Hg<tid>, Hc<tid>
GDB_DEFINE_HANDLER(SetThreadId)
{
if (!m_commandData.starts_with('g') && !m_commandData.starts_with('c')) {
return ReplyErrno(EINVAL);
}
char kind = m_commandData[0];
m_commandData.remove_prefix(1);
auto coreIdOpt = ParseConvertExactlyOneTid(m_commandData);
if (!coreIdOpt) {
return ReplyErrno(EILSEQ);
}
int coreId = *coreIdOpt;
if (kind == 'g') {
if (coreId = -1) {
return ReplyErrno(EINVAL);
}
m_selectedCoreId = coreId;
MigrateRxIrq(m_selectedCoreId);
} else {
m_selectedCoreIdForContinuing = coreId;
}
return ReplyOk();
}
GDB_DEFINE_HANDLER(IsThreadAlive)
{
int coreId = ParseConvertExactlyOneTid(m_commandData).value_or(-1);
if (coreId < 0) {
return ReplyErrno(EILSEQ);
}
// Is the core off?
if (m_attachedCoreList & BIT(coreId)) {
return ReplyOk();
} else {
return ReplyErrno(ESRCH);
}
}
GDB_DEFINE_QUERY_HANDLER(CurrentThreadId)
{
return SendFormattedPacket("QC%x", 1 + currentCoreCtx->coreId);
}
GDB_DEFINE_QUERY_HANDLER(fThreadInfo)
{
// We have made our GDB packet big enough to list all the thread ids (coreIds + 1 for each coreId)
char *buf = GetInPlaceOutputBuffer();
size_t n = 0;
for (int coreId: util::BitsOf{m_attachedCoreList}) {
n += sprintf(buf + n, "%lx,", 1u + coreId);
}
// Remove trailing comma
--n;
return SendStreamData(std::string_view{buf, n}, 0, n, true);
}
GDB_DEFINE_QUERY_HANDLER(sThreadInfo)
{
// 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...
return SendPacket("l");
}
GDB_DEFINE_QUERY_HANDLER(ThreadEvents)
{
if (m_commandData.size() != 1) {
return ReplyErrno(EILSEQ);
}
switch (m_commandData[0]) {
case '0':
m_catchThreadEvents = false;
return ReplyOk();
case '1':
m_catchThreadEvents = true;
return ReplyOk();
default:
return ReplyErrno(EILSEQ);
}
}
GDB_DEFINE_QUERY_HANDLER(ThreadExtraInfo)
{
int coreId = ParseConvertExactlyOneTid(m_commandData).value_or(-1);
if (coreId < 0) {
return ReplyErrno(EILSEQ);
}
size_t n = sprintf(m_workBuffer, "TODO");
return SendHexPacket(m_workBuffer, n);
}
}

View file

@ -0,0 +1,26 @@
/*
* 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/>.
*/
#pragma once
#include "hvisor_gdb_context.hpp"
namespace ams::hvisor::gdb {
int ConvertTidToCoreId(unsigned long tid);
std::optional<int> ParseConvertExactlyOneTid(std::string_view str);
}

View file

@ -8,8 +8,3 @@
#pragma once
#include "context.h"
GDB_DECLARE_HANDLER(ReadRegisters);
GDB_DECLARE_HANDLER(WriteRegisters);
GDB_DECLARE_HANDLER(ReadRegister);
GDB_DECLARE_HANDLER(WriteRegister);

View file

@ -1,119 +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 <stdio.h>
#include <string.h>
#include "thread.h"
#include "net.h"
#include "../core_ctx.h"
GDB_DECLARE_HANDLER(SetThreadId)
{
// Id = 0 means any thread
if (ctx->commandData[0] == 'g') {
if(strcmp(ctx->commandData + 1, "-1") == 0) {
return GDB_ReplyErrno(ctx, EINVAL);
}
unsigned long id;
if (GDB_ParseHexIntegerList(&id, ctx->commandData + 1, 1, 0) == NULL) {
return GDB_ReplyErrno(ctx, EILSEQ);
} else if (id >= MAX_CORE + 1) {
return GDB_ReplyErrno(ctx, EINVAL);
}
ctx->selectedThreadId = id == 0 ? (int)currentCoreCtx->coreId + 1 : (int)id;
GDB_MigrateRxIrq(ctx, (u32)(ctx->selectedThreadId - 1));
return GDB_ReplyOk(ctx);
} else if (ctx->commandData[0] == 'c') {
if(strcmp(ctx->commandData + 1, "-1") == 0) {
ctx->selectedThreadIdForContinuing = -1;
} else {
unsigned long id;
if (GDB_ParseHexIntegerList(&id, ctx->commandData + 1, 1, 0) == NULL) {
return GDB_ReplyErrno(ctx, EILSEQ);
} else if (id >= MAX_CORE + 1) {
return GDB_ReplyErrno(ctx, EINVAL);
}
ctx->selectedThreadIdForContinuing = id == 0 ? (int)currentCoreCtx->coreId + 1 : (int)id;
}
return GDB_ReplyOk(ctx);
}
else
return GDB_ReplyErrno(ctx, EPERM);
}
GDB_DECLARE_HANDLER(IsThreadAlive)
{
unsigned long threadId;
if (GDB_ParseHexIntegerList(&threadId, ctx->commandData, 1, 0) == NULL || threadId < 1) {
return GDB_ReplyErrno(ctx, EILSEQ);
}
u32 coreMask = ctx->attachedCoreList;
return (coreMask & BIT(threadId - 1)) != 0 ? GDB_ReplyOk(ctx) : GDB_ReplyErrno(ctx, ESRCH);
}
GDB_DECLARE_QUERY_HANDLER(CurrentThreadId)
{
return GDB_SendFormattedPacket(ctx, "QC%x", 1 + currentCoreCtx->coreId);
}
GDB_DECLARE_QUERY_HANDLER(fThreadInfo)
{
// We have made our GDB packet big enough to list all the thread ids (coreIds + 1 for each coreId)
char *buf = ctx->buffer + 1;
size_t n = 0;
u32 coreMask = ctx->attachedCoreList;
FOREACH_BIT (tmp, coreId, coreMask) {
n += sprintf(buf + n, "%lx,", 1 + coreId);
}
// Remove trailing comma
buf[--n] = 0;
return GDB_SendStreamData(ctx, buf, 0, n, n, true);
}
GDB_DECLARE_QUERY_HANDLER(sThreadInfo)
{
// 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...
return GDB_SendPacket(ctx, "l", 1);
}
GDB_DECLARE_QUERY_HANDLER(ThreadEvents)
{
switch (ctx->commandData[0]) {
case '0':
ctx->catchThreadEvents = false;
return GDB_ReplyOk(ctx);
case '1':
ctx->catchThreadEvents = true;
return GDB_ReplyOk(ctx);
default:
return GDB_ReplyErrno(ctx, EILSEQ);
}
}
GDB_DECLARE_QUERY_HANDLER(ThreadExtraInfo)
{
unsigned long id;
int n;
if(GDB_ParseHexIntegerList(&id, ctx->commandData, 1, 0) == NULL)
return GDB_ReplyErrno(ctx, EILSEQ);
n = sprintf(ctx->workBuffer, "TODO");
return GDB_SendHexPacket(ctx, ctx->workBuffer, n);
}

View file

@ -1,20 +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"
GDB_DECLARE_HANDLER(SetThreadId);
GDB_DECLARE_HANDLER(IsThreadAlive);
GDB_DECLARE_QUERY_HANDLER(CurrentThreadId);
GDB_DECLARE_QUERY_HANDLER(fThreadInfo);
GDB_DECLARE_QUERY_HANDLER(sThreadInfo);
GDB_DECLARE_QUERY_HANDLER(ThreadEvents);
GDB_DECLARE_QUERY_HANDLER(ThreadExtraInfo);
GDB_DECLARE_QUERY_HANDLER(GetTLSAddr);