Add setting to require hardware breakpoints.
authorJonas Devlieghere <jonas@devlieghere.com>
Thu, 15 Nov 2018 01:18:15 +0000 (01:18 +0000)
committerJonas Devlieghere <jonas@devlieghere.com>
Thu, 15 Nov 2018 01:18:15 +0000 (01:18 +0000)
When debugging read-only memory we cannot use software breakpoint. We
already have support for hardware breakpoints and users can specify them
with `-H`. However, there's no option to force LLDB to use hardware
breakpoints internally, for example while stepping.

This patch adds a setting target.require-hardware-breakpoint that forces
LLDB to always use hardware breakpoints. Because hardware breakpoints
are a limited resource and can fail to resolve, this patch also extends
error handling in thread plans, where breakpoints are used for stepping.

Differential revision: https://reviews.llvm.org/D54221

llvm-svn: 346920

41 files changed:
lldb/include/lldb/API/SBBreakpoint.h
lldb/include/lldb/API/SBThreadPlan.h
lldb/include/lldb/Breakpoint/Breakpoint.h
lldb/include/lldb/Target/Target.h
lldb/include/lldb/Target/Thread.h
lldb/include/lldb/Target/ThreadPlan.h
lldb/include/lldb/Target/ThreadPlanPython.h
lldb/include/lldb/Target/ThreadPlanShouldStopHere.h
lldb/include/lldb/Target/ThreadPlanStepInRange.h
lldb/include/lldb/Target/ThreadPlanStepInstruction.h
lldb/include/lldb/Target/ThreadPlanStepOut.h
lldb/include/lldb/Target/ThreadPlanStepThrough.h
lldb/include/lldb/Target/ThreadPlanStepUntil.h
lldb/include/lldb/lldb-private-interfaces.h
lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/require_hw_breakpoints/Makefile [new file with mode: 0644]
lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/require_hw_breakpoints/TestRequireHWBreakpoints.py [new file with mode: 0644]
lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/require_hw_breakpoints/main.c [new file with mode: 0644]
lldb/packages/Python/lldbsuite/test/functionalities/step_scripted/TestStepScripted.py
lldb/scripts/interface/SBBreakpoint.i
lldb/source/API/SBBreakpoint.cpp
lldb/source/API/SBThread.cpp
lldb/source/API/SBThreadPlan.cpp
lldb/source/Breakpoint/Breakpoint.cpp
lldb/source/Commands/CommandObjectThread.cpp
lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp
lldb/source/Target/Process.cpp
lldb/source/Target/StopInfo.cpp
lldb/source/Target/Target.cpp
lldb/source/Target/Thread.cpp
lldb/source/Target/ThreadPlan.cpp
lldb/source/Target/ThreadPlanCallOnFunctionExit.cpp
lldb/source/Target/ThreadPlanPython.cpp
lldb/source/Target/ThreadPlanRunToAddress.cpp
lldb/source/Target/ThreadPlanShouldStopHere.cpp
lldb/source/Target/ThreadPlanStepInRange.cpp
lldb/source/Target/ThreadPlanStepInstruction.cpp
lldb/source/Target/ThreadPlanStepOut.cpp
lldb/source/Target/ThreadPlanStepOverRange.cpp
lldb/source/Target/ThreadPlanStepRange.cpp
lldb/source/Target/ThreadPlanStepThrough.cpp
lldb/source/Target/ThreadPlanStepUntil.cpp

index 899249b..2c93bf1 100644 (file)
@@ -129,6 +129,8 @@ public:
   static uint32_t
   GetNumBreakpointLocationsFromEvent(const lldb::SBEvent &event_sp);
 
+  bool IsHardware() const;
+
   // Can only be called from a ScriptedBreakpointResolver...
   SBError
   AddLocation(SBAddress &address);
index c1357c9..5084a42 100644 (file)
@@ -79,16 +79,28 @@ public:
   // plans...
   SBThreadPlan QueueThreadPlanForStepOverRange(SBAddress &start_address,
                                                lldb::addr_t range_size);
+  SBThreadPlan QueueThreadPlanForStepOverRange(SBAddress &start_address,
+                                               lldb::addr_t range_size,
+                                               SBError &error);
 
   SBThreadPlan QueueThreadPlanForStepInRange(SBAddress &start_address,
                                              lldb::addr_t range_size);
+  SBThreadPlan QueueThreadPlanForStepInRange(SBAddress &start_address,
+                                             lldb::addr_t range_size,
+                                             SBError &error);
 
   SBThreadPlan QueueThreadPlanForStepOut(uint32_t frame_idx_to_step_to,
                                          bool first_insn = false);
+  SBThreadPlan QueueThreadPlanForStepOut(uint32_t frame_idx_to_step_to,
+                                         bool first_insn, SBError &error);
 
   SBThreadPlan QueueThreadPlanForRunToAddress(SBAddress address);
+  SBThreadPlan QueueThreadPlanForRunToAddress(SBAddress address,
+                                              SBError &error);
 
   SBThreadPlan QueueThreadPlanForStepScripted(const char *script_class_name);
+  SBThreadPlan QueueThreadPlanForStepScripted(const char *script_class_name,
+                                              SBError &error);
 
 #ifndef SWIG
   lldb_private::ThreadPlan *get();
index 0cd8cfd..2ba0c97 100644 (file)
@@ -499,6 +499,14 @@ public:
   size_t GetNumResolvedLocations() const;
 
   //------------------------------------------------------------------
+  /// Return whether this breakpoint has any resolved locations.
+  ///
+  /// @return
+  ///     True if GetNumResolvedLocations > 0
+  //------------------------------------------------------------------
+  bool HasResolvedLocations() const;
+
+  //------------------------------------------------------------------
   /// Return the number of breakpoint locations.
   ///
   /// @return
index ea039e7..febd348 100644 (file)
@@ -198,6 +198,10 @@ public:
 
   bool GetUseModernTypeLookup() const;
 
+  void SetRequireHardwareBreakpoints(bool b);
+
+  bool GetRequireHardwareBreakpoints() const;
+
 private:
   //------------------------------------------------------------------
   // Callbacks for m_launch_info.
index fff2c6b..47d3b08 100644 (file)
@@ -53,7 +53,7 @@ public:
   bool GetStepInAvoidsNoDebug() const;
 
   bool GetStepOutAvoidsNoDebug() const;
-  
+
   uint64_t GetMaxBacktraceDepth() const;
 };
 
@@ -494,9 +494,9 @@ public:
 
   // If stop_format is true, this will be the form used when we print stop
   // info. If false, it will be the form we use for thread list and co.
-  void DumpUsingSettingsFormat(Stream &strm, uint32_t frame_idx, 
+  void DumpUsingSettingsFormat(Stream &strm, uint32_t frame_idx,
                                bool stop_format);
+
   bool GetDescription(Stream &s, lldb::DescriptionLevel level,
                       bool print_json_thread, bool print_json_stopinfo);
 
@@ -653,12 +653,16 @@ public:
   /// @param[in] stop_other_threads
   ///    \b true if we will stop other threads while we single step this one.
   ///
+  /// @param[out] status
+  ///     A status with an error if queuing failed.
+  ///
   /// @return
   ///     A shared pointer to the newly queued thread plan, or nullptr if the
   ///     plan could not be queued.
   //------------------------------------------------------------------
   virtual lldb::ThreadPlanSP QueueThreadPlanForStepSingleInstruction(
-      bool step_over, bool abort_other_plans, bool stop_other_threads);
+      bool step_over, bool abort_other_plans, bool stop_other_threads,
+      Status &status);
 
   //------------------------------------------------------------------
   /// Queues the plan used to step through an address range, stepping  over
@@ -688,6 +692,9 @@ public:
   /// @param[in] stop_other_threads
   ///    \b true if we will stop other threads while we single step this one.
   ///
+  /// @param[out] status
+  ///     A status with an error if queuing failed.
+  ///
   /// @param[in] step_out_avoids_code_without_debug_info
   ///    If eLazyBoolYes, if the step over steps out it will continue to step
   ///    out till it comes to a frame with debug info.
@@ -700,6 +707,7 @@ public:
   virtual lldb::ThreadPlanSP QueueThreadPlanForStepOverRange(
       bool abort_other_plans, const AddressRange &range,
       const SymbolContext &addr_context, lldb::RunMode stop_other_threads,
+      Status &status,
       LazyBool step_out_avoids_code_without_debug_info = eLazyBoolCalculate);
 
   // Helper function that takes a LineEntry to step, insted of an AddressRange.
@@ -708,6 +716,7 @@ public:
   virtual lldb::ThreadPlanSP QueueThreadPlanForStepOverRange(
       bool abort_other_plans, const LineEntry &line_entry,
       const SymbolContext &addr_context, lldb::RunMode stop_other_threads,
+      Status &status,
       LazyBool step_out_avoids_code_without_debug_info = eLazyBoolCalculate);
 
   //------------------------------------------------------------------
@@ -742,6 +751,9 @@ public:
   /// @param[in] stop_other_threads
   ///    \b true if we will stop other threads while we single step this one.
   ///
+  /// @param[out] status
+  ///     A status with an error if queuing failed.
+  ///
   /// @param[in] step_in_avoids_code_without_debug_info
   ///    If eLazyBoolYes we will step out if we step into code with no debug
   ///    info.
@@ -759,7 +771,7 @@ public:
   virtual lldb::ThreadPlanSP QueueThreadPlanForStepInRange(
       bool abort_other_plans, const AddressRange &range,
       const SymbolContext &addr_context, const char *step_in_target,
-      lldb::RunMode stop_other_threads,
+      lldb::RunMode stop_other_threads, Status &status,
       LazyBool step_in_avoids_code_without_debug_info = eLazyBoolCalculate,
       LazyBool step_out_avoids_code_without_debug_info = eLazyBoolCalculate);
 
@@ -769,7 +781,7 @@ public:
   virtual lldb::ThreadPlanSP QueueThreadPlanForStepInRange(
       bool abort_other_plans, const LineEntry &line_entry,
       const SymbolContext &addr_context, const char *step_in_target,
-      lldb::RunMode stop_other_threads,
+      lldb::RunMode stop_other_threads, Status &status,
       LazyBool step_in_avoids_code_without_debug_info = eLazyBoolCalculate,
       LazyBool step_out_avoids_code_without_debug_info = eLazyBoolCalculate);
 
@@ -801,6 +813,9 @@ public:
   /// @param[in] run_vote
   ///    See standard meanings for the stop & run votes in ThreadPlan.h.
   ///
+  /// @param[out] status
+  ///     A status with an error if queuing failed.
+  ///
   /// @param[in] step_out_avoids_code_without_debug_info
   ///    If eLazyBoolYes, if the step over steps out it will continue to step
   ///    out till it comes to a frame with debug info.
@@ -812,10 +827,8 @@ public:
   //------------------------------------------------------------------
   virtual lldb::ThreadPlanSP QueueThreadPlanForStepOut(
       bool abort_other_plans, SymbolContext *addr_context, bool first_insn,
-      bool stop_other_threads,
-      Vote stop_vote, // = eVoteYes,
-      Vote run_vote,  // = eVoteNoOpinion);
-      uint32_t frame_idx,
+      bool stop_other_threads, Vote stop_vote, Vote run_vote,
+      uint32_t frame_idx, Status &status,
       LazyBool step_out_avoids_code_without_debug_info = eLazyBoolCalculate);
 
   //------------------------------------------------------------------
@@ -846,9 +859,15 @@ public:
   ///    \b true if we will stop other threads while we single step this one.
   ///
   /// @param[in] stop_vote
+  ///
   /// @param[in] run_vote
   ///    See standard meanings for the stop & run votes in ThreadPlan.h.
   ///
+  /// @param[in] frame_idx
+  ///
+  /// @param[out] status
+  ///     A status with an error if queuing failed.
+  ///
   /// @param[in] continue_to_next_branch
   ///    Normally this will enqueue a plan that will put a breakpoint on the
   ///    return address and continue
