aboutsummaryrefslogtreecommitdiff
path: root/lldb/source/Breakpoint/Watchpoint.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Breakpoint/Watchpoint.cpp')
-rw-r--r--lldb/source/Breakpoint/Watchpoint.cpp141
1 files changed, 109 insertions, 32 deletions
diff --git a/lldb/source/Breakpoint/Watchpoint.cpp b/lldb/source/Breakpoint/Watchpoint.cpp
index a20a4ad98c5a..4602ce4213b9 100644
--- a/lldb/source/Breakpoint/Watchpoint.cpp
+++ b/lldb/source/Breakpoint/Watchpoint.cpp
@@ -9,9 +9,11 @@
#include "lldb/Breakpoint/Watchpoint.h"
#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Breakpoint/WatchpointResource.h"
#include "lldb/Core/Value.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectMemory.h"
+#include "lldb/DataFormatters/DumpValueObjectOptions.h"
#include "lldb/Expression/UserExpression.h"
#include "lldb/Symbol/TypeSystem.h"
#include "lldb/Target/Process.h"
@@ -29,7 +31,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;
@@ -66,7 +69,7 @@ Watchpoint::~Watchpoint() = default;
void Watchpoint::SetCallback(WatchpointHitCallback callback, void *baton,
bool is_synchronous) {
// The default "Baton" class will keep a copy of "baton" and won't free or
- // delete it when it goes goes out of scope.
+ // delete it when it goes out of scope.
m_options.SetCallback(callback, std::make_shared<UntypedBaton>(baton),
is_synchronous);
@@ -160,7 +163,7 @@ bool Watchpoint::VariableWatchpointDisabler(void *baton,
"callback for watchpoint %" PRId32
" matched internal breakpoint execution context",
watch_sp->GetID());
- process_sp->DisableWatchpoint(watch_sp.get());
+ process_sp->DisableWatchpoint(watch_sp);
return false;
}
LLDB_LOGF(log,
@@ -193,7 +196,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 +208,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.
@@ -230,33 +268,69 @@ void Watchpoint::Dump(Stream *s) const {
// If prefix is nullptr, we display the watch id and ignore the prefix
// altogether.
-void Watchpoint::DumpSnapshots(Stream *s, const char *prefix) const {
- if (!prefix) {
- s->Printf("\nWatchpoint %u hit:", GetID());
- prefix = "";
- }
+bool Watchpoint::DumpSnapshots(Stream *s, const char *prefix) const {
+ bool printed_anything = false;
+
+ // For read watchpoints, don't display any before/after value changes.
+ if (m_watch_read && !m_watch_modify && !m_watch_write)
+ return printed_anything;
+
+ s->Printf("\n");
+ s->Printf("Watchpoint %u hit:\n", GetID());
+
+ StreamString values_ss;
+ if (prefix)
+ values_ss.Indent(prefix);
if (m_old_value_sp) {
- const char *old_value_cstr = m_old_value_sp->GetValueAsCString();
- if (old_value_cstr && old_value_cstr[0])
- s->Printf("\n%sold value: %s", prefix, old_value_cstr);
- else {
- const char *old_summary_cstr = m_old_value_sp->GetSummaryAsCString();
- if (old_summary_cstr && old_summary_cstr[0])
- s->Printf("\n%sold value: %s", prefix, old_summary_cstr);
+ if (auto *old_value_cstr = m_old_value_sp->GetValueAsCString()) {
+ values_ss.Printf("old value: %s", old_value_cstr);
+ } else {
+ if (auto *old_summary_cstr = m_old_value_sp->GetSummaryAsCString())
+ values_ss.Printf("old value: %s", old_summary_cstr);
+ else {
+ StreamString strm;
+ DumpValueObjectOptions options;
+ options.SetUseDynamicType(eNoDynamicValues)
+ .SetHideRootType(true)
+ .SetHideRootName(true)
+ .SetHideName(true);
+ m_old_value_sp->Dump(strm, options);
+ if (strm.GetData())
+ values_ss.Printf("old value: %s", strm.GetData());
+ }
}
}
if (m_new_value_sp) {
- const char *new_value_cstr = m_new_value_sp->GetValueAsCString();
- if (new_value_cstr && new_value_cstr[0])
- s->Printf("\n%snew value: %s", prefix, new_value_cstr);
+ if (values_ss.GetSize())
+ values_ss.Printf("\n");
+
+ if (auto *new_value_cstr = m_new_value_sp->GetValueAsCString())
+ values_ss.Printf("new value: %s", new_value_cstr);
else {
- const char *new_summary_cstr = m_new_value_sp->GetSummaryAsCString();
- if (new_summary_cstr && new_summary_cstr[0])
- s->Printf("\n%snew value: %s", prefix, new_summary_cstr);
+ if (auto *new_summary_cstr = m_new_value_sp->GetSummaryAsCString())
+ values_ss.Printf("new value: %s", new_summary_cstr);
+ else {
+ StreamString strm;
+ DumpValueObjectOptions options;
+ options.SetUseDynamicType(eNoDynamicValues)
+ .SetHideRootType(true)
+ .SetHideRootName(true)
+ .SetHideName(true);
+ m_new_value_sp->Dump(strm, options);
+ if (strm.GetData())
+ values_ss.Printf("new value: %s", strm.GetData());
+ }
}
}
+
+ if (values_ss.GetSize()) {
+ s->Printf("%s", values_ss.GetData());
+ printed_anything = true;
+ }
+
+ return printed_anything;
}
void Watchpoint::DumpWithLevel(Stream *s,
@@ -268,10 +342,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())
@@ -288,8 +362,8 @@ void Watchpoint::DumpWithLevel(Stream *s,
}
if (description_level >= lldb::eDescriptionLevelVerbose) {
- s->Printf("\n hw_index = %i hit_count = %-4u ignore_count = %-4u",
- GetHardwareIndex(), GetHitCount(), GetIgnoreCount());
+ s->Printf("\n hit_count = %-4u ignore_count = %-4u", GetHitCount(),
+ GetIgnoreCount());
}
}
@@ -314,9 +388,7 @@ bool Watchpoint::IsDisabledDuringEphemeralMode() {
void Watchpoint::SetEnabled(bool enabled, bool notify) {
if (!enabled) {
- if (!m_is_ephemeral)
- SetHardwareIndex(LLDB_INVALID_INDEX32);
- else
+ if (m_is_ephemeral)
++m_disabled_count;
// Don't clear the snapshots for now.
@@ -333,10 +405,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 +419,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) {