aboutsummaryrefslogtreecommitdiff
path: root/lldb/source
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source')
-rw-r--r--lldb/source/API/CMakeLists.txt1
-rw-r--r--lldb/source/API/SBTarget.cpp40
-rw-r--r--lldb/source/API/SBValue.cpp13
-rw-r--r--lldb/source/API/SBWatchpoint.cpp3
-rw-r--r--lldb/source/API/SBWatchpointOptions.cpp73
-rw-r--r--lldb/source/Breakpoint/Watchpoint.cpp55
-rw-r--r--lldb/source/Commands/CommandObjectWatchpoint.cpp30
-rw-r--r--lldb/source/Interpreter/OptionGroupWatchpoint.cpp5
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp10
-rw-r--r--lldb/source/Target/StopInfo.cpp6
-rw-r--r--lldb/source/Target/Target.cpp3
11 files changed, 202 insertions, 37 deletions
diff --git a/lldb/source/API/CMakeLists.txt b/lldb/source/API/CMakeLists.txt
index 39ac451..910cb66 100644
--- a/lldb/source/API/CMakeLists.txt
+++ b/lldb/source/API/CMakeLists.txt
@@ -91,6 +91,7 @@ add_lldb_library(liblldb SHARED ${option_framework}
SBValueList.cpp
SBVariablesOptions.cpp
SBWatchpoint.cpp
+ SBWatchpointOptions.cpp
SBUnixSignals.cpp
SystemInitializerFull.cpp
${lldb_python_wrapper}
diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp
index e38edf8..a4a7ac3 100644
--- a/lldb/source/API/SBTarget.cpp
+++ b/lldb/source/API/SBTarget.cpp
@@ -1322,27 +1322,39 @@ SBWatchpoint SBTarget::FindWatchpointByID(lldb::watch_id_t wp_id) {
}
lldb::SBWatchpoint SBTarget::WatchAddress(lldb::addr_t addr, size_t size,
- bool read, bool write,
+ bool read, bool modify,
SBError &error) {
LLDB_INSTRUMENT_VA(this, addr, size, read, write, error);
+ SBWatchpointOptions options;
+ options.SetWatchpointTypeRead(read);
+ options.SetWatchpointTypeWrite(eWatchpointWriteTypeOnModify);
+ return WatchpointCreateByAddress(addr, size, options, error);
+}
+
+lldb::SBWatchpoint
+SBTarget::WatchpointCreateByAddress(lldb::addr_t addr, size_t size,
+ SBWatchpointOptions options,
+ SBError &error) {
+ LLDB_INSTRUMENT_VA(this, addr, size, options, error);
+
SBWatchpoint sb_watchpoint;
lldb::WatchpointSP watchpoint_sp;
TargetSP target_sp(GetSP());
- if (target_sp && (read || write) && addr != LLDB_INVALID_ADDRESS &&
- size > 0) {
+ uint32_t watch_type = 0;
+ if (options.GetWatchpointTypeRead())
+ watch_type |= LLDB_WATCH_TYPE_READ;
+ if (options.GetWatchpointTypeWrite() == eWatchpointWriteTypeAlways)
+ watch_type |= LLDB_WATCH_TYPE_WRITE;
+ if (options.GetWatchpointTypeWrite() == eWatchpointWriteTypeOnModify)
+ watch_type |= LLDB_WATCH_TYPE_MODIFY;
+ if (watch_type == 0) {
+ error.SetErrorString("Can't create a watchpoint that is neither read nor "
+ "write nor modify.");
+ return sb_watchpoint;
+ }
+ if (target_sp && addr != LLDB_INVALID_ADDRESS && size > 0) {
std::lock_guard<std::recursive_mutex> guard(target_sp->GetAPIMutex());
- uint32_t watch_type = 0;
- if (read)
- watch_type |= LLDB_WATCH_TYPE_READ;
- if (write)
- watch_type |= LLDB_WATCH_TYPE_WRITE;
- if (watch_type == 0) {
- error.SetErrorString(
- "Can't create a watchpoint that is neither read nor write.");
- return sb_watchpoint;
- }
-
// Target::CreateWatchpoint() is thread safe.
Status cw_error;
// This API doesn't take in a type, so we can't figure out what it is.
diff --git a/lldb/source/API/SBValue.cpp b/lldb/source/API/SBValue.cpp
index 738773c..e14f119 100644
--- a/lldb/source/API/SBValue.cpp
+++ b/lldb/source/API/SBValue.cpp
@@ -1433,10 +1433,17 @@ lldb::SBWatchpoint SBValue::Watch(bool resolve_location, bool read, bool write,
return sb_watchpoint;
uint32_t watch_type = 0;
- if (read)
+ if (read) {
watch_type |= LLDB_WATCH_TYPE_READ;
- if (write)
- watch_type |= LLDB_WATCH_TYPE_WRITE;
+ // read + write, the most likely intention
+ // is to catch all writes to this, not just
+ // value modifications.
+ if (write)
+ watch_type |= LLDB_WATCH_TYPE_WRITE;
+ } else {
+ if (write)
+ watch_type |= LLDB_WATCH_TYPE_MODIFY;
+ }
Status rc;
CompilerType type(value_sp->GetCompilerType());
diff --git a/lldb/source/API/SBWatchpoint.cpp b/lldb/source/API/SBWatchpoint.cpp
index 6a63e65..8b4e0ad3 100644
--- a/lldb/source/API/SBWatchpoint.cpp
+++ b/lldb/source/API/SBWatchpoint.cpp
@@ -354,7 +354,8 @@ bool SBWatchpoint::IsWatchingWrites() {
std::lock_guard<std::recursive_mutex> guard(
watchpoint_sp->GetTarget().GetAPIMutex());
- return watchpoint_sp->WatchpointWrite();
+ return watchpoint_sp->WatchpointWrite() ||
+ watchpoint_sp->WatchpointModify();
}
return false;
diff --git a/lldb/source/API/SBWatchpointOptions.cpp b/lldb/source/API/SBWatchpointOptions.cpp
new file mode 100644
index 0000000..62e9c21
--- /dev/null
+++ b/lldb/source/API/SBWatchpointOptions.cpp
@@ -0,0 +1,73 @@
+//===-- SBWatchpointOptions.cpp -------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/API/SBWatchpointOptions.h"
+#include "lldb/Breakpoint/Watchpoint.h"
+#include "lldb/Utility/Instrumentation.h"
+
+#include "Utils.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+class WatchpointOptionsImpl {
+public:
+ bool m_read = false;
+ bool m_write = false;
+ bool m_modify = false;
+};
+
+
+SBWatchpointOptions::SBWatchpointOptions()
+ : m_opaque_up(new WatchpointOptionsImpl()) {
+ LLDB_INSTRUMENT_VA(this);
+}
+
+SBWatchpointOptions::SBWatchpointOptions(const SBWatchpointOptions &rhs) {
+ LLDB_INSTRUMENT_VA(this, rhs);
+
+ m_opaque_up = clone(rhs.m_opaque_up);
+}
+
+const SBWatchpointOptions &
+SBWatchpointOptions::operator=(const SBWatchpointOptions &rhs) {
+ LLDB_INSTRUMENT_VA(this, rhs);
+
+ if (this != &rhs)
+ m_opaque_up = clone(rhs.m_opaque_up);
+ return *this;
+}
+
+SBWatchpointOptions::~SBWatchpointOptions() = default;
+
+void SBWatchpointOptions::SetWatchpointTypeRead(bool read) {
+ m_opaque_up->m_read = read;
+}
+bool SBWatchpointOptions::GetWatchpointTypeRead() const {
+ return m_opaque_up->m_read;
+}
+
+void SBWatchpointOptions::SetWatchpointTypeWrite(
+ WatchpointWriteType write_type) {
+ if (write_type == eWatchpointWriteTypeOnModify) {
+ m_opaque_up->m_write = false;
+ m_opaque_up->m_modify = true;
+ } else if (write_type == eWatchpointWriteTypeAlways) {
+ m_opaque_up->m_write = true;
+ m_opaque_up->m_modify = false;
+ } else
+ m_opaque_up->m_write = m_opaque_up->m_modify = false;
+}
+
+WatchpointWriteType SBWatchpointOptions::GetWatchpointTypeWrite() const {
+ if (m_opaque_up->m_modify)
+ return eWatchpointWriteTypeOnModify;
+ if (m_opaque_up->m_write)
+ return eWatchpointWriteTypeAlways;
+ return eWatchpointWriteTypeDisabled;
+}
diff --git a/lldb/source/Breakpoint/Watchpoint.cpp b/lldb/source/Breakpoint/Watchpoint.cpp
index f88e899..1414421 100644
--- a/lldb/source/Breakpoint/Watchpoint.cpp
+++ b/lldb/source/Breakpoint/Watchpoint.cpp
@@ -29,7 +29,8 @@ Watchpoint::Watchpoint(Target &target, lldb::addr_t addr, uint32_t size,
: StoppointSite(0, addr, size, hardware), m_target(target),
m_enabled(false), m_is_hardware(hardware), m_is_watch_variable(false),
m_is_ephemeral(false), m_disabled_count(0), m_watch_read(0),
- m_watch_write(0), m_ignore_count(0), m_being_created(true) {
+ m_watch_write(0), m_watch_modify(0), m_ignore_count(0),
+ m_being_created(true) {
if (type && type->IsValid())
m_type = *type;
@@ -193,7 +194,7 @@ bool Watchpoint::IsWatchVariable() const { return m_is_watch_variable; }
void Watchpoint::SetWatchVariable(bool val) { m_is_watch_variable = val; }
bool Watchpoint::CaptureWatchedValue(const ExecutionContext &exe_ctx) {
- ConstString watch_name("$__lldb__watch_value");
+ ConstString g_watch_name("$__lldb__watch_value");
m_old_value_sp = m_new_value_sp;
Address watch_address(GetLoadAddress());
if (!m_type.IsValid()) {
@@ -205,12 +206,47 @@ bool Watchpoint::CaptureWatchedValue(const ExecutionContext &exe_ctx) {
return false;
}
m_new_value_sp = ValueObjectMemory::Create(
- exe_ctx.GetBestExecutionContextScope(), watch_name.GetStringRef(),
+ exe_ctx.GetBestExecutionContextScope(), g_watch_name.GetStringRef(),
watch_address, m_type);
- m_new_value_sp = m_new_value_sp->CreateConstantValue(watch_name);
+ m_new_value_sp = m_new_value_sp->CreateConstantValue(g_watch_name);
return (m_new_value_sp && m_new_value_sp->GetError().Success());
}
+bool Watchpoint::WatchedValueReportable(const ExecutionContext &exe_ctx) {
+ if (!m_watch_modify || m_watch_read)
+ return true;
+ if (!m_type.IsValid())
+ return true;
+
+ ConstString g_watch_name("$__lldb__watch_value");
+ Address watch_address(GetLoadAddress());
+ ValueObjectSP newest_valueobj_sp = ValueObjectMemory::Create(
+ exe_ctx.GetBestExecutionContextScope(), g_watch_name.GetStringRef(),
+ watch_address, m_type);
+ newest_valueobj_sp = newest_valueobj_sp->CreateConstantValue(g_watch_name);
+ Status error;
+
+ DataExtractor new_data;
+ DataExtractor old_data;
+
+ newest_valueobj_sp->GetData(new_data, error);
+ if (error.Fail())
+ return true;
+ m_new_value_sp->GetData(old_data, error);
+ if (error.Fail())
+ return true;
+
+ if (new_data.GetByteSize() != old_data.GetByteSize() ||
+ new_data.GetByteSize() == 0)
+ return true;
+
+ if (memcmp(new_data.GetDataStart(), old_data.GetDataStart(),
+ old_data.GetByteSize()) == 0)
+ return false; // Value has not changed, user requested modify watchpoint
+
+ return true;
+}
+
// RETURNS - true if we should stop at this breakpoint, false if we
// should continue.
@@ -268,10 +304,10 @@ void Watchpoint::DumpWithLevel(Stream *s,
description_level <= lldb::eDescriptionLevelVerbose);
s->Printf("Watchpoint %u: addr = 0x%8.8" PRIx64
- " size = %u state = %s type = %s%s",
+ " size = %u state = %s type = %s%s%s",
GetID(), GetLoadAddress(), m_byte_size,
IsEnabled() ? "enabled" : "disabled", m_watch_read ? "r" : "",
- m_watch_write ? "w" : "");
+ m_watch_write ? "w" : "", m_watch_modify ? "m" : "");
if (description_level >= lldb::eDescriptionLevelFull) {
if (!m_decl_str.empty())
@@ -333,10 +369,13 @@ void Watchpoint::SetEnabled(bool enabled, bool notify) {
void Watchpoint::SetWatchpointType(uint32_t type, bool notify) {
int old_watch_read = m_watch_read;
int old_watch_write = m_watch_write;
+ int old_watch_modify = m_watch_modify;
m_watch_read = (type & LLDB_WATCH_TYPE_READ) != 0;
m_watch_write = (type & LLDB_WATCH_TYPE_WRITE) != 0;
+ m_watch_modify = (type & LLDB_WATCH_TYPE_MODIFY) != 0;
if (notify &&
- (old_watch_read != m_watch_read || old_watch_write != m_watch_write))
+ (old_watch_read != m_watch_read || old_watch_write != m_watch_write ||
+ old_watch_modify != m_watch_modify))
SendWatchpointChangedEvent(eWatchpointEventTypeTypeChanged);
}
@@ -344,6 +383,8 @@ bool Watchpoint::WatchpointRead() const { return m_watch_read != 0; }
bool Watchpoint::WatchpointWrite() const { return m_watch_write != 0; }
+bool Watchpoint::WatchpointModify() const { return m_watch_modify != 0; }
+
uint32_t Watchpoint::GetIgnoreCount() const { return m_ignore_count; }
void Watchpoint::SetIgnoreCount(uint32_t n) {
diff --git a/lldb/source/Commands/CommandObjectWatchpoint.cpp b/lldb/source/Commands/CommandObjectWatchpoint.cpp
index a4929ea..83c2fb8 100644
--- a/lldb/source/Commands/CommandObjectWatchpoint.cpp
+++ b/lldb/source/Commands/CommandObjectWatchpoint.cpp
@@ -803,7 +803,7 @@ public:
"Set a watchpoint on a variable. "
"Use the '-w' option to specify the type of watchpoint and "
"the '-s' option to specify the byte size to watch for. "
- "If no '-w' option is specified, it defaults to write. "
+ "If no '-w' option is specified, it defaults to modify. "
"If no '-s' option is specified, it defaults to the variable's "
"byte size. "
"Note that there are limited hardware resources for watchpoints. "
@@ -878,9 +878,9 @@ protected:
return false;
}
- // If no '-w' is specified, default to '-w write'.
+ // If no '-w' is specified, default to '-w modify'.
if (!m_option_watchpoint.watch_type_specified) {
- m_option_watchpoint.watch_type = OptionGroupWatchpoint::eWatchWrite;
+ m_option_watchpoint.watch_type = OptionGroupWatchpoint::eWatchModify;
}
// We passed the sanity check for the command. Proceed to set the
@@ -947,7 +947,23 @@ protected:
}
// Now it's time to create the watchpoint.
- uint32_t watch_type = m_option_watchpoint.watch_type;
+ uint32_t watch_type = 0;
+ switch (m_option_watchpoint.watch_type) {
+ case OptionGroupWatchpoint::eWatchModify:
+ watch_type |= LLDB_WATCH_TYPE_MODIFY;
+ break;
+ case OptionGroupWatchpoint::eWatchRead:
+ watch_type |= LLDB_WATCH_TYPE_READ;
+ break;
+ case OptionGroupWatchpoint::eWatchReadWrite:
+ watch_type |= LLDB_WATCH_TYPE_READ | LLDB_WATCH_TYPE_WRITE;
+ break;
+ case OptionGroupWatchpoint::eWatchWrite:
+ watch_type |= LLDB_WATCH_TYPE_WRITE;
+ break;
+ case OptionGroupWatchpoint::eWatchInvalid:
+ break;
+ };
error.Clear();
WatchpointSP watch_sp =
@@ -999,7 +1015,7 @@ public:
"Use the '-l' option to specify the language of the expression. "
"Use the '-w' option to specify the type of watchpoint and "
"the '-s' option to specify the byte size to watch for. "
- "If no '-w' option is specified, it defaults to write. "
+ "If no '-w' option is specified, it defaults to modify. "
"If no '-s' option is specified, it defaults to the target's "
"pointer byte size. "
"Note that there are limited hardware resources for watchpoints. "
@@ -1013,7 +1029,7 @@ public:
R"(
Examples:
-(lldb) watchpoint set expression -w write -s 1 -- foo + 32
+(lldb) watchpoint set expression -w modify -s 1 -- foo + 32
Watches write access for the 1-byte region pointed to by the address 'foo + 32')");
@@ -1073,7 +1089,7 @@ protected:
// If no '-w' is specified, default to '-w write'.
if (!m_option_watchpoint.watch_type_specified) {
- m_option_watchpoint.watch_type = OptionGroupWatchpoint::eWatchWrite;
+ m_option_watchpoint.watch_type = OptionGroupWatchpoint::eWatchModify;
}
// We passed the sanity check for the command. Proceed to set the
diff --git a/lldb/source/Interpreter/OptionGroupWatchpoint.cpp b/lldb/source/Interpreter/OptionGroupWatchpoint.cpp
index c2f78d8..c3708e7 100644
--- a/lldb/source/Interpreter/OptionGroupWatchpoint.cpp
+++ b/lldb/source/Interpreter/OptionGroupWatchpoint.cpp
@@ -28,6 +28,11 @@ static constexpr OptionEnumValueElement g_watch_type[] = {
"Watch for write",
},
{
+ OptionGroupWatchpoint::eWatchModify,
+ "modify",
+ "Watch for modifications",
+ },
+ {
OptionGroupWatchpoint::eWatchReadWrite,
"read_write",
"Watch for read/write",
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 2fc446b..9d4e0a9 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -3108,14 +3108,16 @@ static GDBStoppointType GetGDBStoppointType(Watchpoint *wp) {
assert(wp);
bool watch_read = wp->WatchpointRead();
bool watch_write = wp->WatchpointWrite();
+ bool watch_modify = wp->WatchpointModify();
- // watch_read and watch_write cannot both be false.
- assert(watch_read || watch_write);
- if (watch_read && watch_write)
+ // watch_read, watch_write, watch_modify cannot all be false.
+ assert((watch_read || watch_write || watch_modify) &&
+ "watch_read, watch_write, watch_modify cannot all be false.");
+ if (watch_read && (watch_write || watch_modify))
return eWatchpointReadWrite;
else if (watch_read)
return eWatchpointRead;
- else // Must be watch_write, then.
+ else // Must be watch_write or watch_modify, then.
return eWatchpointWrite;
}
diff --git a/lldb/source/Target/StopInfo.cpp b/lldb/source/Target/StopInfo.cpp
index ff3d8f6..a189f4b 100644
--- a/lldb/source/Target/StopInfo.cpp
+++ b/lldb/source/Target/StopInfo.cpp
@@ -982,6 +982,12 @@ protected:
m_should_stop = false;
}
}
+
+ // Don't stop if the watched region value is unmodified, and
+ // this is a Modify-type watchpoint.
+ if (m_should_stop && !wp_sp->WatchedValueReportable(exe_ctx))
+ m_should_stop = false;
+
// Finally, if we are going to stop, print out the new & old values:
if (m_should_stop) {
wp_sp->CaptureWatchedValue(exe_ctx);
diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp
index 8de4fd0..f197b1b 100644
--- a/lldb/source/Target/Target.cpp
+++ b/lldb/source/Target/Target.cpp
@@ -860,7 +860,8 @@ WatchpointSP Target::CreateWatchpoint(lldb::addr_t addr, size_t size,
size_t old_size = matched_sp->GetByteSize();
uint32_t old_type =
(matched_sp->WatchpointRead() ? LLDB_WATCH_TYPE_READ : 0) |
- (matched_sp->WatchpointWrite() ? LLDB_WATCH_TYPE_WRITE : 0);
+ (matched_sp->WatchpointWrite() ? LLDB_WATCH_TYPE_WRITE : 0) |
+ (matched_sp->WatchpointModify() ? LLDB_WATCH_TYPE_MODIFY : 0);
// Return the existing watchpoint if both size and type match.
if (size == old_size && kind == old_type) {
wp_sp = matched_sp;