JDevlieghere created this revision.
JDevlieghere added reviewers: jingham, jasonmolenda.
JDevlieghere added a project: LLDB.
Herald added subscribers: teemperor, abidh.

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 hardware breakpoints even 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 therefore can fail to resolve, this patch also extends error 
handling in thread plans, where breakpoints are used for stepping.


Repository:
  rLLDB LLDB

https://reviews.llvm.org/D54221

Files:
  include/lldb/API/SBBreakpoint.h
  include/lldb/Breakpoint/Breakpoint.h
  include/lldb/Target/Target.h
  include/lldb/Target/Thread.h
  include/lldb/Target/ThreadPlanBase.h
  include/lldb/Target/ThreadPlanStepInRange.h
  include/lldb/Target/ThreadPlanStepInstruction.h
  include/lldb/Target/ThreadPlanStepOut.h
  include/lldb/Target/ThreadPlanStepRange.h
  include/lldb/Target/ThreadPlanStepThrough.h
  include/lldb/Target/ThreadPlanStepUntil.h
  
packages/Python/lldbsuite/test/functionalities/breakpoint/require_hw_breakpoints/Makefile
  
packages/Python/lldbsuite/test/functionalities/breakpoint/require_hw_breakpoints/TestRequireHWBreakpoints.py
  
packages/Python/lldbsuite/test/functionalities/breakpoint/require_hw_breakpoints/main.c
  scripts/interface/SBBreakpoint.i
  source/API/SBBreakpoint.cpp
  source/API/SBThread.cpp
  source/API/SBThreadPlan.cpp
  source/Breakpoint/Breakpoint.cpp
  source/Commands/CommandObjectThread.cpp
  
source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp
  source/Target/Process.cpp
  source/Target/StopInfo.cpp
  source/Target/Target.cpp
  source/Target/Thread.cpp
  source/Target/ThreadPlanCallOnFunctionExit.cpp
  source/Target/ThreadPlanShouldStopHere.cpp
  source/Target/ThreadPlanStepInRange.cpp
  source/Target/ThreadPlanStepInstruction.cpp
  source/Target/ThreadPlanStepOut.cpp
  source/Target/ThreadPlanStepOverRange.cpp
  source/Target/ThreadPlanStepRange.cpp
  source/Target/ThreadPlanStepThrough.cpp
  source/Target/ThreadPlanStepUntil.cpp

Index: source/Target/ThreadPlanStepUntil.cpp
===================================================================
--- source/Target/ThreadPlanStepUntil.cpp
+++ source/Target/ThreadPlanStepUntil.cpp
@@ -39,7 +39,8 @@
       m_return_bp_id(LLDB_INVALID_BREAK_ID),
       m_return_addr(LLDB_INVALID_ADDRESS), m_stepped_out(false),
       m_should_stop(false), m_ran_analyze(false), m_explains_stop(false),
-      m_until_points(), m_stop_others(stop_others) {
+      m_until_points(), m_stop_others(stop_others),
+      m_could_not_resolve_hw_bp(false) {
   // Stash away our "until" addresses:
   TargetSP target_sp(m_thread.CalculateTarget());
 
@@ -57,7 +58,10 @@
       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");
@@ -97,6 +101,7 @@
     }
   }
   m_until_points.clear();
+  m_could_not_resolve_hw_bp = false;
 }
 
 void ThreadPlanStepUntil::GetDescription(Stream *s,
@@ -127,9 +132,16 @@
 }
 
 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))
Index: source/Target/ThreadPlanStepThrough.cpp
===================================================================
--- source/Target/ThreadPlanStepThrough.cpp
+++ source/Target/ThreadPlanStepThrough.cpp
@@ -40,7 +40,7 @@
                  eVoteNoOpinion, eVoteNoOpinion),
       m_start_address(0), m_backstop_bkpt_id(LLDB_INVALID_BREAK_ID),
       m_backstop_addr(LLDB_INVALID_ADDRESS), m_return_stack_id(m_stack_id),
-      m_stop_others(stop_others) {
+      m_stop_others(stop_others), m_could_not_resolve_hw_bp(false) {
   LookForPlanToStepThroughFromCurrentPC();
 
   // If we don't get a valid step through plan, don't bother to set up a
@@ -62,7 +62,10 @@
               ->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");
@@ -139,6 +142,16 @@
 }
 
 bool ThreadPlanStepThrough::ValidatePlan(Stream *error) {
+  if (m_could_not_resolve_hw_bp) {
+    if (error)
+      error->PutCString(
+          "Could not create hardware breakpoint for thread plan.");
+    return false;
+  } else if (m_backstop_bkpt_id == LLDB_INVALID_BREAK_ID) {
+    if (error)
+      error->PutCString("Could not create backstop breakpoint.");
+    return false;
+  }
   return m_sub_plan_sp.get() != nullptr;
 }
 
@@ -215,6 +228,7 @@
   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: source/Target/ThreadPlanStepRange.cpp
===================================================================
--- source/Target/ThreadPlanStepRange.cpp
+++ source/Target/ThreadPlanStepRange.cpp
@@ -45,7 +45,7 @@
       m_addr_context(addr_context), m_address_ranges(),
       m_stop_others(stop_others), m_stack_id(), m_parent_stack_id(),
       m_no_more_plans(false), m_first_run_event(true), m_use_fast_step(false),
-      m_given_ranges_only(given_ranges_only) {
+      m_given_ranges_only(given_ranges_only), m_could_not_resolve_hw_bp(false) {
   m_use_fast_step = GetTarget().GetUseFastStepping();
   AddRange(range);
   m_stack_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
@@ -61,7 +61,15 @@
   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));
@@ -285,6 +293,7 @@
                   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;
   }
 }
 
@@ -335,6 +344,11 @@
       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 =
