[Lldb-commits] [lldb] r292930 - Bug 30863 - Step doesn't stop with conditional breakpoint on the next line

Boris Ulasevich via lldb-commits lldb-commits at lists.llvm.org
Tue Jan 24 05:15:20 PST 2017


Author: bulasevich
Date: Tue Jan 24 07:15:19 2017
New Revision: 292930

URL: http://llvm.org/viewvc/llvm-project?rev=292930&view=rev
Log:
Bug 30863 - Step doesn't stop with conditional breakpoint on the next line
Differential Revisions:
  https://reviews.llvm.org/D26497 (committed r290168, temporary reverted r290197)
  https://reviews.llvm.org/D28945 (fix for Ubuntu tests fail)

Added:
    lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/step_over_breakpoint/
      - copied from r290180, lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/step_over_breakpoint/
Modified:
    lldb/trunk/include/lldb/Target/Thread.h
    lldb/trunk/include/lldb/Target/ThreadPlan.h
    lldb/trunk/source/Target/StopInfo.cpp
    lldb/trunk/source/Target/Thread.cpp
    lldb/trunk/source/Target/ThreadPlanStepInstruction.cpp
    lldb/trunk/source/Target/ThreadPlanStepRange.cpp

Modified: lldb/trunk/include/lldb/Target/Thread.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Thread.h?rev=292930&r1=292929&r2=292930&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/Thread.h (original)
+++ lldb/trunk/include/lldb/Target/Thread.h Tue Jan 24 07:15:19 2017
@@ -126,6 +126,7 @@ public:
                            // bit of data.
     lldb::StopInfoSP stop_info_sp; // You have to restore the stop info or you
                                    // might continue with the wrong signals.
+    std::vector<lldb::ThreadPlanSP> m_completed_plan_stack;
     lldb::RegisterCheckpointSP
         register_backup_sp; // You need to restore the registers, of course...
     uint32_t current_inlined_depth;
@@ -1029,6 +1030,15 @@ public:
   bool WasThreadPlanDiscarded(ThreadPlan *plan);
 
   //------------------------------------------------------------------
+  /// Check if we have completed plan to override breakpoint stop reason
+  ///
+  /// @return
+  ///     Returns true if completed plan stack is not empty
+  ///     false otherwise.
+  //------------------------------------------------------------------
+  bool CompletedPlanOverridesBreakpoint();
+                   
+  //------------------------------------------------------------------
   /// Queues a generic thread plan.
   ///
   /// @param[in] plan_sp
@@ -1213,6 +1223,8 @@ public:
 
   void SetStopInfo(const lldb::StopInfoSP &stop_info_sp);
 
+  void ResetStopInfo();
+
   void SetShouldReportStop(Vote vote);
 
   //----------------------------------------------------------------------