@@ -872,16 +891,13 @@ public:
   //------------------------------------------------------------------
   virtual lldb::ThreadPlanSP QueueThreadPlanForStepOutNoShouldStop(
       bool abort_other_plans, SymbolContext *addr_context, bool first_insn,
-      bool stop_other_threads,
-      Vote stop_vote, // = eVoteYes,
-      Vote run_vote,  // = eVoteNoOpinion);
-      uint32_t frame_idx, bool continue_to_next_branch = false);
+      bool stop_other_threads, Vote stop_vote, Vote run_vote,
+      uint32_t frame_idx, Status &status, bool continue_to_next_branch = false);
 
   //------------------------------------------------------------------
   /// Gets the plan used to step through the code that steps from a function
   /// call site at the current PC into the actual function call.
   ///
-  ///
   /// @param[in] return_stack_id
   ///    The stack id that we will return to (by setting backstop breakpoints on
   ///    the return
@@ -895,14 +911,17 @@ public:
   /// @param[in] stop_other_threads
   ///    \b true if we will stop other threads while we single step this one.
   ///
+  /// @param[out] status
+  ///     A status with an error if queuing failed.
+  ///
   /// @return
   ///     A shared pointer to the newly queued thread plan, or nullptr if the
   ///     plan could not be queued.
   //------------------------------------------------------------------
   virtual lldb::ThreadPlanSP
   QueueThreadPlanForStepThrough(StackID &return_stack_id,
-                                bool abort_other_plans,
-                                bool stop_other_threads);
+                                bool abort_other_plans, bool stop_other_threads,
+                                Status &status);
 
   //------------------------------------------------------------------
   /// Gets the plan used to continue from the current PC.
@@ -920,22 +939,24 @@ public:
   /// @param[in] stop_other_threads
   ///    \b true if we will stop other threads while we single step this one.
   ///
+  /// @param[out] status
+  ///     A status with an error if queuing failed.
+  ///
   /// @return
   ///     A shared pointer to the newly queued thread plan, or nullptr if the
   ///     plan could not be queued.
   //------------------------------------------------------------------
   virtual lldb::ThreadPlanSP
   QueueThreadPlanForRunToAddress(bool abort_other_plans, Address &target_addr,
-                                 bool stop_other_threads);
+                                 bool stop_other_threads, Status &status);
 
-  virtual lldb::ThreadPlanSP
-  QueueThreadPlanForStepUntil(bool abort_other_plans,
-                              lldb::addr_t *address_list, size_t num_addresses,
-                              bool stop_others, uint32_t frame_idx);
+  virtual lldb::ThreadPlanSP QueueThreadPlanForStepUntil(
+      bool abort_other_plans, lldb::addr_t *address_list, size_t num_addresses,
+      bool stop_others, uint32_t frame_idx, Status &status);
 
   virtual lldb::ThreadPlanSP
   QueueThreadPlanForStepScripted(bool abort_other_plans, const char *class_name,
-                                 bool stop_other_threads);
+                                 bool stop_other_threads, Status &status);
 
   //------------------------------------------------------------------
   // Thread Plan accessors:
@@ -1021,7 +1042,7 @@ public:
   ///     false otherwise.
   //------------------------------------------------------------------
   bool CompletedPlanOverridesBreakpoint();
-                   
+
   //------------------------------------------------------------------
   /// Queues a generic thread plan.
   ///
@@ -1036,7 +1057,7 @@ public:
   /// @return
   ///     A pointer to the last completed plan.
   //------------------------------------------------------------------
-  void QueueThreadPlan(lldb::ThreadPlanSP &plan_sp, bool abort_other_plans);
+  Status QueueThreadPlan(lldb::ThreadPlanSP &plan_sp, bool abort_other_plans);
 
   //------------------------------------------------------------------
   /// Discards the plans queued on the plan stack of the current thread.  This
index 8bfc02e..15bc4c7 100644 (file)
@@ -596,10 +596,12 @@ protected:
 
   bool IsUsuallyUnexplainedStopReason(lldb::StopReason);
 
+  Status m_status;
   Thread &m_thread;
   Vote m_stop_vote;
   Vote m_run_vote;
-  bool m_takes_iteration_count = false;
+  bool m_takes_iteration_count;
+  bool m_could_not_resolve_hw_bp;
   int32_t m_iteration_count = 1;
 
 private:
@@ -651,6 +653,8 @@ public:
 
   bool OkayToDiscard() override { return false; }
 
+  const Status &GetStatus() { return m_status; }
+
 protected:
   bool DoPlanExplainsStop(Event *event_ptr) override;
 
index 7231ac9..fc4cfb3 100644 (file)
@@ -59,6 +59,7 @@ protected:
 private:
   std::string m_class_name;
   StructuredData::ObjectSP m_implementation_sp;
+  bool m_did_push;
 
   DISALLOW_COPY_AND_ASSIGN(ThreadPlanPython);
 };
index 31530cd..d3aca3e 100644 (file)
@@ -97,10 +97,12 @@ public:
 
   void ClearShouldStopHereCallbacks() { m_callbacks.Clear(); }
 
-  bool InvokeShouldStopHereCallback(lldb::FrameComparison operation);
+  bool InvokeShouldStopHereCallback(lldb::FrameComparison operation,
+                                    Status &status);
 
   lldb::ThreadPlanSP
-  CheckShouldStopHereAndQueueStepOut(lldb::FrameComparison operation);
+  CheckShouldStopHereAndQueueStepOut(lldb::FrameComparison operation,
+                                     Status &status);
 
   lldb_private::Flags &GetFlags() { return m_flags; }
 
@@ -110,14 +112,16 @@ protected:
   static bool DefaultShouldStopHereCallback(ThreadPlan *current_plan,
                                             Flags &flags,
                                             lldb::FrameComparison operation,
-                                            void *baton);
+                                            Status &status, void *baton);
 
   static lldb::ThreadPlanSP
   DefaultStepFromHereCallback(ThreadPlan *current_plan, Flags &flags,
-                              lldb::FrameComparison operation, void *baton);
+                              lldb::FrameComparison operation, Status &status,
+                              void *baton);
 
   virtual lldb::ThreadPlanSP
-  QueueStepOutFromHerePlan(Flags &flags, lldb::FrameComparison operation);
+  QueueStepOutFromHerePlan(Flags &flags, lldb::FrameComparison operation,
+                           Status &status);
 
   // Implement this, and call it in the plan's constructor to set the default
   // flags.
index 78f82d8..c13b353 100644 (file)
@@ -54,7 +54,7 @@ protected:
   static bool DefaultShouldStopHereCallback(ThreadPlan *current_plan,
                                             Flags &flags,
                                             lldb::FrameComparison operation,
-                                            void *baton);
+                                            Status &status, void *baton);
 
   bool DoWillResume(lldb::StateType resume_state, bool current_plan) override;
 
@@ -76,11 +76,11 @@ private:
   friend lldb::ThreadPlanSP Thread::QueueThreadPlanForStepOverRange(
       bool abort_other_plans, const AddressRange &range,
       const SymbolContext &addr_context, lldb::RunMode stop_others,
-      LazyBool avoid_code_without_debug_info);
+      Status &status, LazyBool avoid_code_without_debug_info);
   friend lldb::ThreadPlanSP Thread::QueueThreadPlanForStepInRange(
       bool abort_other_plans, const AddressRange &range,
       const SymbolContext &addr_context, const char *step_in_target,
-      lldb::RunMode stop_others,
+      lldb::RunMode stop_others, Status &status,
       LazyBool step_in_avoids_code_without_debug_info,
       LazyBool step_out_avoids_code_without_debug_info);
 
index 9602265..ea5d93f 100644 (file)
@@ -39,7 +39,8 @@ protected:
 
 private:
   friend lldb::ThreadPlanSP Thread::QueueThreadPlanForStepSingleInstruction(
-      bool step_over, bool abort_other_plans, bool stop_other_threads);
+      bool step_over, bool abort_other_plans, bool stop_other_threads,
+      Status &status);
 
   lldb::addr_t m_instruction_addr;
   bool m_stop_other_threads;
index cfdddee..8ef9f95 100644 (file)
@@ -77,7 +77,7 @@ private:
   friend lldb::ThreadPlanSP Thread::QueueThreadPlanForStepOut(
       bool abort_other_plans, SymbolContext *addr_context, bool first_insn,
       bool stop_others, Vote stop_vote, Vote run_vote, uint32_t frame_idx,
-      LazyBool step_out_avoids_code_without_debug_info);
+      Status &status, LazyBool step_out_avoids_code_without_debug_info);
 
   void SetupAvoidNoDebug(LazyBool step_out_avoids_code_without_debug_info);
   // Need an appropriate marker for the current stack so we can tell step out
index 0bf2fd8..1bff541 100644 (file)
@@ -41,10 +41,9 @@ protected:
 
 private:
   friend lldb::ThreadPlanSP
-
   Thread::QueueThreadPlanForStepThrough(StackID &return_stack_id,
                                         bool abort_other_plans,
-                                        bool stop_others);
+                                        bool stop_others, Status &status);
 
   void ClearBackstopBreakpoint();
 
index 2238fdb..33ccc0f 100644 (file)
@@ -55,7 +55,7 @@ private:
 
   friend lldb::ThreadPlanSP Thread::QueueThreadPlanForStepUntil(
       bool abort_other_plans, lldb::addr_t *address_list, size_t num_addresses,
-      bool stop_others, uint32_t frame_idx);
+      bool stop_others, uint32_t frame_idx, Status &status);
 
   // Need an appropriate marker for the current stack so we can tell step out
   // from step in.
