Refactor UnwindLLDB so it doesn't populate the entire stack unless
the frame count is requested or each frame is individually requested.

In practice this doesn't seem to help anything because we have
functions like StackFrameList::GetNumFrames() which is going to
request each frame anyway.  And classes like ThreadPlanStepRange
and ThreadPlanStepOverRange get the stack depth in their ctor forcing
a full stack walk.  But at least UnwindLLDB will delay doing a full
walk if it can.



git-svn-id: https://llvm.org/svn/llvm-project/llvdb/trunk@118477 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/source/Plugins/Process/Utility/UnwindLLDB.cpp b/source/Plugins/Process/Utility/UnwindLLDB.cpp
index 5847718..38f2c46 100644
--- a/source/Plugins/Process/Utility/UnwindLLDB.cpp
+++ b/source/Plugins/Process/Utility/UnwindLLDB.cpp
@@ -31,97 +31,120 @@
 uint32_t
 UnwindLLDB::GetFrameCount()
 {
-    LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
     if (m_frames.empty())
     {
-        // First, set up the 0th (initial) frame
-        CursorSP first_cursor_sp(new Cursor ());
-        RegisterContextSP no_frame; // an empty shared pointer
-        RegisterContextLLDB *first_register_ctx = new RegisterContextLLDB(m_thread, no_frame, first_cursor_sp->sctx, 0);
-        if (!first_register_ctx->IsValid())
-        {
-            delete first_register_ctx;
+        if (!AddFirstFrame ())
             return 0;
-        }
-        if (!first_register_ctx->GetCFA (first_cursor_sp->cfa))
-        {
-            delete first_register_ctx;
-            return 0;
-        }
-        if (!first_register_ctx->GetPC (first_cursor_sp->start_pc))
-        {
-            delete first_register_ctx;
-            return 0;
-        }
-        // Reuse the StackFrame provided by the processor native machine context for the first frame
-        first_register_ctx->SetStackFrame (m_thread.GetStackFrameAtIndex(0).get());
-        RegisterContextSP first_register_ctx_sp(first_register_ctx);
-        first_cursor_sp->reg_ctx = first_register_ctx_sp;
-        m_frames.push_back (first_cursor_sp);
-
-        // Now walk up the rest of the stack
-        while (1)
-        {
-            CursorSP cursor_sp(new Cursor ());
-            RegisterContextLLDB *register_ctx;
-            uint32_t cur_idx = m_frames.size ();
-            register_ctx = new RegisterContextLLDB (m_thread, m_frames[cur_idx - 1]->reg_ctx, cursor_sp->sctx, cur_idx);
-            if (!register_ctx->IsValid())
-            {
-                delete register_ctx;
-                if (log)
-                {
-                    log->Printf("%*sFrame %d invalid RegisterContext for this frame, stopping stack walk", 
-                                cur_idx < 100 ? cur_idx : 100, "", cur_idx);
-                }
-                break;
-            }
-            if (!register_ctx->GetCFA (cursor_sp->cfa))
-            {
-                delete register_ctx;
-                if (log)
-                {
-                    log->Printf("%*sFrame %d did not get CFA for this frame, stopping stack walk",
-                                cur_idx < 100 ? cur_idx : 100, "", cur_idx);
-                }
-                break;
-            }
-            if (cursor_sp->cfa == (addr_t) -1 || cursor_sp->cfa == 1 || cursor_sp->cfa == 0)
-            {
-                delete register_ctx;
-                if (log)
-                {
-                    log->Printf("%*sFrame %d did not get a valid CFA for this frame, stopping stack walk",
-                                cur_idx < 100 ? cur_idx : 100, "", cur_idx);
-                }
-                break;
-            }
-            if (!register_ctx->GetPC (cursor_sp->start_pc))
-            {
-                delete register_ctx;
-                if (log)
-                {
-                    log->Printf("%*sFrame %d did not get PC for this frame, stopping stack walk",
-                                cur_idx < 100 ? cur_idx : 100, "", cur_idx);
-                }
-                break;
-            }
-            RegisterContextSP register_ctx_sp(register_ctx);
-            StackFrame *frame = new StackFrame(cur_idx, cur_idx, m_thread, register_ctx_sp, cursor_sp->cfa, cursor_sp->start_pc, &(cursor_sp->sctx));
-            register_ctx->SetStackFrame (frame);
-            cursor_sp->reg_ctx = register_ctx_sp;
-            m_frames.push_back (cursor_sp);
-        }
+        while (AddOneMoreFrame ())
+            ;
     }
     return m_frames.size ();
 }
 
 bool
