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.

llvm-svn: 157964
This commit is contained in:
Johnny Chen 2012-06-04 23:19:54 +00:00
parent 188d830405
commit b90827e66c
21 changed files with 137 additions and 77 deletions

View File

@ -692,7 +692,7 @@ public:
FindWatchpointByID (lldb::watch_id_t watch_id);
lldb::SBWatchpoint
WatchAddress (lldb::addr_t addr, size_t size, bool read, bool write);
WatchAddress (lldb::addr_t addr, size_t size, bool read, bool write, SBError& error);
bool
EnableAllWatchpoints ();

View File

@ -325,6 +325,9 @@ public:
/// @param[in] write
/// Stop when this value is modified
///
/// @param[out]
/// An error object. Contains the reason if there is some failure.
///
/// @return
/// An SBWatchpoint object. This object might not be valid upon
/// return due to a value not being contained in memory, too
@ -332,7 +335,7 @@ public:
/// use.
//------------------------------------------------------------------
lldb::SBWatchpoint
Watch (bool resolve_location, bool read, bool write);
Watch (bool resolve_location, bool read, bool write, SBError &error);
//------------------------------------------------------------------
/// Watch this value that this value points to in memory
@ -351,6 +354,9 @@ public:
/// @param[in] write
/// Stop when this value is modified
///
/// @param[out]
/// An error object. Contains the reason if there is some failure.
///
/// @return
/// An SBWatchpoint object. This object might not be valid upon
/// return due to a value not being contained in memory, too
@ -358,7 +364,7 @@ public:
/// use.
//------------------------------------------------------------------
lldb::SBWatchpoint
WatchPointee (bool resolve_location, bool read, bool write);
WatchPointee (bool resolve_location, bool read, bool write, SBError &error);
// this must be defined in the .h file because synthetic children as implemented in the core
// currently rely on being able to extract the SharedPointer out of an SBValue. if the implementation

View File

@ -32,9 +32,6 @@ public:
bool
IsValid() const;
SBError
GetError();
watch_id_t
GetID ();

View File

@ -523,7 +523,8 @@ public:
lldb::WatchpointSP
CreateWatchpoint (lldb::addr_t addr,
size_t size,
uint32_t type);
uint32_t type,
Error &error);
lldb::WatchpointSP
GetLastCreatedWatchpoint ()

View File

@ -668,7 +668,8 @@ public:
WatchAddress (lldb::addr_t addr,
size_t size,
bool read,
bool write);
bool write,
SBError &error);
lldb::SBBroadcaster

View File

@ -313,14 +313,14 @@ public:
/// It returns an SBWatchpoint, which may be invalid.
") Watch;
lldb::SBWatchpoint
Watch (bool resolve_location, bool read, bool write);
Watch (bool resolve_location, bool read, bool write, SBError &error);
%feature("docstring", "
/// Find and watch the location pointed to by a variable.
/// It returns an SBWatchpoint, which may be invalid.
") WatchPointee;
lldb::SBWatchpoint
WatchPointee (bool resolve_location, bool read, bool write);
WatchPointee (bool resolve_location, bool read, bool write, SBError &error);
bool
GetDescription (lldb::SBStream &description);

View File

@ -31,9 +31,6 @@ public:
bool
IsValid();
SBError
GetError();
watch_id_t
GetID ();

View File

@ -1674,7 +1674,7 @@ SBTarget::FindWatchpointByID (lldb::watch_id_t wp_id)
}
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 @@ SBTarget::WatchAddress (lldb::addr_t addr, size_t size, bool read, bool write)
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);
}

View File

@ -1655,7 +1655,7 @@ SBValue::GetData ()
}
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 @@ SBValue::Watch (bool resolve_location, bool read, bool write)
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 @@ SBValue::Watch (bool resolve_location, bool read, bool write)
}
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;
}

View File

@ -87,22 +87,7 @@ SBWatchpoint::GetID ()
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

View File

@ -59,20 +59,6 @@ CheckTargetForWatchpointOperations(Target *target, CommandReturnObject &result)
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 @@ CommandObjectWatchpointSetVariable::Execute
// 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 @@ CommandObjectWatchpointSetVariable::Execute
// 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 @@ CommandObjectWatchpointSetVariable::Execute
} 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 @@ CommandObjectWatchpointSetExpression::ExecuteRawCommandString
}
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 @@ CommandObjectWatchpointSetExpression::ExecuteRawCommandString
} 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);
}

View File

@ -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 @@ Target::ProcessIsValid()
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 @@ Target::CreateWatchpoint(lldb::addr_t addr, size_t size, uint32_t type)
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 @@ Target::CreateWatchpoint(lldb::addr_t addr, size_t size, uint32_t type)
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

View File

@ -52,7 +52,8 @@ def fuzz_obj(obj):
obj.GetAddressByteSize()
obj.GetByteOrder()
obj.GetTriple()
obj.WatchAddress(123, 8, True, True)
error = lldb.SBError()
obj.WatchAddress(123, 8, True, True, error)
obj.GetBroadcaster()
obj.GetDescription(lldb.SBStream(), lldb.eDescriptionLevelBrief)
obj.Clear()

View File

@ -34,8 +34,9 @@ def fuzz_obj(obj):
obj.GetDescription(stream)
obj.GetExpressionPath(stream)
obj.GetExpressionPath(stream, True)
obj.Watch(True, True, False)
obj.WatchPointee(True, False, True)
error = lldb.SBError()
obj.Watch(True, True, False, error)
obj.WatchPointee(True, False, True, error)
for child_val in obj:
print child_val
error = lldb.SBError()

View File