index 806068e..76a9fad 100644 (file)
@@ -84,10 +84,10 @@ typedef void (*OptionValueChangedCallback)(void *baton,
                                            OptionValue *option_value);
 typedef bool (*ThreadPlanShouldStopHereCallback)(
     ThreadPlan *current_plan, Flags &flags, lldb::FrameComparison operation,
-    void *baton);
+    Status &status, void *baton);
 typedef lldb::ThreadPlanSP (*ThreadPlanStepFromHereCallback)(
     ThreadPlan *current_plan, Flags &flags, lldb::FrameComparison operation,
-    void *baton);
+    Status &status, void *baton);
 typedef UnwindAssembly *(*UnwindAssemblyCreateInstance)(const ArchSpec &arch);
 typedef lldb::MemoryHistorySP (*MemoryHistoryCreateInstance)(
     const lldb::ProcessSP &process_sp);
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/require_hw_breakpoints/Makefile b/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/require_hw_breakpoints/Makefile
new file mode 100644 (file)
index 0000000..7934cd5
--- /dev/null
@@ -0,0 +1,9 @@
+LEVEL = ../../../make
+
+C_SOURCES := main.c
+
+ifneq (,$(findstring icc,$(CC)))
+    CFLAGS += -debug inline-debug-info
+endif
+
+include $(LEVEL)/Makefile.rules
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/require_hw_breakpoints/TestRequireHWBreakpoints.py b/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/require_hw_breakpoints/TestRequireHWBreakpoints.py
new file mode 100644 (file)
index 0000000..1a1ee2e
--- /dev/null
@@ -0,0 +1,102 @@
+"""
+Test require hardware breakpoints.
+"""
+
+from __future__ import print_function
+
+import os
+import time
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class BreakpointLocationsTestCase(TestBase):
+    NO_DEBUG_INFO_TESTCASE = True
+    mydir = TestBase.compute_mydir(__file__)
+
+    def test_breakpoint(self):
+        """Test regular breakpoints when hardware breakpoints are required."""
+        self.build()
+        exe = self.getBuildArtifact("a.out")
+        target = self.dbg.CreateTarget(exe)
+
+        self.runCmd("settings set target.require-hardware-breakpoint true")
+
+        breakpoint = target.BreakpointCreateByLocation("main.c", 1)
+        self.assertTrue(breakpoint.IsHardware())
+
+    def test_step_range(self):
+        """Test stepping when hardware breakpoints are required."""
+        self.build()
+
+        _, _, thread, _ = lldbutil.run_to_line_breakpoint(
+            self, lldb.SBFileSpec("main.c"), 1)
+
+        self.runCmd("settings set target.require-hardware-breakpoint true")
+
+        # Ensure we fail in the interpreter.
+        self.expect("thread step-in")
+        self.expect("thread step-in", error=True)
+
+        # Ensure we fail when stepping through the API.
+        error = lldb.SBError()
+        thread.StepInto('', 4, error)
+        self.assertTrue(error.Fail())
+        self.assertTrue("Could not create hardware breakpoint for thread plan"
+                        in error.GetCString())
+
+    def test_step_out(self):
+        """Test stepping out when hardware breakpoints are required."""
+        self.build()
+
+        _, _, thread, _ = lldbutil.run_to_line_breakpoint(
+            self, lldb.SBFileSpec("main.c"), 1)
+
+        self.runCmd("settings set target.require-hardware-breakpoint true")
+
+        # Ensure this fails in the command interpreter.
+        self.expect("thread step-out", error=True)
+
+        # Ensure we fail when stepping through the API.
+        error = lldb.SBError()
+        thread.StepOut(error)
+        self.assertTrue(error.Fail())
+        self.assertTrue("Could not create hardware breakpoint for thread plan"
+                        in error.GetCString())
+
+    def test_step_over(self):
+        """Test stepping over when hardware breakpoints are required."""
+        self.build()
+
+        _, _, thread, _ = lldbutil.run_to_line_breakpoint(
+            self, lldb.SBFileSpec("main.c"), 7)
+
+        self.runCmd("settings set target.require-hardware-breakpoint true")
+
+        # Step over doesn't fail immediately but fails later on.
+        self.expect("thread step-over")
+        self.expect(
+            "process status",
+            substrs=[
+                'step over failed',
+                'Could not create hardware breakpoint for thread plan'
+            ])
+
+    def test_step_until(self):
+        """Test stepping until when hardware breakpoints are required."""
+        self.build()
+
+        _, _, thread, _ = lldbutil.run_to_line_breakpoint(
+            self, lldb.SBFileSpec("main.c"), 7)
+
+        self.runCmd("settings set target.require-hardware-breakpoint true")
+
+        self.expect("thread until 5", error=True)
+
+        # Ensure we fail when stepping through the API.
+        error = thread.StepOverUntil(lldb.SBFrame(), lldb.SBFileSpec(), 5)
+        self.assertTrue(error.Fail())
+        self.assertTrue("Could not create hardware breakpoint for thread plan"
+                        in error.GetCString())
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/require_hw_breakpoints/main.c b/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/require_hw_breakpoints/main.c
new file mode 100644 (file)
index 0000000..7d49a57
--- /dev/null
@@ -0,0 +1,9 @@
+int break_on_me() {
+  int i = 10;
+  i++;
+  return i;
+}
+
+int main() {
+  return break_on_me();
+}
index 1c254c5..a111ede 100644 (file)
@@ -35,7 +35,7 @@ class StepScriptedTestCase(TestBase):
         self.assertEqual("foo", frame.GetFunctionName())
 
         err = thread.StepUsingScriptedThreadPlan(name)
-        self.assertTrue(err.Success(), "Failed to step out")
+        self.assertTrue(err.Success(), err.GetCString())
 
         frame = thread.GetFrameAtIndex(0)
         self.assertEqual("main", frame.GetFunctionName())
index b810682..1383f38 100644 (file)
@@ -251,6 +251,9 @@ public:
     static uint32_t
     GetNumBreakpointLocationsFromEvent (const lldb::SBEvent &event_sp);
     
+    bool
+    IsHardware ();
+
     %pythoncode %{
         
         class locations_access(object):
index 11afa99..b672007 100644 (file)
@@ -688,6 +688,13 @@ SBBreakpoint::GetNumBreakpointLocationsFromEvent(const lldb::SBEvent &event) {
   return num_locations;
 }
 
+bool SBBreakpoint::IsHardware() const {
+  BreakpointSP bkpt_sp = GetSP();
+  if (bkpt_sp)
+    return bkpt_sp->IsHardware();
+  return false;
+}
+
 BreakpointSP SBBreakpoint::GetSP() const { return m_opaque_wp.lock(); }
 
 // This is simple collection of breakpoint id's and their target.
index b7af459..a38b9f6 100644 (file)
@@ -657,6 +657,7 @@ void SBThread::StepOver(lldb::RunMode stop_other_threads, SBError &error) {
   bool abort_other_plans = false;
   StackFrameSP frame_sp(thread->GetStackFrameAtIndex(0));
 
+  Status new_plan_status;
   ThreadPlanSP new_plan_sp;
   if (frame_sp) {
     if (frame_sp->HasDebugInformation()) {
@@ -664,10 +665,10 @@ void SBThread::StepOver(lldb::RunMode stop_other_threads, SBError &error) {
       SymbolContext sc(frame_sp->GetSymbolContext(eSymbolContextEverything));
       new_plan_sp = thread->QueueThreadPlanForStepOverRange(
           abort_other_plans, sc.line_entry, sc, stop_other_threads,
-          avoid_no_debug);
+          new_plan_status, avoid_no_debug);
     } else {
       new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction(
-          true, abort_other_plans, stop_other_threads);
+          true, abort_other_plans, stop_other_threads, new_plan_status);
     }
   }
   error = ResumeNewPlan(exe_ctx, new_plan_sp.get());
@@ -707,6 +708,7 @@ void SBThread::StepInto(const char *target_name, uint32_t end_line,
   Thread *thread = exe_ctx.GetThreadPtr();
   StackFrameSP frame_sp(thread->GetStackFrameAtIndex(0));
   ThreadPlanSP new_plan_sp;
+  Status new_plan_status;
 
   if (frame_sp && frame_sp->HasDebugInformation()) {
     SymbolContext sc(frame_sp->GetSymbolContext(eSymbolContextEverything));
@@ -724,13 +726,17 @@ void SBThread::StepInto(const char *target_name, uint32_t end_line,
         eLazyBoolCalculate;
     new_plan_sp = thread->QueueThreadPlanForStepInRange(
         abort_other_plans, range, sc, target_name, stop_other_threads,
-        step_in_avoids_code_without_debug_info,
+        new_plan_status, step_in_avoids_code_without_debug_info,
         step_out_avoids_code_without_debug_info);
   } else {
     new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction(
-        false, abort_other_plans, stop_other_threads);
+        false, abort_other_plans, stop_other_threads, new_plan_status);
   }
-  error = ResumeNewPlan(exe_ctx, new_plan_sp.get());
+
+  if (new_plan_status.Success())
+    error = ResumeNewPlan(exe_ctx, new_plan_sp.get());
+  else
+    error.SetErrorString(new_plan_status.AsCString());
 }
 
 void SBThread::StepOut() {
@@ -759,11 +765,15 @@ void SBThread::StepOut(SBError &error) {
   Thread *thread = exe_ctx.GetThreadPtr();
 
   const LazyBool avoid_no_debug = eLazyBoolCalculate;
+  Status new_plan_status;
   ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForStepOut(
       abort_other_plans, NULL, false, stop_other_threads, eVoteYes,
-      eVoteNoOpinion, 0, avoid_no_debug));
+      eVoteNoOpinion, 0, new_plan_status, avoid_no_debug));
 
-  error = ResumeNewPlan(exe_ctx, new_plan_sp.get());
+  if (new_plan_status.Success())
+    error = ResumeNewPlan(exe_ctx, new_plan_sp.get());
+  else
+    error.SetErrorString(new_plan_status.AsCString());
 }
 
 void SBThread::StepOutOfFrame(SBFrame &sb_frame) {
@@ -812,11 +822,15 @@ void SBThread::StepOutOfFrame(SBFrame &sb_frame, SBError &error) {
     return;
   }
 
+  Status new_plan_status;
   ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForStepOut(
       abort_other_plans, NULL, false, stop_other_threads, eVoteYes,
-      eVoteNoOpinion, frame_sp->GetFrameIndex()));
+      eVoteNoOpinion, frame_sp->GetFrameIndex(), new_plan_status));
 
-  error = ResumeNewPlan(exe_ctx, new_plan_sp.get());
+  if (new_plan_status.Success())
+    error = ResumeNewPlan(exe_ctx, new_plan_sp.get());
+  else
+    error.SetErrorString(new_plan_status.AsCString());
 }
 
 void SBThread::StepInstruction(bool step_over) {
@@ -840,10 +854,14 @@ void SBThread::StepInstruction(bool step_over, SBError &error) {
   }
 
   Thread *thread = exe_ctx.GetThreadPtr();
-  ThreadPlanSP new_plan_sp(
-      thread->QueueThreadPlanForStepSingleInstruction(step_over, true, true));
+  Status new_plan_status;
+  ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForStepSingleInstruction(
+      step_over, true, true, new_plan_status));
 
-  error = ResumeNewPlan(exe_ctx, new_plan_sp.get());
+  if (new_plan_status.Success())
+    error = ResumeNewPlan(exe_ctx, new_plan_sp.get());
+  else
+    error.SetErrorString(new_plan_status.AsCString());
 }
 
 void SBThread::RunToAddress(lldb::addr_t addr) {
@@ -873,10 +891,14 @@ void SBThread::RunToAddress(lldb::addr_t addr, SBError &error) {
 
   Thread *thread = exe_ctx.GetThreadPtr();
 
+  Status new_plan_status;
   ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForRunToAddress(
-      abort_other_plans, target_addr, stop_other_threads));
+      abort_other_plans, target_addr, stop_other_threads, new_plan_status));
 
-  error = ResumeNewPlan(exe_ctx, new_plan_sp.get());
+  if (new_plan_status.Success())
+    error = ResumeNewPlan(exe_ctx, new_plan_sp.get());
+  else
+    error.SetErrorString(new_plan_status.AsCString());
 }
 
 SBError SBThread::StepOverUntil(lldb::SBFrame &sb_frame,
@@ -988,12 +1010,16 @@ SBError SBThread::StepOverUntil(lldb::SBFrame &sb_frame,
       } else
         sb_error.SetErrorString("step until target not in current function");
     } else {
+      Status new_plan_status;
       ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForStepUntil(
           abort_other_plans, &step_over_until_addrs[0],
           step_over_until_addrs.size(), stop_other_threads,
-          frame_sp->GetFrameIndex()));
+          frame_sp->GetFrameIndex(), new_plan_status));
 
