mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 20:31:14 +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 "net.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 "../software_breakpoints.h"
|
|
@ -12,5 +12,3 @@
|
|||
bool GDB_FetchPackedHioRequest(GDBContext *ctx, u32 addr);
|
||||
bool GDB_IsHioInProgress(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
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
|
@ -24,9 +24,17 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "gdb_defines_internal.hpp"
|
||||
#include "../defines.hpp"
|
||||
#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 {
|
||||
|
||||
struct PackedGdbHioRequest {
|
||||
|
@ -47,14 +55,6 @@ namespace ams::hyp::gdb {
|
|||
bool ctrlC;
|
||||
};
|
||||
|
||||
typedef enum GDBState
|
||||
{
|
||||
STATE_DISCONNECTED,
|
||||
STATE_CONNECTED,
|
||||
STATE_ATTACHED,
|
||||
STATE_DETACHING,
|
||||
} GDBState;
|
||||
|
||||
struct DebugEventInfo;
|
||||
|
||||
class Context final {
|
||||
|
@ -106,7 +106,49 @@ namespace ams::hyp::gdb {
|
|||
private:
|
||||
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(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
|
||||
DECLARE_VERBOSE_HANDLER(Stopped);
|
||||
|
@ -117,6 +159,27 @@ namespace ams::hyp::gdb {
|
|||
DECLARE_VERBOSE_HANDLER(Continue);
|
||||
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:
|
||||
void Initialize(TransportInterfaceType ifaceType, u32 ifaceId, u32 ifaceFlags);
|
||||
void Attach();
|
||||
|
@ -125,9 +188,13 @@ namespace ams::hyp::gdb {
|
|||
void Acquire();
|
||||
void Release();
|
||||
|
||||
constexpr bool IsAttached() const
|
||||
{
|
||||
constexpr bool IsAttached() const {
|
||||
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
|
||||
|
||||
#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.
|
||||
// IDA seems to want additional bytes as well.
|
||||
|
@ -33,14 +33,12 @@
|
|||
#define GDB_BUF_LEN 0x800
|
||||
#define GDB_WORK_BUF_LEN 0x1000
|
||||
|
||||
#define HANDLER(name) Handle##name
|
||||
#define QUERY_HANDLER(name) HANDLER(Query##name)
|
||||
#define VERBOSE_HANDLER(name) HANDLER(Verbose##name)
|
||||
#define GDB_HANDLER(name) Handle##name
|
||||
#define GDB_QUERY_HANDLER(name) GDB_HANDLER(Query##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 DECLARE_QUERY_HANDLER(name) DECLARE_HANDLER(Query##name)
|
||||
#define DECLARE_VERBOSE_HANDLER(name) DECLARE_HANDLER(Verbose##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)
|
||||
#define GDB_DEFINE_HANDLER(name) int Context::HANDLER(name)()
|
||||
#define GDB_DEFINE_QUERY_HANDLER(name) DEFINE_HANDLER(Query##name)
|
||||
#define GDB_DECLARE_VERBOSE_HANDLER(name) DEFINE_HANDLER(Verbose##name)
|
||||
#define GDB_DECLARE_Xfer_HANDLER(name) DEFINE_HANDLER(Xfer##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
|
||||
|
||||
#include "context.h"
|
||||
#define _REENT_ONLY
|
||||
#include <errno.h>
|
||||
|
||||
u8 GDB_ComputeChecksum(const char *packetData, size_t len);
|
||||
size_t GDB_EncodeHex(char *dst, const void *src, size_t len);
|
||||
|
|
|
@ -9,9 +9,4 @@
|
|||
|
||||
#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"
|
||||
|
||||
#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