forked from OSchip/llvm-project
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
This commit is contained in:
parent
83564056d4
commit
a14f4a7531
|
@ -34,10 +34,11 @@ public:
|
|||
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 @@ public:
|
|||
|
||||
static void VariablePath(CommandInterpreter &interpreter,
|
||||
CompletionRequest &request, SearchFilter *searcher);
|
||||
|
||||
static void Registers(CommandInterpreter &interpreter,
|
||||
CompletionRequest &request, SearchFilter *searcher);
|
||||
};
|
||||
|
||||
} // namespace lldb_private
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -70,6 +70,17 @@ public:
|
|||
|
||||
~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 @@ public:
|
|||
|
||||
~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;
|
||||
|
|
|
@ -414,3 +414,66 @@ class CommandLineCompletionTestCase(TestBase):
|
|||
# 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 ',
|
||||
[])
|
||||
|
|
Loading…
Reference in New Issue