diff --git a/Headers/DebugServer2/GDBRemote/DummySessionDelegateImpl.h b/Headers/DebugServer2/GDBRemote/DummySessionDelegateImpl.h index 3c4fa5fd..c386528a 100644 --- a/Headers/DebugServer2/GDBRemote/DummySessionDelegateImpl.h +++ b/Headers/DebugServer2/GDBRemote/DummySessionDelegateImpl.h @@ -247,6 +247,8 @@ class DummySessionDelegateImpl : public SessionDelegate { uint64_t &size) override; ErrorCode onFileGetMode(Session &session, std::string const &path, uint32_t &mode) const override; + ErrorCode onFileFstat(Session &session, int fd, + ByteVector &buffer) const override; ErrorCode onQueryProcessList(Session &session, ProcessInfoMatch const &match, bool first, ProcessInfo &info) const override; diff --git a/Headers/DebugServer2/GDBRemote/Mixins/FileOperationsMixin.h b/Headers/DebugServer2/GDBRemote/Mixins/FileOperationsMixin.h index a733bc90..522fb363 100644 --- a/Headers/DebugServer2/GDBRemote/Mixins/FileOperationsMixin.h +++ b/Headers/DebugServer2/GDBRemote/Mixins/FileOperationsMixin.h @@ -49,6 +49,7 @@ template class FileOperationsMixin : public T { uint64_t &size) override; ErrorCode onFileGetMode(Session &session, std::string const &path, uint32_t &mode) const override; + ErrorCode onFileFstat(Session &session, int fd, ByteVector &buffer) const override; ErrorCode onFileRemove(Session &session, std::string const &path) override; protected: diff --git a/Headers/DebugServer2/GDBRemote/SessionDelegate.h b/Headers/DebugServer2/GDBRemote/SessionDelegate.h index 13a13987..52fb5629 100644 --- a/Headers/DebugServer2/GDBRemote/SessionDelegate.h +++ b/Headers/DebugServer2/GDBRemote/SessionDelegate.h @@ -274,6 +274,8 @@ class SessionDelegate { uint64_t &size) = 0; virtual ErrorCode onFileGetMode(Session &session, std::string const &path, uint32_t &mode) const = 0; + virtual ErrorCode onFileFstat(Session &session, int fd, + ByteVector &buffer) const = 0; virtual ErrorCode onQueryProcessList(Session &session, ProcessInfoMatch const &match, diff --git a/Headers/DebugServer2/Host/File.h b/Headers/DebugServer2/Host/File.h index bd7c2524..c4a4efda 100644 --- a/Headers/DebugServer2/Host/File.h +++ b/Headers/DebugServer2/Host/File.h @@ -47,6 +47,7 @@ class File { public: ErrorCode pread(ByteVector &buf, uint64_t &count, uint64_t offset); ErrorCode pwrite(ByteVector const &buf, uint64_t &count, uint64_t offset); + ErrorCode fstat(ByteVector &buffer) const; public: bool valid() const { return (_fd >= 0); } diff --git a/Sources/GDBRemote/DummySessionDelegateImpl.cpp b/Sources/GDBRemote/DummySessionDelegateImpl.cpp index 02f83e63..f4da1aad 100644 --- a/Sources/GDBRemote/DummySessionDelegateImpl.cpp +++ b/Sources/GDBRemote/DummySessionDelegateImpl.cpp @@ -295,6 +295,8 @@ DUMMY_IMPL_EMPTY(onFileGetSize, Session &, std::string const &, uint64_t &) DUMMY_IMPL_EMPTY_CONST(onFileGetMode, Session &, std::string const &, uint32_t&) +DUMMY_IMPL_EMPTY_CONST(onFileFstat, Session &, int, ByteVector &) + DUMMY_IMPL_EMPTY_CONST(onQueryProcessList, Session &, ProcessInfoMatch const &, bool, ProcessInfo &) diff --git a/Sources/GDBRemote/Mixins/FileOperationsMixin.hpp b/Sources/GDBRemote/Mixins/FileOperationsMixin.hpp index 28589b8f..da575803 100644 --- a/Sources/GDBRemote/Mixins/FileOperationsMixin.hpp +++ b/Sources/GDBRemote/Mixins/FileOperationsMixin.hpp @@ -101,6 +101,16 @@ ErrorCode FileOperationsMixin::onFileGetMode(Session &session, return Host::File::fileMode(path, mode); } +template +ErrorCode FileOperationsMixin::onFileFstat(Session &session, int fd, + ByteVector &buffer) const { + auto it = _openFiles.find(fd); + if (it == _openFiles.end()) + return kErrorInvalidHandle; + + return it->second.fstat(buffer); +} + template ErrorCode FileOperationsMixin::onFileRemove(Session &session, std::string const &path) { diff --git a/Sources/GDBRemote/Session.cpp b/Sources/GDBRemote/Session.cpp index fd1faea2..c24b7cab 100644 --- a/Sources/GDBRemote/Session.cpp +++ b/Sources/GDBRemote/Session.cpp @@ -3114,6 +3114,20 @@ void Session::Handle_vFile(ProtocolInterpreter::Handler const &, } else { ss << std::hex << mode; } + } else if (op == "fstat") { + ByteVector buffer; + int fd = std::strtol(&args[op_end], nullptr, 16); + ErrorCode error = _delegate->onFileFstat(*this, fd, buffer); + // Response is F, followed by the the size of the stat data (base 16), + // a semicolon, followed by the stat result in the binary-escaped-data + // encoding or F-1,errno with the errno if an error occurs, base 16 + ss << 'F'; + if (error != kSuccess) { + ss << -1 << ',' << std::hex << error; + } else { + ss << std::hex << buffer.size() << ';' << Escape(buffer); + escaped = true; + } } else { sendError(kErrorUnsupported); return; diff --git a/Sources/Host/POSIX/File.cpp b/Sources/Host/POSIX/File.cpp index 85d16352..33722f23 100644 --- a/Sources/Host/POSIX/File.cpp +++ b/Sources/Host/POSIX/File.cpp @@ -16,6 +16,16 @@ #include #include +#if defined(OS_LINUX) +#include +#elif defined(OS_FREEBSD) +#include +#elif defined(OS_DARWIN) +#include +#define htobe32(x) OSSwapHostToBigInt32(x) +#define htobe64(x) OSSwapHostToBigInt64(x) +#endif + namespace ds2 { namespace Host { @@ -118,6 +128,40 @@ ErrorCode File::pwrite(ByteVector const &buf, uint64_t &count, return _lastError = kSuccess; } +// lldb expects stat data is returned as a packed buffer with total size of 64 +// bytes. The field order is the same as the POSIX defined stat struct. All +// fields are encoded as 4-byte, big-endian unsigned integers except for +// st_size, st_blksize, and st_blocks which are all 8-byte, big-endian unsigned +// integers. +ErrorCode File::fstat(ByteVector &buffer) const { + struct stat s; + if (::fstat(_fd, &s) < 0) + return Platform::TranslateError(); + + const auto appendInteger = [&buffer](auto value) -> void { + buffer.insert(buffer.end(), + reinterpret_cast(&value), + reinterpret_cast(&value) + sizeof(value)); + }; + + appendInteger(htobe32(static_cast(s.st_dev))); + appendInteger(htobe32(static_cast(s.st_ino))); + appendInteger(htobe32(static_cast(s.st_mode))); + appendInteger(htobe32(static_cast(s.st_nlink))); + appendInteger(htobe32(static_cast(s.st_uid))); + appendInteger(htobe32(static_cast(s.st_gid))); + appendInteger(htobe32(static_cast(s.st_rdev))); + appendInteger(htobe64(static_cast(s.st_size))); + appendInteger(htobe64(static_cast(s.st_blksize))); + appendInteger(htobe64(static_cast(s.st_blocks))); + appendInteger(htobe32(static_cast(s.st_atime))); + appendInteger(htobe32(static_cast(s.st_mtime))); + appendInteger(htobe32(static_cast(s.st_ctime))); + DS2ASSERT(buffer.size() == 64); + + return kSuccess; +} + ErrorCode File::chmod(std::string const &path, uint32_t mode) { if (::chmod(path.c_str(), mode) < 0) { return Platform::TranslateError(); diff --git a/Sources/Host/Windows/File.cpp b/Sources/Host/Windows/File.cpp index df65fad7..f266e400 100644 --- a/Sources/Host/Windows/File.cpp +++ b/Sources/Host/Windows/File.cpp @@ -29,6 +29,10 @@ ErrorCode File::pwrite(ByteVector const &buf, uint64_t &count, return kErrorUnsupported; } +ErrorCode File::fstat(ByteVector &buffer) const { + return kErrorUnsupported; +} + ErrorCode File::chmod(std::string const &path, uint32_t mode) { return kErrorUnsupported; }