From be5cd35ef6a985ce96146fef769bb3c453f595fd Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Tue, 2 Nov 2021 10:09:15 -0700 Subject: [PATCH] dmnt2: try to avoid writing out of bounds when generating packets --- .../source/osdbg/osdbg_thread.cpp | 4 +- .../dmnt.gen2/source/dmnt2_debug_process.cpp | 4 +- .../source/dmnt2_gdb_server_impl.cpp | 483 +++++++++--------- .../source/dmnt2_gdb_server_impl.hpp | 5 +- 4 files changed, 261 insertions(+), 235 deletions(-) diff --git a/libraries/libstratosphere/source/osdbg/osdbg_thread.cpp b/libraries/libstratosphere/source/osdbg/osdbg_thread.cpp index 81f69ad5e..6bb9235e1 100644 --- a/libraries/libstratosphere/source/osdbg/osdbg_thread.cpp +++ b/libraries/libstratosphere/source/osdbg/osdbg_thread.cpp @@ -50,9 +50,9 @@ namespace ams::osdbg { } else { /* Special-case libnx threads. */ if (thread_info->_thread_type_type == ThreadTypeType_Libnx) { - util::TSNPrintf(dst, os::ThreadNameLengthMax, "libnx Thread_%p", reinterpret_cast(thread_info->_thread_type)); + util::TSNPrintf(dst, os::ThreadNameLengthMax, "libnx Thread_0x%010lx", reinterpret_cast(thread_info->_thread_type)); } else { - util::TSNPrintf(dst, os::ThreadNameLengthMax, "Thread_%p", reinterpret_cast(thread_info->_thread_type)); + util::TSNPrintf(dst, os::ThreadNameLengthMax, "Thread_0x%010lx", reinterpret_cast(thread_info->_thread_type)); } return ResultSuccess(); diff --git a/stratosphere/dmnt.gen2/source/dmnt2_debug_process.cpp b/stratosphere/dmnt.gen2/source/dmnt2_debug_process.cpp index 09b28b57f..a62f8c0d6 100644 --- a/stratosphere/dmnt.gen2/source/dmnt2_debug_process.cpp +++ b/stratosphere/dmnt.gen2/source/dmnt2_debug_process.cpp @@ -601,9 +601,9 @@ namespace ams::dmnt { if (R_FAILED(osdbg::GetThreadName(dst, std::addressof(m_thread_infos[i])))) { if (m_thread_infos[i]._thread_type != 0) { if (m_thread_infos[i]._thread_type_type == osdbg::ThreadTypeType_Libnx) { - util::TSNPrintf(dst, os::ThreadNameLengthMax, "libnx Thread_%p", reinterpret_cast(m_thread_infos[i]._thread_type)); + util::TSNPrintf(dst, os::ThreadNameLengthMax, "libnx Thread_0x%010lx", reinterpret_cast(m_thread_infos[i]._thread_type)); } else { - util::TSNPrintf(dst, os::ThreadNameLengthMax, "Thread_%p", reinterpret_cast(m_thread_infos[i]._thread_type)); + util::TSNPrintf(dst, os::ThreadNameLengthMax, "Thread_0x%010lx", reinterpret_cast(m_thread_infos[i]._thread_type)); } } else { break; diff --git a/stratosphere/dmnt.gen2/source/dmnt2_gdb_server_impl.cpp b/stratosphere/dmnt.gen2/source/dmnt2_gdb_server_impl.cpp index 90de1cdc2..853489741 100644 --- a/stratosphere/dmnt.gen2/source/dmnt2_gdb_server_impl.cpp +++ b/stratosphere/dmnt.gen2/source/dmnt2_gdb_server_impl.cpp @@ -326,33 +326,27 @@ namespace ams::dmnt { } } - void SetReplyOk(char *reply) { + void AppendReplyOk(char * &reply, char * const reply_end) { + AMS_UNUSED(reply_end); std::strcpy(reply, "OK"); + reply += 2; } - void SetReplyError(char *reply, const char *err) { - AMS_DMNT2_GDB_LOG_ERROR("Reply Error: %s\n", err); + void AppendReplyError(char * reply, char * const reply_end, const char *err) { + AMS_UNUSED(reply_end); std::strcpy(reply, err); + reply += std::strlen(err); } - void SetReply(char *reply, const char *fmt, ...) __attribute__((format(printf, 2, 3))); + void AppendReplyFormat(char * &reply, char * const reply_end, const char *fmt, ...) __attribute__((format(printf, 3, 4))); - 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); + void AppendReplyFormat(char * &reply, char * const reply_end, const char *fmt, ...) { + if (const auto remaining_size = reply_end - reply; remaining_size > 0) { + std::va_list vl; + va_start(vl, fmt); + reply += util::VSNPrintf(reply, remaining_size, fmt, vl); + va_end(vl); + } } constexpr int DecodeHex(char c) { @@ -384,10 +378,10 @@ namespace ams::dmnt { return value; } - void MemoryToHex(char *dst, const void *mem, size_t size) { + void MemoryToHex(char *dst, char * const dst_end, const void *mem, size_t size) { const u8 *mem_u8 = static_cast(mem); - while (size-- > 0) { + while (size-- > 0 && dst < dst_end - 1) { const u8 v = *(mem_u8++); *(dst++) = "0123456789abcdef"[v >> 4]; *(dst++) = "0123456789abcdef"[v & 0xF]; @@ -439,76 +433,76 @@ namespace ams::dmnt { return 0; } - void SetGdbRegister32(char *dst, u32 value) { + void SetGdbRegister32(char *dst, char * const dst_end, u32 value) { if (value != 0) { - AppendReply(dst, "%08x", util::ConvertToBigEndian(value)); + AppendReplyFormat(dst, dst_end, "%08x", util::ConvertToBigEndian(value)); } else { - AppendReply(dst, "0*\"00"); + AppendReplyFormat(dst, dst_end, "0*\"00"); } } - void SetGdbRegister64(char *dst, u64 value) { + void SetGdbRegister64(char *dst, char * const dst_end, u64 value) { if (value != 0) { - AppendReply(dst, "%016lx", util::ConvertToBigEndian(value)); + AppendReplyFormat(dst, dst_end, "%016lx", util::ConvertToBigEndian(value)); } else { - AppendReply(dst, "0*,"); + AppendReplyFormat(dst, dst_end, "0*,"); } } - void SetGdbRegister128(char *dst, u128 value) { + void SetGdbRegister128(char *dst, char * const dst_end, u128 value) { if (value != 0) { - AppendReply(dst, "%016lx%016lx", util::ConvertToBigEndian(static_cast(value >> 0)), util::ConvertToBigEndian(static_cast(value >> BITSIZEOF(u64)))); + AppendReplyFormat(dst, dst_end, "%016lx%016lx", util::ConvertToBigEndian(static_cast(value >> 0)), util::ConvertToBigEndian(static_cast(value >> BITSIZEOF(u64)))); } else { - AppendReply(dst, "0*<"); + AppendReplyFormat(dst, dst_end, "0*<"); } } - void SetGdbRegisterPacket(char *dst, const svc::ThreadContext &thread_context, bool is_64_bit) { + void SetGdbRegisterPacket(char *dst, char * const dst_end, const svc::ThreadContext &thread_context, bool is_64_bit) { /* Clear packet. */ dst[0] = 0; if (is_64_bit) { /* Copy general purpose registers. */ for (size_t i = 0; i < util::size(thread_context.r); ++i) { - SetGdbRegister64(dst, thread_context.r[i]); + SetGdbRegister64(dst, dst_end, thread_context.r[i]); } /* Copy special registers. */ - SetGdbRegister64(dst, thread_context.fp); - SetGdbRegister64(dst, thread_context.lr); - SetGdbRegister64(dst, thread_context.sp); - SetGdbRegister64(dst, thread_context.pc); + SetGdbRegister64(dst, dst_end, thread_context.fp); + SetGdbRegister64(dst, dst_end, thread_context.lr); + SetGdbRegister64(dst, dst_end, thread_context.sp); + SetGdbRegister64(dst, dst_end, thread_context.pc); - SetGdbRegister32(dst, thread_context.pstate); + SetGdbRegister32(dst, dst_end, thread_context.pstate); /* Copy FPU registers. */ for (size_t i = 0; i < util::size(thread_context.v); ++i) { - SetGdbRegister128(dst, thread_context.v[i]); + SetGdbRegister128(dst, dst_end, thread_context.v[i]); } - SetGdbRegister32(dst, thread_context.fpsr); - SetGdbRegister32(dst, thread_context.fpcr); + SetGdbRegister32(dst, dst_end, thread_context.fpsr); + SetGdbRegister32(dst, dst_end, thread_context.fpcr); } else { /* Copy general purpose registers. */ for (size_t i = 0; i < 15; ++i) { - SetGdbRegister32(dst, thread_context.r[i]); + SetGdbRegister32(dst, dst_end, thread_context.r[i]); } /* Copy special registers. */ - SetGdbRegister32(dst, thread_context.pc); - SetGdbRegister32(dst, thread_context.pstate); + SetGdbRegister32(dst, dst_end, thread_context.pc); + SetGdbRegister32(dst, dst_end, thread_context.pstate); /* Copy FPU registers. */ for (size_t i = 0; i < util::size(thread_context.v) / 2; ++i) { - SetGdbRegister128(dst, thread_context.v[i]); + SetGdbRegister128(dst, dst_end, thread_context.v[i]); } const u32 fpscr = (thread_context.fpsr & 0xF80000FF) | (thread_context.fpcr & 0x07FFFF00); - SetGdbRegister32(dst, fpscr); + SetGdbRegister32(dst, dst_end, fpscr); } } - void SetGdbRegisterPacket(char *dst, const svc::ThreadContext &thread_context, u64 reg_num, bool is_64_bit) { + void SetGdbRegisterPacket(char *dst, char * const dst_end, const svc::ThreadContext &thread_context, u64 reg_num, bool is_64_bit) { /* Clear packet. */ dst[0] = 0; @@ -575,9 +569,9 @@ namespace ams::dmnt { } switch (reg_size) { - case sizeof(u32): SetGdbRegister32 (dst, v.v32 ); break; - case sizeof(u64): SetGdbRegister64 (dst, v.v64 ); break; - case sizeof(u128): SetGdbRegister128(dst, v.v128); break; + case sizeof(u32): SetGdbRegister32 (dst, dst_end, v.v32 ); break; + case sizeof(u64): SetGdbRegister64 (dst, dst_end, v.v64 ); break; + case sizeof(u128): SetGdbRegister128(dst, dst_end, v.v128); break; AMS_UNREACHABLE_DEFAULT_CASE(); } } @@ -827,23 +821,29 @@ namespace ams::dmnt { constinit AnnexBufferContents g_annex_buffer_contents = AnnexBufferContents_Invalid; - void GetAnnexBufferContents(char *dst, u32 offset, u32 length) { + void GetAnnexBufferContents(char * &dst, u32 offset, u32 length) { const u32 annex_len = std::strlen(g_annex_buffer); if (offset <= annex_len) { if (offset + length < annex_len) { dst[0] = 'm'; std::memcpy(dst + 1, g_annex_buffer + offset, length); dst[1 + length] = 0; + + dst += 1 + length; } else { const auto size = annex_len - offset; dst[0] = 'l'; std::memcpy(dst + 1, g_annex_buffer + offset, size); dst[1 + size] = 0; + + dst += 1 + size; } } else { dst[0] = '1'; dst[1] = 0; + + dst += 1; } } @@ -977,12 +977,14 @@ namespace ams::dmnt { } /* Process the event. */ - bool reply = false; GdbSignal signal; char send_buffer[GdbPacketBufferSize]; u64 thread_id = d.thread_id; m_debug_process.ClearStep(); + char * reply_cur = send_buffer; + char * const reply_end = std::end(send_buffer); + send_buffer[0] = 0; switch (d.type) { case svc::DebugEvent_Exception: @@ -997,7 +999,7 @@ namespace ams::dmnt { AMS_DMNT2_GDB_LOG_DEBUG("BreakPoint %lx, addr=%lx, type=%s\n", thread_id, address, is_instr ? "Instr" : "Data"); if (is_instr) { - SetReply(send_buffer, "T%02Xthread:p%lx.%lx;hwbreak:;", static_cast(signal), m_process_id.value, thread_id); + AppendReplyFormat(reply_cur, reply_end, "T%02Xthread:p%lx.%lx;hwbreak:;", static_cast(signal), m_process_id.value, thread_id); } else { bool read = false, write = false; const char *type = "watch"; @@ -1011,10 +1013,8 @@ namespace ams::dmnt { AMS_DMNT2_GDB_LOG_DEBUG("GetWatchPointInfo FAIL %lx, addr=%lx, type=%s\n", thread_id, address, is_instr ? "Instr" : "Data"); } - SetReply(send_buffer, "T%02Xthread:p%lx.%lx;%s:%lx;", static_cast(signal), m_process_id.value, thread_id, type, address); + AppendReplyFormat(reply_cur, reply_end, "T%02Xthread:p%lx.%lx;%s:%lx;", static_cast(signal), m_process_id.value, thread_id, type, address); } - - reply = true; } break; case svc::DebugException_UserBreak: @@ -1096,6 +1096,8 @@ namespace ams::dmnt { const u32 insn = d.info.exception.specific.undefined_instruction.insn; u32 new_insn = 0; + AMS_DMNT2_GDB_LOG_DEBUG("Undefined Instruction %lx, address=%p, insn=%08x\n", thread_id, reinterpret_cast(address), insn); + bool is_new_hb_nro = false; svc::ThreadContext ctx; @@ -1160,14 +1162,13 @@ namespace ams::dmnt { } if (signal == GdbSignal_IllegalInstruction) { - AMS_DMNT2_GDB_LOG_DEBUG("Undefined Instruction %lx, address=%p, insn=%08x\n", thread_id, reinterpret_cast(address), insn); + AMS_DMNT2_GDB_LOG_DEBUG("Illegal Instruction %lx, address=%p, insn=%08x\n", thread_id, reinterpret_cast(address), insn); } else if (signal == GdbSignal_BreakpointTrap && ((insn & SdkBreakPointMask) != SdkBreakPoint)) { AMS_DMNT2_GDB_LOG_DEBUG("Non-SDK BreakPoint %lx, address=%p, insn=%08x\n", thread_id, reinterpret_cast(address), insn); } if (signal == GdbSignal_BreakpointTrap && !is_new_hb_nro) { - SetReply(send_buffer, "T%02Xthread:p%lx.%lx;swbreak:;", static_cast(signal), m_process_id.value, thread_id); - reply = true; + AppendReplyFormat(reply_cur, reply_end, "T%02Xthread:p%lx.%lx;swbreak:;", static_cast(signal), m_process_id.value, thread_id); } m_debug_process.ClearStep(); @@ -1179,9 +1180,8 @@ namespace ams::dmnt { break; } - if (!reply) { - SetReply(send_buffer, "T%02Xthread:p%lx.%lx;", static_cast(signal), m_process_id.value, thread_id); - reply = true; + if (reply_cur == send_buffer) { + AppendReplyFormat(reply_cur, reply_end, "T%02Xthread:p%lx.%lx;", static_cast(signal), m_process_id.value, thread_id); } m_debug_process.SetLastThreadId(thread_id); @@ -1195,8 +1195,7 @@ namespace ams::dmnt { if (m_debug_process.IsValid()) { m_debug_process.Continue(); } else { - SetReply(send_buffer, "W00"); - reply = true; + AppendReplyFormat(reply_cur, reply_end, "W00"); } } break; @@ -1207,8 +1206,7 @@ namespace ams::dmnt { if (m_debug_process.IsValid()) { m_debug_process.Continue(); } else { - SetReply(send_buffer, "W00"); - reply = true; + AppendReplyFormat(reply_cur, reply_end, "W00"); } } break; @@ -1218,13 +1216,12 @@ namespace ams::dmnt { AMS_DMNT2_GDB_LOG_DEBUG("ExitProcess\n"); if (d.info.exit_process.reason == svc::ProcessExitReason_ExitProcess) { - SetReply(send_buffer, "W00"); + AppendReplyFormat(reply_cur, reply_end, "W00"); } else { - SetReply(send_buffer, "X%02X", GdbSignal_Killed); + AppendReplyFormat(reply_cur, reply_end, "X%02X", GdbSignal_Killed); } m_debug_process.Detach(); - reply = true; } break; default: @@ -1233,7 +1230,7 @@ namespace ams::dmnt { break; } - if (reply) { + if (reply_cur != send_buffer) { bool do_break; this->SendPacket(std::addressof(do_break), send_buffer); if (do_break) { @@ -1243,9 +1240,9 @@ namespace ams::dmnt { } } - void GdbServerImpl::SetStopReplyPacket(GdbSignal signal) { + void GdbServerImpl::AppendStopReplyPacket(GdbSignal signal) { /* Set the signal. */ - SetReply(m_reply_packet, "T%02X", static_cast(signal)); + AppendReplyFormat(m_reply_cur, m_reply_end, "T%02X", static_cast(signal)); /* Get the last thread id. */ const u64 thread_id = m_debug_process.GetLastThreadId(); @@ -1258,33 +1255,33 @@ namespace ams::dmnt { /* TODO: aarch32 */ { if (thread_context.fp != 0) { - AppendReply(m_reply_packet, "1d:%016lx", util::ConvertToBigEndian(thread_context.fp)); + AppendReplyFormat(m_reply_cur, m_reply_end, "1d:%016lx", util::ConvertToBigEndian(thread_context.fp)); } else { - AppendReply(m_reply_packet, "1d:0*,"); + AppendReplyFormat(m_reply_cur, m_reply_end, "1d:0*,"); } if (thread_context.sp != 0) { - AppendReply(m_reply_packet, ";1f:%016lx", util::ConvertToBigEndian(thread_context.sp)); + AppendReplyFormat(m_reply_cur, m_reply_end, ";1f:%016lx", util::ConvertToBigEndian(thread_context.sp)); } else { - AppendReply(m_reply_packet, ";1f:0*,"); + AppendReplyFormat(m_reply_cur, m_reply_end, ";1f:0*,"); } if (thread_context.pc != 0) { - AppendReply(m_reply_packet, ";20:%016lx", util::ConvertToBigEndian(thread_context.pc)); + AppendReplyFormat(m_reply_cur, m_reply_end, ";20:%016lx", util::ConvertToBigEndian(thread_context.pc)); } else { - AppendReply(m_reply_packet, ";20:0*,"); + AppendReplyFormat(m_reply_cur, m_reply_end, ";20:0*,"); } } /* Add the thread id. */ - AppendReply(m_reply_packet, ";thread:p%lx.%lx", m_process_id.value, thread_id); + AppendReplyFormat(m_reply_cur, m_reply_end, ";thread:p%lx.%lx", m_process_id.value, thread_id); /* Add the thread core. */ { u32 core = 0; m_debug_process.GetThreadCurrentCore(std::addressof(core), thread_id); - AppendReply(m_reply_packet, ";core:%u;", core); + AppendReplyFormat(m_reply_cur, m_reply_end, ";core:%u;", core); } } @@ -1315,13 +1312,14 @@ namespace ams::dmnt { void GdbServerImpl::ProcessPacket(char *receive, char *reply) { /* Set our fields. */ m_receive_packet = receive; - m_reply_packet = reply; + m_reply_cur = reply; + m_reply_end = reply + GdbPacketBufferSize; /* 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; + reply[0] = 0; /* Handle the received packet. */ switch (m_receive_packet[0]) { @@ -1376,7 +1374,7 @@ namespace ams::dmnt { this->z(); break; case '!': - SetReplyOk(m_reply_packet); + AppendReplyOk(m_reply_cur, m_reply_end); break; case '?': this->QuestionMark(); @@ -1389,7 +1387,7 @@ namespace ams::dmnt { void GdbServerImpl::D() { m_debug_process.Detach(); - SetReplyOk(m_reply_packet); + AppendReplyOk(m_reply_cur, m_reply_end); } void GdbServerImpl::G() { @@ -1402,7 +1400,7 @@ namespace ams::dmnt { /* Get thread context. */ svc::ThreadContext ctx; if (R_FAILED(m_debug_process.GetThreadContext(std::addressof(ctx), thread_id, svc::ThreadContextFlag_All))) { - SetReplyError(m_reply_packet, "E01"); + AppendReplyError(m_reply_cur, m_reply_end, "E01"); return; } @@ -1411,9 +1409,9 @@ namespace ams::dmnt { /* Set the thread context. */ if (R_SUCCEEDED(m_debug_process.SetThreadContext(std::addressof(ctx), thread_id, svc::ThreadContextFlag_All))) { - SetReplyOk(m_reply_packet); + AppendReplyOk(m_reply_cur, m_reply_end); } else { - SetReplyError(m_reply_packet, "E01"); + AppendReplyError(m_reply_cur, m_reply_end, "E01"); } } @@ -1422,10 +1420,10 @@ namespace ams::dmnt { if (ParsePrefix(m_receive_packet, "Hg") || ParsePrefix(m_receive_packet, "HG")) { this->Hg(); } else { - SetReplyError(m_reply_packet, "E01"); + AppendReplyError(m_reply_cur, m_reply_end, "E01"); } } else { - SetReplyError(m_reply_packet, "E01"); + AppendReplyError(m_reply_cur, m_reply_end, "E01"); } } @@ -1457,9 +1455,9 @@ namespace ams::dmnt { } if (success) { - SetReplyOk(m_reply_packet); + AppendReplyOk(m_reply_cur, m_reply_end); } else { - SetReplyError(m_reply_packet, "E01"); + AppendReplyError(m_reply_cur, m_reply_end, "E01"); } } @@ -1469,14 +1467,14 @@ namespace ams::dmnt { /* Validate format. */ char *comma = std::strchr(m_receive_packet, ','); if (comma == nullptr) { - SetReplyError(m_reply_packet, "E01"); + AppendReplyError(m_reply_cur, m_reply_end, "E01"); return; } *comma = 0; char *colon = std::strchr(comma + 1, ':'); if (colon == nullptr) { - SetReplyError(m_reply_packet, "E01"); + AppendReplyError(m_reply_cur, m_reply_end, "E01"); return; } *colon = 0; @@ -1485,7 +1483,7 @@ namespace ams::dmnt { const u64 address = DecodeHex(m_receive_packet); const u64 length = DecodeHex(comma + 1); if (length >= sizeof(m_buffer)) { - SetReplyError(m_reply_packet, "E01"); + AppendReplyError(m_reply_cur, m_reply_end, "E01"); return; } @@ -1494,9 +1492,9 @@ namespace ams::dmnt { /* Write the memory. */ if (R_SUCCEEDED(m_debug_process.WriteMemory(m_buffer, address, length))) { - SetReplyOk(m_reply_packet); + AppendReplyOk(m_reply_cur, m_reply_end); } else { - SetReplyError(m_reply_packet, "E01"); + AppendReplyError(m_reply_cur, m_reply_end, "E01"); } } @@ -1506,7 +1504,7 @@ namespace ams::dmnt { /* Validate format. */ char *equal = std::strchr(m_receive_packet, '='); if (equal == nullptr) { - SetReplyError(m_reply_packet, "E01"); + AppendReplyError(m_reply_cur, m_reply_end, "E01"); return; } *equal = 0; @@ -1529,12 +1527,12 @@ namespace ams::dmnt { ParseGdbRegisterPacket(ctx, equal + 1, reg_num, m_debug_process.Is64Bit()); if (R_SUCCEEDED(m_debug_process.SetThreadContext(std::addressof(ctx), thread_id, flags))) { - SetReplyOk(m_reply_packet); + AppendReplyOk(m_reply_cur, m_reply_end); } else { - SetReplyError(m_reply_packet, "E01"); + AppendReplyError(m_reply_cur, m_reply_end, "E01"); } } else { - SetReplyError(m_reply_packet, "E01"); + AppendReplyError(m_reply_cur, m_reply_end, "E01"); } } @@ -1552,12 +1550,12 @@ namespace ams::dmnt { svc::ThreadContext ctx; if (R_SUCCEEDED(m_debug_process.GetThreadContext(std::addressof(ctx), thread_id, svc::ThreadContextFlag_Control))) { - SetReplyOk(m_reply_packet); + AppendReplyOk(m_reply_cur, m_reply_end); } else { - SetReply(m_reply_packet, "E01"); + AppendReplyFormat(m_reply_cur, m_reply_end, "E01"); } } else { - SetReplyError(m_reply_packet, "E01"); + AppendReplyError(m_reply_cur, m_reply_end, "E01"); } } @@ -1567,7 +1565,7 @@ namespace ams::dmnt { /* Decode the type. */ if (!('0' <= m_receive_packet[0] && m_receive_packet[0] <= '4') || m_receive_packet[1] != ',') { - SetReplyError(m_reply_packet, "E01"); + AppendReplyError(m_reply_cur, m_reply_end, "E01"); return; } @@ -1577,7 +1575,7 @@ namespace ams::dmnt { /* Decode the address/length. */ const char *comma = std::strchr(m_receive_packet, ','); if (comma == nullptr) { - SetReplyError(m_reply_packet, "E01"); + AppendReplyError(m_reply_cur, m_reply_end, "E01"); return; } @@ -1590,9 +1588,9 @@ namespace ams::dmnt { { if (length == 2 || length == 4) { if (R_SUCCEEDED(m_debug_process.SetBreakPoint(address, length, false))) { - SetReplyOk(m_reply_packet); + AppendReplyOk(m_reply_cur, m_reply_end); } else { - SetReplyError(m_reply_packet, "E01"); + AppendReplyError(m_reply_cur, m_reply_end, "E01"); } } } @@ -1601,9 +1599,9 @@ namespace ams::dmnt { { if (length == 2 || length == 4) { if (R_SUCCEEDED(m_debug_process.SetHardwareBreakPoint(address, length, false))) { - SetReplyOk(m_reply_packet); + AppendReplyOk(m_reply_cur, m_reply_end); } else { - SetReplyError(m_reply_packet, "E01"); + AppendReplyError(m_reply_cur, m_reply_end, "E01"); } } } @@ -1612,9 +1610,9 @@ namespace ams::dmnt { { if (m_debug_process.IsValidWatchPoint(address, length)) { if (R_SUCCEEDED(m_debug_process.SetWatchPoint(address, length, false, true))) { - SetReplyOk(m_reply_packet); + AppendReplyOk(m_reply_cur, m_reply_end); } else { - SetReplyError(m_reply_packet, "E01"); + AppendReplyError(m_reply_cur, m_reply_end, "E01"); } } } @@ -1623,9 +1621,9 @@ namespace ams::dmnt { { if (m_debug_process.IsValidWatchPoint(address, length)) { if (R_SUCCEEDED(m_debug_process.SetWatchPoint(address, length, true, false))) { - SetReplyOk(m_reply_packet); + AppendReplyOk(m_reply_cur, m_reply_end); } else { - SetReplyError(m_reply_packet, "E01"); + AppendReplyError(m_reply_cur, m_reply_end, "E01"); } } } @@ -1634,9 +1632,9 @@ namespace ams::dmnt { { if (m_debug_process.IsValidWatchPoint(address, length)) { if (R_SUCCEEDED(m_debug_process.SetWatchPoint(address, length, true, true))) { - SetReplyOk(m_reply_packet); + AppendReplyOk(m_reply_cur, m_reply_end); } else { - SetReplyError(m_reply_packet, "E01"); + AppendReplyError(m_reply_cur, m_reply_end, "E01"); } } } @@ -1662,9 +1660,9 @@ namespace ams::dmnt { } if (R_SUCCEEDED(result)) { - SetReplyOk(m_reply_packet); + AppendReplyOk(m_reply_cur, m_reply_end); } else { - SetReplyError(m_reply_packet, "E01"); + AppendReplyError(m_reply_cur, m_reply_end, "E01"); } } @@ -1682,7 +1680,7 @@ namespace ams::dmnt { } /* Populate reply packet. */ - SetGdbRegisterPacket(m_reply_packet, thread_context, m_debug_process.Is64Bit()); + SetGdbRegisterPacket(m_reply_cur, m_reply_end, thread_context, m_debug_process.Is64Bit()); return true; } @@ -1693,7 +1691,7 @@ namespace ams::dmnt { /* Validate format. */ const char *comma = std::strchr(m_receive_packet, ','); if (comma == nullptr) { - SetReplyError(m_reply_packet, "E01"); + AppendReplyError(m_reply_cur, m_reply_end, "E01"); return; } @@ -1701,19 +1699,19 @@ namespace ams::dmnt { const u64 address = DecodeHex(m_receive_packet); const u64 length = DecodeHex(comma + 1); if (length >= sizeof(m_buffer)) { - SetReplyError(m_reply_packet, "E01"); + AppendReplyError(m_reply_cur, m_reply_end, "E01"); return; } /* Read the memory. */ /* TODO: Detect partial readability? */ if (R_FAILED(m_debug_process.ReadMemory(m_buffer, address, length))) { - SetReplyError(m_reply_packet, "E01"); + AppendReplyError(m_reply_cur, m_reply_end, "E01"); return; } /* Encode the memory. */ - MemoryToHex(m_reply_packet, m_buffer, length); + MemoryToHex(m_reply_cur, m_reply_end, m_buffer, length); } void GdbServerImpl::k() { @@ -1739,9 +1737,9 @@ namespace ams::dmnt { /* Get the register. */ svc::ThreadContext ctx; if (R_SUCCEEDED(m_debug_process.GetThreadContext(std::addressof(ctx), thread_id, flags))) { - SetGdbRegisterPacket(m_reply_packet, ctx, reg_num, m_debug_process.Is64Bit()); + SetGdbRegisterPacket(m_reply_cur, m_reply_end, ctx, reg_num, m_debug_process.Is64Bit()); } else { - SetReplyError(m_reply_packet, "E01"); + AppendReplyError(m_reply_cur, m_reply_end, "E01"); } } @@ -1774,22 +1772,22 @@ namespace ams::dmnt { /* If we're attached, send a stop reply packet. */ if (m_debug_process.IsValid()) { /* Set the stop reply packet. */ - this->SetStopReplyPacket(m_debug_process.GetLastSignal()); + this->AppendStopReplyPacket(m_debug_process.GetLastSignal()); } else { - SetReplyError(m_reply_packet, "E01"); + AppendReplyError(m_reply_cur, m_reply_end, "E01"); } } else { - SetReplyError(m_reply_packet, "E01"); + AppendReplyError(m_reply_cur, m_reply_end, "E01"); } } else { - SetReplyError(m_reply_packet, "E01"); + AppendReplyError(m_reply_cur, m_reply_end, "E01"); } } void GdbServerImpl::vCont() { /* Check if this is a query about what we support. */ if (ParsePrefix(m_receive_packet, "?")) { - SetReply(m_reply_packet, "vCont;c;C;s;S;"); + AppendReplyFormat(m_reply_cur, m_reply_end, "vCont;c;C;s;S;"); return; } @@ -1809,7 +1807,7 @@ namespace ams::dmnt { s32 num_threads; if (R_FAILED(m_debug_process.GetThreadList(std::addressof(num_threads), thread_ids, util::size(thread_ids)))) { AMS_DMNT2_GDB_LOG_ERROR("vCont: Failed to get thread list\n"); - SetReplyError(m_reply_packet, "E01"); + AppendReplyError(m_reply_cur, m_reply_end, "E01"); return; } @@ -1841,10 +1839,10 @@ namespace ams::dmnt { /* Set reply. */ if (R_SUCCEEDED(result)) { - SetReplyOk(m_reply_packet); + AppendReplyOk(m_reply_cur, m_reply_end); } else { AMS_DMNT2_GDB_LOG_ERROR("vCont: Failed %08x\n", result.GetValue()); - SetReplyError(m_reply_packet, "E01"); + AppendReplyError(m_reply_cur, m_reply_end, "E01"); } } @@ -1938,18 +1936,18 @@ namespace ams::dmnt { void GdbServerImpl::qAttached() { if (this->HasDebugProcess()) { - SetReply(m_reply_packet, "1"); + AppendReplyFormat(m_reply_cur, m_reply_end, "1"); } else { - SetReplyError(m_reply_packet, "E01"); + AppendReplyError(m_reply_cur, m_reply_end, "E01"); } } void GdbServerImpl::qC() { if (this->HasDebugProcess()) { /* Send the thread id. */ - SetReply(m_reply_packet, "QCp%lx.%lx", m_process_id.value, m_debug_process.GetLastThreadId()); + AppendReplyFormat(m_reply_cur, m_reply_end, "QCp%lx.%lx", m_process_id.value, m_debug_process.GetLastThreadId()); } else { - SetReplyError(m_reply_packet, "E01"); + AppendReplyError(m_reply_cur, m_reply_end, "E01"); } } @@ -1962,59 +1960,75 @@ namespace ams::dmnt { /* Convert our response to hex, on complete. */ ON_SCOPE_EXIT { /* Convert response to hex. */ - MemoryToHex(m_reply_packet, m_buffer, std::strlen(m_buffer)); + MemoryToHex(m_reply_cur, m_reply_end, m_buffer, std::strlen(m_buffer)); }; + char *reply_cur = m_buffer; + char *reply_end = m_buffer + sizeof(m_buffer); + /* Parse the command. */ char *command = reinterpret_cast(m_buffer); if (ParsePrefix(command, "help")) { - SetReply(m_buffer, "get info\n" - "get mappings\n" - "get mapping {address}\n" - "wait application\n" - "wait {program id}\n" - "wait homebrew\n"); + AppendReplyFormat(reply_cur, reply_end, "get info\n" + "get mappings\n" + "get mappings {address}\n" + "get mapping {address}\n" + "wait application\n" + "wait {program id}\n" + "wait homebrew\n"); } else if (ParsePrefix(command, "get base") || ParsePrefix(command, "get info") || ParsePrefix(command, "get modules")) { if (!this->HasDebugProcess()) { - SetReply(m_buffer, "Not attached.\n"); + AppendReplyFormat(reply_cur, reply_end, "Not attached.\n"); return; } - SetReply(m_buffer, "Process: 0x%lx (%s)\n" - "Program Id: 0x%016lx\n" - "Application: %d\n" - "Hbl: %d\n" - "Layout:\n", m_process_id.value, m_debug_process.GetProcessName(), m_debug_process.GetProgramLocation().program_id.value, m_debug_process.IsApplication(), m_debug_process.GetOverrideStatus().IsHbl()); + AppendReplyFormat(reply_cur, reply_end, "Process: 0x%lx (%s)\n" + "Program Id: 0x%016lx\n" + "Application: %d\n" + "Hbl: %d\n" + "Layout:\n", m_process_id.value, m_debug_process.GetProcessName(), m_debug_process.GetProgramLocation().program_id.value, m_debug_process.IsApplication(), m_debug_process.GetOverrideStatus().IsHbl()); - AppendReply(m_buffer, " Alias: 0x%010lx - 0x%010lx\n" - " Heap: 0x%010lx - 0x%010lx\n" - " Aslr: 0x%010lx - 0x%010lx\n" - " Stack: 0x%010lx - 0x%010lx\n" - "Modules:\n", m_debug_process.GetAliasRegionAddress(), m_debug_process.GetAliasRegionAddress() + m_debug_process.GetAliasRegionSize() - 1, - m_debug_process.GetHeapRegionAddress(), m_debug_process.GetHeapRegionAddress() + m_debug_process.GetHeapRegionSize() - 1, - m_debug_process.GetAslrRegionAddress(), m_debug_process.GetAslrRegionAddress() + m_debug_process.GetAslrRegionSize() - 1, - m_debug_process.GetStackRegionAddress(), m_debug_process.GetStackRegionAddress() + m_debug_process.GetStackRegionSize() - 1); + AppendReplyFormat(reply_cur, reply_end, " Alias: 0x%010lx - 0x%010lx\n" + " Heap: 0x%010lx - 0x%010lx\n" + " Aslr: 0x%010lx - 0x%010lx\n" + " Stack: 0x%010lx - 0x%010lx\n" + "Modules:\n", m_debug_process.GetAliasRegionAddress(), m_debug_process.GetAliasRegionAddress() + m_debug_process.GetAliasRegionSize() - 1, + m_debug_process.GetHeapRegionAddress(), m_debug_process.GetHeapRegionAddress() + m_debug_process.GetHeapRegionSize() - 1, + m_debug_process.GetAslrRegionAddress(), m_debug_process.GetAslrRegionAddress() + m_debug_process.GetAslrRegionSize() - 1, + m_debug_process.GetStackRegionAddress(), m_debug_process.GetStackRegionAddress() + m_debug_process.GetStackRegionSize() - 1); /* Get the module list. */ for (size_t i = 0; i < m_debug_process.GetModuleCount(); ++i) { const char *module_name = m_debug_process.GetModuleName(i); const auto name_len = std::strlen(module_name); if (name_len < 5 || (std::strcmp(module_name + name_len - 4, ".elf") != 0 && std::strcmp(module_name + name_len - 4, ".nss") != 0)) { - AppendReply(m_buffer, " 0x%010lx - 0x%010lx %s.elf\n", m_debug_process.GetModuleBaseAddress(i), m_debug_process.GetModuleBaseAddress(i) + m_debug_process.GetModuleSize(i) - 1, module_name); + AppendReplyFormat(reply_cur, reply_end, " 0x%010lx - 0x%010lx %s.elf\n", m_debug_process.GetModuleBaseAddress(i), m_debug_process.GetModuleBaseAddress(i) + m_debug_process.GetModuleSize(i) - 1, module_name); } else { - AppendReply(m_buffer, " 0x%010lx - 0x%010lx %s\n", m_debug_process.GetModuleBaseAddress(i), m_debug_process.GetModuleBaseAddress(i) + m_debug_process.GetModuleSize(i) - 1, module_name); + AppendReplyFormat(reply_cur, reply_end, " 0x%010lx - 0x%010lx %s\n", m_debug_process.GetModuleBaseAddress(i), m_debug_process.GetModuleBaseAddress(i) + m_debug_process.GetModuleSize(i) - 1, module_name); } } } else if (ParsePrefix(command, "get mappings")) { if (!this->HasDebugProcess()) { - SetReply(m_buffer, "Not attached.\n"); + AppendReplyFormat(reply_cur, reply_end, "Not attached.\n"); return; } - SetReply(m_buffer, "Mappings:\n"); - uintptr_t cur_addr = 0; + if (ParsePrefix(command, " ")) { + ParsePrefix(command, "0x"); + + cur_addr = DecodeHex(command); + } + + AppendReplyFormat(reply_cur, reply_end, "Mappings (starting from 0x%010lx):\n", cur_addr); + while (true) { + /* Check if we have room for a mapping. */ + if (reply_end - reply_cur < 0x48 * 2) { + AppendReplyFormat(reply_cur, reply_end, "<-- Send `monitor get mappings 0x%010lx` to continue -->\n", cur_addr); + break; + } + /* Get mapping. */ svc::MemoryInfo mem_info; if (R_FAILED(m_debug_process.QueryMemory(std::addressof(mem_info), cur_addr))) { @@ -2030,7 +2044,7 @@ namespace ams::dmnt { const char d = (mem_info.attribute & svc::MemoryAttribute_DeviceShared) ? 'D' : '-'; const char u = (mem_info.attribute & svc::MemoryAttribute_Uncached) ? 'U' : '-'; - AppendReply(m_buffer, " 0x%010lx - 0x%010lx %s %s %c%c%c%c [%d, %d]\n", mem_info.base_address, mem_info.base_address + mem_info.size - 1, perm, state, l, i, d, u, mem_info.ipc_count, mem_info.device_count); + AppendReplyFormat(reply_cur, reply_end, " 0x%010lx - 0x%010lx %s %s %c%c%c%c [%d, %d]\n", mem_info.base_address, mem_info.base_address + mem_info.size - 1, perm, state, l, i, d, u, mem_info.ipc_count, mem_info.device_count); } /* Advance. */ @@ -2041,10 +2055,9 @@ namespace ams::dmnt { cur_addr = next_address; } - } else if (ParsePrefix(command, "get mapping ")) { if (!this->HasDebugProcess()) { - SetReply(m_buffer, "Not attached.\n"); + AppendReplyFormat(reply_cur, reply_end, "Not attached.\n"); return; } @@ -2057,7 +2070,7 @@ namespace ams::dmnt { /* Get mapping. */ svc::MemoryInfo mem_info; if (R_FAILED(m_debug_process.QueryMemory(std::addressof(mem_info), address))) { - SetReply(m_buffer, "0x%016lx: No mapping.\n", address); + AppendReplyFormat(reply_cur, reply_end, "0x%016lx: No mapping.\n", address); } const char *state = GetMemoryStateName(mem_info.state); @@ -2068,7 +2081,7 @@ namespace ams::dmnt { const char d = (mem_info.attribute & svc::MemoryAttribute_DeviceShared) ? 'D' : '-'; const char u = (mem_info.attribute & svc::MemoryAttribute_Uncached) ? 'U' : '-'; - SetReply(m_buffer, "0x%010lx - 0x%010lx %s %s %c%c%c%c [%d, %d]\n", mem_info.base_address, mem_info.base_address + mem_info.size - 1, perm, state, l, i, d, u, mem_info.ipc_count, mem_info.device_count); + AppendReplyFormat(reply_cur, reply_end, "0x%010lx - 0x%010lx %s %s %c%c%c%c [%d, %d]\n", mem_info.base_address, mem_info.base_address + mem_info.size - 1, perm, state, l, i, d, u, mem_info.ipc_count, mem_info.device_count); } else if (ParsePrefix(command, "wait application") || ParsePrefix(command, "wait app")) { /* Wait for an application process. */ { @@ -2085,7 +2098,7 @@ namespace ams::dmnt { R_ABORT_UNLESS(pm::dmnt::GetApplicationProcessId(std::addressof(m_wait_process_id))); /* Note that we're attaching. */ - SetReply(m_buffer, "Attach to 0x%lx.\n", m_wait_process_id.value); + AppendReplyFormat(reply_cur, reply_end, "Send `attach 0x%lx` to attach.\n", m_wait_process_id.value); } else if (ParsePrefix(command, "wait ")) { /* Allow optional "0x" prefix. */ ParsePrefix(command, "0x"); @@ -2093,10 +2106,10 @@ namespace ams::dmnt { /* Decode program id. */ const u64 program_id = DecodeHex(command); - SetReply(m_buffer, "[TODO] wait for program id 0x%lx\n", program_id); + AppendReplyFormat(reply_cur, reply_end, "[TODO] wait for program id 0x%lx\n", program_id); } else { - SetReply(m_reply_packet, "Unknown command `%s`\n", command); - std::memcpy(m_buffer, m_reply_packet, std::strlen(m_reply_packet) + 1); + std::memcpy(m_reply_cur, command, std::strlen(command) + 1); + AppendReplyFormat(reply_cur, reply_end, "Unknown command `%s`\n", m_reply_cur); } } @@ -2104,18 +2117,18 @@ namespace ams::dmnt { /* 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+"); - // TODO: AppendReply(m_reply_packet, ";qXfer:libraries-svr4:read+"); - // TODO: AppendReply(m_reply_packet, ";augmented-libraries-svr4-read+"); - AppendReply(m_reply_packet, ";qXfer:threads:read+"); - AppendReply(m_reply_packet, ";qXfer:exec-file:read+"); - AppendReply(m_reply_packet, ";swbreak+"); - AppendReply(m_reply_packet, ";hwbreak+"); - AppendReply(m_reply_packet, ";vContSupported+"); + AppendReplyFormat(m_reply_cur, m_reply_end, "PacketSize=%lx", GdbPacketBufferSize - 1); + AppendReplyFormat(m_reply_cur, m_reply_end, ";multiprocess+"); + AppendReplyFormat(m_reply_cur, m_reply_end, ";qXfer:osdata:read+"); + AppendReplyFormat(m_reply_cur, m_reply_end, ";qXfer:features:read+"); + AppendReplyFormat(m_reply_cur, m_reply_end, ";qXfer:libraries:read+"); + // TODO: AppendReplyFormat(m_reply_cur, m_reply_end, ";qXfer:libraries-svr4:read+"); + // TODO: AppendReplyFormat(m_reply_cur, m_reply_end, ";augmented-libraries-svr4-read+"); + AppendReplyFormat(m_reply_cur, m_reply_end, ";qXfer:threads:read+"); + AppendReplyFormat(m_reply_cur, m_reply_end, ";qXfer:exec-file:read+"); + AppendReplyFormat(m_reply_cur, m_reply_end, ";swbreak+"); + AppendReplyFormat(m_reply_cur, m_reply_end, ";hwbreak+"); + AppendReplyFormat(m_reply_cur, m_reply_end, ";vContSupported+"); } void GdbServerImpl::qXfer() { @@ -2125,7 +2138,7 @@ namespace ams::dmnt { } else { /* All other qXfer require debug process. */ if (!this->HasDebugProcess()) { - SetReplyError(m_reply_packet, "E01"); + AppendReplyError(m_reply_cur, m_reply_end, "E01"); return; } @@ -2135,15 +2148,15 @@ namespace ams::dmnt { } else if (ParsePrefix(m_receive_packet, "threads:read::")) { if (!this->qXferThreadsRead()) { m_killed = true; - SetReplyError(m_reply_packet, "E01"); + AppendReplyError(m_reply_cur, m_reply_end, "E01"); } } else if (ParsePrefix(m_receive_packet, "libraries:read::")) { this->qXferLibrariesRead(); } else if (ParsePrefix(m_receive_packet, "exec-file:read:")) { - SetReply(m_reply_packet, "l%s", m_debug_process.GetProcessName()); + AppendReplyFormat(m_reply_cur, m_reply_end, "l%s", m_debug_process.GetProcessName()); } else { AMS_DMNT2_GDB_LOG_DEBUG("Not Implemented qxfer: %s\n", m_receive_packet); - SetReplyError(m_reply_packet, "E01"); + AppendReplyError(m_reply_cur, m_reply_end, "E01"); } } } @@ -2157,44 +2170,44 @@ namespace ams::dmnt { 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); + std::strncpy(m_reply_cur, (this->Is64Bit() ? TargetXmlAarch64 : TargetXmlAarch32) + offset, length); + m_reply_cur[length] = 0; + m_reply_cur += std::strlen(m_reply_cur); } 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); + std::strncpy(m_reply_cur, Aarch64CoreXml + offset, length); + m_reply_cur[length] = 0; + m_reply_cur += std::strlen(m_reply_cur); } 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); + std::strncpy(m_reply_cur, Aarch64FpuXml + offset, length); + m_reply_cur[length] = 0; + m_reply_cur += std::strlen(m_reply_cur); } 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); + std::strncpy(m_reply_cur, ArmCoreXml + offset, length); + m_reply_cur[length] = 0; + m_reply_cur += std::strlen(m_reply_cur); } 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); + std::strncpy(m_reply_cur, ArmVfpXml + offset, length); + m_reply_cur[length] = 0; + m_reply_cur += std::strlen(m_reply_cur); } else { AMS_DMNT2_GDB_LOG_DEBUG("Not Implemented qxfer:features:read: %s\n", m_receive_packet); - SetReplyError(m_reply_packet, "E01"); + AppendReplyError(m_reply_cur, m_reply_end, "E01"); } } @@ -2210,8 +2223,12 @@ namespace ams::dmnt { /* If doing a fresh read, generate the module list. */ if (offset == 0 || g_annex_buffer_contents != AnnexBufferContents_Libraries) { + /* Prepare to write to annex buffer. */ + char *dst_cur = g_annex_buffer; + char *dst_end = g_annex_buffer + sizeof(g_annex_buffer); + /* Set header. */ - SetReply(g_annex_buffer, ""); + AppendReplyFormat(dst_cur, dst_end, ""); /* Get the module list. */ for (size_t i = 0; i < m_debug_process.GetModuleCount(); ++i) { @@ -2220,19 +2237,19 @@ namespace ams::dmnt { const char *module_name = m_debug_process.GetModuleName(i); const auto name_len = std::strlen(module_name); if (name_len < 5 || (std::strcmp(module_name + name_len - 4, ".elf") != 0 && std::strcmp(module_name + name_len - 4, ".nss") != 0)) { - AppendReply(g_annex_buffer, "", module_name, m_debug_process.GetModuleBaseAddress(i)); + AppendReplyFormat(dst_cur, dst_end, "", module_name, m_debug_process.GetModuleBaseAddress(i)); } else { - AppendReply(g_annex_buffer, "", module_name, m_debug_process.GetModuleBaseAddress(i)); + AppendReplyFormat(dst_cur, dst_end, "", module_name, m_debug_process.GetModuleBaseAddress(i)); } } - AppendReply(g_annex_buffer, ""); + AppendReplyFormat(dst_cur, dst_end, ""); g_annex_buffer_contents = AnnexBufferContents_Libraries; } /* Copy out the module list. */ - GetAnnexBufferContents(m_reply_packet, offset, length); + GetAnnexBufferContents(m_reply_cur, offset, length); } void GdbServerImpl::qXferOsdataRead() { @@ -2248,11 +2265,15 @@ namespace ams::dmnt { /* If doing a fresh read, generate the process list. */ if (offset == 0 || g_annex_buffer_contents != AnnexBufferContents_Processes) { + /* Prepare to write to annex buffer. */ + char *dst_cur = g_annex_buffer; + char *dst_end = g_annex_buffer + sizeof(g_annex_buffer); + /* Clear the process list buffer. */ - g_annex_buffer[0] = 0; + dst_cur[0] = 0; /* Set header. */ - SetReply(g_annex_buffer, "\n\n\n"); + AppendReplyFormat(dst_cur, dst_end, "\n\n\n"); /* Get all processes. */ { @@ -2272,22 +2293,22 @@ namespace ams::dmnt { R_ABORT_UNLESS(svc::GetDebugEvent(std::addressof(d), handle)); AMS_ABORT_UNLESS(d.type == svc::DebugEvent_CreateProcess); - AppendReply(g_annex_buffer, "\n%lu\n%s\n\n", d.info.create_process.process_id, d.info.create_process.name); + AppendReplyFormat(dst_cur, dst_end, "\n%lu\n%s\n\n", d.info.create_process.process_id, d.info.create_process.name); } } } /* Set footer. */ - AppendReply(g_annex_buffer, ""); + AppendReplyFormat(dst_cur, dst_end, ""); g_annex_buffer_contents = AnnexBufferContents_Processes; } /* Copy out the process list. */ - GetAnnexBufferContents(m_reply_packet, offset, length); + GetAnnexBufferContents(m_reply_cur, offset, length); } else { AMS_DMNT2_GDB_LOG_DEBUG("Not Implemented qxfer:osdata:read: %s\n", m_receive_packet); - SetReplyError(m_reply_packet, "E01"); + AppendReplyError(m_reply_cur, m_reply_end, "E01"); } } @@ -2303,8 +2324,12 @@ namespace ams::dmnt { /* If doing a fresh read, generate the thread list. */ if (offset == 0 || g_annex_buffer_contents != AnnexBufferContents_Threads) { + /* Prepare to write to annex buffer. */ + char *dst_cur = g_annex_buffer; + char *dst_end = g_annex_buffer + sizeof(g_annex_buffer); + /* Set header. */ - SetReply(g_annex_buffer, ""); + AppendReplyFormat(dst_cur, dst_end, ""); /* Get the thread list. */ u64 thread_ids[DebugProcess::ThreadCountMax]; @@ -2329,17 +2354,17 @@ namespace ams::dmnt { name[sizeof(name) - 1] = '\x00'; /* Set the thread entry */ - AppendReply(g_annex_buffer, "", m_process_id.value, thread_ids[i], core, name); + AppendReplyFormat(dst_cur, dst_end, "", m_process_id.value, thread_ids[i], core, name); } } - AppendReply(g_annex_buffer, ""); + AppendReplyFormat(dst_cur, dst_end, ""); g_annex_buffer_contents = AnnexBufferContents_Threads; } /* Copy out the threads list. */ - GetAnnexBufferContents(m_reply_packet, offset, length); + GetAnnexBufferContents(m_reply_cur, offset, length); return true; } @@ -2350,7 +2375,7 @@ namespace ams::dmnt { /* Decode the type. */ if (!('0' <= m_receive_packet[0] && m_receive_packet[0] <= '4') || m_receive_packet[1] != ',') { - SetReplyError(m_reply_packet, "E01"); + AppendReplyError(m_reply_cur, m_reply_end, "E01"); return; } @@ -2360,7 +2385,7 @@ namespace ams::dmnt { /* Decode the address/length. */ const char *comma = std::strchr(m_receive_packet, ','); if (comma == nullptr) { - SetReplyError(m_reply_packet, "E01"); + AppendReplyError(m_reply_cur, m_reply_end, "E01"); return; } @@ -2372,18 +2397,18 @@ namespace ams::dmnt { case 0: /* SW */ { if (R_SUCCEEDED(m_debug_process.ClearBreakPoint(address, length))) { - SetReplyOk(m_reply_packet); + AppendReplyOk(m_reply_cur, m_reply_end); } else { - SetReplyError(m_reply_packet, "E01"); + AppendReplyError(m_reply_cur, m_reply_end, "E01"); } } break; case 1: /* HW */ { if (R_SUCCEEDED(m_debug_process.ClearHardwareBreakPoint(address, length))) { - SetReplyOk(m_reply_packet); + AppendReplyOk(m_reply_cur, m_reply_end); } else { - SetReplyError(m_reply_packet, "E01"); + AppendReplyError(m_reply_cur, m_reply_end, "E01"); } } break; @@ -2392,9 +2417,9 @@ namespace ams::dmnt { case 4: /* Watch-A */ { if (R_SUCCEEDED(m_debug_process.ClearWatchPoint(address, length))) { - SetReplyOk(m_reply_packet); + AppendReplyOk(m_reply_cur, m_reply_end); } else { - SetReplyError(m_reply_packet, "E01"); + AppendReplyError(m_reply_cur, m_reply_end, "E01"); } } break; @@ -2406,12 +2431,12 @@ namespace ams::dmnt { void GdbServerImpl::QuestionMark() { if (m_debug_process.IsValid()) { if (m_debug_process.GetLastThreadId() == 0) { - SetReply(m_reply_packet, "X01"); + AppendReplyFormat(m_reply_cur, m_reply_end, "X01"); } else { - this->SetStopReplyPacket(m_debug_process.GetLastSignal()); + this->AppendStopReplyPacket(m_debug_process.GetLastSignal()); } } else { - SetReply(m_reply_packet, "W00"); + AppendReplyFormat(m_reply_cur, m_reply_end, "W00"); } } diff --git a/stratosphere/dmnt.gen2/source/dmnt2_gdb_server_impl.hpp b/stratosphere/dmnt.gen2/source/dmnt2_gdb_server_impl.hpp index 66c8e74d0..5aca349e5 100644 --- a/stratosphere/dmnt.gen2/source/dmnt2_gdb_server_impl.hpp +++ b/stratosphere/dmnt.gen2/source/dmnt2_gdb_server_impl.hpp @@ -34,7 +34,8 @@ namespace ams::dmnt { TransportSession m_session; GdbPacketIo m_packet_io; char *m_receive_packet{nullptr}; - char *m_reply_packet{nullptr}; + char *m_reply_cur{nullptr}; + char *m_reply_end{nullptr}; char m_buffer[GdbPacketBufferSize / 2]; bool m_killed{false}; os::ThreadType m_events_thread; @@ -61,7 +62,7 @@ namespace ams::dmnt { static void DebugEventsThreadEntry(void *arg) { static_cast(arg)->DebugEventsThread(); } void DebugEventsThread(); void ProcessDebugEvents(); - void SetStopReplyPacket(GdbSignal signal); + void AppendStopReplyPacket(GdbSignal signal); private: void D();