Add capability to set ignore count for watchpoint on the command line:

watchpoint ignore -i <count> [<watchpt-id | watchpt-id-list>]

Add tests of watchpoint ignore_count for command line as well as API.

llvm-svn: 141217
This commit is contained in:
Johnny Chen 2011-10-05 21:35:46 +00:00
parent a2e40934d5
commit 6cc60e8668
7 changed files with 400 additions and 1 deletions

View File

@ -340,6 +340,9 @@ public:
bool
EnableAllWatchpointLocations (bool end_to_end = true);
bool
IgnoreAllWatchpointLocations (uint32_t ignore_count);
bool
DisableWatchpointLocationByID (lldb::watch_id_t watch_id);
@ -349,6 +352,9 @@ public:
bool
RemoveWatchpointLocationByID (lldb::watch_id_t watch_id);
bool
IgnoreWatchpointLocationByID (lldb::watch_id_t watch_id, uint32_t ignore_count);
void
ModulesDidLoad (ModuleList &module_list);

View File

@ -155,16 +155,19 @@ CommandObjectMultiwordWatchpoint::CommandObjectMultiwordWatchpoint(CommandInterp
CommandObjectSP enable_command_object (new CommandObjectWatchpointEnable (interpreter));
CommandObjectSP disable_command_object (new CommandObjectWatchpointDisable (interpreter));
CommandObjectSP delete_command_object (new CommandObjectWatchpointDelete (interpreter));
CommandObjectSP ignore_command_object (new CommandObjectWatchpointIgnore (interpreter));
list_command_object->SetCommandName ("watchpoint list");
enable_command_object->SetCommandName("watchpoint enable");
disable_command_object->SetCommandName("watchpoint disable");
delete_command_object->SetCommandName("watchpoint delete");
ignore_command_object->SetCommandName("watchpoint ignore");
status = LoadSubCommand ("list", list_command_object);
status = LoadSubCommand ("enable", enable_command_object);
status = LoadSubCommand ("disable", disable_command_object);
status = LoadSubCommand ("delete", delete_command_object);
status = LoadSubCommand ("ignore", ignore_command_object);
}
CommandObjectMultiwordWatchpoint::~CommandObjectMultiwordWatchpoint()
@ -555,3 +558,138 @@ CommandObjectWatchpointDelete::Execute(Args& args, CommandReturnObject &result)
return result.Succeeded();
}
//-------------------------------------------------------------------------
// CommandObjectWatchpointIgnore::CommandOptions
//-------------------------------------------------------------------------
#pragma mark Ignore::CommandOptions
CommandObjectWatchpointIgnore::CommandOptions::CommandOptions(CommandInterpreter &interpreter) :
Options (interpreter),
m_ignore_count (0)
{
}
CommandObjectWatchpointIgnore::CommandOptions::~CommandOptions ()
{
}
OptionDefinition
CommandObjectWatchpointIgnore::CommandOptions::g_option_table[] =
{
{ LLDB_OPT_SET_ALL, true, "ignore-count", 'i', required_argument, NULL, NULL, eArgTypeCount, "Set the number of times this watchpoint is skipped before stopping." },
{ 0, false, NULL, 0 , 0, NULL, 0, eArgTypeNone, NULL }
};
const OptionDefinition*
CommandObjectWatchpointIgnore::CommandOptions::GetDefinitions ()
{
return g_option_table;
}
Error
CommandObjectWatchpointIgnore::CommandOptions::SetOptionValue (uint32_t option_idx, const char *option_arg)
{
Error error;
char short_option = (char) m_getopt_table[option_idx].val;
switch (short_option)
{
case 'i':
{
m_ignore_count = Args::StringToUInt32(option_arg, UINT32_MAX, 0);
if (m_ignore_count == UINT32_MAX)
error.SetErrorStringWithFormat ("Invalid ignore count '%s'.\n", option_arg);
}
break;
default:
error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option);
break;
}
return error;
}
void
CommandObjectWatchpointIgnore::CommandOptions::OptionParsingStarting ()
{
m_ignore_count = 0;
}
//-------------------------------------------------------------------------
// CommandObjectWatchpointIgnore
//-------------------------------------------------------------------------
#pragma mark Ignore
CommandObjectWatchpointIgnore::CommandObjectWatchpointIgnore(CommandInterpreter &interpreter) :
CommandObject(interpreter,
"watchpoint ignore",
"Set ignore count on the specified watchpoint(s). If no watchpoints are specified, set them all.",
NULL),
m_options (interpreter)
{
CommandArgumentEntry arg;
CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID, eArgTypeWatchpointIDRange);
// Add the entry for the first argument for this command to the object's arguments vector.
m_arguments.push_back(arg);
}
CommandObjectWatchpointIgnore::~CommandObjectWatchpointIgnore()
{
}
Options *
CommandObjectWatchpointIgnore::GetOptions ()
{
return &m_options;
}
bool
CommandObjectWatchpointIgnore::Execute(Args& args, CommandReturnObject &result)
{
Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
if (!CheckTargetForWatchpointOperations(target, result))
return false;
Mutex::Locker locker;
target->GetWatchpointLocationList().GetListMutex(locker);
const WatchpointLocationList &watchpoints = target->GetWatchpointLocationList();
size_t num_watchpoints = watchpoints.GetSize();
if (num_watchpoints == 0)
{
result.AppendError("No watchpoints exist to be ignored.");
result.SetStatus(eReturnStatusFailed);
return false;
}
if (args.GetArgumentCount() == 0)
{
target->IgnoreAllWatchpointLocations(m_options.m_ignore_count);
result.AppendMessageWithFormat("All watchpoints ignored. (%lu watchpoints)\n", num_watchpoints);
result.SetStatus (eReturnStatusSuccessFinishNoResult);
}
else
{
// Particular watchpoints selected; ignore them.
std::vector<uint32_t> wp_ids;
if (!VerifyWatchpointIDs(args, wp_ids))
{
result.AppendError("Invalid watchpoints specification.");
result.SetStatus(eReturnStatusFailed);
return false;
}
int count = 0;
const size_t size = wp_ids.size();
for (size_t i = 0; i < size; ++i)
if (target->IgnoreWatchpointLocationByID(wp_ids[i], m_options.m_ignore_count))
++count;
result.AppendMessageWithFormat("%d watchpoints ignored.\n",count);
result.SetStatus (eReturnStatusSuccessFinishNoResult);
}
return result.Succeeded();
}

