[Lldb-commits] [lldb] 3cd8d7b - [lldb] Remote disk file/directory completion for platform commands
Raphael Isemann via lldb-commits
lldb-commits at lists.llvm.org
Mon Aug 24 08:56:29 PDT 2020
Author: Gongyu Deng
Date: 2020-08-24T17:55:54+02:00
New Revision: 3cd8d7b1727f06a701f41764c1109e5d321284b3
URL: https://github.com/llvm/llvm-project/commit/3cd8d7b1727f06a701f41764c1109e5d321284b3
DIFF: https://github.com/llvm/llvm-project/commit/3cd8d7b1727f06a701f41764c1109e5d321284b3.diff
LOG: [lldb] Remote disk file/directory completion for platform commands
1. Extended the gdb-remote communication related classes with disk file/directory
completion functions;
2. Added two common completion functions RemoteDiskFiles and
RemoteDiskDirectories based on the functions above;
3. Added completion for these commands:
A. platform get-file <remote-file> <local-file>;
B. platform put-file <local-file> <remote-file>;
C. platform get-size <remote-file>;
D. platform settings -w <remote-dir>;
E. platform open file <remote-file>.
4. Added related tests for client and server;
5. Updated docs/lldb-platform-packets.txt.
Reviewed By: labath
Differential Revision: https://reviews.llvm.org/D85284
Added:
lldb/test/API/functionalities/gdb_remote_client/TestGDBRemoteDiskFileCompletion.py
lldb/test/API/tools/lldb-server/TestGdbRemoteCompletion.py
Modified:
lldb/docs/lldb-platform-packets.txt
lldb/include/lldb/Interpreter/CommandCompletions.h
lldb/include/lldb/Target/Platform.h
lldb/include/lldb/Utility/StringExtractorGDBRemote.h
lldb/source/Commands/CommandCompletions.cpp
lldb/source/Commands/CommandObjectPlatform.cpp
lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp
lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h
lldb/source/Utility/StringExtractorGDBRemote.cpp
lldb/test/API/functionalities/gdb_remote_client/gdbclientutils.py
Removed:
################################################################################
diff --git a/lldb/docs/lldb-platform-packets.txt b/lldb/docs/lldb-platform-packets.txt
index 23d1cacc5f7e..8d3fed7ab341 100644
--- a/lldb/docs/lldb-platform-packets.txt
+++ b/lldb/docs/lldb-platform-packets.txt
@@ -237,6 +237,27 @@ incompatible with the flags that gdb specifies.
// Continues to return the results of the qfProcessInfo. Once all matches
// have been sent, Exx is returned to indicate end of matches.
+//----------------------------------------------------------------------
+// qPathComplete
+//
+// BRIEF
+// Get a list of matched disk files/directories by passing a boolean flag
+// and a partial path.
+//
+// EXAMPLE
+//
+// receive: qPathComplete:0,6d61696e
+// send: M6d61696e2e637070
+// receive: qPathComplete:1,746573
+// send: M746573742f,74657374732f
+//
+// If the first argument is zero, the result should contain all
+// files (including directories) starting with the given path. If the
+// argument is one, the result should contain only directories.
+//
+// The result should be a comma-separated list of hex-encoded paths.
+// Paths denoting a directory should end with a directory separator ('/' or '\').
+
//----------------------------------------------------------------------
// vFile:size:
//
diff --git a/lldb/include/lldb/Interpreter/CommandCompletions.h b/lldb/include/lldb/Interpreter/CommandCompletions.h
index 0392eaed62c5..b90e81cb95a8 100644
--- a/lldb/include/lldb/Interpreter/CommandCompletions.h
+++ b/lldb/include/lldb/Interpreter/CommandCompletions.h
@@ -47,10 +47,12 @@ class CommandCompletions {
eBreakpointNameCompletion = (1u << 19),
eProcessIDCompletion = (1u << 20),
eProcessNameCompletion = (1u << 21),
+ eRemoteDiskFileCompletion = (1u << 22),
+ eRemoteDiskDirectoryCompletion = (1u << 23),
// This item serves two purposes. It is the last element in the enum, so
// you can add custom enums starting from here in your Option class. Also
// if you & in this bit the base code will not process the option.
- eCustomCompletion = (1u << 22)
+ eCustomCompletion = (1u << 24)
};
static bool InvokeCommonCompletionCallbacks(
@@ -72,6 +74,14 @@ class CommandCompletions {
StringList &matches,
TildeExpressionResolver &Resolver);
+ static void RemoteDiskFiles(CommandInterpreter &interpreter,
+ CompletionRequest &request,
+ SearchFilter *searcher);
+
+ static void RemoteDiskDirectories(CommandInterpreter &interpreter,
+ CompletionRequest &request,
+ SearchFilter *searcher);
+
static void SourceFiles(CommandInterpreter &interpreter,
CompletionRequest &request, SearchFilter *searcher);
diff --git a/lldb/include/lldb/Target/Platform.h b/lldb/include/lldb/Target/Platform.h
index 6234b8244b3f..9335f73b37df 100644
--- a/lldb/include/lldb/Target/Platform.h
+++ b/lldb/include/lldb/Target/Platform.h
@@ -523,6 +523,9 @@ class Platform : public PluginInterface {
return UINT64_MAX;
}
+ virtual void AutoCompleteDiskFileOrDirectory(CompletionRequest &request,
+ bool only_dir) {}
+
virtual uint64_t ReadFile(lldb::user_id_t fd, uint64_t offset, void *dst,
uint64_t dst_len, Status &error) {
error.SetErrorStringWithFormat(
diff --git a/lldb/include/lldb/Utility/StringExtractorGDBRemote.h b/lldb/include/lldb/Utility/StringExtractorGDBRemote.h
index 715f3cb2541d..efb43767e739 100644
--- a/lldb/include/lldb/Utility/StringExtractorGDBRemote.h
+++ b/lldb/include/lldb/Utility/StringExtractorGDBRemote.h
@@ -76,6 +76,7 @@ class StringExtractorGDBRemote : public StringExtractor {
eServerPacketType_QSetSTDERR,
eServerPacketType_QSetWorkingDir,
eServerPacketType_QStartNoAckMode,
+ eServerPacketType_qPathComplete,
eServerPacketType_qPlatform_shell,
eServerPacketType_qPlatform_mkdir,
eServerPacketType_qPlatform_chmod,
diff --git a/lldb/source/Commands/CommandCompletions.cpp b/lldb/source/Commands/CommandCompletions.cpp
index 9e74d8ad26cd..9221830b6460 100644
--- a/lldb/source/Commands/CommandCompletions.cpp
+++ b/lldb/source/Commands/CommandCompletions.cpp
@@ -73,6 +73,8 @@ bool CommandCompletions::InvokeCommonCompletionCallbacks(
{eBreakpointNameCompletion, CommandCompletions::BreakpointNames},
{eProcessIDCompletion, CommandCompletions::ProcessIDs},
{eProcessNameCompletion, CommandCompletions::ProcessNames},
+ {eRemoteDiskFileCompletion, CommandCompletions::RemoteDiskFiles},
+ {eRemoteDiskDirectoryCompletion, CommandCompletions::RemoteDiskDirectories},
{eNoCompletion, nullptr} // This one has to be last in the list.
};
@@ -486,6 +488,24 @@ void CommandCompletions::DiskDirectories(const llvm::Twine &partial_file_name,
DiskFilesOrDirectories(partial_file_name, true, matches, Resolver);
}
+void CommandCompletions::RemoteDiskFiles(CommandInterpreter &interpreter,
+ CompletionRequest &request,
+ SearchFilter *searcher) {
+ lldb::PlatformSP platform_sp =
+ interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform();
+ if (platform_sp)
+ platform_sp->AutoCompleteDiskFileOrDirectory(request, false);
+}
+
+void CommandCompletions::RemoteDiskDirectories(CommandInterpreter &interpreter,
+ CompletionRequest &request,
+ SearchFilter *searcher) {
+ lldb::PlatformSP platform_sp =
+ interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform();
+ if (platform_sp)
+ platform_sp->AutoCompleteDiskFileOrDirectory(request, true);
+}
+
void CommandCompletions::Modules(CommandInterpreter &interpreter,
CompletionRequest &request,
SearchFilter *searcher) {
diff --git a/lldb/source/Commands/CommandObjectPlatform.cpp b/lldb/source/Commands/CommandObjectPlatform.cpp
index da113e5cb342..b5409e611f05 100644
--- a/lldb/source/Commands/CommandObjectPlatform.cpp
+++ b/lldb/source/Commands/CommandObjectPlatform.cpp
@@ -392,7 +392,8 @@ class CommandObjectPlatformSettings : public CommandObjectParsed {
"or for a platform by name.",
"platform settings", 0),
m_options(),
- m_option_working_dir(LLDB_OPT_SET_1, false, "working-dir", 'w', 0,
+ m_option_working_dir(LLDB_OPT_SET_1, false, "working-dir", 'w',
+ CommandCompletions::eRemoteDiskDirectoryCompletion,
eArgTypePath,
"The working directory for the platform.") {
m_options.Append(&m_option_working_dir, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
@@ -485,6 +486,15 @@ class CommandObjectPlatformFOpen : public CommandObjectParsed {
~CommandObjectPlatformFOpen() override = default;
+ void
+ HandleArgumentCompletion(CompletionRequest &request,
+ OptionElementVector &opt_element_vector) override {
+ if (request.GetCursorIndex() == 0)
+ CommandCompletions::InvokeCommonCompletionCallbacks(
+ GetCommandInterpreter(),
+ CommandCompletions::eRemoteDiskFileCompletion, request, nullptr);
+ }
+
bool DoExecute(Args &args, CommandReturnObject &result) override {
PlatformSP platform_sp(
GetDebugger().GetPlatformList().GetSelectedPlatform());
@@ -817,6 +827,19 @@ class CommandObjectPlatformGetFile : public CommandObjectParsed {
~CommandObjectPlatformGetFile() override = default;
+ void
+ HandleArgumentCompletion(CompletionRequest &request,
+ OptionElementVector &opt_element_vector) override {
+ if (request.GetCursorIndex() == 0)
+ CommandCompletions::InvokeCommonCompletionCallbacks(
+ GetCommandInterpreter(),
+ CommandCompletions::eRemoteDiskFileCompletion, request, nullptr);
+ else if (request.GetCursorIndex() == 1)
+ CommandCompletions::InvokeCommonCompletionCallbacks(
+ GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion,
+ request, nullptr);
+ }
+
bool DoExecute(Args &args, CommandReturnObject &result) override {
// If the number of arguments is incorrect, issue an error message.
if (args.GetArgumentCount() != 2) {
@@ -882,6 +905,17 @@ class CommandObjectPlatformGetSize : public CommandObjectParsed {
~CommandObjectPlatformGetSize() override = default;
+ void
+ HandleArgumentCompletion(CompletionRequest &request,
+ OptionElementVector &opt_element_vector) override {
+ if (request.GetCursorIndex() != 0)
+ return;
+
+ CommandCompletions::InvokeCommonCompletionCallbacks(
+ GetCommandInterpreter(), CommandCompletions::eRemoteDiskFileCompletion,
+ request, nullptr);
+ }
+
bool DoExecute(Args &args, CommandReturnObject &result) override {
// If the number of arguments is incorrect, issue an error message.
if (args.GetArgumentCount() != 1) {
@@ -927,6 +961,19 @@ class CommandObjectPlatformPutFile : public CommandObjectParsed {
~CommandObjectPlatformPutFile() override = default;
+ void
+ HandleArgumentCompletion(CompletionRequest &request,
+ OptionElementVector &opt_element_vector) override {
+ if (request.GetCursorIndex() == 0)
+ CommandCompletions::InvokeCommonCompletionCallbacks(
+ GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion,
+ request, nullptr);
+ else if (request.GetCursorIndex() == 1)
+ CommandCompletions::InvokeCommonCompletionCallbacks(
+ GetCommandInterpreter(),
+ CommandCompletions::eRemoteDiskFileCompletion, request, nullptr);
+ }
+
bool DoExecute(Args &args, CommandReturnObject &result) override {
const char *src = args.GetArgumentAtIndex(0);
const char *dst = args.GetArgumentAtIndex(1);
diff --git a/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp b/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp
index 21bf7f4ac46d..e1eb15c3e8c9 100644
--- a/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp
+++ b/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp
@@ -661,6 +661,11 @@ PlatformRemoteGDBServer::GetFileSize(const FileSpec &file_spec) {
return m_gdb_client.GetFileSize(file_spec);
}
+void PlatformRemoteGDBServer::AutoCompleteDiskFileOrDirectory(
+ CompletionRequest &request, bool only_dir) {
+ m_gdb_client.AutoCompleteDiskFileOrDirectory(request, only_dir);
+}
+
uint64_t PlatformRemoteGDBServer::ReadFile(lldb::user_id_t fd, uint64_t offset,
void *dst, uint64_t dst_len,
Status &error) {
diff --git a/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h b/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h
index 0602be1fa377..3562b2bb09df 100644
--- a/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h
+++ b/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h
@@ -127,6 +127,9 @@ class PlatformRemoteGDBServer : public Platform, private UserIDResolver {
lldb::user_id_t GetFileSize(const FileSpec &file_spec) override;
+ void AutoCompleteDiskFileOrDirectory(CompletionRequest &request,
+ bool only_dir) override;
+
Status PutFile(const FileSpec &source, const FileSpec &destination,
uint32_t uid = UINT32_MAX, uint32_t gid = UINT32_MAX) override;
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
index cf0daccc2d0c..2e6d174e4674 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -2982,6 +2982,31 @@ lldb::user_id_t GDBRemoteCommunicationClient::GetFileSize(
return UINT64_MAX;
}
+void GDBRemoteCommunicationClient::AutoCompleteDiskFileOrDirectory(
+ CompletionRequest &request, bool only_dir) {
+ lldb_private::StreamString stream;
+ stream.PutCString("qPathComplete:");
+ stream.PutHex32(only_dir ? 1 : 0);
+ stream.PutChar(',');
+ stream.PutStringAsRawHex8(request.GetCursorArgumentPrefix());
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(stream.GetString(), response, false) ==
+ PacketResult::Success) {
+ StreamString strm;
+ char ch = response.GetChar();
+ if (ch != 'M')
+ return;
+ while (response.Peek()) {
+ strm.Clear();
+ while ((ch = response.GetHexU8(0, false)) != '\0')
+ strm.PutChar(ch);
+ request.AddCompletion(strm.GetString());
+ if (response.GetChar() != ',')
+ break;
+ }
+ }
+}
+
Status
GDBRemoteCommunicationClient::GetFilePermissions(const FileSpec &file_spec,
uint32_t &file_permissions) {
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
index 8df08cbde735..0159125a433b 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
@@ -375,6 +375,9 @@ class GDBRemoteCommunicationClient : public GDBRemoteClientBase {
lldb::user_id_t GetFileSize(const FileSpec &file_spec);
+ void AutoCompleteDiskFileOrDirectory(CompletionRequest &request,
+ bool only_dir);
+
Status GetFilePermissions(const FileSpec &file_spec,
uint32_t &file_permissions);
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp
index d14b79a03d17..7e94afb9ec68 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp
@@ -26,12 +26,14 @@
#include "lldb/Host/FileAction.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/HostInfo.h"
+#include "lldb/Interpreter/CommandCompletions.h"
#include "lldb/Target/Platform.h"
#include "lldb/Target/UnixSignals.h"
#include "lldb/Utility/GDBRemote.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/StreamString.h"
#include "lldb/Utility/StructuredData.h"
+#include "lldb/Utility/TildeExpressionResolver.h"
#include "lldb/Utility/UriParser.h"
#include "lldb/Utility/StringExtractorGDBRemote.h"
@@ -68,6 +70,9 @@ GDBRemoteCommunicationServerPlatform::GDBRemoteCommunicationServerPlatform(
RegisterMemberFunctionHandler(
StringExtractorGDBRemote::eServerPacketType_qProcessInfo,
&GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_qPathComplete,
+ &GDBRemoteCommunicationServerPlatform::Handle_qPathComplete);
RegisterMemberFunctionHandler(
StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir,
&GDBRemoteCommunicationServerPlatform::Handle_QSetWorkingDir);
@@ -333,6 +338,38 @@ GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo(
return SendPacketNoLock(response.GetString());
}
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerPlatform::Handle_qPathComplete(
+ StringExtractorGDBRemote &packet) {
+ packet.SetFilePos(::strlen("qPathComplete:"));
+ const bool only_dir = (packet.GetHexMaxU32(false, 0) == 1);
+ if (packet.GetChar() != ',')
+ return SendErrorResponse(85);
+ std::string path;
+ packet.GetHexByteString(path);
+
+ StringList matches;
+ StandardTildeExpressionResolver resolver;
+ if (only_dir)
+ CommandCompletions::DiskDirectories(path, matches, resolver);
+ else
+ CommandCompletions::DiskFiles(path, matches, resolver);
+
+ StreamString response;
+ response.PutChar('M');
+ llvm::StringRef separator;
+ std::sort(matches.begin(), matches.end());
+ for (const auto &match : matches) {
+ response << separator;
+ separator = ",";
+ // encode result strings into hex bytes to avoid unexpected error caused by
+ // special characters like '$'.
+ response.PutStringAsRawHex8(match.c_str());
+ }
+
+ return SendPacketNoLock(response.GetString());
+}
+
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerPlatform::Handle_qGetWorkingDir(
StringExtractorGDBRemote &packet) {
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h
index a8cacea78835..8b3122d1423e 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h
@@ -81,6 +81,8 @@ class GDBRemoteCommunicationServerPlatform
PacketResult Handle_qKillSpawnedProcess(StringExtractorGDBRemote &packet);
+ PacketResult Handle_qPathComplete(StringExtractorGDBRemote &packet);
+
PacketResult Handle_qProcessInfo(StringExtractorGDBRemote &packet);
PacketResult Handle_qGetWorkingDir(StringExtractorGDBRemote &packet);
diff --git a/lldb/source/Utility/StringExtractorGDBRemote.cpp b/lldb/source/Utility/StringExtractorGDBRemote.cpp
index cfe7577e4863..2901500b29e3 100644
--- a/lldb/source/Utility/StringExtractorGDBRemote.cpp
+++ b/lldb/source/Utility/StringExtractorGDBRemote.cpp
@@ -233,6 +233,8 @@ StringExtractorGDBRemote::GetServerPacketType() const {
return eServerPacketType_qPlatform_chmod;
if (PACKET_MATCHES("qProcessInfo"))
return eServerPacketType_qProcessInfo;
+ if (PACKET_STARTS_WITH("qPathComplete:"))
+ return eServerPacketType_qPathComplete;
break;
case 'Q':
diff --git a/lldb/test/API/functionalities/gdb_remote_client/TestGDBRemoteDiskFileCompletion.py b/lldb/test/API/functionalities/gdb_remote_client/TestGDBRemoteDiskFileCompletion.py
new file mode 100644
index 000000000000..90f830c4a278
--- /dev/null
+++ b/lldb/test/API/functionalities/gdb_remote_client/TestGDBRemoteDiskFileCompletion.py
@@ -0,0 +1,29 @@
+from gdbclientutils import *
+
+class TestGDBRemoteDiskFileCompletion(GDBRemoteTestBase):
+
+ def test_autocomplete_request(self):
+ """Test remote disk completion on remote-gdb-server plugin"""
+
+ class Responder(MockGDBServerResponder):
+ def qPathComplete(self):
+ return "M{},{}".format(
+ "test".encode().hex(),
+ "123".encode().hex()
+ )
+
+ self.server.responder = Responder()
+
+ try:
+ self.runCmd("platform select remote-gdb-server")
+ self.runCmd("platform connect connect://localhost:%d" %
+ self.server.port)
+ self.assertTrue(self.dbg.GetSelectedPlatform().IsConnected())
+
+ self.complete_from_to('platform get-size ', ['test', '123'])
+ self.complete_from_to('platform get-file ', ['test', '123'])
+ self.complete_from_to('platform put-file foo ', ['test', '123'])
+ self.complete_from_to('platform file open ', ['test', '123'])
+ self.complete_from_to('platform settings -w ', ['test', '123'])
+ finally:
+ self.dbg.GetSelectedPlatform().DisconnectRemote()
diff --git a/lldb/test/API/functionalities/gdb_remote_client/gdbclientutils.py b/lldb/test/API/functionalities/gdb_remote_client/gdbclientutils.py
index feda8873d872..eb789e861d9c 100644
--- a/lldb/test/API/functionalities/gdb_remote_client/gdbclientutils.py
+++ b/lldb/test/API/functionalities/gdb_remote_client/gdbclientutils.py
@@ -178,6 +178,8 @@ def respond(self, packet):
return self.qsProcessInfo()
if packet.startswith("qfProcessInfo"):
return self.qfProcessInfo(packet)
+ if packet.startswith("qPathComplete:"):
+ return self.qPathComplete()
return self.other(packet)
@@ -282,6 +284,9 @@ def QListThreadsInStopReply(self):
def qMemoryRegionInfo(self):
return ""
+ def qPathComplete(self):
+ return ""
+
"""
Raised when we receive a packet for which there is no default action.
Override the responder class to implement behavior suitable for the test at
diff --git a/lldb/test/API/tools/lldb-server/TestGdbRemoteCompletion.py b/lldb/test/API/tools/lldb-server/TestGdbRemoteCompletion.py
new file mode 100644
index 000000000000..94e628c811af
--- /dev/null
+++ b/lldb/test/API/tools/lldb-server/TestGdbRemoteCompletion.py
@@ -0,0 +1,63 @@
+import tempfile
+import gdbremote_testcase
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test.decorators import *
+from lldbgdbserverutils import *
+
+class GdbRemoteCompletionTestCase(gdbremote_testcase.GdbRemoteTestCaseBase):
+ mydir = TestBase.compute_mydir(__file__)
+
+ def init_lldb_server(self):
+ self.debug_monitor_exe = get_lldb_server_exe()
+ if not self.debug_monitor_exe:
+ self.skipTest("lldb-server exe not found")
+ port_file = tempfile.NamedTemporaryFile().name
+ commandline_args = [
+ "platform",
+ "--listen",
+ "*:0",
+ "--socket-file",
+ port_file
+ ]
+ server = self.spawnSubprocess(
+ get_lldb_server_exe(),
+ commandline_args,
+ install_remote=False)
+ self.assertIsNotNone(server)
+ self.stub_hostname = "localhost"
+ self.port = int(lldbutil.wait_for_file_on_target(self, port_file))
+ self.sock = self.create_socket()
+
+ self.add_no_ack_remote_stream()
+
+ def generate_hex_path(self, target):
+ return str(os.path.join(self.getBuildDir(), target)).encode().hex()
+
+ @skipIfDarwinEmbedded # <rdar://problem/34539270> lldb-server tests not updated to work on ios etc yet
+ @llgs_test
+ def test_autocomplete_path(self):
+ self.build()
+ self.init_lldb_server()
+
+ # Test file-included completion when flag is set to 0.
+ self.test_sequence.add_log_lines(
+ ["read packet: $qPathComplete:0,{}#00".format(
+ self.generate_hex_path("main")),
+ "send packet: $M{},{}#00".format(
+ self.generate_hex_path("main.d"),
+ self.generate_hex_path("main.o"))
+ ],
+ True)
+
+ # Test directory-only completion when flag is set to 1.
+ os.makedirs(os.path.join(self.getBuildDir(), "test"))
+ self.test_sequence.add_log_lines(
+ ["read packet: $qPathComplete:1,{}#00".format(
+ self.generate_hex_path("tes")),
+ "send packet: $M{}{}#00".format(
+ self.generate_hex_path("test"),
+ os.path.sep.encode().hex()) # "test/" or "test\".
+ ],
+ True)
+
+ self.expect_gdbremote_sequence()
More information about the lldb-commits
mailing list