@@ -351,8 +365,10 @@
                       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: source/Target/ThreadPlanStepOverRange.cpp
===================================================================
--- source/Target/ThreadPlanStepOverRange.cpp
+++ source/Target/ThreadPlanStepOverRange.cpp
@@ -139,6 +139,7 @@
   // forcing running one thread.
   bool stop_others = (m_stop_others == lldb::eOnlyThisThread);
   ThreadPlanSP new_plan_sp;
+  Status new_plan_status;
   FrameComparison frame_order = CompareCurrentFrameToStartFrame();
 
   if (frame_order == eFrameCompareOlder) {
@@ -151,8 +152,8 @@
     // 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(
+        new_plan_status, m_stack_id, false, stop_others);
 
     if (new_plan_sp && log)
       log->Printf(
@@ -172,12 +173,12 @@
           older_frame_sp->GetSymbolContext(eSymbolContextEverything);
       if (IsEquivalentContext(older_context)) {
         new_plan_sp = m_thread.QueueThreadPlanForStepOutNoShouldStop(
-            false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion, 0,
-            true);
+            new_plan_status, false, nullptr, true, stop_others, eVoteNo,
+            eVoteNoOpinion, 0, true);
         break;
       } else {
-        new_plan_sp = m_thread.QueueThreadPlanForStepThrough(m_stack_id, false,
-                                                             stop_others);
+        new_plan_sp = m_thread.QueueThreadPlanForStepThrough(
+            new_plan_status, m_stack_id, false, stop_others);
         // If we found a way through, then we should stop recursing.
         if (new_plan_sp)
           break;
@@ -196,8 +197,8 @@
       // 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(
+          new_plan_status, m_stack_id, false, stop_others);
     } 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
@@ -287,7 +288,7 @@
                               cur_pc);
 
                       new_plan_sp = m_thread.QueueThreadPlanForStepOverRange(
-                          abort_other_plans, step_range, sc,
+                          new_plan_status, abort_other_plans, step_range, sc,
                           stop_other_threads);
                       break;
                     }
@@ -323,7 +324,7 @@
   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(new_plan_status.Success());
     return true;
   } else
     return false;
Index: source/Target/ThreadPlanStepOut.cpp
===================================================================
--- source/Target/ThreadPlanStepOut.cpp
+++ source/Target/ThreadPlanStepOut.cpp
@@ -47,7 +47,8 @@
       m_return_bp_id(LLDB_INVALID_BREAK_ID),
       m_return_addr(LLDB_INVALID_ADDRESS), m_stop_others(stop_others),
       m_immediate_step_from_function(nullptr),
-      m_calculate_return_value(gather_return_value) {
+      m_calculate_return_value(gather_return_value),
+      m_could_not_resolve_hw_bp(false) {
   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
   SetFlagsToDefault();
   SetupAvoidNoDebug(step_out_avoids_code_without_debug_info);
@@ -133,7 +134,10 @@
     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");
@@ -229,7 +233,12 @@
     return m_step_out_to_inline_plan_sp->ValidatePlan(error);
   else 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) {
+  else 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 address breakpoint.");
     return false;
Index: source/Target/ThreadPlanStepInstruction.cpp
===================================================================
--- source/Target/ThreadPlanStepInstruction.cpp
+++ source/Target/ThreadPlanStepInstruction.cpp
@@ -191,8 +191,10 @@
           // StepInstruction should probably have the tri-state RunMode, but
           // for now it is safer to run others.
           const bool stop_others = false;
+          Status status;
           m_thread.QueueThreadPlanForStepOutNoShouldStop(
-              false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion, 0);
+              status, false, nullptr, true, stop_others, eVoteNo,
+              eVoteNoOpinion, 0);
           return false;
         } else {
           if (log) {
Index: source/Target/ThreadPlanStepInRange.cpp
===================================================================
--- source/Target/ThreadPlanStepInRange.cpp
+++ source/Target/ThreadPlanStepInRange.cpp
@@ -168,6 +168,7 @@
     // record which in the m_virtual_step.
     m_sub_plan_sp = CheckShouldStopHereAndQueueStepOut(eFrameCompareYounger);
   } else {
+    Status sub_plan_status;
     // Stepping through should be done running other threads in general, since
     // we're setting a breakpoint and continuing.  So only stop others if we
     // are explicitly told to do so.
@@ -185,8 +186,8 @@
       // 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(
+          sub_plan_status, m_stack_id, false, stop_others);
       if (!m_sub_plan_sp) {
         // Otherwise check the ShouldStopHere for step out:
         m_sub_plan_sp = CheckShouldStopHereAndQueueStepOut(frame_order);
@@ -227,8 +228,8 @@
     // 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(
+          sub_plan_status, m_stack_id, false, stop_others);
 
     if (log) {
       if (m_sub_plan_sp)
@@ -288,7 +289,7 @@
             log->Printf("Pushing past prologue ");
 
           m_sub_plan_sp = m_thread.QueueThreadPlanForRunToAddress(
-              false, func_start_address, true);
+              sub_plan_status, false, func_start_address, true);
         }
       }
     }
