diff options
Diffstat (limited to 'lldb/source/Target/StackFrameList.cpp')
| -rw-r--r-- | lldb/source/Target/StackFrameList.cpp | 122 |
1 files changed, 104 insertions, 18 deletions
diff --git a/lldb/source/Target/StackFrameList.cpp b/lldb/source/Target/StackFrameList.cpp index c782b506a9cb..2841f512439a 100644 --- a/lldb/source/Target/StackFrameList.cpp +++ b/lldb/source/Target/StackFrameList.cpp @@ -9,6 +9,7 @@ #include "lldb/Target/StackFrameList.h" #include "lldb/Breakpoint/Breakpoint.h" #include "lldb/Breakpoint/BreakpointLocation.h" +#include "lldb/Core/Debugger.h" #include "lldb/Core/SourceManager.h" #include "lldb/Core/StreamFile.h" #include "lldb/Symbol/Block.h" @@ -17,6 +18,7 @@ #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/StackFrame.h" +#include "lldb/Target/StackFrameRecognizer.h" #include "lldb/Target/StopInfo.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" @@ -37,7 +39,7 @@ StackFrameList::StackFrameList(Thread &thread, const lldb::StackFrameListSP &prev_frames_sp, bool show_inline_frames) : m_thread(thread), m_prev_frames_sp(prev_frames_sp), m_mutex(), m_frames(), - m_selected_frame_idx(0), m_concrete_frames_fetched(0), + m_selected_frame_idx(), m_concrete_frames_fetched(0), m_current_inlined_depth(UINT32_MAX), m_current_inlined_pc(LLDB_INVALID_ADDRESS), m_show_inlined_frames(show_inline_frames) { @@ -83,8 +85,8 @@ void StackFrameList::ResetCurrentInlinedDepth() { return; std::lock_guard<std::recursive_mutex> guard(m_mutex); - - GetFramesUpTo(0); + + GetFramesUpTo(0, DoNotAllowInterruption); if (m_frames.empty()) return; if (!m_frames[0]->IsInlined()) { @@ -251,7 +253,7 @@ struct CallDescriptor { using CallSequence = std::vector<CallDescriptor>; /// Find the unique path through the call graph from \p begin (with return PC -/// \p return_pc) to \p end. On success this path is stored into \p path, and +/// \p return_pc) to \p end. On success this path is stored into \p path, and /// on failure \p path is unchanged. static void FindInterveningFrames(Function &begin, Function &end, ExecutionContext &exe_ctx, Target &target, @@ -434,21 +436,23 @@ void StackFrameList::SynthesizeTailCallFrames(StackFrame &next_frame) { next_frame.SetFrameIndex(m_frames.size()); } -void StackFrameList::GetFramesUpTo(uint32_t end_idx) { +bool StackFrameList::GetFramesUpTo(uint32_t end_idx, + InterruptionControl allow_interrupt) { // Do not fetch frames for an invalid thread. + bool was_interrupted = false; if (!m_thread.IsValid()) - return; + return false; // We've already gotten more frames than asked for, or we've already finished // unwinding, return. if (m_frames.size() > end_idx || GetAllFramesFetched()) - return; + return false; Unwind &unwinder = m_thread.GetUnwinder(); if (!m_show_inlined_frames) { GetOnlyConcreteFramesUpTo(end_idx, unwinder); - return; + return false; } #if defined(DEBUG_STACK_FRAMES) @@ -470,6 +474,7 @@ void StackFrameList::GetFramesUpTo(uint32_t end_idx) { } StackFrameSP unwind_frame_sp; + Debugger &dbg = m_thread.GetProcess()->GetTarget().GetDebugger(); do { uint32_t idx = m_concrete_frames_fetched++; lldb::addr_t pc = LLDB_INVALID_ADDRESS; @@ -502,6 +507,15 @@ void StackFrameList::GetFramesUpTo(uint32_t end_idx) { cfa = unwind_frame_sp->m_id.GetCallFrameAddress(); } } else { + // Check for interruption when building the frames. + // Do the check in idx > 0 so that we'll always create a 0th frame. + if (allow_interrupt + && INTERRUPT_REQUESTED(dbg, "Interrupted having fetched {0} frames", + m_frames.size())) { + was_interrupted = true; + break; + } + const bool success = unwinder.GetFrameInfoAtIndex(idx, cfa, pc, behaves_like_zeroth_frame); if (!success) { @@ -614,14 +628,19 @@ void StackFrameList::GetFramesUpTo(uint32_t end_idx) { Dump(&s); s.EOL(); #endif + // Don't report interrupted if we happen to have gotten all the frames: + if (!GetAllFramesFetched()) + return was_interrupted; + return false; } uint32_t StackFrameList::GetNumFrames(bool can_create) { std::lock_guard<std::recursive_mutex> guard(m_mutex); - if (can_create) - GetFramesUpTo(UINT32_MAX); - + if (can_create) { + // Don't allow interrupt or we might not return the correct count + GetFramesUpTo(UINT32_MAX, DoNotAllowInterruption); + } return GetVisibleStackFrameIndex(m_frames.size()); } @@ -662,7 +681,13 @@ StackFrameSP StackFrameList::GetFrameAtIndex(uint32_t idx) { // GetFramesUpTo will fill m_frames with as many frames as you asked for, if // there are that many. If there weren't then you asked for too many frames. - GetFramesUpTo(idx); + // GetFramesUpTo returns true if interrupted: + if (GetFramesUpTo(idx)) { + Log *log = GetLog(LLDBLog::Thread); + LLDB_LOG(log, "GetFrameAtIndex was interrupted"); + return {}; + } + if (idx < m_frames.size()) { if (m_show_inlined_frames) { // When inline frames are enabled we actually create all the frames in @@ -772,9 +797,52 @@ bool StackFrameList::SetFrameAtIndex(uint32_t idx, StackFrameSP &frame_sp) { return false; // resize failed, out of memory? } -uint32_t StackFrameList::GetSelectedFrameIndex() const { +void StackFrameList::SelectMostRelevantFrame() { + // Don't call into the frame recognizers on the private state thread as + // they can cause code to run in the target, and that can cause deadlocks + // when fetching stop events for the expression. + if (m_thread.GetProcess()->CurrentThreadIsPrivateStateThread()) + return; + + Log *log = GetLog(LLDBLog::Thread); + + // Only the top frame should be recognized. + StackFrameSP frame_sp = GetFrameAtIndex(0); + if (!frame_sp) { + LLDB_LOG(log, "Failed to construct Frame #0"); + return; + } + + RecognizedStackFrameSP recognized_frame_sp = frame_sp->GetRecognizedFrame(); + + if (!recognized_frame_sp) { + LLDB_LOG(log, "Frame #0 not recognized"); + return; + } + + if (StackFrameSP most_relevant_frame_sp = + recognized_frame_sp->GetMostRelevantFrame()) { + LLDB_LOG(log, "Found most relevant frame at index {0}", + most_relevant_frame_sp->GetFrameIndex()); + SetSelectedFrame(most_relevant_frame_sp.get()); + } else { + LLDB_LOG(log, "No relevant frame!"); + } +} + +uint32_t StackFrameList::GetSelectedFrameIndex( + SelectMostRelevant select_most_relevant) { std::lock_guard<std::recursive_mutex> guard(m_mutex); - return m_selected_frame_idx; + if (!m_selected_frame_idx && select_most_relevant) + SelectMostRelevantFrame(); + if (!m_selected_frame_idx) { + // If we aren't selecting the most relevant frame, and the selected frame + // isn't set, then don't force a selection here, just return 0. + if (!select_most_relevant) + return 0; + m_selected_frame_idx = 0; + } + return *m_selected_frame_idx; } uint32_t StackFrameList::SetSelectedFrame(lldb_private::StackFrame *frame) { @@ -783,17 +851,19 @@ uint32_t StackFrameList::SetSelectedFrame(lldb_private::StackFrame *frame) { const_iterator begin = m_frames.begin(); const_iterator end = m_frames.end(); m_selected_frame_idx = 0; + for (pos = begin; pos != end; ++pos) { if (pos->get() == frame) { m_selected_frame_idx = std::distance(begin, pos); uint32_t inlined_depth = GetCurrentInlinedDepth(); if (inlined_depth != UINT32_MAX) - m_selected_frame_idx -= inlined_depth; + m_selected_frame_idx = *m_selected_frame_idx - inlined_depth; break; } } + SetDefaultFileAndLineToSelectedFrame(); - return m_selected_frame_idx; + return *m_selected_frame_idx; } bool StackFrameList::SetSelectedFrameByIndex(uint32_t idx) { @@ -809,7 +879,8 @@ bool StackFrameList::SetSelectedFrameByIndex(uint32_t idx) { void StackFrameList::SetDefaultFileAndLineToSelectedFrame() { if (m_thread.GetID() == m_thread.GetProcess()->GetThreadList().GetSelectedThread()->GetID()) { - StackFrameSP frame_sp(GetFrameAtIndex(GetSelectedFrameIndex())); + StackFrameSP frame_sp( + GetFrameAtIndex(GetSelectedFrameIndex(DoNoSelectMostRelevantFrame))); if (frame_sp) { SymbolContext sc = frame_sp->GetSymbolContext(eSymbolContextLineEntry); if (sc.line_entry.file) @@ -821,10 +892,16 @@ void StackFrameList::SetDefaultFileAndLineToSelectedFrame() { // The thread has been run, reset the number stack frames to zero so we can // determine how many frames we have lazily. +// Note, we don't actually re-use StackFrameLists, we always make a new +// StackFrameList every time we stop, and then copy frame information frame +// by frame from the old to the new StackFrameList. So the comment above, +// does not describe how StackFrameLists are currently used. +// Clear is currently only used to clear the list in the destructor. void StackFrameList::Clear() { std::lock_guard<std::recursive_mutex> guard(m_mutex); m_frames.clear(); m_concrete_frames_fetched = 0; + m_selected_frame_idx.reset(); } lldb::StackFrameSP @@ -863,7 +940,8 @@ size_t StackFrameList::GetStatus(Stream &strm, uint32_t first_frame, else last_frame = first_frame + num_frames; - StackFrameSP selected_frame_sp = m_thread.GetSelectedFrame(); + StackFrameSP selected_frame_sp = + m_thread.GetSelectedFrame(DoNoSelectMostRelevantFrame); const char *unselected_marker = nullptr; std::string buffer; if (selected_frame_marker) { @@ -884,6 +962,14 @@ size_t StackFrameList::GetStatus(Stream &strm, uint32_t first_frame, else marker = unselected_marker; } + // Check for interruption here. If we're fetching arguments, this loop + // can go slowly: + Debugger &dbg = m_thread.GetProcess()->GetTarget().GetDebugger(); + if (INTERRUPT_REQUESTED(dbg, + "Interrupted dumping stack for thread {0:hex} with {1} shown.", + m_thread.GetID(), num_frames_displayed)) + break; + if (!frame_sp->GetStatus(strm, show_frame_info, num_frames_with_source > (first_frame - frame_idx), |