View File

@ -140,6 +140,56 @@ public:
private:
};
//-------------------------------------------------------------------------
// CommandObjectWatchpointIgnore
//-------------------------------------------------------------------------
class CommandObjectWatchpointIgnore : public CommandObject
{
public:
CommandObjectWatchpointIgnore (CommandInterpreter &interpreter);
virtual
~CommandObjectWatchpointIgnore ();
virtual bool
Execute (Args& command,
CommandReturnObject &result);
virtual Options *
GetOptions ();
class CommandOptions : public Options
{
public:
CommandOptions (CommandInterpreter &interpreter);
virtual
~CommandOptions ();
virtual Error
SetOptionValue (uint32_t option_idx, const char *option_arg);
void
OptionParsingStarting ();
const OptionDefinition *
GetDefinitions ();
// Options table: Required for subclasses of Options.
static OptionDefinition g_option_table[];
// Instance variables to hold the values for command options.
uint32_t m_ignore_count;
};
private:
CommandOptions m_options;
};
} // namespace lldb_private
#endif // liblldb_CommandObjectWatchpoint_h_

View File

@ -672,6 +672,30 @@ Target::EnableAllWatchpointLocations (bool end_to_end)
return true; // Success!
}
// Assumption: Caller holds the list mutex lock for m_watchpoint_location_list
// during these operations.
bool
Target::IgnoreAllWatchpointLocations (uint32_t ignore_count)
{
LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
if (log)
log->Printf ("Target::%s\n", __FUNCTION__);
if (!ProcessIsValid())
return false;
size_t num_watchpoints = m_watchpoint_location_list.GetSize();
for (size_t i = 0; i < num_watchpoints; ++i)
{
WatchpointLocationSP wp_loc_sp = m_watchpoint_location_list.GetByIndex(i);
if (!wp_loc_sp)
return false;
wp_loc_sp->SetIgnoreCount(ignore_count);
}
return true; // Success!
}
// Assumption: Caller holds the list mutex lock for m_watchpoint_location_list.
bool
Target::DisableWatchpointLocationByID (lldb::watch_id_t watch_id)
@ -734,6 +758,26 @@ Target::RemoveWatchpointLocationByID (lldb::watch_id_t watch_id)
return false;
}
// Assumption: Caller holds the list mutex lock for m_watchpoint_location_list.
bool
Target::IgnoreWatchpointLocationByID (lldb::watch_id_t watch_id, uint32_t ignore_count)
{
LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
if (log)
log->Printf ("Target::%s (watch_id = %i)\n", __FUNCTION__, watch_id);
if (!ProcessIsValid())
return false;
WatchpointLocationSP wp_loc_sp = m_watchpoint_location_list.FindByID (watch_id);
if (wp_loc_sp)
{
wp_loc_sp->SetIgnoreCount(ignore_count);
return true;
}
return false;
}
ModuleSP
Target::GetExecutableModule ()
{

View File

@ -51,6 +51,19 @@ class WatchpointCommandsTestCase(TestBase):
self.setTearDownCleanup(dictionary=self.d)
self.delete_read_write_watchpoint()
@unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
def test_rw_watchpoint_set_ignore_count_with_dsym(self):
"""Test watchpoint ignore count and expect to not to stop at all."""
self.buildDsym(dictionary=self.d)
self.setTearDownCleanup(dictionary=self.d)
self.ignore_read_write_watchpoint()
def test_rw_watchpoint_set_ignore_count_with_dwarf(self):
"""Test watchpoint ignore count and expect to not to stop at all."""
self.buildDwarf(dictionary=self.d)
self.setTearDownCleanup(dictionary=self.d)
self.ignore_read_write_watchpoint()
@unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
def test_rw_disable_after_first_stop_with_dsym(self):
"""Test read_write watchpoint but disable it after the first stop."""
@ -175,6 +188,52 @@ class WatchpointCommandsTestCase(TestBase):
self.expect("process status",
substrs = ['exited'])
def ignore_read_write_watchpoint(self):
"""Test watchpoint ignore count and expect to not to stop at all."""
exe = os.path.join(os.getcwd(), self.exe_name)
self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
# Add a breakpoint to set a watchpoint when stopped on the breakpoint.
self.expect("breakpoint set -l %d" % self.line, BREAKPOINT_CREATED,
startstr = "Breakpoint created: 1: file ='%s', line = %d, locations = 1" %
(self.source, self.line))
# Run the program.
self.runCmd("run", RUN_SUCCEEDED)
# We should be stopped again due to the breakpoint.
# The stop reason of the thread should be breakpoint.
self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
substrs = ['stopped',
'stop reason = breakpoint'])
# Now let's set a read_write-type watchpoint for 'global'.
# There should be two watchpoint hits (see main.c).
self.expect("frame variable -w read_write -g -L global", WATCHPOINT_CREATED,
substrs = ['Watchpoint created', 'size = 4', 'type = rw',
'%s:%d' % (self.source, self.decl)])
# Set the ignore count of the watchpoint immediately.
self.expect("watchpoint ignore -i 2",
substrs = ['All watchpoints ignored.'])
# Use the '-v' option to do verbose listing of the watchpoint.
# Expect to find an ignore_count of 2.
self.expect("watchpoint list -v",
substrs = ['hit_count = 0', 'ignore_count = 2'])
self.runCmd("process continue")
# There should be no more watchpoint hit and the process status should
# be 'exited'.
self.expect("process status",
substrs = ['exited'])
# Use the '-v' option to do verbose listing of the watchpoint.
# Expect to find a hit_count of 2 as well.
self.expect("watchpoint list -v",
substrs = ['hit_count = 2', 'ignore_count = 2'])
def read_write_watchpoint_disable_after_first_stop(self):
"""Do read_write watchpoint but disable it after the first stop."""
exe = os.path.join(os.getcwd(), self.exe_name)

