diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2020-07-26 19:36:28 +0000 | 
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2020-07-26 19:36:28 +0000 | 
| commit | cfca06d7963fa0909f90483b42a6d7d194d01e08 (patch) | |
| tree | 209fb2a2d68f8f277793fc8df46c753d31bc853b /lldb/source/Plugins/Process/Utility/UnwindLLDB.cpp | |
| parent | 706b4fc47bbc608932d3b491ae19a3b9cde9497b (diff) | |
Notes
Diffstat (limited to 'lldb/source/Plugins/Process/Utility/UnwindLLDB.cpp')
| -rw-r--r-- | lldb/source/Plugins/Process/Utility/UnwindLLDB.cpp | 519 | 
1 files changed, 0 insertions, 519 deletions
diff --git a/lldb/source/Plugins/Process/Utility/UnwindLLDB.cpp b/lldb/source/Plugins/Process/Utility/UnwindLLDB.cpp deleted file mode 100644 index 74fc90e88547..000000000000 --- a/lldb/source/Plugins/Process/Utility/UnwindLLDB.cpp +++ /dev/null @@ -1,519 +0,0 @@ -//===-- UnwindLLDB.cpp -------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "lldb/Core/Module.h" -#include "lldb/Symbol/FuncUnwinders.h" -#include "lldb/Symbol/Function.h" -#include "lldb/Symbol/UnwindPlan.h" -#include "lldb/Target/ABI.h" -#include "lldb/Target/Process.h" -#include "lldb/Target/RegisterContext.h" -#include "lldb/Target/Target.h" -#include "lldb/Target/Thread.h" -#include "lldb/Utility/Log.h" - -#include "RegisterContextLLDB.h" -#include "UnwindLLDB.h" - -using namespace lldb; -using namespace lldb_private; - -UnwindLLDB::UnwindLLDB(Thread &thread) -    : Unwind(thread), m_frames(), m_unwind_complete(false), -      m_user_supplied_trap_handler_functions() { -  ProcessSP process_sp(thread.GetProcess()); -  if (process_sp) { -    Args args; -    process_sp->GetTarget().GetUserSpecifiedTrapHandlerNames(args); -    size_t count = args.GetArgumentCount(); -    for (size_t i = 0; i < count; i++) { -      const char *func_name = args.GetArgumentAtIndex(i); -      m_user_supplied_trap_handler_functions.push_back(ConstString(func_name)); -    } -  } -} - -uint32_t UnwindLLDB::DoGetFrameCount() { -  if (!m_unwind_complete) { -//#define DEBUG_FRAME_SPEED 1 -#if DEBUG_FRAME_SPEED -#define FRAME_COUNT 10000 -    using namespace std::chrono; -    auto time_value = steady_clock::now(); -#endif -    if (!AddFirstFrame()) -      return 0; - -    ProcessSP process_sp(m_thread.GetProcess()); -    ABI *abi = process_sp ? process_sp->GetABI().get() : nullptr; - -    while (AddOneMoreFrame(abi)) { -#if DEBUG_FRAME_SPEED -      if ((m_frames.size() % FRAME_COUNT) == 0) { -        const auto now = steady_clock::now(); -        const auto delta_t = now - time_value; -        printf("%u frames in %.9f ms (%g frames/sec)\n", FRAME_COUNT, -               duration<double, std::milli>(delta_t).count(), -               (float)FRAME_COUNT / duration<double>(delta_t).count()); -        time_value = now; -      } -#endif -    } -  } -  return m_frames.size(); -} - -bool UnwindLLDB::AddFirstFrame() { -  if (m_frames.size() > 0) -    return true; - -  ProcessSP process_sp(m_thread.GetProcess()); -  ABI *abi = process_sp ? process_sp->GetABI().get() : nullptr; - -  // First, set up the 0th (initial) frame -  CursorSP first_cursor_sp(new Cursor()); -  RegisterContextLLDBSP reg_ctx_sp(new RegisterContextLLDB( -      m_thread, RegisterContextLLDBSP(), first_cursor_sp->sctx, 0, *this)); -  if (reg_ctx_sp.get() == nullptr) -    goto unwind_done; - -  if (!reg_ctx_sp->IsValid()) -    goto unwind_done; - -  if (!reg_ctx_sp->GetCFA(first_cursor_sp->cfa)) -    goto unwind_done; - -  if (!reg_ctx_sp->ReadPC(first_cursor_sp->start_pc)) -    goto unwind_done; - -  // Everything checks out, so release the auto pointer value and let the -  // cursor own it in its shared pointer -  first_cursor_sp->reg_ctx_lldb_sp = reg_ctx_sp; -  m_frames.push_back(first_cursor_sp); - -  // Update the Full Unwind Plan for this frame if not valid -  UpdateUnwindPlanForFirstFrameIfInvalid(abi); - -  return true; - -unwind_done: -  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); -  if (log) { -    LLDB_LOGF(log, "th%d Unwind of this thread is complete.", -              m_thread.GetIndexID()); -  } -  m_unwind_complete = true; -  return false; -} - -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 nullptr; - -  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); - -  CursorSP prev_frame = m_frames.back(); -  uint32_t cur_idx = m_frames.size(); - -  CursorSP cursor_sp(new Cursor()); -  RegisterContextLLDBSP reg_ctx_sp(new RegisterContextLLDB( -      m_thread, prev_frame->reg_ctx_lldb_sp, cursor_sp->sctx, cur_idx, *this)); - -  uint64_t max_stack_depth = m_thread.GetMaxBacktraceDepth(); - -  // 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 you actually care about.  So you can't just cap the -  // unwind at 10,000 or something. Realistically anything over around 200,000 -  // is going to blow out the stack space. If we're still unwinding at that -  // point, we're probably never going to finish. -  if (cur_idx >= max_stack_depth) { -    LLDB_LOGF(log, -              "%*sFrame %d unwound too many frames, assuming unwind has " -              "gone astray, stopping.", -              cur_idx < 100 ? cur_idx : 100, "", cur_idx); -    return nullptr; -  } - -  if (reg_ctx_sp.get() == nullptr) { -    // If the RegisterContextLLDB has a fallback UnwindPlan, it will switch to -    // that and return true.  Subsequent calls to TryFallbackUnwindPlan() will -    // return false. -    if (prev_frame->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) { -      // TryFallbackUnwindPlan for prev_frame succeeded and updated -      // reg_ctx_lldb_sp field of prev_frame. However, cfa field of prev_frame -      // still needs to be updated. Hence updating it. -      if (!(prev_frame->reg_ctx_lldb_sp->GetCFA(prev_frame->cfa))) -        return nullptr; - -      return GetOneMoreFrame(abi); -    } - -    LLDB_LOGF(log, "%*sFrame %d did not get a RegisterContext, stopping.", -              cur_idx < 100 ? cur_idx : 100, "", cur_idx); -    return nullptr; -  } - -  if (!reg_ctx_sp->IsValid()) { -    // 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 (prev_frame->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) { -      // TryFallbackUnwindPlan for prev_frame succeeded and updated -      // reg_ctx_lldb_sp field of prev_frame. However, cfa field of prev_frame -      // still needs to be updated. Hence updating it. -      if (!(prev_frame->reg_ctx_lldb_sp->GetCFA(prev_frame->cfa))) -        return nullptr; - -      return GetOneMoreFrame(abi); -    } - -    LLDB_LOGF(log, -              "%*sFrame %d invalid RegisterContext for this frame, " -              "stopping stack walk", -              cur_idx < 100 ? cur_idx : 100, "", cur_idx); -    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 (prev_frame->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) { -      // TryFallbackUnwindPlan for prev_frame succeeded and updated -      // reg_ctx_lldb_sp field of prev_frame. However, cfa field of prev_frame -      // still needs to be updated. Hence updating it. -      if (!(prev_frame->reg_ctx_lldb_sp->GetCFA(prev_frame->cfa))) -        return nullptr; - -      return GetOneMoreFrame(abi); -    } - -    LLDB_LOGF(log, -              "%*sFrame %d did not get CFA for this frame, stopping stack walk", -              cur_idx < 100 ? cur_idx : 100, "", cur_idx); -    return nullptr; -  } -  if (abi && !abi->CallFrameAddressIsValid(cursor_sp->cfa)) { -    // On Mac OS X, the _sigtramp asynchronous signal trampoline frame may not -    // have its (constructed) CFA aligned correctly -- don't do the abi -    // alignment check for these. -    if (!reg_ctx_sp->IsTrapHandlerFrame()) { -      // See if we can find a fallback unwind plan for THIS frame.  It may be -      // that the UnwindPlan we're using for THIS frame was bad and gave us a -      // bad CFA. If that's not it, then see if we can change the UnwindPlan -      // for the frame below us ("NEXT") -- see if using that other UnwindPlan -      // gets us a better unwind state. -      if (!reg_ctx_sp->TryFallbackUnwindPlan() || -          !reg_ctx_sp->GetCFA(cursor_sp->cfa) || -          !abi->CallFrameAddressIsValid(cursor_sp->cfa)) { -        if (prev_frame->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) { -          // TryFallbackUnwindPlan for prev_frame succeeded and updated -          // reg_ctx_lldb_sp field of prev_frame. However, cfa field of -          // prev_frame still needs to be updated. Hence updating it. -          if (!(prev_frame->reg_ctx_lldb_sp->GetCFA(prev_frame->cfa))) -            return nullptr; - -          return GetOneMoreFrame(abi); -        } - -        LLDB_LOGF(log, -                  "%*sFrame %d did not get a valid CFA for this frame, " -                  "stopping stack walk", -                  cur_idx < 100 ? cur_idx : 100, "", cur_idx); -        return nullptr; -      } else { -        LLDB_LOGF(log, -                  "%*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); -      } -    } -  } -  if (!reg_ctx_sp->ReadPC(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 (prev_frame->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) { -      // TryFallbackUnwindPlan for prev_frame succeeded and updated -      // reg_ctx_lldb_sp field of prev_frame. However, cfa field of prev_frame -      // still needs to be updated. Hence updating it. -      if (!(prev_frame->reg_ctx_lldb_sp->GetCFA(prev_frame->cfa))) -        return nullptr; - -      return GetOneMoreFrame(abi); -    } - -    LLDB_LOGF(log, -              "%*sFrame %d did not get PC for this frame, stopping stack walk", -              cur_idx < 100 ? cur_idx : 100, "", cur_idx); -    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 (prev_frame->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) { -      // TryFallbackUnwindPlan for prev_frame succeeded and updated -      // reg_ctx_lldb_sp field of prev_frame. However, cfa field of prev_frame -      // still needs to be updated. Hence updating it. -      if (!(prev_frame->reg_ctx_lldb_sp->GetCFA(prev_frame->cfa))) -        return nullptr; - -      return GetOneMoreFrame(abi); -    } - -    LLDB_LOGF(log, "%*sFrame %d did not get a valid PC, stopping stack walk", -              cur_idx < 100 ? cur_idx : 100, "", cur_idx); -    return nullptr; -  } -  // 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) { -    LLDB_LOGF(log, -              "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; -  return cursor_sp; -} - -void UnwindLLDB::UpdateUnwindPlanForFirstFrameIfInvalid(ABI *abi) { -  // This function is called for First Frame only. -  assert(m_frames.size() == 1 && "No. of cursor frames are not 1"); - -  bool old_m_unwind_complete = m_unwind_complete; -  CursorSP old_m_candidate_frame = m_candidate_frame; - -  // Try to unwind 2 more frames using the Unwinder. It uses Full UnwindPlan -  // and if Full UnwindPlan fails, then uses FallBack UnwindPlan. Also update -  // the cfa of Frame 0 (if required). -  AddOneMoreFrame(abi); - -  // Remove all the frames added by above function as the purpose of using -  // above function was just to check whether Unwinder of Frame 0 works or not. -  for (uint32_t i = 1; i < m_frames.size(); i++) -    m_frames.pop_back(); - -  // Restore status after calling AddOneMoreFrame -  m_unwind_complete = old_m_unwind_complete; -  m_candidate_frame = old_m_candidate_frame; -  return; -} - -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) { -    LLDB_LOGF(log, "th%d Unwind of this thread is complete.", -              m_thread.GetIndexID()); -    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) { -    // If control reached here then TryFallbackUnwindPlan had succeeded for -    // Cursor::m_frames[m_frames.size() - 2]. It also succeeded to Unwind next -    // 2 frames i.e. m_frames[m_frames.size() - 1] and a frame after that. For -    // Cursor::m_frames[m_frames.size() - 2], reg_ctx_lldb_sp field was already -    // updated during TryFallbackUnwindPlan call above. However, cfa field -    // still needs to be updated. Hence updating it here and then returning. -    return m_frames[m_frames.size() - 2]->reg_ctx_lldb_sp->GetCFA( -        m_frames[m_frames.size() - 2]->cfa); -  } - -  // The new frame hasn'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 UnwindLLDB::DoGetFrameInfoAtIndex(uint32_t idx, addr_t &cfa, addr_t &pc, -                                       bool &behaves_like_zeroth_frame) { -  if (m_frames.size() == 0) { -    if (!AddFirstFrame()) -      return false; -  } - -  ProcessSP process_sp(m_thread.GetProcess()); -  ABI *abi = process_sp ? process_sp->GetABI().get() : nullptr; - -  while (idx >= m_frames.size() && AddOneMoreFrame(abi)) -    ; - -  if (idx < m_frames.size()) { -    cfa = m_frames[idx]->cfa; -    pc = m_frames[idx]->start_pc; -    if (idx == 0) { -      // Frame zero always behaves like it. -      behaves_like_zeroth_frame = true; -    } else if (m_frames[idx - 1]->reg_ctx_lldb_sp->IsTrapHandlerFrame()) { -      // This could be an asynchronous signal, thus the -      // pc might point to the interrupted instruction rather -      // than a post-call instruction -      behaves_like_zeroth_frame = true; -    } else if (m_frames[idx]->reg_ctx_lldb_sp->IsTrapHandlerFrame()) { -      // This frame may result from signal processing installing -      // a pointer to the first byte of a signal-return trampoline -      // in the return address slot of the frame below, so this -      // too behaves like the zeroth frame (i.e. the pc might not -      // be pointing just past a call in it) -      behaves_like_zeroth_frame = true; -    } else { -      behaves_like_zeroth_frame = false; -    } -    return true; -  } -  return false; -} - -lldb::RegisterContextSP -UnwindLLDB::DoCreateRegisterContextForFrame(StackFrame *frame) { -  lldb::RegisterContextSP reg_ctx_sp; -  uint32_t idx = frame->GetConcreteFrameIndex(); - -  if (idx == 0) { -    return m_thread.GetRegisterContext(); -  } - -  if (m_frames.size() == 0) { -    if (!AddFirstFrame()) -      return reg_ctx_sp; -  } - -  ProcessSP process_sp(m_thread.GetProcess()); -  ABI *abi = process_sp ? process_sp->GetABI().get() : nullptr; - -  while (idx >= m_frames.size()) { -    if (!AddOneMoreFrame(abi)) -      break; -  } - -  const uint32_t num_frames = m_frames.size(); -  if (idx < num_frames) { -    Cursor *frame_cursor = m_frames[idx].get(); -    reg_ctx_sp = frame_cursor->reg_ctx_lldb_sp; -  } -  return reg_ctx_sp; -} - -UnwindLLDB::RegisterContextLLDBSP -UnwindLLDB::GetRegisterContextForFrameNum(uint32_t frame_num) { -  RegisterContextLLDBSP reg_ctx_sp; -  if (frame_num < m_frames.size()) -    reg_ctx_sp = m_frames[frame_num]->reg_ctx_lldb_sp; -  return reg_ctx_sp; -} - -bool UnwindLLDB::SearchForSavedLocationForRegister( -    uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation ®loc, -    uint32_t starting_frame_num, bool pc_reg) { -  int64_t frame_num = starting_frame_num; -  if (static_cast<size_t>(frame_num) >= m_frames.size()) -    return false; - -  // Never interrogate more than one level while looking for the saved pc -  // value. If the value isn't saved by frame_num, none of the frames lower on -  // the stack will have a useful value. -  if (pc_reg) { -    UnwindLLDB::RegisterSearchResult result; -    result = m_frames[frame_num]->reg_ctx_lldb_sp->SavedLocationForRegister( -        lldb_regnum, regloc); -    return result == UnwindLLDB::RegisterSearchResult::eRegisterFound; -  } -  while (frame_num >= 0) { -    UnwindLLDB::RegisterSearchResult result; -    result = m_frames[frame_num]->reg_ctx_lldb_sp->SavedLocationForRegister( -        lldb_regnum, regloc); - -    // We descended down to the live register context aka stack frame 0 and are -    // reading the value out of a live register. -    if (result == UnwindLLDB::RegisterSearchResult::eRegisterFound && -        regloc.type == -            UnwindLLDB::RegisterLocation::eRegisterInLiveRegisterContext) { -      return true; -    } - -    // If we have unwind instructions saying that register N is saved in -    // register M in the middle of the stack (and N can equal M here, meaning -    // the register was not used in this function), then change the register -    // number we're looking for to M and keep looking for a concrete  location -    // down the stack, or an actual value from a live RegisterContext at frame -    // 0. -    if (result == UnwindLLDB::RegisterSearchResult::eRegisterFound && -        regloc.type == UnwindLLDB::RegisterLocation::eRegisterInRegister && -        frame_num > 0) { -      result = UnwindLLDB::RegisterSearchResult::eRegisterNotFound; -      lldb_regnum = regloc.location.register_number; -    } - -    if (result == UnwindLLDB::RegisterSearchResult::eRegisterFound) -      return true; -    if (result == UnwindLLDB::RegisterSearchResult::eRegisterIsVolatile) -      return false; -    frame_num--; -  } -  return false; -}  | 
