aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/lldb/source/Commands/CommandObjectFrame.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/lldb/source/Commands/CommandObjectFrame.cpp')
-rw-r--r--contrib/llvm-project/lldb/source/Commands/CommandObjectFrame.cpp187
1 files changed, 107 insertions, 80 deletions
diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectFrame.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectFrame.cpp
index 4a0d75202797..1390fd8748df 100644
--- a/contrib/llvm-project/lldb/source/Commands/CommandObjectFrame.cpp
+++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectFrame.cpp
@@ -135,7 +135,7 @@ public:
protected:
bool DoExecute(Args &command, CommandReturnObject &result) override {
Thread *thread = m_exe_ctx.GetThreadPtr();
- StackFrameSP frame_sp = thread->GetSelectedFrame();
+ StackFrameSP frame_sp = thread->GetSelectedFrame(SelectMostRelevantFrame);
ValueObjectSP valobj_sp;
@@ -292,9 +292,8 @@ public:
if (request.GetCursorIndex() != 0)
return;
- CommandCompletions::InvokeCommonCompletionCallbacks(
- GetCommandInterpreter(), CommandCompletions::eFrameIndexCompletion,
- request, nullptr);
+ lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
+ GetCommandInterpreter(), lldb::eFrameIndexCompletion, request, nullptr);
}
Options *GetOptions() override { return &m_options; }
@@ -308,7 +307,7 @@ protected:
uint32_t frame_idx = UINT32_MAX;
if (m_options.relative_frame_offset) {
// The one and only argument is a signed relative frame index
- frame_idx = thread->GetSelectedFrameIndex();
+ frame_idx = thread->GetSelectedFrameIndex(SelectMostRelevantFrame);
if (frame_idx == UINT32_MAX)
frame_idx = 0;
@@ -327,21 +326,29 @@ protected:
}
} else if (*m_options.relative_frame_offset > 0) {
// I don't want "up 20" where "20" takes you past the top of the stack
- // to produce
- // an error, but rather to just go to the top. So I have to count the
- // stack here...
- const uint32_t num_frames = thread->GetStackFrameCount();
- if (static_cast<int32_t>(num_frames - frame_idx) >
- *m_options.relative_frame_offset)
- frame_idx += *m_options.relative_frame_offset;
+ // to produce an error, but rather to just go to the top. OTOH, start
+ // by seeing if the requested frame exists, in which case we can avoid
+ // counting the stack here...
+ const uint32_t frame_requested = frame_idx
+ + *m_options.relative_frame_offset;
+ StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_requested);
+ if (frame_sp)
+ frame_idx = frame_requested;
else {
- if (frame_idx == num_frames - 1) {
- // If we are already at the top of the stack, just warn and don't
- // reset the frame.
- result.AppendError("Already at the top of the stack.");
- return false;
- } else
- frame_idx = num_frames - 1;
+ // The request went past the stack, so handle that case:
+ const uint32_t num_frames = thread->GetStackFrameCount();
+ if (static_cast<int32_t>(num_frames - frame_idx) >
+ *m_options.relative_frame_offset)
+ frame_idx += *m_options.relative_frame_offset;
+ else {
+ if (frame_idx == num_frames - 1) {
+ // If we are already at the top of the stack, just warn and don't
+ // reset the frame.
+ result.AppendError("Already at the top of the stack.");
+ return false;
+ } else
+ frame_idx = num_frames - 1;
+ }
}
}
} else {
@@ -362,7 +369,7 @@ protected:
return false;
}
} else if (command.GetArgumentCount() == 0) {
- frame_idx = thread->GetSelectedFrameIndex();
+ frame_idx = thread->GetSelectedFrameIndex(SelectMostRelevantFrame);
if (frame_idx == UINT32_MAX) {
frame_idx = 0;
}
@@ -372,7 +379,7 @@ protected:
bool success = thread->SetSelectedFrameByIndexNoisily(
frame_idx, result.GetOutputStream());
if (success) {
- m_exe_ctx.SetFrameSP(thread->GetSelectedFrame());
+ m_exe_ctx.SetFrameSP(thread->GetSelectedFrame(SelectMostRelevantFrame));
result.SetStatus(eReturnStatusSuccessFinishResult);
} else {
result.AppendErrorWithFormat("Frame index (%u) out of range.\n",
@@ -445,9 +452,9 @@ may even involve JITing and running code in the target program.)");
HandleArgumentCompletion(CompletionRequest &request,
OptionElementVector &opt_element_vector) override {
// Arguments are the standard source file completer.
- CommandCompletions::InvokeCommonCompletionCallbacks(
- GetCommandInterpreter(), CommandCompletions::eVariablePathCompletion,
- request, nullptr);
+ lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
+ GetCommandInterpreter(), lldb::eVariablePathCompletion, request,
+ nullptr);
}
protected:
@@ -473,6 +480,50 @@ protected:
return llvm::StringRef();
}
+ /// Returns true if `scope` matches any of the options in `m_option_variable`.
+ bool ScopeRequested(lldb::ValueType scope) {
+ switch (scope) {
+ case eValueTypeVariableGlobal:
+ case eValueTypeVariableStatic:
+ return m_option_variable.show_globals;
+ case eValueTypeVariableArgument:
+ return m_option_variable.show_args;
+ case eValueTypeVariableLocal:
+ return m_option_variable.show_locals;
+ case eValueTypeInvalid:
+ case eValueTypeRegister:
+ case eValueTypeRegisterSet:
+ case eValueTypeConstResult:
+ case eValueTypeVariableThreadLocal:
+ return false;
+ }
+ }
+
+ /// Finds all the variables in `all_variables` whose name matches `regex`,
+ /// inserting them into `matches`. Variables already contained in `matches`
+ /// are not inserted again.
+ /// Nullopt is returned in case of no matches.
+ /// A sub-range of `matches` with all newly inserted variables is returned.
+ /// This may be empty if all matches were already contained in `matches`.
+ std::optional<llvm::ArrayRef<VariableSP>>
+ findUniqueRegexMatches(RegularExpression &regex,
+ VariableList &matches,
+ const VariableList &all_variables) {
+ bool any_matches = false;
+ const size_t previous_num_vars = matches.GetSize();
+
+ for (const VariableSP &var : all_variables) {
+ if (!var->NameMatches(regex) || !ScopeRequested(var->GetScope()))
+ continue;
+ any_matches = true;
+ matches.AddVariableIfUnique(var);
+ }
+
+ if (any_matches)
+ return matches.toArrayRef().drop_front(previous_num_vars);
+ return std::nullopt;
+ }
+
bool DoExecute(Args &command, CommandReturnObject &result) override {
// No need to check "frame" for validity as eCommandRequiresFrame ensures
// it is valid
@@ -480,6 +531,10 @@ protected:
Stream &s = result.GetOutputStream();
+ // Using a regex should behave like looking for an exact name match: it
+ // also finds globals.
+ m_option_variable.show_globals |= m_option_variable.use_regex;
+
// Be careful about the stack frame, if any summary formatter runs code, it
// might clear the StackFrameList for the thread. So hold onto a shared
// pointer to the frame so it stays alive.
@@ -492,7 +547,6 @@ protected:
result.AppendError(error.AsCString());
}
- VariableSP var_sp;
ValueObjectSP valobj_sp;
TypeSummaryImplSP summary_format_sp;
@@ -525,46 +579,38 @@ protected:
// objects from them...
for (auto &entry : command) {
if (m_option_variable.use_regex) {
- const size_t regex_start_index = regex_var_list.GetSize();
llvm::StringRef name_str = entry.ref();
RegularExpression regex(name_str);
if (regex.IsValid()) {
- size_t num_matches = 0;
- const size_t num_new_regex_vars =
- variable_list->AppendVariablesIfUnique(regex, regex_var_list,
- num_matches);
- if (num_new_regex_vars > 0) {
- for (size_t regex_idx = regex_start_index,
- end_index = regex_var_list.GetSize();
- regex_idx < end_index; ++regex_idx) {
- var_sp = regex_var_list.GetVariableAtIndex(regex_idx);
- if (var_sp) {
- valobj_sp = frame->GetValueObjectForFrameVariable(
- var_sp, m_varobj_options.use_dynamic);
- if (valobj_sp) {
- std::string scope_string;
- if (m_option_variable.show_scope)
- scope_string = GetScopeString(var_sp).str();
-
- if (!scope_string.empty())
- s.PutCString(scope_string);
-
- if (m_option_variable.show_decl &&
- var_sp->GetDeclaration().GetFile()) {
- bool show_fullpaths = false;
- bool show_module = true;
- if (var_sp->DumpDeclaration(&s, show_fullpaths,
- show_module))
- s.PutCString(": ");
- }
- valobj_sp->Dump(result.GetOutputStream(), options);
- }
- }
- }
- } else if (num_matches == 0) {
+ std::optional<llvm::ArrayRef<VariableSP>> results =
+ findUniqueRegexMatches(regex, regex_var_list, *variable_list);
+ if (!results) {
result.AppendErrorWithFormat(
"no variables matched the regular expression '%s'.",
entry.c_str());
+ continue;
+ }
+ for (const VariableSP &var_sp : *results) {
+ valobj_sp = frame->GetValueObjectForFrameVariable(
+ var_sp, m_varobj_options.use_dynamic);
+ if (valobj_sp) {
+ std::string scope_string;
+ if (m_option_variable.show_scope)
+ scope_string = GetScopeString(var_sp).str();
+
+ if (!scope_string.empty())
+ s.PutCString(scope_string);
+
+ if (m_option_variable.show_decl &&
+ var_sp->GetDeclaration().GetFile()) {
+ bool show_fullpaths = false;
+ bool show_module = true;
+ if (var_sp->DumpDeclaration(&s, show_fullpaths,
+ show_module))
+ s.PutCString(": ");
+ }
+ valobj_sp->Dump(result.GetOutputStream(), options);
+ }
}
} else {
if (llvm::Error err = regex.GetError())
@@ -622,28 +668,9 @@ protected:
const size_t num_variables = variable_list->GetSize();
if (num_variables > 0) {
for (size_t i = 0; i < num_variables; i++) {
- var_sp = variable_list->GetVariableAtIndex(i);
- switch (var_sp->GetScope()) {
- case eValueTypeVariableGlobal:
- if (!m_option_variable.show_globals)
- continue;
- break;
- case eValueTypeVariableStatic:
- if (!m_option_variable.show_globals)
+ VariableSP var_sp = variable_list->GetVariableAtIndex(i);
+ if (!ScopeRequested(var_sp->GetScope()))
continue;
- break;
- case eValueTypeVariableArgument:
- if (!m_option_variable.show_args)
- continue;
- break;
- case eValueTypeVariableLocal:
- if (!m_option_variable.show_locals)
- continue;
- break;
- default:
- continue;
- break;
- }
std::string scope_string;
if (m_option_variable.show_scope)
scope_string = GetScopeString(var_sp).str();