Implement Luma3DS gdb hio (#433)
This commit is contained in:
parent
754c334c29
commit
ed7674626e
@ -91,6 +91,8 @@ extern "C" {
|
||||
#include <3ds/font.h>
|
||||
#include <3ds/mii.h>
|
||||
|
||||
#include <3ds/gdbhio_dev.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
29
libctru/include/3ds/gdbhio.h
Normal file
29
libctru/include/3ds/gdbhio.h
Normal file
@ -0,0 +1,29 @@
|
||||
/**
|
||||
* @file gdbhio.h
|
||||
* @brief Luma3DS GDB HIO (called File I/O in GDB documentation) functions.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define GDBHIO_STDIN_FILENO 0
|
||||
#define GDBHIO_STDOUT_FILENO 1
|
||||
#define GDBHIO_STDERR_FILENO 2
|
||||
|
||||
int gdbHioOpen(const char *pathname, int flags, mode_t mode);
|
||||
int gdbHioClose(int fd);
|
||||
int gdbHioRead(int fd, void *buf, unsigned int count);
|
||||
int gdbHioWrite(int fd, const void *buf, unsigned int count);
|
||||
off_t gdbHioLseek(int fd, off_t offset, int flag);
|
||||
int gdbHioRename(const char *oldpath, const char *newpath);
|
||||
int gdbHioUnlink(const char *pathname);
|
||||
int gdbHioStat(const char *pathname, struct stat *st);
|
||||
int gdbHioFstat(int fd, struct stat *st);
|
||||
int gdbHioGettimeofday(struct timeval *tv, void *tz);
|
||||
int gdbHioIsatty(int fd);
|
||||
|
||||
///< Host I/O 'system' function, requires 'set remote system-call-allowed 1'.
|
||||
int gdbHioSystem(const char *command);
|
37
libctru/include/3ds/gdbhio_dev.h
Normal file
37
libctru/include/3ds/gdbhio_dev.h
Normal file
@ -0,0 +1,37 @@
|
||||
/**
|
||||
* @file gdbhio_dev.h
|
||||
* @brief Luma3DS GDB HIO (called File I/O in GDB documentation) devoptab wrapper.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
struct timeval;
|
||||
|
||||
///< Initializes the GDB HIO devoptab wrapper, returns 0 on success, -1 on failure.
|
||||
int gdbHioDevInit(void);
|
||||
|
||||
///< Deinitializes the GDB HIO devoptab wrapper.
|
||||
void gdbHioDevExit(void);
|
||||
|
||||
///< Returns a file descriptor mapping to the GDB client console's standard input stream.
|
||||
int gdbHioDevGetStdin(void);
|
||||
|
||||
///< Returns a file descriptor mapping to the GDB client console's standard output stream.
|
||||
int gdbHioDevGetStdout(void);
|
||||
|
||||
///< Returns a file descriptor mapping to the GDB client console's standard error stream.
|
||||
int gdbHioDevGetStderr(void);
|
||||
|
||||
///< Redirects 0 to 3 of the application's standard streams to GDB client console's. Returns -1, -2, or -3, resp., on failure; 0 on success.
|
||||
int gdbHioDevRedirectStdStreams(bool in, bool out, bool err);
|
||||
|
||||
///< GDB HIO POSIX function gettimeofday.
|
||||
int gdbHioDevGettimeofday(struct timeval *tv, void *tz);
|
||||
|
||||
///< GDB HIO POSIX function isatty.
|
||||
int gdbHioDevIsatty(int fd);
|
||||
|
||||
///< GDB HIO POSIX function system. Requires 'set remote system-call-allowed 1'.
|
||||
int gdbHioDevSystem(const char *command);
|
403
libctru/source/gdbhio.c
Normal file
403
libctru/source/gdbhio.c
Normal file
@ -0,0 +1,403 @@
|
||||
#include <3ds/gdbhio.h>
|
||||
|
||||
#include <3ds/svc.h>
|
||||
#include <3ds/result.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.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 (GDBHIO_S_IRUSR | GDBHIO_S_IWUSR | GDBHIO_S_IXUSR)
|
||||
#define GDBHIO_S_IRGRP 040
|
||||
#define GDBHIO_S_IWGRP 020
|
||||
#define GDBHIO_S_IXGRP 010
|
||||
#define GDBHIO_S_IRWXG (GDBHIO_S_IRGRP | GDBHIO_S_IWGRP | GDBHIO_S_IXGRP)
|
||||
#define GDBHIO_S_IROTH 04
|
||||
#define GDBHIO_S_IWOTH 02
|
||||
#define GDBHIO_S_IXOTH 01
|
||||
#define GDBHIO_S_IRWXO (GDBHIO_S_IROTH | GDBHIO_S_IWOTH | GDBHIO_S_IXOTH)
|
||||
#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
|
||||
|
||||
typedef struct PackedGdbHioRequest
|
||||
{
|
||||
char magic[4]; // "GDB\x00"
|
||||
u32 version;
|
||||
|
||||
// Request
|
||||
char functionName[16+1];
|
||||
char paramFormat[8+1];
|
||||
|
||||
u64 parameters[8];
|
||||
size_t stringLengths[8];
|
||||
|
||||
// Return
|
||||
s64 retval;
|
||||
int gdbErrno;
|
||||
bool ctrlC;
|
||||
} PackedGdbHioRequest;
|
||||
|
||||
static __thread bool g_gdbHioWasInterruptedByCtrlC = false;
|
||||
|
||||
bool gdbHioWasInterruptedByCtrlC(void)
|
||||
{
|
||||
return g_gdbHioWasInterruptedByCtrlC;
|
||||
}
|
||||
|
||||
static int _gdbHioImportErrno(int errnum)
|
||||
{
|
||||
switch (errnum) {
|
||||
case GDBHIO_EPERM: return EPERM;
|
||||
case GDBHIO_ENOENT: return ENOENT;
|
||||
case GDBHIO_EINTR: return EINTR;
|
||||
case GDBHIO_EIO: return EIO;
|
||||
case GDBHIO_EBADF: return EBADF;
|
||||
case GDBHIO_EACCES: return EACCES;
|
||||
case GDBHIO_EFAULT: return EFAULT;
|
||||
case GDBHIO_EBUSY: return EBUSY;
|
||||
case GDBHIO_EEXIST: return EEXIST;
|
||||
case GDBHIO_ENODEV: return ENODEV;
|
||||
case GDBHIO_ENOTDIR: return ENOTDIR;
|
||||
case GDBHIO_EISDIR: return EISDIR;
|
||||
case GDBHIO_EINVAL: return EINVAL;
|
||||
case GDBHIO_ENFILE: return ENFILE;
|
||||
case GDBHIO_EMFILE: return EMFILE;
|
||||
case GDBHIO_EFBIG: return EFBIG;
|
||||
case GDBHIO_ENOSPC: return ENOSPC;
|
||||
case GDBHIO_ESPIPE: return ESPIPE;
|
||||
case GDBHIO_EROFS: return EROFS;
|
||||
case GDBHIO_ENOSYS: return ENOSYS;
|
||||
case GDBHIO_ENAMETOOLONG: return ENAMETOOLONG;
|
||||
default: return EPIPE;
|
||||
}
|
||||
}
|
||||
|
||||
static int _gdbHioExportOpenFlags(int flags)
|
||||
{
|
||||
int outflags = 0;
|
||||
if (flags & O_CREAT) outflags |= GDBHIO_O_CREAT;
|
||||
if (flags & O_EXCL) outflags |= GDBHIO_O_EXCL;
|
||||
if (flags & O_TRUNC) outflags |= GDBHIO_O_TRUNC;
|
||||
if (flags & O_APPEND) outflags |= GDBHIO_O_APPEND;
|
||||
|
||||
switch (flags & O_ACCMODE) {
|
||||
case O_RDONLY:
|
||||
outflags |= GDBHIO_O_RDONLY;
|
||||
break;
|
||||
case O_WRONLY:
|
||||
outflags |= GDBHIO_O_WRONLY;
|
||||
break;
|
||||
case O_RDWR:
|
||||
outflags |= GDBHIO_O_RDWR;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Note: O_BINARY is implicit if the host supports it
|
||||
|
||||
return outflags;
|
||||
}
|
||||
|
||||
typedef s32 gdbhio_mode_t;
|
||||
|
||||
static mode_t _gdbHioImportFileMode(gdbhio_mode_t gdbMode)
|
||||
{
|
||||
mode_t mode = 0;
|
||||
if (mode & ~GDBHIO_S_SUPPORTED) return -1;
|
||||
|
||||
if (gdbMode & GDBHIO_S_IFREG) mode |= S_IFREG;
|
||||
if (gdbMode & GDBHIO_S_IFDIR) mode |= S_IFDIR;
|
||||
if (gdbMode & GDBHIO_S_IFCHR) mode |= S_IFCHR;
|
||||
if (gdbMode & GDBHIO_S_IRUSR) mode |= S_IRUSR;
|
||||
if (gdbMode & GDBHIO_S_IWUSR) mode |= S_IWUSR;
|
||||
if (gdbMode & GDBHIO_S_IXUSR) mode |= S_IXUSR;
|
||||
if (gdbMode & GDBHIO_S_IRGRP) mode |= S_IRGRP;
|
||||
if (gdbMode & GDBHIO_S_IWGRP) mode |= S_IWGRP;
|
||||
if (gdbMode & GDBHIO_S_IXGRP) mode |= S_IXGRP;
|
||||
if (gdbMode & GDBHIO_S_IROTH) mode |= S_IROTH;
|
||||
if (gdbMode & GDBHIO_S_IWOTH) mode |= S_IWOTH;
|
||||
if (gdbMode & GDBHIO_S_IXOTH) mode |= S_IXOTH;
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
static int _gdbHioExportFileMode(mode_t mode)
|
||||
{
|
||||
gdbhio_mode_t gdbMode = 0;
|
||||
if (mode & ~GDBHIO_S_SUPPORTED) return -1;
|
||||
|
||||
if (mode & S_IFREG) gdbMode |= GDBHIO_S_IFREG;
|
||||
if (mode & S_IFDIR) gdbMode |= GDBHIO_S_IFDIR;
|
||||
if (mode & S_IFCHR) gdbMode |= GDBHIO_S_IFCHR;
|
||||
if (mode & S_IRUSR) gdbMode |= GDBHIO_S_IRUSR;
|
||||
if (mode & S_IWUSR) gdbMode |= GDBHIO_S_IWUSR;
|
||||
if (mode & S_IXUSR) gdbMode |= GDBHIO_S_IXUSR;
|
||||
if (mode & S_IRGRP) gdbMode |= GDBHIO_S_IRGRP;
|
||||
if (mode & S_IWGRP) gdbMode |= GDBHIO_S_IWGRP;
|
||||
if (mode & S_IXGRP) gdbMode |= GDBHIO_S_IXGRP;
|
||||
if (mode & S_IROTH) gdbMode |= GDBHIO_S_IROTH;
|
||||
if (mode & S_IWOTH) gdbMode |= GDBHIO_S_IWOTH;
|
||||
if (mode & S_IXOTH) gdbMode |= GDBHIO_S_IXOTH;
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
|
||||
static int _gdbExportSeekFlag(int flag)
|
||||
{
|
||||
switch (flag) {
|
||||
case SEEK_SET: return GDBHIO_SEEK_SET;
|
||||
case SEEK_CUR: return GDBHIO_SEEK_CUR;
|
||||
case SEEK_END: return GDBHIO_SEEK_END;
|
||||
default: return GDBHIO_SEEK_SET;
|
||||
}
|
||||
}
|
||||
// https://sourceware.org/gdb/onlinedocs/gdb/struct-stat.html#struct-stat
|
||||
typedef u32 gdbhio_time_t;
|
||||
|
||||
struct PACKED ALIGN(4) gdbhio_stat {
|
||||
u32 st_dev; /* device */
|
||||
u32 st_ino; /* inode */
|
||||
gdbhio_mode_t st_mode; /* protection */
|
||||
u32 st_nlink; /* number of hard links */
|
||||
u32 st_uid; /* user ID of owner */
|
||||
u32 st_gid; /* group ID of owner */
|
||||
u32 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 inline u32 _gdbHioImportScalar32(u32 v)
|
||||
{
|
||||
return __builtin_bswap32(v);
|
||||
}
|
||||
|
||||
static inline u64 _gdbHioImportScalar64(u64 v)
|
||||
{
|
||||
return __builtin_bswap64(v);
|
||||
}
|
||||
|
||||
static void _gdbHioImportStructStat(struct stat *out, const struct gdbhio_stat *in)
|
||||
{
|
||||
memset(out, 0, sizeof(struct stat));
|
||||
out->st_dev = _gdbHioImportScalar32(in->st_dev);
|
||||
out->st_ino = _gdbHioImportScalar32(in->st_ino);
|
||||
out->st_mode = _gdbHioImportFileMode(_gdbHioImportScalar32(in->st_mode));
|
||||
out->st_nlink = _gdbHioImportScalar32(in->st_nlink);
|
||||
out->st_uid = _gdbHioImportScalar32(in->st_uid);
|
||||
out->st_gid = _gdbHioImportScalar32(in->st_gid);
|
||||
out->st_rdev = _gdbHioImportScalar32(in->st_rdev);
|
||||
out->st_size = (off_t)_gdbHioImportScalar64(in->st_size);
|
||||
out->st_blksize = (blksize_t)_gdbHioImportScalar64(in->st_blksize);
|
||||
out->st_blocks = (blkcnt_t)_gdbHioImportScalar64(in->st_blocks);
|
||||
out->st_atime = _gdbHioImportScalar32(in->st_atime);
|
||||
out->st_mtime = _gdbHioImportScalar32(in->st_mtime);
|
||||
out->st_ctime = _gdbHioImportScalar32(in->st_ctime);
|
||||
}
|
||||
|
||||
struct gdbhio_timeval {
|
||||
gdbhio_time_t tv_sec; /* second */
|
||||
u64 tv_usec; /* microsecond */
|
||||
};
|
||||
|
||||
static void _gdbHioImportStructTimeval(struct timeval *out, const struct gdbhio_timeval *in)
|
||||
{
|
||||
out->tv_sec = _gdbHioImportScalar32(in->tv_sec);
|
||||
out->tv_usec = _gdbHioImportScalar64(in->tv_usec);
|
||||
}
|
||||
|
||||
static void _gdbHioSetErrno(int gdbErrno, bool ctrlC)
|
||||
{
|
||||
if (gdbErrno != 0) {
|
||||
errno = _gdbHioImportErrno(gdbErrno);
|
||||
}
|
||||
g_gdbHioWasInterruptedByCtrlC = ctrlC;
|
||||
}
|
||||
|
||||
static s64 _gdbHioSendSyncRequest64V(const char *name, const char *paramFormat, va_list args)
|
||||
{
|
||||
PackedGdbHioRequest req = {{0}};
|
||||
memcpy(req.magic, "GDB", 4);
|
||||
strncpy(req.functionName, name, 16);
|
||||
strncpy(req.paramFormat, paramFormat, 8);
|
||||
|
||||
u32 numStrs = 0;
|
||||
const char *str;
|
||||
|
||||
for (u32 i = 0; i < 8 && paramFormat[i] != 0; i++) {
|
||||
switch (paramFormat[i]) {
|
||||
case 'i':
|
||||
case 'I':
|
||||
req.parameters[i] = va_arg(args, u32);
|
||||
break;
|
||||
case 'l':
|
||||
case 'L':
|
||||
req.parameters[i] = va_arg(args, u64);
|
||||
break;
|
||||
case 'p':
|
||||
req.parameters[i] = va_arg(args, uintptr_t);
|
||||
break;
|
||||
case 's':
|
||||
str = va_arg(args, const char *);
|
||||
req.parameters[i] = (uintptr_t)str;
|
||||
req.stringLengths[numStrs++] = strlen(str)+1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (R_FAILED(svcOutputDebugString((const char *)&req, 0)) || req.paramFormat[0] != 0) {
|
||||
errno = EPIPE;
|
||||
g_gdbHioWasInterruptedByCtrlC = false;
|
||||
return -1;
|
||||
}
|
||||
|
||||
_gdbHioSetErrno(req.gdbErrno, req.ctrlC);
|
||||
return req.retval;
|
||||
}
|
||||
|
||||
static s64 _gdbHioSendSyncRequest64(const char *name, const char *paramFormat, ...)
|
||||
{
|
||||
s64 ret = 0;
|
||||
va_list args;
|
||||
va_start(args, paramFormat);
|
||||
ret = _gdbHioSendSyncRequest64V(name, paramFormat, args);
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _gdbHioSendSyncRequest(const char *name, const char *paramFormat, ...)
|
||||
{
|
||||
s64 ret = 0;
|
||||
va_list args;
|
||||
va_start(args, paramFormat);
|
||||
ret = _gdbHioSendSyncRequest64V(name, paramFormat, args);
|
||||
va_end(args);
|
||||
return (int)ret;
|
||||
}
|
||||
|
||||
int gdbHioOpen(const char *pathname, int flags, mode_t mode)
|
||||
{
|
||||
return _gdbHioSendSyncRequest("open", "siI", pathname, _gdbHioExportOpenFlags(flags), _gdbHioExportFileMode(mode));
|
||||
}
|
||||
|
||||
int gdbHioClose(int fd)
|
||||
{
|
||||
return _gdbHioSendSyncRequest("close", "i", fd);
|
||||
}
|
||||
|
||||
int gdbHioRead(int fd, void *buf, unsigned int count)
|
||||
{
|
||||
return _gdbHioSendSyncRequest("read", "ipI", fd, buf, count);
|
||||
}
|
||||
|
||||
int gdbHioWrite(int fd, const void *buf, unsigned int count)
|
||||
{
|
||||
return _gdbHioSendSyncRequest("write", "ipI", fd, buf, count);
|
||||
}
|
||||
|
||||
off_t gdbHioLseek(int fd, off_t offset, int flag)
|
||||
{
|
||||
return _gdbHioSendSyncRequest64("lseek", "ili", fd, offset, _gdbExportSeekFlag(flag));
|
||||
}
|
||||
|
||||
int gdbHioRename(const char *oldpath, const char *newpath)
|
||||
{
|
||||
return _gdbHioSendSyncRequest("rename", "ss", oldpath, newpath);
|
||||
}
|
||||
|
||||
int gdbHioUnlink(const char *pathname)
|
||||
{
|
||||
return _gdbHioSendSyncRequest("unlink", "s", pathname);
|
||||
}
|
||||
|
||||
int gdbHioStat(const char *pathname, struct stat *st)
|
||||
{
|
||||
struct gdbhio_stat gst;
|
||||
int ret = _gdbHioSendSyncRequest("stat", "sp", pathname, &gst);
|
||||
_gdbHioImportStructStat(st, &gst);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int gdbHioFstat(int fd, struct stat *st)
|
||||
{
|
||||
struct gdbhio_stat gst;
|
||||
int ret = _gdbHioSendSyncRequest("fstat", "ip", fd, &gst);
|
||||
_gdbHioImportStructStat(st, &gst);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int gdbHioGettimeofday(struct timeval *tv, void *tz)
|
||||
{
|
||||
// GDB ignores tz and passes NULL
|
||||
struct gdbhio_timeval gtv;
|
||||
int ret = _gdbHioSendSyncRequest("gettimeofday", "pp", >v, tz);
|
||||
_gdbHioImportStructTimeval(tv, >v);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int gdbHioIsatty(int fd)
|
||||
{
|
||||
return _gdbHioSendSyncRequest("isatty", "i", fd);
|
||||
}
|
||||
|
||||
// Requires set remote system-call-allowed 1
|
||||
int gdbHioSystem(const char *command)
|
||||
{
|
||||
return _gdbHioSendSyncRequest("system", "s", command);
|
||||
}
|
250
libctru/source/gdbhio_dev.c
Normal file
250
libctru/source/gdbhio_dev.c
Normal file
@ -0,0 +1,250 @@
|
||||
#include <3ds/gdbhio_dev.h>
|
||||
#include <3ds/gdbhio.h>
|
||||
|
||||
#include <sys/iosupport.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
static int g_gdbHioStdinFd = -1, g_gdbHioStdoutFd = -1, g_gdbHioStderrFd = -1;
|
||||
|
||||
static int _gdbHioGetFd(int fd)
|
||||
{
|
||||
__handle *handle = __get_handle(fd);
|
||||
if (handle == NULL) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(strcmp(devoptab_list[handle->device]->name, "gdbhio") != 0) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
return *(int *)handle->fileStruct;
|
||||
}
|
||||
|
||||
static inline int _gdbHioGetFdFromPtr(void *fdptr)
|
||||
{
|
||||
return *(int *)fdptr;
|
||||
}
|
||||
|
||||
static inline const char *_gdbHioSkipMountpoint(const char *pathname)
|
||||
{
|
||||
return strncmp(pathname, "gdbhio:", 7) == 0 ? pathname + 7 : pathname;
|
||||
}
|
||||
|
||||
static int _gdbHioDevOpen(struct _reent *r, void *fdptr, const char *pathname, int flags, int mode)
|
||||
{
|
||||
(void)r;
|
||||
|
||||
pathname = _gdbHioSkipMountpoint(pathname);
|
||||
int ret = gdbHioOpen(pathname, flags, mode);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
} else {
|
||||
*(int *)fdptr = ret;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int _gdbHioDevClose(struct _reent *r, void *fdptr)
|
||||
{
|
||||
(void)r;
|
||||
|
||||
int fd = _gdbHioGetFdFromPtr(fdptr);
|
||||
if (fd == g_gdbHioStdinFd)
|
||||
g_gdbHioStdinFd = -1;
|
||||
else if (fd == g_gdbHioStdoutFd)
|
||||
g_gdbHioStdoutFd = -1;
|
||||
else if (fd == g_gdbHioStderrFd)
|
||||
g_gdbHioStderrFd = -1;
|
||||
else
|
||||
return gdbHioClose(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t _gdbHioDevRead(struct _reent *r, void *fdptr, char *buf, size_t count)
|
||||
{
|
||||
(void)r;
|
||||
return gdbHioRead(_gdbHioGetFdFromPtr(fdptr), buf, (unsigned int)count);
|
||||
}
|
||||
|
||||
static ssize_t _gdbHioDevWrite(struct _reent *r, void *fdptr, const char *buf, size_t count)
|
||||
{
|
||||
(void)r;
|
||||
return gdbHioWrite(_gdbHioGetFdFromPtr(fdptr), buf, (unsigned int)count);
|
||||
}
|
||||
|
||||
static off_t _gdbHioDevLseek(struct _reent *r, void *fdptr, off_t offset, int flag)
|
||||
{
|
||||
(void)r;
|
||||
return gdbHioLseek(_gdbHioGetFdFromPtr(fdptr), offset, flag);
|
||||
}
|
||||
|
||||
static int _gdbHioDevRename(struct _reent *r, const char *oldpath, const char *newpath)
|
||||
{
|
||||
(void)r;
|
||||
return gdbHioRename(_gdbHioSkipMountpoint(oldpath), _gdbHioSkipMountpoint(newpath));
|
||||
}
|
||||
|
||||
static int _gdbHioDevUnlink(struct _reent *r, const char *pathname)
|
||||
{
|
||||
(void)r;
|
||||
return gdbHioUnlink(_gdbHioSkipMountpoint(pathname));
|
||||
}
|
||||
|
||||
static int _gdbHioDevStat(struct _reent *r, const char *pathname, struct stat *st)
|
||||
{
|
||||
(void)r;
|
||||
return gdbHioStat(_gdbHioSkipMountpoint(pathname), st);
|
||||
}
|
||||
|
||||
static int _gdbHioDevFstat(struct _reent *r, void *fdptr, struct stat *st)
|
||||
{
|
||||
(void)r;
|
||||
return gdbHioFstat(_gdbHioGetFdFromPtr(fdptr), st);
|
||||
}
|
||||
|
||||
static int _gdbHioDevImportFd(int gdbFd)
|
||||
{
|
||||
int fd, dev;
|
||||
|
||||
dev = FindDevice("gdbhio:");
|
||||
if(dev == -1)
|
||||
return -1;
|
||||
|
||||
fd = __alloc_handle(dev);
|
||||
if(fd == -1)
|
||||
return -1;
|
||||
|
||||
*(int *)__get_handle(fd)->fileStruct = gdbFd;
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static const devoptab_t g_gdbHioDevoptab = {
|
||||
.name = "gdbhio",
|
||||
.structSize = sizeof(int),
|
||||
.open_r = _gdbHioDevOpen,
|
||||
.close_r = _gdbHioDevClose,
|
||||
.write_r = _gdbHioDevWrite,
|
||||
.read_r = _gdbHioDevRead,
|
||||
.seek_r = _gdbHioDevLseek,
|
||||
.fstat_r = _gdbHioDevFstat,
|
||||
.stat_r = _gdbHioDevStat,
|
||||
.link_r = NULL,
|
||||
.unlink_r = _gdbHioDevUnlink,
|
||||
.chdir_r = NULL,
|
||||
.rename_r = _gdbHioDevRename,
|
||||
.mkdir_r = NULL,
|
||||
.dirStateSize = 0,
|
||||
.diropen_r = NULL,
|
||||
.dirreset_r = NULL,
|
||||
.dirnext_r = NULL,
|
||||
.dirclose_r = NULL,
|
||||
.statvfs_r = NULL,
|
||||
.ftruncate_r = NULL,
|
||||
.fsync_r = NULL,
|
||||
.deviceData = 0,
|
||||
.chmod_r = NULL,
|
||||
.fchmod_r = NULL,
|
||||
.rmdir_r = NULL,
|
||||
};
|
||||
|
||||
int gdbHioDevGettimeofday(struct timeval *tv, void *tz)
|
||||
{
|
||||
return gdbHioGettimeofday(tv, tz);
|
||||
}
|
||||
|
||||
int gdbHioDevIsatty(int fd)
|
||||
{
|
||||
return gdbHioIsatty(_gdbHioGetFd(fd));
|
||||
}
|
||||
|
||||
int gdbHioDevSystem(const char *command)
|
||||
{
|
||||
return gdbHioSystem(command);
|
||||
}
|
||||
|
||||
int gdbHioDevInit(void)
|
||||
{
|
||||
int dev = FindDevice("gdbhio:");
|
||||
if (dev >= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
dev = AddDevice(&g_gdbHioDevoptab);
|
||||
if (dev < 0) return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void gdbHioDevExit(void)
|
||||
{
|
||||
close(g_gdbHioStdinFd);
|
||||
close(g_gdbHioStdoutFd);
|
||||
close(g_gdbHioStderrFd);
|
||||
RemoveDevice("gdbhio:");
|
||||
}
|
||||
|
||||
int gdbHioDevGetStdin(void)
|
||||
{
|
||||
if (g_gdbHioStdinFd < 0)
|
||||
g_gdbHioStdinFd = _gdbHioDevImportFd(GDBHIO_STDIN_FILENO);
|
||||
|
||||
return g_gdbHioStdinFd;
|
||||
}
|
||||
|
||||
int gdbHioDevGetStdout(void)
|
||||
{
|
||||
if (g_gdbHioStdoutFd < 0)
|
||||
g_gdbHioStdoutFd = _gdbHioDevImportFd(GDBHIO_STDOUT_FILENO);
|
||||
|
||||
return g_gdbHioStdoutFd;
|
||||
}
|
||||
|
||||
int gdbHioDevGetStderr(void)
|
||||
{
|
||||
if (g_gdbHioStderrFd < 0)
|
||||
g_gdbHioStderrFd = _gdbHioDevImportFd(GDBHIO_STDERR_FILENO);
|
||||
|
||||
return g_gdbHioStderrFd;
|
||||
}
|
||||
|
||||
int gdbHioDevRedirectStdStreams(bool in, bool out, bool err)
|
||||
{
|
||||
int ret = 0;
|
||||
if (in) {
|
||||
if (gdbHioDevGetStdin() < 0) return -1;
|
||||
ret = dup2(g_gdbHioStdinFd, STDIN_FILENO);
|
||||
if (ret < 0) return -1;
|
||||
if (ret != g_gdbHioStdinFd) {
|
||||
close(g_gdbHioStdinFd);
|
||||
g_gdbHioStdinFd = STDIN_FILENO;
|
||||
}
|
||||
}
|
||||
|
||||
if (out) {
|
||||
if (gdbHioDevGetStdout() < 0) return -2;
|
||||
ret = dup2(g_gdbHioStdoutFd, STDOUT_FILENO);
|
||||
if (ret < 0) return -2;
|
||||
if (ret != g_gdbHioStdoutFd) {
|
||||
close(g_gdbHioStdoutFd);
|
||||
g_gdbHioStdoutFd = STDOUT_FILENO;
|
||||
}
|
||||
}
|
||||
|
||||
if (err) {
|
||||
if (gdbHioDevGetStderr() < 0) return -3;
|
||||
ret = dup2(g_gdbHioStderrFd, STDERR_FILENO);
|
||||
if (ret < 0) return -3;
|
||||
if (ret != g_gdbHioStderrFd) {
|
||||
close(g_gdbHioStderrFd);
|
||||
g_gdbHioStderrFd = STDERR_FILENO;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user