rdar://problem/11584012

Refactorings of watchpoint creation APIs so that SBTarget::WatchAddress(), SBValue::Watch(), and SBValue::WatchPointee()
now take an additional 'SBError &error' parameter (at the end) to contain the reason if there is some failure in the
operation.  Update 'watchpoint set variable/expression' commands to take advantage of that.

Update existing test cases to reflect the API change and add test cases to verify that the SBError mechanism works for
SBTarget::WatchAddress() by passing an invalid watch_size.


git-svn-id: https://llvm.org/svn/llvm-project/lldb/trunk@157964 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/source/Target/Target.cpp b/source/Target/Target.cpp
index 0fce9ae..c5c0a18 100644
--- a/source/Target/Target.cpp
+++ b/source/Target/Target.cpp
@@ -30,6 +30,7 @@
 #include "lldb/Host/Host.h"
 #include "lldb/Interpreter/CommandInterpreter.h"
 #include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/OptionGroupWatchpoint.h"
 #include "lldb/lldb-private-log.h"
 #include "lldb/Symbol/ObjectFile.h"
 #include "lldb/Target/Process.h"
@@ -465,10 +466,25 @@
     return (m_process_sp && m_process_sp->IsAlive());
 }
 
+static bool
+CheckIfWatchpointsExhausted(Target *target, Error &error)
+{
+    uint32_t num_supported_hardware_watchpoints;
+    Error rc = target->GetProcessSP()->GetWatchpointSupportInfo(num_supported_hardware_watchpoints);
+    if (rc.Success())
+    {
+        uint32_t num_current_watchpoints = target->GetWatchpointList().GetSize();
+        if (num_current_watchpoints >= num_supported_hardware_watchpoints)
+            error.SetErrorStringWithFormat("number of supported hardware watchpoints (%u) has been reached",
+                                           num_supported_hardware_watchpoints);
+    }
+    return false;
+}
+
 // See also Watchpoint::SetWatchpointType(uint32_t type) and
 // the OptionGroupWatchpoint::WatchType enum type.
 WatchpointSP
-Target::CreateWatchpoint(lldb::addr_t addr, size_t size, uint32_t type)
+Target::CreateWatchpoint(lldb::addr_t addr, size_t size, uint32_t type, Error &error)
 {
     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
     if (log)
@@ -477,9 +493,18 @@
 
     WatchpointSP wp_sp;
     if (!ProcessIsValid())
+    {
+        error.SetErrorString("process is not alive");
         return wp_sp;
+    }
     if (addr == LLDB_INVALID_ADDRESS || size == 0)
+    {
+        if (size == 0)
+            error.SetErrorString("cannot set a watchpoint with watch_size of 0");
+        else
+            error.SetErrorStringWithFormat("invalid watch address: %llu", addr);
         return wp_sp;
+    }
 
     // Currently we only support one watchpoint per address, with total number
     // of watchpoints limited by the hardware which the inferior is running on.
@@ -517,17 +542,23 @@
         m_watchpoint_list.Add(wp_sp);
     }
 
-    Error rc = m_process_sp->EnableWatchpoint(wp_sp.get());
+    error = m_process_sp->EnableWatchpoint(wp_sp.get());
     if (log)
             log->Printf("Target::%s (creation of watchpoint %s with id = %u)\n",
                         __FUNCTION__,
-                        rc.Success() ? "succeeded" : "failed",
+                        error.Success() ? "succeeded" : "failed",
                         wp_sp->GetID());
 
-    if (rc.Fail()) {
+    if (error.Fail()) {
         // Enabling the watchpoint on the device side failed.
         // Remove the said watchpoint from the list maintained by the target instance.
         m_watchpoint_list.Remove(wp_sp->GetID());
+        // See if we could provide more helpful error message.
+        if (!CheckIfWatchpointsExhausted(this, error))
+        {
+            if (!OptionGroupWatchpoint::IsWatchSizeSupported(size))
+                error.SetErrorStringWithFormat("watch size of %lu is not supported", size);
+        }
         wp_sp.reset();
     }
     else