Index: source/Target/ThreadPlanShouldStopHere.cpp
===================================================================
--- source/Target/ThreadPlanShouldStopHere.cpp
+++ source/Target/ThreadPlanShouldStopHere.cpp
@@ -103,6 +103,7 @@
     void *baton) {
   const bool stop_others = false;
   const size_t frame_index = 0;
+  Status return_plan_status;
   ThreadPlanSP return_plan_sp;
   // If we are stepping through code at line number 0, then we need to step
   // over this range.  Otherwise we will step out.
@@ -137,16 +138,16 @@
                     "Queueing StepInRange plan to step through line 0 code.");
 
       return_plan_sp = current_plan->GetThread().QueueThreadPlanForStepInRange(
-          false, range, sc, NULL, eOnlyDuringStepping, eLazyBoolCalculate,
-          eLazyBoolNo);
+          return_plan_status, false, range, sc, NULL, eOnlyDuringStepping,
+          eLazyBoolCalculate, eLazyBoolNo);
     }
   }
 
   if (!return_plan_sp)
     return_plan_sp =
         current_plan->GetThread().QueueThreadPlanForStepOutNoShouldStop(
-            false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion,
-            frame_index, true);
+            return_plan_status, false, nullptr, true, stop_others, eVoteNo,
+            eVoteNoOpinion, frame_index, true);
   return return_plan_sp;
 }
 
Index: source/Target/ThreadPlanCallOnFunctionExit.cpp
===================================================================
--- source/Target/ThreadPlanCallOnFunctionExit.cpp
+++ source/Target/ThreadPlanCallOnFunctionExit.cpp
@@ -27,7 +27,9 @@
   // completes.
 
   // Set stop vote to eVoteNo.
+  Status status;
   m_step_out_threadplan_sp = GetThread().QueueThreadPlanForStepOut(
+      status,
       false,             // abort other plans
       nullptr,           // addr_context
       true,              // first instruction
@@ -37,7 +39,7 @@
                          // run state broadcasting
       0,                 // frame_idx
       eLazyBoolCalculate // avoid code w/o debinfo
-      );
+  );
 }
 
 // -------------------------------------------------------------------------
Index: source/Target/Thread.cpp
===================================================================
--- source/Target/Thread.cpp
+++ source/Target/Thread.cpp
@@ -266,7 +266,9 @@
                 static_cast<void *>(this), GetID());
 
   CheckInWithManager();
-  QueueFundamentalPlan(true);
+
+  Status status;
+  QueueFundamentalPlan(status, true);
 }
 
 Thread::~Thread() {
@@ -399,13 +401,14 @@
       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 {
@@ -1177,12 +1180,34 @@
   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) {
@@ -1340,47 +1365,50 @@
   return error;
 }
 
-ThreadPlanSP Thread::QueueFundamentalPlan(bool abort_other_plans) {
+ThreadPlanSP Thread::QueueFundamentalPlan(Status &status,
+                                          bool abort_other_plans) {
   ThreadPlanSP thread_plan_sp(new ThreadPlanBase(*this));
-  QueueThreadPlan(thread_plan_sp, abort_other_plans);
+  status = QueueThreadPlan(thread_plan_sp, abort_other_plans);
   return thread_plan_sp;
 }
 
-ThreadPlanSP Thread::QueueThreadPlanForStepSingleInstruction(
-    bool step_over, bool abort_other_plans, bool stop_other_threads) {
+ThreadPlanSP
+Thread::QueueThreadPlanForStepSingleInstruction(Status &status, bool step_over,
+                                                bool abort_other_plans,
+                                                bool stop_other_threads) {
   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,
+    Status &status, bool abort_other_plans, const AddressRange &range,
     const SymbolContext &addr_context, lldb::RunMode stop_other_threads,
     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;
 }
 
 // Call the QueueThreadPlanForStepOverRange method which takes an address
 // range.
 ThreadPlanSP Thread::QueueThreadPlanForStepOverRange(
-    bool abort_other_plans, const LineEntry &line_entry,
+    Status &status, 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) {
   return QueueThreadPlanForStepOverRange(
-      abort_other_plans, line_entry.GetSameLineContiguousAddressRange(),
+      status, abort_other_plans, line_entry.GetSameLineContiguousAddressRange(),
       addr_context, stop_other_threads,
       step_out_avoids_code_withoug_debug_info);
 }
 
 ThreadPlanSP Thread::QueueThreadPlanForStepInRange(
-    bool abort_other_plans, const AddressRange &range,
+    Status &status, bool abort_other_plans, const AddressRange &range,
     const SymbolContext &addr_context, const char *step_in_target,
     lldb::RunMode stop_other_threads,
     LazyBool step_in_avoids_code_without_debug_info,
@@ -1395,44 +1423,40 @@
   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;
 }
 
 // Call the QueueThreadPlanForStepInRange method which takes an address range.
 ThreadPlanSP Thread::QueueThreadPlanForStepInRange(
-    bool abort_other_plans, const LineEntry &line_entry,
+    Status &status, bool abort_other_plans, const LineEntry &line_entry,
     const SymbolContext &addr_context, const char *step_in_target,
     lldb::RunMode stop_other_threads,
     LazyBool step_in_avoids_code_without_debug_info,
     LazyBool step_out_avoids_code_without_debug_info) {
   return QueueThreadPlanForStepInRange(
-      abort_other_plans, line_entry.GetSameLineContiguousAddressRange(),
+      status, abort_other_plans, line_entry.GetSameLineContiguousAddressRange(),
       addr_context, step_in_target, stop_other_threads,
       step_in_avoids_code_without_debug_info,
       step_out_avoids_code_without_debug_info);
 }
 
 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, 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) {
   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 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) {
   const bool calculate_return_value =
       false; // No need to calculate the return value here.
   ThreadPlanSP thread_plan_sp(new ThreadPlanStepOut(
@@ -1443,59 +1467,52 @@
       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,
+ThreadPlanSP Thread::QueueThreadPlanForStepThrough(Status &status,
+                                                   StackID &return_stack_id,
                                                    bool abort_other_plans,
                                                    bool stop_other_threads) {
   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,
+ThreadPlanSP Thread::QueueThreadPlanForRunToAddress(Status &status,
+                                                    bool abort_other_plans,
                                                     Address &target_addr,
                                                     bool stop_other_threads) {
   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(
+    Status &status, bool abort_other_plans, lldb::addr_t *address_list,
+    size_t num_addresses, bool stop_other_threads, uint32_t frame_idx) {
   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) {
+lldb::ThreadPlanSP
+Thread::QueueThreadPlanForStepScripted(Status &status, bool abort_other_plans,
+                                       const char *class_name,
+                                       bool stop_other_threads) {
   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; }
@@ -2114,12 +2131,12 @@
     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,
+          error, abort_other_plans, sc.line_entry, sc, nullptr, run_mode,
           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);
+          error, false, abort_other_plans, run_mode);
     }
 
     new_plan_sp->SetIsMasterPlan(true);
@@ -2148,11 +2165,11 @@
     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,
+          error, abort_other_plans, sc.line_entry, sc, run_mode,
           step_out_avoids_code_without_debug_info);
     } else {
       new_plan_sp = QueueThreadPlanForStepSingleInstruction(
-          true, abort_other_plans, run_mode);
+          error, true, abort_other_plans, run_mode);
     }
 
     new_plan_sp->SetIsMasterPlan(true);
@@ -2176,8 +2193,8 @@
     const bool abort_other_plans = false;
 
     ThreadPlanSP new_plan_sp(QueueThreadPlanForStepOut(
-        abort_other_plans, nullptr, first_instruction, stop_other_threads,
-        eVoteYes, eVoteNoOpinion, 0));
+        error, abort_other_plans, nullptr, first_instruction,
+        stop_other_threads, eVoteYes, eVoteNoOpinion, 0));
 
     new_plan_sp->SetIsMasterPlan(true);
     new_plan_sp->SetOkayToDiscard(false);
