mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-05-14 01:46:41 +00:00

Currently, the interpreter's context is not updated until a command is executed. This has resulted in the behavior of SB-interface functions and some commands depends on previous user actions. The interpreter's context can stay uninitialized, point to a currently selected target, or point to one of previously selected targets. This patch removes any usages of CommandInterpreter::UpdateExecutionContext. CommandInterpreter::HandleCommand* functions still may override context temporarily, but now they always restore it before exiting. CommandInterpreter saves overriden contexts to the stack, that makes nesting commands possible. Added test reproduces one of the issues. Without this fix, the last assertion fails because interpreter's execution context is empty until running "target list", so, the value of the global property was updated instead of process's local instance. Differential Revision: https://reviews.llvm.org/D92164
91 lines
3.7 KiB
C++
91 lines
3.7 KiB
C++
//===-- CommandObjectRegexCommand.cpp -------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "CommandObjectRegexCommand.h"
|
|
#include "lldb/Interpreter/CommandInterpreter.h"
|
|
#include "lldb/Interpreter/CommandReturnObject.h"
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
|
|
// CommandObjectRegexCommand constructor
|
|
CommandObjectRegexCommand::CommandObjectRegexCommand(
|
|
CommandInterpreter &interpreter, llvm::StringRef name, llvm::StringRef help,
|
|
llvm::StringRef syntax, uint32_t max_matches, uint32_t completion_type_mask,
|
|
bool is_removable)
|
|
: CommandObjectRaw(interpreter, name, help, syntax),
|
|
m_max_matches(max_matches), m_completion_type_mask(completion_type_mask),
|
|
m_entries(), m_is_removable(is_removable) {}
|
|
|
|
// Destructor
|
|
CommandObjectRegexCommand::~CommandObjectRegexCommand() {}
|
|
|
|
bool CommandObjectRegexCommand::DoExecute(llvm::StringRef command,
|
|
CommandReturnObject &result) {
|
|
EntryCollection::const_iterator pos, end = m_entries.end();
|
|
for (pos = m_entries.begin(); pos != end; ++pos) {
|
|
llvm::SmallVector<llvm::StringRef, 4> matches;
|
|
if (pos->regex.Execute(command, &matches)) {
|
|
std::string new_command(pos->command);
|
|
char percent_var[8];
|
|
size_t idx, percent_var_idx;
|
|
for (uint32_t match_idx = 1; match_idx <= m_max_matches; ++match_idx) {
|
|
if (match_idx < matches.size()) {
|
|
const std::string match_str = matches[match_idx].str();
|
|
const int percent_var_len =
|
|
::snprintf(percent_var, sizeof(percent_var), "%%%u", match_idx);
|
|
for (idx = 0; (percent_var_idx = new_command.find(
|
|
percent_var, idx)) != std::string::npos;) {
|
|
new_command.erase(percent_var_idx, percent_var_len);
|
|
new_command.insert(percent_var_idx, match_str);
|
|
idx += percent_var_idx + match_str.size();
|
|
}
|
|
}
|
|
}
|
|
// Interpret the new command and return this as the result!
|
|
if (m_interpreter.GetExpandRegexAliases())
|
|
result.GetOutputStream().Printf("%s\n", new_command.c_str());
|
|
// Pass in true for "no context switching". The command that called us
|
|
// should have set up the context appropriately, we shouldn't have to
|
|
// redo that.
|
|
return m_interpreter.HandleCommand(new_command.c_str(),
|
|
eLazyBoolCalculate, result);
|
|
}
|
|
}
|
|
result.SetStatus(eReturnStatusFailed);
|
|
if (!GetSyntax().empty())
|
|
result.AppendError(GetSyntax());
|
|
else
|
|
result.GetOutputStream() << "Command contents '" << command
|
|
<< "' failed to match any "
|
|
"regular expression in the '"
|
|
<< m_cmd_name << "' regex ";
|
|
return false;
|
|
}
|
|
|
|
bool CommandObjectRegexCommand::AddRegexCommand(llvm::StringRef re_cstr,
|
|
llvm::StringRef command_cstr) {
|
|
m_entries.resize(m_entries.size() + 1);
|
|
// Only add the regular expression if it compiles
|
|
m_entries.back().regex = RegularExpression(re_cstr);
|
|
if (m_entries.back().regex.IsValid()) {
|
|
m_entries.back().command = command_cstr.str();
|
|
return true;
|
|
}
|
|
// The regex didn't compile...
|
|
m_entries.pop_back();
|
|
return false;
|
|
}
|
|
|
|
void CommandObjectRegexCommand::HandleCompletion(CompletionRequest &request) {
|
|
if (m_completion_type_mask) {
|
|
CommandCompletions::InvokeCommonCompletionCallbacks(
|
|
GetCommandInterpreter(), m_completion_type_mask, request, nullptr);
|
|
}
|
|
}
|