diff --git a/thermosphere/src/gdb/hvisor_gdb_context.hpp b/thermosphere/src/gdb/hvisor_gdb_context.hpp
index 9e4647c44..4245cc30f 100644
--- a/thermosphere/src/gdb/hvisor_gdb_context.hpp
+++ b/thermosphere/src/gdb/hvisor_gdb_context.hpp
@@ -35,6 +35,7 @@
#define DECLARE_HANDLER(name) int Handle##name()
#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)
namespace ams::hvisor::gdb {
@@ -211,4 +212,5 @@ namespace ams::hvisor::gdb {
#undef DECLARE_HANDLER
#undef DECLARE_QUERY_HANDLER
#undef DECLARE_VERBOSE_HANDLER
+#undef DECLARE_REMOTE_HANDLER
#undef DECLARE_XFER_HANDLER
diff --git a/thermosphere/src/gdb/hvisor_gdb_defines_internal.hpp b/thermosphere/src/gdb/hvisor_gdb_defines_internal.hpp
index 9b48fb2b9..4bfc7e6cf 100644
--- a/thermosphere/src/gdb/hvisor_gdb_defines_internal.hpp
+++ b/thermosphere/src/gdb/hvisor_gdb_defines_internal.hpp
@@ -36,9 +36,11 @@
#define GDB_HANDLER(name) Handle##name
#define GDB_QUERY_HANDLER(name) GDB_HANDLER(Query##name)
#define GDB_VERBOSE_HANDLER(name) GDB_HANDLER(Verbose##name)
+#define GDB_REMOTE_COMMAND_HANDLER(name) GDB_HANDLER(RemoteCommand##name)
#define GDB_XFER_HANDLER(name) GDB_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)
+#define GDB_DEFINE_HANDLER(name) int Context::GDB_HANDLER(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_REMOTE_COMMAND_HANDLER(name) GDB_DEFINE_HANDLER(RemoteCommand##name)
+#define GDB_DECLARE_XFER_HANDLER(name) GDB_DEFINE_HANDLER(Xfer##name)
diff --git a/thermosphere/src/gdb/hvisor_gdb_remote_command.cpp b/thermosphere/src/gdb/hvisor_gdb_remote_command.cpp
new file mode 100644
index 000000000..42a88db27
--- /dev/null
+++ b/thermosphere/src/gdb/hvisor_gdb_remote_command.cpp
@@ -0,0 +1,75 @@
+/*
+ * 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"
+
+namespace {
+
+ constexpr std::string_view SkipSpaces(std::string_view str)
+ {
+ size_t n = str.find_first_not_of("\t\v\n\f\r ");
+ if (n == std::string_view::npos) {
+ return {};
+ } else {
+ str.remove_prefix(n);
+ return str;
+ }
+ }
+
+}
+
+namespace ams::hvisor::gdb {
+
+ GDB_DEFINE_QUERY_HANDLER(Rcmd)
+ {
+ char *buf = GetInPlaceOutputBuffer();
+ size_t encodedLen = m_commandData.size();
+ if (encodedLen == 0 || encodedLen % 2 != 0) {
+ ReplyErrno(EILSEQ);
+ }
+
+ // Decode in place
+ if (DecodeHex(buf, m_commandData) != encodedLen / 2) {
+ ReplyErrno(EILSEQ);
+ }
+
+ // Extract command name, data
+ m_commandData = std::string_view{buf, encodedLen / 2};
+ size_t nameSize = m_commandData.find_first_of("\t\v\n\f\r ");
+ std::string_view commandName = m_commandData;
+ if (nameSize != std::string_view::npos) {
+ commandName.remove_suffix(commandName.size() - nameSize);
+ m_commandData.remove_prefix(nameSize);
+ m_commandData = SkipSpaces(m_commandData);
+ } else {
+ m_commandData = std::string_view{};
+ }
+
+ // Nothing implemented yet
+ (void)commandName;
+
+ return SendHexPacket("Unrecognized command.\n");
+ }
+
+}
diff --git a/thermosphere/src/gdb/remote_command.c b/thermosphere/src/gdb/remote_command.c
deleted file mode 100644
index cb36a9bd0..000000000
--- a/thermosphere/src/gdb/remote_command.c
+++ /dev/null
@@ -1,51 +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 "remote_command.h"
-#include "net.h"
-struct
-{
- const char *name;
- GDBCommandHandler handler;
-} remoteCommandHandlers[] = {
-};
-
-static const char *GDB_SkipSpaces(const char *pos)
-{
- const char *nextpos;
- for (nextpos = pos; *nextpos != 0 && ((*nextpos >= 9 && *nextpos <= 13) || *nextpos == ' '); nextpos++);
- return nextpos;
-}
-
-GDB_DECLARE_QUERY_HANDLER(Rcmd)
-{
- char commandData[GDB_BUF_LEN / 2 + 1];
- char *endpos;
- const char *errstr = "Unrecognized command.\n";
- size_t len = strlen(ctx->commandData);
-
- if(len == 0 || (len % 2) == 1 || GDB_DecodeHex(commandData, ctx->commandData, len / 2) != len / 2) {
- return GDB_ReplyErrno(ctx, EILSEQ);
- }
- commandData[len / 2] = 0;
-
- for (endpos = commandData; !(*endpos >= 9 && *endpos <= 13) && *endpos != ' ' && *endpos != 0; endpos++);
-
- char *nextpos = (char *)GDB_SkipSpaces(endpos);
- *endpos = 0;
-
- for (size_t i = 0; i < sizeof(remoteCommandHandlers) / sizeof(remoteCommandHandlers[0]); i++) {
- if (strcmp(commandData, remoteCommandHandlers[i].name) == 0) {
- ctx->commandData = nextpos;
- return remoteCommandHandlers[i].handler(ctx);
- }
- }
-
- return GDB_SendHexPacket(ctx, errstr, strlen(errstr));
-}
diff --git a/thermosphere/src/gdb/remote_command.h b/thermosphere/src/gdb/remote_command.h
deleted file mode 100644
index be89bea6a..000000000
--- a/thermosphere/src/gdb/remote_command.h
+++ /dev/null
@@ -1,15 +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"
-
-#define GDB_REMOTE_COMMAND_HANDLER(name) GDB_HANDLER(RemoteCommand##name)
-#define GDB_DECLARE_REMOTE_COMMAND_HANDLER(name) GDB_DECLARE_HANDLER(RemoteCommand##name)
-
-GDB_DECLARE_QUERY_HANDLER(Rcmd);