@ -8,7 +8,6 @@ import lldb
def fuzz_obj(obj):
obj.GetID()
obj.IsValid()
obj.GetError()
obj.GetHardwareIndex()
obj.GetWatchAddress()
obj.GetWatchSize()

View File

@ -61,7 +61,8 @@ class SetWatchpointAPITestCase(TestBase):
# Watch 'global' for read and write.
value = frame0.FindValue('global', lldb.eValueTypeVariableGlobal)
watchpoint = value.Watch(True, True, True)
error = lldb.SBError();
watchpoint = value.Watch(True, True, True, error)
self.assertTrue(value and watchpoint,
"Successfully found the variable and set a watchpoint")
self.DebugSBValue(value)

View File

@ -61,7 +61,8 @@ class WatchpointIgnoreCountTestCase(TestBase):
# Watch 'global' for read and write.
value = frame0.FindValue('global', lldb.eValueTypeVariableGlobal)
watchpoint = value.Watch(True, True, True)
error = lldb.SBError();
watchpoint = value.Watch(True, True, True, error)
self.assertTrue(value and watchpoint,
"Successfully found the variable and set a watchpoint")
self.DebugSBValue(value)

View File

@ -61,7 +61,8 @@ class WatchpointIteratorTestCase(TestBase):
# Watch 'global' for read and write.
value = frame0.FindValue('global', lldb.eValueTypeVariableGlobal)
watchpoint = value.Watch(True, True, True)
error = lldb.SBError();
watchpoint = value.Watch(True, True, True, error)
self.assertTrue(value and watchpoint,
"Successfully found the variable and set a watchpoint")
self.DebugSBValue(value)

View File

@ -66,7 +66,8 @@ class WatchpointConditionAPITestCase(TestBase):
# Watch 'global' for write.
value = frame0.FindValue('global', lldb.eValueTypeVariableGlobal)
watchpoint = value.Watch(True, False, True)
error = lldb.SBError();
watchpoint = value.Watch(True, False, True, error)
self.assertTrue(value and watchpoint,
"Successfully found the variable and set a watchpoint")
self.DebugSBValue(value)

View File

@ -67,7 +67,8 @@ class SetWatchlocationAPITestCase(TestBase):
value.GetValueAsUnsigned(0),
value.GetType().GetPointeeType())
# Watch for write to *g_char_ptr.
watchpoint = value.WatchPointee(True, False, True)
error = lldb.SBError();
watchpoint = value.WatchPointee(True, False, True, error)
self.assertTrue(value and watchpoint,
"Successfully found the pointer and set a watchpoint")
self.DebugSBValue(value)

View File

@ -37,6 +37,21 @@ class TargetWatchAddressAPITestCase(TestBase):
self.buildDwarf()
self.do_set_watchaddress()
@unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
@python_api_test
@dsym_test
def test_watch_address_with_invalid_watch_size_with_dsym(self):
"""Exercise SBTarget.WatchAddress() API but pass an invalid watch_size."""
self.buildDsym()
self.do_set_watchaddress_with_invalid_watch_size()
@python_api_test
@dwarf_test
def test_watch_address_with_invalid_watch_size_with_dwarf(self):
"""Exercise SBTarget.WatchAddress() API but pass an invalid watch_size."""
self.buildDwarf()
self.do_set_watchaddress_with_invalid_watch_size()
def do_set_watchaddress(self):
"""Use SBTarget.WatchAddress() to set a watchpoint and verify that the program stops later due to the watchpoint."""
exe = os.path.join(os.getcwd(), "a.out")
@ -67,7 +82,8 @@ class TargetWatchAddressAPITestCase(TestBase):
value.GetValueAsUnsigned(0),
value.GetType().GetPointeeType())
# Watch for write to *g_char_ptr.
watchpoint = target.WatchAddress(value.GetValueAsUnsigned(), 1, False, True)
error = lldb.SBError();
watchpoint = target.WatchAddress(value.GetValueAsUnsigned(), 1, False, True, error)
self.assertTrue(value and watchpoint,
"Successfully found the pointer and set a watchpoint")
self.DebugSBValue(value)
@ -95,6 +111,42 @@ class TargetWatchAddressAPITestCase(TestBase):
# This finishes our test.
def do_set_watchaddress_with_invalid_watch_size(self):
"""Use SBTarget.WatchAddress() to set a watchpoint with invalid watch_size and verify we get a meaningful error message."""
exe = os.path.join(os.getcwd(), "a.out")
# Create a target by the debugger.
target = self.dbg.CreateTarget(exe)
self.assertTrue(target, VALID_TARGET)
# Now create a breakpoint on main.c.
breakpoint = target.BreakpointCreateByLocation(self.source, self.line)
self.assertTrue(breakpoint and
breakpoint.GetNumLocations() == 1,
VALID_BREAKPOINT)
# Now launch the process, and do not stop at the entry point.
process = target.LaunchSimple(None, None, os.getcwd())
# We should be stopped due to the breakpoint. Get frame #0.
process = target.GetProcess()
self.assertTrue(process.GetState() == lldb.eStateStopped,
PROCESS_STOPPED)
thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint)
frame0 = thread.GetFrameAtIndex(0)
value = frame0.FindValue('g_char_ptr',
lldb.eValueTypeVariableGlobal)
pointee = value.CreateValueFromAddress("pointee",
value.GetValueAsUnsigned(0),
value.GetType().GetPointeeType())
# Watch for write to *g_char_ptr.
error = lldb.SBError();
watchpoint = target.WatchAddress(value.GetValueAsUnsigned(), 365, False, True, error)
self.assertFalse(watchpoint)
self.expect(error.GetCString(), exe=False,
substrs = ['watch size of %d is not supported' % 365])
if __name__ == '__main__':
import atexit