This commit is contained in:
TuxSH 2020-02-05 02:51:10 +00:00
parent b65f11d205
commit b445fe1bf4
9 changed files with 300 additions and 49 deletions

View file

@ -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"

View file

@ -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);

View file

@ -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

View file

@ -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)

View 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);
}
}

View 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);
}

View file

@ -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);

View file

@ -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);

View file

@ -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);