diff options
Diffstat (limited to 'lldb/source/Breakpoint/Watchpoint.cpp')
| -rw-r--r-- | lldb/source/Breakpoint/Watchpoint.cpp | 141 |
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) { |
