summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lldb/include/lldb/Breakpoint/Watchpoint.h6
-rw-r--r--lldb/source/Breakpoint/Watchpoint.cpp20
-rw-r--r--lldb/source/Target/StopInfo.cpp26
-rw-r--r--lldb/test/functionalities/watchpoint/variable_out_of_scope/Makefile5
-rw-r--r--lldb/test/functionalities/watchpoint/variable_out_of_scope/TestWatchedVarHitWhenInScope.py88
-rw-r--r--lldb/test/functionalities/watchpoint/variable_out_of_scope/main.c15
6 files changed, 152 insertions, 8 deletions
diff --git a/lldb/include/lldb/Breakpoint/Watchpoint.h b/lldb/include/lldb/Breakpoint/Watchpoint.h
index 0f11b30811c..2b72a2fd4fe 100644
--- a/lldb/include/lldb/Breakpoint/Watchpoint.h
+++ b/lldb/include/lldb/Breakpoint/Watchpoint.h
@@ -36,6 +36,9 @@ public:
~Watchpoint ();
+ void
+ IncrementFalseAlarmsAndReviseHitCount();
+
bool
IsEnabled () const;
@@ -162,7 +165,8 @@ private:
m_watch_write:1, // 1 if we stop when the watched data is written to
m_watch_was_read:1, // Set to 1 when watchpoint is hit for a read access
m_watch_was_written:1; // Set to 1 when watchpoint is hit for a write access
- uint32_t m_ignore_count; // Number of times to ignore this breakpoint
+ uint32_t m_ignore_count; // Number of times to ignore this watchpoint
+ uint32_t m_false_alarms; // Number of false alarms.
std::string m_decl_str; // Declaration information, if any.
std::string m_watch_spec_str; // Spec for the watchpoint.
std::string m_snapshot_old_str; // Old snapshot for the watchpoint value as by ValueObject::DumpValueObject().
diff --git a/lldb/source/Breakpoint/Watchpoint.cpp b/lldb/source/Breakpoint/Watchpoint.cpp
index 6ba2f9c89f4..d4c099be0c1 100644
--- a/lldb/source/Breakpoint/Watchpoint.cpp
+++ b/lldb/source/Breakpoint/Watchpoint.cpp
@@ -34,6 +34,7 @@ Watchpoint::Watchpoint (lldb::addr_t addr, size_t size, bool hardware) :
m_watch_was_read(0),
m_watch_was_written(0),
m_ignore_count(0),
+ m_false_alarms(0),
m_decl_str(),
m_watch_spec_str(),
m_snapshot_old_str(),
@@ -183,6 +184,25 @@ Watchpoint::SetWatchVariable(bool val)
m_is_watch_variable = val;
}
+void
+Watchpoint::IncrementFalseAlarmsAndReviseHitCount()
+{
+ ++m_false_alarms;
+ if (m_false_alarms)
+ {
+ if (m_hit_count >= m_false_alarms)
+ {
+ m_hit_count -= m_false_alarms;
+ m_false_alarms = 0;
+ }
+ else
+ {
+ m_false_alarms -= m_hit_count;
+ m_hit_count = 0;
+ }
+ }
+}
+
// RETURNS - true if we should stop at this breakpoint, false if we
// should continue.
diff --git a/lldb/source/Target/StopInfo.cpp b/lldb/source/Target/StopInfo.cpp
index 5732ed66cc1..434b0067712 100644
--- a/lldb/source/Target/StopInfo.cpp
+++ b/lldb/source/Target/StopInfo.cpp
@@ -498,6 +498,7 @@ public:
StackFrame *frame = exe_ctx.GetFramePtr();
if (frame)
{
+ bool snapshot_taken = true;
if (!wp_sp->IsWatchVariable())
{
// We are not watching a variable, just read from the process memory for the watched location.
@@ -535,18 +536,29 @@ public:
wp_sp->SetNewSnapshot(ss.GetString());
}
else
- wp_sp->SetNewSnapshot("snapshot attempt failed.");
+ {
+ // The variable expression has become out of scope?
+ // Let us forget about this stop info.
+ if (log)
+ log->Printf("Snapshot attempt failed. Variable expression has become out of scope?");
+ snapshot_taken = false;
+ m_should_stop = false;
+ wp_sp->IncrementFalseAlarmsAndReviseHitCount();
+ }
- if (log)
+ if (log && snapshot_taken)
log->Printf("Watchpoint snapshot taken: '%s'\n", wp_sp->GetNewSnapshot().c_str());
}
// Now dump the snapshots we have taken.
- Debugger &debugger = exe_ctx.GetTargetRef().GetDebugger();
- StreamSP output_sp = debugger.GetAsyncOutputStream ();
- wp_sp->DumpSnapshots(output_sp.get());
- output_sp->EOL();
- output_sp->Flush();
+ if (snapshot_taken)
+ {
+ Debugger &debugger = exe_ctx.GetTargetRef().GetDebugger();
+ StreamSP output_sp = debugger.GetAsyncOutputStream ();
+ wp_sp->DumpSnapshots(output_sp.get());
+ output_sp->EOL();
+ output_sp->Flush();
+ }
}
if (m_should_stop && wp_sp->GetConditionText() != NULL)
diff --git a/lldb/test/functionalities/watchpoint/variable_out_of_scope/Makefile b/lldb/test/functionalities/watchpoint/variable_out_of_scope/Makefile
new file mode 100644
index 00000000000..b09a579159d
--- /dev/null
+++ b/lldb/test/functionalities/watchpoint/variable_out_of_scope/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+C_SOURCES := main.c
+
+include $(LEVEL)/Makefile.rules
diff --git a/lldb/test/functionalities/watchpoint/variable_out_of_scope/TestWatchedVarHitWhenInScope.py b/lldb/test/functionalities/watchpoint/variable_out_of_scope/TestWatchedVarHitWhenInScope.py
new file mode 100644
index 00000000000..b690432c2cd
--- /dev/null
+++ b/lldb/test/functionalities/watchpoint/variable_out_of_scope/TestWatchedVarHitWhenInScope.py
@@ -0,0 +1,88 @@
+"""
+Test that a variable watchpoint should only hit when in scope.
+"""
+
+import os, time
+import unittest2
+import lldb
+from lldbtest import *
+
+class WatchedVariableHitWhenInScopeTestCase(TestBase):
+
+ mydir = os.path.join("functionalities", "watchpoint", "variable_out_of_scope")
+
+ @dsym_test
+ def test_watched_var_should_only_hit_when_in_scope_with_dsym(self):
+ """Test that a variable watchpoint should only hit when in scope."""
+ self.buildDsym(dictionary=self.d)
+ self.setTearDownCleanup(dictionary=self.d)
+ self.watched_var()
+
+ @dwarf_test
+ def test_watched_var_should_only_hit_when_in_scope_with_dwarf(self):
+ """Test that a variable watchpoint should only hit when in scope."""
+ self.buildDwarf(dictionary=self.d)
+ self.setTearDownCleanup(dictionary=self.d)
+ self.watched_var()
+
+ def setUp(self):
+ # Call super's setUp().
+ TestBase.setUp(self)
+ # Our simple source filename.
+ self.source = 'main.c'
+ self.exe_name = self.testMethodName
+ self.d = {'C_SOURCES': self.source, 'EXE': self.exe_name}
+
+ def watched_var(self):
+ """Test a simple sequence of watchpoint creation and watchpoint hit."""
+ 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 in main.
+ self.expect("breakpoint set -n main", BREAKPOINT_CREATED,
+ startstr = "Breakpoint created: 1: name = 'main'")
+
+ # 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 watchpoint for 'c.a'.
+ # There should be only one watchpoint hit (see main.c).
+ self.expect("watchpoint set variable c.a", WATCHPOINT_CREATED,
+ substrs = ['Watchpoint created', 'size = 4', 'type = w'])
+
+ # Use the '-v' option to do verbose listing of the watchpoint.
+ # The hit count should be 0 initially.
+ self.expect("watchpoint list -v",
+ substrs = ['hit_count = 0'])
+
+ self.runCmd("process continue")
+
+ # We should be stopped again due to the watchpoint (write type), but
+ # only once. The stop reason of the thread should be watchpoint.
+ self.expect("thread list", STOPPED_DUE_TO_WATCHPOINT,
+ substrs = ['stopped',
+ 'stop reason = watchpoint'])
+
+ self.runCmd("process continue")
+ # Don't expect the read of 'global' to trigger a stop exception.
+ # The process status should be 'exited'.
+ self.expect("process status",
+ substrs = ['exited'])
+
+ # Use the '-v' option to do verbose listing of the watchpoint.
+ # The hit count should now be 1.
+ self.expect("watchpoint list -v",
+ substrs = ['hit_count = 1'])
+
+
+if __name__ == '__main__':
+ import atexit
+ lldb.SBDebugger.Initialize()
+ atexit.register(lambda: lldb.SBDebugger.Terminate())
+ unittest2.main()
diff --git a/lldb/test/functionalities/watchpoint/variable_out_of_scope/main.c b/lldb/test/functionalities/watchpoint/variable_out_of_scope/main.c
new file mode 100644
index 00000000000..1bf7a00ac83
--- /dev/null
+++ b/lldb/test/functionalities/watchpoint/variable_out_of_scope/main.c
@@ -0,0 +1,15 @@
+typedef struct
+{
+ int a;
+ float b;
+} mystruct;
+
+int main()
+{
+ mystruct c;
+
+ c.a = 5;
+ c.b = 3.6;
+
+ return 0;
+} \ No newline at end of file
OpenPOWER on IntegriCloud