Index: source/Target/Target.cpp
===================================================================
--- source/Target/Target.cpp
+++ source/Target/Target.cpp
@@ -631,7 +631,8 @@
                                       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);
@@ -3133,6 +3134,7 @@
 // class TargetProperties
 //--------------------------------------------------------------
 
+// clang-format off
 static constexpr OptionEnumValueElement g_dynamic_value_types[] = {
     {eNoDynamicValues, "no-dynamic-values",
      "Don't calculate the dynamic type of values"},
@@ -3360,7 +3362,10 @@
      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,
@@ -3405,7 +3410,8 @@
   ePropertyTrapHandlerNames,
   ePropertyDisplayRuntimeSupportValues,
   ePropertyNonStopModeEnabled,
-  ePropertyExperimental
+  ePropertyRequireHardwareBreakpoints,
+  ePropertyExperimental,
 };
 
 class TargetOptionValueProperties : public OptionValueProperties {
@@ -4003,6 +4009,17 @@
   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: source/Target/StopInfo.cpp
===================================================================
--- source/Target/StopInfo.cpp
+++ source/Target/StopInfo.cpp
@@ -720,11 +720,14 @@
                 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_status,
+                        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);
@@ -1042,6 +1045,8 @@
     if (m_description.empty()) {
       StreamString strm;
       m_plan_sp->GetDescription(&strm, eDescriptionLevelBrief);
+      if (!m_plan_sp->PlanSucceeded())
+        strm << " (FAILED)";
       m_description = strm.GetString();
     }
     return m_description.c_str();
Index: source/Target/Process.cpp
===================================================================
--- source/Target/Process.cpp
+++ source/Target/Process.cpp
@@ -1924,7 +1924,7 @@
           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: source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp
===================================================================
--- source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp
+++ source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp
@@ -161,12 +161,13 @@
 
       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);
+          status, abort_other_plans, &sc, first_insn, m_stop_others,
+          eVoteNoOpinion, eVoteNoOpinion, frame_idx);
       m_run_to_sp->SetPrivate(true);
       return false;
     }
Index: source/Commands/CommandObjectThread.cpp
===================================================================
--- source/Commands/CommandObjectThread.cpp
+++ source/Commands/CommandObjectThread.cpp
@@ -654,6 +654,7 @@
       bool_stop_other_threads = true;
 
     ThreadPlanSP new_plan_sp;
+    Status new_plan_status;
 
     if (m_step_type == eStepTypeInto) {
       StackFrame *frame = thread->GetStackFrameAtIndex(0).get();
@@ -700,7 +701,7 @@
         }
 
         new_plan_sp = thread->QueueThreadPlanForStepInRange(
-            abort_other_plans, range,
+            new_plan_status, 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,
@@ -713,33 +714,33 @@
         }
       } else
         new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction(
-            false, abort_other_plans, bool_stop_other_threads);
+            new_plan_status, false, abort_other_plans, bool_stop_other_threads);
     } else if (m_step_type == eStepTypeOver) {
       StackFrame *frame = thread->GetStackFrameAtIndex(0).get();
 
       if (frame->HasDebugInformation())
         new_plan_sp = thread->QueueThreadPlanForStepOverRange(
-            abort_other_plans,
+            new_plan_status, abort_other_plans,
             frame->GetSymbolContext(eSymbolContextEverything).line_entry,
             frame->GetSymbolContext(eSymbolContextEverything),
             stop_other_threads, m_options.m_step_out_avoid_no_debug);
       else
         new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction(
-            true, abort_other_plans, bool_stop_other_threads);
+            new_plan_status, true, abort_other_plans, bool_stop_other_threads);
     } else if (m_step_type == eStepTypeTrace) {
       new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction(
-          false, abort_other_plans, bool_stop_other_threads);
+          new_plan_status, false, abort_other_plans, bool_stop_other_threads);
     } else if (m_step_type == eStepTypeTraceOver) {
       new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction(
-          true, abort_other_plans, bool_stop_other_threads);
+          new_plan_status, true, abort_other_plans, bool_stop_other_threads);
     } else if (m_step_type == eStepTypeOut) {
       new_plan_sp = thread->QueueThreadPlanForStepOut(
-          abort_other_plans, nullptr, false, bool_stop_other_threads, eVoteYes,
-          eVoteNoOpinion, thread->GetSelectedFrameIndex(),
-          m_options.m_step_out_avoid_no_debug);
+          new_plan_status, abort_other_plans, nullptr, false,
+          bool_stop_other_threads, eVoteYes, eVoteNoOpinion,
+          thread->GetSelectedFrameIndex(), 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(),
+          new_plan_status, abort_other_plans, m_options.m_class_name.c_str(),
           bool_stop_other_threads);
     } else {
       result.AppendError("step type is not supported");
@@ -798,6 +799,7 @@
         result.SetStatus(eReturnStatusSuccessContinuingNoResult);
       }
     } else {
+      result.SetError(new_plan_status);
       result.AppendError("Couldn't find thread plan to implement step type.");
       result.SetStatus(eReturnStatusFailed);
     }
