diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2015-09-06 14:32:30 +0000 | 
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2015-09-06 14:32:30 +0000 | 
| commit | 027f1c9655391dcb2b0117f931f720211ac933db (patch) | |
| tree | 94980f450aa3daec3e1fec217374704ad62cfe45 /source/Plugins/Process/Utility/UnwindLLDB.cpp | |
| parent | 5e95aa85bb660d45e9905ef1d7180b2678280660 (diff) | |
Notes
Diffstat (limited to 'source/Plugins/Process/Utility/UnwindLLDB.cpp')
| -rw-r--r-- | source/Plugins/Process/Utility/UnwindLLDB.cpp | 176 | 
1 files changed, 106 insertions, 70 deletions
diff --git a/source/Plugins/Process/Utility/UnwindLLDB.cpp b/source/Plugins/Process/Utility/UnwindLLDB.cpp index 02d3ecd7b3c5..1cdae9011673 100644 --- a/source/Plugins/Process/Utility/UnwindLLDB.cpp +++ b/source/Plugins/Process/Utility/UnwindLLDB.cpp @@ -120,29 +120,28 @@ unwind_done:      return false;  } -// For adding a non-zero stack frame to m_frames. -bool -UnwindLLDB::AddOneMoreFrame (ABI *abi) +UnwindLLDB::CursorSP +UnwindLLDB::GetOneMoreFrame (ABI* abi)  { +    assert (m_frames.size() != 0 && "Get one more frame called with empty frame list"); +      // If we've already gotten to the end of the stack, don't bother to try again...      if (m_unwind_complete) -        return false; +        return nullptr;      Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND)); -    CursorSP cursor_sp(new Cursor ()); -    // Frame zero is a little different -    if (m_frames.size() == 0) -        return false; +    CursorSP prev_frame = m_frames.back(); +    uint32_t cur_idx = m_frames.size(); -    uint32_t cur_idx = m_frames.size (); +    CursorSP cursor_sp(new Cursor ());      RegisterContextLLDBSP reg_ctx_sp(new RegisterContextLLDB (m_thread,  -                                                              m_frames[cur_idx - 1]->reg_ctx_lldb_sp,  +                                                              prev_frame->reg_ctx_lldb_sp,                                                                 cursor_sp->sctx,                                                                 cur_idx,                                                                 *this)); -    // We want to detect an unwind that cycles erronously and stop backtracing. +    // We want to detect an unwind that cycles erroneously and stop backtracing.      // Don't want this maximum unwind limit to be too low -- if you have a backtrace      // with an "infinitely recursing" bug, it will crash when the stack blows out      // and the first 35,000 frames are uninteresting - it's the top most 5 frames that @@ -154,21 +153,20 @@ UnwindLLDB::AddOneMoreFrame (ABI *abi)          if (log)              log->Printf ("%*sFrame %d unwound too many frames, assuming unwind has gone astray, stopping.",                            cur_idx < 100 ? cur_idx : 100, "", cur_idx); -        goto unwind_done; +        return nullptr;      }      if (reg_ctx_sp.get() == NULL)      {          // If the RegisterContextLLDB has a fallback UnwindPlan, it will switch to that and return          // true.  Subsequent calls to TryFallbackUnwindPlan() will return false. -        if (m_frames[cur_idx - 1]->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) -        { -            return AddOneMoreFrame (abi); -        } +        if (prev_frame->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) +            return GetOneMoreFrame (abi); +          if (log)              log->Printf ("%*sFrame %d did not get a RegisterContext, stopping.",                           cur_idx < 100 ? cur_idx : 100, "", cur_idx); -        goto unwind_done; +        return nullptr;      }      if (!reg_ctx_sp->IsValid()) @@ -176,31 +174,25 @@ UnwindLLDB::AddOneMoreFrame (ABI *abi)          // We failed to get a valid RegisterContext.          // See if the regctx below this on the stack has a fallback unwind plan it can use.          // Subsequent calls to TryFallbackUnwindPlan() will return false. -        if (m_frames[cur_idx - 1]->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) -        { -            return AddOneMoreFrame (abi); -        } +        if (prev_frame->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) +            return GetOneMoreFrame (abi); +          if (log) -        {              log->Printf("%*sFrame %d invalid RegisterContext for this frame, stopping stack walk",                           cur_idx < 100 ? cur_idx : 100, "", cur_idx); -        } -        goto unwind_done; +        return nullptr;      }      if (!reg_ctx_sp->GetCFA (cursor_sp->cfa))      {          // If the RegisterContextLLDB has a fallback UnwindPlan, it will switch to that and return          // true.  Subsequent calls to TryFallbackUnwindPlan() will return false. -        if (m_frames[cur_idx - 1]->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) -        { -            return AddOneMoreFrame (abi); -        } +        if (prev_frame->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) +            return GetOneMoreFrame (abi); +          if (log) -        {              log->Printf("%*sFrame %d did not get CFA for this frame, stopping stack walk",                          cur_idx < 100 ? cur_idx : 100, "", cur_idx); -        } -        goto unwind_done; +        return nullptr;      }      if (abi && !abi->CallFrameAddressIsValid(cursor_sp->cfa))      { @@ -219,24 +211,19 @@ UnwindLLDB::AddOneMoreFrame (ABI *abi)                  || reg_ctx_sp->GetCFA (cursor_sp->cfa) == false                  || abi->CallFrameAddressIsValid(cursor_sp->cfa) == false)              { -                if (m_frames[cur_idx - 1]->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) -                { -                    return AddOneMoreFrame (abi); -                } +                if (prev_frame->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) +                    return GetOneMoreFrame (abi); +                  if (log) -                {                      log->Printf("%*sFrame %d did not get a valid CFA for this frame, stopping stack walk",                                  cur_idx < 100 ? cur_idx : 100, "", cur_idx); -                } -                goto unwind_done; +                return nullptr;              }              else              {                  if (log) -                {                      log->Printf("%*sFrame %d had a bad CFA value but we switched the UnwindPlan being used and got one that looks more realistic.",                                  cur_idx < 100 ? cur_idx : 100, "", cur_idx); -                }              }          }      } @@ -244,54 +231,103 @@ UnwindLLDB::AddOneMoreFrame (ABI *abi)      {          // If the RegisterContextLLDB has a fallback UnwindPlan, it will switch to that and return          // true.  Subsequent calls to TryFallbackUnwindPlan() will return false. -        if (m_frames[cur_idx - 1]->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) -        { -            return AddOneMoreFrame (abi); -        } +        if (prev_frame->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) +            return GetOneMoreFrame (abi); +          if (log) -        {              log->Printf("%*sFrame %d did not get PC for this frame, stopping stack walk",                          cur_idx < 100 ? cur_idx : 100, "", cur_idx); -        } -        goto unwind_done; +        return nullptr;      }      if (abi && !abi->CodeAddressIsValid (cursor_sp->start_pc))      {          // If the RegisterContextLLDB has a fallback UnwindPlan, it will switch to that and return          // true.  Subsequent calls to TryFallbackUnwindPlan() will return false. -        if (m_frames[cur_idx - 1]->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) -        { -            return AddOneMoreFrame (abi); -        } +        if (prev_frame->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) +            return GetOneMoreFrame (abi); +          if (log) -        {              log->Printf("%*sFrame %d did not get a valid PC, stopping stack walk",                          cur_idx < 100 ? cur_idx : 100, "", cur_idx); -        } -        goto unwind_done; +        return nullptr;      } -    if (!m_frames.empty()) +    // Infinite loop where the current cursor is the same as the previous one... +    if (prev_frame->start_pc == cursor_sp->start_pc && prev_frame->cfa == cursor_sp->cfa)      { -        // Infinite loop where the current cursor is the same as the previous one... -        if (m_frames.back()->start_pc == cursor_sp->start_pc && m_frames.back()->cfa == cursor_sp->cfa) -        { -            if (log) -                log->Printf ("th%d pc of this frame is the same as the previous frame and CFAs for both frames are identical -- stopping unwind", m_thread.GetIndexID()); -            goto unwind_done;  -        } +        if (log) +            log->Printf ("th%d pc of this frame is the same as the previous frame and CFAs for both frames are identical -- stopping unwind", m_thread.GetIndexID()); +        return nullptr;      }      cursor_sp->reg_ctx_lldb_sp = reg_ctx_sp; -    m_frames.push_back (cursor_sp); -    return true; -     -unwind_done: -    if (log) +    return cursor_sp; +} + +bool +UnwindLLDB::AddOneMoreFrame (ABI *abi) +{ +    Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND)); + +    // Frame zero is a little different +    if (m_frames.empty()) +        return false; + +    // If we've already gotten to the end of the stack, don't bother to try again... +    if (m_unwind_complete) +        return false; + +    CursorSP new_frame = m_candidate_frame; +    if (new_frame == nullptr) +        new_frame = GetOneMoreFrame(abi); + +    if (new_frame == nullptr)      { -        log->Printf ("th%d Unwind of this thread is complete.", m_thread.GetIndexID()); +        if (log) +            log->Printf ("th%d Unwind of this thread is complete.", m_thread.GetIndexID()); +        m_unwind_complete = true; +        return false;      } -    m_unwind_complete = true; -    return false; + +    m_frames.push_back(new_frame); + +    // If we can get one more frame further then accept that we get back a correct frame. +    m_candidate_frame = GetOneMoreFrame(abi); +    if (m_candidate_frame) +        return true; + +    // We can't go further from the frame returned by GetOneMore frame. Lets try to get a +    // different frame with using the fallback unwind plan. +    if (!m_frames[m_frames.size() - 2]->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) +    { +        // We don't have a valid fallback unwind plan. Accept the frame as it is. This is a +        // valid situation when we are at the bottom of the stack. +        return true; +    } + +    // Remove the possibly incorrect frame from the frame list and try to add a different one with +    // the newly selected fallback unwind plan. +    m_frames.pop_back(); +    CursorSP new_frame_v2 = GetOneMoreFrame(abi); +    if (new_frame_v2 == nullptr) +    { +        // We haven't got a new frame from the fallback unwind plan. Accept the frame from the +        // original unwind plan. This is a valid situation when we are at the bottom of the stack. +        m_frames.push_back(new_frame); +        return true; +    } + +    // Push the new frame to the list and try to continue from this frame. If we can get a new frame +    // then accept it as the correct one. +    m_frames.push_back(new_frame_v2); +    m_candidate_frame = GetOneMoreFrame(abi); +    if (m_candidate_frame) +        return true; + +    // The new frame isn't helped in unwinding. Fall back to the original one as the default unwind +    // plan is usually more reliable then the fallback one. +    m_frames.pop_back(); +    m_frames.push_back(new_frame); +    return true;  }  bool  | 
