gdb: hio support (untested yet)

This commit is contained in:
TuxSH 2019-04-14 21:48:15 +02:00
parent e11cc090b2
commit 4c9fe186d7
9 changed files with 292 additions and 53 deletions

View File

@ -58,6 +58,24 @@ typedef struct Breakpoint
bool persistent;
} Breakpoint;
typedef struct PackedGdbHioRequest
{
char magic[4]; // "GDB\x00"
u32 version;
// Request
char functionName[16+1];
char paramFormat[8+1];
u32 parameters[8];
u32 stringLengths[8];
// Return
int retval;
int gdbErrno;
bool ctrlC;
} PackedGdbHioRequest;
enum
{
GDB_FLAG_SELECTED = 1,
@ -128,6 +146,9 @@ typedef struct GDBContext
u32 nbWatchpoints;
u32 watchpoints[2];
u32 currentHioRequestTargetAddr;
PackedGdbHioRequest currentHioRequest;
bool enableExternalMemoryAccess;
char *commandData, *commandEnd;
int latestSentPacketSize;

View File

@ -38,6 +38,7 @@ GDB_DECLARE_HANDLER(Continue);
GDB_DECLARE_VERBOSE_HANDLER(Continue);
GDB_DECLARE_HANDLER(GetStopReason);
void GDB_ContinueExecution(GDBContext *ctx);
void GDB_PreprocessDebugEvent(GDBContext *ctx, DebugEventInfo *info);
int GDB_SendStopReply(GDBContext *ctx, const DebugEventInfo *info);
int GDB_HandleDebugEvents(GDBContext *ctx);

View File

@ -0,0 +1,35 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that 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/>.
*
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
* * Requiring preservation of specified reasonable legal notices or
* author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
* * Prohibiting misrepresentation of the origin of that material,
* or requiring that modified versions of such material be marked in
* reasonable ways as different from the original version.
*/
#pragma once
#include "gdb.h"
bool GDB_FetchPackedHioRequest(GDBContext *ctx, u32 addr);
bool GDB_IsHioInProgress(GDBContext *ctx);
int GDB_SendCurrentHioRequest(GDBContext *ctx);
GDB_DECLARE_HANDLER(HioReply);

View File

@ -28,8 +28,11 @@
#include "gdb.h"
Result GDB_ReadMemoryInPage(void *out, GDBContext *ctx, u32 addr, u32 len);
Result GDB_WriteMemoryInPage(GDBContext *ctx, const void *in, u32 addr, u32 len);
Result GDB_ReadTargetMemoryInPage(void *out, GDBContext *ctx, u32 addr, u32 len);
Result GDB_WriteTargetMemoryInPage(GDBContext *ctx, const void *in, u32 addr, u32 len);
u32 GDB_ReadTargetMemory(void *out, GDBContext *ctx, u32 addr, u32 len);
u32 GDB_WriteTargetMemory(GDBContext *ctx, const void *in, u32 addr, u32 len);
int GDB_SendMemory(GDBContext *ctx, const char *prefix, u32 prefixLen, u32 addr, u32 len);
int GDB_WriteMemory(GDBContext *ctx, const void *buf, u32 addr, u32 len);
u32 GDB_SearchMemory(bool *found, GDBContext *ctx, u32 addr, u32 len, const void *pattern, u32 patternLen);

View File

@ -180,6 +180,9 @@ void GDB_DetachFromProcess(GDBContext *ctx)
ctx->totalNbCreatedThreads = 0;
memset(ctx->threadInfos, 0, sizeof(ctx->threadInfos));
ctx->currentHioRequestTargetAddr = 0;
memset(&ctx->currentHioRequest, 0, sizeof(PackedGdbHioRequest));
ctx->state = GDB_STATE_CONNECTED;
}

View File

@ -31,6 +31,7 @@
#include "gdb/net.h"
#include "gdb/thread.h"
#include "gdb/mem.h"
#include "gdb/hio.h"
#include "gdb/watchpoints.h"
#include "fmt.h"
@ -190,7 +191,7 @@ GDB_DECLARE_HANDLER(Break)
}
}
static void GDB_ContinueExecution(GDBContext *ctx)
void GDB_ContinueExecution(GDBContext *ctx)
{
ctx->selectedThreadId = ctx->selectedThreadIdForContinuing = 0;
svcContinueDebugEvent(ctx->debug, ctx->continueFlags);
@ -376,6 +377,8 @@ void GDB_PreprocessDebugEvent(GDBContext *ctx, DebugEventInfo *info)
info->flags = 1;
info->syscall.syscall = sz;
}
else if (info->output_string.string_size == 0)
GDB_FetchPackedHioRequest(ctx, info->output_string.string_addr);
break;
}
@ -572,25 +575,34 @@ int GDB_SendStopReply(GDBContext *ctx, const DebugEventInfo *info)
case DBGEVENT_OUTPUT_STRING:
{
u32 addr = info->output_string.string_addr;
u32 remaining = info->output_string.string_size;
u32 sent = 0;
int total = 0;
while(remaining > 0)
// Regular "output string"
if (!GDB_IsHioInProgress(ctx))
{
u32 pending = (GDB_BUF_LEN - 1) / 2;
pending = pending < remaining ? pending : remaining;
u32 addr = info->output_string.string_addr;
u32 remaining = info->output_string.string_size;
u32 sent = 0;
int total = 0;
while(remaining > 0)
{
u32 pending = (GDB_BUF_LEN - 1) / 2;
pending = pending < remaining ? pending : remaining;
int res = GDB_SendMemory(ctx, "O", 1, addr + sent, pending);
if(res < 0 || (u32) res != 5 + 2 * pending)
break;
int res = GDB_SendMemory(ctx, "O", 1, addr + sent, pending);
if(res < 0 || (u32) res != 5 + 2 * pending)
break;
sent += pending;
remaining -= pending;
total += res;
sent += pending;
remaining -= pending;
total += res;
}
return total;
}
else // HIO
{
return GDB_SendCurrentHioRequest(ctx);
}
return total;
}
default:
break;
@ -617,7 +629,8 @@ int GDB_HandleDebugEvents(GDBContext *ctx)
GDB_PreprocessDebugEvent(ctx, &info);
int ret = 0;
bool continueAutomatically = info.type == DBGEVENT_OUTPUT_STRING || info.type == DBGEVENT_ATTACH_PROCESS ||
bool continueAutomatically = (info.type == DBGEVENT_OUTPUT_STRING && !GDB_IsHioInProgress(ctx)) ||
info.type == DBGEVENT_ATTACH_PROCESS ||
(info.type == DBGEVENT_ATTACH_THREAD && (info.attach_thread.creator_thread_id == 0 || !ctx->catchThreadEvents)) ||
(info.type == DBGEVENT_EXIT_THREAD && (info.exit_thread.reason >= EXITTHREAD_EVENT_EXIT_PROCESS || !ctx->catchThreadEvents)) ||
info.type == DBGEVENT_EXIT_PROCESS || !(info.flags & 1);

View File

