Add GDB target IO support (called Host I/O by gdb), not working yet
This commit is contained in:
parent
593f50de91
commit
54eeb97b24
@ -33,10 +33,14 @@
|
|||||||
#include "pmdbgext.h"
|
#include "pmdbgext.h"
|
||||||
#include "sock_util.h"
|
#include "sock_util.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
#include "ifile.h"
|
||||||
|
|
||||||
#define MAX_DEBUG 3
|
#define MAX_DEBUG 3
|
||||||
#define MAX_DEBUG_THREAD 127
|
#define MAX_DEBUG_THREAD 127
|
||||||
#define MAX_BREAKPOINT 256
|
#define MAX_BREAKPOINT 256
|
||||||
|
|
||||||
|
#define MAX_TIO_OPEN_FILE 64
|
||||||
|
|
||||||
// 512+24 is the ideal size as IDA will try to read exactly 0x100 bytes at a time. Add 4 to this, for $#<checksum>, see below.
|
// 512+24 is the ideal size as IDA will try to read exactly 0x100 bytes at a time. Add 4 to this, for $#<checksum>, see below.
|
||||||
// IDA seems to want additional bytes as well.
|
// IDA seems to want additional bytes as well.
|
||||||
// 1024 is fine enough to put all regs in the 'T' stop reply packets
|
// 1024 is fine enough to put all regs in the 'T' stop reply packets
|
||||||
@ -76,6 +80,12 @@ typedef struct PackedGdbHioRequest
|
|||||||
bool ctrlC;
|
bool ctrlC;
|
||||||
} PackedGdbHioRequest;
|
} PackedGdbHioRequest;
|
||||||
|
|
||||||
|
typedef struct GdbTioFileInfo
|
||||||
|
{
|
||||||
|
IFile f;
|
||||||
|
int flags;
|
||||||
|
} GdbTioFileInfo;
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
GDB_FLAG_SELECTED = 1,
|
GDB_FLAG_SELECTED = 1,
|
||||||
@ -149,6 +159,9 @@ typedef struct GDBContext
|
|||||||
u32 currentHioRequestTargetAddr;
|
u32 currentHioRequestTargetAddr;
|
||||||
PackedGdbHioRequest currentHioRequest;
|
PackedGdbHioRequest currentHioRequest;
|
||||||
|
|
||||||
|
GdbTioFileInfo openTioFileInfos[MAX_TIO_OPEN_FILE];
|
||||||
|
u32 numOpenTioFiles;
|
||||||
|
|
||||||
bool enableExternalMemoryAccess;
|
bool enableExternalMemoryAccess;
|
||||||
char *commandData, *commandEnd;
|
char *commandData, *commandEnd;
|
||||||
int latestSentPacketSize;
|
int latestSentPacketSize;
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
u8 GDB_ComputeChecksum(const char *packetData, u32 len);
|
u8 GDB_ComputeChecksum(const char *packetData, u32 len);
|
||||||
void GDB_EncodeHex(char *dst, const void *src, u32 len);
|
void GDB_EncodeHex(char *dst, const void *src, u32 len);
|
||||||
u32 GDB_DecodeHex(void *dst, const char *src, u32 len);
|
u32 GDB_DecodeHex(void *dst, const char *src, u32 len);
|
||||||
|
u32 GDB_EscapeBinaryData(void *dst, const void *src, u32 len, u32 maxLen);
|
||||||
u32 GDB_UnescapeBinaryData(void *dst, const void *src, u32 len);
|
u32 GDB_UnescapeBinaryData(void *dst, const void *src, u32 len);
|
||||||
const char *GDB_ParseIntegerList(u32 *dst, const char *src, u32 nb, char sep, char lastSep, u32 base, bool allowPrefix);
|
const char *GDB_ParseIntegerList(u32 *dst, const char *src, u32 nb, char sep, char lastSep, u32 base, bool allowPrefix);
|
||||||
const char *GDB_ParseHexIntegerList(u32 *dst, const char *src, u32 nb, char lastSep);
|
const char *GDB_ParseHexIntegerList(u32 *dst, const char *src, u32 nb, char lastSep);
|
||||||
|
31
sysmodules/rosalina/include/gdb/tio.h
Normal file
31
sysmodules/rosalina/include/gdb/tio.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* 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"
|
||||||
|
|
||||||
|
GDB_DECLARE_VERBOSE_HANDLER(File);
|
@ -26,7 +26,6 @@
|
|||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "gdb.h"
|
|
||||||
#include "gdb/hio.h"
|
#include "gdb/hio.h"
|
||||||
#include "gdb/net.h"
|
#include "gdb/net.h"
|
||||||
#include "gdb/mem.h"
|
#include "gdb/mem.h"
|
||||||
|
@ -75,6 +75,25 @@ u32 GDB_DecodeHex(void *dst, const char *src, u32 len)
|
|||||||
return (!ok) ? i - 1 : i;
|
return (!ok) ? i - 1 : i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 GDB_EscapeBinaryData(void *dst, const void *src, u32 len, u32 maxLen)
|
||||||
|
{
|
||||||
|
u8 *dst8 = (u8 *)dst;
|
||||||
|
const u8 *src8 = (const u8 *)src;
|
||||||
|
|
||||||
|
for(u32 i = 0; i < len && (u32)dst8 - (u32)dst < maxLen; i++)
|
||||||
|
{
|
||||||
|
if(*src8 == '$' || *src8 == '#' || *src8 == '}' || *src8 == '*')
|
||||||
|
{
|
||||||
|
*dst8++ = '}';
|
||||||
|
*dst8++ = *src8++ ^ 0x20;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*dst8++ = *src8++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dst8 - (u8 *)dst;
|
||||||
|
}
|
||||||
|
|
||||||
u32 GDB_UnescapeBinaryData(void *dst, const void *src, u32 len)
|
u32 GDB_UnescapeBinaryData(void *dst, const void *src, u32 len)
|
||||||
{
|
{
|
||||||
u8 *dst8 = (u8 *)dst;
|
u8 *dst8 = (u8 *)dst;
|
||||||
|
@ -215,6 +215,11 @@ int GDB_CloseClient(GDBContext *ctx)
|
|||||||
memset(ctx->memoryOsInfoXmlData, 0, sizeof(ctx->memoryOsInfoXmlData));
|
memset(ctx->memoryOsInfoXmlData, 0, sizeof(ctx->memoryOsInfoXmlData));
|
||||||
memset(ctx->processesOsInfoXmlData, 0, sizeof(ctx->processesOsInfoXmlData));
|
memset(ctx->processesOsInfoXmlData, 0, sizeof(ctx->processesOsInfoXmlData));
|
||||||
|
|
||||||
|
for (u32 i = 0; i < MAX_TIO_OPEN_FILE; i++)
|
||||||
|
IFile_Close(&ctx->openTioFileInfos[i].f);
|
||||||
|
memset(ctx->openTioFileInfos, 0, sizeof(ctx->openTioFileInfos));
|
||||||
|
ctx->numOpenTioFiles = 0;
|
||||||
|
|
||||||
RecursiveLock_Unlock(&ctx->lock);
|
RecursiveLock_Unlock(&ctx->lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
512
sysmodules/rosalina/source/gdb/tio.c
Normal file
512
sysmodules/rosalina/source/gdb/tio.c
Normal file
@ -0,0 +1,512 @@
|
|||||||
|
/*
|
||||||
|
* 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/tio.h"
|
||||||
|
#include "gdb/hio.h"
|
||||||
|
#include "gdb/net.h"
|
||||||
|
#include "gdb/mem.h"
|
||||||
|
#include "gdb/debug.h"
|
||||||
|
#include "fmt.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#include <3ds/util/utf.h>
|
||||||
|
|
||||||
|
#define GDBHIO_O_RDONLY 0x0
|
||||||
|
#define GDBHIO_O_WRONLY 0x1
|
||||||
|
#define GDBHIO_O_RDWR 0x2
|
||||||
|
#define GDBHIO_O_ACCMODE 0x3
|
||||||
|
#define GDBHIO_O_APPEND 0x8
|
||||||
|
#define GDBHIO_O_CREAT 0x200
|
||||||
|
#define GDBHIO_O_TRUNC 0x400
|
||||||
|
#define GDBHIO_O_EXCL 0x800
|
||||||
|
#define GDBHIO_O_SUPPORTED (GDBHIO_O_RDONLY | GDBHIO_O_WRONLY| \
|
||||||
|
GDBHIO_O_RDWR | GDBHIO_O_APPEND| \
|
||||||
|
GDBHIO_O_CREAT | GDBHIO_O_TRUNC| \
|
||||||
|
GDBHIO_O_EXCL)
|
||||||
|
|
||||||
|
#define GDBHIO_S_IFREG 0100000
|
||||||
|
#define GDBHIO_S_IFDIR 040000
|
||||||
|
#define GDBHIO_S_IFCHR 020000
|
||||||
|
#define GDBHIO_S_IRUSR 0400
|
||||||
|
#define GDBHIO_S_IWUSR 0200
|
||||||
|
#define GDBHIO_S_IXUSR 0100
|
||||||
|
#define GDBHIO_S_IRWXU 0700
|
||||||
|
#define GDBHIO_S_IRGRP 040
|
||||||
|
#define GDBHIO_S_IWGRP 020
|
||||||
|
#define GDBHIO_S_IXGRP 010
|
||||||
|
#define GDBHIO_S_IRWXG 070
|
||||||
|
#define GDBHIO_S_IROTH 04
|
||||||
|
#define GDBHIO_S_IWOTH 02
|
||||||
|
#define GDBHIO_S_IXOTH 01
|
||||||
|
#define GDBHIO_S_IRWXO 07
|
||||||
|
#define GDBHIO_S_SUPPORTED (GDBHIO_S_IFREG|GDBHIO_S_IFDIR| \
|
||||||
|
GDBHIO_S_IRWXU|GDBHIO_S_IRWXG| \
|
||||||
|
GDBHIO_S_IRWXO)
|
||||||
|
|
||||||
|
#define GDBHIO_SEEK_SET 0
|
||||||
|
#define GDBHIO_SEEK_CUR 1
|
||||||
|
#define GDBHIO_SEEK_END 2
|
||||||
|
|
||||||
|
#define GDBHIO_EPERM 1
|
||||||
|
#define GDBHIO_ENOENT 2
|
||||||
|
#define GDBHIO_EINTR 4
|
||||||
|
#define GDBHIO_EIO 5
|
||||||
|
#define GDBHIO_EBADF 9
|
||||||
|
#define GDBHIO_EACCES 13
|
||||||
|
#define GDBHIO_EFAULT 14
|
||||||
|
#define GDBHIO_EBUSY 16
|
||||||
|
#define GDBHIO_EEXIST 17
|
||||||
|
#define GDBHIO_ENODEV 19
|
||||||
|
#define GDBHIO_ENOTDIR 20
|
||||||
|
#define GDBHIO_EISDIR 21
|
||||||
|
#define GDBHIO_EINVAL 22
|
||||||
|
#define GDBHIO_ENFILE 23
|
||||||
|
#define GDBHIO_EMFILE 24
|
||||||
|
#define GDBHIO_EFBIG 27
|
||||||
|
#define GDBHIO_ENOSPC 28
|
||||||
|
#define GDBHIO_ESPIPE 29
|
||||||
|
#define GDBHIO_EROFS 30
|
||||||
|
#define GDBHIO_ENOSYS 88
|
||||||
|
#define GDBHIO_ENAMETOOLONG 91
|
||||||
|
#define GDBHIO_EUNKNOWN 9999
|
||||||
|
|
||||||
|
#define GDB_TIO_HANDLER(name) GDB_HANDLER(Tio##name)
|
||||||
|
#define GDB_DECLARE_TIO_HANDLER(name) GDB_DECLARE_HANDLER(Tio##name)
|
||||||
|
|
||||||
|
// https://sourceware.org/gdb/onlinedocs/gdb/struct-stat.html#struct-stat
|
||||||
|
typedef u32 gdbhio_time_t;
|
||||||
|
typedef int gdbhio_mode_t;
|
||||||
|
|
||||||
|
struct gdbhio_stat {
|
||||||
|
unsigned int st_dev; /* device */
|
||||||
|
unsigned int st_ino; /* inode */
|
||||||
|
gdbhio_mode_t st_mode; /* protection */
|
||||||
|
unsigned int st_nlink; /* number of hard links */
|
||||||
|
unsigned int st_uid; /* user ID of owner */
|
||||||
|
unsigned int st_gid; /* group ID of owner */
|
||||||
|
unsigned int st_rdev; /* device type (if inode device) */
|
||||||
|
u64 st_size; /* total size, in bytes */
|
||||||
|
u64 st_blksize; /* blocksize for filesystem I/O */
|
||||||
|
u64 st_blocks; /* number of blocks allocated */
|
||||||
|
gdbhio_time_t st_atime; /* time of last access */
|
||||||
|
gdbhio_time_t st_mtime; /* time of last modification */
|
||||||
|
gdbhio_time_t st_ctime; /* time of last change */
|
||||||
|
};
|
||||||
|
|
||||||
|
static void GDB_TioMakeStructStat(struct gdbhio_stat *out, const struct gdbhio_stat *in)
|
||||||
|
{
|
||||||
|
memset(out, 0, sizeof(struct gdbhio_stat));
|
||||||
|
out->st_dev = __builtin_bswap32(in->st_dev);
|
||||||
|
out->st_ino = __builtin_bswap32(in->st_ino);
|
||||||
|
out->st_mode = __builtin_bswap32(in->st_dev);
|
||||||
|
out->st_nlink = __builtin_bswap32(in->st_nlink);
|
||||||
|
out->st_uid = __builtin_bswap32(in->st_uid);
|
||||||
|
out->st_gid = __builtin_bswap32(in->st_gid);
|
||||||
|
out->st_rdev = __builtin_bswap32(in->st_rdev);
|
||||||
|
out->st_size = __builtin_bswap64(in->st_size);
|
||||||
|
out->st_blksize = __builtin_bswap64(in->st_blksize);
|
||||||
|
out->st_blocks = __builtin_bswap64(in->st_blocks);
|
||||||
|
out->st_atime = __builtin_bswap32(in->st_atime);
|
||||||
|
out->st_mtime = __builtin_bswap32(in->st_mtime);
|
||||||
|
out->st_ctime = __builtin_bswap32(in->st_ctime);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inspired from https://github.com/smealum/ctrulib/blob/master/libctru/source/sdmc_dev.c
|
||||||
|
|
||||||
|
static int GDB_TioConvertResult(Result res)
|
||||||
|
{
|
||||||
|
switch(res)
|
||||||
|
{
|
||||||
|
case 0: return 0;
|
||||||
|
case 0x082044BE: return GDBHIO_EEXIST;
|
||||||
|
case 0x086044D2: return GDBHIO_ENOSPC;
|
||||||
|
case 0xC8804478:
|
||||||
|
case 0xC92044FA: return GDBHIO_ENOENT;
|
||||||
|
case 0xE0E046BE: return GDBHIO_EINVAL;
|
||||||
|
case 0xE0E046BF: return GDBHIO_ENAMETOOLONG;
|
||||||
|
default: return GDBHIO_EUNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static GdbTioFileInfo *GDB_TioConvertFd(GDBContext *ctx, int fd)
|
||||||
|
{
|
||||||
|
if (fd < 3 || fd - 3 >= MAX_TIO_OPEN_FILE)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
GdbTioFileInfo *slot = &ctx->openTioFileInfos[fd - 3];
|
||||||
|
return slot->f.handle == 0 ? NULL : slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int GDB_TioRegisterFile(GDBContext *ctx, Handle h, int gdbOpenFlags)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
for (fd = 3; fd < 3 + MAX_TIO_OPEN_FILE && GDB_TioConvertFd(ctx, fd) != NULL; fd++);
|
||||||
|
|
||||||
|
if (fd >= 3 + MAX_TIO_OPEN_FILE)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
GdbTioFileInfo *slot = &ctx->openTioFileInfos[fd - 3];
|
||||||
|
memset(slot, 0, sizeof(GdbTioFileInfo));
|
||||||
|
slot->f.handle = h;
|
||||||
|
slot->flags = gdbOpenFlags;
|
||||||
|
|
||||||
|
ctx->numOpenTioFiles++;
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int GDB_MakeUtf16Path(FS_Path *outPath, const char *path)
|
||||||
|
{
|
||||||
|
u16 *p16 = (u16 *)outPath->data;
|
||||||
|
outPath->type = PATH_UTF16;
|
||||||
|
|
||||||
|
ssize_t units = utf8_to_utf16(p16, (const u8 *) path, PATH_MAX);
|
||||||
|
if (units < 0) return GDBHIO_EINVAL;
|
||||||
|
else if (units >= PATH_MAX) return GDBHIO_ENAMETOOLONG;
|
||||||
|
|
||||||
|
p16[units] = 0;
|
||||||
|
outPath->size = 2 * (units + 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int GDB_TioReplyErrno(GDBContext *ctx, int err)
|
||||||
|
{
|
||||||
|
return GDB_SendFormattedPacket(ctx, "F-1,%lx", (u32)err);
|
||||||
|
}
|
||||||
|
|
||||||
|
GDB_DECLARE_TIO_HANDLER(Open)
|
||||||
|
{
|
||||||
|
s64 out = 1;
|
||||||
|
svcGetSystemInfo(&out, 0x10000, 0x203);
|
||||||
|
bool isSdMode = (bool)out;
|
||||||
|
FS_ArchiveID archiveId = isSdMode ? ARCHIVE_SDMC : ARCHIVE_NAND_RW;
|
||||||
|
u16 fsNameBuf[PATH_MAX + 1];
|
||||||
|
FS_Path fsPath;
|
||||||
|
fsPath.data = fsNameBuf;
|
||||||
|
|
||||||
|
char *comma = strchr(ctx->commandData, ',');
|
||||||
|
if (comma == NULL)
|
||||||
|
return GDB_ReplyErrno(ctx, EILSEQ);
|
||||||
|
|
||||||
|
*comma = 0;
|
||||||
|
char *fileName = ctx->commandData;
|
||||||
|
|
||||||
|
u32 args[2] = {0};
|
||||||
|
if (GDB_ParseHexIntegerList(args, comma + 1, 2, 0) == NULL)
|
||||||
|
return GDB_ReplyErrno(ctx, EILSEQ);
|
||||||
|
int flags = (int)args[1];
|
||||||
|
IFile f = {0};
|
||||||
|
u32 fsFlags = 0;
|
||||||
|
|
||||||
|
if (ctx->numOpenTioFiles >= MAX_TIO_OPEN_FILE)
|
||||||
|
return GDB_TioReplyErrno(ctx, GDBHIO_EMFILE);
|
||||||
|
|
||||||
|
int err = GDB_MakeUtf16Path(&fsPath, fileName);
|
||||||
|
if (err != 0)
|
||||||
|
return GDB_TioReplyErrno(ctx, err);
|
||||||
|
|
||||||
|
switch (flags & GDBHIO_O_ACCMODE)
|
||||||
|
{
|
||||||
|
case GDBHIO_O_RDONLY:
|
||||||
|
fsFlags |= FS_OPEN_READ;
|
||||||
|
if (flags & GDBHIO_O_APPEND) err = GDBHIO_EINVAL;
|
||||||
|
break;
|
||||||
|
case GDBHIO_O_WRONLY:
|
||||||
|
fsFlags |= FS_OPEN_WRITE;
|
||||||
|
break;
|
||||||
|
case GDBHIO_O_RDWR:
|
||||||
|
fsFlags |= FS_OPEN_READ | FS_OPEN_WRITE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
err = GDBHIO_EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & GDBHIO_O_CREAT)
|
||||||
|
fsFlags |= FS_OPEN_CREATE;
|
||||||
|
|
||||||
|
if (err != 0)
|
||||||
|
return GDB_TioReplyErrno(ctx, err);
|
||||||
|
|
||||||
|
if ((flags & O_CREAT) && (flags & O_EXCL))
|
||||||
|
{
|
||||||
|
err = GDB_TioConvertResult(FSUSER_CreateFile(archiveId, fsPath, 0, 0));
|
||||||
|
if (err != 0)
|
||||||
|
return GDB_TioReplyErrno(ctx, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
err = GDB_TioConvertResult(IFile_Open(&f, archiveId, fsPath, fsMakePath(PATH_EMPTY, ""), fsFlags));
|
||||||
|
if (err != 0)
|
||||||
|
return GDB_TioReplyErrno(ctx, err);
|
||||||
|
|
||||||
|
if((flags & GDBHIO_O_ACCMODE) != GDBHIO_O_RDONLY && (flags & GDBHIO_O_TRUNC))
|
||||||
|
{
|
||||||
|
f.size = 0;
|
||||||
|
err = GDB_TioConvertResult(FSFILE_SetSize(f.handle, 0));
|
||||||
|
if (err != 0)
|
||||||
|
{
|
||||||
|
IFile_Close(&f);
|
||||||
|
return GDB_TioReplyErrno(ctx, err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int fd = GDB_TioRegisterFile(ctx, f.handle, flags & (GDBHIO_O_ACCMODE | GDBHIO_O_APPEND));
|
||||||
|
if (fd < 0)
|
||||||
|
return GDB_TioReplyErrno(ctx, GDBHIO_EMFILE);
|
||||||
|
|
||||||
|
return GDB_SendFormattedPacket(ctx, "F%lx", (u32)fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
GDB_DECLARE_TIO_HANDLER(Close)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
if (GDB_ParseHexIntegerList((u32 *)&fd, ctx->commandData, 1, 0) == NULL)
|
||||||
|
return GDB_ReplyErrno(ctx, EILSEQ);
|
||||||
|
|
||||||
|
GdbTioFileInfo *fi = GDB_TioConvertFd(ctx, fd);
|
||||||
|
if (fi == NULL)
|
||||||
|
return GDB_TioReplyErrno(ctx, GDBHIO_EBADF);
|
||||||
|
|
||||||
|
int err = GDB_TioConvertResult(IFile_Close(&fi->f));
|
||||||
|
memset(fi, 0, sizeof(GdbTioFileInfo));
|
||||||
|
|
||||||
|
if (err != 0)
|
||||||
|
return GDB_TioReplyErrno(ctx, err);
|
||||||
|
else
|
||||||
|
return GDB_SendPacket(ctx, "F0", 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
GDB_DECLARE_TIO_HANDLER(Read)
|
||||||
|
{
|
||||||
|
// "$F<num>;<data>#XX"
|
||||||
|
char buf2[GDB_BUF_LEN - 4];
|
||||||
|
u8 buf[sizeof(buf2) - 2 - 8];
|
||||||
|
|
||||||
|
u32 args[3];
|
||||||
|
if (GDB_ParseHexIntegerList(args, ctx->commandData, 3, 0) == NULL)
|
||||||
|
return GDB_ReplyErrno(ctx, EILSEQ);
|
||||||
|
|
||||||
|
u64 numRead = 0;
|
||||||
|
int fd = (int)args[0];
|
||||||
|
u32 count = args[1] > sizeof(buf) ? sizeof(buf) : args[1];
|
||||||
|
u32 offset = args[2];
|
||||||
|
|
||||||
|
GdbTioFileInfo *fi = GDB_TioConvertFd(ctx, fd);
|
||||||
|
if (fi == NULL)
|
||||||
|
return GDB_TioReplyErrno(ctx, GDBHIO_EBADF);
|
||||||
|
|
||||||
|
fi->f.pos = offset;
|
||||||
|
|
||||||
|
int err = GDB_TioConvertResult(IFile_Read(&fi->f, &numRead, buf, count));
|
||||||
|
if (err != 0)
|
||||||
|
return GDB_TioReplyErrno(ctx, err);
|
||||||
|
|
||||||
|
int pos = sprintf(buf2, "F%lx;", (u32)numRead);
|
||||||
|
u32 actualCount = GDB_EscapeBinaryData(buf2 + pos, buf, (u32)numRead, sizeof(buf));
|
||||||
|
|
||||||
|
return GDB_SendPacket(ctx, buf2, pos + actualCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
GDB_DECLARE_TIO_HANDLER(Write)
|
||||||
|
{
|
||||||
|
u8 buf[GDB_BUF_LEN];
|
||||||
|
u32 args[2];
|
||||||
|
const char *comma = GDB_ParseHexIntegerList(args, ctx->commandData, 2, ',');
|
||||||
|
if (comma == NULL)
|
||||||
|
return GDB_ReplyErrno(ctx, EILSEQ);
|
||||||
|
|
||||||
|
int fd = (int)args[0];
|
||||||
|
u32 offset = args[1];
|
||||||
|
const char *escData = comma + 1;
|
||||||
|
|
||||||
|
u32 count = GDB_UnescapeBinaryData(buf, escData, ctx->commandEnd - escData);
|
||||||
|
|
||||||
|
GdbTioFileInfo *fi = GDB_TioConvertFd(ctx, fd);
|
||||||
|
if (fi == NULL)
|
||||||
|
return GDB_TioReplyErrno(ctx, GDBHIO_EBADF);
|
||||||
|
|
||||||
|
fi->f.pos = offset;
|
||||||
|
|
||||||
|
|
||||||
|
u64 written;
|
||||||
|
int err = GDB_TioConvertResult(IFile_Write(&fi->f, &written, buf, count, 0));
|
||||||
|
if (err != 0)
|
||||||
|
return GDB_TioReplyErrno(ctx, err);
|
||||||
|
else
|
||||||
|
return GDB_SendFormattedPacket(ctx, "F%lx", (u32)written);
|
||||||
|
}
|
||||||
|
|
||||||
|
GDB_DECLARE_TIO_HANDLER(Stat)
|
||||||
|
{
|
||||||
|
char *fileName = ctx->commandData;
|
||||||
|
if (*fileName == 0)
|
||||||
|
return GDB_ReplyErrno(ctx, EILSEQ);
|
||||||
|
|
||||||
|
s64 out = 1;
|
||||||
|
svcGetSystemInfo(&out, 0x10000, 0x203);
|
||||||
|
bool isSdMode = (bool)out;
|
||||||
|
FS_ArchiveID archiveId = isSdMode ? ARCHIVE_SDMC : ARCHIVE_NAND_RW;
|
||||||
|
u16 fsNameBuf[PATH_MAX + 1];
|
||||||
|
FS_Path fsPath;
|
||||||
|
fsPath.data = fsNameBuf;
|
||||||
|
|
||||||
|
int err = GDB_MakeUtf16Path(&fsPath, fileName);
|
||||||
|
if (err != 0)
|
||||||
|
return GDB_TioReplyErrno(ctx, err);
|
||||||
|
|
||||||
|
Handle fileHandle;
|
||||||
|
Handle dirHandle;
|
||||||
|
FS_Archive ar;
|
||||||
|
err = GDB_TioConvertResult(FSUSER_OpenArchive(&ar, archiveId, fsMakePath(PATH_EMPTY, "")));
|
||||||
|
if (err != 0)
|
||||||
|
return GDB_TioReplyErrno(ctx, err);
|
||||||
|
|
||||||
|
struct gdbhio_stat gdbSt = {0};
|
||||||
|
err = GDB_TioConvertResult(FSUSER_OpenFile(&fileHandle, ar, fsPath, FS_OPEN_READ, 0));
|
||||||
|
if (err == 0)
|
||||||
|
{
|
||||||
|
u64 size = 0;
|
||||||
|
err = GDB_TioConvertResult(FSFILE_GetSize(fileHandle, &size));
|
||||||
|
FSFILE_Close(fileHandle);
|
||||||
|
|
||||||
|
if (err == 0)
|
||||||
|
{
|
||||||
|
gdbSt.st_nlink = 1;
|
||||||
|
gdbSt.st_mode = GDBHIO_S_IFREG | GDBHIO_S_IRUSR | GDBHIO_S_IWUSR |
|
||||||
|
GDBHIO_S_IRGRP | GDBHIO_S_IWGRP | GDBHIO_S_IROTH | GDBHIO_S_IWOTH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
err = GDB_TioConvertResult(FSUSER_OpenDirectory(&dirHandle, ar, fsPath));
|
||||||
|
if (err == 0)
|
||||||
|
{
|
||||||
|
FSDIR_Close(dirHandle);
|
||||||
|
gdbSt.st_nlink = 1;
|
||||||
|
gdbSt.st_mode = GDBHIO_S_IFDIR | GDBHIO_S_IRWXU | GDBHIO_S_IRWXG | GDBHIO_S_IRWXO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FSUSER_CloseArchive(ar);
|
||||||
|
|
||||||
|
if (err != 0)
|
||||||
|
return GDB_TioReplyErrno(ctx, err);
|
||||||
|
|
||||||
|
struct gdbhio_stat gdbStFinal;
|
||||||
|
GDB_TioMakeStructStat(&gdbStFinal, &gdbSt);
|
||||||
|
|
||||||
|
char buf[3 + 2 * sizeof(struct gdbhio_stat)] = "F0;";
|
||||||
|
u32 actualCount = GDB_EscapeBinaryData(buf + 3, buf, sizeof(struct gdbhio_stat), 2 * sizeof(struct gdbhio_stat));
|
||||||
|
|
||||||
|
return GDB_SendPacket(ctx, buf, 3 + actualCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
GDB_DECLARE_TIO_HANDLER(Unlink)
|
||||||
|
{
|
||||||
|
char *fileName = ctx->commandData;
|
||||||
|
if (*fileName == 0)
|
||||||
|
return GDB_ReplyErrno(ctx, EILSEQ);
|
||||||
|
|
||||||
|
s64 out = 1;
|
||||||
|
svcGetSystemInfo(&out, 0x10000, 0x203);
|
||||||
|
bool isSdMode = (bool)out;
|
||||||
|
FS_ArchiveID archiveId = isSdMode ? ARCHIVE_SDMC : ARCHIVE_NAND_RW;
|
||||||
|
u16 fsNameBuf[PATH_MAX + 1];
|
||||||
|
FS_Path fsPath;
|
||||||
|
fsPath.data = fsNameBuf;
|
||||||
|
|
||||||
|
int err = GDB_MakeUtf16Path(&fsPath, fileName);
|
||||||
|
if (err != 0)
|
||||||
|
return GDB_TioReplyErrno(ctx, err);
|
||||||
|
|
||||||
|
err = GDB_TioConvertResult(FSUSER_DeleteFile(archiveId, fsPath));
|
||||||
|
if (err != 0)
|
||||||
|
return GDB_TioReplyErrno(ctx, err);
|
||||||
|
|
||||||
|
return GDB_SendPacket(ctx, "F0", 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
GDB_DECLARE_TIO_HANDLER(Readlink)
|
||||||
|
{
|
||||||
|
// Not really supported
|
||||||
|
char *fileName = ctx->commandData;
|
||||||
|
if (*fileName == 0)
|
||||||
|
return GDB_ReplyErrno(ctx, EILSEQ);
|
||||||
|
|
||||||
|
return GDB_SendPacket(ctx, "F0;", 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
GDB_DECLARE_TIO_HANDLER(Setfs)
|
||||||
|
{
|
||||||
|
// Largely ignored
|
||||||
|
u32 pid;
|
||||||
|
if (GDB_ParseHexIntegerList(&pid, ctx->commandData, 1, 0) == NULL)
|
||||||
|
return GDB_ReplyErrno(ctx, EILSEQ);
|
||||||
|
return GDB_SendPacket(ctx, "F0", 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct
|
||||||
|
{
|
||||||
|
const char *name;
|
||||||
|
GDBCommandHandler handler;
|
||||||
|
} gdbTioCommandHandlers[] =
|
||||||
|
{
|
||||||
|
{ "open", GDB_TIO_HANDLER(Open) },
|
||||||
|
{ "close", GDB_TIO_HANDLER(Close) },
|
||||||
|
{ "pread", GDB_TIO_HANDLER(Read) },
|
||||||
|
{ "pwrite", GDB_TIO_HANDLER(Write) },
|
||||||
|
{ "fstat", GDB_TIO_HANDLER(Stat) },
|
||||||
|
{ "unlink", GDB_TIO_HANDLER(Unlink) },
|
||||||
|
{ "readlink", GDB_TIO_HANDLER(Readlink) },
|
||||||
|
{ "setfs", GDB_TIO_HANDLER(Setfs) },
|
||||||
|
};
|
||||||
|
|
||||||
|
GDB_DECLARE_VERBOSE_HANDLER(File)
|
||||||
|
{
|
||||||
|
if (*ctx->commandData == 0)
|
||||||
|
return GDB_ReplyErrno(ctx, EILSEQ);
|
||||||
|
|
||||||
|
char *colon = strchr(ctx->commandData, ':');
|
||||||
|
if (colon == NULL)
|
||||||
|
return GDB_ReplyErrno(ctx, EILSEQ);
|
||||||
|
|
||||||
|
*colon = 0;
|
||||||
|
|
||||||
|
for(u32 i = 0; i < sizeof(gdbTioCommandHandlers) / sizeof(gdbTioCommandHandlers[0]); i++)
|
||||||
|
{
|
||||||
|
if(strcmp(gdbTioCommandHandlers[i].name, ctx->commandData) == 0)
|
||||||
|
{
|
||||||
|
ctx->commandData = colon + 1;
|
||||||
|
return gdbTioCommandHandlers[i].handler(ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return GDB_HandleUnsupported(ctx); // No handler found!
|
||||||
|
}
|
@ -27,6 +27,7 @@
|
|||||||
#include "gdb/verbose.h"
|
#include "gdb/verbose.h"
|
||||||
#include "gdb/net.h"
|
#include "gdb/net.h"
|
||||||
#include "gdb/debug.h"
|
#include "gdb/debug.h"
|
||||||
|
#include "gdb/tio.h"
|
||||||
|
|
||||||
static const struct
|
static const struct
|
||||||
{
|
{
|
||||||
@ -37,6 +38,7 @@ static const struct
|
|||||||
{ "Attach", GDB_VERBOSE_HANDLER(Attach) },
|
{ "Attach", GDB_VERBOSE_HANDLER(Attach) },
|
||||||
{ "Cont?", GDB_VERBOSE_HANDLER(ContinueSupported) },
|
{ "Cont?", GDB_VERBOSE_HANDLER(ContinueSupported) },
|
||||||
{ "Cont", GDB_VERBOSE_HANDLER(Continue) },
|
{ "Cont", GDB_VERBOSE_HANDLER(Continue) },
|
||||||
|
{ "File", GDB_VERBOSE_HANDLER(File) },
|
||||||
{ "MustReplyEmpty", GDB_HANDLER(Unsupported) },
|
{ "MustReplyEmpty", GDB_HANDLER(Unsupported) },
|
||||||
{ "Run", GDB_VERBOSE_HANDLER(Run) },
|
{ "Run", GDB_VERBOSE_HANDLER(Run) },
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user