@@ -1194,6 +1196,7 @@
       }
 
       ThreadPlanSP new_plan_sp;
+      Status new_plan_status;
 
       if (frame->HasDebugInformation()) {
         // Finally we got here...  Translate the given line number to a bunch
@@ -1273,15 +1276,17 @@
         }
 
         new_plan_sp = thread->QueueThreadPlanForStepUntil(
-            abort_other_plans, &address_list.front(), address_list.size(),
-            m_options.m_stop_others, m_options.m_frame_idx);
+            new_plan_status, 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);
       } else {
+        result.SetError(new_plan_status);
         result.AppendErrorWithFormat(
             "Frame index %u of thread %u has no debug information.\n",
             m_options.m_frame_idx, m_options.m_thread_idx);
Index: source/Breakpoint/Breakpoint.cpp
===================================================================
--- source/Breakpoint/Breakpoint.cpp
+++ source/Breakpoint/Breakpoint.cpp
@@ -857,6 +857,10 @@
   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: source/API/SBThreadPlan.cpp
===================================================================
--- source/API/SBThreadPlan.cpp
+++ source/API/SBThreadPlan.cpp
@@ -152,9 +152,10 @@
     AddressRange range(*start_address, size);
     SymbolContext sc;
     start_address->CalculateSymbolContext(&sc);
+    Status plan_status;
     return SBThreadPlan(
         m_opaque_sp->GetThread().QueueThreadPlanForStepOverRange(
-            false, range, sc, eAllThreads));
+            plan_status, false, range, sc, eAllThreads));
   } else {
     return SBThreadPlan();
   }
@@ -172,8 +173,9 @@
     AddressRange range(*start_address, size);
     SymbolContext sc;
     start_address->CalculateSymbolContext(&sc);
+    Status plan_status;
     return SBThreadPlan(m_opaque_sp->GetThread().QueueThreadPlanForStepInRange(
-        false, range, sc, NULL, eAllThreads));
+        plan_status, false, range, sc, NULL, eAllThreads));
   } else {
     return SBThreadPlan();
   }
@@ -184,10 +186,11 @@
                                         bool first_insn) {
   if (m_opaque_sp) {
     SymbolContext sc;
+    Status status;
     sc = m_opaque_sp->GetThread().GetStackFrameAtIndex(0)->GetSymbolContext(
         lldb::eSymbolContextEverything);
     return SBThreadPlan(m_opaque_sp->GetThread().QueueThreadPlanForStepOut(
-        false, &sc, first_insn, false, eVoteYes, eVoteNoOpinion,
+        status, false, &sc, first_insn, false, eVoteYes, eVoteNoOpinion,
         frame_idx_to_step_to));
   } else {
     return SBThreadPlan();
@@ -201,18 +204,20 @@
     if (!address)
       return SBThreadPlan();
 
+    Status status;
     return SBThreadPlan(m_opaque_sp->GetThread().QueueThreadPlanForRunToAddress(
-        false, *address, false));
+        status, false, *address, false));
   } else {
     return SBThreadPlan();
   }
 }
 
 SBThreadPlan
 SBThreadPlan::QueueThreadPlanForStepScripted(const char *script_class_name) {
   if (m_opaque_sp) {
+    Status status;
     return SBThreadPlan(m_opaque_sp->GetThread().QueueThreadPlanForStepScripted(
-        false, script_class_name, false));
+        status, false, script_class_name, false));
   } else {
     return SBThreadPlan();
   }
Index: source/API/SBThread.cpp
===================================================================
--- source/API/SBThread.cpp
+++ source/API/SBThread.cpp
@@ -657,17 +657,18 @@
   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()) {
       const LazyBool avoid_no_debug = eLazyBoolCalculate;
       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, abort_other_plans, sc.line_entry, sc,
+          stop_other_threads, avoid_no_debug);
     } else {
       new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction(
-          true, abort_other_plans, stop_other_threads);
+          new_plan_status, true, abort_other_plans, stop_other_threads);
     }
   }
   error = ResumeNewPlan(exe_ctx, new_plan_sp.get());
@@ -707,6 +708,7 @@
   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));
@@ -723,12 +725,12 @@
     const LazyBool step_in_avoids_code_without_debug_info =
         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, abort_other_plans, range, sc, target_name,
+        stop_other_threads, 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);
+        new_plan_status, false, abort_other_plans, stop_other_threads);
   }
   error = ResumeNewPlan(exe_ctx, new_plan_sp.get());
 }
@@ -759,9 +761,10 @@
   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));
+      new_plan_status, abort_other_plans, NULL, false, stop_other_threads,
+      eVoteYes, eVoteNoOpinion, 0, avoid_no_debug));
 
   error = ResumeNewPlan(exe_ctx, new_plan_sp.get());
 }
@@ -812,9 +815,10 @@
     return;
   }
 
