diff --git a/thermosphere/src/gdb/hvisor_gdb_context.hpp b/thermosphere/src/gdb/hvisor_gdb_context.hpp index 6cdab8d9c..9e4647c44 100644 --- a/thermosphere/src/gdb/hvisor_gdb_context.hpp +++ b/thermosphere/src/gdb/hvisor_gdb_context.hpp @@ -119,9 +119,20 @@ namespace ams::hvisor::gdb { int ReplyEmpty(); int ReplyErrno(int no); - char *GetInPlaceOutputBuffer() const { + // Memory + int SendMemory(uintptr_t addr, size_t len, std::string_view prefix = {}); + int WriteMemoryImpl(size_t (*decoder)(void *, const void *, size_t)); + + // Helpers + char *GetInPlaceOutputBuffer() const + { return m_buffer + 1; } + + char *GetWorkBuffer() const + { + return m_workBuffer; + } private: // Meta DECLARE_HANDLER(Unsupported); @@ -190,7 +201,8 @@ namespace ams::hvisor::gdb { void Acquire(); void Release(); - constexpr bool IsAttached() const { + constexpr bool IsAttached() const + { return m_state == State::Attached; } }; diff --git a/thermosphere/src/gdb/hvisor_gdb_mem.cpp b/thermosphere/src/gdb/hvisor_gdb_mem.cpp new file mode 100644 index 000000000..43e4aca37 --- /dev/null +++ b/thermosphere/src/gdb/hvisor_gdb_mem.cpp @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2019-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* +* This file is part of Luma3DS. +* Copyright (C) 2016-2019 Aurora Wright, TuxSH +* +* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later) +*/ + +#include "hvisor_gdb_defines_internal.hpp" +#include "hvisor_gdb_packet_data.hpp" + +#include "../core_ctx.h" +#include "../guest_memory.h" + +namespace ams::hvisor::gdb { + + int Context::SendMemory(uintptr_t addr, size_t len, std::string_view prefix) + { + char *buf = GetInPlaceOutputBuffer(); + char *membuf = GetWorkBuffer(); + + size_t prefixLen = prefix.size(); + + if(prefixLen + 2 * len > GDB_BUF_LEN) { + // gdb shouldn't send requests which responses don't fit in a packet + return prefixLen == 0 ? ReplyErrno(ENOMEM) : -1; + } + + size_t total = guestReadMemory(addr, len, membuf); + + if (total == 0) { + return prefixLen == 0 ? ReplyErrno(EFAULT) : -EFAULT; + } else { + std::copy(prefix.begin(), prefix.end(), buf); + EncodeHex(buf + prefixLen, membuf, total); + return SendPacket(std::string_view{buf, prefixLen + 2 * total}); + } + } + + int Context::WriteMemoryImpl(size_t (*decoder)(void *, const void *, size_t)) + { + char *workbuf = GetWorkBuffer(); + + auto [nread, addr, len] = ParseHexIntegerList<2>(m_commandData, ':'); + if (nread == 0) { + return ReplyErrno(EILSEQ); + } + + m_commandData.remove_prefix(nread); + if (len > m_commandData.length() / 2) { + // Data len field doesn't match what we got... + return ReplyErrno(ENOMEM); + } + + size_t n = decoder(workbuf, m_commandData.data(), m_commandData.size()); + + if(n != len) { + // Decoding error... + return ReplyErrno(EILSEQ); + } + + size_t total = guestWriteMemory(addr, len, workbuf); + return total == len ? ReplyOk() : ReplyErrno(EFAULT); + } + + + GDB_DEFINE_HANDLER(ReadMemory) + { + auto [nparsed, addr, len] = ParseHexIntegerList<2>(m_commandData); + if (nparsed == 0) { + return ReplyErrno(EILSEQ); + } + + return SendMemory(addr, len); + } + + GDB_DEFINE_HANDLER(WriteMemory) + { + return WriteMemoryImpl(DecodeHex); + } + + GDB_DEFINE_HANDLER(WriteMemoryRaw) + { + return WriteMemoryImpl(UnescapeBinaryData); + } + +} diff --git a/thermosphere/src/gdb/hvisor_gdb_packet_data.cpp b/thermosphere/src/gdb/hvisor_gdb_packet_data.cpp index 68f1e33a0..115bc62b0 100644 --- a/thermosphere/src/gdb/hvisor_gdb_packet_data.cpp +++ b/thermosphere/src/gdb/hvisor_gdb_packet_data.cpp @@ -55,6 +55,11 @@ namespace ams::hvisor::gdb { return i; } + size_t DecodeHex(void *dst, const void *src, size_t len) + { + return DecodeHex(dst, std::string_view{reinterpret_cast(src), len}); + } + size_t EscapeBinaryData(size_t *encodedCount, void *dst, const void *src, size_t len, size_t maxLen) { u8 *dst8 = reinterpret_cast(dst); diff --git a/thermosphere/src/gdb/hvisor_gdb_packet_data.hpp b/thermosphere/src/gdb/hvisor_gdb_packet_data.hpp index 2988659b5..838b37bbf 100644 --- a/thermosphere/src/gdb/hvisor_gdb_packet_data.hpp +++ b/thermosphere/src/gdb/hvisor_gdb_packet_data.hpp @@ -169,6 +169,7 @@ namespace ams::hvisor::gdb { u8 ComputeChecksum(std::string_view packetData); size_t EncodeHex(char *dst, const void *src, size_t len); size_t DecodeHex(void *dst, std::string_view data); + size_t DecodeHex(void *dst, const void *src, size_t len); size_t EscapeBinaryData(size_t *encodedCount, void *dst, const void *src, size_t len, size_t maxLen); size_t UnescapeBinaryData(void *dst, const void *src, size_t len); diff --git a/thermosphere/src/gdb/mem.c b/thermosphere/src/gdb/mem.c deleted file mode 100644 index 2ee5ab1f0..000000000 --- a/thermosphere/src/gdb/mem.c +++ /dev/null @@ -1,182 +0,0 @@ -/* -* This file is part of Luma3DS. -* Copyright (C) 2016-2019 Aurora Wright, TuxSH -* -* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later) -*/ - -#include -#include "mem.h" -#include "net.h" -#include "../guest_memory.h" -#include "../pattern_utils.h" - -int GDB_SendMemory(GDBContext *ctx, const char *prefix, size_t prefixLen, size_t addr, size_t len) -{ - char *buf = ctx->buffer + 1; - char *membuf = ctx->workBuffer; - - if(prefix != NULL) { - memmove(buf, prefix, prefixLen); - } - else { - prefixLen = 0; - } - - if(prefixLen + 2 * len > GDB_BUF_LEN) { - // gdb shouldn't send requests which responses don't fit in a packet - return prefix == NULL ? GDB_ReplyErrno(ctx, ENOMEM) : -1; - } - - size_t total = guestReadMemory(addr, len, membuf); - - if (total == 0) { - return prefix == NULL ? GDB_ReplyErrno(ctx, EFAULT) : -EFAULT; - } else { - GDB_EncodeHex(buf + prefixLen, membuf, total); - return GDB_SendPacket(ctx, buf, prefixLen + 2 * total); - } -} - -int GDB_WriteMemory(GDBContext *ctx, const void *buf, uintptr_t addr, size_t len) -{ - size_t total = guestWriteMemory(addr, len, buf); - return total == len ? GDB_ReplyOk(ctx) : GDB_ReplyErrno(ctx, EFAULT); -} - -u32 GDB_SearchMemory(bool *found, GDBContext *ctx, uintptr_t addr, size_t len, const void *pattern, size_t patternLen) -{ - // Note: need to ensure GDB_WORK_BUF_LEN is at least 0x1000 bytes in size - - u8 *buf = (u8 *)ctx->workBuffer; - size_t maxNbPages = GDB_WORK_BUF_LEN / 0x1000; - uintptr_t curAddr = addr; - - while (curAddr < addr + len) { - size_t nbPages; - uintptr_t addrBase = curAddr & ~0xFFF; - size_t addrDispl = curAddr & 0xFFF; - - for (nbPages = 0; nbPages < maxNbPages; nbPages++) { - if (guestReadMemory(addrBase + nbPages * 0x1000, 0x1000, buf + nbPages * 0x1000) != 0x1000) { - break; - } - } - - u8 *pos = NULL; - if(addrDispl + patternLen <= 0x1000 * nbPages) { - pos = memsearch(buf + addrDispl, pattern, 0x1000 * nbPages - addrDispl, patternLen); - } - - if(pos != NULL) { - *found = true; - return addrBase + (pos - buf); - } - - curAddr = addrBase + 0x1000; - } - - *found = false; - return 0; -} - -GDB_DECLARE_HANDLER(ReadMemory) -{ - unsigned long lst[2]; - if (GDB_ParseHexIntegerList(lst, ctx->commandData, 2, 0) == NULL) { - return GDB_ReplyErrno(ctx, EILSEQ); - } - - uintptr_t addr = lst[0]; - size_t len = lst[1]; - - return GDB_SendMemory(ctx, NULL, 0, addr, len); -} - -GDB_DECLARE_HANDLER(WriteMemory) -{ - unsigned long lst[2]; - const char *dataStart = GDB_ParseHexIntegerList(lst, ctx->commandData, 2, ':'); - if (dataStart == NULL || *dataStart != ':') { - return GDB_ReplyErrno(ctx, EILSEQ); - } - - dataStart++; - uintptr_t addr = lst[0]; - size_t len = lst[1]; - - if(dataStart + 2 * len >= ctx->buffer + 4 + GDB_BUF_LEN) { - // Data len field doesn't match what we got... - return GDB_ReplyErrno(ctx, ENOMEM); - } - - size_t n = GDB_DecodeHex(ctx->workBuffer, dataStart, len); - - if(n != len) { - // Decoding error... - return GDB_ReplyErrno(ctx, EILSEQ); - } - - return GDB_WriteMemory(ctx, ctx->workBuffer, addr, len); -} - -GDB_DECLARE_HANDLER(WriteMemoryRaw) -{ - unsigned long lst[2]; - const char *dataStart = GDB_ParseHexIntegerList(lst, ctx->commandData, 2, ':'); - if (dataStart == NULL || *dataStart != ':') { - return GDB_ReplyErrno(ctx, EILSEQ); - } - - dataStart++; - uintptr_t addr = lst[0]; - size_t len = lst[1]; - - if(dataStart + 2 * len >= ctx->buffer + 4 + GDB_BUF_LEN) { - // Data len field doesn't match what we got... - return GDB_ReplyErrno(ctx, ENOMEM); - } - - // Note: could be done in place in ctx->buffer... - size_t n = GDB_UnescapeBinaryData(ctx->workBuffer, dataStart, len); - - if(n != len) { - // Decoding error... - return GDB_ReplyErrno(ctx, n); - } - - return GDB_WriteMemory(ctx, ctx->workBuffer, addr, len); -} - -GDB_DECLARE_QUERY_HANDLER(SearchMemory) -{ - unsigned long lst[2]; - const char *patternStart; - size_t patternLen; - bool found; - u32 foundAddr; - - if (strncmp(ctx->commandData, "memory:", 7) != 0) { - return GDB_ReplyErrno(ctx, EILSEQ); - } - - ctx->commandData += 7; - patternStart = GDB_ParseIntegerList(lst, ctx->commandData, 2, ';', ';', 16, false); - if (patternStart == NULL || *patternStart != ';') { - return GDB_ReplyErrno(ctx, EILSEQ); - } - - uintptr_t addr = lst[0]; - size_t len = lst[1]; - - patternStart++; - patternLen = ctx->commandEnd - patternStart; - - // Unescape pattern in place - char *pattern = (char *)patternStart; - patternLen = GDB_UnescapeBinaryData(pattern, patternStart, patternLen); - - foundAddr = GDB_SearchMemory(&found, ctx, addr, len, patternStart, patternLen); - - return found ? GDB_SendFormattedPacket(ctx, "1,%x", foundAddr) : GDB_SendPacket(ctx, "0", 1); -} diff --git a/thermosphere/src/gdb/mem.h b/thermosphere/src/gdb/mem.h deleted file mode 100644 index 264f73f5f..000000000 --- a/thermosphere/src/gdb/mem.h +++ /dev/null @@ -1,14 +0,0 @@ -/* -* This file is part of Luma3DS. -* Copyright (C) 2016-2019 Aurora Wright, TuxSH -* -* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later) -*/ - -#pragma once - -#include "context.h" - -int GDB_SendMemory(GDBContext *ctx, const char *prefix, size_t prefixLen, uintptr_t addr, size_t len); -int GDB_WriteMemory(GDBContext *ctx, const void *buf, uintptr_t addr, size_t len); -u32 GDB_SearchMemory(bool *found, GDBContext *ctx, size_t addr, size_t len, const void *pattern, size_t patternLen);