forked from OSchip/llvm-project
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:
parent
a2e40934d5
commit
6cc60e8668
|
@ -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);
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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 ()
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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()
|
Loading…
Reference in New Issue