diff --git a/stratosphere/dmnt.gen2/dmnt.gen2.json b/stratosphere/dmnt.gen2/dmnt.gen2.json
index b6dc58e..cd3fa9b 100644
--- a/stratosphere/dmnt.gen2/dmnt.gen2.json
+++ b/stratosphere/dmnt.gen2/dmnt.gen2.json
@@ -99,5 +99,12 @@
}, {
"type": "handle_table_size",
"value": 0
- }]
+ },
+ {
+ "type": "debug_flags",
+ "value": {
+ "allow_debug": false,
+ "force_debug": true
+ }
+ }]
}
\ No newline at end of file
diff --git a/stratosphere/dmnt.gen2/source/dmnt2_gdb_packet_parser.cpp b/stratosphere/dmnt.gen2/source/dmnt2_gdb_packet_parser.cpp
deleted file mode 100644
index a02519b..0000000
--- a/stratosphere/dmnt.gen2/source/dmnt2_gdb_packet_parser.cpp
+++ /dev/null
@@ -1,421 +0,0 @@
-/*
- * Copyright (c) 2018-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 .
- */
-#include
-#include "dmnt2_debug_log.hpp"
-#include "dmnt2_gdb_packet_parser.hpp"
-
-namespace ams::dmnt {
-
- namespace {
-
- constexpr const char TargetXmlAarch64[] =
- "l"
- ""
- ""
- "aarch64"
- "GNU/Linux"
- ""
- ""
- "";
-
- constexpr const char Aarch64CoreXml[] =
- "l\n"
- "\n"
- "\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\t\n"
- "\t\t\n"
- "\t\t\n"
- "\n"
- "\t\t\n"
- "\t\t\n"
- "\t\t\n"
- "\t\t\n"
- "\n"
- "\t\t\n"
- "\n"
- "\t\t\n"
- "\t\t\n"
- "\t\t\n"
- "\t\t\n"
- "\t\t\n"
- "\t\t\n"
- "\n"
- "\t\t\n"
- "\t\t\n"
- "\t\t\n"
- "\t\t\n"
- "\t\n"
- "\t\n"
- "";
-
- constexpr const char Aarch64FpuXml[] =
- "l\n"
- "\n"
- "\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\t\n"
- "\t\t\n"
- "\t\t\n"
- "\t\n"
- "\t\n"
- "\t\t\n"
- "\t\t\n"
- "\t\t\n"
- "\t\n"
- "\t\n"
- "\t\t\n"
- "\t\t\n"
- "\t\t\n"
- "\t\n"
- "\t\n"
- "\t\t\n"
- "\t\t\n"
- "\t\n"
- "\t\n"
- "\t\t\n"
- "\t\t\n"
- "\t\n"
- "\t\n"
- "\t\t\n"
- "\t\t\n"
- "\t\t\n"
- "\t\t\n"
- "\t\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "";
-
- constexpr const char TargetXmlAarch32[] =
- "l"
- ""
- ""
- ""
- ""
- "";
-
- constexpr const char ArmCoreXml[] =
- "l\n"
- "\n"
- "\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\n";
-
- constexpr const char ArmVfpXml[] =
- "l\n"
- "\n"
- "\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\t\n"
- "\n";
-
- bool ParsePrefix(char *&packet, const char *prefix) {
- const auto len = std::strlen(prefix);
- if (std::strncmp(packet, prefix, len) == 0) {
- packet += len;
- return true;
- } else {
- return false;
- }
- }
-
- void SetReplyOk(char *reply) {
- std::strcpy(reply, "OK");
- }
-
- void SetReplyError(char *reply, const char *err) {
- AMS_DMNT2_GDB_LOG_ERROR("Reply Error: %s\n", err);
- std::strcpy(reply, err);
- }
-
- void SetReply(char *reply, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
-
- void SetReply(char *reply, const char *fmt, ...) {
- std::va_list vl;
- va_start(vl, fmt);
- util::VSNPrintf(reply, GdbPacketBufferSize, fmt, vl);
- va_end(vl);
- }
-
- void AppendReply(char *reply, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
-
- void AppendReply(char *reply, const char *fmt, ...) {
- const auto len = std::strlen(reply);
-
- std::va_list vl;
- va_start(vl, fmt);
- util::VSNPrintf(reply + len, GdbPacketBufferSize - len, fmt, vl);
- va_end(vl);
- }
-
- constexpr int DecodeHex(char c) {
- if ('a' <= c && c <= 'f') {
- return 10 + (c - 'a');
- } else if ('A' <= c && c <= 'F') {
- return 10 + (c - 'A');
- } else if ('0' <= c && c <= '9') {
- return 0 + (c - '0');
- } else {
- return -1;
- }
- }
-
- void ParseOffsetLength(const char *packet, u32 &offset, u32 &length) {
- /* Default to zero. */
- offset = 0;
- length = 0;
-
- bool parsed_offset = false;
- while (*packet) {
- const char c = *(packet++);
- if (c == ',') {
- parsed_offset = true;
- } else if (auto hex = DecodeHex(c); hex >= 0) {
- if (parsed_offset) {
- length <<= 4;
- length |= hex;
- } else {
- offset <<= 4;
- offset |= hex;
- }
- }
- }
-
- AMS_DMNT2_GDB_LOG_DEBUG("Offset/Length %x/%x\n", offset, length);
- }
-
- }
-
- void GdbPacketParser::Process() {
- /* Log the packet we're processing. */
- AMS_DMNT2_GDB_LOG_DEBUG("Receive: %s\n", m_receive_packet);
-
- /* Clear our reply packet. */
- m_reply_packet[0] = 0;
-
- /* Handle the received packet. */
- switch (m_receive_packet[0]) {
- case 'q':
- this->q();
- break;
- case '!':
- SetReplyOk(m_reply_packet);
- break;
- default:
- AMS_DMNT2_GDB_LOG_DEBUG("Not Implemented: %s\n", m_receive_packet);
- break;
- }
- }
-
- void GdbPacketParser::q() {
- if (ParsePrefix(m_receive_packet, "qSupported:")) {
- this->qSupported();
- } else if (ParsePrefix(m_receive_packet, "qXfer:features:read:")) {
- this->qXferFeaturesRead();
- } else {
- AMS_DMNT2_GDB_LOG_DEBUG("Not Implemented q: %s\n", m_receive_packet);
- }
- }
-
- void GdbPacketParser::qSupported() {
- /* Current string from devkita64-none-elf-gdb: */
- /* qSupported:multiprocess+;swbreak+;hwbreak+;qRelocInsn+;fork-events+;vfork-events+;exec-events+;vContSupported+;QThreadEvents+;no-resumed+ */
-
- SetReply(m_reply_packet, "PacketSize=%lx", GdbPacketBufferSize - 1);
- AppendReply(m_reply_packet, ";multiprocess+");
- AppendReply(m_reply_packet, ";qXfer:osdata:read+");
- AppendReply(m_reply_packet, ";qXfer:features:read+");
- AppendReply(m_reply_packet, ";qXfer:libraries:read+");
- AppendReply(m_reply_packet, ";qXfer:threads:read+");
- AppendReply(m_reply_packet, ";swbreak+");
- AppendReply(m_reply_packet, ";hwbreak+");
- }
-
- void GdbPacketParser::qXferFeaturesRead() {
- u32 offset, length;
-
- if (ParsePrefix(m_receive_packet, "target.xml:")) {
- /* Parse offset/length. */
- ParseOffsetLength(m_receive_packet, offset, length);
-
- /* Send the desired xml. */
- std::strncpy(m_reply_packet, (this->Is64Bit() ? TargetXmlAarch64 : TargetXmlAarch32) + offset, length);
- m_reply_packet[length] = 0;
- m_reply_packet += std::strlen(m_reply_packet);
- } else if (ParsePrefix(m_receive_packet, "aarch64-core.xml:")) {
- /* Parse offset/length. */
- ParseOffsetLength(m_receive_packet, offset, length);
-
- /* Send the desired xml. */
- std::strncpy(m_reply_packet, Aarch64CoreXml + offset, length);
- m_reply_packet[length] = 0;
- m_reply_packet += std::strlen(m_reply_packet);
- } else if (ParsePrefix(m_receive_packet, "aarch64-fpu.xml:")) {
- /* Parse offset/length. */
- ParseOffsetLength(m_receive_packet, offset, length);
-
- /* Send the desired xml. */
- std::strncpy(m_reply_packet, Aarch64FpuXml + offset, length);
- m_reply_packet[length] = 0;
- m_reply_packet += std::strlen(m_reply_packet);
- } else if (ParsePrefix(m_receive_packet, "arm-core.xml:")) {
- /* Parse offset/length. */
- ParseOffsetLength(m_receive_packet, offset, length);
-
- /* Send the desired xml. */
- std::strncpy(m_reply_packet, ArmCoreXml + offset, length);
- m_reply_packet[length] = 0;
- m_reply_packet += std::strlen(m_reply_packet);
- } else if (ParsePrefix(m_receive_packet, "arm-vfp.xml:")) {
- /* Parse offset/length. */
- ParseOffsetLength(m_receive_packet, offset, length);
-
- /* Send the desired xml. */
- std::strncpy(m_reply_packet, ArmVfpXml + offset, length);
- m_reply_packet[length] = 0;
- m_reply_packet += std::strlen(m_reply_packet);
- } else {
- AMS_DMNT2_GDB_LOG_DEBUG("Not Implemented qxfer:features:read: %s\n", m_receive_packet);
- }
- }
-
-}
\ No newline at end of file
diff --git a/stratosphere/dmnt.gen2/source/dmnt2_gdb_packet_parser.hpp b/stratosphere/dmnt.gen2/source/dmnt2_gdb_packet_parser.hpp
deleted file mode 100644
index 6bd1a6d..0000000
--- a/stratosphere/dmnt.gen2/source/dmnt2_gdb_packet_parser.hpp
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2018-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 .
- */
-#pragma once
-#include
-#include "dmnt2_gdb_packet_io.hpp"
-
-namespace ams::dmnt {
-
- class GdbPacketParser {
- private:
- char *m_receive_packet;
- char *m_reply_packet;
- char m_buffer[GdbPacketBufferSize / 2];
- bool m_64_bit;
- bool m_no_ack;
- public:
- GdbPacketParser(char *recv, char *reply, bool is_64_bit) : m_receive_packet(recv), m_reply_packet(reply), m_64_bit(is_64_bit), m_no_ack(false) { /* ... */ }
-
- void Process();
-
- bool Is64Bit() const { return m_64_bit; }
- private:
- void q();
-
- void qSupported();
- void qXferFeaturesRead();
- };
-
-}
\ No newline at end of file
diff --git a/stratosphere/dmnt.gen2/source/dmnt2_gdb_server.cpp b/stratosphere/dmnt.gen2/source/dmnt2_gdb_server.cpp
index 8758d9f..0cca175 100644
--- a/stratosphere/dmnt.gen2/source/dmnt2_gdb_server.cpp
+++ b/stratosphere/dmnt.gen2/source/dmnt2_gdb_server.cpp
@@ -14,10 +14,9 @@
* along with this program. If not, see .
*/
#include
-#include "dmnt2_gdb_packet_io.hpp"
-#include "dmnt2_gdb_packet_parser.hpp"
-#include "dmnt2_gdb_server.hpp"
#include "dmnt2_debug_log.hpp"
+#include "dmnt2_gdb_server.hpp"
+#include "dmnt2_gdb_server_impl.hpp"
namespace ams::dmnt {
@@ -25,43 +24,13 @@
constexpr size_t ServerThreadStackSize = util::AlignUp(4 * GdbPacketBufferSize + os::MemoryPageSize, os::ThreadStackAlignment);
- alignas(os::ThreadStackAlignment) constinit u8 g_server_thread32_stack[ServerThreadStackSize];
- alignas(os::ThreadStackAlignment) constinit u8 g_server_thread64_stack[ServerThreadStackSize];
+ alignas(os::ThreadStackAlignment) constinit u8 g_server_thread_stack[ServerThreadStackSize];
- constinit os::ThreadType g_server_thread32;
- constinit os::ThreadType g_server_thread64;
+ constinit os::ThreadType g_server_thread;
- constinit util::TypedStorage g_session32;
- constinit util::TypedStorage g_session64;
+ constinit util::TypedStorage g_gdb_server;
-
- void ProcessForHtcsSession(HtcsSession *session, bool is_64_bit) {
- /* Create packet io handler. */
- GdbPacketIo packet_io;
-
- /* Process packets. */
- while (session->IsValid()) {
- /* Receive a packet. */
- bool do_break = false;
- char recv_buf[GdbPacketBufferSize];
- char *packet = packet_io.ReceivePacket(std::addressof(do_break), recv_buf, sizeof(recv_buf), session);
-
- if (!do_break && packet != nullptr) {
- /* Create a packet parser. */
- char reply_buffer[GdbPacketBufferSize];
- GdbPacketParser parser(packet, reply_buffer, is_64_bit);
-
- /* Process the packet. */
- parser.Process();
-
- /* Send packet. */
- packet_io.SendPacket(std::addressof(do_break), reply_buffer, session);
- }
- }
- }
-
- template
- void GdbServerThreadFunction() {
+ void GdbServerThreadFunction(void *) {
/* Loop forever, servicing our gdb server. */
while (true) {
/* Get a socket. */
@@ -80,7 +49,7 @@
htcs::SockAddrHtcs addr;
addr.family = htcs::HTCS_AF_HTCS;
addr.peer_name = htcs::GetPeerNameAny();
- std::strcpy(addr.port_name.name, Is64Bit ? "iywys@$gdb-aarch64" : "iywys@$gdb-aarch32");
+ std::strcpy(addr.port_name.name, "iywys@$gdb");
/* Bind. */
if (htcs::Bind(fd, std::addressof(addr)) == -1) {
@@ -97,13 +66,14 @@
break;
}
- /* Create htcs session for the socket. */
- auto &session_storage = Is64Bit ? g_session64 : g_session32;
- util::ConstructAt(session_storage, client_fd);
- ON_SCOPE_EXIT { util::DestroyAt(session_storage); };
+ {
+ /* Create gdb server for the socket. */
+ util::ConstructAt(g_gdb_server, client_fd);
+ ON_SCOPE_EXIT { util::DestroyAt(g_gdb_server); };
- /* Process for the session. */
- ProcessForHtcsSession(util::GetPointer(session_storage), Is64Bit);
+ /* Process for the server. */
+ util::GetReference(g_gdb_server).LoopProcess();
+ }
/* Close the client socket. */
htcs::Close(client_fd);
@@ -112,22 +82,12 @@
}
}
- void GdbServerThreadFunction64(void *) {
- GdbServerThreadFunction();
- }
-
- void GdbServerThreadFunction32(void *) {
- GdbServerThreadFunction();
- }
-
}
void InitializeGdbServer() {
/* Create and start gdb server threads. */
- R_ABORT_UNLESS(os::CreateThread(std::addressof(g_server_thread64), GdbServerThreadFunction64, nullptr, g_server_thread64_stack, sizeof(g_server_thread64_stack), os::HighestThreadPriority - 1));
- R_ABORT_UNLESS(os::CreateThread(std::addressof(g_server_thread32), GdbServerThreadFunction32, nullptr, g_server_thread32_stack, sizeof(g_server_thread32_stack), os::HighestThreadPriority - 1));
- os::StartThread(std::addressof(g_server_thread64));
- os::StartThread(std::addressof(g_server_thread32));
+ R_ABORT_UNLESS(os::CreateThread(std::addressof(g_server_thread), GdbServerThreadFunction, nullptr, g_server_thread_stack, sizeof(g_server_thread_stack), os::HighestThreadPriority - 1));
+ os::StartThread(std::addressof(g_server_thread));
}
}
diff --git a/stratosphere/dmnt.gen2/source/dmnt2_gdb_server_impl.cpp b/stratosphere/dmnt.gen2/source/dmnt2_gdb_server_impl.cpp
new file mode 100644
index 0000000..18e83b4
--- /dev/null
+++ b/stratosphere/dmnt.gen2/source/dmnt2_gdb_server_impl.cpp
@@ -0,0 +1,586 @@
+/*
+ * Copyright (c) 2018-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 .
+ */
+#include
+#include "dmnt2_debug_log.hpp"
+#include "dmnt2_gdb_server_impl.hpp"
+
+namespace ams::dmnt {
+
+ namespace {
+
+ constexpr const char TargetXmlAarch64[] =
+ "l"
+ ""
+ ""
+ "aarch64"
+ "GNU/Linux"
+ ""
+ ""
+ "";
+
+ constexpr const char Aarch64CoreXml[] =
+ "l\n"
+ "\n"
+ "\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\t\n"
+ "\t\t\n"
+ "\t\t\n"
+ "\n"
+ "\t\t\n"
+ "\t\t\n"
+ "\t\t\n"
+ "\t\t\n"
+ "\n"
+ "\t\t\n"
+ "\n"
+ "\t\t\n"
+ "\t\t\n"
+ "\t\t\n"
+ "\t\t\n"
+ "\t\t\n"
+ "\t\t\n"
+ "\n"
+ "\t\t\n"
+ "\t\t\n"
+ "\t\t\n"
+ "\t\t\n"
+ "\t\n"
+ "\t\n"
+ "";
+
+ constexpr const char Aarch64FpuXml[] =
+ "l\n"
+ "\n"
+ "\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\t\n"
+ "\t\t\n"
+ "\t\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\t\n"
+ "\t\t\n"
+ "\t\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\t\n"
+ "\t\t\n"
+ "\t\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\t\n"
+ "\t\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\t\n"
+ "\t\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\t\n"
+ "\t\t\n"
+ "\t\t\n"
+ "\t\t\n"
+ "\t\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "";
+
+ constexpr const char TargetXmlAarch32[] =
+ "l"
+ ""
+ ""
+ ""
+ ""
+ "";
+
+ constexpr const char ArmCoreXml[] =
+ "l\n"
+ "\n"
+ "\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\n";
+
+ constexpr const char ArmVfpXml[] =
+ "l\n"
+ "\n"
+ "\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\t\n"
+ "\n";
+
+ bool ParsePrefix(char *&packet, const char *prefix) {
+ const auto len = std::strlen(prefix);
+ if (std::strncmp(packet, prefix, len) == 0) {
+ packet += len;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ void SetReplyOk(char *reply) {
+ std::strcpy(reply, "OK");
+ }
+
+ void SetReplyError(char *reply, const char *err) {
+ AMS_DMNT2_GDB_LOG_ERROR("Reply Error: %s\n", err);
+ std::strcpy(reply, err);
+ }
+
+ void SetReply(char *reply, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
+
+ void SetReply(char *reply, const char *fmt, ...) {
+ std::va_list vl;
+ va_start(vl, fmt);
+ util::VSNPrintf(reply, GdbPacketBufferSize, fmt, vl);
+ va_end(vl);
+ }
+
+ void AppendReply(char *reply, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
+
+ void AppendReply(char *reply, const char *fmt, ...) {
+ const auto len = std::strlen(reply);
+
+ std::va_list vl;
+ va_start(vl, fmt);
+ util::VSNPrintf(reply + len, GdbPacketBufferSize - len, fmt, vl);
+ va_end(vl);
+ }
+
+ constexpr int DecodeHex(char c) {
+ if ('a' <= c && c <= 'f') {
+ return 10 + (c - 'a');
+ } else if ('A' <= c && c <= 'F') {
+ return 10 + (c - 'A');
+ } else if ('0' <= c && c <= '9') {
+ return 0 + (c - '0');
+ } else {
+ return -1;
+ }
+ }
+
+ void ParseOffsetLength(const char *packet, u32 &offset, u32 &length) {
+ /* Default to zero. */
+ offset = 0;
+ length = 0;
+
+ bool parsed_offset = false;
+ while (*packet) {
+ const char c = *(packet++);
+ if (c == ',') {
+ parsed_offset = true;
+ } else if (auto hex = DecodeHex(c); hex >= 0) {
+ if (parsed_offset) {
+ length <<= 4;
+ length |= hex;
+ } else {
+ offset <<= 4;
+ offset |= hex;
+ }
+ }
+ }
+
+ AMS_DMNT2_GDB_LOG_DEBUG("Offset/Length %x/%x\n", offset, length);
+ }
+
+ constinit char g_process_list_buffer[0x2000];
+
+ }
+
+ GdbServerImpl::GdbServerImpl(int socket) : m_socket(socket), m_session(socket), m_packet_io() { /* ... */ }
+
+ GdbServerImpl::~GdbServerImpl() { /* ... */ }
+
+ void GdbServerImpl::LoopProcess() {
+ /* Process packets. */
+ while (m_session.IsValid()) {
+ /* Receive a packet. */
+ bool do_break = false;
+ char recv_buf[GdbPacketBufferSize];
+ char *packet = this->ReceivePacket(std::addressof(do_break), recv_buf, sizeof(recv_buf));
+
+ if (!do_break && packet != nullptr) {
+ /* Process the packet. */
+ char reply_buffer[GdbPacketBufferSize];
+ this->ProcessPacket(packet, reply_buffer);
+
+ /* Send packet. */
+ this->SendPacket(std::addressof(do_break), reply_buffer);
+ }
+ }
+ }
+
+ void GdbServerImpl::ProcessPacket(char *receive, char *reply) {
+ /* Set our fields. */
+ m_receive_packet = receive;
+ m_reply_packet = reply;
+
+ /* Log the packet we're processing. */
+ AMS_DMNT2_GDB_LOG_DEBUG("Receive: %s\n", m_receive_packet);
+
+ /* Clear our reply packet. */
+ m_reply_packet[0] = 0;
+
+ /* Handle the received packet. */
+ switch (m_receive_packet[0]) {
+ case 'H':
+ this->H();
+ break;
+ case 'q':
+ this->q();
+ break;
+ case '!':
+ SetReplyOk(m_reply_packet);
+ break;
+ case '?':
+ this->QuestionMark();
+ break;
+ default:
+ AMS_DMNT2_GDB_LOG_DEBUG("Not Implemented: %s\n", m_receive_packet);
+ break;
+ }
+ }
+
+ void GdbServerImpl::H() {
+ if (this->HasDebugProcess()) {
+ /* TODO */
+ SetReplyError(m_reply_packet, "E01");
+ } else {
+ SetReplyError(m_reply_packet, "E01");
+ }
+ }
+
+ void GdbServerImpl::q() {
+ if (ParsePrefix(m_receive_packet, "qAttached:")) {
+ this->qAttached();
+ } else if (ParsePrefix(m_receive_packet, "qC")) {
+ this->qC();
+ } else if (ParsePrefix(m_receive_packet, "qSupported:")) {
+ this->qSupported();
+ } else if (ParsePrefix(m_receive_packet, "qXfer:")) {
+ this->qXfer();
+ } else {
+ AMS_DMNT2_GDB_LOG_DEBUG("Not Implemented q: %s\n", m_receive_packet);
+ }
+ }
+
+ void GdbServerImpl::qAttached() {
+ if (this->HasDebugProcess()) {
+ /* TODO: Parse/Save the requested process id */
+ SetReply(m_reply_packet, "1");
+ } else {
+ SetReplyError(m_reply_packet, "E01");
+ }
+ }
+
+ void GdbServerImpl::qC() {
+ if (this->HasDebugProcess()) {
+ /* TODO */
+ SetReplyError(m_reply_packet, "E01");
+ } else {
+ SetReplyError(m_reply_packet, "E01");
+ }
+ }
+
+ void GdbServerImpl::qSupported() {
+ /* Current string from devkita64-none-elf-gdb: */
+ /* qSupported:multiprocess+;swbreak+;hwbreak+;qRelocInsn+;fork-events+;vfork-events+;exec-events+;vContSupported+;QThreadEvents+;no-resumed+ */
+
+ SetReply(m_reply_packet, "PacketSize=%lx", GdbPacketBufferSize - 1);
+ AppendReply(m_reply_packet, ";multiprocess+");
+ AppendReply(m_reply_packet, ";qXfer:osdata:read+");
+ AppendReply(m_reply_packet, ";qXfer:features:read+");
+ AppendReply(m_reply_packet, ";qXfer:libraries:read+");
+ AppendReply(m_reply_packet, ";qXfer:threads:read+");
+ AppendReply(m_reply_packet, ";swbreak+");
+ AppendReply(m_reply_packet, ";hwbreak+");
+ }
+
+ void GdbServerImpl::qXfer() {
+ /* Check for osdata. */
+ if (ParsePrefix(m_receive_packet, "osdata:read:")) {
+ this->qXferOsdataRead();
+ } else {
+ /* All other qXfer require debug process. */
+ if (!this->HasDebugProcess()) {
+ SetReplyError(m_reply_packet, "E01");
+ return;
+ }
+
+ /* Process. */
+ if (ParsePrefix(m_receive_packet, "features:read:")) {
+ this->qXferFeaturesRead();
+ } else {
+ AMS_DMNT2_GDB_LOG_DEBUG("Not Implemented qxfer: %s\n", m_receive_packet);
+ SetReplyError(m_reply_packet, "E01");
+ }
+ }
+ }
+
+ void GdbServerImpl::qXferFeaturesRead() {
+ /* Handle the qXfer. */
+ u32 offset, length;
+
+ if (ParsePrefix(m_receive_packet, "target.xml:")) {
+ /* Parse offset/length. */
+ ParseOffsetLength(m_receive_packet, offset, length);
+
+ /* Send the desired xml. */
+ /* TODO: Detection of debug-process as 64 bit or not. */
+ std::strncpy(m_reply_packet, (this->Is64Bit() ? TargetXmlAarch64 : TargetXmlAarch32) + offset, length);
+ m_reply_packet[length] = 0;
+ m_reply_packet += std::strlen(m_reply_packet);
+ } else if (ParsePrefix(m_receive_packet, "aarch64-core.xml:")) {
+ /* Parse offset/length. */
+ ParseOffsetLength(m_receive_packet, offset, length);
+
+ /* Send the desired xml. */
+ std::strncpy(m_reply_packet, Aarch64CoreXml + offset, length);
+ m_reply_packet[length] = 0;
+ m_reply_packet += std::strlen(m_reply_packet);
+ } else if (ParsePrefix(m_receive_packet, "aarch64-fpu.xml:")) {
+ /* Parse offset/length. */
+ ParseOffsetLength(m_receive_packet, offset, length);
+
+ /* Send the desired xml. */
+ std::strncpy(m_reply_packet, Aarch64FpuXml + offset, length);
+ m_reply_packet[length] = 0;
+ m_reply_packet += std::strlen(m_reply_packet);
+ } else if (ParsePrefix(m_receive_packet, "arm-core.xml:")) {
+ /* Parse offset/length. */
+ ParseOffsetLength(m_receive_packet, offset, length);
+
+ /* Send the desired xml. */
+ std::strncpy(m_reply_packet, ArmCoreXml + offset, length);
+ m_reply_packet[length] = 0;
+ m_reply_packet += std::strlen(m_reply_packet);
+ } else if (ParsePrefix(m_receive_packet, "arm-vfp.xml:")) {
+ /* Parse offset/length. */
+ ParseOffsetLength(m_receive_packet, offset, length);
+
+ /* Send the desired xml. */
+ std::strncpy(m_reply_packet, ArmVfpXml + offset, length);
+ m_reply_packet[length] = 0;
+ m_reply_packet += std::strlen(m_reply_packet);
+ } else {
+ AMS_DMNT2_GDB_LOG_DEBUG("Not Implemented qxfer:features:read: %s\n", m_receive_packet);
+ SetReplyError(m_reply_packet, "E01");
+ }
+ }
+
+ void GdbServerImpl::qXferOsdataRead() {
+ /* Handle the qXfer. */
+ u32 offset, length;
+
+ if (ParsePrefix(m_receive_packet, "processes:")) {
+ /* Parse offset/length. */
+ ParseOffsetLength(m_receive_packet, offset, length);
+
+ /* If doing a fresh read, generate the process list. */
+ if (offset == 0) {
+ /* Clear the process list buffer. */
+ g_process_list_buffer[0] = 0;
+
+ /* Set header. */
+ SetReply(g_process_list_buffer, "\n\n\n");
+
+ /* Get all processes. */
+ {
+ /* Get all process ids. */
+ u64 process_ids[0x50];
+ s32 num_process_ids;
+ R_ABORT_UNLESS(svc::GetProcessList(std::addressof(num_process_ids), process_ids, util::size(process_ids)));
+
+ /* Send all processes. */
+ for (s32 i = 0; i < num_process_ids; ++i) {
+ svc::Handle handle;
+ if (R_SUCCEEDED(svc::DebugActiveProcess(std::addressof(handle), process_ids[i]))) {
+ ON_SCOPE_EXIT { R_ABORT_UNLESS(svc::CloseHandle(handle)); };
+
+ /* Get the create process event. */
+ svc::DebugEventInfo d;
+ while (true) {
+ R_ABORT_UNLESS(svc::GetDebugEvent(std::addressof(d), handle));
+ if (d.type == svc::DebugEvent_CreateProcess) {
+ AppendReply(g_process_list_buffer, "- \n%lu\n%s\n
\n", d.info.create_process.process_id, d.info.create_process.name);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /* Set footer. */
+ AppendReply(g_process_list_buffer, "");
+ }
+
+ /* Copy out the process list. */
+ const u32 annex_len = std::strlen(g_process_list_buffer);
+ if (offset <= annex_len) {
+ if (offset + length < annex_len) {
+ m_reply_packet[0] = 'm';
+ std::memcpy(m_reply_packet + 1, g_process_list_buffer + offset, length);
+ m_reply_packet[1 + length] = 0;
+ } else {
+ const auto size = annex_len - offset;
+
+ m_reply_packet[0] = 'l';
+ std::memcpy(m_reply_packet + 1, g_process_list_buffer + offset, size);
+ m_reply_packet[1 + size] = 0;
+ }
+ } else {
+ SetReply(m_reply_packet, "l");
+ }
+ } else {
+ AMS_DMNT2_GDB_LOG_DEBUG("Not Implemented qxfer:osdata:read: %s\n", m_receive_packet);
+ SetReplyError(m_reply_packet, "E01");
+ }
+ }
+
+ void GdbServerImpl::QuestionMark() {
+ /* TODO */
+ AMS_DMNT2_GDB_LOG_DEBUG("Not Implemented QuestionMark\n");
+ SetReply(m_reply_packet, "W00");
+ }
+
+}
\ No newline at end of file
diff --git a/stratosphere/dmnt.gen2/source/dmnt2_gdb_server_impl.hpp b/stratosphere/dmnt.gen2/source/dmnt2_gdb_server_impl.hpp
new file mode 100644
index 0000000..dc868c8
--- /dev/null
+++ b/stratosphere/dmnt.gen2/source/dmnt2_gdb_server_impl.hpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2018-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 .
+ */
+#pragma once
+#include
+#include "dmnt2_gdb_packet_io.hpp"
+
+namespace ams::dmnt {
+
+ class GdbServerImpl {
+ private:
+ int m_socket;
+ HtcsSession m_session;
+ GdbPacketIo m_packet_io;
+ char *m_receive_packet{nullptr};
+ char *m_reply_packet{nullptr};
+ char m_buffer[GdbPacketBufferSize / 2];
+ svc::Handle m_debug_handle{svc::InvalidHandle};
+ public:
+ GdbServerImpl(int socket);
+ ~GdbServerImpl();
+
+ void LoopProcess();
+ private:
+ void ProcessPacket(char *receive, char *reply);
+
+ void SendPacket(bool *out_break, const char *src) { return m_packet_io.SendPacket(out_break, src, std::addressof(m_session)); }
+ char *ReceivePacket(bool *out_break, char *dst, size_t size) { return m_packet_io.ReceivePacket(out_break, dst, size, std::addressof(m_session)); }
+ private:
+ bool HasDebugProcess() const { return m_debug_handle != svc::InvalidHandle; }
+ bool Is64Bit() const { return true; /* TODO: Retrieve from debug process info. */ }
+ private:
+ void H();
+ void q();
+
+ void qAttached();
+ void qC();
+ void qSupported();
+ void qXfer();
+ void qXferFeaturesRead();
+ void qXferOsdataRead();
+
+ void QuestionMark();
+ };
+
+}
\ No newline at end of file