diff --git a/sysmodules/rosalina/include/gdb.h b/sysmodules/rosalina/include/gdb.h index e21c41e..2c36288 100644 --- a/sysmodules/rosalina/include/gdb.h +++ b/sysmodules/rosalina/include/gdb.h @@ -33,10 +33,14 @@ #include "pmdbgext.h" #include "sock_util.h" #include "memory.h" +#include "ifile.h" #define MAX_DEBUG 3 #define MAX_DEBUG_THREAD 127 #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 $#, see below. // IDA seems to want additional bytes as well. // 1024 is fine enough to put all regs in the 'T' stop reply packets @@ -76,6 +80,12 @@ typedef struct PackedGdbHioRequest bool ctrlC; } PackedGdbHioRequest; +typedef struct GdbTioFileInfo +{ + IFile f; + int flags; +} GdbTioFileInfo; + enum { GDB_FLAG_SELECTED = 1, @@ -149,6 +159,9 @@ typedef struct GDBContext u32 currentHioRequestTargetAddr; PackedGdbHioRequest currentHioRequest; + GdbTioFileInfo openTioFileInfos[MAX_TIO_OPEN_FILE]; + u32 numOpenTioFiles; + bool enableExternalMemoryAccess; char *commandData, *commandEnd; int latestSentPacketSize; diff --git a/sysmodules/rosalina/include/gdb/net.h b/sysmodules/rosalina/include/gdb/net.h index d7e05a8..10a950b 100644 --- a/sysmodules/rosalina/include/gdb/net.h +++ b/sysmodules/rosalina/include/gdb/net.h @@ -33,6 +33,7 @@ u8 GDB_ComputeChecksum(const char *packetData, u32 len); void GDB_EncodeHex(char *dst, const void *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); 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); diff --git a/sysmodules/rosalina/include/gdb/tio.h b/sysmodules/rosalina/include/gdb/tio.h new file mode 100644 index 0000000..8bed00f --- /dev/null +++ b/sysmodules/rosalina/include/gdb/tio.h @@ -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 . +* +* 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); diff --git a/sysmodules/rosalina/source/gdb/hio.c b/sysmodules/rosalina/source/gdb/hio.c index 616ba97..1af0255 100644 --- a/sysmodules/rosalina/source/gdb/hio.c +++ b/sysmodules/rosalina/source/gdb/hio.c @@ -26,7 +26,6 @@ #include -#include "gdb.h" #include "gdb/hio.h" #include "gdb/net.h" #include "gdb/mem.h" diff --git a/sysmodules/rosalina/source/gdb/net.c b/sysmodules/rosalina/source/gdb/net.c index 6c371ee..3dda8b2 100644 --- a/sysmodules/rosalina/source/gdb/net.c +++ b/sysmodules/rosalina/source/gdb/net.c @@ -75,6 +75,25 @@ u32 GDB_DecodeHex(void *dst, const char *src, u32 len) 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) { u8 *dst8 = (u8 *)dst; diff --git a/sysmodules/rosalina/source/gdb/server.c b/sysmodules/rosalina/source/gdb/server.c index ed00161..9577b11 100644 --- a/sysmodules/rosalina/source/gdb/server.c +++ b/sysmodules/rosalina/source/gdb/server.c @@ -215,6 +215,11 @@ int GDB_CloseClient(GDBContext *ctx) memset(ctx->memoryOsInfoXmlData, 0, sizeof(ctx->memoryOsInfoXmlData)); 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); return 0; } diff --git a/sysmodules/rosalina/source/gdb/tio.c b/sysmodules/rosalina/source/gdb/tio.c new file mode 100644 index 0000000..06beebd --- /dev/null +++ b/sysmodules/rosalina/source/gdb/tio.c @@ -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 . +* +* 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 + +#include "gdb/tio.h" +#include "gdb/hio.h" +#include "gdb/net.h" +#include "gdb/mem.h" +#include "gdb/debug.h" +#include "fmt.h" + +#include +#include + +#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;#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! +} \ No newline at end of file diff --git a/sysmodules/rosalina/source/gdb/verbose.c b/sysmodules/rosalina/source/gdb/verbose.c index 0822d2f..ac6fddc 100644 --- a/sysmodules/rosalina/source/gdb/verbose.c +++ b/sysmodules/rosalina/source/gdb/verbose.c @@ -27,6 +27,7 @@ #include "gdb/verbose.h" #include "gdb/net.h" #include "gdb/debug.h" +#include "gdb/tio.h" static const struct { @@ -37,6 +38,7 @@ static const struct { "Attach", GDB_VERBOSE_HANDLER(Attach) }, { "Cont?", GDB_VERBOSE_HANDLER(ContinueSupported) }, { "Cont", GDB_VERBOSE_HANDLER(Continue) }, + { "File", GDB_VERBOSE_HANDLER(File) }, { "MustReplyEmpty", GDB_HANDLER(Unsupported) }, { "Run", GDB_VERBOSE_HANDLER(Run) }, };