2010-06-09 00:52:24 +08:00
|
|
|
//===-- StackFrameList.cpp --------------------------------------*- C++ -*-===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2010-08-25 08:35:26 +08:00
|
|
|
#include "lldb/Target/StackFrameList.h"
|
|
|
|
|
2010-06-09 00:52:24 +08:00
|
|
|
// C Includes
|
|
|
|
// C++ Includes
|
|
|
|
// Other libraries and framework includes
|
|
|
|
// Project includes
|
2010-08-28 02:24:16 +08:00
|
|
|
#include "lldb/Core/StreamFile.h"
|
2011-09-09 06:13:49 +08:00
|
|
|
#include "lldb/Core/SourceManager.h"
|
2010-08-25 08:35:26 +08:00
|
|
|
#include "lldb/Symbol/Block.h"
|
|
|
|
#include "lldb/Symbol/Function.h"
|
2010-08-31 02:11:35 +08:00
|
|
|
#include "lldb/Symbol/Symbol.h"
|
2011-09-09 06:13:49 +08:00
|
|
|
#include "lldb/Target/Process.h"
|
2010-08-25 08:35:26 +08:00
|
|
|
#include "lldb/Target/RegisterContext.h"
|
2010-06-09 00:52:24 +08:00
|
|
|
#include "lldb/Target/StackFrame.h"
|
2012-09-01 09:02:41 +08:00
|
|
|
#include "lldb/Target/StopInfo.h"
|
2011-09-09 06:13:49 +08:00
|
|
|
#include "lldb/Target/Target.h"
|
2010-08-25 08:35:26 +08:00
|
|
|
#include "lldb/Target/Thread.h"
|
|
|
|
#include "lldb/Target/Unwind.h"
|
2010-06-09 00:52:24 +08:00
|
|
|
|
2010-08-28 02:24:16 +08:00
|
|
|
//#define DEBUG_STACK_FRAMES 1
|
|
|
|
|
2010-06-09 00:52:24 +08:00
|
|
|
using namespace lldb;
|
|
|
|
using namespace lldb_private;
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// StackFrameList constructor
|
|
|
|
//----------------------------------------------------------------------
|
2010-09-04 01:10:42 +08:00
|
|
|
StackFrameList::StackFrameList
|
|
|
|
(
|
|
|
|
Thread &thread,
|
|
|
|
const lldb::StackFrameListSP &prev_frames_sp,
|
|
|
|
bool show_inline_frames
|
|
|
|
) :
|
2010-08-25 08:35:26 +08:00
|
|
|
m_thread (thread),
|
2010-09-04 01:10:42 +08:00
|
|
|
m_prev_frames_sp (prev_frames_sp),
|
2010-06-09 00:52:24 +08:00
|
|
|
m_mutex (Mutex::eMutexTypeRecursive),
|
2010-08-28 02:24:16 +08:00
|
|
|
m_frames (),
|
2011-04-12 03:41:40 +08:00
|
|
|
m_selected_frame_idx (0),
|
2012-02-29 11:40:22 +08:00
|
|
|
m_concrete_frames_fetched (0),
|
2012-09-01 09:02:41 +08:00
|
|
|
m_current_inlined_depth (UINT32_MAX),
|
|
|
|
m_current_inlined_pc (LLDB_INVALID_ADDRESS),
|
2011-04-12 03:41:40 +08:00
|
|
|
m_show_inlined_frames (show_inline_frames)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
2012-09-01 09:02:41 +08:00
|
|
|
if (prev_frames_sp)
|
|
|
|
{
|
|
|
|
m_current_inlined_depth = prev_frames_sp->m_current_inlined_depth;
|
|
|
|
m_current_inlined_pc = prev_frames_sp->m_current_inlined_pc;
|
|
|
|
}
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// Destructor
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
StackFrameList::~StackFrameList()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2012-09-01 09:02:41 +08:00
|
|
|
void
|
|
|
|
StackFrameList::CalculateCurrentInlinedDepth()
|
|
|
|
{
|
|
|
|
uint32_t cur_inlined_depth = GetCurrentInlinedDepth();
|
|
|
|
if (cur_inlined_depth == UINT32_MAX)
|
|
|
|
{
|
|
|
|
ResetCurrentInlinedDepth();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t
|
|
|
|
StackFrameList::GetCurrentInlinedDepth ()
|
|
|
|
{
|
|
|
|
if (m_show_inlined_frames)
|
|
|
|
{
|
|
|
|
lldb::addr_t cur_pc = m_thread.GetRegisterContext()->GetPC();
|
|
|
|
if (cur_pc != m_current_inlined_pc)
|
|
|
|
{
|
|
|
|
m_current_inlined_pc = LLDB_INVALID_ADDRESS;
|
|
|
|
m_current_inlined_depth = UINT32_MAX;
|
|
|
|
}
|
|
|
|
return m_current_inlined_depth;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return UINT32_MAX;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static const bool LLDB_FANCY_INLINED_STEPPING = false;
|
|
|
|
|
|
|
|
void
|
|
|
|
StackFrameList::ResetCurrentInlinedDepth ()
|
|
|
|
{
|
|
|
|
if (LLDB_FANCY_INLINED_STEPPING && m_show_inlined_frames)
|
|
|
|
{
|
|
|
|
GetFramesUpTo(0);
|
|
|
|
if (!m_frames[0]->IsInlined())
|
|
|
|
{
|
|
|
|
m_current_inlined_depth = UINT32_MAX;
|
|
|
|
m_current_inlined_pc = LLDB_INVALID_ADDRESS;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// We only need to do something special about inlined blocks when we
|
|
|
|
// are at the beginning of an inlined function:
|
|
|
|
// FIXME: We probably also have to do something special if the PC is at the END
|
|
|
|
// of an inlined function, which coincides with the end of either its containing
|
|
|
|
// function or another inlined function.
|
|
|
|
|
|
|
|
lldb::addr_t curr_pc = m_thread.GetRegisterContext()->GetPC();
|
|
|
|
Block *block_ptr = m_frames[0]->GetFrameBlock();
|
|
|
|
if (block_ptr)
|
|
|
|
{
|
|
|
|
Address pc_as_address;
|
|
|
|
pc_as_address.SetLoadAddress(curr_pc, &(m_thread.GetProcess()->GetTarget()));
|
|
|
|
AddressRange containing_range;
|
|
|
|
if (block_ptr->GetRangeContainingAddress(pc_as_address, containing_range))
|
|
|
|
{
|
|
|
|
if (pc_as_address == containing_range.GetBaseAddress())
|
|
|
|
{
|
|
|
|
// If we got here because of a breakpoint hit, then set the inlined depth depending on where
|
|
|
|
// the breakpoint was set.
|
|
|
|
// If we got here because of a crash, then set the inlined depth to the deepest most block.
|
|
|
|
// Otherwise, we stopped here naturally as the result of a step, so set ourselves in the
|
|
|
|
// containing frame of the whole set of nested inlines, so the user can then "virtually"
|
|
|
|
// step into the frames one by one, or next over the whole mess.
|
|
|
|
// Note: We don't have to handle being somewhere in the middle of the stack here, since
|
|
|
|
// ResetCurrentInlinedDepth doesn't get called if there is a valid inlined depth set.
|
|
|
|
StopInfoSP stop_info_sp = m_thread.GetStopInfo();
|
|
|
|
if (stop_info_sp)
|
|
|
|
{
|
|
|
|
switch (stop_info_sp->GetStopReason())
|
|
|
|
{
|
|
|
|
case eStopReasonBreakpoint:
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case eStopReasonWatchpoint:
|
|
|
|
case eStopReasonException:
|
|
|
|
case eStopReasonSignal:
|
|
|
|
// In all these cases we want to stop in the deepest most frame.
|
|
|
|
m_current_inlined_pc = curr_pc;
|
|
|
|
m_current_inlined_depth = 0;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
// Otherwise, we should set ourselves at the container of the inlining, so that the
|
|
|
|
// user can descend into them.
|
|
|
|
// So first we check whether we have more than one inlined block sharing this PC:
|
|
|
|
int num_inlined_functions = 0;
|
|
|
|
|
|
|
|
for (Block *container_ptr = block_ptr->GetInlinedParent();
|
|
|
|
container_ptr != NULL;
|
|
|
|
container_ptr = container_ptr->GetInlinedParent())
|
|
|
|
{
|
|
|
|
if (!container_ptr->GetRangeContainingAddress(pc_as_address, containing_range))
|
|
|
|
break;
|
|
|
|
if (pc_as_address != containing_range.GetBaseAddress())
|
|
|
|
break;
|
|
|
|
|
|
|
|
num_inlined_functions++;
|
|
|
|
}
|
|
|
|
m_current_inlined_pc = curr_pc;
|
|
|
|
m_current_inlined_depth = num_inlined_functions + 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
StackFrameList::DecrementCurrentInlinedDepth ()
|
|
|
|
{
|
|
|
|
if (m_show_inlined_frames)
|
|
|
|
{
|
|
|
|
uint32_t current_inlined_depth = GetCurrentInlinedDepth();
|
|
|
|
if (current_inlined_depth != UINT32_MAX)
|
|
|
|
{
|
|
|
|
if (current_inlined_depth > 0)
|
|
|
|
m_current_inlined_depth--;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-02-29 11:40:22 +08:00
|
|
|
void
|
|
|
|
StackFrameList::GetFramesUpTo(uint32_t end_idx)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
2012-02-29 11:40:22 +08:00
|
|
|
// We've already gotten more frames than asked for, or we've already finished unwinding, return.
|
|
|
|
if (m_frames.size() > end_idx || GetAllFramesFetched())
|
|
|
|
return;
|
|
|
|
|
|
|
|
Unwind *unwinder = m_thread.GetUnwinder ();
|
2010-08-25 08:35:26 +08:00
|
|
|
|
2012-02-29 11:40:22 +08:00
|
|
|
if (m_show_inlined_frames)
|
2010-08-25 08:35:26 +08:00
|
|
|
{
|
2010-08-28 02:24:16 +08:00
|
|
|
#if defined (DEBUG_STACK_FRAMES)
|
2012-02-29 11:40:22 +08:00
|
|
|
StreamFile s(stdout, false);
|
2010-08-28 02:24:16 +08:00
|
|
|
#endif
|
2012-09-01 09:02:41 +08:00
|
|
|
// If we are hiding some frames from the outside world, we need to add those onto the total count of
|
|
|
|
// frames to fetch. However, we don't need ot do that if end_idx is 0 since in that case we always
|
|
|
|
// get the first concrete frame and all the inlined frames below it...
|
|
|
|
|
|
|
|
uint32_t inlined_depth = 0;
|
|
|
|
if (end_idx > 0)
|
|
|
|
{
|
|
|
|
inlined_depth = GetCurrentInlinedDepth();
|
|
|
|
if (inlined_depth != UINT32_MAX)
|
|
|
|
{
|
|
|
|
if (end_idx > 0)
|
|
|
|
end_idx += inlined_depth;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
inlined_depth = 0;
|
|
|
|
}
|
2012-02-29 11:40:22 +08:00
|
|
|
|
|
|
|
StackFrameSP unwind_frame_sp;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
uint32_t idx = m_concrete_frames_fetched++;
|
|
|
|
lldb::addr_t pc;
|
|
|
|
lldb::addr_t cfa;
|
|
|
|
if (idx == 0)
|
2010-08-25 08:35:26 +08:00
|
|
|
{
|
2012-02-29 11:40:22 +08:00
|
|
|
// We might have already created frame zero, only create it
|
|
|
|
// if we need to
|
|
|
|
if (m_frames.empty())
|
2010-08-25 08:35:26 +08:00
|
|
|
{
|
2012-02-29 11:40:22 +08:00
|
|
|
m_thread.GetRegisterContext();
|
2012-03-01 03:58:25 +08:00
|
|
|
assert (m_thread.m_reg_context_sp.get());
|
2012-03-01 10:53:40 +08:00
|
|
|
|
|
|
|
const bool success = unwinder->GetFrameInfoAtIndex(idx, cfa, pc);
|
|
|
|
// There shouldn't be any way not to get the frame info for frame 0.
|
|
|
|
// But if the unwinder can't make one, lets make one by hand with the
|
|
|
|
// SP as the CFA and see if that gets any further.
|
|
|
|
if (!success)
|
|
|
|
{
|
|
|
|
cfa = m_thread.GetRegisterContext()->GetSP();
|
|
|
|
pc = m_thread.GetRegisterContext()->GetPC();
|
|
|
|
}
|
|
|
|
|
2012-02-29 11:40:22 +08:00
|
|
|
unwind_frame_sp.reset (new StackFrame (m_thread.shared_from_this(),
|
|
|
|
m_frames.size(),
|
2012-09-01 09:02:41 +08:00
|
|
|
idx,
|
2012-03-01 03:58:25 +08:00
|
|
|
m_thread.m_reg_context_sp,
|
2012-03-01 10:53:40 +08:00
|
|
|
cfa,
|
2012-03-01 03:58:25 +08:00
|
|
|
pc,
|
2012-02-29 11:40:22 +08:00
|
|
|
NULL));
|
|
|
|
m_frames.push_back (unwind_frame_sp);
|
2010-08-25 08:35:26 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-02-29 11:40:22 +08:00
|
|
|
unwind_frame_sp = m_frames.front();
|
|
|
|
cfa = unwind_frame_sp->m_id.GetCallFrameAddress();
|
2010-08-25 08:35:26 +08:00
|
|
|
}
|
2012-02-29 11:40:22 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
const bool success = unwinder->GetFrameInfoAtIndex(idx, cfa, pc);
|
|
|
|
if (!success)
|
2010-08-25 08:35:26 +08:00
|
|
|
{
|
2012-02-29 11:40:22 +08:00
|
|
|
// We've gotten to the end of the stack.
|
|
|
|
SetAllFramesFetched();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
unwind_frame_sp.reset (new StackFrame (m_thread.shared_from_this(), m_frames.size(), idx, cfa, pc, NULL));
|
|
|
|
m_frames.push_back (unwind_frame_sp);
|
|
|
|
}
|
|
|
|
|
|
|
|
SymbolContext unwind_sc = unwind_frame_sp->GetSymbolContext (eSymbolContextBlock | eSymbolContextFunction);
|
|
|
|
Block *unwind_block = unwind_sc.block;
|
|
|
|
if (unwind_block)
|
|
|
|
{
|
|
|
|
Address curr_frame_address (unwind_frame_sp->GetFrameCodeAddress());
|
|
|
|
// Be sure to adjust the frame address to match the address
|
|
|
|
// that was used to lookup the symbol context above. If we are
|
|
|
|
// in the first concrete frame, then we lookup using the current
|
|
|
|
// address, else we decrement the address by one to get the correct
|
|
|
|
// location.
|
|
|
|
if (idx > 0)
|
|
|
|
curr_frame_address.Slide(-1);
|
2011-10-01 08:45:15 +08:00
|
|
|
|
2012-02-29 11:40:22 +08:00
|
|
|
SymbolContext next_frame_sc;
|
|
|
|
Address next_frame_address;
|
|
|
|
|
|
|
|
while (unwind_sc.GetParentOfInlinedScope(curr_frame_address, next_frame_sc, next_frame_address))
|
|
|
|
{
|
|
|
|
StackFrameSP frame_sp(new StackFrame (m_thread.shared_from_this(),
|
|
|
|
m_frames.size(),
|
|
|
|
idx,
|
|
|
|
unwind_frame_sp->GetRegisterContextSP (),
|
|
|
|
cfa,
|
|
|
|
next_frame_address,
|
|
|
|
&next_frame_sc));
|
|
|
|
|
|
|
|
m_frames.push_back (frame_sp);
|
|
|
|
unwind_sc = next_frame_sc;
|
|
|
|
curr_frame_address = next_frame_address;
|
2010-08-28 02:24:16 +08:00
|
|
|
}
|
|
|
|
}
|
2012-02-29 11:40:22 +08:00
|
|
|
} while (m_frames.size() - 1 < end_idx);
|
2010-09-04 01:10:42 +08:00
|
|
|
|
2012-02-29 11:40:22 +08:00
|
|
|
// Don't try to merge till you've calculated all the frames in this stack.
|
|
|
|
if (GetAllFramesFetched() && m_prev_frames_sp)
|
|
|
|
{
|
|
|
|
StackFrameList *prev_frames = m_prev_frames_sp.get();
|
|
|
|
StackFrameList *curr_frames = this;
|
2010-08-28 02:24:16 +08:00
|
|
|
|
|
|
|
#if defined (DEBUG_STACK_FRAMES)
|
2012-02-29 11:40:22 +08:00
|
|
|
s.PutCString("\nprev_frames:\n");
|
|
|
|
prev_frames->Dump (&s);
|
|
|
|
s.PutCString("\ncurr_frames:\n");
|
|
|
|
curr_frames->Dump (&s);
|
|
|
|
s.EOL();
|
2010-08-28 02:24:16 +08:00
|
|
|
#endif
|
2012-02-29 11:40:22 +08:00
|
|
|
size_t curr_frame_num, prev_frame_num;
|
|
|
|
|
|
|
|
for (curr_frame_num = curr_frames->m_frames.size(), prev_frame_num = prev_frames->m_frames.size();
|
|
|
|
curr_frame_num > 0 && prev_frame_num > 0;
|
|
|
|
--curr_frame_num, --prev_frame_num)
|
|
|
|
{
|
|
|
|
const size_t curr_frame_idx = curr_frame_num-1;
|
|
|
|
const size_t prev_frame_idx = prev_frame_num-1;
|
|
|
|
StackFrameSP curr_frame_sp (curr_frames->m_frames[curr_frame_idx]);
|
|
|
|
StackFrameSP prev_frame_sp (prev_frames->m_frames[prev_frame_idx]);
|
2010-08-28 02:24:16 +08:00
|
|
|
|
|
|
|
#if defined (DEBUG_STACK_FRAMES)
|
2012-02-29 11:40:22 +08:00
|
|
|
s.Printf("\n\nCurr frame #%u ", curr_frame_idx);
|
|
|
|
if (curr_frame_sp)
|
|
|
|
curr_frame_sp->Dump (&s, true, false);
|
|
|
|
else
|
|
|
|
s.PutCString("NULL");
|
|
|
|
s.Printf("\nPrev frame #%u ", prev_frame_idx);
|
|
|
|
if (prev_frame_sp)
|
|
|
|
prev_frame_sp->Dump (&s, true, false);
|
|
|
|
else
|
|
|
|
s.PutCString("NULL");
|
2010-08-28 02:24:16 +08:00
|
|
|
#endif
|
|
|
|
|
2012-02-29 11:40:22 +08:00
|
|
|
StackFrame *curr_frame = curr_frame_sp.get();
|
|
|
|
StackFrame *prev_frame = prev_frame_sp.get();
|
|
|
|
|
|
|
|
if (curr_frame == NULL || prev_frame == NULL)
|
|
|
|
break;
|
|
|
|
|
|
|
|
// Check the stack ID to make sure they are equal
|
|
|
|
if (curr_frame->GetStackID() != prev_frame->GetStackID())
|
|
|
|
break;
|
|
|
|
|
|
|
|
prev_frame->UpdatePreviousFrameFromCurrentFrame (*curr_frame);
|
|
|
|
// Now copy the fixed up previous frame into the current frames
|
|
|
|
// so the pointer doesn't change
|
|
|
|
m_frames[curr_frame_idx] = prev_frame_sp;
|
|
|
|
//curr_frame->UpdateCurrentFrameFromPreviousFrame (*prev_frame);
|
|
|
|
|
2010-08-28 02:24:16 +08:00
|
|
|
#if defined (DEBUG_STACK_FRAMES)
|
2012-02-29 11:40:22 +08:00
|
|
|
s.Printf("\n Copying previous frame to current frame");
|
2010-08-28 02:24:16 +08:00
|
|
|
#endif
|
2010-08-25 08:35:26 +08:00
|
|
|
}
|
2012-02-29 11:40:22 +08:00
|
|
|
// We are done with the old stack frame list, we can release it now
|
|
|
|
m_prev_frames_sp.reset();
|
|
|
|
}
|
|
|
|
|
2010-08-28 05:47:54 +08:00
|
|
|
#if defined (DEBUG_STACK_FRAMES)
|
2012-02-29 11:40:22 +08:00
|
|
|
s.PutCString("\n\nNew frames:\n");
|
|
|
|
Dump (&s);
|
|
|
|
s.EOL();
|
2010-08-28 05:47:54 +08:00
|
|
|
#endif
|
2012-02-29 11:40:22 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (end_idx < m_concrete_frames_fetched)
|
|
|
|
return;
|
|
|
|
|
|
|
|
uint32_t num_frames = unwinder->GetFramesUpTo(end_idx);
|
|
|
|
if (num_frames <= end_idx + 1)
|
2010-08-28 02:24:16 +08:00
|
|
|
{
|
2012-02-29 11:40:22 +08:00
|
|
|
//Done unwinding.
|
|
|
|
m_concrete_frames_fetched = UINT32_MAX;
|
2010-08-28 02:24:16 +08:00
|
|
|
}
|
2012-02-29 11:40:22 +08:00
|
|
|
m_frames.resize(num_frames);
|
2010-08-25 08:35:26 +08:00
|
|
|
}
|
2012-02-29 11:40:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t
|
|
|
|
StackFrameList::GetNumFrames (bool can_create)
|
|
|
|
{
|
|
|
|
Mutex::Locker locker (m_mutex);
|
|
|
|
|
|
|
|
if (can_create)
|
|
|
|
GetFramesUpTo (UINT32_MAX);
|
2012-09-01 09:02:41 +08:00
|
|
|
|
|
|
|
uint32_t inlined_depth = GetCurrentInlinedDepth();
|
|
|
|
if (inlined_depth == UINT32_MAX)
|
|
|
|
return m_frames.size();
|
|
|
|
else
|
|
|
|
return m_frames.size() - inlined_depth;
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
|
|
|
|
2010-08-28 02:24:16 +08:00
|
|
|
void
|
|
|
|
StackFrameList::Dump (Stream *s)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
2010-08-28 02:24:16 +08:00
|
|
|
if (s == NULL)
|
|
|
|
return;
|
|
|
|
Mutex::Locker locker (m_mutex);
|
2010-08-25 08:35:26 +08:00
|
|
|
|
2010-08-28 02:24:16 +08:00
|
|
|
const_iterator pos, begin = m_frames.begin(), end = m_frames.end();
|
|
|
|
for (pos = begin; pos != end; ++pos)
|
|
|
|
{
|
|
|
|
StackFrame *frame = (*pos).get();
|
|
|
|
s->Printf("%p: ", frame);
|
|
|
|
if (frame)
|
2010-08-31 02:11:35 +08:00
|
|
|
{
|
|
|
|
frame->GetStackID().Dump (s);
|
2010-10-04 09:05:56 +08:00
|
|
|
frame->DumpUsingSettingsFormat (s);
|
2010-08-31 02:11:35 +08:00
|
|
|
}
|
2010-08-28 02:24:16 +08:00
|
|
|
else
|
2011-11-04 11:34:56 +08:00
|
|
|
s->Printf("frame #%u", (uint32_t)std::distance (begin, pos));
|
2010-08-28 02:24:16 +08:00
|
|
|
s->EOL();
|
|
|
|
}
|
|
|
|
s->EOL();
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
StackFrameSP
|
2010-08-25 08:35:26 +08:00
|
|
|
StackFrameList::GetFrameAtIndex (uint32_t idx)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
StackFrameSP frame_sp;
|
2010-08-28 02:24:16 +08:00
|
|
|
Mutex::Locker locker (m_mutex);
|
2012-09-01 09:02:41 +08:00
|
|
|
uint32_t inlined_depth = GetCurrentInlinedDepth();
|
|
|
|
if (inlined_depth != UINT32_MAX)
|
|
|
|
idx += inlined_depth;
|
|
|
|
|
2010-08-28 02:24:16 +08:00
|
|
|
if (idx < m_frames.size())
|
|
|
|
frame_sp = m_frames[idx];
|
2010-08-25 08:35:26 +08:00
|
|
|
|
2010-08-28 02:24:16 +08:00
|
|
|
if (frame_sp)
|
|
|
|
return frame_sp;
|
|
|
|
|
2012-03-01 03:58:25 +08:00
|
|
|
// GetFramesUpTo will fill m_frames with as many frames as you asked for,
|
|
|
|
// if there are that many. If there weren't then you asked for too many
|
|
|
|
// frames.
|
2012-02-29 11:40:22 +08:00
|
|
|
GetFramesUpTo (idx);
|
|
|
|
if (idx < m_frames.size())
|
2010-08-25 08:35:26 +08:00
|
|
|
{
|
2012-02-29 11:40:22 +08:00
|
|
|
if (m_show_inlined_frames)
|
|
|
|
{
|
2012-03-01 03:58:25 +08:00
|
|
|
// When inline frames are enabled we actually create all the frames in GetFramesUpTo.
|
2012-02-29 11:40:22 +08:00
|
|
|
frame_sp = m_frames[idx];
|
|
|
|
}
|
|
|
|
else
|
2010-08-28 02:24:16 +08:00
|
|
|
{
|
2012-02-29 11:40:22 +08:00
|
|
|
Unwind *unwinder = m_thread.GetUnwinder ();
|
|
|
|
if (unwinder)
|
2010-08-28 02:24:16 +08:00
|
|
|
{
|
2012-02-29 11:40:22 +08:00
|
|
|
addr_t pc, cfa;
|
|
|
|
if (unwinder->GetFrameInfoAtIndex(idx, cfa, pc))
|
2010-08-31 02:11:35 +08:00
|
|
|
{
|
2012-02-29 11:40:22 +08:00
|
|
|
frame_sp.reset (new StackFrame (m_thread.shared_from_this(), idx, idx, cfa, pc, NULL));
|
|
|
|
|
|
|
|
Function *function = frame_sp->GetSymbolContext (eSymbolContextFunction).function;
|
|
|
|
if (function)
|
|
|
|
{
|
|
|
|
// When we aren't showing inline functions we always use
|
|
|
|
// the top most function block as the scope.
|
|
|
|
frame_sp->SetSymbolContextScope (&function->GetBlock(false));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Set the symbol scope from the symbol regardless if it is NULL or valid.
|
|
|
|
frame_sp->SetSymbolContextScope (frame_sp->GetSymbolContext (eSymbolContextSymbol).symbol);
|
|
|
|
}
|
|
|
|
SetFrameAtIndex(idx, frame_sp);
|
2010-08-31 02:11:35 +08:00
|
|
|
}
|
2010-08-28 02:24:16 +08:00
|
|
|
}
|
|
|
|
}
|
2010-08-25 08:35:26 +08:00
|
|
|
}
|
2010-06-09 00:52:24 +08:00
|
|
|
return frame_sp;
|
|
|
|
}
|
|
|
|
|
2011-01-07 06:15:06 +08:00
|
|
|
StackFrameSP
|
|
|
|
StackFrameList::GetFrameWithConcreteFrameIndex (uint32_t unwind_idx)
|
|
|
|
{
|
|
|
|
// First try assuming the unwind index is the same as the frame index. The
|
|
|
|
// unwind index is always greater than or equal to the frame index, so it
|
|
|
|
// is a good place to start. If we have inlined frames we might have 5
|
|
|
|
// concrete frames (frame unwind indexes go from 0-4), but we might have 15
|
|
|
|
// frames after we make all the inlined frames. Most of the time the unwind
|
|
|
|
// frame index (or the concrete frame index) is the same as the frame index.
|
|
|
|
uint32_t frame_idx = unwind_idx;
|
|
|
|
StackFrameSP frame_sp (GetFrameAtIndex (frame_idx));
|
|
|
|
while (frame_sp)
|
|
|
|
{
|
|
|
|
if (frame_sp->GetFrameIndex() == unwind_idx)
|
|
|
|
break;
|
|
|
|
frame_sp = GetFrameAtIndex (++frame_idx);
|
|
|
|
}
|
|
|
|
return frame_sp;
|
|
|
|
}
|
|
|
|
|
2011-03-31 08:15:49 +08:00
|
|
|
StackFrameSP
|
2012-02-17 15:49:44 +08:00
|
|
|
StackFrameList::GetFrameWithStackID (const StackID &stack_id)
|
2011-03-31 08:15:49 +08:00
|
|
|
{
|
|
|
|
uint32_t frame_idx = 0;
|
|
|
|
StackFrameSP frame_sp;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
frame_sp = GetFrameAtIndex (frame_idx);
|
|
|
|
if (frame_sp && frame_sp->GetStackID() == stack_id)
|
|
|
|
break;
|
|
|
|
frame_idx++;
|
|
|
|
}
|
|
|
|
while (frame_sp);
|
|
|
|
return frame_sp;
|
|
|
|
}
|
2011-01-07 06:15:06 +08:00
|
|
|
|
2010-08-25 08:35:26 +08:00
|
|
|
bool
|
2010-08-28 02:24:16 +08:00
|
|
|
StackFrameList::SetFrameAtIndex (uint32_t idx, StackFrameSP &frame_sp)
|
2010-08-25 08:35:26 +08:00
|
|
|
{
|
2010-08-28 02:24:16 +08:00
|
|
|
if (idx >= m_frames.size())
|
|
|
|
m_frames.resize(idx + 1);
|
2010-08-25 08:35:26 +08:00
|
|
|
// Make sure allocation succeeded by checking bounds again
|
2010-08-28 02:24:16 +08:00
|
|
|
if (idx < m_frames.size())
|
2010-08-25 08:35:26 +08:00
|
|
|
{
|
2010-08-28 02:24:16 +08:00
|
|
|
m_frames[idx] = frame_sp;
|
2010-06-09 00:52:24 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false; // resize failed, out of memory?
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t
|
2010-08-27 05:32:51 +08:00
|
|
|
StackFrameList::GetSelectedFrameIndex () const
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
Mutex::Locker locker (m_mutex);
|
2010-08-27 05:32:51 +08:00
|
|
|
return m_selected_frame_idx;
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint32_t
|
2010-08-27 05:32:51 +08:00
|
|
|
StackFrameList::SetSelectedFrame (lldb_private::StackFrame *frame)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
Mutex::Locker locker (m_mutex);
|
2010-08-25 08:35:26 +08:00
|
|
|
const_iterator pos;
|
2010-08-28 02:24:16 +08:00
|
|
|
const_iterator begin = m_frames.begin();
|
|
|
|
const_iterator end = m_frames.end();
|
2011-09-09 06:13:49 +08:00
|
|
|
m_selected_frame_idx = 0;
|
2010-06-09 00:52:24 +08:00
|
|
|
for (pos = begin; pos != end; ++pos)
|
|
|
|
{
|
|
|
|
if (pos->get() == frame)
|
|
|
|
{
|
2010-08-27 05:32:51 +08:00
|
|
|
m_selected_frame_idx = std::distance (begin, pos);
|
2012-09-01 09:02:41 +08:00
|
|
|
uint32_t inlined_depth = GetCurrentInlinedDepth();
|
|
|
|
if (inlined_depth != UINT32_MAX)
|
|
|
|
m_selected_frame_idx -= inlined_depth;
|
2011-09-09 06:13:49 +08:00
|
|
|
break;
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
|
|
|
}
|
2011-09-09 06:13:49 +08:00
|
|
|
SetDefaultFileAndLineToSelectedFrame();
|
2010-08-27 05:32:51 +08:00
|
|
|
return m_selected_frame_idx;
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Mark a stack frame as the current frame using the frame index
|
2012-02-29 11:40:22 +08:00
|
|
|
bool
|
2010-08-27 05:32:51 +08:00
|
|
|
StackFrameList::SetSelectedFrameByIndex (uint32_t idx)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
Mutex::Locker locker (m_mutex);
|
2012-02-29 11:40:22 +08:00
|
|
|
StackFrameSP frame_sp (GetFrameAtIndex (idx));
|
|
|
|
if (frame_sp)
|
|
|
|
{
|
|
|
|
SetSelectedFrame(frame_sp.get());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return false;
|
2011-09-09 06:13:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
StackFrameList::SetDefaultFileAndLineToSelectedFrame()
|
|
|
|
{
|
2012-02-21 08:09:25 +08:00
|
|
|
if (m_thread.GetID() == m_thread.GetProcess()->GetThreadList().GetSelectedThread()->GetID())
|
2011-09-09 06:13:49 +08:00
|
|
|
{
|
2011-10-05 11:14:31 +08:00
|
|
|
StackFrameSP frame_sp (GetFrameAtIndex (GetSelectedFrameIndex()));
|
2011-09-09 06:13:49 +08:00
|
|
|
if (frame_sp)
|
|
|
|
{
|
2011-10-05 11:14:31 +08:00
|
|
|
SymbolContext sc = frame_sp->GetSymbolContext(eSymbolContextLineEntry);
|
2011-09-09 06:13:49 +08:00
|
|
|
if (sc.line_entry.file)
|
2012-02-21 08:09:25 +08:00
|
|
|
m_thread.CalculateTarget()->GetSourceManager().SetDefaultFileAndLine (sc.line_entry.file,
|
2011-10-05 11:14:31 +08:00
|
|
|
sc.line_entry.line);
|
2011-09-09 06:13:49 +08:00
|
|
|
}
|
|
|
|
}
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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);
|
2010-08-28 02:24:16 +08:00
|
|
|
m_frames.clear();
|
2012-02-29 11:40:22 +08:00
|
|
|
m_concrete_frames_fetched = 0;
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
StackFrameList::InvalidateFrames (uint32_t start_idx)
|
|
|
|
{
|
|
|
|
Mutex::Locker locker (m_mutex);
|
2010-08-25 08:35:26 +08:00
|
|
|
if (m_show_inlined_frames)
|
|
|
|
{
|
|
|
|
Clear();
|
|
|
|
}
|
|
|
|
else
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
2010-08-28 02:24:16 +08:00
|
|
|
const size_t num_frames = m_frames.size();
|
2010-08-25 08:35:26 +08:00
|
|
|
while (start_idx < num_frames)
|
|
|
|
{
|
2010-08-28 02:24:16 +08:00
|
|
|
m_frames[start_idx].reset();
|
2010-08-25 08:35:26 +08:00
|
|
|
++start_idx;
|
|
|
|
}
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
|
|
|
}
|
2010-09-04 01:10:42 +08:00
|
|
|
|
|
|
|
void
|
|
|
|
StackFrameList::Merge (std::auto_ptr<StackFrameList>& curr_ap, lldb::StackFrameListSP& prev_sp)
|
|
|
|
{
|
2012-05-05 07:02:50 +08:00
|
|
|
Mutex::Locker curr_locker (curr_ap.get() ? &curr_ap->m_mutex : NULL);
|
|
|
|
Mutex::Locker prev_locker (prev_sp.get() ? &prev_sp->m_mutex : NULL);
|
2010-09-04 01:10:42 +08:00
|
|
|
|
|
|
|
#if defined (DEBUG_STACK_FRAMES)
|
2011-08-26 01:27:02 +08:00
|
|
|
StreamFile s(stdout, false);
|
2010-09-04 01:10:42 +08:00
|
|
|
s.PutCString("\n\nStackFrameList::Merge():\nPrev:\n");
|
|
|
|
if (prev_sp.get())
|
|
|
|
prev_sp->Dump (&s);
|
|
|
|
else
|
|
|
|
s.PutCString ("NULL");
|
|
|
|
s.PutCString("\nCurr:\n");
|
|
|
|
if (curr_ap.get())
|
|
|
|
curr_ap->Dump (&s);
|
|
|
|
else
|
|
|
|
s.PutCString ("NULL");
|
|
|
|
s.EOL();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (curr_ap.get() == NULL || curr_ap->GetNumFrames (false) == 0)
|
|
|
|
{
|
|
|
|
#if defined (DEBUG_STACK_FRAMES)
|
|
|
|
s.PutCString("No current frames, leave previous frames alone...\n");
|
|
|
|
#endif
|
|
|
|
curr_ap.release();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (prev_sp.get() == NULL || prev_sp->GetNumFrames (false) == 0)
|
|
|
|
{
|
|
|
|
#if defined (DEBUG_STACK_FRAMES)
|
|
|
|
s.PutCString("No previous frames, so use current frames...\n");
|
|
|
|
#endif
|
|
|
|
// We either don't have any previous frames, or since we have more than
|
|
|
|
// one current frames it means we have all the frames and can safely
|
|
|
|
// replace our previous frames.
|
|
|
|
prev_sp.reset (curr_ap.release());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const uint32_t num_curr_frames = curr_ap->GetNumFrames (false);
|
|
|
|
|
|
|
|
if (num_curr_frames > 1)
|
|
|
|
{
|
|
|
|
#if defined (DEBUG_STACK_FRAMES)
|
|
|
|
s.PutCString("We have more than one current frame, so use current frames...\n");
|
|
|
|
#endif
|
|
|
|
// We have more than one current frames it means we have all the frames
|
|
|
|
// and can safely replace our previous frames.
|
|
|
|
prev_sp.reset (curr_ap.release());
|
|
|
|
|
|
|
|
#if defined (DEBUG_STACK_FRAMES)
|
|
|
|
s.PutCString("\nMerged:\n");
|
|
|
|
prev_sp->Dump (&s);
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
StackFrameSP prev_frame_zero_sp(prev_sp->GetFrameAtIndex (0));
|
|
|
|
StackFrameSP curr_frame_zero_sp(curr_ap->GetFrameAtIndex (0));
|
|
|
|
StackID curr_stack_id (curr_frame_zero_sp->GetStackID());
|
|
|
|
StackID prev_stack_id (prev_frame_zero_sp->GetStackID());
|
|
|
|
|
|
|
|
#if defined (DEBUG_STACK_FRAMES)
|
2011-08-26 01:27:02 +08:00
|
|
|
const uint32_t num_prev_frames = prev_sp->GetNumFrames (false);
|
2010-09-04 01:10:42 +08:00
|
|
|
s.Printf("\n%u previous frames with one current frame\n", num_prev_frames);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// We have only a single current frame
|
|
|
|
// Our previous stack frames only had a single frame as well...
|
|
|
|
if (curr_stack_id == prev_stack_id)
|
|
|
|
{
|
|
|
|
#if defined (DEBUG_STACK_FRAMES)
|
|
|
|
s.Printf("\nPrevious frame #0 is same as current frame #0, merge the cached data\n");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
curr_frame_zero_sp->UpdateCurrentFrameFromPreviousFrame (*prev_frame_zero_sp);
|
|
|
|
// prev_frame_zero_sp->UpdatePreviousFrameFromCurrentFrame (*curr_frame_zero_sp);
|
|
|
|
// prev_sp->SetFrameAtIndex (0, prev_frame_zero_sp);
|
|
|
|
}
|
|
|
|
else if (curr_stack_id < prev_stack_id)
|
|
|
|
{
|
|
|
|
#if defined (DEBUG_STACK_FRAMES)
|
|
|
|
s.Printf("\nCurrent frame #0 has a stack ID that is less than the previous frame #0, insert current frame zero in front of previous\n");
|
|
|
|
#endif
|
|
|
|
prev_sp->m_frames.insert (prev_sp->m_frames.begin(), curr_frame_zero_sp);
|
|
|
|
}
|
|
|
|
|
|
|
|
curr_ap.release();
|
|
|
|
|
|
|
|
#if defined (DEBUG_STACK_FRAMES)
|
|
|
|
s.PutCString("\nMerged:\n");
|
|
|
|
prev_sp->Dump (&s);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
}
|
2010-09-24 01:40:12 +08:00
|
|
|
|
|
|
|
lldb::StackFrameSP
|
|
|
|
StackFrameList::GetStackFrameSPForStackFramePtr (StackFrame *stack_frame_ptr)
|
|
|
|
{
|
|
|
|
const_iterator pos;
|
|
|
|
const_iterator begin = m_frames.begin();
|
|
|
|
const_iterator end = m_frames.end();
|
|
|
|
lldb::StackFrameSP ret_sp;
|
|
|
|
|
|
|
|
for (pos = begin; pos != end; ++pos)
|
|
|
|
{
|
|
|
|
if (pos->get() == stack_frame_ptr)
|
|
|
|
{
|
|
|
|
ret_sp = (*pos);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret_sp;
|
|
|
|
}
|
|
|
|
|
Centralized a lot of the status information for processes,
threads, and stack frame down in the lldb_private::Process,
lldb_private::Thread, lldb_private::StackFrameList and the
lldb_private::StackFrame classes. We had some command line
commands that had duplicate versions of the process status
output ("thread list" and "process status" for example).
Removed the "file" command and placed it where it should
have been: "target create". Made an alias for "file" to
"target create" so we stay compatible with GDB commands.
We can now have multple usable targets in lldb at the
same time. This is nice for comparing two runs of a program
or debugging more than one binary at the same time. The
new command is "target select <target-idx>" and also to see
a list of the current targets you can use the new "target list"
command. The flow in a debug session can be:
(lldb) target create /path/to/exe/a.out
(lldb) breakpoint set --name main
(lldb) run
... hit breakpoint
(lldb) target create /bin/ls
(lldb) run /tmp
Process 36001 exited with status = 0 (0x00000000)
(lldb) target list
Current targets:
target #0: /tmp/args/a.out ( arch=x86_64-apple-darwin, platform=localhost, pid=35999, state=stopped )
* target #1: /bin/ls ( arch=x86_64-apple-darwin, platform=localhost, pid=36001, state=exited )
(lldb) target select 0
Current targets:
* target #0: /tmp/args/a.out ( arch=x86_64-apple-darwin, platform=localhost, pid=35999, state=stopped )
target #1: /bin/ls ( arch=x86_64-apple-darwin, platform=localhost, pid=36001, state=exited )
(lldb) bt
* thread #1: tid = 0x2d03, 0x0000000100000b9a a.out`main + 42 at main.c:16, stop reason = breakpoint 1.1
frame #0: 0x0000000100000b9a a.out`main + 42 at main.c:16
frame #1: 0x0000000100000b64 a.out`start + 52
Above we created a target for "a.out" and ran and hit a
breakpoint at "main". Then we created a new target for /bin/ls
and ran it. Then we listed the targest and selected our original
"a.out" program, so we showed two concurent debug sessions
going on at the same time.
llvm-svn: 129695
2011-04-18 16:33:37 +08:00
|
|
|
size_t
|
|
|
|
StackFrameList::GetStatus (Stream& strm,
|
|
|
|
uint32_t first_frame,
|
|
|
|
uint32_t num_frames,
|
|
|
|
bool show_frame_info,
|
2012-07-12 04:33:48 +08:00
|
|
|
uint32_t num_frames_with_source)
|
Centralized a lot of the status information for processes,
threads, and stack frame down in the lldb_private::Process,
lldb_private::Thread, lldb_private::StackFrameList and the
lldb_private::StackFrame classes. We had some command line
commands that had duplicate versions of the process status
output ("thread list" and "process status" for example).
Removed the "file" command and placed it where it should
have been: "target create". Made an alias for "file" to
"target create" so we stay compatible with GDB commands.
We can now have multple usable targets in lldb at the
same time. This is nice for comparing two runs of a program
or debugging more than one binary at the same time. The
new command is "target select <target-idx>" and also to see
a list of the current targets you can use the new "target list"
command. The flow in a debug session can be:
(lldb) target create /path/to/exe/a.out
(lldb) breakpoint set --name main
(lldb) run
... hit breakpoint
(lldb) target create /bin/ls
(lldb) run /tmp
Process 36001 exited with status = 0 (0x00000000)
(lldb) target list
Current targets:
target #0: /tmp/args/a.out ( arch=x86_64-apple-darwin, platform=localhost, pid=35999, state=stopped )
* target #1: /bin/ls ( arch=x86_64-apple-darwin, platform=localhost, pid=36001, state=exited )
(lldb) target select 0
Current targets:
* target #0: /tmp/args/a.out ( arch=x86_64-apple-darwin, platform=localhost, pid=35999, state=stopped )
target #1: /bin/ls ( arch=x86_64-apple-darwin, platform=localhost, pid=36001, state=exited )
(lldb) bt
* thread #1: tid = 0x2d03, 0x0000000100000b9a a.out`main + 42 at main.c:16, stop reason = breakpoint 1.1
frame #0: 0x0000000100000b9a a.out`main + 42 at main.c:16
frame #1: 0x0000000100000b64 a.out`start + 52
Above we created a target for "a.out" and ran and hit a
breakpoint at "main". Then we created a new target for /bin/ls
and ran it. Then we listed the targest and selected our original
"a.out" program, so we showed two concurent debug sessions
going on at the same time.
llvm-svn: 129695
2011-04-18 16:33:37 +08:00
|
|
|
{
|
|
|
|
size_t num_frames_displayed = 0;
|
|
|
|
|
|
|
|
if (num_frames == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
StackFrameSP frame_sp;
|
|
|
|
uint32_t frame_idx = 0;
|
|
|
|
uint32_t last_frame;
|
|
|
|
|
|
|
|
// Don't let the last frame wrap around...
|
|
|
|
if (num_frames == UINT32_MAX)
|
|
|
|
last_frame = UINT32_MAX;
|
|
|
|
else
|
|
|
|
last_frame = first_frame + num_frames;
|
|
|
|
|
|
|
|
for (frame_idx = first_frame; frame_idx < last_frame; ++frame_idx)
|
|
|
|
{
|
|
|
|
frame_sp = GetFrameAtIndex(frame_idx);
|
|
|
|
if (frame_sp.get() == NULL)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (!frame_sp->GetStatus (strm,
|
|
|
|
show_frame_info,
|
2012-07-12 04:33:48 +08:00
|
|
|
num_frames_with_source > (first_frame - frame_idx)))
|
Centralized a lot of the status information for processes,
threads, and stack frame down in the lldb_private::Process,
lldb_private::Thread, lldb_private::StackFrameList and the
lldb_private::StackFrame classes. We had some command line
commands that had duplicate versions of the process status
output ("thread list" and "process status" for example).
Removed the "file" command and placed it where it should
have been: "target create". Made an alias for "file" to
"target create" so we stay compatible with GDB commands.
We can now have multple usable targets in lldb at the
same time. This is nice for comparing two runs of a program
or debugging more than one binary at the same time. The
new command is "target select <target-idx>" and also to see
a list of the current targets you can use the new "target list"
command. The flow in a debug session can be:
(lldb) target create /path/to/exe/a.out
(lldb) breakpoint set --name main
(lldb) run
... hit breakpoint
(lldb) target create /bin/ls
(lldb) run /tmp
Process 36001 exited with status = 0 (0x00000000)
(lldb) target list
Current targets:
target #0: /tmp/args/a.out ( arch=x86_64-apple-darwin, platform=localhost, pid=35999, state=stopped )
* target #1: /bin/ls ( arch=x86_64-apple-darwin, platform=localhost, pid=36001, state=exited )
(lldb) target select 0
Current targets:
* target #0: /tmp/args/a.out ( arch=x86_64-apple-darwin, platform=localhost, pid=35999, state=stopped )
target #1: /bin/ls ( arch=x86_64-apple-darwin, platform=localhost, pid=36001, state=exited )
(lldb) bt
* thread #1: tid = 0x2d03, 0x0000000100000b9a a.out`main + 42 at main.c:16, stop reason = breakpoint 1.1
frame #0: 0x0000000100000b9a a.out`main + 42 at main.c:16
frame #1: 0x0000000100000b64 a.out`start + 52
Above we created a target for "a.out" and ran and hit a
breakpoint at "main". Then we created a new target for /bin/ls
and ran it. Then we listed the targest and selected our original
"a.out" program, so we showed two concurent debug sessions
going on at the same time.
llvm-svn: 129695
2011-04-18 16:33:37 +08:00
|
|
|
break;
|
|
|
|
++num_frames_displayed;
|
|
|
|
}
|
|
|
|
|
|
|
|
strm.IndentLess();
|
|
|
|
return num_frames_displayed;
|
|
|
|
}
|
|
|
|
|