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/API/SBTarget.cpp b/source/API/SBTarget.cpp
index d267886..1b2b948 100644
--- a/source/API/SBTarget.cpp
+++ b/source/API/SBTarget.cpp
@@ -1674,7 +1674,7 @@
 }
 
 lldb::SBWatchpoint
-SBTarget::WatchAddress (lldb::addr_t addr, size_t size, bool read, bool write)
+SBTarget::WatchAddress (lldb::addr_t addr, size_t size, bool read, bool write, SBError &error)
 {
     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
     
@@ -1690,7 +1690,9 @@
         if (write)
             watch_type |= LLDB_WATCH_TYPE_WRITE;
         // Target::CreateWatchpoint() is thread safe.
-        watchpoint_sp = target_sp->CreateWatchpoint(addr, size, watch_type);
+        Error cw_error;
+        watchpoint_sp = target_sp->CreateWatchpoint(addr, size, watch_type, cw_error);
+        error.SetError(cw_error);
         sb_watchpoint.SetSP (watchpoint_sp);
     }
     
diff --git a/source/API/SBValue.cpp b/source/API/SBValue.cpp
index bb656e5..bd6a5fc 100644
--- a/source/API/SBValue.cpp
+++ b/source/API/SBValue.cpp
@@ -1655,7 +1655,7 @@
 }
 
 lldb::SBWatchpoint
-SBValue::Watch (bool resolve_location, bool read, bool write)
+SBValue::Watch (bool resolve_location, bool read, bool write, SBError &error)
 {
     SBWatchpoint sb_watchpoint;
     
@@ -1696,7 +1696,9 @@
         if (write)
             watch_type |= LLDB_WATCH_TYPE_WRITE;
         
-        WatchpointSP watchpoint_sp = target_sp->CreateWatchpoint(addr, byte_size, watch_type);
+        Error rc;
+        WatchpointSP watchpoint_sp = target_sp->CreateWatchpoint(addr, byte_size, watch_type, rc);
+        error.SetError(rc);
                 
         if (watchpoint_sp) 
         {
@@ -1718,11 +1720,11 @@
 }
 
 lldb::SBWatchpoint
-SBValue::WatchPointee (bool resolve_location, bool read, bool write)
+SBValue::WatchPointee (bool resolve_location, bool read, bool write, SBError &error)
 {
     SBWatchpoint sb_watchpoint;
     if (IsInScope() && GetType().IsPointerType())
-        sb_watchpoint = Dereference().Watch (resolve_location, read, write);
+        sb_watchpoint = Dereference().Watch (resolve_location, read, write, error);
     return sb_watchpoint;
 }
 
diff --git a/source/API/SBWatchpoint.cpp b/source/API/SBWatchpoint.cpp
index fd505ae..76ce57c 100644
--- a/source/API/SBWatchpoint.cpp
+++ b/source/API/SBWatchpoint.cpp
@@ -87,22 +87,7 @@
 bool
 SBWatchpoint::IsValid() const
 {
-    lldb::WatchpointSP watchpoint_sp(GetSP());
-    if (watchpoint_sp && watchpoint_sp->GetError().Success())
-        return true;
-    return false;
-}
-
-SBError
-SBWatchpoint::GetError ()
-{
-    SBError sb_error;
-    lldb::WatchpointSP watchpoint_sp(GetSP());
-    if (watchpoint_sp)
-    {
-        sb_error.SetError(watchpoint_sp->GetError());
-    }
-    return sb_error;
+    return m_opaque_sp;
 }
 
 int32_t
diff --git a/source/Commands/CommandObjectWatchpoint.cpp b/source/Commands/CommandObjectWatchpoint.cpp
index 591b8ec..04d8789 100644
--- a/source/Commands/CommandObjectWatchpoint.cpp
+++ b/source/Commands/CommandObjectWatchpoint.cpp
@@ -59,20 +59,6 @@
     return true;
 }
 
-static void
-CheckIfWatchpointsExhausted(Target *target, CommandReturnObject &result)
-{
-    uint32_t num_supported_hardware_watchpoints;
-    Error error = target->GetProcessSP()->GetWatchpointSupportInfo(num_supported_hardware_watchpoints);
-    if (error.Success())
-    {
-        uint32_t num_current_watchpoints = target->GetWatchpointList().GetSize();
-        if (num_current_watchpoints >= num_supported_hardware_watchpoints)
-            result.AppendErrorWithFormat("Number of supported hardware watchpoints (%u) has been reached.\n",
-                                         num_supported_hardware_watchpoints);
-    }
-}
-
 #include "llvm/ADT/StringRef.h"
 
 // Equivalent class: {"-", "to", "To", "TO"} of range specifier array.
@@ -1013,11 +999,6 @@
             // Find out the size of this variable.
             size = m_option_watchpoint.watch_size == 0 ? valobj_sp->GetByteSize()
                                                        : m_option_watchpoint.watch_size;
-            if (!m_option_watchpoint.IsWatchSizeSupported(size))
-            {
-                result.GetErrorStream().Printf("Watch size of %lu is not supported\n", size);
-                return false;
-            }
         }
     } else {
         const char *error_cstr = error.AsCString(NULL);
@@ -1031,7 +1012,8 @@
 
     // Now it's time to create the watchpoint.
     uint32_t watch_type = m_option_watchpoint.watch_type;
-    Watchpoint *wp = target->CreateWatchpoint(addr, size, watch_type).get();
+    error.Clear();
+    Watchpoint *wp = target->CreateWatchpoint(addr, size, watch_type, error).get();
     if (wp) {
         if (var_sp && var_sp->GetDeclaration().GetFile()) {
             StreamString ss;
@@ -1047,7 +1029,8 @@
     } else {
         result.AppendErrorWithFormat("Watchpoint creation failed (addr=0x%llx, size=%lu).\n",
                                      addr, size);
-        CheckIfWatchpointsExhausted(target, result);
+        if (error.AsCString(NULL))
+            result.AppendError(error.AsCString());
         result.SetStatus(eReturnStatusFailed);
     }
 
@@ -1221,15 +1204,11 @@
     }
     size = with_dash_x ? m_option_watchpoint.watch_size
                        : target->GetArchitecture().GetAddressByteSize();
-    if (!m_option_watchpoint.IsWatchSizeSupported(size))
-    {
-        result.GetErrorStream().Printf("Watch size of %lu is not supported\n", size);
-        return false;
-    }
 
     // Now it's time to create the watchpoint.
     uint32_t watch_type = m_option_watchpoint.watch_type;
-    Watchpoint *wp = target->CreateWatchpoint(addr, size, watch_type).get();
+    Error error;
+    Watchpoint *wp = target->CreateWatchpoint(addr, size, watch_type, error).get();
     if (wp) {
         if (var_sp && var_sp->GetDeclaration().GetFile()) {
             StreamString ss;
@@ -1245,7 +1224,8 @@
     } else {
         result.AppendErrorWithFormat("Watchpoint creation failed (addr=0x%llx, size=%lu).\n",
                                      addr, size);
-        CheckIfWatchpointsExhausted(target, result);
+        if (error.AsCString(NULL))
+            result.AppendError(error.AsCString());
         result.SetStatus(eReturnStatusFailed);
     }
 
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