diff options
| author | Jim Ingham <jingham@apple.com> | 2023-05-10 17:48:48 -0700 |
|---|---|---|
| committer | Jim Ingham <jingham@apple.com> | 2023-05-11 14:48:54 -0700 |
| commit | e19387e6936c9ccc6200b32f3affea7b1020664c (patch) | |
| tree | 17c33ecd481a53bdf768687de885a92d36c69746 /lldb/source/Target/StackFrameList.cpp | |
| parent | c45ee7c0fba8daa2b5b6b201faa99d02c01cce8b (diff) | |
We can't let GetStackFrameCount get interrupted or it will give the
wrong answer. Plus, it's useful in some places to have a way to force
the full stack to be created even in the face of
interruption. Moreover, most of the time when you're just getting
frames, you don't need to know the number of frames in the stack to
start with. You just keep calling
Thread::GetStackFrameAtIndex(index++) and when you get a null
StackFrameSP back, you're done. That's also more amenable to
interruption if you are doing some work frame by frame.
So this patch makes GetStackFrameCount always return the full count,
suspending interruption. I also went through all the places that use
GetStackFrameCount to make sure that they really needed the full stack
walk. In many cases, they did not. For instance frame select -r 10 was
getting the number of frames just to check whether cur_frame_idx + 10
was within the stack. It's better in that case to see if that frame
exists first, since that doesn't force a full stack walk, and only
deal with walking off the end of the stack if it doesn't...
I also added a test for some of these behaviors.
Differential Revision: https://reviews.llvm.org/D150236
Diffstat (limited to 'lldb/source/Target/StackFrameList.cpp')
| -rw-r--r-- | lldb/source/Target/StackFrameList.cpp | 57 |
1 files changed, 40 insertions, 17 deletions
diff --git a/lldb/source/Target/StackFrameList.cpp b/lldb/source/Target/StackFrameList.cpp index 86939a14a288..81e7b00ee995 100644 --- a/lldb/source/Target/StackFrameList.cpp +++ b/lldb/source/Target/StackFrameList.cpp @@ -85,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()) { @@ -436,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) @@ -474,13 +476,6 @@ void StackFrameList::GetFramesUpTo(uint32_t end_idx) { StackFrameSP unwind_frame_sp; Debugger &dbg = m_thread.GetProcess()->GetTarget().GetDebugger(); do { - // Check for interruption here when building the frames - this is the - // expensive part, Dump later on is cheap. - if (dbg.InterruptRequested()) { - Log *log = GetLog(LLDBLog::Host); - LLDB_LOG(log, "Interrupted %s", __FUNCTION__); - break; - } uint32_t idx = m_concrete_frames_fetched++; lldb::addr_t pc = LLDB_INVALID_ADDRESS; lldb::addr_t cfa = LLDB_INVALID_ADDRESS; @@ -512,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 && dbg.InterruptRequested()) { + Log *log = GetLog(LLDBLog::Host); + LLDB_LOG(log, "Interrupted %s", __FUNCTION__); + was_interrupted = true; + break; + } + const bool success = unwinder.GetFrameInfoAtIndex(idx, cfa, pc, behaves_like_zeroth_frame); if (!success) { @@ -624,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()); } @@ -672,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 @@ -947,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 (dbg.InterruptRequested()) { + Log *log = GetLog(LLDBLog::Host); + LLDB_LOG(log, "Interrupted %s", __FUNCTION__); + break; + } if (!frame_sp->GetStatus(strm, show_frame_info, num_frames_with_source > (first_frame - frame_idx), |
