[Lldb-commits] [lldb] 21e2d7c - [lldb] [gdb-remote] Implement fallback to vFile:stat for GetFileSize()
Michał Górny via lldb-commits
lldb-commits at lists.llvm.org
Fri Sep 10 02:09:39 PDT 2021
Author: Michał Górny
Date: 2021-09-10T11:09:35+02:00
New Revision: 21e2d7ce43c42df5d60a2805c801b8f1eda7919c
URL: https://github.com/llvm/llvm-project/commit/21e2d7ce43c42df5d60a2805c801b8f1eda7919c
DIFF: https://github.com/llvm/llvm-project/commit/21e2d7ce43c42df5d60a2805c801b8f1eda7919c.diff
LOG: [lldb] [gdb-remote] Implement fallback to vFile:stat for GetFileSize()
Implement a fallback to getting the file size via vFile:stat packet
when the remote server does not implement vFile:size. This makes it
possible to query file sizes from remote gdbserver.
Note that unlike vFile:size, the fallback will not work if the server is
unable to open the file.
While at it, add a few tests for the 'platform get-size' command.
Differential Revision: https://reviews.llvm.org/D107780
Added:
Modified:
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
lldb/test/API/functionalities/gdb_remote_client/TestGDBRemotePlatformFile.py
Removed:
################################################################################
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
index b1e2075a64fef..967dc82f0270a 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
@@ -51,6 +51,26 @@ enum class CompressionType {
LZMA, // Lempel–Ziv–Markov chain algorithm
};
+// Data included in the vFile:fstat packet.
+// https://sourceware.org/gdb/onlinedocs/gdb/struct-stat.html#struct-stat
+struct GDBRemoteFStatData {
+ llvm::support::ubig32_t gdb_st_dev;
+ llvm::support::ubig32_t gdb_st_ino;
+ llvm::support::ubig32_t gdb_st_mode;
+ llvm::support::ubig32_t gdb_st_nlink;
+ llvm::support::ubig32_t gdb_st_uid;
+ llvm::support::ubig32_t gdb_st_gid;
+ llvm::support::ubig32_t gdb_st_rdev;
+ llvm::support::ubig64_t gdb_st_size;
+ llvm::support::ubig64_t gdb_st_blksize;
+ llvm::support::ubig64_t gdb_st_blocks;
+ llvm::support::ubig32_t gdb_st_atime;
+ llvm::support::ubig32_t gdb_st_mtime;
+ llvm::support::ubig32_t gdb_st_ctime;
+};
+static_assert(sizeof(GDBRemoteFStatData) == 64,
+ "size of GDBRemoteFStatData is not 64");
+
class ProcessGDBRemote;
class GDBRemoteCommunication : public Communication {
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
index 16a27af700c6e..4bcef1f05cdbc 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -65,6 +65,7 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient()
m_supports_QEnvironmentHexEncoded(true), m_supports_qSymbol(true),
m_qSymbol_requests_done(false), m_supports_qModuleInfo(true),
m_supports_jThreadsInfo(true), m_supports_jModulesInfo(true),
+ m_supports_vFileSize(true),
m_host_arch(), m_process_arch(), m_os_build(), m_os_kernel(),
m_hostname(), m_gdb_server_name(), m_default_packet_timeout(0),
@@ -3068,22 +3069,66 @@ bool GDBRemoteCommunicationClient::CloseFile(lldb::user_id_t fd,
return false;
}
-// Extension of host I/O packets to get the file size.
-lldb::user_id_t GDBRemoteCommunicationClient::GetFileSize(
- const lldb_private::FileSpec &file_spec) {
- std::string path(file_spec.GetPath(false));
+llvm::Optional<GDBRemoteFStatData>
+GDBRemoteCommunicationClient::FStat(lldb::user_id_t fd) {
lldb_private::StreamString stream;
- stream.PutCString("vFile:size:");
- stream.PutStringAsRawHex8(path);
+ stream.Printf("vFile:fstat:%" PRIx64, fd);
StringExtractorGDBRemote response;
if (SendPacketAndWaitForResponse(stream.GetString(), response) ==
PacketResult::Success) {
if (response.GetChar() != 'F')
+ return llvm::None;
+ int64_t size = response.GetS64(-1, 16);
+ if (size > 0 && response.GetChar() == ';') {
+ std::string buffer;
+ if (response.GetEscapedBinaryData(buffer)) {
+ GDBRemoteFStatData out;
+ if (buffer.size() != sizeof(out))
+ return llvm::None;
+ memcpy(&out, buffer.data(), sizeof(out));
+ return out;
+ }
+ }
+ }
+ return llvm::None;
+}
+
+llvm::Optional<GDBRemoteFStatData>
+GDBRemoteCommunicationClient::Stat(const lldb_private::FileSpec &file_spec) {
+ Status error;
+ lldb::user_id_t fd = OpenFile(file_spec, File::eOpenOptionReadOnly, 0, error);
+ if (fd == UINT64_MAX)
+ return llvm::None;
+ llvm::Optional<GDBRemoteFStatData> st = FStat(fd);
+ CloseFile(fd, error);
+ return st;
+}
+
+// Extension of host I/O packets to get the file size.
+lldb::user_id_t GDBRemoteCommunicationClient::GetFileSize(
+ const lldb_private::FileSpec &file_spec) {
+ if (m_supports_vFileSize) {
+ std::string path(file_spec.GetPath(false));
+ lldb_private::StreamString stream;
+ stream.PutCString("vFile:size:");
+ stream.PutStringAsRawHex8(path);
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(stream.GetString(), response) !=
+ PacketResult::Success)
return UINT64_MAX;
- uint32_t retcode = response.GetHexMaxU64(false, UINT64_MAX);
- return retcode;
+
+ if (!response.IsUnsupportedResponse()) {
+ if (response.GetChar() != 'F')
+ return UINT64_MAX;
+ uint32_t retcode = response.GetHexMaxU64(false, UINT64_MAX);
+ return retcode;
+ }
+ m_supports_vFileSize = false;
}
- return UINT64_MAX;
+
+ // Fallback to fstat.
+ llvm::Optional<GDBRemoteFStatData> st = Stat(file_spec);
+ return st ? st->gdb_st_size : UINT64_MAX;
}
void GDBRemoteCommunicationClient::AutoCompleteDiskFileOrDirectory(
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
index 00625088d42a0..f1a78ceeddcda 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
@@ -376,6 +376,12 @@ class GDBRemoteCommunicationClient : public GDBRemoteClientBase {
bool CloseFile(lldb::user_id_t fd, Status &error);
+ llvm::Optional<GDBRemoteFStatData> FStat(lldb::user_id_t fd);
+
+ // NB: this is just a convenience wrapper over open() + fstat(). It does not
+ // work if the file cannot be opened.
+ llvm::Optional<GDBRemoteFStatData> Stat(const FileSpec &file_spec);
+
lldb::user_id_t GetFileSize(const FileSpec &file_spec);
void AutoCompleteDiskFileOrDirectory(CompletionRequest &request,
@@ -581,7 +587,7 @@ class GDBRemoteCommunicationClient : public GDBRemoteClientBase {
m_supports_QEnvironment : 1, m_supports_QEnvironmentHexEncoded : 1,
m_supports_qSymbol : 1, m_qSymbol_requests_done : 1,
m_supports_qModuleInfo : 1, m_supports_jThreadsInfo : 1,
- m_supports_jModulesInfo : 1;
+ m_supports_jModulesInfo : 1, m_supports_vFileSize : 1;
/// Current gdb remote protocol process identifier for all other operations
lldb::pid_t m_curr_pid = LLDB_INVALID_PROCESS_ID;
diff --git a/lldb/test/API/functionalities/gdb_remote_client/TestGDBRemotePlatformFile.py b/lldb/test/API/functionalities/gdb_remote_client/TestGDBRemotePlatformFile.py
index b0ecddbdc5579..fcc2579266806 100644
--- a/lldb/test/API/functionalities/gdb_remote_client/TestGDBRemotePlatformFile.py
+++ b/lldb/test/API/functionalities/gdb_remote_client/TestGDBRemotePlatformFile.py
@@ -77,3 +77,58 @@ def vFile(self, packet):
])
finally:
self.dbg.GetSelectedPlatform().DisconnectRemote()
+
+ def test_file_size(self):
+ """Test 'platform get-size'"""
+
+ class Responder(MockGDBServerResponder):
+ def vFile(self, packet):
+ return "F1000"
+
+ self.server.responder = Responder()
+
+ try:
+ self.runCmd("platform select remote-gdb-server")
+ self.runCmd("platform connect connect://" +
+ self.server.get_connect_address())
+ self.assertTrue(self.dbg.GetSelectedPlatform().IsConnected())
+
+ self.match("platform get-size /some/file.txt",
+ [r"File size of /some/file\.txt \(remote\): 4096"])
+ self.assertPacketLogContains([
+ "vFile:size:2f736f6d652f66696c652e747874",
+ ])
+ finally:
+ self.dbg.GetSelectedPlatform().DisconnectRemote()
+
+ def test_file_size_fallback(self):
+ """Test 'platform get-size fallback to vFile:fstat'"""
+
+ class Responder(MockGDBServerResponder):
+ def vFile(self, packet):
+ if packet.startswith("vFile:open:"):
+ return "F5"
+ elif packet.startswith("vFile:fstat:"):
+ return "F40;" + 28 * "\0" + "\0\0\0\0\0\1\2\3" + 28 * "\0"
+ if packet.startswith("vFile:close:"):
+ return "F0"
+ return ""
+
+ self.server.responder = Responder()
+
+ try:
+ self.runCmd("platform select remote-gdb-server")
+ self.runCmd("platform connect connect://" +
+ self.server.get_connect_address())
+ self.assertTrue(self.dbg.GetSelectedPlatform().IsConnected())
+
+ self.match("platform get-size /some/file.txt",
+ [r"File size of /some/file\.txt \(remote\): 66051"])
+ self.assertPacketLogContains([
+ "vFile:size:2f736f6d652f66696c652e747874",
+ "vFile:open:2f736f6d652f66696c652e747874,00000000,00000000",
+ "vFile:fstat:5",
+ "vFile:close:5",
+ ])
+ finally:
+ self.dbg.GetSelectedPlatform().DisconnectRemote()
More information about the lldb-commits
mailing list