mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-11-09 22:56:35 +00:00
dmnt: refactor/add support for getting process list in gdb
This commit is contained in:
parent
a7f9729f63
commit
649a0052d0
5 changed files with 255 additions and 107 deletions
|
@ -99,5 +99,12 @@
|
||||||
}, {
|
}, {
|
||||||
"type": "handle_table_size",
|
"type": "handle_table_size",
|
||||||
"value": 0
|
"value": 0
|
||||||
}]
|
},
|
||||||
|
{
|
||||||
|
"type": "debug_flags",
|
||||||
|
"value": {
|
||||||
|
"allow_debug": false,
|
||||||
|
"force_debug": true
|
||||||
|
}
|
||||||
|
}]
|
||||||
}
|
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
#pragma once
|
|
||||||
#include <stratosphere.hpp>
|
|
||||||
#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();
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -14,10 +14,9 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
#include "dmnt2_gdb_packet_io.hpp"
|
|
||||||
#include "dmnt2_gdb_packet_parser.hpp"
|
|
||||||
#include "dmnt2_gdb_server.hpp"
|
|
||||||
#include "dmnt2_debug_log.hpp"
|
#include "dmnt2_debug_log.hpp"
|
||||||
|
#include "dmnt2_gdb_server.hpp"
|
||||||
|
#include "dmnt2_gdb_server_impl.hpp"
|
||||||
|
|
||||||
namespace ams::dmnt {
|
namespace ams::dmnt {
|
||||||
|
|
||||||
|
@ -25,43 +24,13 @@ namespace ams::dmnt {
|
||||||
|
|
||||||
constexpr size_t ServerThreadStackSize = util::AlignUp(4 * GdbPacketBufferSize + os::MemoryPageSize, os::ThreadStackAlignment);
|
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_thread_stack[ServerThreadStackSize];
|
||||||
alignas(os::ThreadStackAlignment) constinit u8 g_server_thread64_stack[ServerThreadStackSize];
|
|
||||||
|
|
||||||
constinit os::ThreadType g_server_thread32;
|
constinit os::ThreadType g_server_thread;
|
||||||
constinit os::ThreadType g_server_thread64;
|
|
||||||
|
|
||||||
constinit util::TypedStorage<HtcsSession> g_session32;
|
constinit util::TypedStorage<GdbServerImpl> g_gdb_server;
|
||||||
constinit util::TypedStorage<HtcsSession> g_session64;
|
|
||||||
|
|
||||||
|
void GdbServerThreadFunction(void *) {
|
||||||
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<bool Is64Bit>
|
|
||||||
void GdbServerThreadFunction() {
|
|
||||||
/* Loop forever, servicing our gdb server. */
|
/* Loop forever, servicing our gdb server. */
|
||||||
while (true) {
|
while (true) {
|
||||||
/* Get a socket. */
|
/* Get a socket. */
|
||||||
|
@ -80,7 +49,7 @@ namespace ams::dmnt {
|
||||||
htcs::SockAddrHtcs addr;
|
htcs::SockAddrHtcs addr;
|
||||||
addr.family = htcs::HTCS_AF_HTCS;
|
addr.family = htcs::HTCS_AF_HTCS;
|
||||||
addr.peer_name = htcs::GetPeerNameAny();
|
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. */
|
/* Bind. */
|
||||||
if (htcs::Bind(fd, std::addressof(addr)) == -1) {
|
if (htcs::Bind(fd, std::addressof(addr)) == -1) {
|
||||||
|
@ -97,13 +66,14 @@ namespace ams::dmnt {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create htcs session for the socket. */
|
{
|
||||||
auto &session_storage = Is64Bit ? g_session64 : g_session32;
|
/* Create gdb server for the socket. */
|
||||||
util::ConstructAt(session_storage, client_fd);
|
util::ConstructAt(g_gdb_server, client_fd);
|
||||||
ON_SCOPE_EXIT { util::DestroyAt(session_storage); };
|
ON_SCOPE_EXIT { util::DestroyAt(g_gdb_server); };
|
||||||
|
|
||||||
/* Process for the session. */
|
/* Process for the server. */
|
||||||
ProcessForHtcsSession(util::GetPointer(session_storage), Is64Bit);
|
util::GetReference(g_gdb_server).LoopProcess();
|
||||||
|
}
|
||||||
|
|
||||||
/* Close the client socket. */
|
/* Close the client socket. */
|
||||||
htcs::Close(client_fd);
|
htcs::Close(client_fd);
|
||||||
|
@ -112,22 +82,12 @@ namespace ams::dmnt {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GdbServerThreadFunction64(void *) {
|
|
||||||
GdbServerThreadFunction<true>();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GdbServerThreadFunction32(void *) {
|
|
||||||
GdbServerThreadFunction<false>();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitializeGdbServer() {
|
void InitializeGdbServer() {
|
||||||
/* Create and start gdb server threads. */
|
/* 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_thread), GdbServerThreadFunction, nullptr, g_server_thread_stack, sizeof(g_server_thread_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_thread));
|
||||||
os::StartThread(std::addressof(g_server_thread64));
|
|
||||||
os::StartThread(std::addressof(g_server_thread32));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
*/
|
*/
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
#include "dmnt2_debug_log.hpp"
|
#include "dmnt2_debug_log.hpp"
|
||||||
#include "dmnt2_gdb_packet_parser.hpp"
|
#include "dmnt2_gdb_server_impl.hpp"
|
||||||
|
|
||||||
namespace ams::dmnt {
|
namespace ams::dmnt {
|
||||||
|
|
||||||
|
@ -323,9 +323,38 @@ namespace ams::dmnt {
|
||||||
AMS_DMNT2_GDB_LOG_DEBUG("Offset/Length %x/%x\n", offset, length);
|
AMS_DMNT2_GDB_LOG_DEBUG("Offset/Length %x/%x\n", offset, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constinit char g_process_list_buffer[0x2000];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GdbPacketParser::Process() {
|
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. */
|
/* Log the packet we're processing. */
|
||||||
AMS_DMNT2_GDB_LOG_DEBUG("Receive: %s\n", m_receive_packet);
|
AMS_DMNT2_GDB_LOG_DEBUG("Receive: %s\n", m_receive_packet);
|
||||||
|
|
||||||
|
@ -334,29 +363,66 @@ namespace ams::dmnt {
|
||||||
|
|
||||||
/* Handle the received packet. */
|
/* Handle the received packet. */
|
||||||
switch (m_receive_packet[0]) {
|
switch (m_receive_packet[0]) {
|
||||||
|
case 'H':
|
||||||
|
this->H();
|
||||||
|
break;
|
||||||
case 'q':
|
case 'q':
|
||||||
this->q();
|
this->q();
|
||||||
break;
|
break;
|
||||||
case '!':
|
case '!':
|
||||||
SetReplyOk(m_reply_packet);
|
SetReplyOk(m_reply_packet);
|
||||||
break;
|
break;
|
||||||
|
case '?':
|
||||||
|
this->QuestionMark();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
AMS_DMNT2_GDB_LOG_DEBUG("Not Implemented: %s\n", m_receive_packet);
|
AMS_DMNT2_GDB_LOG_DEBUG("Not Implemented: %s\n", m_receive_packet);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GdbPacketParser::q() {
|
void GdbServerImpl::H() {
|
||||||
if (ParsePrefix(m_receive_packet, "qSupported:")) {
|
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();
|
this->qSupported();
|
||||||
} else if (ParsePrefix(m_receive_packet, "qXfer:features:read:")) {
|
} else if (ParsePrefix(m_receive_packet, "qXfer:")) {
|
||||||
this->qXferFeaturesRead();
|
this->qXfer();
|
||||||
} else {
|
} else {
|
||||||
AMS_DMNT2_GDB_LOG_DEBUG("Not Implemented q: %s\n", m_receive_packet);
|
AMS_DMNT2_GDB_LOG_DEBUG("Not Implemented q: %s\n", m_receive_packet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GdbPacketParser::qSupported() {
|
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: */
|
/* Current string from devkita64-none-elf-gdb: */
|
||||||
/* qSupported:multiprocess+;swbreak+;hwbreak+;qRelocInsn+;fork-events+;vfork-events+;exec-events+;vContSupported+;QThreadEvents+;no-resumed+ */
|
/* qSupported:multiprocess+;swbreak+;hwbreak+;qRelocInsn+;fork-events+;vfork-events+;exec-events+;vContSupported+;QThreadEvents+;no-resumed+ */
|
||||||
|
|
||||||
|
@ -370,7 +436,29 @@ namespace ams::dmnt {
|
||||||
AppendReply(m_reply_packet, ";hwbreak+");
|
AppendReply(m_reply_packet, ";hwbreak+");
|
||||||
}
|
}
|
||||||
|
|
||||||
void GdbPacketParser::qXferFeaturesRead() {
|
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;
|
u32 offset, length;
|
||||||
|
|
||||||
if (ParsePrefix(m_receive_packet, "target.xml:")) {
|
if (ParsePrefix(m_receive_packet, "target.xml:")) {
|
||||||
|
@ -378,6 +466,7 @@ namespace ams::dmnt {
|
||||||
ParseOffsetLength(m_receive_packet, offset, length);
|
ParseOffsetLength(m_receive_packet, offset, length);
|
||||||
|
|
||||||
/* Send the desired xml. */
|
/* 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);
|
std::strncpy(m_reply_packet, (this->Is64Bit() ? TargetXmlAarch64 : TargetXmlAarch32) + offset, length);
|
||||||
m_reply_packet[length] = 0;
|
m_reply_packet[length] = 0;
|
||||||
m_reply_packet += std::strlen(m_reply_packet);
|
m_reply_packet += std::strlen(m_reply_packet);
|
||||||
|
@ -415,7 +504,83 @@ namespace ams::dmnt {
|
||||||
m_reply_packet += std::strlen(m_reply_packet);
|
m_reply_packet += std::strlen(m_reply_packet);
|
||||||
} else {
|
} else {
|
||||||
AMS_DMNT2_GDB_LOG_DEBUG("Not Implemented qxfer:features:read: %s\n", m_receive_packet);
|
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, "<?xml version=\"1.0\"?>\n<!DOCTYPE target SYSTEM \"osdata.dtd\">\n<osdata type=\"processes\">\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, "<item>\n<column name=\"pid\">%lu</column>\n<column name=\"command\">%s</column>\n</item>\n", d.info.create_process.process_id, d.info.create_process.name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set footer. */
|
||||||
|
AppendReply(g_process_list_buffer, "</osdata>");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
58
stratosphere/dmnt.gen2/source/dmnt2_gdb_server_impl.hpp
Normal file
58
stratosphere/dmnt.gen2/source/dmnt2_gdb_server_impl.hpp
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#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();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue