//===-- StackFrameList.cpp --------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "lldb/Target/StackFrameList.h" // C Includes // C++ Includes // Other libraries and framework includes // Project includes #include "lldb/Symbol/Block.h" #include "lldb/Symbol/Function.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/StackFrame.h" #include "lldb/Target/Thread.h" #include "lldb/Target/Unwind.h" using namespace lldb; using namespace lldb_private; //---------------------------------------------------------------------- // StackFrameList constructor //---------------------------------------------------------------------- StackFrameList::StackFrameList(Thread &thread, StackFrameList *prev_frames, bool show_inline_frames) : m_thread (thread), m_prev_frames_ap (prev_frames), m_show_inlined_frames (show_inline_frames), m_mutex (Mutex::eMutexTypeRecursive), m_unwind_frames (), m_inline_frames (), m_selected_frame_idx (0) { } //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- StackFrameList::~StackFrameList() { } uint32_t StackFrameList::GetNumFrames() { Mutex::Locker locker (m_mutex); if (m_show_inlined_frames) { if (m_inlined_info.empty()) { Unwind *unwinder = m_thread.GetUnwinder (); // If we are going to show inlined stack frames as actual frames, // we need to calculate all concrete frames first, then iterate // through all of them and count up how many inlined functions are // in each frame. We can then fill in m_inlined_info with // the concrete frame index and inlined depth const uint32_t concrete_frame_count = unwinder->GetFrameCount(); addr_t pc, cfa; InlinedFrameInfo inlined_frame_info; StackFrameSP frame_sp; for (uint32_t idx=0; idxGetSP(), m_thread.m_reg_context_sp->GetPC(), NULL)); } else { const bool success = unwinder->GetFrameInfoAtIndex(idx, cfa, pc); assert (success); frame_sp.reset (new StackFrame (m_inlined_info.size(), idx, m_thread, cfa, pc, NULL)); } SetUnwindFrameAtIndex (idx, frame_sp); Block *block = frame_sp->GetSymbolContext (eSymbolContextBlock).block; inlined_frame_info.unwind_frame_index = idx; inlined_frame_info.block = NULL; m_inlined_info.push_back (inlined_frame_info); if (block) { Block *inlined_block = block->GetContainingInlinedBlock(); if (inlined_block) { frame_sp->SetInlineBlockID (inlined_block->GetID()); while (inlined_block) { inlined_frame_info.block = inlined_block; m_inlined_info.push_back (inlined_frame_info); inlined_block = inlined_block->GetInlinedParent (); } } } } } return m_inlined_info.size(); } else { if (m_unwind_frames.empty()) m_unwind_frames.resize(m_thread.GetUnwinder()->GetFrameCount()); return m_unwind_frames.size(); } return 0; } lldb::StackFrameSP StackFrameList::GetUnwindFrameAtIndex (uint32_t idx) const { StackFrameSP frame_sp; if (idx < m_unwind_frames.size()) frame_sp = m_unwind_frames[idx]; return frame_sp; } lldb::StackFrameSP StackFrameList::GetInlineFrameAtIndex (uint32_t idx) const { StackFrameSP frame_sp; if (idx < m_inline_frames.size()) frame_sp = m_inline_frames[idx]; return frame_sp; } StackFrameSP StackFrameList::GetFrameAtIndex (uint32_t idx) { StackFrameSP frame_sp; { Mutex::Locker locker (m_mutex); if (m_show_inlined_frames) { frame_sp = GetInlineFrameAtIndex (idx); } else { frame_sp = GetUnwindFrameAtIndex (idx); } if (frame_sp.get()) return frame_sp; // Special case the first frame (idx == 0) so that we don't need to // know how many stack frames there are to get it. If we need any other // frames, then we do need to know if "idx" is a valid index. if (idx == 0) { // If this is the first frame, we want to share the thread register // context with the stack frame at index zero. m_thread.GetRegisterContext(); assert (m_thread.m_reg_context_sp.get()); frame_sp.reset (new StackFrame (0, 0, m_thread, m_thread.m_reg_context_sp, m_thread.m_reg_context_sp->GetSP(), m_thread.m_reg_context_sp->GetPC(), NULL)); if (m_show_inlined_frames && idx + 1 < m_inlined_info.size()) { if (m_inlined_info[idx].unwind_frame_index == m_inlined_info[idx+1].unwind_frame_index) frame_sp->SetInlineBlockID (frame_sp->GetSymbolContext (eSymbolContextBlock).block->GetID()); } } else if (idx < GetNumFrames()) { if (m_show_inlined_frames) { if (m_inlined_info[idx].block == NULL) { // Same as the concrete stack frame if block is NULL assert (m_inlined_info[idx].unwind_frame_index < m_unwind_frames.size()); frame_sp = GetUnwindFrameAtIndex (m_inlined_info[idx].unwind_frame_index); if (idx + 1 < m_inlined_info.size()) { if (m_inlined_info[idx].unwind_frame_index == m_inlined_info[idx+1].unwind_frame_index) frame_sp->SetInlineBlockID (frame_sp->GetSymbolContext (eSymbolContextBlock).block->GetID()); } } else { // We have blocks that were above an inlined function. Inlined // functions are represented as blocks with non-NULL inline // function info. Here we must reconstruct a frame by looking // at the block StackFrameSP previous_frame_sp (m_thread.GetStackFrameAtIndex (idx-1)); SymbolContext inline_sc; Block *inlined_parent_block = m_inlined_info[idx].block->GetInlinedParent(); if (inlined_parent_block) inlined_parent_block->CalculateSymbolContext (&inline_sc); else { Block *parent_block = m_inlined_info[idx].block->GetParent(); parent_block->CalculateSymbolContext(&inline_sc); } Address previous_frame_lookup_addr (previous_frame_sp->GetFrameCodeAddress()); if (previous_frame_sp->GetFrameIndex() > 0 && m_inlined_info[idx-1].block == NULL) previous_frame_lookup_addr.Slide (-1); AddressRange range; m_inlined_info[idx].block->GetRangeContainingAddress (previous_frame_lookup_addr, range); const InlineFunctionInfo* inline_info = m_inlined_info[idx].block->InlinedFunctionInfo(); assert (inline_info); inline_sc.line_entry.range.GetBaseAddress() = previous_frame_sp->GetFrameCodeAddress(); inline_sc.line_entry.file = inline_info->GetCallSite().GetFile(); inline_sc.line_entry.line = inline_info->GetCallSite().GetLine(); inline_sc.line_entry.column = inline_info->GetCallSite().GetColumn(); StackFrameSP concrete_frame_sp (GetUnwindFrameAtIndex (m_inlined_info[idx].unwind_frame_index)); assert (previous_frame_sp.get()); frame_sp.reset (new StackFrame (idx, m_inlined_info[idx].unwind_frame_index, m_thread, concrete_frame_sp->GetRegisterContextSP (), concrete_frame_sp->GetStackID().GetCallFrameAddress(), // CFA range.GetBaseAddress(), &inline_sc)); // The symbol context for this inline frame if (idx + 1 < m_inlined_info.size()) { if (m_inlined_info[idx].unwind_frame_index == m_inlined_info[idx+1].unwind_frame_index) frame_sp->SetInlineBlockID (m_inlined_info[idx].block->GetID()); } } } else { Unwind *unwinder = m_thread.GetUnwinder (); if (unwinder) { addr_t pc, cfa; if (unwinder->GetFrameInfoAtIndex(idx, cfa, pc)) frame_sp.reset (new StackFrame (idx, idx, m_thread, cfa, pc, NULL)); } } } if (m_show_inlined_frames) { SetInlineFrameAtIndex(idx, frame_sp); } else { SetUnwindFrameAtIndex(idx, frame_sp); } return frame_sp; } return frame_sp; } bool StackFrameList::SetUnwindFrameAtIndex (uint32_t idx, StackFrameSP &frame_sp) { if (idx >= m_unwind_frames.size()) m_unwind_frames.resize(idx + 1); // Make sure allocation succeeded by checking bounds again if (idx < m_unwind_frames.size()) { m_unwind_frames[idx] = frame_sp; return true; } return false; // resize failed, out of memory? } bool StackFrameList::SetInlineFrameAtIndex (uint32_t idx, StackFrameSP &frame_sp) { if (idx >= m_inline_frames.size()) m_inline_frames.resize(idx + 1); // Make sure allocation succeeded by checking bounds again if (idx < m_inline_frames.size()) { m_inline_frames[idx] = frame_sp; return true; } return false; // resize failed, out of memory? } uint32_t StackFrameList::GetSelectedFrameIndex () const { Mutex::Locker locker (m_mutex); return m_selected_frame_idx; } uint32_t StackFrameList::SetSelectedFrame (lldb_private::StackFrame *frame) { Mutex::Locker locker (m_mutex); const_iterator pos; const_iterator begin = m_show_inlined_frames ? m_inline_frames.begin() : m_unwind_frames.begin(); const_iterator end = m_show_inlined_frames ? m_inline_frames.end() : m_unwind_frames.end(); for (pos = begin; pos != end; ++pos) { if (pos->get() == frame) { m_selected_frame_idx = std::distance (begin, pos); return m_selected_frame_idx; } } m_selected_frame_idx = 0; return m_selected_frame_idx; } // Mark a stack frame as the current frame using the frame index void StackFrameList::SetSelectedFrameByIndex (uint32_t idx) { Mutex::Locker locker (m_mutex); m_selected_frame_idx = idx; } // The thread has been run, reset the number stack frames to zero so we can // determine how many frames we have lazily. void StackFrameList::Clear () { Mutex::Locker locker (m_mutex); m_unwind_frames.clear(); m_inline_frames.clear(); m_inlined_info.clear(); } void StackFrameList::InvalidateFrames (uint32_t start_idx) { Mutex::Locker locker (m_mutex); if (m_show_inlined_frames) { Clear(); } else { const size_t num_frames = m_unwind_frames.size(); while (start_idx < num_frames) { m_unwind_frames[start_idx].reset(); ++start_idx; } } }