mgorny updated this revision to Diff 365414. mgorny added a comment. Add a helper `Stat` method to take care of opening and closing the file. Add a cache variable for whether `vFile:size` is supported.
CHANGES SINCE LAST ACTION https://reviews.llvm.org/D107780/new/ https://reviews.llvm.org/D107780 Files: 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
Index: lldb/test/API/functionalities/gdb_remote_client/TestGDBRemotePlatformFile.py =================================================================== --- lldb/test/API/functionalities/gdb_remote_client/TestGDBRemotePlatformFile.py +++ lldb/test/API/functionalities/gdb_remote_client/TestGDBRemotePlatformFile.py @@ -77,3 +77,58 @@ ]) 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() Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h =================================================================== --- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -391,6 +391,10 @@ bool CloseFile(lldb::user_id_t fd, Status &error); + llvm::Optional<GDBRemoteFStatData> FStat(lldb::user_id_t fd); + + llvm::Optional<GDBRemoteFStatData> Stat(const FileSpec &file_spec); + lldb::user_id_t GetFileSize(const FileSpec &file_spec); void AutoCompleteDiskFileOrDirectory(CompletionRequest &request, @@ -593,7 +597,7 @@ 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; Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp =================================================================== --- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -65,6 +65,7 @@ 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), @@ -3035,22 +3036,82 @@ 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)) { + DataExtractor extractor{buffer.data(), buffer.size(), + lldb::eByteOrderBig, sizeof(void *)}; + lldb::offset_t offset = 0; + GDBRemoteFStatData out; + + out.gdb_st_dev = extractor.GetU32(&offset); + out.gdb_st_ino = extractor.GetU32(&offset); + out.gdb_st_mode = extractor.GetU32(&offset); + out.gdb_st_nlink = extractor.GetU32(&offset); + out.gdb_st_uid = extractor.GetU32(&offset); + out.gdb_st_gid = extractor.GetU32(&offset); + out.gdb_st_rdev = extractor.GetU32(&offset); + out.gdb_st_size = extractor.GetU64(&offset); + out.gdb_st_blksize = extractor.GetU64(&offset); + out.gdb_st_blocks = extractor.GetU64(&offset); + out.gdb_st_atime = extractor.GetU32(&offset); + out.gdb_st_mtime = extractor.GetU32(&offset); + out.gdb_st_ctime = extractor.GetU32(&offset); + assert(offset == 64); + + 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; + } else + 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( Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h =================================================================== --- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h +++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h @@ -51,6 +51,24 @@ 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 { + uint32_t gdb_st_dev; + uint32_t gdb_st_ino; + uint32_t gdb_st_mode; + uint32_t gdb_st_nlink; + uint32_t gdb_st_uid; + uint32_t gdb_st_gid; + uint32_t gdb_st_rdev; + uint64_t gdb_st_size; + uint64_t gdb_st_blksize; + uint64_t gdb_st_blocks; + uint32_t gdb_st_atime; + uint32_t gdb_st_mtime; + uint32_t gdb_st_ctime; +}; + class ProcessGDBRemote; class GDBRemoteCommunication : public Communication {
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits