diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp --- a/lldb/source/Target/RegisterContextUnwind.cpp +++ b/lldb/source/Target/RegisterContextUnwind.cpp @@ -690,28 +690,29 @@ // -- or even more devious, we can actually oscillate between two CFA values. // Detect that here and break out to avoid a possible infinite loop in lldb // trying to unwind the stack. To detect when we have the same CFA value - // multiple times, we compare the - // CFA of the current - // frame with the 2nd next frame because in some specail case (e.g. signal - // hanlders, hand written assembly without ABI compliance) we can have 2 - // frames with the same - // CFA (in theory we - // can have arbitrary number of frames with the same CFA, but more then 2 is - // very very unlikely) + // multiple times, we compare the CFA of the current frame with the 2nd next + // frame because in some specail case (e.g. signal hanlders, hand written + // assembly without ABI compiance) we can have 2 frames with the same CFA (in + // theory we can have arbitrary number of frames with the same CFA, but more + // then 2 is very very unlikely). RegisterContextUnwind::SharedPtr next_frame = GetNextFrame(); - if (next_frame) { - RegisterContextUnwind::SharedPtr next_next_frame = - next_frame->GetNextFrame(); - addr_t next_next_frame_cfa = LLDB_INVALID_ADDRESS; - if (next_next_frame && next_next_frame->GetCFA(next_next_frame_cfa)) { - if (next_next_frame_cfa == m_cfa) { - // We have a loop in the stack unwind - return true; - } - } - } - return false; + if (!next_frame) + return false; + + RegisterContextUnwind::SharedPtr next_next_frame = next_frame->GetNextFrame(); + if (!next_next_frame) + return false; + + // Since the return address value can be restored not only from the stack but + // also from a register, don't consider frames with the same CFAs and different + // PCs as a loop. + if (m_current_pc.IsValid() && (m_current_pc != next_next_frame->GetPC())) + return false; + + addr_t next_next_frame_cfa = LLDB_INVALID_ADDRESS; + return next_next_frame->GetCFA(next_next_frame_cfa) && + next_next_frame_cfa == m_cfa; } bool RegisterContextUnwind::IsFrameZero() const { return m_frame_number == 0; }