mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-12-18 16:32:05 +00:00
wip
This commit is contained in:
parent
b65f11d205
commit
b445fe1bf4
9 changed files with 300 additions and 49 deletions
|
@ -27,16 +27,7 @@
|
||||||
//#include "context.h"
|
//#include "context.h"
|
||||||
|
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
|
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "query.h"
|
|
||||||
#include "verbose.h"
|
|
||||||
#include "thread.h"
|
|
||||||
#include "debug.h"
|
|
||||||
#include "regs.h"
|
|
||||||
#include "mem.h"
|
|
||||||
#include "hio.h"
|
|
||||||
#include "stop_points.h"
|
|
||||||
|
|
||||||
#include "../breakpoints.h"
|
#include "../breakpoints.h"
|
||||||
#include "../software_breakpoints.h"
|
#include "../software_breakpoints.h"
|
|
@ -12,5 +12,3 @@
|
||||||
bool GDB_FetchPackedHioRequest(GDBContext *ctx, u32 addr);
|
bool GDB_FetchPackedHioRequest(GDBContext *ctx, u32 addr);
|
||||||
bool GDB_IsHioInProgress(GDBContext *ctx);
|
bool GDB_IsHioInProgress(GDBContext *ctx);
|
||||||
int GDB_SendCurrentHioRequest(GDBContext *ctx);
|
int GDB_SendCurrentHioRequest(GDBContext *ctx);
|
||||||
|
|
||||||
GDB_DECLARE_HANDLER(HioReply);
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019 Atmosphère-NX
|
* Copyright (c) 2019-2020 Atmosphère-NX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
@ -24,9 +24,17 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "gdb_defines_internal.hpp"
|
#include "../defines.hpp"
|
||||||
#include "../transport_interface.h"
|
#include "../transport_interface.h"
|
||||||
|
|
||||||
|
#define _REENT_ONLY
|
||||||
|
#include <cerrno>
|
||||||
|
|
||||||
|
#define DECLARE_HANDLER(name) int Handle##name()
|
||||||
|
#define DECLARE_QUERY_HANDLER(name) DECLARE_HANDLER(Query##name)
|
||||||
|
#define DECLARE_VERBOSE_HANDLER(name) DECLARE_HANDLER(Verbose##name)
|
||||||
|
#define DECLARE_XFER_HANDLER(name) DECLARE_HANDLER(Xfer##name)
|
||||||
|
|
||||||
namespace ams::hyp::gdb {
|
namespace ams::hyp::gdb {
|
||||||
|
|
||||||
struct PackedGdbHioRequest {
|
struct PackedGdbHioRequest {
|
||||||
|
@ -47,14 +55,6 @@ namespace ams::hyp::gdb {
|
||||||
bool ctrlC;
|
bool ctrlC;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum GDBState
|
|
||||||
{
|
|
||||||
STATE_DISCONNECTED,
|
|
||||||
STATE_CONNECTED,
|
|
||||||
STATE_ATTACHED,
|
|
||||||
STATE_DETACHING,
|
|
||||||
} GDBState;
|
|
||||||
|
|
||||||
struct DebugEventInfo;
|
struct DebugEventInfo;
|
||||||
|
|
||||||
class Context final {
|
class Context final {
|
||||||
|
@ -106,7 +106,49 @@ namespace ams::hyp::gdb {
|
||||||
private:
|
private:
|
||||||
void MigrateRxIrq(u32 coreId) const;
|
void MigrateRxIrq(u32 coreId) const;
|
||||||
|
|
||||||
|
// Comms
|
||||||
|
int ReceivePacket();
|
||||||
|
int DoSendPacket();
|
||||||
|
int SendPacket(const char *packetData, size_t len);
|
||||||
|
int SendFormattedPacket(const char *packetDataFmt, ...);
|
||||||
|
int SendHexPacket(const void *packetData, size_t len);
|
||||||
|
int SendNotificationPacket(const char *packetData, size_t len);
|
||||||
|
int SendStreamData(const char *streamData, size_t offset, size_t length, size_t totalSize, bool forceEmptyLast);
|
||||||
|
int ReplyEmpty();
|
||||||
|
int ReplyErrno(int no);
|
||||||
|
|
||||||
|
char *GetInPlaceOutputBuffer() const {
|
||||||
|
return m_buffer + 1;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
// Meta
|
||||||
DECLARE_HANDLER(Unsupported);
|
DECLARE_HANDLER(Unsupported);
|
||||||
|
DECLARE_HANDLER(ReadQuery);
|
||||||
|
DECLARE_HANDLER(WriteQuery);
|
||||||
|
DECLARE_QUERY_HANDLER(Xfer);
|
||||||
|
DECLARE_HANDLER(VerboseCommand);
|
||||||
|
|
||||||
|
// General queries
|
||||||
|
DECLARE_QUERY_HANDLER(Supported);
|
||||||
|
DECLARE_QUERY_HANDLER(StartNoAckMode);
|
||||||
|
DECLARE_QUERY_HANDLER(Attached);
|
||||||
|
|
||||||
|
// XML Transfer
|
||||||
|
DECLARE_XFER_HANDLER(Features);
|
||||||
|
|
||||||
|
// Resuming features enumeration
|
||||||
|
DECLARE_VERBOSE_HANDLER(ContinueSupported);
|
||||||
|
|
||||||
|
// "Threads"
|
||||||
|
// Capitalization in "GetTLSAddr" is intended.
|
||||||
|
DECLARE_HANDLER(SetThreadId);
|
||||||
|
DECLARE_HANDLER(IsThreadAlive);
|
||||||
|
DECLARE_QUERY_HANDLER(CurrentThreadId);
|
||||||
|
DECLARE_QUERY_HANDLER(fThreadInfo);
|
||||||
|
DECLARE_QUERY_HANDLER(sThreadInfo);
|
||||||
|
DECLARE_QUERY_HANDLER(ThreadEvents);
|
||||||
|
DECLARE_QUERY_HANDLER(ThreadExtraInfo);
|
||||||
|
DECLARE_QUERY_HANDLER(GetTLSAddr);
|
||||||
|
|
||||||
// Debug
|
// Debug
|
||||||
DECLARE_VERBOSE_HANDLER(Stopped);
|
DECLARE_VERBOSE_HANDLER(Stopped);
|
||||||
|
@ -117,6 +159,27 @@ namespace ams::hyp::gdb {
|
||||||
DECLARE_VERBOSE_HANDLER(Continue);
|
DECLARE_VERBOSE_HANDLER(Continue);
|
||||||
DECLARE_HANDLER(GetStopReason);
|
DECLARE_HANDLER(GetStopReason);
|
||||||
|
|
||||||
|
// Stop points
|
||||||
|
DECLARE_HANDLER(ToggleStopPoint);
|
||||||
|
|
||||||
|
// Memory
|
||||||
|
DECLARE_HANDLER(ReadMemory);
|
||||||
|
DECLARE_HANDLER(WriteMemory);
|
||||||
|
DECLARE_HANDLER(WriteMemoryRaw);
|
||||||
|
DECLARE_QUERY_HANDLER(SearchMemory);
|
||||||
|
|
||||||
|
// Registers
|
||||||
|
DECLARE_HANDLER(ReadRegisters);
|
||||||
|
DECLARE_HANDLER(WriteRegisters);
|
||||||
|
DECLARE_HANDLER(ReadRegister);
|
||||||
|
DECLARE_HANDLER(WriteRegister);
|
||||||
|
|
||||||
|
// Hio
|
||||||
|
DECLARE_HANDLER(HioReply);
|
||||||
|
|
||||||
|
// Custom commands
|
||||||
|
DECLARE_QUERY_HANDLER(Rcmd);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void Initialize(TransportInterfaceType ifaceType, u32 ifaceId, u32 ifaceFlags);
|
void Initialize(TransportInterfaceType ifaceType, u32 ifaceId, u32 ifaceFlags);
|
||||||
void Attach();
|
void Attach();
|
||||||
|
@ -125,9 +188,13 @@ namespace ams::hyp::gdb {
|
||||||
void Acquire();
|
void Acquire();
|
||||||
void Release();
|
void Release();
|
||||||
|
|
||||||
constexpr bool IsAttached() const
|
constexpr bool IsAttached() const {
|
||||||
{
|
|
||||||
return m_state == State::Attached;
|
return m_state == State::Attached;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
#undef DECLARE_HANDLER
|
||||||
|
#undef DECLARE_QUERY_HANDLER
|
||||||
|
#undef DECLARE_VERBOSE_HANDLER
|
||||||
|
#undef DECLARE_XFER_HANDLER
|
|
@ -24,7 +24,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../defines.hpp"
|
#include "hyp_gdb_context.hpp"
|
||||||
|
|
||||||
// 512+24 is the ideal size as IDA will try to read exactly 0x100 bytes at a time.
|
// 512+24 is the ideal size as IDA will try to read exactly 0x100 bytes at a time.
|
||||||
// IDA seems to want additional bytes as well.
|
// IDA seems to want additional bytes as well.
|
||||||
|
@ -33,14 +33,12 @@
|
||||||
#define GDB_BUF_LEN 0x800
|
#define GDB_BUF_LEN 0x800
|
||||||
#define GDB_WORK_BUF_LEN 0x1000
|
#define GDB_WORK_BUF_LEN 0x1000
|
||||||
|
|
||||||
#define HANDLER(name) Handle##name
|
#define GDB_HANDLER(name) Handle##name
|
||||||
#define QUERY_HANDLER(name) HANDLER(Query##name)
|
#define GDB_QUERY_HANDLER(name) GDB_HANDLER(Query##name)
|
||||||
#define VERBOSE_HANDLER(name) HANDLER(Verbose##name)
|
#define GDB_VERBOSE_HANDLER(name) GDB_HANDLER(Verbose##name)
|
||||||
|
#define GDB_XFER_HANDLER(name) GDB_HANDLER(Xfer##name)
|
||||||
|
|
||||||
#define DECLARE_HANDLER(name) int HANDLER(name)()
|
#define GDB_DEFINE_HANDLER(name) int Context::HANDLER(name)()
|
||||||
#define DECLARE_QUERY_HANDLER(name) DECLARE_HANDLER(Query##name)
|
#define GDB_DEFINE_QUERY_HANDLER(name) DEFINE_HANDLER(Query##name)
|
||||||
#define DECLARE_VERBOSE_HANDLER(name) DECLARE_HANDLER(Verbose##name)
|
#define GDB_DECLARE_VERBOSE_HANDLER(name) DEFINE_HANDLER(Verbose##name)
|
||||||
|
#define GDB_DECLARE_Xfer_HANDLER(name) DEFINE_HANDLER(Xfer##name)
|
||||||
#define DEFINE_HANDLER(name) int Context::HANDLER(name)()
|
|
||||||
#define DEFINE_QUERY_HANDLER(name) DEFINE_HANDLER(Query##name)
|
|
||||||
#define DECLARE_VERBOSE_HANDLER(name) DEFINE_HANDLER(Verbose##name)
|
|
101
thermosphere/src/gdb/hyp_gdb_packet_data.cpp
Normal file
101
thermosphere/src/gdb/hyp_gdb_packet_data.cpp
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "hyp_gdb_packet_data.hpp"
|
||||||
|
#include <cctype>
|
||||||
|
|
||||||
|
namespace ams::hyp::gdb {
|
||||||
|
u8 ComputeChecksum(std::string_view packetData)
|
||||||
|
{
|
||||||
|
return std::accumulate(packetData.cbegin(), packetData.cend(), u8{0u});
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t EncodeHex(char *dst, const void *src, size_t len)
|
||||||
|
{
|
||||||
|
static const char *alphabet = "0123456789abcdef";
|
||||||
|
const u8 *src8 = reinterpret_cast<const u8 *>(src);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < len; i++) {
|
||||||
|
dst[2 * i] = alphabet[(src8[i] & 0xF0) >> 4];
|
||||||
|
dst[2 * i + 1] = alphabet[src8[i] & 0x0F];
|
||||||
|
}
|
||||||
|
|
||||||
|
return 2 * len;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t DecodeHex(void *dst, std::string_view data)
|
||||||
|
{
|
||||||
|
size_t i = 0;
|
||||||
|
u8 *dst8 = reinterpret_cast<u8 *>(dst);
|
||||||
|
for (i = 0; i < data.size() / 2; i++) {
|
||||||
|
auto v1 = DecodeHexDigit(data[2 * i]);
|
||||||
|
auto v2 = DecodeHexDigit(data[2 * i + 1]);
|
||||||
|
|
||||||
|
if (v1 >= 16 || v2 >= 16) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
dst8[i] = (v1 << 4) | v2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t EscapeBinaryData(size_t *encodedCount, void *dst, const void *src, size_t len, size_t maxLen)
|
||||||
|
{
|
||||||
|
u8 *dst8 = reinterpret_cast<u8 *>(dst);
|
||||||
|
const u8 *src8 = reinterpret_cast<const u8 *>(src);
|
||||||
|
len = std::min(len, maxLen);
|
||||||
|
|
||||||
|
u8 *dstMax = dst8 + len;
|
||||||
|
|
||||||
|
while (dst8 < dstMax) {
|
||||||
|
if (*src8 == '$' || *src8 == '#' || *src8 == '}' || *src8 == '*') {
|
||||||
|
if (dst8 + 1 >= dstMax) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*dst8++ = '}';
|
||||||
|
*dst8++ = *src8++ ^ 0x20;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*dst8++ = *src8++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*encodedCount = dst8 - reinterpret_cast<u8 *>(dst);
|
||||||
|
return src8 - reinterpret_cast<const u8 *>(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t UnescapeBinaryData(void *dst, const void *src, size_t len)
|
||||||
|
{
|
||||||
|
u8 *dst8 = reinterpret_cast<u8 *>(dst);
|
||||||
|
const u8 *src8 = reinterpret_cast<const u8 *>(src);
|
||||||
|
const u8 *srcEnd = src8 + len;
|
||||||
|
|
||||||
|
while (src8 < srcEnd) {
|
||||||
|
if (*src8 == '}') {
|
||||||
|
src8++;
|
||||||
|
*dst8++ = *src8++ ^ 0x20;
|
||||||
|
} else {
|
||||||
|
*dst8++ = *src8++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dst8 - reinterpret_cast<u8 *>(dst);
|
||||||
|
}
|
||||||
|
}
|
109
thermosphere/src/gdb/hyp_gdb_packet_data.hpp
Normal file
109
thermosphere/src/gdb/hyp_gdb_packet_data.hpp
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../defines.hpp"
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
namespace ams::hyp::gdb {
|
||||||
|
|
||||||
|
constexpr unsigned long DecodeHexDigit(char src)
|
||||||
|
{
|
||||||
|
switch (src) {
|
||||||
|
case '0' ... '9': return 0 + (src - '0');
|
||||||
|
case 'a' ... 'f': return 10 + (src - 'a');
|
||||||
|
case 'A' ... 'F': return 10 + (src - 'A');
|
||||||
|
default:
|
||||||
|
return 16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr auto ParseInteger(std::string_view str, u32 base = 0, bool allowPrefix = true)
|
||||||
|
{
|
||||||
|
unsigned long res = 0;
|
||||||
|
long mult = 1;
|
||||||
|
auto errval = std::tuple{false, 0ul, str.end()};
|
||||||
|
|
||||||
|
if ((base == 0 && !allowPrefix) || base > 16 || str.empty()) {
|
||||||
|
return errval;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for +, -
|
||||||
|
if (str[0] == '+') {
|
||||||
|
if (!allowPrefix) {
|
||||||
|
return errval;
|
||||||
|
}
|
||||||
|
str.remove_prefix(1);
|
||||||
|
} else if (str[0] == '-') {
|
||||||
|
if (!allowPrefix) {
|
||||||
|
return errval;
|
||||||
|
}
|
||||||
|
str.remove_prefix(1);
|
||||||
|
mult = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str.empty()) {
|
||||||
|
// Oops
|
||||||
|
return errval;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now, check for 0x or leading 0
|
||||||
|
if (str.size() >= 2 && str[0] == '0' && str[1] == 'x') {
|
||||||
|
if (!allowPrefix || (base != 16 && base != 0)) {
|
||||||
|
return errval;
|
||||||
|
} else {
|
||||||
|
str.remove_prefix(2);
|
||||||
|
base = 16;
|
||||||
|
}
|
||||||
|
} else if (base == 0 || str[0] == '0') {
|
||||||
|
if (!allowPrefix) {
|
||||||
|
return errval;
|
||||||
|
}
|
||||||
|
base = 8;
|
||||||
|
} else if (base == 0) {
|
||||||
|
base = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str.empty()) {
|
||||||
|
// Oops
|
||||||
|
return errval;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto it = str.begin();
|
||||||
|
for (; it != str.end(); ++it) {
|
||||||
|
unsigned long v = DecodeHexDigit(*it);
|
||||||
|
if (v >= base) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
res *= base;
|
||||||
|
res += v;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::tuple{true, res * mult, it};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string_view::iterator ParseIntegerList(unsigned long *dst, std::string_view str, size_t nb, char sep, char lastSep, u32 base, bool allowPrefix);
|
||||||
|
std::string_view::iterator ParseHexIntegerList(unsigned long *dst, std::string_view str, size_t nb, char lastSep);
|
||||||
|
|
||||||
|
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 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);
|
||||||
|
|
||||||
|
}
|
|
@ -8,8 +8,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "context.h"
|
#include "context.h"
|
||||||
#define _REENT_ONLY
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
u8 GDB_ComputeChecksum(const char *packetData, size_t len);
|
u8 GDB_ComputeChecksum(const char *packetData, size_t len);
|
||||||
size_t GDB_EncodeHex(char *dst, const void *src, size_t len);
|
size_t GDB_EncodeHex(char *dst, const void *src, size_t len);
|
||||||
|
|
|
@ -9,9 +9,4 @@
|
||||||
|
|
||||||
#include "context.h"
|
#include "context.h"
|
||||||
|
|
||||||
int GDB_HandleReadQuery(GDBContext *ctx);
|
|
||||||
int GDB_HandleWriteQuery(GDBContext *ctx);
|
|
||||||
|
|
||||||
GDB_DECLARE_QUERY_HANDLER(Supported);
|
|
||||||
GDB_DECLARE_QUERY_HANDLER(StartNoAckMode);
|
|
||||||
GDB_DECLARE_QUERY_HANDLER(Attached);
|
|
||||||
|
|
|
@ -9,9 +9,3 @@
|
||||||
|
|
||||||
#include "context.h"
|
#include "context.h"
|
||||||
|
|
||||||
#define GDB_XFER_HANDLER(name) GDB_HANDLER(Xfer##name)
|
|
||||||
#define GDB_DECLARE_XFER_HANDLER(name) int GDB_XFER_HANDLER(name)(GDBContext *ctx, bool write, const char *annex, size_t offset, size_t length)
|
|
||||||
|
|
||||||
GDB_DECLARE_XFER_HANDLER(Features);
|
|
||||||
|
|
||||||
GDB_DECLARE_QUERY_HANDLER(Xfer);
|
|
||||||
|
|
Loading…
Reference in a new issue