From 61a972abf39c89ea7f5ba709d197262308e8beb4 Mon Sep 17 00:00:00 2001
From: TuxSH <1922548+TuxSH@users.noreply.github.com>
Date: Thu, 6 Feb 2020 01:19:56 +0000
Subject: [PATCH] thermosphere: rewrite gdb/mem in c++. Remove SearchMemory
 handler

---
 thermosphere/src/gdb/hvisor_gdb_context.hpp   |  16 +-
 thermosphere/src/gdb/hvisor_gdb_mem.cpp       | 102 ++++++++++
 .../src/gdb/hvisor_gdb_packet_data.cpp        |   5 +
 .../src/gdb/hvisor_gdb_packet_data.hpp        |   1 +
 thermosphere/src/gdb/mem.c                    | 182 ------------------
 thermosphere/src/gdb/mem.h                    |  14 --
 6 files changed, 122 insertions(+), 198 deletions(-)
 create mode 100644 thermosphere/src/gdb/hvisor_gdb_mem.cpp
 delete mode 100644 thermosphere/src/gdb/mem.c
 delete mode 100644 thermosphere/src/gdb/mem.h

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 <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"
+
+#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<const char *>(src), len});
+    }
+
     size_t EscapeBinaryData(size_t *encodedCount, void *dst, const void *src, size_t len, size_t maxLen)
     {
         u8 *dst8 = reinterpret_cast<u8 *>(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 <string.h>
-#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);