diff --git a/thermosphere/src/gdb/hvisor_gdb_context.hpp b/thermosphere/src/gdb/hvisor_gdb_context.hpp
index 6cdab8d9c..9e4647c44 100644
--- a/thermosphere/src/gdb/hvisor_gdb_context.hpp
+++ b/thermosphere/src/gdb/hvisor_gdb_context.hpp
@@ -119,9 +119,20 @@ namespace ams::hvisor::gdb {
int ReplyEmpty();
int ReplyErrno(int no);
- char *GetInPlaceOutputBuffer() const {
+ // Memory
+ int SendMemory(uintptr_t addr, size_t len, std::string_view prefix = {});
+ int WriteMemoryImpl(size_t (*decoder)(void *, const void *, size_t));
+
+ // Helpers
+ char *GetInPlaceOutputBuffer() const
+ {
return m_buffer + 1;
}
+
+ char *GetWorkBuffer() const
+ {
+ return m_workBuffer;
+ }
private:
// Meta
DECLARE_HANDLER(Unsupported);
@@ -190,7 +201,8 @@ namespace ams::hvisor::gdb {
void Acquire();
void Release();
- constexpr bool IsAttached() const {
+ constexpr bool IsAttached() const
+ {
return m_state == State::Attached;
}
};
diff --git a/thermosphere/src/gdb/hvisor_gdb_mem.cpp b/thermosphere/src/gdb/hvisor_gdb_mem.cpp
new file mode 100644
index 000000000..43e4aca37
--- /dev/null
+++ b/thermosphere/src/gdb/hvisor_gdb_mem.cpp
@@ -0,0 +1,102 @@
+/*
+ * 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 .
+ */
+
+/*
+* 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"
+
+#include "../core_ctx.h"
+#include "../guest_memory.h"
+
+namespace ams::hvisor::gdb {
+
+ int Context::SendMemory(uintptr_t addr, size_t len, std::string_view prefix)
+ {
+ char *buf = GetInPlaceOutputBuffer();
+ char *membuf = GetWorkBuffer();
+
+ size_t prefixLen = prefix.size();
+
+ if(prefixLen + 2 * len > GDB_BUF_LEN) {
+ // gdb shouldn't send requests which responses don't fit in a packet
+ return prefixLen == 0 ? ReplyErrno(ENOMEM) : -1;
+ }
+
+ size_t total = guestReadMemory(addr, len, membuf);
+
+ if (total == 0) {
+ return prefixLen == 0 ? ReplyErrno(EFAULT) : -EFAULT;
+ } else {
+ std::copy(prefix.begin(), prefix.end(), buf);
+ EncodeHex(buf + prefixLen, membuf, total);
+ return SendPacket(std::string_view{buf, prefixLen + 2 * total});
+ }
+ }
+
+ int Context::WriteMemoryImpl(size_t (*decoder)(void *, const void *, size_t))
+ {
+ char *workbuf = GetWorkBuffer();
+
+ auto [nread, addr, len] = ParseHexIntegerList<2>(m_commandData, ':');
+ if (nread == 0) {
+ return ReplyErrno(EILSEQ);
+ }
+
+ m_commandData.remove_prefix(nread);
+ if (len > m_commandData.length() / 2) {
+ // Data len field doesn't match what we got...
+ return ReplyErrno(ENOMEM);
+ }
+
+ size_t n = decoder(workbuf, m_commandData.data(), m_commandData.size());
+
+ if(n != len) {
+ // Decoding error...
+ return ReplyErrno(EILSEQ);
+ }
+
+ size_t total = guestWriteMemory(addr, len, workbuf);
+ return total == len ? ReplyOk() : ReplyErrno(EFAULT);
+ }
+
+
+ GDB_DEFINE_HANDLER(ReadMemory)
+ {
+ auto [nparsed, addr, len] = ParseHexIntegerList<2>(m_commandData);
+ if (nparsed == 0) {
+ return ReplyErrno(EILSEQ);
+ }
+
+ return SendMemory(addr, len);
+ }
+
+ GDB_DEFINE_HANDLER(WriteMemory)
+ {
+ return WriteMemoryImpl(DecodeHex);
+ }
+
+ GDB_DEFINE_HANDLER(WriteMemoryRaw)
+ {
+ return WriteMemoryImpl(UnescapeBinaryData);
+ }
+
+}
diff --git a/thermosphere/src/gdb/hvisor_gdb_packet_data.cpp b/thermosphere/src/gdb/hvisor_gdb_packet_data.cpp
index 68f1e33a0..115bc62b0 100644
--- a/thermosphere/src/gdb/hvisor_gdb_packet_data.cpp
+++ b/thermosphere/src/gdb/hvisor_gdb_packet_data.cpp
@@ -55,6 +55,11 @@ namespace ams::hvisor::gdb {
return i;
}
+ size_t DecodeHex(void *dst, const void *src, size_t len)
+ {
+ return DecodeHex(dst, std::string_view{reinterpret_cast(src), len});
+ }
+
size_t EscapeBinaryData(size_t *encodedCount, void *dst, const void *src, size_t len, size_t maxLen)
{
u8 *dst8 = reinterpret_cast(dst);
diff --git a/thermosphere/src/gdb/hvisor_gdb_packet_data.hpp b/thermosphere/src/gdb/hvisor_gdb_packet_data.hpp
index 2988659b5..838b37bbf 100644
--- a/thermosphere/src/gdb/hvisor_gdb_packet_data.hpp
+++ b/thermosphere/src/gdb/hvisor_gdb_packet_data.hpp
@@ -169,6 +169,7 @@ namespace ams::hvisor::gdb {
u8 ComputeChecksum(std::string_view packetData);
size_t EncodeHex(char *dst, const void *src, size_t len);
size_t DecodeHex(void *dst, std::string_view data);
+ size_t DecodeHex(void *dst, const void *src, size_t len);
size_t EscapeBinaryData(size_t *encodedCount, void *dst, const void *src, size_t len, size_t maxLen);
size_t UnescapeBinaryData(void *dst, const void *src, size_t len);
diff --git a/thermosphere/src/gdb/mem.c b/thermosphere/src/gdb/mem.c
deleted file mode 100644
index 2ee5ab1f0..000000000
--- a/thermosphere/src/gdb/mem.c
+++ /dev/null
@@ -1,182 +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
-#include "mem.h"
-#include "net.h"
-#include "../guest_memory.h"
-#include "../pattern_utils.h"
-
-int GDB_SendMemory(GDBContext *ctx, const char *prefix, size_t prefixLen, size_t addr, size_t len)
-{
- char *buf = ctx->buffer + 1;
- char *membuf = ctx->workBuffer;
-
- if(prefix != NULL) {
- memmove(buf, prefix, prefixLen);
- }
- else {
- prefixLen = 0;
- }
-
- if(prefixLen + 2 * len > GDB_BUF_LEN) {
- // gdb shouldn't send requests which responses don't fit in a packet
- return prefix == NULL ? GDB_ReplyErrno(ctx, ENOMEM) : -1;
- }
-
- size_t total = guestReadMemory(addr, len, membuf);
-
- if (total == 0) {
- return prefix == NULL ? GDB_ReplyErrno(ctx, EFAULT) : -EFAULT;
- } else {
- GDB_EncodeHex(buf + prefixLen, membuf, total);
- return GDB_SendPacket(ctx, buf, prefixLen + 2 * total);
- }
-}
-
-int GDB_WriteMemory(GDBContext *ctx, const void *buf, uintptr_t addr, size_t len)
-{
- size_t total = guestWriteMemory(addr, len, buf);
- return total == len ? GDB_ReplyOk(ctx) : GDB_ReplyErrno(ctx, EFAULT);
-}
-
-u32 GDB_SearchMemory(bool *found, GDBContext *ctx, uintptr_t addr, size_t len, const void *pattern, size_t patternLen)
-{
- // Note: need to ensure GDB_WORK_BUF_LEN is at least 0x1000 bytes in size
-
- u8 *buf = (u8 *)ctx->workBuffer;
- size_t maxNbPages = GDB_WORK_BUF_LEN / 0x1000;
- uintptr_t curAddr = addr;
-
- while (curAddr < addr + len) {
- size_t nbPages;
- uintptr_t addrBase = curAddr & ~0xFFF;
- size_t addrDispl = curAddr & 0xFFF;
-
- for (nbPages = 0; nbPages < maxNbPages; nbPages++) {
- if (guestReadMemory(addrBase + nbPages * 0x1000, 0x1000, buf + nbPages * 0x1000) != 0x1000) {
- break;
- }
- }
-
- u8 *pos = NULL;
- if(addrDispl + patternLen <= 0x1000 * nbPages) {
- pos = memsearch(buf + addrDispl, pattern, 0x1000 * nbPages - addrDispl, patternLen);
- }
-
- if(pos != NULL) {
- *found = true;
- return addrBase + (pos - buf);
- }
-
- curAddr = addrBase + 0x1000;
- }
-
- *found = false;
- return 0;
-}
-
-GDB_DECLARE_HANDLER(ReadMemory)
-{
- unsigned long lst[2];
- if (GDB_ParseHexIntegerList(lst, ctx->commandData, 2, 0) == NULL) {
- return GDB_ReplyErrno(ctx, EILSEQ);
- }
-
- uintptr_t addr = lst[0];
- size_t len = lst[1];
-
- return GDB_SendMemory(ctx, NULL, 0, addr, len);
-}
-
-GDB_DECLARE_HANDLER(WriteMemory)
-{
- unsigned long lst[2];
- const char *dataStart = GDB_ParseHexIntegerList(lst, ctx->commandData, 2, ':');
- if (dataStart == NULL || *dataStart != ':') {
- return GDB_ReplyErrno(ctx, EILSEQ);
- }
-
- dataStart++;
- uintptr_t addr = lst[0];
- size_t len = lst[1];
-
- if(dataStart + 2 * len >= ctx->buffer + 4 + GDB_BUF_LEN) {
- // Data len field doesn't match what we got...
- return GDB_ReplyErrno(ctx, ENOMEM);
- }
-
- size_t n = GDB_DecodeHex(ctx->workBuffer, dataStart, len);
-
- if(n != len) {
- // Decoding error...
- return GDB_ReplyErrno(ctx, EILSEQ);
- }
-
- return GDB_WriteMemory(ctx, ctx->workBuffer, addr, len);
-}
-
-GDB_DECLARE_HANDLER(WriteMemoryRaw)
-{
- unsigned long lst[2];
- const char *dataStart = GDB_ParseHexIntegerList(lst, ctx->commandData, 2, ':');
- if (dataStart == NULL || *dataStart != ':') {
- return GDB_ReplyErrno(ctx, EILSEQ);
- }
-
- dataStart++;
- uintptr_t addr = lst[0];
- size_t len = lst[1];
-
- if(dataStart + 2 * len >= ctx->buffer + 4 + GDB_BUF_LEN) {
- // Data len field doesn't match what we got...
- return GDB_ReplyErrno(ctx, ENOMEM);
- }
-
- // Note: could be done in place in ctx->buffer...
- size_t n = GDB_UnescapeBinaryData(ctx->workBuffer, dataStart, len);
-
- if(n != len) {
- // Decoding error...
- return GDB_ReplyErrno(ctx, n);
- }
-
- return GDB_WriteMemory(ctx, ctx->workBuffer, addr, len);
-}
-
-GDB_DECLARE_QUERY_HANDLER(SearchMemory)
-{
- unsigned long lst[2];
- const char *patternStart;
- size_t patternLen;
- bool found;
- u32 foundAddr;
-
- if (strncmp(ctx->commandData, "memory:", 7) != 0) {
- return GDB_ReplyErrno(ctx, EILSEQ);
- }
-
- ctx->commandData += 7;
- patternStart = GDB_ParseIntegerList(lst, ctx->commandData, 2, ';', ';', 16, false);
- if (patternStart == NULL || *patternStart != ';') {
- return GDB_ReplyErrno(ctx, EILSEQ);
- }
-
- uintptr_t addr = lst[0];
- size_t len = lst[1];
-
- patternStart++;
- patternLen = ctx->commandEnd - patternStart;
-
- // Unescape pattern in place
- char *pattern = (char *)patternStart;
- patternLen = GDB_UnescapeBinaryData(pattern, patternStart, patternLen);
-
- foundAddr = GDB_SearchMemory(&found, ctx, addr, len, patternStart, patternLen);
-
- return found ? GDB_SendFormattedPacket(ctx, "1,%x", foundAddr) : GDB_SendPacket(ctx, "0", 1);
-}
diff --git a/thermosphere/src/gdb/mem.h b/thermosphere/src/gdb/mem.h
deleted file mode 100644
index 264f73f5f..000000000
--- a/thermosphere/src/gdb/mem.h
+++ /dev/null
@@ -1,14 +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"
-
-int GDB_SendMemory(GDBContext *ctx, const char *prefix, size_t prefixLen, uintptr_t addr, size_t len);
-int GDB_WriteMemory(GDBContext *ctx, const void *buf, uintptr_t addr, size_t len);
-u32 GDB_SearchMemory(bool *found, GDBContext *ctx, size_t addr, size_t len, const void *pattern, size_t patternLen);