diff options
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; -} |