mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 20:31:14 +00:00
thermosphere: rewrite gdb/mem in c++. Remove SearchMemory handler
This commit is contained in:
parent
697e61850f
commit
61a972abf3
6 changed files with 122 additions and 198 deletions
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
|
102
thermosphere/src/gdb/hvisor_gdb_mem.cpp
Normal file
102
thermosphere/src/gdb/hvisor_gdb_mem.cpp
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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<const char *>(src), len});
|
||||
}
|
||||
|
||||
size_t EscapeBinaryData(size_t *encodedCount, void *dst, const void *src, size_t len, size_t maxLen)
|
||||
{
|
||||
u8 *dst8 = reinterpret_cast<u8 *>(dst);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 <string.h>
|
||||
#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);
|
||||
}
|
|
@ -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);
|
Loading…
Reference in a new issue