+  Status new_plan_status;
   ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForStepOut(
-      abort_other_plans, NULL, false, stop_other_threads, eVoteYes,
-      eVoteNoOpinion, frame_sp->GetFrameIndex()));
+      new_plan_status, abort_other_plans, NULL, false, stop_other_threads,
+      eVoteYes, eVoteNoOpinion, frame_sp->GetFrameIndex()));
 
   error = ResumeNewPlan(exe_ctx, new_plan_sp.get());
 }
@@ -840,8 +844,9 @@
   }
 
   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(
+      new_plan_status, step_over, true, true));
 
   error = ResumeNewPlan(exe_ctx, new_plan_sp.get());
 }
@@ -873,8 +878,9 @@
 
   Thread *thread = exe_ctx.GetThreadPtr();
 
+  Status new_plan_status;
   ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForRunToAddress(
-      abort_other_plans, target_addr, stop_other_threads));
+      new_plan_status, abort_other_plans, target_addr, stop_other_threads));
 
   error = ResumeNewPlan(exe_ctx, new_plan_sp.get());
 }
@@ -988,8 +994,9 @@
       } 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],
+          new_plan_status, abort_other_plans, &step_over_until_addrs[0],
           step_over_until_addrs.size(), stop_other_threads,
           frame_sp->GetFrameIndex()));
 
@@ -1024,8 +1031,9 @@
   }
 
   Thread *thread = exe_ctx.GetThreadPtr();
