[lldb] [gdb-remote] Add fallbacks for vFile:mode and vFile:exists
Add a GDB-compatible fallback to vFile:fstat for vFile:mode, and to vFile:open for vFile:exists. Note that this is only partial fallback, as it fails if the file cannot be opened. Differential Revision: https://reviews.llvm.org/D107811
This commit is contained in:
parent
dbb0c14d27
commit
501eaf8877
|
@ -65,7 +65,8 @@ 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_supports_vFileSize(true), m_supports_vFileMode(true),
|
||||
m_supports_vFileExists(true),
|
||||
|
||||
m_host_arch(), m_process_arch(), m_os_build(), m_os_kernel(),
|
||||
m_hostname(), m_gdb_server_name(), m_default_packet_timeout(0),
|
||||
|
@ -3159,14 +3160,20 @@ void GDBRemoteCommunicationClient::AutoCompleteDiskFileOrDirectory(
|
|||
Status
|
||||
GDBRemoteCommunicationClient::GetFilePermissions(const FileSpec &file_spec,
|
||||
uint32_t &file_permissions) {
|
||||
if (m_supports_vFileMode) {
|
||||
std::string path{file_spec.GetPath(false)};
|
||||
Status error;
|
||||
lldb_private::StreamString stream;
|
||||
stream.PutCString("vFile:mode:");
|
||||
stream.PutStringAsRawHex8(path);
|
||||
StringExtractorGDBRemote response;
|
||||
if (SendPacketAndWaitForResponse(stream.GetString(), response) ==
|
||||
if (SendPacketAndWaitForResponse(stream.GetString(), response) !=
|
||||
PacketResult::Success) {
|
||||
error.SetErrorStringWithFormat("failed to send '%s' packet",
|
||||
stream.GetData());
|
||||
return error;
|
||||
}
|
||||
if (!response.IsUnsupportedResponse()) {
|
||||
if (response.GetChar() != 'F') {
|
||||
error.SetErrorStringWithFormat("invalid response to '%s' packet",
|
||||
stream.GetData());
|
||||
|
@ -3185,11 +3192,18 @@ GDBRemoteCommunicationClient::GetFilePermissions(const FileSpec &file_spec,
|
|||
file_permissions = mode & (S_IRWXU | S_IRWXG | S_IRWXO);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
error.SetErrorStringWithFormat("failed to send '%s' packet",
|
||||
stream.GetData());
|
||||
}
|
||||
return error;
|
||||
} else { // response.IsUnsupportedResponse()
|
||||
m_supports_vFileMode = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to fstat.
|
||||
if (llvm::Optional<GDBRemoteFStatData> st = Stat(file_spec)) {
|
||||
file_permissions = st->gdb_st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
|
||||
return Status();
|
||||
}
|
||||
return Status("fstat failed");
|
||||
}
|
||||
|
||||
uint64_t GDBRemoteCommunicationClient::ReadFile(lldb::user_id_t fd,
|
||||
|
@ -3332,21 +3346,33 @@ Status GDBRemoteCommunicationClient::Unlink(const FileSpec &file_spec) {
|
|||
// Extension of host I/O packets to get whether a file exists.
|
||||
bool GDBRemoteCommunicationClient::GetFileExists(
|
||||
const lldb_private::FileSpec &file_spec) {
|
||||
if (m_supports_vFileExists) {
|
||||
std::string path(file_spec.GetPath(false));
|
||||
lldb_private::StreamString stream;
|
||||
stream.PutCString("vFile:exists:");
|
||||
stream.PutStringAsRawHex8(path);
|
||||
StringExtractorGDBRemote response;
|
||||
if (SendPacketAndWaitForResponse(stream.GetString(), response) ==
|
||||
PacketResult::Success) {
|
||||
if (SendPacketAndWaitForResponse(stream.GetString(), response) !=
|
||||
PacketResult::Success)
|
||||
return false;
|
||||
if (!response.IsUnsupportedResponse()) {
|
||||
if (response.GetChar() != 'F')
|
||||
return false;
|
||||
if (response.GetChar() != ',')
|
||||
return false;
|
||||
bool retcode = (response.GetChar() != '0');
|
||||
return retcode;
|
||||
} else
|
||||
m_supports_vFileExists = false;
|
||||
}
|
||||
|
||||
// Fallback to open.
|
||||
Status error;
|
||||
lldb::user_id_t fd = OpenFile(file_spec, File::eOpenOptionReadOnly, 0, error);
|
||||
if (fd == UINT64_MAX)
|
||||
return false;
|
||||
CloseFile(fd, error);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GDBRemoteCommunicationClient::CalculateMD5(
|
||||
|
|
|
@ -587,7 +587,8 @@ protected:
|
|||
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_vFileSize : 1;
|
||||
m_supports_jModulesInfo : 1, m_supports_vFileSize : 1,
|
||||
m_supports_vFileMode : 1, m_supports_vFileExists : 1;
|
||||
|
||||
/// Current gdb remote protocol process identifier for all other operations
|
||||
lldb::pid_t m_curr_pid = LLDB_INVALID_PROCESS_ID;
|
||||
|
|
|
@ -116,6 +116,33 @@ class TestGDBRemotePlatformFile(GDBPlatformClientTestBase):
|
|||
"vFile:mode:2f736f6d652f66696c652e747874",
|
||||
])
|
||||
|
||||
def test_file_permissions_fallback(self):
|
||||
"""Test 'platform get-permissions' fallback to fstat"""
|
||||
|
||||
class Responder(MockGDBServerResponder):
|
||||
def vFile(self, packet):
|
||||
if packet.startswith("vFile:open:"):
|
||||
return "F5"
|
||||
elif packet.startswith("vFile:fstat:"):
|
||||
return "F40;" + 8 * "\0" + "\0\0\1\xA4" + 52 * "\0"
|
||||
if packet.startswith("vFile:close:"):
|
||||
return "F0"
|
||||
return ""
|
||||
|
||||
self.server.responder = Responder()
|
||||
|
||||
try:
|
||||
self.match("platform get-permissions /some/file.txt",
|
||||
[r"File permissions of /some/file\.txt \(remote\): 0o0644"])
|
||||
self.assertPacketLogContains([
|
||||
"vFile:mode:2f736f6d652f66696c652e747874",
|
||||
"vFile:open:2f736f6d652f66696c652e747874,00000000,00000000",
|
||||
"vFile:fstat:5",
|
||||
"vFile:close:5",
|
||||
])
|
||||
finally:
|
||||
self.dbg.GetSelectedPlatform().DisconnectRemote()
|
||||
|
||||
def test_file_exists(self):
|
||||
"""Test 'platform file-exists'"""
|
||||
|
||||
|
@ -145,3 +172,42 @@ class TestGDBRemotePlatformFile(GDBPlatformClientTestBase):
|
|||
self.assertPacketLogContains([
|
||||
"vFile:exists:2f736f6d652f66696c652e747874",
|
||||
])
|
||||
|
||||
def test_file_exists_fallback(self):
|
||||
"""Test 'platform file-exists' fallback to open"""
|
||||
|
||||
class Responder(MockGDBServerResponder):
|
||||
def vFile(self, packet):
|
||||
if packet.startswith("vFile:open:"):
|
||||
return "F5"
|
||||
if packet.startswith("vFile:close:"):
|
||||
return "F0"
|
||||
return ""
|
||||
|
||||
self.server.responder = Responder()
|
||||
|
||||
self.match("platform file-exists /some/file.txt",
|
||||
[r"File /some/file\.txt \(remote\) exists"])
|
||||
self.assertPacketLogContains([
|
||||
"vFile:exists:2f736f6d652f66696c652e747874",
|
||||
"vFile:open:2f736f6d652f66696c652e747874,00000000,00000000",
|
||||
"vFile:close:5",
|
||||
])
|
||||
|
||||
def test_file_exists_not_fallback(self):
|
||||
"""Test 'platform file-exists' fallback to open with non-existing file"""
|
||||
|
||||
class Responder(MockGDBServerResponder):
|
||||
def vFile(self, packet):
|
||||
if packet.startswith("vFile:open:"):
|
||||
return "F-1,2"
|
||||
return ""
|
||||
|
||||
self.server.responder = Responder()
|
||||
|
||||
self.match("platform file-exists /some/file.txt",
|
||||
[r"File /some/file\.txt \(remote\) does not exist"])
|
||||
self.assertPacketLogContains([
|
||||
"vFile:exists:2f736f6d652f66696c652e747874",
|
||||
"vFile:open:2f736f6d652f66696c652e747874,00000000,00000000",
|
||||
])
|
||||
|
|
Loading…
Reference in a new issue