mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-23 04:41:12 +00:00
thermopshere: gdb: rewrite stop point handling
This commit is contained in:
parent
5de05ed8a8
commit
779aeaa538
14 changed files with 94 additions and 388 deletions
|
@ -69,7 +69,7 @@ static void freeBreakpoint(u32 pos)
|
||||||
g_breakpointManager.allocationBitmap |= BIT(pos);
|
g_breakpointManager.allocationBitmap |= BIT(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
static DebugRegisterPair *findBreakpoint(u64 addr)
|
static DebugRegisterPair *findBreakpoint(uintptr_t addr)
|
||||||
{
|
{
|
||||||
u16 bitmap = ~g_breakpointManager.allocationBitmap & 0xFFFF;
|
u16 bitmap = ~g_breakpointManager.allocationBitmap & 0xFFFF;
|
||||||
while (bitmap != 0) {
|
while (bitmap != 0) {
|
||||||
|
@ -90,7 +90,7 @@ static DebugRegisterPair *findBreakpoint(u64 addr)
|
||||||
// Note: A32/T32/T16 support intentionnally left out
|
// Note: A32/T32/T16 support intentionnally left out
|
||||||
// Note: addresses are supposed to be well-formed regarding the sign extension bits
|
// Note: addresses are supposed to be well-formed regarding the sign extension bits
|
||||||
|
|
||||||
int addBreakpoint(u64 addr)
|
int addBreakpoint(uintptr_t addr)
|
||||||
{
|
{
|
||||||
recursiveSpinlockLock(&g_breakpointManager.lock);
|
recursiveSpinlockLock(&g_breakpointManager.lock);
|
||||||
|
|
||||||
|
@ -127,7 +127,7 @@ int addBreakpoint(u64 addr)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int removeBreakpoint(u64 addr)
|
int removeBreakpoint(uintptr_t addr)
|
||||||
{
|
{
|
||||||
recursiveSpinlockLock(&g_breakpointManager.lock);
|
recursiveSpinlockLock(&g_breakpointManager.lock);
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,6 @@ typedef struct BreakpointManager {
|
||||||
extern BreakpointManager g_breakpointManager;
|
extern BreakpointManager g_breakpointManager;
|
||||||
|
|
||||||
void initBreakpoints(void);
|
void initBreakpoints(void);
|
||||||
int addBreakpoint(u64 addr);
|
int addBreakpoint(uintptr_t addr);
|
||||||
int removeBreakpoint(u64 addr);
|
int removeBreakpoint(uintptr_t addr);
|
||||||
int removeAllBreakpoints(void);
|
int removeAllBreakpoints(void);
|
||||||
|
|
|
@ -1,116 +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 "gdb/breakpoints.h"
|
|
||||||
|
|
||||||
#define _REENT_ONLY
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
u32 GDB_FindClosestBreakpointSlot(GDBContext *ctx, u32 address)
|
|
||||||
{
|
|
||||||
if(ctx->nbBreakpoints == 0 || address <= ctx->breakpoints[0].address)
|
|
||||||
return 0;
|
|
||||||
else if(address > ctx->breakpoints[ctx->nbBreakpoints - 1].address)
|
|
||||||
return ctx->nbBreakpoints;
|
|
||||||
|
|
||||||
u32 a = 0, b = ctx->nbBreakpoints - 1, m;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
m = (a + b) / 2;
|
|
||||||
if(ctx->breakpoints[m].address < address)
|
|
||||||
a = m;
|
|
||||||
else if(ctx->breakpoints[m].address > address)
|
|
||||||
b = m;
|
|
||||||
else
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
while(b - a > 1);
|
|
||||||
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
|
|
||||||
int GDB_GetBreakpointInstruction(u32 *instruction, GDBContext *ctx, u32 address)
|
|
||||||
{
|
|
||||||
u32 id = GDB_FindClosestBreakpointSlot(ctx, address);
|
|
||||||
|
|
||||||
if(id == ctx->nbBreakpoints || ctx->breakpoints[id].address != address)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if(instruction != NULL)
|
|
||||||
*instruction = ctx->breakpoints[id].savedInstruction;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int GDB_AddBreakpoint(GDBContext *ctx, u32 address, bool thumb, bool persist)
|
|
||||||
{
|
|
||||||
if(!thumb && (address & 3) != 0)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
address &= ~1;
|
|
||||||
|
|
||||||
u32 id = GDB_FindClosestBreakpointSlot(ctx, address);
|
|
||||||
|
|
||||||
if(id != ctx->nbBreakpoints && ctx->breakpoints[id].instructionSize != 0 && ctx->breakpoints[id].address == address)
|
|
||||||
return 0;
|
|
||||||
else if(ctx->nbBreakpoints == MAX_BREAKPOINT)
|
|
||||||
return -EBUSY;
|
|
||||||
|
|
||||||
for(u32 i = ctx->nbBreakpoints; i > id && i != 0; i--)
|
|
||||||
ctx->breakpoints[i] = ctx->breakpoints[i - 1];
|
|
||||||
|
|
||||||
ctx->nbBreakpoints++;
|
|
||||||
|
|
||||||
Breakpoint *bkpt = &ctx->breakpoints[id];
|
|
||||||
u32 instr = thumb ? BREAKPOINT_INSTRUCTION_THUMB : BREAKPOINT_INSTRUCTION_ARM;
|
|
||||||
if(R_FAILED(svcReadProcessMemory(&bkpt->savedInstruction, ctx->debug, address, thumb ? 2 : 4)) ||
|
|
||||||
R_FAILED(svcWriteProcessMemory(ctx->debug, &instr, address, thumb ? 2 : 4)))
|
|
||||||
{
|
|
||||||
for(u32 i = id; i < ctx->nbBreakpoints - 1; i++)
|
|
||||||
ctx->breakpoints[i] = ctx->breakpoints[i + 1];
|
|
||||||
|
|
||||||
memset(&ctx->breakpoints[--ctx->nbBreakpoints], 0, sizeof(Breakpoint));
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
bkpt->instructionSize = thumb ? 2 : 4;
|
|
||||||
bkpt->address = address;
|
|
||||||
bkpt->persistent = persist;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int GDB_DisableBreakpointById(GDBContext *ctx, u32 id)
|
|
||||||
{
|
|
||||||
Breakpoint *bkpt = &ctx->breakpoints[id];
|
|
||||||
if(R_FAILED(svcWriteProcessMemory(ctx->debug, &bkpt->savedInstruction, bkpt->address, bkpt->instructionSize)))
|
|
||||||
return -EFAULT;
|
|
||||||
else return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int GDB_RemoveBreakpoint(GDBContext *ctx, u32 address)
|
|
||||||
{
|
|
||||||
address &= ~1;
|
|
||||||
|
|
||||||
u32 id = GDB_FindClosestBreakpointSlot(ctx, address);
|
|
||||||
if(id == ctx->nbBreakpoints || ctx->breakpoints[id].address != address)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
int r = GDB_DisableBreakpointById(ctx, id);
|
|
||||||
if(r != 0)
|
|
||||||
return r;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for(u32 i = id; i < ctx->nbBreakpoints - 1; i++)
|
|
||||||
ctx->breakpoints[i] = ctx->breakpoints[i + 1];
|
|
||||||
|
|
||||||
memset(&ctx->breakpoints[--ctx->nbBreakpoints], 0, sizeof(Breakpoint));
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,20 +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 "gdb.h"
|
|
||||||
|
|
||||||
// We'll actually use SVC 0xFF for breakpoints :P
|
|
||||||
#define BREAKPOINT_INSTRUCTION_ARM 0xEF0000FF
|
|
||||||
#define BREAKPOINT_INSTRUCTION_THUMB 0xDFFF
|
|
||||||
|
|
||||||
u32 GDB_FindClosestBreakpointSlot(GDBContext *ctx, u32 address);
|
|
||||||
int GDB_GetBreakpointInstruction(u32 *instr, GDBContext *ctx, u32 address);
|
|
||||||
int GDB_AddBreakpoint(GDBContext *ctx, u32 address, bool thumb, bool persist);
|
|
||||||
int GDB_DisableBreakpointById(GDBContext *ctx, u32 id);
|
|
||||||
int GDB_RemoveBreakpoint(GDBContext *ctx, u32 address);
|
|
|
@ -16,7 +16,7 @@
|
||||||
#include "gdb/hio.h"
|
#include "gdb/hio.h"
|
||||||
#include "gdb/watchpoints.h"
|
#include "gdb/watchpoints.h"
|
||||||
#include "gdb/breakpoints.h"
|
#include "gdb/breakpoints.h"
|
||||||
#include "gdb/stop_point.h"
|
#include "gdb/stop_points.h"
|
||||||
|
|
||||||
void GDB_InitializeServer(GDBServer *server)
|
void GDB_InitializeServer(GDBServer *server)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,52 +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 "gdb.h"
|
|
||||||
#include "gdb/net.h"
|
|
||||||
#include "gdb/watchpoints.h"
|
|
||||||
#include "gdb/breakpoints.h"
|
|
||||||
|
|
||||||
GDB_DECLARE_HANDLER(ToggleStopPoint)
|
|
||||||
{
|
|
||||||
bool add = ctx->commandData[-1] == 'Z';
|
|
||||||
u32 lst[3];
|
|
||||||
|
|
||||||
const char *pos = GDB_ParseHexIntegerList(lst, ctx->commandData, 3, ';');
|
|
||||||
if(pos == NULL)
|
|
||||||
return GDB_ReplyErrno(ctx, EILSEQ);
|
|
||||||
bool persist = *pos != 0 && strncmp(pos, ";cmds:1", 7) == 0;
|
|
||||||
|
|
||||||
u32 kind = lst[0];
|
|
||||||
u32 addr = lst[1];
|
|
||||||
u32 size = lst[2];
|
|
||||||
|
|
||||||
int res;
|
|
||||||
static const WatchpointKind kinds[3] = { WATCHPOINT_WRITE, WATCHPOINT_READ, WATCHPOINT_READWRITE };
|
|
||||||
switch(kind)
|
|
||||||
{
|
|
||||||
case 0: // software breakpoint
|
|
||||||
if(size != 2 && size != 4)
|
|
||||||
return GDB_ReplyEmpty(ctx);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
res = add ? GDB_AddBreakpoint(ctx, addr, size == 2, persist) :
|
|
||||||
GDB_RemoveBreakpoint(ctx, addr);
|
|
||||||
return res == 0 ? GDB_ReplyOk(ctx) : GDB_ReplyErrno(ctx, -res);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Watchpoints
|
|
||||||
case 2:
|
|
||||||
case 3:
|
|
||||||
case 4:
|
|
||||||
res = add ? GDB_AddWatchpoint(ctx, addr, size, kinds[kind - 2]) :
|
|
||||||
GDB_RemoveWatchpoint(ctx, addr, kinds[kind - 2]);
|
|
||||||
return res == 0 ? GDB_ReplyOk(ctx) : GDB_ReplyErrno(ctx, -res);
|
|
||||||
|
|
||||||
default:
|
|
||||||
return GDB_ReplyEmpty(ctx);
|
|
||||||
}
|
|
||||||
}
|
|
70
thermosphere/src/gdb/stop_points.c
Normal file
70
thermosphere/src/gdb/stop_points.c
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
/*
|
||||||
|
* 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 "../gdb.h"
|
||||||
|
#include "net.h"
|
||||||
|
|
||||||
|
#include "../breakpoints.h"
|
||||||
|
#include "../software_breakpoints.h"
|
||||||
|
#include "../watchpoints.h"
|
||||||
|
|
||||||
|
GDB_DECLARE_HANDLER(ToggleStopPoint)
|
||||||
|
{
|
||||||
|
bool add = ctx->commandData[-1] == 'Z';
|
||||||
|
unsigned long lst[3];
|
||||||
|
|
||||||
|
const char *pos = GDB_ParseHexIntegerList(lst, ctx->commandData, 3, ';');
|
||||||
|
if (pos == NULL) {
|
||||||
|
return GDB_ReplyErrno(ctx, EILSEQ);
|
||||||
|
}
|
||||||
|
bool persist = *pos != 0 && strncmp(pos, ";cmds:1", 7) == 0;
|
||||||
|
|
||||||
|
// In theory we should reject leading zeroes in "kind". Oh well...
|
||||||
|
unsigned long kind = lst[0];
|
||||||
|
uintptr_t addr = lst[1];
|
||||||
|
size_t size = lst[2];
|
||||||
|
|
||||||
|
int res;
|
||||||
|
static const WatchpointLoadStoreControl kinds[3] = {
|
||||||
|
WatchpointLoadStoreControl_Store,
|
||||||
|
WatchpointLoadStoreControl_Load,
|
||||||
|
WatchpointLoadStoreControl_LoadStore,
|
||||||
|
};
|
||||||
|
|
||||||
|
switch(kind) {
|
||||||
|
// Software breakpoint
|
||||||
|
case 0: {
|
||||||
|
if(size != 4) {
|
||||||
|
return GDB_ReplyErrno(ctx, EINVAL);
|
||||||
|
}
|
||||||
|
res = add ? addSoftwareBreakpoint(addr, persist) : removeSoftwareBreakpoint(addr, false);
|
||||||
|
return res == 0 ? GDB_ReplyOk(ctx) : GDB_ReplyErrno(ctx, -res);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hardware breakpoint
|
||||||
|
case 1: {
|
||||||
|
if(size != 4) {
|
||||||
|
return GDB_ReplyErrno(ctx, EINVAL);
|
||||||
|
}
|
||||||
|
res = add ? addBreakpoint(addr) : removeBreakpoint(addr);
|
||||||
|
return res == 0 ? GDB_ReplyOk(ctx) : GDB_ReplyErrno(ctx, -res);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Watchpoints
|
||||||
|
case 2:
|
||||||
|
case 3:
|
||||||
|
case 4: {
|
||||||
|
res = add ? addWatchpoint(addr, size, kinds[kind - 2]) : removeWatchpoint(addr, size, kinds[kind - 2]);
|
||||||
|
return res == 0 ? GDB_ReplyOk(ctx) : GDB_ReplyErrno(ctx, -res);
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
return GDB_ReplyEmpty(ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,6 +7,6 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "gdb.h"
|
#include "../gdb.h"
|
||||||
|
|
||||||
GDB_DECLARE_HANDLER(ToggleStopPoint);
|
GDB_DECLARE_HANDLER(ToggleStopPoint);
|
|
@ -1,151 +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 "gdb/watchpoints.h"
|
|
||||||
#include "csvc.h"
|
|
||||||
|
|
||||||
#define _REENT_ONLY
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
There are only 2 Watchpoint Register Pairs on MPCORE ARM11 CPUs,
|
|
||||||
and only 2 Breakpoint Register Pairs with context ID capabilities (BRP4-5) as well.
|
|
||||||
|
|
||||||
We'll reserve and use all 4 of them
|
|
||||||
*/
|
|
||||||
|
|
||||||
RecursiveLock watchpointManagerLock;
|
|
||||||
|
|
||||||
typedef struct Watchpoint
|
|
||||||
{
|
|
||||||
u32 address;
|
|
||||||
u32 size;
|
|
||||||
WatchpointKind kind;
|
|
||||||
Handle debug; // => context ID
|
|
||||||
} Watchpoint;
|
|
||||||
|
|
||||||
typedef struct WatchpointManager
|
|
||||||
{
|
|
||||||
u32 total;
|
|
||||||
Watchpoint watchpoints[2];
|
|
||||||
} WatchpointManager;
|
|
||||||
|
|
||||||
static WatchpointManager manager;
|
|
||||||
|
|
||||||
void GDB_ResetWatchpoints(void)
|
|
||||||
{
|
|
||||||
static bool lockInitialized = false;
|
|
||||||
if(!lockInitialized)
|
|
||||||
{
|
|
||||||
RecursiveLock_Init(&watchpointManagerLock);
|
|
||||||
lockInitialized = true;
|
|
||||||
}
|
|
||||||
recursiveSpinlockLock(&watchpointManagerLock);
|
|
||||||
|
|
||||||
svcKernelSetState(0x10003); // enable monitor mode debugging
|
|
||||||
svcKernelSetState(0x10004, 0); // disable watchpoint 0
|
|
||||||
svcKernelSetState(0x10004, 1); // disable watchpoint 1
|
|
||||||
|
|
||||||
memset(&manager, 0, sizeof(WatchpointManager));
|
|
||||||
|
|
||||||
recursiveSpinlockUnlock(&watchpointManagerLock);
|
|
||||||
}
|
|
||||||
|
|
||||||
int GDB_AddWatchpoint(GDBContext *ctx, u32 address, u32 size, WatchpointKind kind)
|
|
||||||
{
|
|
||||||
recursiveSpinlockLock(&watchpointManagerLock);
|
|
||||||
|
|
||||||
u32 offset = address - (address & ~3);
|
|
||||||
|
|
||||||
if(manager.total == 2)
|
|
||||||
return -EBUSY;
|
|
||||||
|
|
||||||
if(size == 0 || (offset + size) > 4 || kind == WATCHPOINT_DISABLED)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if(GDB_GetWatchpointKind(ctx, address) != WATCHPOINT_DISABLED)
|
|
||||||
// Disallow duplicate watchpoints: the kernel doesn't give us sufficient info to differentiate them by kind (DFSR)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
u32 id = manager.watchpoints[0].kind == WATCHPOINT_DISABLED ? 0 : 1;
|
|
||||||
u32 selectMask = ((1 << size) - 1) << offset;
|
|
||||||
|
|
||||||
u32 WCR = (1 << 20) | /* linked */
|
|
||||||
((4 + id) << 16) | /* ID of the linked BRP */
|
|
||||||
(selectMask << 5) | /* byte address select */
|
|
||||||
((u32)kind << 3) | /* kind */
|
|
||||||
(2 << 1) | /* user mode only */
|
|
||||||
(1 << 0) ; /* enabled */
|
|
||||||
|
|
||||||
s64 out;
|
|
||||||
|
|
||||||
Result r = svcGetHandleInfo(&out, ctx->debug, 0x10000); // context ID
|
|
||||||
|
|
||||||
if(R_SUCCEEDED(r))
|
|
||||||
{
|
|
||||||
svcKernelSetState(id == 0 ? 0x10005 : 0x10006, address, WCR, (u32)out); // set watchpoint
|
|
||||||
Watchpoint *watchpoint = &manager.watchpoints[id];
|
|
||||||
manager.total++;
|
|
||||||
watchpoint->address = address;
|
|
||||||
watchpoint->size = size;
|
|
||||||
watchpoint->kind = kind;
|
|
||||||
watchpoint->debug = ctx->debug;
|
|
||||||
ctx->watchpoints[ctx->nbWatchpoints++] = address;
|
|
||||||
recursiveSpinlockUnlock(&watchpointManagerLock);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
recursiveSpinlockUnlock(&watchpointManagerLock);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int GDB_RemoveWatchpoint(GDBContext *ctx, u32 address, WatchpointKind kind)
|
|
||||||
{
|
|
||||||
recursiveSpinlockLock(&watchpointManagerLock);
|
|
||||||
|
|
||||||
u32 id;
|
|
||||||
for(id = 0; id < 2 && manager.watchpoints[id].address != address && manager.watchpoints[id].debug != ctx->debug; id++);
|
|
||||||
|
|
||||||
if(id == 2 || (kind != WATCHPOINT_DISABLED && manager.watchpoints[id].kind != kind))
|
|
||||||
{
|
|
||||||
recursiveSpinlockUnlock(&watchpointManagerLock);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
svcKernelSetState(0x10004, id); // disable watchpoint
|
|
||||||
|
|
||||||
memset(&manager.watchpoints[id], 0, sizeof(Watchpoint));
|
|
||||||
manager.total--;
|
|
||||||
|
|
||||||
if(ctx->watchpoints[0] == address)
|
|
||||||
{
|
|
||||||
ctx->watchpoints[0] = ctx->watchpoints[1];
|
|
||||||
ctx->watchpoints[1] = 0;
|
|
||||||
ctx->nbWatchpoints--;
|
|
||||||
}
|
|
||||||
else if(ctx->watchpoints[1] == address)
|
|
||||||
{
|
|
||||||
ctx->watchpoints[1] = 0;
|
|
||||||
ctx->nbWatchpoints--;
|
|
||||||
}
|
|
||||||
|
|
||||||
recursiveSpinlockUnlock(&watchpointManagerLock);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
WatchpointKind GDB_GetWatchpointKind(GDBContext *ctx, u32 address)
|
|
||||||
{
|
|
||||||
u32 id;
|
|
||||||
for(id = 0; id < 2 && (manager.watchpoints[id].address != address || manager.watchpoints[id].debug != ctx->debug); id++);
|
|
||||||
|
|
||||||
return id == 2 ? WATCHPOINT_DISABLED : manager.watchpoints[id].kind;
|
|
||||||
}
|
|
|
@ -1,25 +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 "gdb.h"
|
|
||||||
|
|
||||||
typedef enum WatchpointKind
|
|
||||||
{
|
|
||||||
WATCHPOINT_DISABLED = 0,
|
|
||||||
WATCHPOINT_READ,
|
|
||||||
WATCHPOINT_WRITE,
|
|
||||||
WATCHPOINT_READWRITE
|
|
||||||
} WatchpointKind;
|
|
||||||
|
|
||||||
void GDB_ResetWatchpoints(void); // needed for software breakpoints to be detected as debug events as well
|
|
||||||
|
|
||||||
int GDB_AddWatchpoint(GDBContext *ctx, u32 address, u32 size, WatchpointKind kind);
|
|
||||||
int GDB_RemoveWatchpoint(GDBContext *ctx, u32 address, WatchpointKind kind);
|
|
||||||
|
|
||||||
WatchpointKind GDB_GetWatchpointKind(GDBContext *ctx, u32 address);
|
|
|
@ -31,7 +31,7 @@ SoftwareBreakpointManager g_softwareBreakpointManager = {0};
|
||||||
We also define sw breakpoints on invalid addresses (for one or more cores) UNPREDICTABLE.
|
We also define sw breakpoints on invalid addresses (for one or more cores) UNPREDICTABLE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static size_t findClosestSoftwareBreakpointSlot(u64 address)
|
static size_t findClosestSoftwareBreakpointSlot(uintptr_t address)
|
||||||
{
|
{
|
||||||
if(g_softwareBreakpointManager.numBreakpoints == 0 || address <= g_softwareBreakpointManager.breakpoints[0].address) {
|
if(g_softwareBreakpointManager.numBreakpoints == 0 || address <= g_softwareBreakpointManager.breakpoints[0].address) {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -154,7 +154,7 @@ bool revertAllSoftwareBreakpoints(void)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int addSoftwareBreakpoint(u64 addr, bool persistent)
|
int addSoftwareBreakpoint(uintptr_t addr, bool persistent)
|
||||||
{
|
{
|
||||||
if ((addr & 3) != 0) {
|
if ((addr & 3) != 0) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -189,7 +189,7 @@ int addSoftwareBreakpoint(u64 addr, bool persistent)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int removeSoftwareBreakpoint(u64 addr, bool keepPersistent)
|
int removeSoftwareBreakpoint(uintptr_t addr, bool keepPersistent)
|
||||||
{
|
{
|
||||||
if ((addr & 3) != 0) {
|
if ((addr & 3) != 0) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
|
@ -45,6 +45,6 @@ extern SoftwareBreakpointManager g_softwareBreakpointManager;
|
||||||
bool revertAllSoftwareBreakpoints(void);
|
bool revertAllSoftwareBreakpoints(void);
|
||||||
bool applyAllSoftwareBreakpoints(void);
|
bool applyAllSoftwareBreakpoints(void);
|
||||||
|
|
||||||
int addSoftwareBreakpoint(u64 addr, bool persistent);
|
int addSoftwareBreakpoint(uintptr_t addr, bool persistent);
|
||||||
int removeSoftwareBreakpoint(u64 addr, bool keepPersistent);
|
int removeSoftwareBreakpoint(uintptr_t addr, bool keepPersistent);
|
||||||
int removeAllSoftwareBreakpoints(bool keepPersistent);
|
int removeAllSoftwareBreakpoints(bool keepPersistent);
|
||||||
|
|
|
@ -60,7 +60,7 @@ static inline void commitAndBroadcastWatchpoints(void)
|
||||||
executeFunctionOnAllCores(commitAndBroadcastWatchpointHandler, NULL, true);
|
executeFunctionOnAllCores(commitAndBroadcastWatchpointHandler, NULL, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static DebugRegisterPair *findCombinedWatchpoint(u64 addr)
|
static DebugRegisterPair *findCombinedWatchpoint(uintptr_t addr)
|
||||||
{
|
{
|
||||||
addr &= ~7ull;
|
addr &= ~7ull;
|
||||||
u16 bitmap = ~g_watchpointManager.allocationBitmap & 0xFFFF;
|
u16 bitmap = ~g_watchpointManager.allocationBitmap & 0xFFFF;
|
||||||
|
@ -91,7 +91,7 @@ static DebugRegisterPair *allocateCombinedWatchpoint(u16 *bitmap)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Precondition: not a MASK-based watchpoint
|
// Precondition: not a MASK-based watchpoint
|
||||||
static bool checkNormalWatchpointRange(u64 addr, size_t size)
|
static bool checkNormalWatchpointRange(uintptr_t addr, size_t size)
|
||||||
{
|
{
|
||||||
u16 bitmap = g_watchpointManager.allocationBitmap;
|
u16 bitmap = g_watchpointManager.allocationBitmap;
|
||||||
if (findCombinedWatchpoint(addr) == NULL) {
|
if (findCombinedWatchpoint(addr) == NULL) {
|
||||||
|
@ -101,7 +101,7 @@ static bool checkNormalWatchpointRange(u64 addr, size_t size)
|
||||||
}
|
}
|
||||||
|
|
||||||
// if it overlaps...
|
// if it overlaps...
|
||||||
u64 addr2 = (addr + size) & ~7ull;
|
uintptr_t addr2 = (addr + size) & ~7ull;
|
||||||
|
|
||||||
if (addr2 != (addr & ~7ull)) {
|
if (addr2 != (addr & ~7ull)) {
|
||||||
if (findCombinedWatchpoint(addr2) == NULL) {
|
if (findCombinedWatchpoint(addr2) == NULL) {
|
||||||
|
@ -112,7 +112,7 @@ static bool checkNormalWatchpointRange(u64 addr, size_t size)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool isRangeMaskWatchpoint(u64 addr, size_t size)
|
static inline bool isRangeMaskWatchpoint(uintptr_t addr, size_t size)
|
||||||
{
|
{
|
||||||
// size needs to be a power of 2, at least 8 (we'll only allow 16+ though), addr needs to be aligned.
|
// size needs to be a power of 2, at least 8 (we'll only allow 16+ though), addr needs to be aligned.
|
||||||
bool ret = (size & (size - 1)) == 0 && size >= 16 && (addr & (size - 1)) == 0;
|
bool ret = (size & (size - 1)) == 0 && size >= 16 && (addr & (size - 1)) == 0;
|
||||||
|
@ -152,7 +152,7 @@ static bool combineWatchpoint(const DebugRegisterPair *wp)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DebugRegisterPair *doFindSplitWatchpoint(u64 addr, size_t size, WatchpointLoadStoreControl direction, bool strict)
|
static DebugRegisterPair *doFindSplitWatchpoint(uintptr_t addr, size_t size, WatchpointLoadStoreControl direction, bool strict)
|
||||||
{
|
{
|
||||||
// Note: we will use RES0 bit0_1 of wr in case of overlapping
|
// Note: we will use RES0 bit0_1 of wr in case of overlapping
|
||||||
for (u32 i = 0; i < g_watchpointManager.numSplitWatchpoints; i++) {
|
for (u32 i = 0; i < g_watchpointManager.numSplitWatchpoints; i++) {
|
||||||
|
@ -189,7 +189,7 @@ static DebugRegisterPair *doFindSplitWatchpoint(u64 addr, size_t size, Watchpoin
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
DebugControlRegister retrieveSplitWatchpointConfig(u64 addr, size_t size, WatchpointLoadStoreControl direction, bool strict)
|
DebugControlRegister retrieveSplitWatchpointConfig(uintptr_t addr, size_t size, WatchpointLoadStoreControl direction, bool strict)
|
||||||
{
|
{
|
||||||
recursiveSpinlockLock(&g_watchpointManager.lock);
|
recursiveSpinlockLock(&g_watchpointManager.lock);
|
||||||
DebugRegisterPair *wp = doFindSplitWatchpoint(addr, size, direction, strict);
|
DebugRegisterPair *wp = doFindSplitWatchpoint(addr, size, direction, strict);
|
||||||
|
@ -201,7 +201,7 @@ DebugControlRegister retrieveSplitWatchpointConfig(u64 addr, size_t size, Watchp
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int addWatchpoint(u64 addr, size_t size, WatchpointLoadStoreControl direction)
|
int addWatchpoint(uintptr_t addr, size_t size, WatchpointLoadStoreControl direction)
|
||||||
{
|
{
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -242,7 +242,7 @@ int addWatchpoint(u64 addr, size_t size, WatchpointLoadStoreControl direction)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 addr2 = (addr + size) & ~7ull;
|
uintptr_t addr2 = (addr + size) & ~7ull;
|
||||||
size_t off1 = addr & 7ull;
|
size_t off1 = addr & 7ull;
|
||||||
size_t size1 = (addr != addr2) ? 8 - off1 : size;
|
size_t size1 = (addr != addr2) ? 8 - off1 : size;
|
||||||
size_t size2 = size - size1;
|
size_t size2 = size - size1;
|
||||||
|
@ -290,7 +290,7 @@ static void combineAllCurrentWatchpoints(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int removeWatchpoint(u64 addr, size_t size, WatchpointLoadStoreControl direction)
|
int removeWatchpoint(uintptr_t addr, size_t size, WatchpointLoadStoreControl direction)
|
||||||
{
|
{
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
|
@ -35,7 +35,7 @@ typedef struct WatchpointManager {
|
||||||
extern WatchpointManager g_watchpointManager;
|
extern WatchpointManager g_watchpointManager;
|
||||||
|
|
||||||
void initWatchpoints(void);
|
void initWatchpoints(void);
|
||||||
DebugControlRegister retrieveSplitWatchpointConfig(u64 addr, size_t size, WatchpointLoadStoreControl direction, bool strict);
|
DebugControlRegister retrieveSplitWatchpointConfig(uintptr_t addr, size_t size, WatchpointLoadStoreControl direction, bool strict);
|
||||||
int addWatchpoint(u64 addr, size_t size, WatchpointLoadStoreControl direction);
|
int addWatchpoint(uintptr_t addr, size_t size, WatchpointLoadStoreControl direction);
|
||||||
int removeWatchpoint(u64 addr, size_t size, WatchpointLoadStoreControl direction);
|
int removeWatchpoint(uintptr_t addr, size_t size, WatchpointLoadStoreControl direction);
|
||||||
int removeAllWatchpoints(void);
|
int removeAllWatchpoints(void);
|
||||||
|
|
Loading…
Reference in a new issue