-      sb_error = ResumeNewPlan(exe_ctx, new_plan_sp.get());
+      if (new_plan_status.Success())
+        sb_error = ResumeNewPlan(exe_ctx, new_plan_sp.get());
+      else
+        sb_error.SetErrorString(new_plan_status.AsCString());
     }
   } else {
     sb_error.SetErrorString("this SBThread object is invalid");
@@ -1008,7 +1034,7 @@ SBError SBThread::StepUsingScriptedThreadPlan(const char *script_class_name) {
 SBError SBThread::StepUsingScriptedThreadPlan(const char *script_class_name,
                                               bool resume_immediately) {
   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
-  SBError sb_error;
+  SBError error;
 
   std::unique_lock<std::recursive_mutex> lock;
   ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
@@ -1019,37 +1045,29 @@ SBError SBThread::StepUsingScriptedThreadPlan(const char *script_class_name,
   }
 
   if (!exe_ctx.HasThreadScope()) {
-    sb_error.SetErrorString("this SBThread object is invalid");
-    return sb_error;
+    error.SetErrorString("this SBThread object is invalid");
+    return error;
   }
 
   Thread *thread = exe_ctx.GetThreadPtr();
-  ThreadPlanSP thread_plan_sp =
-      thread->QueueThreadPlanForStepScripted(false, script_class_name, false);
+  Status new_plan_status;
+  ThreadPlanSP new_plan_sp = thread->QueueThreadPlanForStepScripted(
+      false, script_class_name, false, new_plan_status);
 
-  if (!thread_plan_sp) {
-    sb_error.SetErrorStringWithFormat(
-        "Error queueing thread plan for class: %s", script_class_name);
-    return sb_error;
+  if (new_plan_status.Fail()) {
+    error.SetErrorString(new_plan_status.AsCString());
+    return error;
   }
 
-  if (!resume_immediately) {
-    return sb_error;
-  }
+  if (!resume_immediately)
+    return error;
 
-  if (thread_plan_sp)
-    sb_error = ResumeNewPlan(exe_ctx, thread_plan_sp.get());
-  else {
-    sb_error.SetErrorStringWithFormat(
-        "Error resuming thread plan for class: %s.", script_class_name);
-    if (log)
-      log->Printf("SBThread(%p)::StepUsingScriptedThreadPlan: Error queuing "
-                  "thread plan for class: %s",
-                  static_cast<void *>(exe_ctx.GetThreadPtr()),
-                  script_class_name);
-  }
+  if (new_plan_status.Success())
+    error = ResumeNewPlan(exe_ctx, new_plan_sp.get());
+  else
+    error.SetErrorString(new_plan_status.AsCString());
 
-  return sb_error;
+  return error;
 }
 
 SBError SBThread::JumpToLine(lldb::SBFileSpec &file_spec, uint32_t line) {
index c15c39a..fc54f5b 100644 (file)
@@ -143,6 +143,12 @@ bool SBThreadPlan::IsValid() {
 SBThreadPlan
 SBThreadPlan::QueueThreadPlanForStepOverRange(SBAddress &sb_start_address,
                                               lldb::addr_t size) {
+  SBError error;
+  return QueueThreadPlanForStepOverRange(sb_start_address, size, error);
+}
+
+SBThreadPlan SBThreadPlan::QueueThreadPlanForStepOverRange(
+    SBAddress &sb_start_address, lldb::addr_t size, SBError &error) {
   if (m_opaque_sp) {
     Address *start_address = sb_start_address.get();
     if (!start_address) {
@@ -152,9 +158,16 @@ SBThreadPlan::QueueThreadPlanForStepOverRange(SBAddress &sb_start_address,
     AddressRange range(*start_address, size);
     SymbolContext sc;
     start_address->CalculateSymbolContext(&sc);
-    return SBThreadPlan(
-        m_opaque_sp->GetThread().QueueThreadPlanForStepOverRange(
-            false, range, sc, eAllThreads));
+    Status plan_status;
+
+    SBThreadPlan plan =
+        SBThreadPlan(m_opaque_sp->GetThread().QueueThreadPlanForStepOverRange(
+            false, range, sc, eAllThreads, plan_status));
+
+    if (plan_status.Fail())
+      error.SetErrorString(plan_status.AsCString());
+
+    return plan;
   } else {
     return SBThreadPlan();
   }
@@ -163,6 +176,13 @@ SBThreadPlan::QueueThreadPlanForStepOverRange(SBAddress &sb_start_address,
 SBThreadPlan
 SBThreadPlan::QueueThreadPlanForStepInRange(SBAddress &sb_start_address,
                                             lldb::addr_t size) {
+  SBError error;
+  return QueueThreadPlanForStepInRange(sb_start_address, size, error);
+}
+
+SBThreadPlan
+SBThreadPlan::QueueThreadPlanForStepInRange(SBAddress &sb_start_address,
+                                            lldb::addr_t size, SBError &error) {
   if (m_opaque_sp) {
     Address *start_address = sb_start_address.get();
     if (!start_address) {
@@ -172,8 +192,16 @@ SBThreadPlan::QueueThreadPlanForStepInRange(SBAddress &sb_start_address,
     AddressRange range(*start_address, size);
     SymbolContext sc;
     start_address->CalculateSymbolContext(&sc);
-    return SBThreadPlan(m_opaque_sp->GetThread().QueueThreadPlanForStepInRange(
-        false, range, sc, NULL, eAllThreads));
+
+    Status plan_status;
+    SBThreadPlan plan =
+        SBThreadPlan(m_opaque_sp->GetThread().QueueThreadPlanForStepInRange(
+            false, range, sc, NULL, eAllThreads, plan_status));
+
+    if (plan_status.Fail())
+      error.SetErrorString(plan_status.AsCString());
+
+    return plan;
   } else {
     return SBThreadPlan();
   }
@@ -182,13 +210,28 @@ SBThreadPlan::QueueThreadPlanForStepInRange(SBAddress &sb_start_address,
 SBThreadPlan
 SBThreadPlan::QueueThreadPlanForStepOut(uint32_t frame_idx_to_step_to,
                                         bool first_insn) {
+  SBError error;
+  return QueueThreadPlanForStepOut(frame_idx_to_step_to, first_insn, error);
+}
+
+SBThreadPlan
+SBThreadPlan::QueueThreadPlanForStepOut(uint32_t frame_idx_to_step_to,
+                                        bool first_insn, SBError &error) {
   if (m_opaque_sp) {
     SymbolContext sc;
     sc = m_opaque_sp->GetThread().GetStackFrameAtIndex(0)->GetSymbolContext(
         lldb::eSymbolContextEverything);
-    return SBThreadPlan(m_opaque_sp->GetThread().QueueThreadPlanForStepOut(
-        false, &sc, first_insn, false, eVoteYes, eVoteNoOpinion,
-        frame_idx_to_step_to));
+
+    Status plan_status;
+    SBThreadPlan plan =
+        SBThreadPlan(m_opaque_sp->GetThread().QueueThreadPlanForStepOut(
+            false, &sc, first_insn, false, eVoteYes, eVoteNoOpinion,
+            frame_idx_to_step_to, plan_status));
+
+    if (plan_status.Fail())
+      error.SetErrorString(plan_status.AsCString());
+
+    return plan;
   } else {
     return SBThreadPlan();
   }
@@ -196,13 +239,26 @@ SBThreadPlan::QueueThreadPlanForStepOut(uint32_t frame_idx_to_step_to,
 
 SBThreadPlan
 SBThreadPlan::QueueThreadPlanForRunToAddress(SBAddress sb_address) {
+  SBError error;
+  return QueueThreadPlanForRunToAddress(sb_address, error);
+}
+
+SBThreadPlan SBThreadPlan::QueueThreadPlanForRunToAddress(SBAddress sb_address,
+                                                          SBError &error) {
   if (m_opaque_sp) {
     Address *address = sb_address.get();
     if (!address)
       return SBThreadPlan();
 
-    return SBThreadPlan(m_opaque_sp->GetThread().QueueThreadPlanForRunToAddress(
-        false, *address, false));
+    Status plan_status;
+    SBThreadPlan plan =
+        SBThreadPlan(m_opaque_sp->GetThread().QueueThreadPlanForRunToAddress(
+            false, *address, false, plan_status));
+
+    if (plan_status.Fail())
+      error.SetErrorString(plan_status.AsCString());
+
+    return plan;
   } else {
     return SBThreadPlan();
   }
@@ -210,9 +266,23 @@ SBThreadPlan::QueueThreadPlanForRunToAddress(SBAddress sb_address) {
 
 SBThreadPlan
 SBThreadPlan::QueueThreadPlanForStepScripted(const char *script_class_name) {
+  SBError error;
+  return QueueThreadPlanForStepScripted(script_class_name, error);
+}
+
+SBThreadPlan
+SBThreadPlan::QueueThreadPlanForStepScripted(const char *script_class_name,
+                                             SBError &error) {
   if (m_opaque_sp) {
-    return SBThreadPlan(m_opaque_sp->GetThread().QueueThreadPlanForStepScripted(
-        false, script_class_name, false));
+    Status plan_status;
+    SBThreadPlan plan =
+        SBThreadPlan(m_opaque_sp->GetThread().QueueThreadPlanForStepScripted(
+            false, script_class_name, false, plan_status));
+
+    if (plan_status.Fail())
+      error.SetErrorString(plan_status.AsCString());
+
+    return plan;
   } else {
     return SBThreadPlan();
   }
index 6ee8a48..131d2a7 100644 (file)
@@ -853,6 +853,10 @@ size_t Breakpoint::GetNumResolvedLocations() const {
   return m_locations.GetNumResolvedLocations();
 }
 
+bool Breakpoint::HasResolvedLocations() const {
+  return GetNumResolvedLocations() > 0;
+}
+
 size_t Breakpoint::GetNumLocations() const { return m_locations.GetSize(); }
 
 bool Breakpoint::AddName(llvm::StringRef new_name) {
index 94cba9d..95c5666 100644 (file)
@@ -650,6 +650,7 @@ protected:
       bool_stop_other_threads = true;
 
     ThreadPlanSP new_plan_sp;
+    Status new_plan_status;
 
     if (m_step_type == eStepTypeInto) {
       StackFrame *frame = thread->GetStackFrameAtIndex(0).get();
@@ -699,7 +700,7 @@ protected:
             abort_other_plans, range,
             frame->GetSymbolContext(eSymbolContextEverything),
             m_options.m_step_in_target.c_str(), stop_other_threads,
-            m_options.m_step_in_avoid_no_debug,
+            new_plan_status, m_options.m_step_in_avoid_no_debug,
             m_options.m_step_out_avoid_no_debug);
 
         if (new_plan_sp && !m_options.m_avoid_regexp.empty()) {
@@ -709,7 +710,7 @@ protected:
         }
       } else
         new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction(
-            false, abort_other_plans, bool_stop_other_threads);
+            false, abort_other_plans, bool_stop_other_threads, new_plan_status);
     } else if (m_step_type == eStepTypeOver) {
       StackFrame *frame = thread->GetStackFrameAtIndex(0).get();
 
@@ -718,25 +719,26 @@ protected:
             abort_other_plans,
             frame->GetSymbolContext(eSymbolContextEverything).line_entry,
             frame->GetSymbolContext(eSymbolContextEverything),
-            stop_other_threads, m_options.m_step_out_avoid_no_debug);
+            stop_other_threads, new_plan_status,
+            m_options.m_step_out_avoid_no_debug);
       else
         new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction(
-            true, abort_other_plans, bool_stop_other_threads);
+            true, abort_other_plans, bool_stop_other_threads, new_plan_status);
     } else if (m_step_type == eStepTypeTrace) {
       new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction(
-          false, abort_other_plans, bool_stop_other_threads);
+          false, abort_other_plans, bool_stop_other_threads, new_plan_status);
     } else if (m_step_type == eStepTypeTraceOver) {
       new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction(
-          true, abort_other_plans, bool_stop_other_threads);
+          true, abort_other_plans, bool_stop_other_threads, new_plan_status);
     } else if (m_step_type == eStepTypeOut) {
       new_plan_sp = thread->QueueThreadPlanForStepOut(
           abort_other_plans, nullptr, false, bool_stop_other_threads, eVoteYes,
-          eVoteNoOpinion, thread->GetSelectedFrameIndex(),
+          eVoteNoOpinion, thread->GetSelectedFrameIndex(), new_plan_status,
           m_options.m_step_out_avoid_no_debug);
     } else if (m_step_type == eStepTypeScripted) {
       new_plan_sp = thread->QueueThreadPlanForStepScripted(
           abort_other_plans, m_options.m_class_name.c_str(),
-          bool_stop_other_threads);
+          bool_stop_other_threads, new_plan_status);
     } else {
       result.AppendError("step type is not supported");
       result.SetStatus(eReturnStatusFailed);
@@ -794,7 +796,7 @@ protected:
         result.SetStatus(eReturnStatusSuccessContinuingNoResult);
       }
     } else {
-      result.AppendError("Couldn't find thread plan to implement step type.");
+      result.SetError(new_plan_status);
       result.SetStatus(eReturnStatusFailed);
     }
     return result.Succeeded();
@@ -1190,6 +1192,7 @@ protected:
       }
 
       ThreadPlanSP new_plan_sp;
+      Status new_plan_status;
 
       if (frame->HasDebugInformation()) {
         // Finally we got here...  Translate the given line number to a bunch
@@ -1270,13 +1273,19 @@ protected:
 
         new_plan_sp = thread->QueueThreadPlanForStepUntil(
             abort_other_plans, &address_list.front(), address_list.size(),
-            m_options.m_stop_others, m_options.m_frame_idx);
-        // User level plans should be master plans so they can be interrupted
-        // (e.g. by hitting a breakpoint) and other plans executed by the user
-        // (stepping around the breakpoint) and then a "continue" will resume
-        // the original plan.
-        new_plan_sp->SetIsMasterPlan(true);
-        new_plan_sp->SetOkayToDiscard(false);
+            m_options.m_stop_others, m_options.m_frame_idx, new_plan_status);
+        if (new_plan_sp) {
+          // User level plans should be master plans so they can be interrupted
+          // (e.g. by hitting a breakpoint) and other plans executed by the
+          // user (stepping around the breakpoint) and then a "continue" will
+          // resume the original plan.
+          new_plan_sp->SetIsMasterPlan(true);
+          new_plan_sp->SetOkayToDiscard(false);
+        } else {
+          result.SetError(new_plan_status);
+          result.SetStatus(eReturnStatusFailed);
+          return false;
+        }
       } else {
         result.AppendErrorWithFormat(
             "Frame index %u of thread %u has no debug information.\n",
index d19ab44..19d9676 100644 (file)
@@ -157,13 +157,15 @@ bool AppleThreadPlanStepThroughObjCTrampoline::ShouldStop(Event *event_ptr) {
 
       SymbolContext sc = m_thread.GetStackFrameAtIndex(0)->GetSymbolContext(
           eSymbolContextEverything);
+      Status status;
       const bool abort_other_plans = false;
       const bool first_insn = true;
       const uint32_t frame_idx = 0;
       m_run_to_sp = m_thread.QueueThreadPlanForStepOutNoShouldStop(
           abort_other_plans, &sc, first_insn, m_stop_others, eVoteNoOpinion,
-          eVoteNoOpinion, frame_idx);
-      m_run_to_sp->SetPrivate(true);
+          eVoteNoOpinion, frame_idx, status);
+      if (m_run_to_sp && status.Success())
+        m_run_to_sp->SetPrivate(true);
       return false;
     }
 
index b80c9eb..7ec772b 100644 (file)
@@ -1920,7 +1920,7 @@ Process::CreateBreakpointSite(const BreakpointLocationSP &owner,
           owner->SetBreakpointSite(bp_site_sp);
           return m_breakpoint_site_list.Add(bp_site_sp);
         } else {
-          if (show_error) {
+          if (show_error || use_hardware) {
             // Report error for setting breakpoint...
             GetTarget().GetDebugger().GetErrorFile()->Printf(
                 "warning: failed to set breakpoint site at 0x%" PRIx64
index 1e885bd..6965f58 100644 (file)
@@ -716,14 +716,18 @@ protected:
                 StopInfoSP stored_stop_info_sp = thread_sp->GetStopInfo();
                 assert(stored_stop_info_sp.get() == this);
 
+                Status new_plan_status;
                 ThreadPlanSP new_plan_sp(
                     thread_sp->QueueThreadPlanForStepSingleInstruction(
-                        false,  // step-over
-                        false,  // abort_other_plans
-                        true)); // stop_other_threads
-                new_plan_sp->SetIsMasterPlan(true);
-                new_plan_sp->SetOkayToDiscard(false);
-                new_plan_sp->SetPrivate(true);
+                        false, // step-over
+                        false, // abort_other_plans
+                        true,  // stop_other_threads
+                        new_plan_status));
+                if (new_plan_sp && new_plan_status.Success()) {
+                  new_plan_sp->SetIsMasterPlan(true);
+                  new_plan_sp->SetOkayToDiscard(false);
+                  new_plan_sp->SetPrivate(true);
+                }
                 process_sp->GetThreadList().SetSelectedThreadByID(
                     thread_sp->GetID());
                 process_sp->ResumeSynchronous(nullptr);
index c8fea37..fe46c7b 100644 (file)
@@ -627,7 +627,8 @@ BreakpointSP Target::CreateBreakpoint(SearchFilterSP &filter_sp,
                                       bool resolve_indirect_symbols) {
   BreakpointSP bp_sp;
   if (filter_sp && resolver_sp) {
-    bp_sp.reset(new Breakpoint(*this, filter_sp, resolver_sp, request_hardware,
+    const bool hardware = request_hardware || GetRequireHardwareBreakpoints();
+    bp_sp.reset(new Breakpoint(*this, filter_sp, resolver_sp, hardware,
                                resolve_indirect_symbols));
     resolver_sp->SetBreakpoint(bp_sp.get());
     AddBreakpoint(bp_sp, internal);
@@ -3135,6 +3136,7 @@ void Target::StopHook::GetDescription(Stream *s,
 // class TargetProperties
 //--------------------------------------------------------------
 
+// clang-format off
 static constexpr OptionEnumValueElement g_dynamic_value_types[] = {
     {eNoDynamicValues, "no-dynamic-values",
      "Don't calculate the dynamic type of values"},
@@ -3362,7 +3364,10 @@ static constexpr PropertyDefinition g_properties[] = {
      nullptr, {}, "If true, LLDB will show variables that are meant to "
                   "support the operation of a language's runtime support."},
     {"non-stop-mode", OptionValue::eTypeBoolean, false, 0, nullptr, {},
-     "Disable lock-step debugging, instead control threads independently."}};
+     "Disable lock-step debugging, instead control threads independently."},
+    {"require-hardware-breakpoint", OptionValue::eTypeBoolean, false, 0,
+     nullptr, {}, "Require all breakpoints to be hardware breakpoints."}};
+// clang-format on
 
 enum {
   ePropertyDefaultArch,
@@ -3407,7 +3412,8 @@ enum {
   ePropertyTrapHandlerNames,
   ePropertyDisplayRuntimeSupportValues,
   ePropertyNonStopModeEnabled,
-  ePropertyExperimental
+  ePropertyRequireHardwareBreakpoints,
+  ePropertyExperimental,
 };
 
 class TargetOptionValueProperties : public OptionValueProperties {
@@ -4005,6 +4011,17 @@ void TargetProperties::SetProcessLaunchInfo(
   SetDisableSTDIO(launch_info.GetFlags().Test(lldb::eLaunchFlagDisableSTDIO));
 }
 
+bool TargetProperties::GetRequireHardwareBreakpoints() const {
+  const uint32_t idx = ePropertyRequireHardwareBreakpoints;
+  return m_collection_sp->GetPropertyAtIndexAsBoolean(
+      nullptr, idx, g_properties[idx].default_uint_value != 0);
+}
+
+void TargetProperties::SetRequireHardwareBreakpoints(bool b) {
+  const uint32_t idx = ePropertyRequireHardwareBreakpoints;
+  m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b);
+}
+
 void TargetProperties::Arg0ValueChangedCallback(void *target_property_ptr,
                                                 OptionValue *) {
   TargetProperties *this_ =
index 0cd3ed6..404847e 100644 (file)
@@ -262,6 +262,7 @@ Thread::Thread(Process &process, lldb::tid_t tid, bool use_invalid_index_id)
                 static_cast<void *>(this), GetID());
 
   CheckInWithManager();
+
   QueueFundamentalPlan(true);
 }
 
@@ -395,13 +396,14 @@ lldb::StopInfoSP Thread::GetStopInfo() {
       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_failed = 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) {
+  if (have_valid_stop_info && !plan_overrides_trace && !plan_failed) {
     return m_stop_info_sp;
-  } else if (have_valid_completed_plan) {
+  } else if (completed_plan_sp) {
     return StopInfo::CreateStopReasonWithPlan(
         completed_plan_sp, GetReturnValueObject(), GetExpressionVariable());
   } else {
@@ -1173,12 +1175,34 @@ ThreadPlan *Thread::GetPreviousPlan(ThreadPlan *current_plan) {
   return nullptr;
 }
 
-void Thread::QueueThreadPlan(ThreadPlanSP &thread_plan_sp,
-                             bool abort_other_plans) {
+Status Thread::QueueThreadPlan(ThreadPlanSP &thread_plan_sp,
+                               bool abort_other_plans) {
+  Status status;
+  StreamString s;
+  if (!thread_plan_sp->ValidatePlan(&s)) {
+    DiscardThreadPlansUpToPlan(thread_plan_sp);
+    thread_plan_sp.reset();
+    status.SetErrorString(s.GetString());
+    return status;
+  }
+
   if (abort_other_plans)
     DiscardThreadPlans(true);
 
   PushPlan(thread_plan_sp);
+
+  // This seems a little funny, but I don't want to have to split up the
+  // constructor and the DidPush in the scripted plan, that seems annoying.
+  // That means the constructor has to be in DidPush. So I have to validate the
+  // plan AFTER pushing it, and then take it off again...
+  if (!thread_plan_sp->ValidatePlan(&s)) {
+    DiscardThreadPlansUpToPlan(thread_plan_sp);
+    thread_plan_sp.reset();
+    status.SetErrorString(s.GetString());
+    return status;
+  }
+
+  return status;
 }
 
 void Thread::EnableTracer(bool value, bool single_stepping) {
@@ -1343,23 +1367,24 @@ ThreadPlanSP Thread::QueueFundamentalPlan(bool abort_other_plans) {
 }
 
 ThreadPlanSP Thread::QueueThreadPlanForStepSingleInstruction(
-    bool step_over, bool abort_other_plans, bool stop_other_threads) {
+    bool step_over, bool abort_other_plans, bool stop_other_threads,
+    Status &status) {
   ThreadPlanSP thread_plan_sp(new ThreadPlanStepInstruction(
       *this, step_over, stop_other_threads, eVoteNoOpinion, eVoteNoOpinion));
-  QueueThreadPlan(thread_plan_sp, abort_other_plans);
+  status = QueueThreadPlan(thread_plan_sp, abort_other_plans);
   return thread_plan_sp;
 }
 
 ThreadPlanSP Thread::QueueThreadPlanForStepOverRange(
     bool abort_other_plans, const AddressRange &range,
     const SymbolContext &addr_context, lldb::RunMode stop_other_threads,
-    LazyBool step_out_avoids_code_withoug_debug_info) {
+    Status &status, LazyBool step_out_avoids_code_withoug_debug_info) {
   ThreadPlanSP thread_plan_sp;
   thread_plan_sp.reset(new ThreadPlanStepOverRange(
       *this, range, addr_context, stop_other_threads,
       step_out_avoids_code_withoug_debug_info));
 
-  QueueThreadPlan(thread_plan_sp, abort_other_plans);
+  status = QueueThreadPlan(thread_plan_sp, abort_other_plans);
   return thread_plan_sp;
 }
 
@@ -1368,17 +1393,17 @@ ThreadPlanSP Thread::QueueThreadPlanForStepOverRange(
 ThreadPlanSP Thread::QueueThreadPlanForStepOverRange(
     bool abort_other_plans, const LineEntry &line_entry,
     const SymbolContext &addr_context, lldb::RunMode stop_other_threads,
-    LazyBool step_out_avoids_code_withoug_debug_info) {
+    Status &status, LazyBool step_out_avoids_code_withoug_debug_info) {
   return QueueThreadPlanForStepOverRange(
       abort_other_plans, line_entry.GetSameLineContiguousAddressRange(),
-      addr_context, stop_other_threads,
+      addr_context, stop_other_threads, status,
       step_out_avoids_code_withoug_debug_info);
 }
 
 ThreadPlanSP Thread::QueueThreadPlanForStepInRange(
     bool abort_other_plans, const AddressRange &range,
     const SymbolContext &addr_context, const char *step_in_target,
-    lldb::RunMode stop_other_threads,
+    lldb::RunMode stop_other_threads, Status &status,
     LazyBool step_in_avoids_code_without_debug_info,
     LazyBool step_out_avoids_code_without_debug_info) {
   ThreadPlanSP thread_plan_sp(
@@ -1391,7 +1416,7 @@ ThreadPlanSP Thread::QueueThreadPlanForStepInRange(
   if (step_in_target)
     plan->SetStepInTarget(step_in_target);
 
-  QueueThreadPlan(thread_plan_sp, abort_other_plans);
+  status = QueueThreadPlan(thread_plan_sp, abort_other_plans);
   return thread_plan_sp;
 }
 
@@ -1399,12 +1424,12 @@ ThreadPlanSP Thread::QueueThreadPlanForStepInRange(
 ThreadPlanSP Thread::QueueThreadPlanForStepInRange(
     bool abort_other_plans, const LineEntry &line_entry,
     const SymbolContext &addr_context, const char *step_in_target,
-    lldb::RunMode stop_other_threads,
+    lldb::RunMode stop_other_threads, Status &status,
     LazyBool step_in_avoids_code_without_debug_info,
     LazyBool step_out_avoids_code_without_debug_info) {
   return QueueThreadPlanForStepInRange(
       abort_other_plans, line_entry.GetSameLineContiguousAddressRange(),
-      addr_context, step_in_target, stop_other_threads,
+      addr_context, step_in_target, stop_other_threads, status,
       step_in_avoids_code_without_debug_info,
       step_out_avoids_code_without_debug_info);
 }
@@ -1412,23 +1437,19 @@ ThreadPlanSP Thread::QueueThreadPlanForStepInRange(
 ThreadPlanSP Thread::QueueThreadPlanForStepOut(
     bool abort_other_plans, SymbolContext *addr_context, bool first_insn,
     bool stop_other_threads, Vote stop_vote, Vote run_vote, uint32_t frame_idx,
-    LazyBool step_out_avoids_code_without_debug_info) {
+    Status &status, LazyBool step_out_avoids_code_without_debug_info) {
   ThreadPlanSP thread_plan_sp(new ThreadPlanStepOut(
       *this, addr_context, first_insn, stop_other_threads, stop_vote, run_vote,
       frame_idx, step_out_avoids_code_without_debug_info));
 
-  if (thread_plan_sp->ValidatePlan(nullptr)) {
-    QueueThreadPlan(thread_plan_sp, abort_other_plans);
-    return thread_plan_sp;
-  } else {
-    return ThreadPlanSP();
-  }
+  status = QueueThreadPlan(thread_plan_sp, abort_other_plans);
+  return thread_plan_sp;
 }
 
 ThreadPlanSP Thread::QueueThreadPlanForStepOutNoShouldStop(
     bool abort_other_plans, SymbolContext *addr_context, bool first_insn,
     bool stop_other_threads, Vote stop_vote, Vote run_vote, uint32_t frame_idx,
-    bool continue_to_next_branch) {
+    Status &status, bool continue_to_next_branch) {
   const bool calculate_return_value =
       false; // No need to calculate the return value here.
   ThreadPlanSP thread_plan_sp(new ThreadPlanStepOut(
@@ -1439,59 +1460,51 @@ ThreadPlanSP Thread::QueueThreadPlanForStepOutNoShouldStop(
       static_cast<ThreadPlanStepOut *>(thread_plan_sp.get());
   new_plan->ClearShouldStopHereCallbacks();
 
-  if (thread_plan_sp->ValidatePlan(nullptr)) {
-    QueueThreadPlan(thread_plan_sp, abort_other_plans);
-    return thread_plan_sp;
-  } else {
-    return ThreadPlanSP();
-  }
+  status = QueueThreadPlan(thread_plan_sp, abort_other_plans);
+  return thread_plan_sp;
 }
 
 ThreadPlanSP Thread::QueueThreadPlanForStepThrough(StackID &return_stack_id,
                                                    bool abort_other_plans,
-                                                   bool stop_other_threads) {
+                                                   bool stop_other_threads,
+                                                   Status &status) {
   ThreadPlanSP thread_plan_sp(
       new ThreadPlanStepThrough(*this, return_stack_id, stop_other_threads));
   if (!thread_plan_sp || !thread_plan_sp->ValidatePlan(nullptr))
     return ThreadPlanSP();
 
-  QueueThreadPlan(thread_plan_sp, abort_other_plans);
+  status = QueueThreadPlan(thread_plan_sp, abort_other_plans);
   return thread_plan_sp;
 }
 
 ThreadPlanSP Thread::QueueThreadPlanForRunToAddress(bool abort_other_plans,
                                                     Address &target_addr,
-                                                    bool stop_other_threads) {
+                                                    bool stop_other_threads,
+                                                    Status &status) {
   ThreadPlanSP thread_plan_sp(
       new ThreadPlanRunToAddress(*this, target_addr, stop_other_threads));
-  QueueThreadPlan(thread_plan_sp, abort_other_plans);
+
+  status = QueueThreadPlan(thread_plan_sp, abort_other_plans);
   return thread_plan_sp;
 }
 
-ThreadPlanSP Thread::QueueThreadPlanForStepUntil(bool abort_other_plans,
-                                                 lldb::addr_t *address_list,
-                                                 size_t num_addresses,
-                                                 bool stop_other_threads,
-                                                 uint32_t frame_idx) {
+ThreadPlanSP Thread::QueueThreadPlanForStepUntil(
+    bool abort_other_plans, lldb::addr_t *address_list, size_t num_addresses,
+    bool stop_other_threads, uint32_t frame_idx, Status &status) {
   ThreadPlanSP thread_plan_sp(new ThreadPlanStepUntil(
       *this, address_list, num_addresses, stop_other_threads, frame_idx));
-  QueueThreadPlan(thread_plan_sp, abort_other_plans);
+
+  status = QueueThreadPlan(thread_plan_sp, abort_other_plans);
   return thread_plan_sp;
 }
 
 lldb::ThreadPlanSP Thread::QueueThreadPlanForStepScripted(
-    bool abort_other_plans, const char *class_name, bool stop_other_threads) {
+    bool abort_other_plans, const char *class_name, bool stop_other_threads,
+    Status &status) {
   ThreadPlanSP thread_plan_sp(new ThreadPlanPython(*this, class_name));
-  QueueThreadPlan(thread_plan_sp, abort_other_plans);
-  // This seems a little funny, but I don't want to have to split up the
-  // constructor and the DidPush in the scripted plan, that seems annoying.
-  // That means the constructor has to be in DidPush. So I have to validate the
-  // plan AFTER pushing it, and then take it off again...
-  if (!thread_plan_sp->ValidatePlan(nullptr)) {
-    DiscardThreadPlansUpToPlan(thread_plan_sp);
-    return ThreadPlanSP();
-  } else
-    return thread_plan_sp;
+
+  status = QueueThreadPlan(thread_plan_sp, abort_other_plans);
+  return thread_plan_sp;
 }
 
 uint32_t Thread::GetIndexID() const { return m_index_id; }
@@ -2110,12 +2123,12 @@ Status Thread::StepIn(bool source_step,
     if (source_step && frame_sp && frame_sp->HasDebugInformation()) {
       SymbolContext sc(frame_sp->GetSymbolContext(eSymbolContextEverything));
       new_plan_sp = QueueThreadPlanForStepInRange(
-          abort_other_plans, sc.line_entry, sc, nullptr, run_mode,
+          abort_other_plans, sc.line_entry, sc, nullptr, run_mode, error,
           step_in_avoids_code_without_debug_info,
           step_out_avoids_code_without_debug_info);
     } else {
       new_plan_sp = QueueThreadPlanForStepSingleInstruction(
-          false, abort_other_plans, run_mode);
+          false, abort_other_plans, run_mode, error);
     }
 
     new_plan_sp->SetIsMasterPlan(true);
@@ -2144,11 +2157,11 @@ Status Thread::StepOver(bool source_step,
     if (source_step && frame_sp && frame_sp->HasDebugInformation()) {
       SymbolContext sc(frame_sp->GetSymbolContext(eSymbolContextEverything));
       new_plan_sp = QueueThreadPlanForStepOverRange(
-          abort_other_plans, sc.line_entry, sc, run_mode,
+          abort_other_plans, sc.line_entry, sc, run_mode, error,
           step_out_avoids_code_without_debug_info);
     } else {
       new_plan_sp = QueueThreadPlanForStepSingleInstruction(
-          true, abort_other_plans, run_mode);
+          true, abort_other_plans, run_mode, error);
     }
 
     new_plan_sp->SetIsMasterPlan(true);
@@ -2173,7 +2186,7 @@ Status Thread::StepOut() {
 
     ThreadPlanSP new_plan_sp(QueueThreadPlanForStepOut(
         abort_other_plans, nullptr, first_instruction, stop_other_threads,
-        eVoteYes, eVoteNoOpinion, 0));
+        eVoteYes, eVoteNoOpinion, 0, error));
 
     new_plan_sp->SetIsMasterPlan(true);
     new_plan_sp->SetOkayToDiscard(false);
index 1216bb5..1f2c69c 100644 (file)
@@ -25,6 +25,7 @@ using namespace lldb_private;
 ThreadPlan::ThreadPlan(ThreadPlanKind kind, const char *name, Thread &thread,
                        Vote stop_vote, Vote run_vote)
     : m_thread(thread), m_stop_vote(stop_vote), m_run_vote(run_vote),
+      m_takes_iteration_count(false), m_could_not_resolve_hw_bp(false),
       m_kind(kind), m_name(name), m_plan_complete_mutex(),
       m_cached_plan_explains_stop(eLazyBoolCalculate), m_plan_complete(false),
       m_plan_private(false), m_okay_to_discard(true), m_is_master_plan(false),
index e8ea73f..2ea083d 100644 (file)
@@ -27,17 +27,18 @@ void ThreadPlanCallOnFunctionExit::DidPush() {
   // completes.
 
   // Set stop vote to eVoteNo.
+  Status status;
   m_step_out_threadplan_sp = GetThread().QueueThreadPlanForStepOut(
       false,             // abort other plans
       nullptr,           // addr_context
       true,              // first instruction
       true,              // stop other threads
       eVoteNo,           // do not say "we're stopping"
-      eVoteNoOpinion,    // don't care about
-                         // run state broadcasting
+      eVoteNoOpinion,    // don't care about run state broadcasting
       0,                 // frame_idx
+      status,            // status
       eLazyBoolCalculate // avoid code w/o debinfo
-      );
+  );
 }
 
 // -------------------------------------------------------------------------
index 8db443b..84b93bd 100644 (file)
@@ -31,7 +31,7 @@ using namespace lldb_private;
 ThreadPlanPython::ThreadPlanPython(Thread &thread, const char *class_name)
     : ThreadPlan(ThreadPlan::eKindPython, "Python based Thread Plan", thread,
                  eVoteNoOpinion, eVoteNoOpinion),
-      m_class_name(class_name) {
+      m_class_name(class_name), m_did_push(false) {
   SetIsMasterPlan(true);
   SetOkayToDiscard(true);
   SetPrivate(false);
@@ -43,20 +43,22 @@ ThreadPlanPython::~ThreadPlanPython() {
 }
 
 bool ThreadPlanPython::ValidatePlan(Stream *error) {
-  // I have to postpone setting up the implementation till after the constructor
-  // because I need to call
-  // shared_from_this, which you can't do in the constructor.  So I'll do it
-  // here.
-  if (m_implementation_sp)
+  if (!m_did_push)
     return true;
-  else
+
+  if (!m_implementation_sp) {
+    if (error)
+      error->Printf("Python thread plan does not have an implementation");
     return false;
+  }
+
+  return true;
 }
 
 void ThreadPlanPython::DidPush() {
   // We set up the script side in DidPush, so that it can push other plans in
   // the constructor, and doesn't have to care about the details of DidPush.
-
+  m_did_push = true;
   if (!m_class_name.empty()) {
     ScriptInterpreter *script_interp = m_thread.GetProcess()
                                            ->GetTarget()
index 8091b8a..bd11f8b 100644 (file)
@@ -69,6 +69,8 @@ void ThreadPlanRunToAddress::SetInitialBreakpoints() {
                      ->CreateBreakpoint(m_addresses[i], true, false)
                      .get();
     if (breakpoint != nullptr) {
+      if (breakpoint->IsHardware() && !breakpoint->HasResolvedLocations())
+        m_could_not_resolve_hw_bp = true;
       m_break_ids[i] = breakpoint->GetID();
       breakpoint->SetThreadID(m_thread.GetID());
       breakpoint->SetBreakpointKind("run-to-address");
@@ -81,6 +83,7 @@ ThreadPlanRunToAddress::~ThreadPlanRunToAddress() {
   for (size_t i = 0; i < num_break_ids; i++) {
     m_thread.CalculateTarget()->RemoveBreakpointByID(m_break_ids[i]);
   }
+  m_could_not_resolve_hw_bp = false;
 }
 
 void ThreadPlanRunToAddress::GetDescription(Stream *s,
@@ -129,10 +132,15 @@ void ThreadPlanRunToAddress::GetDescription(Stream *s,
 }
 
 bool ThreadPlanRunToAddress::ValidatePlan(Stream *error) {
+  if (m_could_not_resolve_hw_bp) {
+    if (error)
+      error->Printf("Could not set hardware breakpoint(s)");
+    return false;
+  }
+
   // If we couldn't set the breakpoint for some reason, then this won't work.
   bool all_bps_good = true;
   size_t num_break_ids = m_break_ids.size();
-
   for (size_t i = 0; i < num_break_ids; i++) {
     if (m_break_ids[i] == LLDB_INVALID_BREAK_ID) {
       all_bps_good = false;
index 8141a66..8062d80 100644 (file)
@@ -39,11 +39,11 @@ ThreadPlanShouldStopHere::ThreadPlanShouldStopHere(
 ThreadPlanShouldStopHere::~ThreadPlanShouldStopHere() = default;
 
 bool ThreadPlanShouldStopHere::InvokeShouldStopHereCallback(
-    FrameComparison operation) {
+    FrameComparison operation, Status &status) {
   bool should_stop_here = true;
   if (m_callbacks.should_stop_here_callback) {
     should_stop_here = m_callbacks.should_stop_here_callback(
-        m_owner, m_flags, operation, m_baton);
+        m_owner, m_flags, operation, status, m_baton);
     Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
     if (log) {
       lldb::addr_t current_addr =
@@ -59,7 +59,7 @@ bool ThreadPlanShouldStopHere::InvokeShouldStopHereCallback(
 
 bool ThreadPlanShouldStopHere::DefaultShouldStopHereCallback(
     ThreadPlan *current_plan, Flags &flags, FrameComparison operation,
-    void *baton) {
+    Status &status, void *baton) {
   bool should_stop_here = true;
   StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get();
   if (!frame)
@@ -96,7 +96,7 @@ bool ThreadPlanShouldStopHere::DefaultShouldStopHereCallback(
 
 ThreadPlanSP ThreadPlanShouldStopHere::DefaultStepFromHereCallback(
     ThreadPlan *current_plan, Flags &flags, FrameComparison operation,
-    void *baton) {
+    Status &status, void *baton) {
   const bool stop_others = false;
   const size_t frame_index = 0;
   ThreadPlanSP return_plan_sp;
@@ -133,8 +133,8 @@ ThreadPlanSP ThreadPlanShouldStopHere::DefaultStepFromHereCallback(
                     "Queueing StepInRange plan to step through line 0 code.");
 
       return_plan_sp = current_plan->GetThread().QueueThreadPlanForStepInRange(
-          false, range, sc, NULL, eOnlyDuringStepping, eLazyBoolCalculate,
-          eLazyBoolNo);
+          false, range, sc, NULL, eOnlyDuringStepping, status,
+          eLazyBoolCalculate, eLazyBoolNo);
     }
   }
 
@@ -142,24 +142,25 @@ ThreadPlanSP ThreadPlanShouldStopHere::DefaultStepFromHereCallback(
     return_plan_sp =
         current_plan->GetThread().QueueThreadPlanForStepOutNoShouldStop(
             false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion,
-            frame_index, true);
+            frame_index, status, true);
   return return_plan_sp;
 }
 
 ThreadPlanSP ThreadPlanShouldStopHere::QueueStepOutFromHerePlan(
-    lldb_private::Flags &flags, lldb::FrameComparison operation) {
+    lldb_private::Flags &flags, lldb::FrameComparison operation,
+    Status &status) {
   ThreadPlanSP return_plan_sp;
   if (m_callbacks.step_from_here_callback) {
-    return_plan_sp =
-        m_callbacks.step_from_here_callback(m_owner, flags, operation, m_baton);
+    return_plan_sp = m_callbacks.step_from_here_callback(
+        m_owner, flags, operation, status, m_baton);
   }
   return return_plan_sp;
 }
 
 lldb::ThreadPlanSP ThreadPlanShouldStopHere::CheckShouldStopHereAndQueueStepOut(
-    lldb::FrameComparison operation) {
-  if (!InvokeShouldStopHereCallback(operation))
-    return QueueStepOutFromHerePlan(m_flags, operation);
+    lldb::FrameComparison operation, Status &status) {
+  if (!InvokeShouldStopHereCallback(operation, status))
+    return QueueStepOutFromHerePlan(m_flags, operation, status);
   else
     return ThreadPlanSP();
 }
index 6784e89..8f9889a 100644 (file)
@@ -108,8 +108,16 @@ void ThreadPlanStepInRange::SetupAvoidNoDebug(
 
 void ThreadPlanStepInRange::GetDescription(Stream *s,
                                            lldb::DescriptionLevel level) {
+
+  auto PrintFailureIfAny = [&]() {
+    if (m_status.Success())
+      return;
+    s->Printf(" failed (%s)", m_status.AsCString());
+  };
+
   if (level == lldb::eDescriptionLevelBrief) {
     s->Printf("step in");
+    PrintFailureIfAny();
     return;
   }
 
@@ -130,6 +138,8 @@ void ThreadPlanStepInRange::GetDescription(Stream *s,
     DumpRanges(s);
   }
 
+  PrintFailureIfAny();
+
   s->PutChar('.');
 }
 
@@ -162,7 +172,8 @@ bool ThreadPlanStepInRange::ShouldStop(Event *event_ptr) {
     // ShouldStopHere plan, and otherwise we're done.
     // FIXME - This can be both a step in and a step out.  Probably should
     // record which in the m_virtual_step.
-    m_sub_plan_sp = CheckShouldStopHereAndQueueStepOut(eFrameCompareYounger);
+    m_sub_plan_sp =
+        CheckShouldStopHereAndQueueStepOut(eFrameCompareYounger, m_status);
   } else {
     // Stepping through should be done running other threads in general, since
     // we're setting a breakpoint and continuing.  So only stop others if we
@@ -181,11 +192,12 @@ bool ThreadPlanStepInRange::ShouldStop(Event *event_ptr) {
       // I'm going to make the assumption that you wouldn't RETURN to a
       // trampoline.  So if we are in a trampoline we think the frame is older
       // because the trampoline confused the backtracer.
-      m_sub_plan_sp = m_thread.QueueThreadPlanForStepThrough(m_stack_id, false,
-                                                             stop_others);
+      m_sub_plan_sp = m_thread.QueueThreadPlanForStepThrough(
+          m_stack_id, false, stop_others, m_status);
       if (!m_sub_plan_sp) {
         // Otherwise check the ShouldStopHere for step out:
-        m_sub_plan_sp = CheckShouldStopHereAndQueueStepOut(frame_order);
+        m_sub_plan_sp =
+            CheckShouldStopHereAndQueueStepOut(frame_order, m_status);
         if (log) {
           if (m_sub_plan_sp)
             log->Printf("ShouldStopHere found plan to step out of this frame.");
@@ -223,8 +235,8 @@ bool ThreadPlanStepInRange::ShouldStop(Event *event_ptr) {
     // We may have set the plan up above in the FrameIsOlder section:
 
     if (!m_sub_plan_sp)
-      m_sub_plan_sp = m_thread.QueueThreadPlanForStepThrough(m_stack_id, false,
-                                                             stop_others);
+      m_sub_plan_sp = m_thread.QueueThreadPlanForStepThrough(
+          m_stack_id, false, stop_others, m_status);
 
     if (log) {
       if (m_sub_plan_sp)
@@ -236,7 +248,7 @@ bool ThreadPlanStepInRange::ShouldStop(Event *event_ptr) {
     // If not, give the "should_stop" callback a chance to push a plan to get
     // us out of here. But only do that if we actually have stepped in.
     if (!m_sub_plan_sp && frame_order == eFrameCompareYounger)
-      m_sub_plan_sp = CheckShouldStopHereAndQueueStepOut(frame_order);
+      m_sub_plan_sp = CheckShouldStopHereAndQueueStepOut(frame_order, m_status);
 
     // If we've stepped in and we are going to stop here, check to see if we
     // were asked to run past the prologue, and if so do that.
@@ -284,7 +296,7 @@ bool ThreadPlanStepInRange::ShouldStop(Event *event_ptr) {
             log->Printf("Pushing past prologue ");
 
           m_sub_plan_sp = m_thread.QueueThreadPlanForRunToAddress(
-              false, func_start_address, true);
+              false, func_start_address, true, m_status);
         }
       }
     }
@@ -380,7 +392,7 @@ bool ThreadPlanStepInRange::FrameMatchesAvoidCriteria() {
 
 bool ThreadPlanStepInRange::DefaultShouldStopHereCallback(
     ThreadPlan *current_plan, Flags &flags, FrameComparison operation,
-    void *baton) {
+    Status &status, void *baton) {
   bool should_stop_here = true;
   StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get();
   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
@@ -388,7 +400,7 @@ bool ThreadPlanStepInRange::DefaultShouldStopHereCallback(
   // First see if the ThreadPlanShouldStopHere default implementation thinks we
   // should get out of here:
   should_stop_here = ThreadPlanShouldStopHere::DefaultShouldStopHereCallback(
-      current_plan, flags, operation, baton);
+      current_plan, flags, operation, status, baton);
   if (!should_stop_here)
     return should_stop_here;
 
index b2cecf3..7707454 100644 (file)
@@ -53,11 +53,19 @@ void ThreadPlanStepInstruction::SetUpState() {
 
 void ThreadPlanStepInstruction::GetDescription(Stream *s,
                                                lldb::DescriptionLevel level) {
+  auto PrintFailureIfAny = [&]() {
+    if (m_status.Success())
+      return;
+    s->Printf(" failed (%s)", m_status.AsCString());
+  };
+
   if (level == lldb::eDescriptionLevelBrief) {
     if (m_step_over)
       s->Printf("instruction step over");
     else
       s->Printf("instruction step into");
+
+    PrintFailureIfAny();
   } else {
     s->Printf("Stepping one instruction past ");
     s->Address(m_instruction_addr, sizeof(addr_t));
@@ -68,6 +76,8 @@ void ThreadPlanStepInstruction::GetDescription(Stream *s,
       s->Printf(" stepping over calls");
     else
       s->Printf(" stepping into calls");
+
+    PrintFailureIfAny();
   }
 }
 
@@ -188,7 +198,8 @@ bool ThreadPlanStepInstruction::ShouldStop(Event *event_ptr) {
           // for now it is safer to run others.
           const bool stop_others = false;
           m_thread.QueueThreadPlanForStepOutNoShouldStop(
-              false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion, 0);
+              false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion, 0,
+              m_status);
           return false;
         } else {
           if (log) {
index db8ab9f..378de53 100644 (file)
@@ -129,7 +129,10 @@ ThreadPlanStepOut::ThreadPlanStepOut(
     Breakpoint *return_bp = m_thread.CalculateTarget()
                                 ->CreateBreakpoint(m_return_addr, true, false)
                                 .get();
+
     if (return_bp != nullptr) {
+      if (return_bp->IsHardware() && !return_bp->HasResolvedLocations())
+        m_could_not_resolve_hw_bp = true;
       return_bp->SetThreadID(m_thread.GetID());
       m_return_bp_id = return_bp->GetID();
       return_bp->SetBreakpointKind("step-out");
@@ -223,14 +226,24 @@ void ThreadPlanStepOut::GetDescription(Stream *s,
 bool ThreadPlanStepOut::ValidatePlan(Stream *error) {
   if (m_step_out_to_inline_plan_sp)
     return m_step_out_to_inline_plan_sp->ValidatePlan(error);
-  else if (m_step_through_inline_plan_sp)
+
+  if (m_step_through_inline_plan_sp)
     return m_step_through_inline_plan_sp->ValidatePlan(error);
-  else if (m_return_bp_id == LLDB_INVALID_BREAK_ID) {
+
+  if (m_could_not_resolve_hw_bp) {
+    if (error)
+      error->PutCString(
+          "Could not create hardware breakpoint for thread plan.");
+    return false;
+  }
+
+  if (m_return_bp_id == LLDB_INVALID_BREAK_ID) {
     if (error)
       error->PutCString("Could not create return address breakpoint.");
     return false;
-  } else
-    return true;
+  }
+
+  return true;
 }
 
 bool ThreadPlanStepOut::DoPlanExplainsStop(Event *event_ptr) {
@@ -277,7 +290,7 @@ bool ThreadPlanStepOut::DoPlanExplainsStop(Event *event_ptr) {
         }
 
         if (done) {
-          if (InvokeShouldStopHereCallback(eFrameCompareOlder)) {
+          if (InvokeShouldStopHereCallback(eFrameCompareOlder, m_status)) {
             CalculateReturnValue();
             SetPlanComplete();
           }
@@ -339,12 +352,12 @@ bool ThreadPlanStepOut::ShouldStop(Event *event_ptr) {
   // is consult the ShouldStopHere, and we are done.
 
   if (done) {
-    if (InvokeShouldStopHereCallback(eFrameCompareOlder)) {
+    if (InvokeShouldStopHereCallback(eFrameCompareOlder, m_status)) {
       CalculateReturnValue();
       SetPlanComplete();
     } else {
       m_step_out_further_plan_sp =
-          QueueStepOutFromHerePlan(m_flags, eFrameCompareOlder);
+          QueueStepOutFromHerePlan(m_flags, eFrameCompareOlder, m_status);
       done = false;
     }
   }
index 2043b96..a9fff1b 100644 (file)
@@ -47,10 +47,18 @@ ThreadPlanStepOverRange::~ThreadPlanStepOverRange() = default;
 
 void ThreadPlanStepOverRange::GetDescription(Stream *s,
                                              lldb::DescriptionLevel level) {
+  auto PrintFailureIfAny = [&]() {
+    if (m_status.Success())
+      return;
+    s->Printf(" failed (%s)", m_status.AsCString());
+  };
+
   if (level == lldb::eDescriptionLevelBrief) {
     s->Printf("step over");
+    PrintFailureIfAny();
     return;
   }
+
   s->Printf("Stepping over");
   bool printed_line_info = false;
   if (m_addr_context.line_entry.IsValid()) {
@@ -64,6 +72,8 @@ void ThreadPlanStepOverRange::GetDescription(Stream *s,
     DumpRanges(s);
   }
 
+  PrintFailureIfAny();
+
   s->PutChar('.');
 }
 
@@ -147,8 +157,8 @@ bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) {
     // because the trampoline confused the backtracer. As below, we step
     // through first, and then try to figure out how to get back out again.
 
-    new_plan_sp =
-        m_thread.QueueThreadPlanForStepThrough(m_stack_id, false, stop_others);
+    new_plan_sp = m_thread.QueueThreadPlanForStepThrough(m_stack_id, false,
+                                                         stop_others, m_status);
 
     if (new_plan_sp && log)
       log->Printf(
@@ -169,11 +179,11 @@ bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) {
       if (IsEquivalentContext(older_context)) {
         new_plan_sp = m_thread.QueueThreadPlanForStepOutNoShouldStop(
             false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion, 0,
-            true);
+            m_status, true);
         break;
       } else {
-        new_plan_sp = m_thread.QueueThreadPlanForStepThrough(m_stack_id, false,
-                                                             stop_others);
+        new_plan_sp = m_thread.QueueThreadPlanForStepThrough(
+            m_stack_id, false, stop_others, m_status);
         // If we found a way through, then we should stop recursing.
         if (new_plan_sp)
           break;
@@ -192,8 +202,8 @@ bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) {
       // we are in a stub then it's likely going to be hard to get out from
       // here.  It is probably easiest to step into the stub, and then it will
       // be straight-forward to step out.
-      new_plan_sp = m_thread.QueueThreadPlanForStepThrough(m_stack_id, false,
-                                                           stop_others);
+      new_plan_sp = m_thread.QueueThreadPlanForStepThrough(
+          m_stack_id, false, stop_others, m_status);
     } else {
       // The current clang (at least through 424) doesn't always get the
       // address range for the DW_TAG_inlined_subroutines right, so that when
@@ -283,8 +293,8 @@ bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) {
                               cur_pc);
 
                       new_plan_sp = m_thread.QueueThreadPlanForStepOverRange(
-                          abort_other_plans, step_range, sc,
-                          stop_other_threads);
+                          abort_other_plans, step_range, sc, stop_other_threads,
+                          m_status);
                       break;
                     }
                     look_ahead_step++;
@@ -305,7 +315,7 @@ bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) {
   // If we haven't figured out something to do yet, then ask the ShouldStopHere
   // callback:
   if (!new_plan_sp) {
-    new_plan_sp = CheckShouldStopHereAndQueueStepOut(frame_order);
+    new_plan_sp = CheckShouldStopHereAndQueueStepOut(frame_order, m_status);
   }
 
   if (!new_plan_sp)
@@ -319,7 +329,7 @@ bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) {
   if (!new_plan_sp) {
     // For efficiencies sake, we know we're done here so we don't have to do
     // this calculation again in MischiefManaged.
-    SetPlanComplete();
+    SetPlanComplete(m_status.Success());
     return true;
   } else
     return false;
index 507f0e7..7ba68ee 100644 (file)
@@ -57,7 +57,15 @@ void ThreadPlanStepRange::DidPush() {
   SetNextBranchBreakpoint();
 }
 
-bool ThreadPlanStepRange::ValidatePlan(Stream *error) { return true; }
+bool ThreadPlanStepRange::ValidatePlan(Stream *error) {
+  if (m_could_not_resolve_hw_bp) {
+    if (error)
+      error->PutCString(
+          "Could not create hardware breakpoint for thread plan.");
+    return false;
+  }
+  return true;
+}
 
 Vote ThreadPlanStepRange::ShouldReportStop(Event *event_ptr) {
   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
@@ -281,6 +289,7 @@ void ThreadPlanStepRange::ClearNextBranchBreakpoint() {
                   m_next_branch_bp_sp->GetID());
     GetTarget().RemoveBreakpointByID(m_next_branch_bp_sp->GetID());
     m_next_branch_bp_sp.reset();
+    m_could_not_resolve_hw_bp = false;
   }
 }
 
@@ -331,6 +340,11 @@ bool ThreadPlanStepRange::SetNextBranchBreakpoint() {
       m_next_branch_bp_sp =
           GetTarget().CreateBreakpoint(run_to_address, is_internal, false);
       if (m_next_branch_bp_sp) {
+
+        if (m_next_branch_bp_sp->IsHardware() &&
+            !m_next_branch_bp_sp->HasResolvedLocations())
+          m_could_not_resolve_hw_bp = true;
+
         if (log) {
           lldb::break_id_t bp_site_id = LLDB_INVALID_BREAK_ID;
           BreakpointLocationSP bp_loc =
@@ -347,8 +361,10 @@ bool ThreadPlanStepRange::SetNextBranchBreakpoint() {
                       run_to_address.GetLoadAddress(
                           &m_thread.GetProcess()->GetTarget()));
         }
+
         m_next_branch_bp_sp->SetThreadID(m_thread.GetID());
         m_next_branch_bp_sp->SetBreakpointKind("next-branch-location");
+
         return true;
       } else
         return false;
index b373edb..d1f3c22 100644 (file)
@@ -58,7 +58,10 @@ ThreadPlanStepThrough::ThreadPlanStepThrough(Thread &thread,
               ->GetTarget()
               .CreateBreakpoint(m_backstop_addr, true, false)
               .get();
+
       if (return_bp != nullptr) {
+        if (return_bp->IsHardware() && !return_bp->HasResolvedLocations())
+          m_could_not_resolve_hw_bp = true;
         return_bp->SetThreadID(m_thread.GetID());
         m_backstop_bkpt_id = return_bp->GetID();
         return_bp->SetBreakpointKind("step-through-backstop");
@@ -135,7 +138,26 @@ void ThreadPlanStepThrough::GetDescription(Stream *s,
 }
 
 bool ThreadPlanStepThrough::ValidatePlan(Stream *error) {
-  return m_sub_plan_sp.get() != nullptr;
+  if (m_could_not_resolve_hw_bp) {
+    if (error)
+      error->PutCString(
+          "Could not create hardware breakpoint for thread plan.");
+    return false;
+  }
+
+  if (m_backstop_bkpt_id == LLDB_INVALID_BREAK_ID) {
+    if (error)
+      error->PutCString("Could not create backstop breakpoint.");
+    return false;
+  }
+
+  if (!m_sub_plan_sp.get()) {
+    if (error)
+      error->PutCString("Does not have a subplan.");
+    return false;
+  }
+
+  return true;
 }
 
 bool ThreadPlanStepThrough::DoPlanExplainsStop(Event *event_ptr) {
@@ -211,6 +233,7 @@ void ThreadPlanStepThrough::ClearBackstopBreakpoint() {
   if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID) {
     m_thread.GetProcess()->GetTarget().RemoveBreakpointByID(m_backstop_bkpt_id);
     m_backstop_bkpt_id = LLDB_INVALID_BREAK_ID;
+    m_could_not_resolve_hw_bp = false;
   }
 }
 
index b0cd53a..1335c62 100644 (file)
@@ -53,7 +53,10 @@ ThreadPlanStepUntil::ThreadPlanStepUntil(Thread &thread,
       m_return_addr = return_frame_sp->GetStackID().GetPC();
       Breakpoint *return_bp =
           target_sp->CreateBreakpoint(m_return_addr, true, false).get();
+
       if (return_bp != nullptr) {
+        if (return_bp->IsHardware() && !return_bp->HasResolvedLocations())
+          m_could_not_resolve_hw_bp = true;
         return_bp->SetThreadID(thread_id);
         m_return_bp_id = return_bp->GetID();
         return_bp->SetBreakpointKind("until-return-backstop");
@@ -93,6 +96,7 @@ void ThreadPlanStepUntil::Clear() {
     }
   }
   m_until_points.clear();
+  m_could_not_resolve_hw_bp = false;
 }
 
 void ThreadPlanStepUntil::GetDescription(Stream *s,
@@ -123,9 +127,16 @@ void ThreadPlanStepUntil::GetDescription(Stream *s,
 }
 
 bool ThreadPlanStepUntil::ValidatePlan(Stream *error) {
-  if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
+  if (m_could_not_resolve_hw_bp) {
+    if (error)
+      error->PutCString(
+          "Could not create hardware breakpoint for thread plan.");
+    return false;
+  } else if (m_return_bp_id == LLDB_INVALID_BREAK_ID) {
+    if (error)
+      error->PutCString("Could not create return breakpoint.");
     return false;
-  else {
+  else {
     until_collection::iterator pos, end = m_until_points.end();
     for (pos = m_until_points.begin(); pos != end; pos++) {
       if (!LLDB_BREAK_ID_IS_VALID((*pos).second))