Author: Gongyu Deng Date: 2020-05-07T18:14:27+02:00 New Revision: a14f4a7531f083a4820b5452808a1d003f1e88cc
URL: https://github.com/llvm/llvm-project/commit/a14f4a7531f083a4820b5452808a1d003f1e88cc DIFF: https://github.com/llvm/llvm-project/commit/a14f4a7531f083a4820b5452808a1d003f1e88cc.diff LOG: tab completion for register read/write Summary: 1. Created a new common completion for the registers of the current context; 2. Apply this new common completion to the commands register read/write; 3. Unit test. Reviewers: teemperor, JDevlieghere Reviewed By: teemperor Tags: #lldb Differential Revision: https://reviews.llvm.org/D79490 Added: Modified: lldb/include/lldb/Interpreter/CommandCompletions.h lldb/source/Commands/CommandCompletions.cpp lldb/source/Commands/CommandObjectRegister.cpp lldb/test/API/functionalities/completion/TestCompletion.py Removed: ################################################################################ diff --git a/lldb/include/lldb/Interpreter/CommandCompletions.h b/lldb/include/lldb/Interpreter/CommandCompletions.h index 51f5a2e5705e..a6e025e72baf 100644 --- a/lldb/include/lldb/Interpreter/CommandCompletions.h +++ b/lldb/include/lldb/Interpreter/CommandCompletions.h @@ -34,10 +34,11 @@ class CommandCompletions { ePlatformPluginCompletion = (1u << 6), eArchitectureCompletion = (1u << 7), eVariablePathCompletion = (1u << 8), + eRegisterCompletion = (1u << 9), // 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 << 9) + eCustomCompletion = (1u << 10) }; static bool InvokeCommonCompletionCallbacks( @@ -81,6 +82,9 @@ class CommandCompletions { static void VariablePath(CommandInterpreter &interpreter, CompletionRequest &request, SearchFilter *searcher); + + static void Registers(CommandInterpreter &interpreter, + CompletionRequest &request, SearchFilter *searcher); }; } // namespace lldb_private diff --git a/lldb/source/Commands/CommandCompletions.cpp b/lldb/source/Commands/CommandCompletions.cpp index bc3a2ec4bd9e..1e903157c511 100644 --- a/lldb/source/Commands/CommandCompletions.cpp +++ b/lldb/source/Commands/CommandCompletions.cpp @@ -18,6 +18,7 @@ #include "lldb/Interpreter/OptionValueProperties.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/Variable.h" +#include "lldb/Target/RegisterContext.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/TildeExpressionResolver.h" @@ -55,6 +56,7 @@ bool CommandCompletions::InvokeCommonCompletionCallbacks( {ePlatformPluginCompletion, CommandCompletions::PlatformPluginNames}, {eArchitectureCompletion, CommandCompletions::ArchitectureNames}, {eVariablePathCompletion, CommandCompletions::VariablePath}, + {eRegisterCompletion, CommandCompletions::Registers}, {eNoCompletion, nullptr} // This one has to be last in the list. }; @@ -531,3 +533,20 @@ void CommandCompletions::VariablePath(CommandInterpreter &interpreter, SearchFilter *searcher) { Variable::AutoComplete(interpreter.GetExecutionContext(), request); } + +void CommandCompletions::Registers(CommandInterpreter &interpreter, + CompletionRequest &request, + SearchFilter *searcher) { + std::string reg_prefix = ""; + if (request.GetCursorArgumentPrefix().startswith("$")) + reg_prefix = "$"; + + RegisterContext *reg_ctx = + interpreter.GetExecutionContext().GetRegisterContext(); + const size_t reg_num = reg_ctx->GetRegisterCount(); + for (size_t reg_idx = 0; reg_idx < reg_num; ++reg_idx) { + const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex(reg_idx); + request.TryCompleteCurrentArg(reg_prefix + reg_info->name, + reg_info->alt_name); + } +} \ No newline at end of file diff --git a/lldb/source/Commands/CommandObjectRegister.cpp b/lldb/source/Commands/CommandObjectRegister.cpp index 2c5457396eca..56e8c3fb4b84 100644 --- a/lldb/source/Commands/CommandObjectRegister.cpp +++ b/lldb/source/Commands/CommandObjectRegister.cpp @@ -70,6 +70,17 @@ class CommandObjectRegisterRead : public CommandObjectParsed { ~CommandObjectRegisterRead() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + if (!m_exe_ctx.HasProcessScope()) + return; + + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eRegisterCompletion, + request, nullptr); + } + Options *GetOptions() override { return &m_option_group; } bool DumpRegister(const ExecutionContext &exe_ctx, Stream &strm, @@ -323,6 +334,17 @@ class CommandObjectRegisterWrite : public CommandObjectParsed { ~CommandObjectRegisterWrite() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + if (!m_exe_ctx.HasProcessScope() || request.GetCursorIndex() != 0) + return; + + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eRegisterCompletion, + request, nullptr); + } + protected: bool DoExecute(Args &command, CommandReturnObject &result) override { DataExtractor reg_data; diff --git a/lldb/test/API/functionalities/completion/TestCompletion.py b/lldb/test/API/functionalities/completion/TestCompletion.py index c2d3b919f1de..5e8f79934345 100644 --- a/lldb/test/API/functionalities/completion/TestCompletion.py +++ b/lldb/test/API/functionalities/completion/TestCompletion.py @@ -414,3 +414,66 @@ def test_symbol_name(self): # No completion for Qu because the candidate is # (anonymous namespace)::Quux(). self.complete_from_to('breakpoint set -n Qu', '') + + @skipIf(archs=no_match(['x86_64'])) + def test_register_read_and_write_on_x86(self): + """Test the completion of the commands register read and write on x86""" + + # The tab completion for "register read/write" won't work without a running process. + self.complete_from_to('register read ', + 'register read ') + self.complete_from_to('register write ', + 'register write ') + + self.build() + self.main_source_spec = lldb.SBFileSpec("main.cpp") + lldbutil.run_to_source_breakpoint(self, '// Break here', self.main_source_spec) + + # test cases for register read + self.complete_from_to('register read ', + ['rax', + 'rbx', + 'rcx']) + self.complete_from_to('register read r', + ['rax', + 'rbx', + 'rcx']) + self.complete_from_to('register read ra', + 'register read rax') + # register read can take multiple register names as arguments + self.complete_from_to('register read rax ', + ['rax', + 'rbx', + 'rcx']) + # complete with prefix '$' + self.completions_match('register read $rb', + ['$rbx', + '$rbp']) + self.completions_match('register read $ra', + ['$rax']) + self.complete_from_to('register read rax $', + ['\$rax', + '\$rbx', + '\$rcx']) + self.complete_from_to('register read $rax ', + ['rax', + 'rbx', + 'rcx']) + + # test cases for register write + self.complete_from_to('register write ', + ['rax', + 'rbx', + 'rcx']) + self.complete_from_to('register write r', + ['rax', + 'rbx', + 'rcx']) + self.complete_from_to('register write ra', + 'register write rax') + self.complete_from_to('register write rb', + ['rbx', + 'rbp']) + # register write can only take exact one register name as argument + self.complete_from_to('register write rbx ', + []) _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits