diff options
Diffstat (limited to 'contrib/llvm/tools/lldb/source/Target/StackFrameList.cpp')
-rw-r--r-- | contrib/llvm/tools/lldb/source/Target/StackFrameList.cpp | 899 |
1 files changed, 899 insertions, 0 deletions
diff --git a/contrib/llvm/tools/lldb/source/Target/StackFrameList.cpp b/contrib/llvm/tools/lldb/source/Target/StackFrameList.cpp new file mode 100644 index 0000000..69309df --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Target/StackFrameList.cpp @@ -0,0 +1,899 @@ +//===-- 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/Breakpoint/BreakpointLocation.h" +#include "lldb/Breakpoint/Breakpoint.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/StreamFile.h" +#include "lldb/Core/SourceManager.h" +#include "lldb/Symbol/Block.h" +#include "lldb/Symbol/Function.h" +#include "lldb/Symbol/Symbol.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/StackFrame.h" +#include "lldb/Target/StopInfo.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/Target/Unwind.h" + +//#define DEBUG_STACK_FRAMES 1 + +using namespace lldb; +using namespace lldb_private; + +//---------------------------------------------------------------------- +// StackFrameList constructor +//---------------------------------------------------------------------- +StackFrameList::StackFrameList +( + Thread &thread, + const lldb::StackFrameListSP &prev_frames_sp, + bool show_inline_frames +) : + m_thread (thread), + m_prev_frames_sp (prev_frames_sp), + m_mutex (Mutex::eMutexTypeRecursive), + m_frames (), + m_selected_frame_idx (0), + m_concrete_frames_fetched (0), + m_current_inlined_depth (UINT32_MAX), + m_current_inlined_pc (LLDB_INVALID_ADDRESS), + m_show_inlined_frames (show_inline_frames) +{ + 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; + } +} + +//---------------------------------------------------------------------- +// Destructor +//---------------------------------------------------------------------- +StackFrameList::~StackFrameList() +{ + // Call clear since this takes a lock and clears the stack frame list + // in case another thread is currently using this stack frame list + Clear(); +} + +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 && m_current_inlined_pc != LLDB_INVALID_ADDRESS) + { + 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; + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); + if (log && log->GetVerbose()) + log->Printf ("GetCurrentInlinedDepth: invalidating current inlined depth.\n"); + } + return m_current_inlined_depth; + } + else + { + return UINT32_MAX; + } +} + +void +StackFrameList::ResetCurrentInlinedDepth () +{ + if (m_show_inlined_frames) + { + GetFramesUpTo(0); + if (!m_frames[0]->IsInlined()) + { + m_current_inlined_depth = UINT32_MAX; + m_current_inlined_pc = LLDB_INVALID_ADDRESS; + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); + if (log && log->GetVerbose()) + log->Printf ("ResetCurrentInlinedDepth: Invalidating current inlined depth.\n"); + } + 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 eStopReasonWatchpoint: + case eStopReasonException: + case eStopReasonExec: + 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; + case eStopReasonBreakpoint: + { + // FIXME: Figure out what this break point is doing, and set the inline depth + // appropriately. Be careful to take into account breakpoints that implement + // step over prologue, since that should do the default calculation. + // For now, if the breakpoints corresponding to this hit are all internal, + // I set the stop location to the top of the inlined stack, since that will make + // things like stepping over prologues work right. But if there are any non-internal + // breakpoints I do to the bottom of the stack, since that was the old behavior. + uint32_t bp_site_id = stop_info_sp->GetValue(); + BreakpointSiteSP bp_site_sp(m_thread.GetProcess()->GetBreakpointSiteList().FindByID(bp_site_id)); + bool all_internal = true; + if (bp_site_sp) + { + uint32_t num_owners = bp_site_sp->GetNumberOfOwners(); + for (uint32_t i = 0; i < num_owners; i++) + { + Breakpoint &bp_ref = bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint(); + if (!bp_ref.IsInternal()) + { + all_internal = false; + } + } + } + if (!all_internal) + { + 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; + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); + if (log && log->GetVerbose()) + log->Printf ("ResetCurrentInlinedDepth: setting inlined depth: %d 0x%" PRIx64 ".\n", m_current_inlined_depth, curr_pc); + + } + 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; +} + +void +StackFrameList::SetCurrentInlinedDepth (uint32_t new_depth) +{ + m_current_inlined_depth = new_depth; + if (new_depth == UINT32_MAX) + m_current_inlined_pc = LLDB_INVALID_ADDRESS; + else + m_current_inlined_pc = m_thread.GetRegisterContext()->GetPC(); +} + +void +StackFrameList::GetFramesUpTo(uint32_t end_idx) +{ + // this makes sure we do not fetch frames for an invalid thread + if (m_thread.IsValid() == false) + return; + + // 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 (); + + if (m_show_inlined_frames) + { +#if defined (DEBUG_STACK_FRAMES) + StreamFile s(stdout, false); +#endif + // 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... And of course, if end_idx is + // UINT32_MAX that means get all, so just do that... + + uint32_t inlined_depth = 0; + if (end_idx > 0 && end_idx != UINT32_MAX) + { + inlined_depth = GetCurrentInlinedDepth(); + if (inlined_depth != UINT32_MAX) + { + if (end_idx > 0) + end_idx += inlined_depth; + } + } + + StackFrameSP unwind_frame_sp; + do + { + uint32_t idx = m_concrete_frames_fetched++; + lldb::addr_t pc; + lldb::addr_t cfa; + if (idx == 0) + { + // We might have already created frame zero, only create it + // if we need to + if (m_frames.empty()) + { + RegisterContextSP reg_ctx_sp (m_thread.GetRegisterContext()); + + if (reg_ctx_sp) + { + + 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 = reg_ctx_sp->GetSP(); + pc = reg_ctx_sp->GetPC(); + } + + unwind_frame_sp.reset (new StackFrame (m_thread.shared_from_this(), + m_frames.size(), + idx, + reg_ctx_sp, + cfa, + pc, + NULL)); + m_frames.push_back (unwind_frame_sp); + } + } + else + { + unwind_frame_sp = m_frames.front(); + cfa = unwind_frame_sp->m_id.GetCallFrameAddress(); + } + } + else + { + const bool success = unwinder->GetFrameInfoAtIndex(idx, cfa, pc); + if (!success) + { + // 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); + + 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; + } + } + } while (m_frames.size() - 1 < end_idx); + + // 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; + + //curr_frames->m_current_inlined_depth = prev_frames->m_current_inlined_depth; + //curr_frames->m_current_inlined_pc = prev_frames->m_current_inlined_pc; + //printf ("GetFramesUpTo: Copying current inlined depth: %d 0x%" PRIx64 ".\n", curr_frames->m_current_inlined_depth, curr_frames->m_current_inlined_pc); + +#if defined (DEBUG_STACK_FRAMES) + s.PutCString("\nprev_frames:\n"); + prev_frames->Dump (&s); + s.PutCString("\ncurr_frames:\n"); + curr_frames->Dump (&s); + s.EOL(); +#endif + 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]); + +#if defined (DEBUG_STACK_FRAMES) + 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"); +#endif + + 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); + +#if defined (DEBUG_STACK_FRAMES) + s.Printf("\n Copying previous frame to current frame"); +#endif + } + // We are done with the old stack frame list, we can release it now + m_prev_frames_sp.reset(); + } + +#if defined (DEBUG_STACK_FRAMES) + s.PutCString("\n\nNew frames:\n"); + Dump (&s); + s.EOL(); +#endif + } + else + { + if (end_idx < m_concrete_frames_fetched) + return; + + uint32_t num_frames = unwinder->GetFramesUpTo(end_idx); + if (num_frames <= end_idx + 1) + { + //Done unwinding. + m_concrete_frames_fetched = UINT32_MAX; + } + m_frames.resize(num_frames); + } +} + +uint32_t +StackFrameList::GetNumFrames (bool can_create) +{ + Mutex::Locker locker (m_mutex); + + if (can_create) + GetFramesUpTo (UINT32_MAX); + + uint32_t inlined_depth = GetCurrentInlinedDepth(); + if (inlined_depth == UINT32_MAX) + return m_frames.size(); + else + return m_frames.size() - inlined_depth; +} + +void +StackFrameList::Dump (Stream *s) +{ + if (s == NULL) + return; + Mutex::Locker locker (m_mutex); + + 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) + { + frame->GetStackID().Dump (s); + frame->DumpUsingSettingsFormat (s); + } + else + s->Printf("frame #%u", (uint32_t)std::distance (begin, pos)); + s->EOL(); + } + s->EOL(); +} + +StackFrameSP +StackFrameList::GetFrameAtIndex (uint32_t idx) +{ + StackFrameSP frame_sp; + Mutex::Locker locker (m_mutex); + uint32_t original_idx = idx; + + uint32_t inlined_depth = GetCurrentInlinedDepth(); + if (inlined_depth != UINT32_MAX) + idx += inlined_depth; + + if (idx < m_frames.size()) + frame_sp = m_frames[idx]; + + if (frame_sp) + return frame_sp; + + // 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. + GetFramesUpTo (idx); + if (idx < m_frames.size()) + { + if (m_show_inlined_frames) + { + // When inline frames are enabled we actually create all the frames in GetFramesUpTo. + frame_sp = m_frames[idx]; + } + else + { + Unwind *unwinder = m_thread.GetUnwinder (); + if (unwinder) + { + addr_t pc, cfa; + if (unwinder->GetFrameInfoAtIndex(idx, cfa, pc)) + { + 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); + } + } + } + } + else if (original_idx == 0) + { + // There should ALWAYS be a frame at index 0. If something went wrong with the CurrentInlinedDepth such that + // there weren't as many frames as we thought taking that into account, then reset the current inlined depth + // and return the real zeroth frame. + if (m_frames.size() > 0) + { + ResetCurrentInlinedDepth(); + frame_sp = m_frames[original_idx]; + } + else + { + // Why do we have a thread with zero frames, that should not ever happen... + if (m_thread.IsValid()) + assert ("A valid thread has no frames."); + + } + } + + return frame_sp; +} + +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; +} + +static bool +CompareStackID (const StackFrameSP &stack_sp, const StackID &stack_id) +{ + return stack_sp->GetStackID() < stack_id; +} + +StackFrameSP +StackFrameList::GetFrameWithStackID (const StackID &stack_id) +{ + StackFrameSP frame_sp; + + if (stack_id.IsValid()) + { + Mutex::Locker locker (m_mutex); + uint32_t frame_idx = 0; + // Do a binary search in case the stack frame is already in our cache + collection::const_iterator begin = m_frames.begin(); + collection::const_iterator end = m_frames.end(); + if (begin != end) + { + collection::const_iterator pos = std::lower_bound (begin, end, stack_id, CompareStackID); + if (pos != end && (*pos)->GetStackID() == stack_id) + return *pos; + + if (m_frames.back()->GetStackID() < stack_id) + frame_idx = m_frames.size(); + } + do + { + frame_sp = GetFrameAtIndex (frame_idx); + if (frame_sp && frame_sp->GetStackID() == stack_id) + break; + frame_idx++; + } + while (frame_sp); + } + return frame_sp; +} + +bool +StackFrameList::SetFrameAtIndex (uint32_t idx, StackFrameSP &frame_sp) +{ + if (idx >= m_frames.size()) + m_frames.resize(idx + 1); + // Make sure allocation succeeded by checking bounds again + if (idx < m_frames.size()) + { + m_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_frames.begin(); + const_iterator end = m_frames.end(); + m_selected_frame_idx = 0; + for (pos = begin; pos != end; ++pos) + { + if (pos->get() == frame) + { + m_selected_frame_idx = std::distance (begin, pos); + uint32_t inlined_depth = GetCurrentInlinedDepth(); + if (inlined_depth != UINT32_MAX) + m_selected_frame_idx -= inlined_depth; + break; + } + } + SetDefaultFileAndLineToSelectedFrame(); + return m_selected_frame_idx; +} + +// Mark a stack frame as the current frame using the frame index +bool +StackFrameList::SetSelectedFrameByIndex (uint32_t idx) +{ + Mutex::Locker locker (m_mutex); + StackFrameSP frame_sp (GetFrameAtIndex (idx)); + if (frame_sp) + { + SetSelectedFrame(frame_sp.get()); + return true; + } + else + return false; +} + +void +StackFrameList::SetDefaultFileAndLineToSelectedFrame() +{ + if (m_thread.GetID() == m_thread.GetProcess()->GetThreadList().GetSelectedThread()->GetID()) + { + StackFrameSP frame_sp (GetFrameAtIndex (GetSelectedFrameIndex())); + if (frame_sp) + { + SymbolContext sc = frame_sp->GetSymbolContext(eSymbolContextLineEntry); + if (sc.line_entry.file) + m_thread.CalculateTarget()->GetSourceManager().SetDefaultFileAndLine (sc.line_entry.file, + sc.line_entry.line); + } + } +} + +// 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_frames.clear(); + m_concrete_frames_fetched = 0; +} + +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_frames.size(); + while (start_idx < num_frames) + { + m_frames[start_idx].reset(); + ++start_idx; + } + } +} + +void +StackFrameList::Merge (std::unique_ptr<StackFrameList>& curr_ap, lldb::StackFrameListSP& prev_sp) +{ + Mutex::Locker curr_locker (curr_ap.get() ? &curr_ap->m_mutex : NULL); + Mutex::Locker prev_locker (prev_sp.get() ? &prev_sp->m_mutex : NULL); + +#if defined (DEBUG_STACK_FRAMES) + StreamFile s(stdout, false); + 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) + const uint32_t num_prev_frames = prev_sp->GetNumFrames (false); + 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 + + +} + +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; +} + +size_t +StackFrameList::GetStatus (Stream& strm, + uint32_t first_frame, + uint32_t num_frames, + bool show_frame_info, + uint32_t num_frames_with_source) +{ + 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, + num_frames_with_source > (first_frame - frame_idx))) + break; + ++num_frames_displayed; + } + + strm.IndentLess(); + return num_frames_displayed; +} + |