@ -0,0 +1,148 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that 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/>.
*
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
* * Requiring preservation of specified reasonable legal notices or
* author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
* * Prohibiting misrepresentation of the origin of that material,
* or requiring that modified versions of such material be marked in
* reasonable ways as different from the original version.
*/
#include <string.h>
#include "gdb.h"
#include "gdb/hio.h"
#include "gdb/net.h"
#include "gdb/mem.h"
#include "gdb/debug.h"
#include "fmt.h"
bool GDB_FetchPackedHioRequest(GDBContext *ctx, u32 addr)
{
u32 total = GDB_ReadTargetMemory(&ctx->currentHioRequest, ctx, addr, sizeof(PackedGdbHioRequest));
if (total != sizeof(PackedGdbHioRequest) || memcmp(&ctx->currentHioRequest.magic, "GDB\x00", 4) != 0)
{
memset(&ctx->currentHioRequest, 0, sizeof(PackedGdbHioRequest));
ctx->currentHioRequestTargetAddr = 0;
return false;
}
else
{
ctx->currentHioRequestTargetAddr = addr;
return true;
}
}
bool GDB_IsHioInProgress(GDBContext *ctx)
{
return ctx->currentHioRequestTargetAddr != 0;
}
int GDB_SendCurrentHioRequest(GDBContext *ctx)
{
char buf[256+1];
char tmp[32+1];
u32 nStr = 0;
sprintf(buf, "F%s", ctx->currentHioRequest.functionName);
for (u32 i = 0; i < 8 && ctx->currentHioRequest.paramFormat[i] != 0; i++)
{
switch (ctx->currentHioRequest.paramFormat[i])
{
case 'i':
case 'I':
case 'p':
sprintf(tmp, ",%lx", ctx->currentHioRequest.parameters[i]);
break;
case 's':
sprintf(tmp, ",%lx/%lx", ctx->currentHioRequest.parameters[i], ctx->currentHioRequest.stringLengths[nStr++]);
break;
default:
tmp[0] = 0;
break;
}
strcat(buf, tmp);
}
return GDB_SendPacket(ctx, buf, strlen(buf));
}
GDB_DECLARE_HANDLER(HioReply)
{
if (!GDB_IsHioInProgress(ctx))
return GDB_ReplyErrno(ctx, EPERM);
// Reply in the form of Fretcode,errno,Ctrl-C flag;call-specific attachment
// "Call specific attachement" is always empty, though.
const char *pos = ctx->commandData;
u32 retval;
if (*pos == 0 || *pos == ',')
return GDB_ReplyErrno(ctx, EILSEQ);
else if (*pos == '-')
{
pos++;
ctx->currentHioRequest.retval = -1;
}
else if (*pos == '+')
{
pos++;
ctx->currentHioRequest.retval = 1;
}
else
ctx->currentHioRequest.retval = 1;
pos = GDB_ParseHexIntegerList(&retval, pos, 1, ',');
if (pos == NULL)
return GDB_ReplyErrno(ctx, EILSEQ);
ctx->currentHioRequest.retval *= retval;
ctx->currentHioRequest.gdbErrno = 0;
ctx->currentHioRequest.ctrlC = false;
if (*pos != 0)
{
u32 errno_;
pos = GDB_ParseHexIntegerList(&errno_, pos, 1, ',');
ctx->currentHioRequest.gdbErrno = (int)errno_;
if (pos == NULL)
return GDB_ReplyErrno(ctx, EILSEQ);
if (*pos != 0)
{
if (*pos == 'C')
return GDB_ReplyErrno(ctx, EILSEQ);
ctx->currentHioRequest.ctrlC = true;
}
}
memset(ctx->currentHioRequest.paramFormat, 0, sizeof(ctx->currentHioRequest.paramFormat));
u32 total = GDB_WriteTargetMemory(ctx, &ctx->currentHioRequest, ctx->currentHioRequestTargetAddr, sizeof(PackedGdbHioRequest));
memset(&ctx->currentHioRequest, 0, sizeof(PackedGdbHioRequest));
ctx->currentHioRequestTargetAddr = 0;
GDB_ContinueExecution(ctx);
return total == sizeof(PackedGdbHioRequest) ? 0 : GDB_ReplyErrno(ctx, EFAULT);
}

View File

