diff options
author | Adrian Prantl <aprantl@apple.com> | 2024-08-20 16:01:22 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-08-20 16:01:22 -0700 |
commit | f01f80ce6ca7640bb0e267b84b1ed0e89b57e2d9 (patch) | |
tree | c38a79f19b1eef07a0b315cc067035d380a83c80 /lldb/source | |
parent | 1e9d0028d35ae69263aa848b4cb02245f442eb5c (diff) | |
download | llvm-f01f80ce6ca7640bb0e267b84b1ed0e89b57e2d9.zip llvm-f01f80ce6ca7640bb0e267b84b1ed0e89b57e2d9.tar.gz llvm-f01f80ce6ca7640bb0e267b84b1ed0e89b57e2d9.tar.bz2 |
[lldb] Extend frame recognizers to hide frames from backtraces (#104523)
Compilers and language runtimes often use helper functions that are
fundamentally uninteresting when debugging anything but the
compiler/runtime itself. This patch introduces a user-extensible
mechanism that allows for these frames to be hidden from backtraces and
automatically skipped over when navigating the stack with `up` and
`down`.
This does not affect the numbering of frames, so `f <N>` will still
provide access to the hidden frames. The `bt` output will also print a
hint that frames have been hidden.
My primary motivation for this feature is to hide thunks in the Swift
programming language, but I'm including an example recognizer for
`std::function::operator()` that I wished for myself many times while
debugging LLDB.
rdar://126629381
Example output. (Yes, my proof-of-concept recognizer could hide even
more frames if we had a method that returned the function name without
the return type or I used something that isn't based off regex, but it's
really only meant as an example).
before:
```
(lldb) thread backtrace --filtered=false
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
* frame #0: 0x0000000100001f04 a.out`foo(x=1, y=1) at main.cpp:4:10
frame #1: 0x0000000100003a00 a.out`decltype(std::declval<int (*&)(int, int)>()(std::declval<int>(), std::declval<int>())) std::__1::__invoke[abi:se200000]<int (*&)(int, int), int, int>(__f=0x000000016fdff280, __args=0x000000016fdff224, __args=0x000000016fdff220) at invoke.h:149:25
frame #2: 0x000000010000399c a.out`int std::__1::__invoke_void_return_wrapper<int, false>::__call[abi:se200000]<int (*&)(int, int), int, int>(__args=0x000000016fdff280, __args=0x000000016fdff224, __args=0x000000016fdff220) at invoke.h:216:12
frame #3: 0x0000000100003968 a.out`std::__1::__function::__alloc_func<int (*)(int, int), std::__1::allocator<int (*)(int, int)>, int (int, int)>::operator()[abi:se200000](this=0x000000016fdff280, __arg=0x000000016fdff224, __arg=0x000000016fdff220) at function.h:171:12
frame #4: 0x00000001000026bc a.out`std::__1::__function::__func<int (*)(int, int), std::__1::allocator<int (*)(int, int)>, int (int, int)>::operator()(this=0x000000016fdff278, __arg=0x000000016fdff224, __arg=0x000000016fdff220) at function.h:313:10
frame #5: 0x0000000100003c38 a.out`std::__1::__function::__value_func<int (int, int)>::operator()[abi:se200000](this=0x000000016fdff278, __args=0x000000016fdff224, __args=0x000000016fdff220) const at function.h:430:12
frame #6: 0x0000000100002038 a.out`std::__1::function<int (int, int)>::operator()(this= Function = foo(int, int) , __arg=1, __arg=1) const at function.h:989:10
frame #7: 0x0000000100001f64 a.out`main(argc=1, argv=0x000000016fdff4f8) at main.cpp:9:10
frame #8: 0x0000000183cdf154 dyld`start + 2476
(lldb)
```
after
```
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
* frame #0: 0x0000000100001f04 a.out`foo(x=1, y=1) at main.cpp:4:10
frame #1: 0x0000000100003a00 a.out`decltype(std::declval<int (*&)(int, int)>()(std::declval<int>(), std::declval<int>())) std::__1::__invoke[abi:se200000]<int (*&)(int, int), int, int>(__f=0x000000016fdff280, __args=0x000000016fdff224, __args=0x000000016fdff220) at invoke.h:149:25
frame #2: 0x000000010000399c a.out`int std::__1::__invoke_void_return_wrapper<int, false>::__call[abi:se200000]<int (*&)(int, int), int, int>(__args=0x000000016fdff280, __args=0x000000016fdff224, __args=0x000000016fdff220) at invoke.h:216:12
frame #6: 0x0000000100002038 a.out`std::__1::function<int (int, int)>::operator()(this= Function = foo(int, int) , __arg=1, __arg=1) const at function.h:989:10
frame #7: 0x0000000100001f64 a.out`main(argc=1, argv=0x000000016fdff4f8) at main.cpp:9:10
frame #8: 0x0000000183cdf154 dyld`start + 2476
Note: Some frames were hidden by frame recognizers
```
Diffstat (limited to 'lldb/source')
19 files changed, 204 insertions, 41 deletions
diff --git a/lldb/source/API/SBFrame.cpp b/lldb/source/API/SBFrame.cpp index 47fc886..2689ecb 100644 --- a/lldb/source/API/SBFrame.cpp +++ b/lldb/source/API/SBFrame.cpp @@ -1195,13 +1195,24 @@ bool SBFrame::IsArtificial() const { std::unique_lock<std::recursive_mutex> lock; ExecutionContext exe_ctx(m_opaque_sp.get(), lock); - StackFrame *frame = exe_ctx.GetFramePtr(); - if (frame) + if (StackFrame *frame = exe_ctx.GetFramePtr()) return frame->IsArtificial(); return false; } +bool SBFrame::IsHidden() const { + LLDB_INSTRUMENT_VA(this); + + std::unique_lock<std::recursive_mutex> lock; + ExecutionContext exe_ctx(m_opaque_sp.get(), lock); + + if (StackFrame *frame = exe_ctx.GetFramePtr()) + return frame->IsHidden(); + + return false; +} + const char *SBFrame::GetFunctionName() { LLDB_INSTRUMENT_VA(this); diff --git a/lldb/source/API/SBThread.cpp b/lldb/source/API/SBThread.cpp index 786f62b..140a292 100644 --- a/lldb/source/API/SBThread.cpp +++ b/lldb/source/API/SBThread.cpp @@ -1208,7 +1208,8 @@ bool SBThread::GetStatus(SBStream &status) const { ExecutionContext exe_ctx(m_opaque_sp.get(), lock); if (exe_ctx.HasThreadScope()) { - exe_ctx.GetThreadPtr()->GetStatus(strm, 0, 1, 1, true); + exe_ctx.GetThreadPtr()->GetStatus(strm, 0, 1, 1, true, + /*show_hidden=*/true); } else strm.PutCString("No status"); diff --git a/lldb/source/Commands/CommandCompletions.cpp b/lldb/source/Commands/CommandCompletions.cpp index 54f4b36..216aaf9 100644 --- a/lldb/source/Commands/CommandCompletions.cpp +++ b/lldb/source/Commands/CommandCompletions.cpp @@ -791,7 +791,7 @@ void CommandCompletions::ThreadIndexes(CommandInterpreter &interpreter, lldb::ThreadSP thread_sp; for (uint32_t idx = 0; (thread_sp = threads.GetThreadAtIndex(idx)); ++idx) { StreamString strm; - thread_sp->GetStatus(strm, 0, 1, 1, true); + thread_sp->GetStatus(strm, 0, 1, 1, true, /*show_hidden*/ true); request.TryCompleteCurrentArg(std::to_string(thread_sp->GetIndexID()), strm.GetString()); } @@ -835,7 +835,7 @@ void CommandCompletions::ThreadIDs(CommandInterpreter &interpreter, lldb::ThreadSP thread_sp; for (uint32_t idx = 0; (thread_sp = threads.GetThreadAtIndex(idx)); ++idx) { StreamString strm; - thread_sp->GetStatus(strm, 0, 1, 1, true); + thread_sp->GetStatus(strm, 0, 1, 1, true, /*show_hidden*/ true); request.TryCompleteCurrentArg(std::to_string(thread_sp->GetID()), strm.GetString()); } diff --git a/lldb/source/Commands/CommandObjectFrame.cpp b/lldb/source/Commands/CommandObjectFrame.cpp index 29e460f..46c75e3 100644 --- a/lldb/source/Commands/CommandObjectFrame.cpp +++ b/lldb/source/Commands/CommandObjectFrame.cpp @@ -278,6 +278,30 @@ protected: if (frame_idx == UINT32_MAX) frame_idx = 0; + // If moving up/down by one, skip over hidden frames. + if (*m_options.relative_frame_offset == 1 || + *m_options.relative_frame_offset == -1) { + uint32_t candidate_idx = frame_idx; + const unsigned max_depth = 12; + for (unsigned num_try = 0; num_try < max_depth; ++num_try) { + if (candidate_idx == 0 && *m_options.relative_frame_offset == -1) { + candidate_idx = UINT32_MAX; + break; + } + candidate_idx += *m_options.relative_frame_offset; + if (auto candidate_sp = thread->GetStackFrameAtIndex(candidate_idx)) { + if (candidate_sp->IsHidden()) + continue; + // Now candidate_idx is the first non-hidden frame. + break; + } + candidate_idx = UINT32_MAX; + break; + }; + if (candidate_idx != UINT32_MAX) + m_options.relative_frame_offset = candidate_idx - frame_idx; + } + if (*m_options.relative_frame_offset < 0) { if (static_cast<int32_t>(frame_idx) >= -*m_options.relative_frame_offset) diff --git a/lldb/source/Commands/CommandObjectMemory.cpp b/lldb/source/Commands/CommandObjectMemory.cpp index 137b1ad..baf5d91 100644 --- a/lldb/source/Commands/CommandObjectMemory.cpp +++ b/lldb/source/Commands/CommandObjectMemory.cpp @@ -1570,7 +1570,8 @@ protected: const bool stop_format = false; for (auto thread : thread_list) { - thread->GetStatus(*output_stream, 0, UINT32_MAX, 0, stop_format); + thread->GetStatus(*output_stream, 0, UINT32_MAX, 0, stop_format, + /*should_filter*/ false); } result.SetStatus(eReturnStatusSuccessFinishResult); diff --git a/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp index 605f872..6a89c16 100644 --- a/lldb/source/Commands/CommandObjectThread.cpp +++ b/lldb/source/Commands/CommandObjectThread.cpp @@ -89,6 +89,9 @@ public: "invalid boolean value for option '%c': %s", short_option, option_arg.data()); } break; + case 'u': + m_filtered_backtrace = false; + break; default: llvm_unreachable("Unimplemented option"); } @@ -99,6 +102,7 @@ public: m_count = UINT32_MAX; m_start = 0; m_extended_backtrace = false; + m_filtered_backtrace = true; } llvm::ArrayRef<OptionDefinition> GetDefinitions() override { @@ -109,6 +113,7 @@ public: uint32_t m_count; uint32_t m_start; bool m_extended_backtrace; + bool m_filtered_backtrace; }; CommandObjectThreadBacktrace(CommandInterpreter &interpreter) @@ -121,7 +126,10 @@ public: "call stacks.\n" "Use 'settings set frame-format' to customize the printing of " "frames in the backtrace and 'settings set thread-format' to " - "customize the thread header.", + "customize the thread header.\n" + "Customizable frame recognizers may filter out less interesting " + "frames, which results in gaps in the numbering. " + "Use '-u' to see all frames.", nullptr, eCommandRequiresProcess | eCommandRequiresThread | eCommandTryTargetAPILock | eCommandProcessMustBeLaunched | @@ -199,7 +207,8 @@ protected: strm.PutChar('\n'); if (ext_thread_sp->GetStatus(strm, m_options.m_start, m_options.m_count, - num_frames_with_source, stop_format)) { + num_frames_with_source, stop_format, + !m_options.m_filtered_backtrace)) { DoExtendedBacktrace(ext_thread_sp.get(), result); } } @@ -228,7 +237,8 @@ protected: const uint32_t num_frames_with_source = 0; const bool stop_format = true; if (!thread->GetStatus(strm, m_options.m_start, m_options.m_count, - num_frames_with_source, stop_format, only_stacks)) { + num_frames_with_source, stop_format, + !m_options.m_filtered_backtrace, only_stacks)) { result.AppendErrorWithFormat( "error displaying backtrace for thread: \"0x%4.4x\"\n", thread->GetIndexID()); @@ -1392,7 +1402,8 @@ public: const uint32_t num_frames_with_source = 0; const bool stop_format = false; exception_thread_sp->GetStatus(strm, 0, UINT32_MAX, - num_frames_with_source, stop_format); + num_frames_with_source, stop_format, + /*filtered*/ false); } return true; diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td index f050cd2..9c4dbed 100644 --- a/lldb/source/Commands/Options.td +++ b/lldb/source/Commands/Options.td @@ -1048,6 +1048,8 @@ let Command = "thread backtrace" in { Arg<"FrameIndex">, Desc<"Frame in which to start the backtrace">; def thread_backtrace_extended : Option<"extended", "e">, Group<1>, Arg<"Boolean">, Desc<"Show the extended backtrace, if available">; + def thread_backtrace_unfiltered : Option<"unfiltered", "u">, Group<1>, + Desc<"Filter out frames according to installed frame recognizers">; } let Command = "thread step scope" in { diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index 309e01e..67f01707a 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -1869,7 +1869,8 @@ void Debugger::HandleThreadEvent(const EventSP &event_sp) { ThreadSP thread_sp( Thread::ThreadEventData::GetThreadFromEvent(event_sp.get())); if (thread_sp) { - thread_sp->GetStatus(*GetAsyncOutputStream(), 0, 1, 1, stop_format); + thread_sp->GetStatus(*GetAsyncOutputStream(), 0, 1, 1, stop_format, + /*show_hidden*/ true); } } } diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp index e451125..8729880 100644 --- a/lldb/source/Interpreter/CommandInterpreter.cpp +++ b/lldb/source/Interpreter/CommandInterpreter.cpp @@ -835,11 +835,12 @@ void CommandInterpreter::LoadCommandDictionary() { std::unique_ptr<CommandObjectRegexCommand> bt_regex_cmd_up( new CommandObjectRegexCommand( *this, "_regexp-bt", - "Show backtrace of the current thread's call stack. Any numeric " - "argument displays at most that many frames. The argument 'all' " - "displays all threads. Use 'settings set frame-format' to customize " + "Show backtrace of the current thread's call stack. Any numeric " + "argument displays at most that many frames. The argument 'all' " + "displays all threads. Use 'settings set frame-format' to customize " "the printing of individual frames and 'settings set thread-format' " - "to customize the thread header.", + "to customize the thread header. Frame recognizers may filter the" + "list. Use 'thread backtrace -u (--unfiltered)' to see them all.", "bt [<digit> | all]", 0, false)); if (bt_regex_cmd_up) { // accept but don't document "bt -c <number>" -- before bt was a regex diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp index c7202a4..c60200a 100644 --- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp @@ -26,6 +26,7 @@ #include "lldb/Target/RegisterContext.h" #include "lldb/Target/SectionLoadList.h" #include "lldb/Target/StackFrame.h" +#include "lldb/Target/StackFrameRecognizer.h" #include "lldb/Target/ThreadPlanRunToAddress.h" #include "lldb/Target/ThreadPlanStepInRange.h" #include "lldb/Utility/Timer.h" @@ -40,8 +41,49 @@ static ConstString g_coro_frame = ConstString("__coro_frame"); char CPPLanguageRuntime::ID = 0; +/// A frame recognizer that is installed to hide libc++ implementation +/// details from the backtrace. +class LibCXXFrameRecognizer : public StackFrameRecognizer { + RegularExpression m_hidden_function_regex; + RecognizedStackFrameSP m_hidden_frame; + + struct LibCXXHiddenFrame : public RecognizedStackFrame { + bool ShouldHide() override { return true; } + }; + +public: + LibCXXFrameRecognizer() + : m_hidden_function_regex( + R"(^std::__1::(__function.*::operator\(\)|__invoke))" + R"((\[.*\])?)" // ABI tag. + R"(( const)?$)"), // const. + m_hidden_frame(new LibCXXHiddenFrame()) {} + + std::string GetName() override { return "libc++ frame recognizer"; } + + lldb::RecognizedStackFrameSP + RecognizeFrame(lldb::StackFrameSP frame_sp) override { + if (!frame_sp) + return {}; + const auto &sc = frame_sp->GetSymbolContext(lldb::eSymbolContextFunction); + if (!sc.function) + return {}; + + if (m_hidden_function_regex.Execute(sc.function->GetNameNoArguments())) + return m_hidden_frame; + + return {}; + } +}; + CPPLanguageRuntime::CPPLanguageRuntime(Process *process) - : LanguageRuntime(process) {} + : LanguageRuntime(process) { + if (process) + process->GetTarget().GetFrameRecognizerManager().AddRecognizer( + StackFrameRecognizerSP(new LibCXXFrameRecognizer()), {}, + std::make_shared<RegularExpression>("^std::__1::"), + /*first_instruction_only*/ false); +} bool CPPLanguageRuntime::IsAllowedRuntimeValue(ConstString name) { return name == g_this || name == g_promise || name == g_coro_frame; diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h b/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h index 3026b61..5351c1a 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h +++ b/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h @@ -227,6 +227,9 @@ public: LLDBSwigPython_GetRecognizedArguments(PyObject *implementor, const lldb::StackFrameSP &frame_sp); + static bool LLDBSwigPython_ShouldHide(PyObject *implementor, + const lldb::StackFrameSP &frame_sp); + static bool LLDBSWIGPythonRunScriptKeywordProcess( const char *python_function_name, const char *session_dictionary_name, const lldb::ProcessSP &process, std::string &output); diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp index 335c482..2a94f11 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp +++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp @@ -1524,6 +1524,35 @@ lldb::ValueObjectListSP ScriptInterpreterPythonImpl::GetRecognizedArguments( return ValueObjectListSP(); } +bool ScriptInterpreterPythonImpl::ShouldHide( + const StructuredData::ObjectSP &os_plugin_object_sp, + lldb::StackFrameSP frame_sp) { + Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock); + + if (!os_plugin_object_sp) + return false; + + StructuredData::Generic *generic = os_plugin_object_sp->GetAsGeneric(); + if (!generic) + return false; + + PythonObject implementor(PyRefType::Borrowed, + (PyObject *)generic->GetValue()); + + if (!implementor.IsAllocated()) + return false; + + bool result = + SWIGBridge::LLDBSwigPython_ShouldHide(implementor.get(), frame_sp); + + // if it fails, print the error but otherwise go on + if (PyErr_Occurred()) { + PyErr_Print(); + PyErr_Clear(); + } + return result; +} + ScriptedProcessInterfaceUP ScriptInterpreterPythonImpl::CreateScriptedProcessInterface() { return std::make_unique<ScriptedProcessPythonInterface>(*this); diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h index c2024ef..85d7995 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h +++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h @@ -107,6 +107,9 @@ public: GetRecognizedArguments(const StructuredData::ObjectSP &implementor, lldb::StackFrameSP frame_sp) override; + bool ShouldHide(const StructuredData::ObjectSP &implementor, + lldb::StackFrameSP frame_sp) override; + lldb::ScriptedProcessInterfaceUP CreateScriptedProcessInterface() override; lldb::ScriptedThreadInterfaceSP CreateScriptedThreadInterface() override; diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index 3c9247fdb..b2a0f13 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -5545,7 +5545,8 @@ Process::RunThreadPlan(ExecutionContext &exe_ctx, // Print a backtrace into the log so we can figure out where we are: StreamString s; s.PutCString("Thread state after unsuccessful completion: \n"); - thread->GetStackFrameStatus(s, 0, UINT32_MAX, true, UINT32_MAX); + thread->GetStackFrameStatus(s, 0, UINT32_MAX, true, UINT32_MAX, + /*show_hidden*/ true); log->PutString(s.GetString()); } // Restore the thread state if we are going to discard the plan execution. @@ -5819,8 +5820,8 @@ size_t Process::GetThreadStatus(Stream &strm, continue; } thread_sp->GetStatus(strm, start_frame, num_frames, - num_frames_with_source, - stop_format); + num_frames_with_source, stop_format, + /*show_hidden*/ num_frames <= 1); ++num_thread_infos_dumped; } else { Log *log = GetLog(LLDBLog::Process); diff --git a/lldb/source/Target/StackFrame.cpp b/lldb/source/Target/StackFrame.cpp index 3a2b4d0..0ebaf55 100644 --- a/lldb/source/Target/StackFrame.cpp +++ b/lldb/source/Target/StackFrame.cpp @@ -1198,6 +1198,12 @@ bool StackFrame::IsArtificial() const { return m_stack_frame_kind == StackFrame::Kind::Artificial; } +bool StackFrame::IsHidden() { + if (auto recognized_frame_sp = GetRecognizedFrame()) + return recognized_frame_sp->ShouldHide(); + return false; +} + SourceLanguage StackFrame::GetLanguage() { CompileUnit *cu = GetSymbolContext(eSymbolContextCompUnit).comp_unit; if (cu) @@ -1971,12 +1977,16 @@ bool StackFrame::GetStatus(Stream &strm, bool show_frame_info, bool show_source, } RecognizedStackFrameSP StackFrame::GetRecognizedFrame() { - if (!m_recognized_frame_sp) { - m_recognized_frame_sp = GetThread() - ->GetProcess() - ->GetTarget() - .GetFrameRecognizerManager() - .RecognizeFrame(CalculateStackFrame()); - } - return m_recognized_frame_sp; + auto process = GetThread()->GetProcess(); + if (!process) + return {}; + // If recognizer list has been modified, discard cache. + auto &manager = process->GetTarget().GetFrameRecognizerManager(); + auto new_generation = manager.GetGeneration(); + if (m_frame_recognizer_generation != new_generation) + m_recognized_frame_sp.reset(); + m_frame_recognizer_generation = new_generation; + if (!m_recognized_frame_sp.has_value()) + m_recognized_frame_sp = manager.RecognizeFrame(CalculateStackFrame()); + return m_recognized_frame_sp.value(); } diff --git a/lldb/source/Target/StackFrameList.cpp b/lldb/source/Target/StackFrameList.cpp index 0cf9ce1..7808bd3 100644 --- a/lldb/source/Target/StackFrameList.cpp +++ b/lldb/source/Target/StackFrameList.cpp @@ -924,7 +924,7 @@ StackFrameList::GetStackFrameSPForStackFramePtr(StackFrame *stack_frame_ptr) { size_t StackFrameList::GetStatus(Stream &strm, uint32_t first_frame, uint32_t num_frames, bool show_frame_info, uint32_t num_frames_with_source, - bool show_unique, + bool show_unique, bool show_hidden, const char *selected_frame_marker) { size_t num_frames_displayed = 0; @@ -951,7 +951,6 @@ size_t StackFrameList::GetStatus(Stream &strm, uint32_t first_frame, unselected_marker = buffer.c_str(); } const char *marker = nullptr; - for (frame_idx = first_frame; frame_idx < last_frame; ++frame_idx) { frame_sp = GetFrameAtIndex(frame_idx); if (!frame_sp) @@ -963,6 +962,11 @@ size_t StackFrameList::GetStatus(Stream &strm, uint32_t first_frame, else marker = unselected_marker; } + + // Hide uninteresting frames unless it's the selected frame. + if (!show_hidden && frame_sp != selected_frame_sp && frame_sp->IsHidden()) + continue; + // Check for interruption here. If we're fetching arguments, this loop // can go slowly: Debugger &dbg = m_thread.GetProcess()->GetTarget().GetDebugger(); diff --git a/lldb/source/Target/StackFrameRecognizer.cpp b/lldb/source/Target/StackFrameRecognizer.cpp index 0ccb1ae..44411af 100644 --- a/lldb/source/Target/StackFrameRecognizer.cpp +++ b/lldb/source/Target/StackFrameRecognizer.cpp @@ -17,10 +17,14 @@ using namespace lldb; using namespace lldb_private; class ScriptedRecognizedStackFrame : public RecognizedStackFrame { + bool m_hidden; + public: - ScriptedRecognizedStackFrame(ValueObjectListSP args) { - m_arguments = args; + ScriptedRecognizedStackFrame(ValueObjectListSP args, bool hidden) + : m_hidden(hidden) { + m_arguments = std::move(args); } + bool ShouldHide() override { return m_hidden; } }; ScriptedStackFrameRecognizer::ScriptedStackFrameRecognizer( @@ -38,13 +42,22 @@ ScriptedStackFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame) { ValueObjectListSP args = m_interpreter->GetRecognizedArguments(m_python_object_sp, frame); auto args_synthesized = ValueObjectListSP(new ValueObjectList()); - for (const auto &o : args->GetObjects()) { - args_synthesized->Append(ValueObjectRecognizerSynthesizedValue::Create( - *o, eValueTypeVariableArgument)); + if (args) { + for (const auto &o : args->GetObjects()) + args_synthesized->Append(ValueObjectRecognizerSynthesizedValue::Create( + *o, eValueTypeVariableArgument)); } + bool hidden = m_interpreter->ShouldHide(m_python_object_sp, frame); + return RecognizedStackFrameSP( - new ScriptedRecognizedStackFrame(args_synthesized)); + new ScriptedRecognizedStackFrame(args_synthesized, hidden)); +} + +void StackFrameRecognizerManager::BumpGeneration() { + uint32_t n = m_generation; + n = (n + 1) & ((1 << 16) - 1); + m_generation = n; } void StackFrameRecognizerManager::AddRecognizer( @@ -53,6 +66,7 @@ void StackFrameRecognizerManager::AddRecognizer( m_recognizers.push_front({(uint32_t)m_recognizers.size(), recognizer, false, module, RegularExpressionSP(), symbols, RegularExpressionSP(), first_instruction_only}); + BumpGeneration(); } void StackFrameRecognizerManager::AddRecognizer( @@ -61,6 +75,7 @@ void StackFrameRecognizerManager::AddRecognizer( m_recognizers.push_front({(uint32_t)m_recognizers.size(), recognizer, true, ConstString(), module, std::vector<ConstString>(), symbol, first_instruction_only}); + BumpGeneration(); } void StackFrameRecognizerManager::ForEach( @@ -97,10 +112,12 @@ bool StackFrameRecognizerManager::RemoveRecognizerWithID( if (found == m_recognizers.end()) return false; m_recognizers.erase(found); + BumpGeneration(); return true; } void StackFrameRecognizerManager::RemoveAllRecognizers() { + BumpGeneration(); m_recognizers.clear(); } diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp index 74d1a26..fcf0f4e 100644 --- a/lldb/source/Target/Thread.cpp +++ b/lldb/source/Target/Thread.cpp @@ -1748,7 +1748,7 @@ std::string Thread::RunModeAsString(lldb::RunMode mode) { size_t Thread::GetStatus(Stream &strm, uint32_t start_frame, uint32_t num_frames, uint32_t num_frames_with_source, - bool stop_format, bool only_stacks) { + bool stop_format, bool show_hidden, bool only_stacks) { if (!only_stacks) { ExecutionContext exe_ctx(shared_from_this()); @@ -1795,7 +1795,7 @@ size_t Thread::GetStatus(Stream &strm, uint32_t start_frame, num_frames_shown = GetStackFrameList()->GetStatus( strm, start_frame, num_frames, show_frame_info, num_frames_with_source, - show_frame_unique, selected_frame_marker); + show_frame_unique, show_hidden, selected_frame_marker); if (num_frames == 1) strm.IndentLess(); strm.IndentLess(); @@ -1893,9 +1893,11 @@ bool Thread::GetDescription(Stream &strm, lldb::DescriptionLevel level, size_t Thread::GetStackFrameStatus(Stream &strm, uint32_t first_frame, uint32_t num_frames, bool show_frame_info, - uint32_t num_frames_with_source) { - return GetStackFrameList()->GetStatus( - strm, first_frame, num_frames, show_frame_info, num_frames_with_source); + uint32_t num_frames_with_source, + bool show_hidden) { + return GetStackFrameList()->GetStatus(strm, first_frame, num_frames, + show_frame_info, num_frames_with_source, + /*show_unique*/ false, show_hidden); } Unwind &Thread::GetUnwinder() { diff --git a/lldb/source/Target/ThreadPlanStepOut.cpp b/lldb/source/Target/ThreadPlanStepOut.cpp index 0a1e2ae..8ca1dbc 100644 --- a/lldb/source/Target/ThreadPlanStepOut.cpp +++ b/lldb/source/Target/ThreadPlanStepOut.cpp @@ -58,7 +58,7 @@ ThreadPlanStepOut::ThreadPlanStepOut( return; // we can't do anything here. ValidatePlan() will return false. // While stepping out, behave as-if artificial frames are not present. - while (return_frame_sp->IsArtificial()) { + while (return_frame_sp->IsArtificial() || return_frame_sp->IsHidden()) { m_stepped_past_frames.push_back(return_frame_sp); ++return_frame_index; |