Modified: lldb/trunk/include/lldb/Target/ThreadPlan.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/ThreadPlan.h?rev=292930&r1=292929&r2=292930&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/ThreadPlan.h (original)
+++ lldb/trunk/include/lldb/Target/ThreadPlan.h Tue Jan 24 07:15:19 2017
@@ -40,9 +40,10 @@ namespace lldb_private {
 //  The thread maintaining a thread plan stack, and you program the actions of a
 //  particular thread
 //  by pushing plans onto the plan stack.
-//  There is always a "Current" plan, which is the head of the plan stack,
+//  There is always a "Current" plan, which is the top of the plan stack,
 //  though in some cases
-//  a plan may defer to plans higher in the stack for some piece of information.
+//  a plan may defer to plans higher in the stack for some piece of information
+//  (let us define that the plan stack grows downwards).
 //
 //  The plan stack is never empty, there is always a Base Plan which persists
 //  through the life
@@ -109,6 +110,15 @@ namespace lldb_private {
 //  plans in the time between when
 //  your plan gets unshipped and the next resume.
 //
+//  Thread State Checkpoint:
+//
+//  Note that calling functions on target process (ThreadPlanCallFunction) changes
+//  current thread state. The function can be called either by direct user demand or
+//  internally, for example lldb allocates memory on device to calculate breakpoint
+//  condition expression - on Linux it is performed by calling mmap on device.
+//  ThreadStateCheckpoint saves Thread state (stop info and completed
+//  plan stack) to restore it after completing function call.
+//
 //  Over the lifetime of the plan, various methods of the ThreadPlan are then
 //  called in response to changes of state in
 //  the process we are debugging as follows:
@@ -149,7 +159,7 @@ namespace lldb_private {
 //  If the Current plan answers "true" then it is asked if the stop should
 //  percolate all the way to the
 //  user by calling the ShouldStop method.  If the current plan doesn't explain
-//  the stop, then we query down
+//  the stop, then we query up
 //  the plan stack for a plan that does explain the stop.  The plan that does
 //  explain the stop then needs to
 //  figure out what to do about the plans below it in the stack.  If the stop is
@@ -170,7 +180,7 @@ namespace lldb_private {
 //  event it didn't directly handle
 //  it can designate itself a "Master" plan by responding true to IsMasterPlan,
 //  and then if it wants not to be
-//  discarded, it can return true to OkayToDiscard, and it and all its dependent
+//  discarded, it can return false to OkayToDiscard, and it and all its dependent
 //  plans will be preserved when
 //  we resume execution.
 //
@@ -207,7 +217,7 @@ namespace lldb_private {
 //
 //  If a plan says responds "true" to ShouldStop, then it is asked if it's job
 //  is complete by calling
-//  MischiefManaged.  If that returns true, the thread is popped from the plan
+//  MischiefManaged.  If that returns true, the plan is popped from the plan
 //  stack and added to the
 //  Completed Plan Stack.  Then the next plan in the stack is asked if it
 //  ShouldStop, and  it returns "true",
@@ -241,9 +251,9 @@ namespace lldb_private {
 //
 //  When the process stops, the thread is given a StopReason, in the form of a
 //  StopInfo object.  If there is a completed
-//  plan corresponding to the stop, then the "actual" stop reason will be
+//  plan corresponding to the stop, then the "actual" stop reason can be
 //  suppressed, and instead a StopInfoThreadPlan
-//  object will be cons'ed up from the highest completed plan in the stack.
+//  object will be cons'ed up from the top completed plan in the stack.
 //  However, if the plan doesn't want to be
 //  the stop reason, then it can call SetPlanComplete and pass in "false" for
 //  the "success" parameter.  In that case,

Modified: lldb/trunk/source/Target/StopInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/StopInfo.cpp?rev=292930&r1=292929&r2=292930&view=diff
==============================================================================
--- lldb/trunk/source/Target/StopInfo.cpp (original)
+++ lldb/trunk/source/Target/StopInfo.cpp Tue Jan 24 07:15:19 2017
@@ -269,6 +269,7 @@ protected:
     if (!m_should_perform_action)
       return;
     m_should_perform_action = false;
+    bool internal_breakpoint = true;
 
     ThreadSP thread_sp(m_thread_wp.lock());
 
@@ -495,6 +496,9 @@ protected:
             if (callback_says_stop)
               m_should_stop = true;
 
+            if (m_should_stop && !bp_loc_sp->GetBreakpoint().IsInternal())
+              internal_breakpoint = false;
+                  
             // If we are going to stop for this breakpoint, then remove the
             // breakpoint.
             if (callback_says_stop && bp_loc_sp &&
@@ -526,6 +530,20 @@ protected:
               "Process::%s could not find breakpoint site id: %" PRId64 "...",
               __FUNCTION__, m_value);
       }
+
+      if ((m_should_stop == false || internal_breakpoint)
+          && thread_sp->CompletedPlanOverridesBreakpoint()) {
+        
+        // Override should_stop decision when we have
+        // completed step plan additionally to the breakpoint
+        m_should_stop = true;
+        
+        // Here we clean the preset stop info so the next
+        // GetStopInfo call will find the appropriate stop info,
+        // which should be the stop info related to the completed plan
+        thread_sp->ResetStopInfo();
+      }
+
       if (log)
         log->Printf("Process::%s returning from action with m_should_stop: %d.",
                     __FUNCTION__, m_should_stop);

Modified: lldb/trunk/source/Target/Thread.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Thread.cpp?rev=292930&r1=292929&r2=292930&view=diff
==============================================================================
--- lldb/trunk/source/Target/Thread.cpp (original)
+++ lldb/trunk/source/Target/Thread.cpp Tue Jan 24 07:15:19 2017
@@ -380,24 +380,32 @@ lldb::StopInfoSP Thread::GetStopInfo() {
   if (m_destroy_called)
     return m_stop_info_sp;
 
-  ThreadPlanSP plan_sp(GetCompletedPlan());
+  ThreadPlanSP completed_plan_sp(GetCompletedPlan());
   ProcessSP process_sp(GetProcess());
   const uint32_t stop_id = process_sp ? process_sp->GetStopID() : UINT32_MAX;
-  if (plan_sp && plan_sp->PlanSucceeded()) {
-    return StopInfo::CreateStopReasonWithPlan(plan_sp, GetReturnValueObject(),
-                                              GetExpressionVariable());
+
+  // Here we select the stop info according to priorirty:
+  // - m_stop_info_sp (if not trace) - preset value
+  // - completed plan stop info - new value with plan from completed plan stack
+  // - m_stop_info_sp (trace stop reason is OK now)
+  // - ask GetPrivateStopInfo to set stop info
+
+  bool have_valid_stop_info = m_stop_info_sp &&
+      m_stop_info_sp ->IsValid() &&
+      m_stop_info_stop_id == stop_id;
+  bool have_valid_completed_plan = completed_plan_sp && completed_plan_sp->PlanSucceeded();
+  bool plan_overrides_trace =
+    have_valid_stop_info && have_valid_completed_plan
+    && (m_stop_info_sp->GetStopReason() == eStopReasonTrace);
+    
+  if (have_valid_stop_info && !plan_overrides_trace) {
+    return m_stop_info_sp;
+  } else if (have_valid_completed_plan) {
+    return StopInfo::CreateStopReasonWithPlan(
+        completed_plan_sp, GetReturnValueObject(), GetExpressionVariable());
   } else {
-    if ((m_stop_info_stop_id == stop_id) || // Stop info is valid, just return
-                                            // what we have (even if empty)
-        (m_stop_info_sp &&
-         m_stop_info_sp
-             ->IsValid())) // Stop info is valid, just return what we have
-    {
-      return m_stop_info_sp;
-    } else {
-      GetPrivateStopInfo();
-      return m_stop_info_sp;
-    }
+    GetPrivateStopInfo();
+    return m_stop_info_sp;
   }
 }
 
@@ -459,6 +467,12 @@ bool Thread::StopInfoIsUpToDate() const
                  // date...
 }
 
+void Thread::ResetStopInfo() {
+  if (m_stop_info_sp) {
+    m_stop_info_sp.reset();
+  }
+}
+
 void Thread::SetStopInfo(const lldb::StopInfoSP &stop_info_sp) {
   m_stop_info_sp = stop_info_sp;
   if (m_stop_info_sp) {
@@ -526,7 +540,8 @@ bool Thread::CheckpointThreadState(Threa
   if (process_sp)
     saved_state.orig_stop_id = process_sp->GetStopID();
   saved_state.current_inlined_depth = GetCurrentInlinedDepth();
-
+  saved_state.m_completed_plan_stack = m_completed_plan_stack;
+	
   return true;
 }
 
@@ -559,6 +574,7 @@ bool Thread::RestoreThreadStateFromCheck
   SetStopInfo(saved_state.stop_info_sp);
   GetStackFrameList()->SetCurrentInlinedDepth(
       saved_state.current_inlined_depth);
+  m_completed_plan_stack = saved_state.m_completed_plan_stack;
   return true;
 }
 
@@ -895,6 +911,9 @@ bool Thread::ShouldStop(Event *event_ptr
 
   if (should_stop) {
     ThreadPlan *plan_ptr = GetCurrentPlan();
+
+    // Discard the stale plans and all plans below them in the stack,
+    // plus move the completed plans to the completed plan stack
     while (!PlanIsBasePlan(plan_ptr)) {
       bool stale = plan_ptr->IsPlanStale();
       ThreadPlan *examined_plan = plan_ptr;
@@ -905,7 +924,15 @@ bool Thread::ShouldStop(Event *event_ptr
           log->Printf(
               "Plan %s being discarded in cleanup, it says it is already done.",
               examined_plan->GetName());
-        DiscardThreadPlansUpToPlan(examined_plan);
+        while (GetCurrentPlan() != examined_plan) {
+          DiscardPlan();
+        }
+        if (examined_plan->IsPlanComplete()) {
+          // plan is complete but does not explain the stop (example: step to a line
+          // with breakpoint), let us move the plan to completed_plan_stack anyway
+          PopPlan();
+        } else
+          DiscardPlan();
       }
     }
   }
@@ -1133,6 +1160,10 @@ bool Thread::WasThreadPlanDiscarded(Thre
   return false;
 }
 
+bool Thread::CompletedPlanOverridesBreakpoint() {
+  return (!m_completed_plan_stack.empty()) ;
+}
+
 ThreadPlan *Thread::GetPreviousPlan(ThreadPlan *current_plan) {
   if (current_plan == nullptr)
     return nullptr;

Modified: lldb/trunk/source/Target/ThreadPlanStepInstruction.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/ThreadPlanStepInstruction.cpp?rev=292930&r1=292929&r2=292930&view=diff
==============================================================================
--- lldb/trunk/source/Target/ThreadPlanStepInstruction.cpp (original)
+++ lldb/trunk/source/Target/ThreadPlanStepInstruction.cpp Tue Jan 24 07:15:19 2017
@@ -94,6 +94,15 @@ bool ThreadPlanStepInstruction::IsPlanSt
   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
   StackID cur_frame_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
   if (cur_frame_id == m_stack_id) {
+    // Set plan Complete when we reach next instruction
+    uint64_t pc = m_thread.GetRegisterContext()->GetPC(0);
+    uint32_t max_opcode_size = m_thread.CalculateTarget()
+        ->GetArchitecture().GetMaximumOpcodeByteSize();
+    bool next_instruction_reached = (pc > m_instruction_addr) &&
+        (pc <= m_instruction_addr + max_opcode_size);
+    if (next_instruction_reached) {
+      SetPlanComplete();
+    }
     return (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr);
   } else if (cur_frame_id < m_stack_id) {
     // If the current frame is younger than the start frame and we are stepping

Modified: lldb/trunk/source/Target/ThreadPlanStepRange.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/ThreadPlanStepRange.cpp?rev=292930&r1=292929&r2=292930&view=diff
==============================================================================
--- lldb/trunk/source/Target/ThreadPlanStepRange.cpp (original)
+++ lldb/trunk/source/Target/ThreadPlanStepRange.cpp Tue Jan 24 07:15:19 2017
@@ -461,6 +461,16 @@ bool ThreadPlanStepRange::IsPlanStale()
     // One tricky bit here is that some stubs don't push a frame, so we should.
     // check that we are in the same symbol.
     if (!InRange()) {
+      // Set plan Complete when we reach next instruction just after the range
+      lldb::addr_t addr = m_thread.GetRegisterContext()->GetPC() - 1;
+      size_t num_ranges = m_address_ranges.size();
+      for (size_t i = 0; i < num_ranges; i++) {
+        bool in_range = m_address_ranges[i].ContainsLoadAddress(
+            addr, m_thread.CalculateTarget().get());
+        if (in_range) {
+          SetPlanComplete();
+        }
+      }
       return true;
     }
   }




More information about the lldb-commits mailing list