Files
clang-p2996/lldb/source/Target/StackFrameList.cpp
Greg Clayton 0445d8f498 Cleaned up the inline stack frame code one more time to prepare for inlined
code stepping. Also we now store the stack frames for the current and previous
stops in the thread in std::auto_ptr objects. When we create a thread stack
frame list we pass the previous frame into it so it can re-use the frames
and maintain will allow for variable changes to be detected. I will implement
the stack frame reuse next.

llvm-svn: 112152
2010-08-26 02:28:22 +00:00

372 lines
13 KiB
C++

//===-- 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_current_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; idx<concrete_frame_count; ++idx)
{
if (idx == 0)
{
m_thread.GetRegisterContext();
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));
}
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::GetCurrentFrameIndex () const
{
Mutex::Locker locker (m_mutex);
return m_current_frame_idx;
}
uint32_t
StackFrameList::SetCurrentFrame (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_current_frame_idx = std::distance (begin, pos);
return m_current_frame_idx;
}
}
m_current_frame_idx = 0;
return m_current_frame_idx;
}
// Mark a stack frame as the current frame using the frame index
void
StackFrameList::SetCurrentFrameByIndex (uint32_t idx)
{
Mutex::Locker locker (m_mutex);
m_current_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;
}
}
}