View File

@ -15,7 +15,7 @@ int main(int argc, char** argv) {
int local = 0;
printf("&global=%p\n", &global);
printf("about to write to 'global'...\n"); // Set break point at this line.
// When stopped, watch 'global' for write.
// When stopped, watch 'global'.
global = 20;
local += argc;
++local; // Set 2nd break point for disable_then_enable test case.

View File

@ -0,0 +1,102 @@
"""
Use lldb Python SBWatchpointLocation API to set the ignore count.
"""
import os, time
import re
import unittest2
import lldb, lldbutil
from lldbtest import *
class WatchpointIgnoreCountTestCase(TestBase):
mydir = os.path.join("python_api", "watchpoint")
def setUp(self):
# Call super's setUp().
TestBase.setUp(self)
# Our simple source filename.
self.source = 'main.c'
# Find the line number to break inside main().
self.line = line_number(self.source, '// Set break point at this line.')
@unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
@python_api_test
def test_set_watch_loc_ignore_count_with_dsym(self):
"""Test SBWatchpointLocation.SetIgnoreCount() API."""
self.buildDsym()
self.do_watchpoint_location_ignore_count()
@python_api_test
def test_set_watch_loc_ignore_count_with_dwarf(self):
"""Test SBWatchpointLocation.SetIgnoreCount() API."""
self.buildDwarf()
self.do_watchpoint_location_ignore_count()
def do_watchpoint_location_ignore_count(self):
"""Test SBWatchpointLocation.SetIgnoreCount() API."""
exe = os.path.join(os.getcwd(), "a.out")
# Create a target by the debugger.
target = self.dbg.CreateTarget(exe)
self.assertTrue(target, VALID_TARGET)
# Create a breakpoint on main.c in order to set our watchpoint later.
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)
# Watch 'global' for read and write.
value = frame0.WatchValue('global',
lldb.eValueTypeVariableGlobal,
lldb.LLDB_WATCH_TYPE_READ|lldb.LLDB_WATCH_TYPE_WRITE)
self.assertTrue(value, "Successfully found the variable and set a watchpoint")
self.DebugSBValue(value)
# Hide stdout if not running with '-t' option.
if not self.TraceOn():
self.HideStdout()
# There should be only 1 watchpoint location under the target.
self.assertTrue(target.GetNumWatchpointLocations() == 1)
wp_loc = target.GetWatchpointLocationAtIndex(0)
last_created = target.GetLastCreatedWatchpointLocation()
self.assertTrue(wp_loc == last_created)
self.assertTrue(wp_loc.IsEnabled())
self.assertTrue(wp_loc.GetIgnoreCount() == 0)
watch_id = wp_loc.GetID()
self.assertTrue(watch_id != 0)
print wp_loc
# Now immediately set the ignore count to 2. When we continue, expect the
# inferior to run to its completion without stopping due to watchpoint.
wp_loc.SetIgnoreCount(2)
print wp_loc
process.Continue()
# At this point, the inferior process should have exited.
self.assertTrue(process.GetState() == lldb.eStateExited, PROCESS_EXITED)
# Verify some vital statistics.
self.assertTrue(wp_loc)
self.assertTrue(wp_loc.GetWatchSize() == 4)
self.assertTrue(wp_loc.GetHitCount() == 2)
print wp_loc
if __name__ == '__main__':
import atexit
lldb.SBDebugger.Initialize()
atexit.register(lambda: lldb.SBDebugger.Terminate())
unittest2.main()