-  ThreadPlanSP thread_plan_sp =
-      thread->QueueThreadPlanForStepScripted(false, script_class_name, false);
+  Status thread_plan_status;
+  ThreadPlanSP thread_plan_sp = thread->QueueThreadPlanForStepScripted(
+      thread_plan_status, false, script_class_name, false);
 
   if (!thread_plan_sp) {
     sb_error.SetErrorStringWithFormat(
Index: source/API/SBBreakpoint.cpp
===================================================================
--- source/API/SBBreakpoint.cpp
+++ source/API/SBBreakpoint.cpp
@@ -692,6 +692,13 @@
   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: scripts/interface/SBBreakpoint.i
===================================================================
--- scripts/interface/SBBreakpoint.i
+++ scripts/interface/SBBreakpoint.i
@@ -251,6 +251,9 @@
     static uint32_t
     GetNumBreakpointLocationsFromEvent (const lldb::SBEvent &event_sp);
     
+    bool
+    IsHardware ();
+
     %pythoncode %{
         
         class locations_access(object):
Index: packages/Python/lldbsuite/test/functionalities/breakpoint/require_hw_breakpoints/main.c
===================================================================
--- /dev/null
+++ packages/Python/lldbsuite/test/functionalities/breakpoint/require_hw_breakpoints/main.c
@@ -0,0 +1,9 @@
+int break_on_me() {
+  int i = 10;
+  i++;
+  return i;
+}
+
+int main() {
+  return break_on_me();
+}
Index: packages/Python/lldbsuite/test/functionalities/breakpoint/require_hw_breakpoints/TestRequireHWBreakpoints.py
===================================================================
--- /dev/null
+++ packages/Python/lldbsuite/test/functionalities/breakpoint/require_hw_breakpoints/TestRequireHWBreakpoints.py
@@ -0,0 +1,88 @@
+"""
+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):
+
+    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()
+        exe = self.getBuildArtifact("a.out")
+        target = self.dbg.CreateTarget(exe)
+
+        breakpoint = target.BreakpointCreateByLocation("main.c", 1)
+
+        self.runCmd("run")
+
+        stepping_thread = lldbutil.get_one_thread_stopped_at_breakpoint(
+            target.GetProcess(), breakpoint)
+        self.assertTrue(stepping_thread.IsValid(),
+                        "We stopped at the right breakpoint")
+
+        self.runCmd("settings set target.require-hardware-breakpoint true")
+
+        self.expect("thread step-in")
+        self.expect("thread step-in", error=True)
+
+    def test_step_out(self):
+        """Test stepping out when hardware breakpoints are required."""
+        self.build()
+        exe = self.getBuildArtifact("a.out")
+        target = self.dbg.CreateTarget(exe)
+
+        breakpoint = target.BreakpointCreateByLocation("main.c", 1)
+
+        self.runCmd("run")
+
+        stepping_thread = lldbutil.get_one_thread_stopped_at_breakpoint(
+            target.GetProcess(), breakpoint)
+        self.assertTrue(stepping_thread.IsValid(),
+                        "We stopped at the right breakpoint")
+
+        self.runCmd("settings set target.require-hardware-breakpoint true")
+
+        self.expect("thread step-out", error=True)
+
+    def test_step_over(self):
+        """Test stepping over when hardware breakpoints are required."""
+        self.build()
+        exe = self.getBuildArtifact("a.out")
+        target = self.dbg.CreateTarget(exe)
+
+        breakpoint = target.BreakpointCreateByLocation("main.c", 7)
+
+        self.runCmd("run")
+
+        stepping_thread = lldbutil.get_one_thread_stopped_at_breakpoint(
+            target.GetProcess(), breakpoint)
+        self.assertTrue(stepping_thread.IsValid(),
+                        "We stopped at the right breakpoint")
+
+        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=['stop reason = step over (FAILED)'])
Index: packages/Python/lldbsuite/test/functionalities/breakpoint/require_hw_breakpoints/Makefile
===================================================================
--- /dev/null
+++ packages/Python/lldbsuite/test/functionalities/breakpoint/require_hw_breakpoints/Makefile
@@ -0,0 +1,9 @@
+LEVEL = ../../../make
+
+C_SOURCES := main.c
+
+ifneq (,$(findstring icc,$(CC)))
+    CFLAGS += -debug inline-debug-info
+endif
+
+include $(LEVEL)/Makefile.rules
Index: include/lldb/Target/ThreadPlanStepUntil.h
===================================================================
--- include/lldb/Target/ThreadPlanStepUntil.h
+++ include/lldb/Target/ThreadPlanStepUntil.h
@@ -54,12 +54,13 @@
   typedef std::map<lldb::addr_t, lldb::break_id_t> until_collection;
   until_collection m_until_points;
   bool m_stop_others;
+  bool m_could_not_resolve_hw_bp;
 
   void Clear();
 
   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);
+      Status &status, bool abort_other_plans, lldb::addr_t *address_list,
+      size_t num_addresses, bool stop_others, uint32_t frame_idx);
 
   // Need an appropriate marker for the current stack so we can tell step out
   // from step in.
Index: include/lldb/Target/ThreadPlanStepThrough.h
===================================================================
--- include/lldb/Target/ThreadPlanStepThrough.h
+++ include/lldb/Target/ThreadPlanStepThrough.h
@@ -44,11 +44,9 @@
   bool HitOurBackstopBreakpoint();
 
 private:
-  friend lldb::ThreadPlanSP
-
-  Thread::QueueThreadPlanForStepThrough(StackID &return_stack_id,
-                                        bool abort_other_plans,
-                                        bool stop_others);
+  friend lldb::ThreadPlanSP Thread::QueueThreadPlanForStepThrough(
+      Status &status, StackID &return_stack_id, bool abort_other_plans,
+      bool stop_others);
 
   void ClearBackstopBreakpoint();
 
@@ -58,6 +56,7 @@
   lldb::addr_t m_backstop_addr;
   StackID m_return_stack_id;
   bool m_stop_others;
+  bool m_could_not_resolve_hw_bp;
 
   DISALLOW_COPY_AND_ASSIGN(ThreadPlanStepThrough);
 };
Index: include/lldb/Target/ThreadPlanStepRange.h
===================================================================
--- include/lldb/Target/ThreadPlanStepRange.h
+++ include/lldb/Target/ThreadPlanStepRange.h
@@ -81,6 +81,7 @@
   lldb::BreakpointSP m_next_branch_bp_sp;
   bool m_use_fast_step;
   bool m_given_ranges_only;
+  bool m_could_not_resolve_hw_bp;
 
 private:
   std::vector<lldb::DisassemblerSP> m_instruction_ranges;
Index: include/lldb/Target/ThreadPlanStepOut.h
===================================================================
--- include/lldb/Target/ThreadPlanStepOut.h
+++ include/lldb/Target/ThreadPlanStepOut.h
@@ -77,11 +77,12 @@
   std::vector<lldb::StackFrameSP> m_stepped_past_frames;
   lldb::ValueObjectSP m_return_valobj_sp;
   bool m_calculate_return_value;
+  bool m_could_not_resolve_hw_bp;
 
   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, 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);
 
   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: include/lldb/Target/ThreadPlanStepInstruction.h
===================================================================
--- include/lldb/Target/ThreadPlanStepInstruction.h
+++ include/lldb/Target/ThreadPlanStepInstruction.h
@@ -43,7 +43,8 @@
 
 private:
   friend lldb::ThreadPlanSP Thread::QueueThreadPlanForStepSingleInstruction(
-      bool step_over, bool abort_other_plans, bool stop_other_threads);
+      Status &status, bool step_over, bool abort_other_plans,
+      bool stop_other_threads);
 
   lldb::addr_t m_instruction_addr;
   bool m_stop_other_threads;
Index: include/lldb/Target/ThreadPlanStepInRange.h
===================================================================
--- include/lldb/Target/ThreadPlanStepInRange.h
+++ include/lldb/Target/ThreadPlanStepInRange.h
@@ -78,11 +78,11 @@
 
 private:
   friend lldb::ThreadPlanSP Thread::QueueThreadPlanForStepOverRange(
-      bool abort_other_plans, const AddressRange &range,
+      Status &status, bool abort_other_plans, const AddressRange &range,
       const SymbolContext &addr_context, lldb::RunMode stop_others,
       LazyBool avoid_code_without_debug_info);
   friend lldb::ThreadPlanSP Thread::QueueThreadPlanForStepInRange(
-      bool abort_other_plans, const AddressRange &range,
+      Status &status, bool abort_other_plans, const AddressRange &range,
       const SymbolContext &addr_context, const char *step_in_target,
       lldb::RunMode stop_others,
       LazyBool step_in_avoids_code_without_debug_info,
Index: include/lldb/Target/ThreadPlanBase.h
===================================================================
--- include/lldb/Target/ThreadPlanBase.h
+++ include/lldb/Target/ThreadPlanBase.h
@@ -52,7 +52,7 @@
 
 private:
   friend lldb::ThreadPlanSP
-  Thread::QueueFundamentalPlan(bool abort_other_plans);
+  Thread::QueueFundamentalPlan(Status &status, bool abort_other_plans);
 
   DISALLOW_COPY_AND_ASSIGN(ThreadPlanBase);
 };
Index: include/lldb/Target/Thread.h
===================================================================
--- include/lldb/Target/Thread.h
+++ include/lldb/Target/Thread.h
@@ -640,7 +640,8 @@
   ///     A shared pointer to the newly queued thread plan, or nullptr if the
   ///     plan could not be queued.
   //------------------------------------------------------------------
-  virtual lldb::ThreadPlanSP QueueFundamentalPlan(bool abort_other_plans);
+  virtual lldb::ThreadPlanSP QueueFundamentalPlan(Status &status,
+                                                  bool abort_other_plans);
 
   //------------------------------------------------------------------
   /// Queues the plan used to step one instruction from the current PC of \a
@@ -661,8 +662,10 @@
   ///     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);
+  virtual lldb::ThreadPlanSP
+  QueueThreadPlanForStepSingleInstruction(Status &status, bool step_over,
+                                          bool abort_other_plans,
+                                          bool stop_other_threads);
 
   //------------------------------------------------------------------
   /// Queues the plan used to step through an address range, stepping  over
@@ -702,15 +705,15 @@
   ///     plan could not be queued.
   //------------------------------------------------------------------
   virtual lldb::ThreadPlanSP QueueThreadPlanForStepOverRange(
-      bool abort_other_plans, const AddressRange &range,
+      Status &status, bool abort_other_plans, const AddressRange &range,
       const SymbolContext &addr_context, lldb::RunMode stop_other_threads,
       LazyBool step_out_avoids_code_without_debug_info = eLazyBoolCalculate);
 
   // Helper function that takes a LineEntry to step, insted of an AddressRange.
   // This may combine multiple LineEntries of the same source line number to
   // step over a longer address range in a single operation.
   virtual lldb::ThreadPlanSP QueueThreadPlanForStepOverRange(
-      bool abort_other_plans, const LineEntry &line_entry,
+      Status &status, bool abort_other_plans, const LineEntry &line_entry,
       const SymbolContext &addr_context, lldb::RunMode stop_other_threads,
       LazyBool step_out_avoids_code_without_debug_info = eLazyBoolCalculate);
 
@@ -761,7 +764,7 @@
   ///     plan could not be queued.
   //------------------------------------------------------------------
   virtual lldb::ThreadPlanSP QueueThreadPlanForStepInRange(
-      bool abort_other_plans, const AddressRange &range,
+      Status &status, bool abort_other_plans, const AddressRange &range,
       const SymbolContext &addr_context, const char *step_in_target,
       lldb::RunMode stop_other_threads,
       LazyBool step_in_avoids_code_without_debug_info = eLazyBoolCalculate,
@@ -771,7 +774,7 @@
   // This may combine multiple LineEntries of the same source line number to
   // step over a longer address range in a single operation.
   virtual lldb::ThreadPlanSP QueueThreadPlanForStepInRange(
-      bool abort_other_plans, const LineEntry &line_entry,
+      Status &status, bool abort_other_plans, const LineEntry &line_entry,
       const SymbolContext &addr_context, const char *step_in_target,
       lldb::RunMode stop_other_threads,
       LazyBool step_in_avoids_code_without_debug_info = eLazyBoolCalculate,
@@ -815,8 +818,8 @@
   ///     plan could not be queued.
   //------------------------------------------------------------------
   virtual lldb::ThreadPlanSP QueueThreadPlanForStepOut(
-      bool abort_other_plans, SymbolContext *addr_context, bool first_insn,
-      bool stop_other_threads,
+      Status &status, 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,
@@ -875,8 +878,8 @@
   ///     plan could not be queued.
   //------------------------------------------------------------------
   virtual lldb::ThreadPlanSP QueueThreadPlanForStepOutNoShouldStop(
-      bool abort_other_plans, SymbolContext *addr_context, bool first_insn,
-      bool stop_other_threads,
+      Status &status, 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);
@@ -904,7 +907,7 @@
   ///     plan could not be queued.
   //------------------------------------------------------------------
   virtual lldb::ThreadPlanSP
-  QueueThreadPlanForStepThrough(StackID &return_stack_id,
+  QueueThreadPlanForStepThrough(Status &status, StackID &return_stack_id,
                                 bool abort_other_plans,
                                 bool stop_other_threads);
 
@@ -929,16 +932,17 @@
   ///     plan could not be queued.
   //------------------------------------------------------------------
   virtual lldb::ThreadPlanSP
-  QueueThreadPlanForRunToAddress(bool abort_other_plans, Address &target_addr,
-                                 bool stop_other_threads);
+  QueueThreadPlanForRunToAddress(Status &status, bool abort_other_plans,
+                                 Address &target_addr, bool stop_other_threads);
 
   virtual lldb::ThreadPlanSP
-  QueueThreadPlanForStepUntil(bool abort_other_plans,
+  QueueThreadPlanForStepUntil(Status &status, bool abort_other_plans,
                               lldb::addr_t *address_list, size_t num_addresses,
                               bool stop_others, uint32_t frame_idx);
 
   virtual lldb::ThreadPlanSP
-  QueueThreadPlanForStepScripted(bool abort_other_plans, const char *class_name,
+  QueueThreadPlanForStepScripted(Status &status, bool abort_other_plans,
+                                 const char *class_name,
                                  bool stop_other_threads);
 
   //------------------------------------------------------------------
@@ -1040,7 +1044,7 @@
   /// @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: include/lldb/Target/Target.h
===================================================================
--- include/lldb/Target/Target.h
+++ include/lldb/Target/Target.h
@@ -202,6 +202,10 @@
 
   bool GetUseModernTypeLookup() const;
 
+  void SetRequireHardwareBreakpoints(bool b);
+
+  bool GetRequireHardwareBreakpoints() const;
+
 private:
   //------------------------------------------------------------------
   // Callbacks for m_launch_info.
Index: include/lldb/Breakpoint/Breakpoint.h
===================================================================
--- include/lldb/Breakpoint/Breakpoint.h
+++ include/lldb/Breakpoint/Breakpoint.h
@@ -502,6 +502,14 @@
   //------------------------------------------------------------------
   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.
   ///
Index: include/lldb/API/SBBreakpoint.h
===================================================================
--- include/lldb/API/SBBreakpoint.h
+++ include/lldb/API/SBBreakpoint.h
@@ -129,6 +129,8 @@
   static uint32_t
   GetNumBreakpointLocationsFromEvent(const lldb::SBEvent &event_sp);
 
+  bool IsHardware() const;
+
   // Can only be called from a ScriptedBreakpointResolver...
   SBError
   AddLocation(SBAddress &address);
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to