diff options
Diffstat (limited to 'lldb/source')
-rw-r--r-- | lldb/source/API/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lldb/source/API/SBTarget.cpp | 40 | ||||
-rw-r--r-- | lldb/source/API/SBValue.cpp | 13 | ||||
-rw-r--r-- | lldb/source/API/SBWatchpoint.cpp | 3 | ||||
-rw-r--r-- | lldb/source/API/SBWatchpointOptions.cpp | 73 | ||||
-rw-r--r-- | lldb/source/Breakpoint/Watchpoint.cpp | 55 | ||||
-rw-r--r-- | lldb/source/Commands/CommandObjectWatchpoint.cpp | 30 | ||||
-rw-r--r-- | lldb/source/Interpreter/OptionGroupWatchpoint.cpp | 5 | ||||
-rw-r--r-- | lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp | 10 | ||||
-rw-r--r-- | lldb/source/Target/StopInfo.cpp | 6 | ||||
-rw-r--r-- | lldb/source/Target/Target.cpp | 3 |
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; |