@ -34,7 +34,7 @@ static void *k_memcpy_no_interrupt(void *dst, const void *src, u32 len)
return memcpy(dst, src, len);
}
Result GDB_ReadMemoryInPage(void *out, GDBContext *ctx, u32 addr, u32 len)
Result GDB_ReadTargetMemoryInPage(void *out, GDBContext *ctx, u32 addr, u32 len)
{
s64 TTBCR;
svcGetSystemInfo(&TTBCR, 0x10002, 0);
@ -83,7 +83,7 @@ Result GDB_ReadMemoryInPage(void *out, GDBContext *ctx, u32 addr, u32 len)
}
}
Result GDB_WriteMemoryInPage(GDBContext *ctx, const void *in, u32 addr, u32 len)
Result GDB_WriteTargetMemoryInPage(GDBContext *ctx, const void *in, u32 addr, u32 len)
{
s64 TTBCR;
svcGetSystemInfo(&TTBCR, 0x10002, 0);
@ -133,7 +133,7 @@ Result GDB_WriteMemoryInPage(GDBContext *ctx, const void *in, u32 addr, u32 len)
svcFlushEntireDataCache();
svcInvalidateEntireInstructionCache();
Result ret = GDB_WriteMemoryInPage(ctx, PA_FROM_VA_PTR(in), addr, len);
Result ret = GDB_WriteTargetMemoryInPage(ctx, PA_FROM_VA_PTR(in), addr, len);
svcFlushEntireDataCache();
svcInvalidateEntireInstructionCache();
return ret;
@ -141,6 +141,47 @@ Result GDB_WriteMemoryInPage(GDBContext *ctx, const void *in, u32 addr, u32 len)
}
}
u32 GDB_ReadTargetMemory(void *out, GDBContext *ctx, u32 addr, u32 len)
{
Result r = 0;
u32 remaining = len, total = 0;
u8 *out8 = (u8 *)out;
do
{
u32 nb = (remaining > 0x1000 - (addr & 0xFFF)) ? 0x1000 - (addr & 0xFFF) : remaining;
r = GDB_ReadTargetMemoryInPage(out8 + total, ctx, addr, nb);
if(R_SUCCEEDED(r))
{
addr += nb;
total += nb;
remaining -= nb;
}
}
while(remaining > 0 && R_SUCCEEDED(r));
return total;
}
u32 GDB_WriteTargetMemory(GDBContext *ctx, const void *in, u32 addr, u32 len)
{
Result r = 0;
u32 remaining = len, total = 0;
do
{
u32 nb = (remaining > 0x1000 - (addr & 0xFFF)) ? 0x1000 - (addr & 0xFFF) : remaining;
r = GDB_WriteTargetMemoryInPage(ctx, (u8 *)in + total, addr, nb);
if(R_SUCCEEDED(r))
{
addr += nb;
total += nb;
remaining -= nb;
}
}
while(remaining > 0 && R_SUCCEEDED(r));
return total;
}
int GDB_SendMemory(GDBContext *ctx, const char *prefix, u32 prefixLen, u32 addr, u32 len)
{
char buf[GDB_BUF_LEN];
@ -154,21 +195,7 @@ int GDB_SendMemory(GDBContext *ctx, const char *prefix, u32 prefixLen, u32 addr,
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;
Result r = 0;
u32 remaining = len, total = 0;
do
{
u32 nb = (remaining > 0x1000 - (addr & 0xFFF)) ? 0x1000 - (addr & 0xFFF) : remaining;
r = GDB_ReadMemoryInPage(membuf + total, ctx, addr, nb);
if(R_SUCCEEDED(r))
{
addr += nb;
total += nb;
remaining -= nb;
}
}
while(remaining > 0 && R_SUCCEEDED(r));
u32 total = GDB_ReadTargetMemory(membuf, ctx, addr, len);
if(total == 0)
return prefix == NULL ? GDB_ReplyErrno(ctx, EFAULT) : -EFAULT;
else
@ -180,22 +207,8 @@ int GDB_SendMemory(GDBContext *ctx, const char *prefix, u32 prefixLen, u32 addr,
int GDB_WriteMemory(GDBContext *ctx, const void *buf, u32 addr, u32 len)
{
Result r = 0;
u32 remaining = len, total = 0;
do
{
u32 nb = (remaining > 0x1000 - (addr & 0xFFF)) ? 0x1000 - (addr & 0xFFF) : remaining;
r = GDB_WriteMemoryInPage(ctx, (u8 *)buf + total, addr, nb);
if(R_SUCCEEDED(r))
{
addr += nb;
total += nb;
remaining -= nb;
}
}
while(remaining > 0 && R_SUCCEEDED(r));
if(R_FAILED(r))
u32 total = GDB_WriteTargetMemory(ctx, buf, addr, len);
if(total != len)
return GDB_ReplyErrno(ctx, EFAULT);
else
return GDB_ReplyOk(ctx);
@ -223,7 +236,7 @@ u32 GDB_SearchMemory(bool *found, GDBContext *ctx, u32 addr, u32 len, const void
break;
}
if(R_FAILED(GDB_ReadMemoryInPage(buf + 0x1000 * nbPages, ctx, addrBase + nbPages * 0x1000, 0x1000)))
if(R_FAILED(GDB_ReadTargetMemoryInPage(buf + 0x1000 * nbPages, ctx, addrBase + nbPages * 0x1000, 0x1000)))
break;
}

View File

@ -32,6 +32,7 @@
#include "gdb/debug.h"
#include "gdb/regs.h"
#include "gdb/mem.h"
#include "gdb/hio.h"
#include "gdb/watchpoints.h"
#include "gdb/breakpoints.h"
#include "gdb/stop_point.h"
@ -272,6 +273,7 @@ static const struct
{ 'c', GDB_HANDLER(Continue) },
{ 'C', GDB_HANDLER(Continue) },
{ 'D', GDB_HANDLER(Detach) },
{ 'F', GDB_HANDLER(HioReply) },
{ 'g', GDB_HANDLER(ReadRegisters) },
{ 'G', GDB_HANDLER(WriteRegisters) },
{ 'H', GDB_HANDLER(SetThreadId) },