Initial check-in of "fancy" inlined stepping. Doesn't do anything useful unless you switch LLDB_FANCY_INLINED_STEPPING to true. With that
on, basic inlined stepping works, including step-over of inlined functions. But for some as yet mysterious reason i386 debugging gets an
assert and dies immediately. So for now its off.
git-svn-id: https://llvm.org/svn/llvm-project/lldb/trunk@163044 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/source/Target/StackFrameList.cpp b/source/Target/StackFrameList.cpp
index 6fd410d..bfdb1a2 100644
--- a/source/Target/StackFrameList.cpp
+++ b/source/Target/StackFrameList.cpp
@@ -21,6 +21,7 @@
#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"
@@ -45,8 +46,15 @@
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;
+ }
}
//----------------------------------------------------------------------
@@ -57,6 +65,140 @@
}
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;
+}
+
+void
StackFrameList::GetFramesUpTo(uint32_t end_idx)
{
// We've already gotten more frames than asked for, or we've already finished unwinding, return.
@@ -70,6 +212,22 @@
#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...
+
+ 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;
+ }
StackFrameSP unwind_frame_sp;
do
@@ -98,7 +256,7 @@
unwind_frame_sp.reset (new StackFrame (m_thread.shared_from_this(),
m_frames.size(),
- idx,
+ idx,
m_thread.m_reg_context_sp,
cfa,
pc,
@@ -246,7 +404,12 @@
if (can_create)
GetFramesUpTo (UINT32_MAX);
- return m_frames.size();
+
+ uint32_t inlined_depth = GetCurrentInlinedDepth();
+ if (inlined_depth == UINT32_MAX)
+ return m_frames.size();
+ else
+ return m_frames.size() - inlined_depth;
}
void
@@ -278,6 +441,10 @@
{
StackFrameSP frame_sp;
Mutex::Locker locker (m_mutex);
+ uint32_t inlined_depth = GetCurrentInlinedDepth();
+ if (inlined_depth != UINT32_MAX)
+ idx += inlined_depth;
+
if (idx < m_frames.size())
frame_sp = m_frames[idx];
@@ -396,6 +563,9 @@
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;
}
}