+UnwindLLDB::AddFirstFrame ()
+{
+    // First, set up the 0th (initial) frame
+    CursorSP first_cursor_sp(new Cursor ());
+    RegisterContextSP no_frame; 
+    RegisterContextLLDB *first_register_ctx = new RegisterContextLLDB(m_thread, no_frame, first_cursor_sp->sctx, 0);
+    if (!first_register_ctx->IsValid())
+    {
+        delete first_register_ctx;
+        return false;
+    }
+    if (!first_register_ctx->GetCFA (first_cursor_sp->cfa))
+    {
+        delete first_register_ctx;
+        return false;
+    }
+    if (!first_register_ctx->GetPC (first_cursor_sp->start_pc))
+    {
+        delete first_register_ctx;
+        return false;
+    }
+    // Reuse the StackFrame provided by the processor native machine context for the first frame
+    first_register_ctx->SetStackFrame (m_thread.GetStackFrameAtIndex(0).get());
+    RegisterContextSP first_register_ctx_sp(first_register_ctx);
+    first_cursor_sp->reg_ctx = first_register_ctx_sp;
+    m_frames.push_back (first_cursor_sp);
+    return true;
+}
+
+// For adding a non-zero stack frame to m_frames.
+bool
+UnwindLLDB::AddOneMoreFrame ()
+{
+    LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+    CursorSP cursor_sp(new Cursor ());
+    RegisterContextLLDB *register_ctx;
+
+    // Frame zero is a little different
+    if (m_frames.size() == 0)
+        return false;
+
+    uint32_t cur_idx = m_frames.size ();
+    register_ctx = new RegisterContextLLDB (m_thread, m_frames[cur_idx - 1]->reg_ctx, cursor_sp->sctx, cur_idx);
+
+    if (!register_ctx->IsValid())
+    {
+        delete register_ctx;
+        if (log)
+        {
+            log->Printf("%*sFrame %d invalid RegisterContext for this frame, stopping stack walk", 
+                        cur_idx < 100 ? cur_idx : 100, "", cur_idx);
+        }
+        return false;
+    }
+    if (!register_ctx->GetCFA (cursor_sp->cfa))
+    {
+        delete register_ctx;
+        if (log)
+        {
+            log->Printf("%*sFrame %d did not get CFA for this frame, stopping stack walk",
+                        cur_idx < 100 ? cur_idx : 100, "", cur_idx);
+        }
+        return false;
+    }
+    if (cursor_sp->cfa == (addr_t) -1 || cursor_sp->cfa == 1 || cursor_sp->cfa == 0)
+    {
+        delete register_ctx;
+        if (log)
+        {
+            log->Printf("%*sFrame %d did not get a valid CFA for this frame, stopping stack walk",
+                        cur_idx < 100 ? cur_idx : 100, "", cur_idx);
+        }
+        return false;
+    }
+    if (!register_ctx->GetPC (cursor_sp->start_pc))
+    {
+        delete register_ctx;
+        if (log)
+        {
+            log->Printf("%*sFrame %d did not get PC for this frame, stopping stack walk",
+                        cur_idx < 100 ? cur_idx : 100, "", cur_idx);
+        }
+        return false;
+    }
+    RegisterContextSP register_ctx_sp(register_ctx);
+    StackFrame *frame = new StackFrame(cur_idx, cur_idx, m_thread, register_ctx_sp, cursor_sp->cfa, cursor_sp->start_pc, &(cursor_sp->sctx));
+    register_ctx->SetStackFrame (frame);
+    cursor_sp->reg_ctx = register_ctx_sp;
+    m_frames.push_back (cursor_sp);
+    return true;
+}
+
+bool
 UnwindLLDB::GetFrameInfoAtIndex (uint32_t idx, addr_t& cfa, addr_t& pc)
 {
-    // FIXME don't get the entire stack if it isn't needed.
     if (m_frames.size() == 0)
-        GetFrameCount();
+    {
+        if (!AddFirstFrame())
+            return false;
+    }
+
+    while (idx >= m_frames.size() && AddOneMoreFrame ())
+        ;
 
     if (idx < m_frames.size ())
     {
@@ -136,15 +159,21 @@
 UnwindLLDB::CreateRegisterContextForFrame (StackFrame *frame)
 {
     uint32_t idx = frame->GetFrameIndex ();
-    
-    // FIXME don't get the entire stack if it isn't needed.
-    if (m_frames.size() == 0)
-        GetFrameCount();
-    
+
     if (idx == 0)
     {
         return m_thread.GetRegisterContext();
     }
+
+    if (m_frames.size() == 0)
+    {
+        if (!AddFirstFrame())
+            return NULL;
+    }
+
+    while (idx >= m_frames.size() && AddOneMoreFrame ())
+        ;
+
     if (idx < m_frames.size ())
         return m_frames[idx]->reg_ctx.get();
     return NULL;