diff options
Diffstat (limited to 'lldb/source')
33 files changed, 714 insertions, 533 deletions
diff --git a/lldb/source/API/SBThread.cpp b/lldb/source/API/SBThread.cpp index 18c086b..fa4c80e 100644 --- a/lldb/source/API/SBThread.cpp +++ b/lldb/source/API/SBThread.cpp @@ -181,7 +181,7 @@ size_t SBThread::GetStopReasonDataCount() { exe_ctx.GetProcessPtr()->GetBreakpointSiteList().FindByID( site_id)); if (bp_site_sp) - return bp_site_sp->GetNumberOfOwners() * 2; + return bp_site_sp->GetNumberOfConstituents() * 2; else return 0; // Breakpoint must have cleared itself... } break; @@ -241,7 +241,7 @@ uint64_t SBThread::GetStopReasonDataAtIndex(uint32_t idx) { if (bp_site_sp) { uint32_t bp_index = idx / 2; BreakpointLocationSP bp_loc_sp( - bp_site_sp->GetOwnerAtIndex(bp_index)); + bp_site_sp->GetConstituentAtIndex(bp_index)); if (bp_loc_sp) { if (idx & 1) { // Odd idx, return the breakpoint location ID diff --git a/lldb/source/API/SBWatchpoint.cpp b/lldb/source/API/SBWatchpoint.cpp index 8e60e6d..9664bbe 100644 --- a/lldb/source/API/SBWatchpoint.cpp +++ b/lldb/source/API/SBWatchpoint.cpp @@ -142,9 +142,9 @@ void SBWatchpoint::SetEnabled(bool enabled) { const bool notify = true; if (process_sp) { if (enabled) - process_sp->EnableWatchpoint(watchpoint_sp.get(), notify); + process_sp->EnableWatchpoint(watchpoint_sp, notify); else - process_sp->DisableWatchpoint(watchpoint_sp.get(), notify); + process_sp->DisableWatchpoint(watchpoint_sp, notify); } else { watchpoint_sp->SetEnabled(enabled, notify); } diff --git a/lldb/source/Breakpoint/BreakpointLocation.cpp b/lldb/source/Breakpoint/BreakpointLocation.cpp index 931e1ad..99f94d0 100644 --- a/lldb/source/Breakpoint/BreakpointLocation.cpp +++ b/lldb/source/Breakpoint/BreakpointLocation.cpp @@ -473,10 +473,10 @@ bool BreakpointLocation::ClearBreakpointSite() { // physical implementation of the breakpoint as well if there are no more // owners. Otherwise just remove this owner. if (process_sp) - process_sp->RemoveOwnerFromBreakpointSite(GetBreakpoint().GetID(), - GetID(), m_bp_site_sp); + process_sp->RemoveConstituentFromBreakpointSite(GetBreakpoint().GetID(), + GetID(), m_bp_site_sp); else - m_bp_site_sp->RemoveOwner(GetBreakpoint().GetID(), GetID()); + m_bp_site_sp->RemoveConstituent(GetBreakpoint().GetID(), GetID()); m_bp_site_sp.reset(); return true; diff --git a/lldb/source/Breakpoint/BreakpointSite.cpp b/lldb/source/Breakpoint/BreakpointSite.cpp index 5187bc5..3ca93f9 100644 --- a/lldb/source/Breakpoint/BreakpointSite.cpp +++ b/lldb/source/Breakpoint/BreakpointSite.cpp @@ -12,14 +12,12 @@ #include "lldb/Breakpoint/Breakpoint.h" #include "lldb/Breakpoint/BreakpointLocation.h" -#include "lldb/Breakpoint/BreakpointSiteList.h" #include "lldb/Utility/Stream.h" using namespace lldb; using namespace lldb_private; -BreakpointSite::BreakpointSite(BreakpointSiteList *list, - const BreakpointLocationSP &owner, +BreakpointSite::BreakpointSite(const BreakpointLocationSP &constituent, lldb::addr_t addr, bool use_hardware) : StoppointSite(GetNextID(), addr, 0, use_hardware), m_type(eSoftware), // Process subclasses need to set this correctly using @@ -28,14 +26,14 @@ BreakpointSite::BreakpointSite(BreakpointSiteList *list, m_enabled(false) // Need to create it disabled, so the first enable turns // it on. { - m_owners.Add(owner); + m_constituents.Add(constituent); } BreakpointSite::~BreakpointSite() { BreakpointLocationSP bp_loc_sp; - const size_t owner_count = m_owners.GetSize(); - for (size_t i = 0; i < owner_count; i++) { - m_owners.GetByIndex(i)->ClearBreakpointSite(); + const size_t constituent_count = m_constituents.GetSize(); + for (size_t i = 0; i < constituent_count; i++) { + m_constituents.GetByIndex(i)->ClearBreakpointSite(); } } @@ -50,22 +48,22 @@ break_id_t BreakpointSite::GetNextID() { bool BreakpointSite::ShouldStop(StoppointCallbackContext *context) { m_hit_counter.Increment(); // ShouldStop can do a lot of work, and might even come back and hit - // this breakpoint site again. So don't hold the m_owners_mutex the whole - // while. Instead make a local copy of the collection and call ShouldStop on - // the copy. - BreakpointLocationCollection owners_copy; + // this breakpoint site again. So don't hold the m_constituents_mutex the + // whole while. Instead make a local copy of the collection and call + // ShouldStop on the copy. + BreakpointLocationCollection constituents_copy; { - std::lock_guard<std::recursive_mutex> guard(m_owners_mutex); - owners_copy = m_owners; + std::lock_guard<std::recursive_mutex> guard(m_constituents_mutex); + constituents_copy = m_constituents; } - return owners_copy.ShouldStop(context); + return constituents_copy.ShouldStop(context); } bool BreakpointSite::IsBreakpointAtThisSite(lldb::break_id_t bp_id) { - std::lock_guard<std::recursive_mutex> guard(m_owners_mutex); - const size_t owner_count = m_owners.GetSize(); - for (size_t i = 0; i < owner_count; i++) { - if (m_owners.GetByIndex(i)->GetBreakpoint().GetID() == bp_id) + std::lock_guard<std::recursive_mutex> guard(m_constituents_mutex); + const size_t constituent_count = m_constituents.GetSize(); + for (size_t i = 0; i < constituent_count; i++) { + if (m_constituents.GetByIndex(i)->GetBreakpoint().GetID() == bp_id) return true; } return false; @@ -82,14 +80,14 @@ void BreakpointSite::Dump(Stream *s) const { } void BreakpointSite::GetDescription(Stream *s, lldb::DescriptionLevel level) { - std::lock_guard<std::recursive_mutex> guard(m_owners_mutex); + std::lock_guard<std::recursive_mutex> guard(m_constituents_mutex); if (level != lldb::eDescriptionLevelBrief) s->Printf("breakpoint site: %d at 0x%8.8" PRIx64, GetID(), GetLoadAddress()); - m_owners.GetDescription(s, level); + m_constituents.GetDescription(s, level); } -bool BreakpointSite::IsInternal() const { return m_owners.IsInternal(); } +bool BreakpointSite::IsInternal() const { return m_constituents.IsInternal(); } uint8_t *BreakpointSite::GetTrapOpcodeBytes() { return &m_trap_opcode[0]; } @@ -122,36 +120,36 @@ bool BreakpointSite::IsEnabled() const { return m_enabled; } void BreakpointSite::SetEnabled(bool enabled) { m_enabled = enabled; } -void BreakpointSite::AddOwner(const BreakpointLocationSP &owner) { - std::lock_guard<std::recursive_mutex> guard(m_owners_mutex); - m_owners.Add(owner); +void BreakpointSite::AddConstituent(const BreakpointLocationSP &constituent) { + std::lock_guard<std::recursive_mutex> guard(m_constituents_mutex); + m_constituents.Add(constituent); } -size_t BreakpointSite::RemoveOwner(lldb::break_id_t break_id, - lldb::break_id_t break_loc_id) { - std::lock_guard<std::recursive_mutex> guard(m_owners_mutex); - m_owners.Remove(break_id, break_loc_id); - return m_owners.GetSize(); +size_t BreakpointSite::RemoveConstituent(lldb::break_id_t break_id, + lldb::break_id_t break_loc_id) { + std::lock_guard<std::recursive_mutex> guard(m_constituents_mutex); + m_constituents.Remove(break_id, break_loc_id); + return m_constituents.GetSize(); } -size_t BreakpointSite::GetNumberOfOwners() { - std::lock_guard<std::recursive_mutex> guard(m_owners_mutex); - return m_owners.GetSize(); +size_t BreakpointSite::GetNumberOfConstituents() { + std::lock_guard<std::recursive_mutex> guard(m_constituents_mutex); + return m_constituents.GetSize(); } -BreakpointLocationSP BreakpointSite::GetOwnerAtIndex(size_t index) { - std::lock_guard<std::recursive_mutex> guard(m_owners_mutex); - return m_owners.GetByIndex(index); +BreakpointLocationSP BreakpointSite::GetConstituentAtIndex(size_t index) { + std::lock_guard<std::recursive_mutex> guard(m_constituents_mutex); + return m_constituents.GetByIndex(index); } bool BreakpointSite::ValidForThisThread(Thread &thread) { - std::lock_guard<std::recursive_mutex> guard(m_owners_mutex); - return m_owners.ValidForThisThread(thread); + std::lock_guard<std::recursive_mutex> guard(m_constituents_mutex); + return m_constituents.ValidForThisThread(thread); } void BreakpointSite::BumpHitCounts() { - std::lock_guard<std::recursive_mutex> guard(m_owners_mutex); - for (BreakpointLocationSP loc_sp : m_owners.BreakpointLocations()) { + std::lock_guard<std::recursive_mutex> guard(m_constituents_mutex); + for (BreakpointLocationSP loc_sp : m_constituents.BreakpointLocations()) { loc_sp->BumpHitCount(); } } @@ -198,10 +196,10 @@ bool BreakpointSite::IntersectsRange(lldb::addr_t addr, size_t size, return true; } -size_t -BreakpointSite::CopyOwnersList(BreakpointLocationCollection &out_collection) { - std::lock_guard<std::recursive_mutex> guard(m_owners_mutex); - for (BreakpointLocationSP loc_sp : m_owners.BreakpointLocations()) { +size_t BreakpointSite::CopyConstituentsList( + BreakpointLocationCollection &out_collection) { + std::lock_guard<std::recursive_mutex> guard(m_constituents_mutex); + for (BreakpointLocationSP loc_sp : m_constituents.BreakpointLocations()) { out_collection.Add(loc_sp); } return out_collection.GetSize(); diff --git a/lldb/source/Breakpoint/BreakpointSiteList.cpp b/lldb/source/Breakpoint/BreakpointSiteList.cpp deleted file mode 100644 index ab15da8..0000000 --- a/lldb/source/Breakpoint/BreakpointSiteList.cpp +++ /dev/null @@ -1,193 +0,0 @@ -//===-- BreakpointSiteList.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/Breakpoint/BreakpointSiteList.h" - -#include "lldb/Utility/Stream.h" -#include <algorithm> - -using namespace lldb; -using namespace lldb_private; - -BreakpointSiteList::BreakpointSiteList() = default; - -BreakpointSiteList::~BreakpointSiteList() = default; - -// Add breakpoint site to the list. However, if the element already exists in -// the list, then we don't add it, and return LLDB_INVALID_BREAK_ID. - -lldb::break_id_t BreakpointSiteList::Add(const BreakpointSiteSP &bp) { - lldb::addr_t bp_site_load_addr = bp->GetLoadAddress(); - std::lock_guard<std::recursive_mutex> guard(m_mutex); - collection::iterator iter = m_bp_site_list.find(bp_site_load_addr); - - if (iter == m_bp_site_list.end()) { - m_bp_site_list.insert(iter, collection::value_type(bp_site_load_addr, bp)); - return bp->GetID(); - } else { - return LLDB_INVALID_BREAK_ID; - } -} - -bool BreakpointSiteList::ShouldStop(StoppointCallbackContext *context, - lldb::break_id_t site_id) { - BreakpointSiteSP site_sp(FindByID(site_id)); - if (site_sp) { - // Let the BreakpointSite decide if it should stop here (could not have - // reached it's target hit count yet, or it could have a callback that - // decided it shouldn't stop (shared library loads/unloads). - return site_sp->ShouldStop(context); - } - // We should stop here since this BreakpointSite isn't valid anymore or it - // doesn't exist. - return true; -} -lldb::break_id_t BreakpointSiteList::FindIDByAddress(lldb::addr_t addr) { - if (BreakpointSiteSP bp = FindByAddress(addr)) - return bp.get()->GetID(); - return LLDB_INVALID_BREAK_ID; -} - -bool BreakpointSiteList::Remove(lldb::break_id_t break_id) { - std::lock_guard<std::recursive_mutex> guard(m_mutex); - collection::iterator pos = GetIDIterator(break_id); // Predicate - if (pos != m_bp_site_list.end()) { - m_bp_site_list.erase(pos); - return true; - } - return false; -} - -bool BreakpointSiteList::RemoveByAddress(lldb::addr_t address) { - std::lock_guard<std::recursive_mutex> guard(m_mutex); - collection::iterator pos = m_bp_site_list.find(address); - if (pos != m_bp_site_list.end()) { - m_bp_site_list.erase(pos); - return true; - } - return false; -} - -class BreakpointSiteIDMatches { -public: - BreakpointSiteIDMatches(lldb::break_id_t break_id) : m_break_id(break_id) {} - - bool operator()(std::pair<lldb::addr_t, BreakpointSiteSP> val_pair) const { - return m_break_id == val_pair.second->GetID(); - } - -private: - const lldb::break_id_t m_break_id; -}; - -BreakpointSiteList::collection::iterator -BreakpointSiteList::GetIDIterator(lldb::break_id_t break_id) { - std::lock_guard<std::recursive_mutex> guard(m_mutex); - return std::find_if(m_bp_site_list.begin(), - m_bp_site_list.end(), // Search full range - BreakpointSiteIDMatches(break_id)); // Predicate -} - -BreakpointSiteList::collection::const_iterator -BreakpointSiteList::GetIDConstIterator(lldb::break_id_t break_id) const { - std::lock_guard<std::recursive_mutex> guard(m_mutex); - return std::find_if(m_bp_site_list.begin(), - m_bp_site_list.end(), // Search full range - BreakpointSiteIDMatches(break_id)); // Predicate -} - -BreakpointSiteSP BreakpointSiteList::FindByID(lldb::break_id_t break_id) { - std::lock_guard<std::recursive_mutex> guard(m_mutex); - BreakpointSiteSP stop_sp; - collection::iterator pos = GetIDIterator(break_id); - if (pos != m_bp_site_list.end()) - stop_sp = pos->second; - - return stop_sp; -} - -const BreakpointSiteSP -BreakpointSiteList::FindByID(lldb::break_id_t break_id) const { - std::lock_guard<std::recursive_mutex> guard(m_mutex); - BreakpointSiteSP stop_sp; - collection::const_iterator pos = GetIDConstIterator(break_id); - if (pos != m_bp_site_list.end()) - stop_sp = pos->second; - - return stop_sp; -} - -BreakpointSiteSP BreakpointSiteList::FindByAddress(lldb::addr_t addr) { - BreakpointSiteSP found_sp; - std::lock_guard<std::recursive_mutex> guard(m_mutex); - collection::iterator iter = m_bp_site_list.find(addr); - if (iter != m_bp_site_list.end()) - found_sp = iter->second; - return found_sp; -} - -bool BreakpointSiteList::BreakpointSiteContainsBreakpoint( - lldb::break_id_t bp_site_id, lldb::break_id_t bp_id) { - std::lock_guard<std::recursive_mutex> guard(m_mutex); - collection::const_iterator pos = GetIDConstIterator(bp_site_id); - if (pos != m_bp_site_list.end()) - return pos->second->IsBreakpointAtThisSite(bp_id); - - return false; -} - -void BreakpointSiteList::Dump(Stream *s) const { - s->Printf("%p: ", static_cast<const void *>(this)); - // s->Indent(); - s->Printf("BreakpointSiteList with %u BreakpointSites:\n", - (uint32_t)m_bp_site_list.size()); - s->IndentMore(); - collection::const_iterator pos; - collection::const_iterator end = m_bp_site_list.end(); - for (pos = m_bp_site_list.begin(); pos != end; ++pos) - pos->second->Dump(s); - s->IndentLess(); -} - -void BreakpointSiteList::ForEach( - std::function<void(BreakpointSite *)> const &callback) { - std::lock_guard<std::recursive_mutex> guard(m_mutex); - for (auto pair : m_bp_site_list) - callback(pair.second.get()); -} - -bool BreakpointSiteList::FindInRange(lldb::addr_t lower_bound, - lldb::addr_t upper_bound, - BreakpointSiteList &bp_site_list) const { - if (lower_bound > upper_bound) - return false; - - std::lock_guard<std::recursive_mutex> guard(m_mutex); - collection::const_iterator lower, upper, pos; - lower = m_bp_site_list.lower_bound(lower_bound); - if (lower == m_bp_site_list.end() || (*lower).first >= upper_bound) - return false; - - // This is one tricky bit. The breakpoint might overlap the bottom end of - // the range. So we grab the breakpoint prior to the lower bound, and check - // that that + its byte size isn't in our range. - if (lower != m_bp_site_list.begin()) { - collection::const_iterator prev_pos = lower; - prev_pos--; - const BreakpointSiteSP &prev_bp = (*prev_pos).second; - if (prev_bp->GetLoadAddress() + prev_bp->GetByteSize() > lower_bound) - bp_site_list.Add(prev_bp); - } - - upper = m_bp_site_list.upper_bound(upper_bound); - - for (pos = lower; pos != upper; pos++) { - bp_site_list.Add((*pos).second); - } - return true; -} diff --git a/lldb/source/Breakpoint/CMakeLists.txt b/lldb/source/Breakpoint/CMakeLists.txt index 5c28023..42ac338 100644 --- a/lldb/source/Breakpoint/CMakeLists.txt +++ b/lldb/source/Breakpoint/CMakeLists.txt @@ -16,13 +16,15 @@ add_lldb_library(lldbBreakpoint NO_PLUGIN_DEPENDENCIES BreakpointResolverName.cpp BreakpointResolverScripted.cpp BreakpointSite.cpp - BreakpointSiteList.cpp Stoppoint.cpp StoppointCallbackContext.cpp StoppointSite.cpp + StopPointSiteList.cpp Watchpoint.cpp WatchpointList.cpp WatchpointOptions.cpp + WatchpointResource.cpp + WatchpointResourceList.cpp LINK_LIBS lldbCore diff --git a/lldb/source/Breakpoint/StopPointSiteList.cpp b/lldb/source/Breakpoint/StopPointSiteList.cpp new file mode 100644 index 0000000..275d0fb --- /dev/null +++ b/lldb/source/Breakpoint/StopPointSiteList.cpp @@ -0,0 +1,37 @@ +//===-- StopPointSiteList.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/Breakpoint/StopPointSiteList.h" +#include "lldb/Breakpoint/BreakpointSite.h" +#include "lldb/Breakpoint/WatchpointResource.h" + +#include "lldb/Utility/Stream.h" +#include <algorithm> + +using namespace lldb; +using namespace lldb_private; + +// This method is only defined when we're specializing for +// BreakpointSite / BreakpointLocation / Breakpoint. +// Watchpoints don't have a similar structure, they are +// WatchpointResource / Watchpoint + +template <> +bool StopPointSiteList<BreakpointSite>::StopPointSiteContainsBreakpoint( + typename BreakpointSite::SiteID site_id, lldb::break_id_t bp_id) { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + typename collection::const_iterator pos = GetIDConstIterator(site_id); + if (pos != m_site_list.end()) + return pos->second->IsBreakpointAtThisSite(bp_id); + + return false; +} + +namespace lldb_private { +template class StopPointSiteList<BreakpointSite>; +} // namespace lldb_private diff --git a/lldb/source/Breakpoint/Watchpoint.cpp b/lldb/source/Breakpoint/Watchpoint.cpp index b58455f..4602ce4 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" @@ -161,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, @@ -266,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, diff --git a/lldb/source/Breakpoint/WatchpointResource.cpp b/lldb/source/Breakpoint/WatchpointResource.cpp new file mode 100644 index 0000000..4b8fbe4 --- /dev/null +++ b/lldb/source/Breakpoint/WatchpointResource.cpp @@ -0,0 +1,122 @@ +//===-- WatchpointResource.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 <assert.h> + +#include "lldb/Breakpoint/WatchpointResource.h" + +using namespace lldb; +using namespace lldb_private; + +WatchpointResource::WatchpointResource(lldb::addr_t addr, size_t size, + bool read, bool write) + : m_id(GetNextID()), m_addr(addr), m_size(size), + m_watch_read(read), m_watch_write(write) {} + +WatchpointResource::~WatchpointResource() { + std::lock_guard<std::mutex> guard(m_constituents_mutex); + m_constituents.clear(); +} + +addr_t WatchpointResource::GetLoadAddress() const { return m_addr; } + +size_t WatchpointResource::GetByteSize() const { return m_size; } + +bool WatchpointResource::WatchpointResourceRead() const { return m_watch_read; } + +bool WatchpointResource::WatchpointResourceWrite() const { + return m_watch_write; +} + +void WatchpointResource::SetType(bool read, bool write) { + m_watch_read = read; + m_watch_write = write; +} + +wp_resource_id_t WatchpointResource::GetID() const { return m_id; } + +void WatchpointResource::SetID(wp_resource_id_t id) { m_id = id; } + +bool WatchpointResource::Contains(addr_t addr) { + if (addr >= m_addr && addr < m_addr + m_size) + return true; + return false; +} + +void WatchpointResource::AddConstituent(const WatchpointSP &wp_sp) { + std::lock_guard<std::mutex> guard(m_constituents_mutex); + m_constituents.push_back(wp_sp); +} + +void WatchpointResource::RemoveConstituent(WatchpointSP &wp_sp) { + std::lock_guard<std::mutex> guard(m_constituents_mutex); + const auto &it = + std::find(m_constituents.begin(), m_constituents.end(), wp_sp); + if (it != m_constituents.end()) + m_constituents.erase(it); +} + +size_t WatchpointResource::GetNumberOfConstituents() { + std::lock_guard<std::mutex> guard(m_constituents_mutex); + return m_constituents.size(); +} + +bool WatchpointResource::ConstituentsContains(const WatchpointSP &wp_sp) { + return ConstituentsContains(wp_sp.get()); +} + +bool WatchpointResource::ConstituentsContains(const Watchpoint *wp) { + std::lock_guard<std::mutex> guard(m_constituents_mutex); + WatchpointCollection::const_iterator match = + std::find_if(m_constituents.begin(), m_constituents.end(), + [&wp](const WatchpointSP &x) { return x.get() == wp; }); + return match != m_constituents.end(); +} + +WatchpointSP WatchpointResource::GetConstituentAtIndex(size_t idx) { + std::lock_guard<std::mutex> guard(m_constituents_mutex); + assert(idx < m_constituents.size()); + if (idx >= m_constituents.size()) + return {}; + + return m_constituents[idx]; +} + +WatchpointResource::WatchpointCollection +WatchpointResource::CopyConstituentsList() { + std::lock_guard<std::mutex> guard(m_constituents_mutex); + return m_constituents; +} + +bool WatchpointResource::ShouldStop(StoppointCallbackContext *context) { + // LWP_TODO: Need to poll all Watchpoint constituents and see if + // we should stop, like BreakpointSites do. +#if 0 + m_hit_counter.Increment(); + // ShouldStop can do a lot of work, and might even come back and hit + // this breakpoint site again. So don't hold the m_constituents_mutex the + // whole while. Instead make a local copy of the collection and call + // ShouldStop on the copy. + WatchpointResourceCollection constituents_copy; + { + std::lock_guard<std::recursive_mutex> guard(m_constituents_mutex); + constituents_copy = m_constituents; + } + return constituents_copy.ShouldStop(context); +#endif + return true; +} + +void WatchpointResource::Dump(Stream *s) const { + return; // LWP_TODO +} + +wp_resource_id_t WatchpointResource::GetNextID() { + static wp_resource_id_t g_next_id = 0; + return ++g_next_id; +} diff --git a/lldb/source/Breakpoint/WatchpointResourceList.cpp b/lldb/source/Breakpoint/WatchpointResourceList.cpp new file mode 100644 index 0000000..d1d3648 --- /dev/null +++ b/lldb/source/Breakpoint/WatchpointResourceList.cpp @@ -0,0 +1,114 @@ +//===-- WatchpointResourceList.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/Breakpoint/WatchpointResourceList.h" +#include "lldb/Breakpoint/WatchpointResource.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" + +using namespace lldb; +using namespace lldb_private; + +WatchpointResourceList::WatchpointResourceList() : m_resources(), m_mutex() {} + +WatchpointResourceList::~WatchpointResourceList() { Clear(); } + +wp_resource_id_t +WatchpointResourceList::Add(const WatchpointResourceSP &wp_res_sp) { + Log *log = GetLog(LLDBLog::Watchpoints); + std::lock_guard<std::mutex> guard(m_mutex); + LLDB_LOGF(log, "WatchpointResourceList::Add(addr 0x%" PRIx64 " size %zu)", + wp_res_sp->GetLoadAddress(), wp_res_sp->GetByteSize()); + + m_resources.push_back(wp_res_sp); + return wp_res_sp->GetID(); +} + +bool WatchpointResourceList::Remove(wp_resource_id_t id) { + std::lock_guard<std::mutex> guard(m_mutex); + Log *log = GetLog(LLDBLog::Watchpoints); + for (collection::iterator pos = m_resources.begin(); pos != m_resources.end(); + ++pos) { + if ((*pos)->GetID() == id) { + LLDB_LOGF(log, + "WatchpointResourceList::Remove(addr 0x%" PRIx64 " size %zu)", + (*pos)->GetLoadAddress(), (*pos)->GetByteSize()); + m_resources.erase(pos); + return true; + } + } + return false; +} + +bool WatchpointResourceList::RemoveByAddress(addr_t addr) { + std::lock_guard<std::mutex> guard(m_mutex); + Log *log = GetLog(LLDBLog::Watchpoints); + for (collection::iterator pos = m_resources.begin(); pos != m_resources.end(); + ++pos) { + if ((*pos)->Contains(addr)) { + LLDB_LOGF(log, + "WatchpointResourceList::RemoveByAddress(addr 0x%" PRIx64 + " size %zu)", + (*pos)->GetLoadAddress(), (*pos)->GetByteSize()); + m_resources.erase(pos); + return true; + } + } + return false; +} + +WatchpointResourceSP WatchpointResourceList::FindByAddress(addr_t addr) { + std::lock_guard<std::mutex> guard(m_mutex); + for (WatchpointResourceSP wp_res_sp : m_resources) + if (wp_res_sp->Contains(addr)) + return wp_res_sp; + return {}; +} + +WatchpointResourceSP +WatchpointResourceList::FindByWatchpointSP(WatchpointSP &wp_sp) { + return FindByWatchpoint(wp_sp.get()); +} + +WatchpointResourceSP +WatchpointResourceList::FindByWatchpoint(const Watchpoint *wp) { + std::lock_guard<std::mutex> guard(m_mutex); + for (WatchpointResourceSP wp_res_sp : m_resources) + if (wp_res_sp->ConstituentsContains(wp)) + return wp_res_sp; + return {}; +} + +WatchpointResourceSP WatchpointResourceList::FindByID(wp_resource_id_t id) { + std::lock_guard<std::mutex> guard(m_mutex); + for (WatchpointResourceSP wp_res_sp : m_resources) + if (wp_res_sp->GetID() == id) + return wp_res_sp; + return {}; +} + +uint32_t WatchpointResourceList::GetSize() { + std::lock_guard<std::mutex> guard(m_mutex); + return m_resources.size(); +} + +lldb::WatchpointResourceSP +WatchpointResourceList::GetResourceAtIndex(uint32_t idx) { + std::lock_guard<std::mutex> guard(m_mutex); + if (idx < m_resources.size()) + return m_resources[idx]; + + return {}; +} + +void WatchpointResourceList::Clear() { + std::lock_guard<std::mutex> guard(m_mutex); + m_resources.clear(); +} + +std::mutex &WatchpointResourceList::GetMutex() { return m_mutex; } diff --git a/lldb/source/Commands/CommandObjectProcess.cpp b/lldb/source/Commands/CommandObjectProcess.cpp index e42d637..6dc7648f 100644 --- a/lldb/source/Commands/CommandObjectProcess.cpp +++ b/lldb/source/Commands/CommandObjectProcess.cpp @@ -519,10 +519,10 @@ protected: BreakpointSiteSP bp_site_sp( process->GetBreakpointSiteList().FindByID(bp_site_id)); if (bp_site_sp) { - const size_t num_owners = bp_site_sp->GetNumberOfOwners(); + const size_t num_owners = bp_site_sp->GetNumberOfConstituents(); for (size_t i = 0; i < num_owners; i++) { Breakpoint &bp_ref = - bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint(); + bp_site_sp->GetConstituentAtIndex(i)->GetBreakpoint(); if (!bp_ref.IsInternal()) { bp_ref.SetIgnoreCount(m_options.m_ignore); } diff --git a/lldb/source/Commands/CommandObjectWatchpoint.cpp b/lldb/source/Commands/CommandObjectWatchpoint.cpp index cd1d226..c80868d 100644 --- a/lldb/source/Commands/CommandObjectWatchpoint.cpp +++ b/lldb/source/Commands/CommandObjectWatchpoint.cpp @@ -918,9 +918,9 @@ protected: if (addr_type == eAddressTypeLoad) { // We're in business. // Find out the size of this variable. - size = m_option_watchpoint.watch_size == 0 + size = m_option_watchpoint.watch_size.GetCurrentValue() == 0 ? valobj_sp->GetByteSize().value_or(0) - : m_option_watchpoint.watch_size; + : m_option_watchpoint.watch_size.GetCurrentValue(); } compiler_type = valobj_sp->GetCompilerType(); } else { @@ -1113,8 +1113,8 @@ protected: return; } - if (m_option_watchpoint.watch_size != 0) - size = m_option_watchpoint.watch_size; + if (m_option_watchpoint.watch_size.GetCurrentValue() != 0) + size = m_option_watchpoint.watch_size.GetCurrentValue(); else size = target->GetArchitecture().GetAddressByteSize(); diff --git a/lldb/source/Interpreter/OptionGroupWatchpoint.cpp b/lldb/source/Interpreter/OptionGroupWatchpoint.cpp index c3708e7..d1ae916 100644 --- a/lldb/source/Interpreter/OptionGroupWatchpoint.cpp +++ b/lldb/source/Interpreter/OptionGroupWatchpoint.cpp @@ -39,35 +39,12 @@ static constexpr OptionEnumValueElement g_watch_type[] = { }, }; -static constexpr OptionEnumValueElement g_watch_size[] = { - { - 1, - "1", - "Watch for byte size of 1", - }, - { - 2, - "2", - "Watch for byte size of 2", - }, - { - 4, - "4", - "Watch for byte size of 4", - }, - { - 8, - "8", - "Watch for byte size of 8", - }, -}; - static constexpr OptionDefinition g_option_table[] = { {LLDB_OPT_SET_1, false, "watch", 'w', OptionParser::eRequiredArgument, nullptr, OptionEnumValues(g_watch_type), 0, eArgTypeWatchType, "Specify the type of watching to perform."}, {LLDB_OPT_SET_1, false, "size", 's', OptionParser::eRequiredArgument, - nullptr, OptionEnumValues(g_watch_size), 0, eArgTypeByteSize, + nullptr, {}, 0, eArgTypeByteSize, "Number of bytes to use to watch a region."}, {LLDB_OPT_SET_2, false, @@ -80,16 +57,6 @@ static constexpr OptionDefinition g_option_table[] = { eArgTypeLanguage, "Language of expression to run"}}; -bool OptionGroupWatchpoint::IsWatchSizeSupported(uint32_t watch_size) { - for (const auto& size : g_watch_size) { - if (0 == size.value) - break; - if (watch_size == size.value) - return true; - } - return false; -} - Status OptionGroupWatchpoint::SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, @@ -120,8 +87,10 @@ OptionGroupWatchpoint::SetOptionValue(uint32_t option_idx, break; } case 's': - watch_size = (uint32_t)OptionArgParser::ToOptionEnum( - option_arg, g_option_table[option_idx].enum_values, 0, error); + error = watch_size.SetValueFromString(option_arg); + if (watch_size.GetCurrentValue() == 0) + error.SetErrorStringWithFormat("invalid --size option value '%s'", + option_arg.str().c_str()); break; default: @@ -135,7 +104,7 @@ void OptionGroupWatchpoint::OptionParsingStarting( ExecutionContext *execution_context) { watch_type_specified = false; watch_type = eWatchInvalid; - watch_size = 0; + watch_size.Clear(); language_type = eLanguageTypeUnknown; } diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp index 6c763ea..a5c9ead 100644 --- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp @@ -607,7 +607,7 @@ bool ItaniumABILanguageRuntime::ExceptionBreakpointsExplainStop( return false; uint64_t break_site_id = stop_reason->GetValue(); - return m_process->GetBreakpointSiteList().BreakpointSiteContainsBreakpoint( + return m_process->GetBreakpointSiteList().StopPointSiteContainsBreakpoint( break_site_id, m_cxx_exception_bp_sp->GetID()); } diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp index 80c7bd0..f08f9f0 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp @@ -445,7 +445,7 @@ bool AppleObjCRuntime::ExceptionBreakpointsExplainStop( return false; uint64_t break_site_id = stop_reason->GetValue(); - return m_process->GetBreakpointSiteList().BreakpointSiteContainsBreakpoint( + return m_process->GetBreakpointSiteList().StopPointSiteContainsBreakpoint( break_site_id, m_objc_exception_bp_sp->GetID()); } diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp index 547a1f6..4093cbd 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp @@ -333,7 +333,7 @@ AppleThreadPlanStepThroughDirectDispatch::DoPlanExplainsStop(Event *event_ptr) { if (site_sp->IsBreakpointAtThisSite(break_sp->GetID())) { // If we aren't the only one with a breakpoint on this site, then we // should just stop and return control to the user. - if (site_sp->GetNumberOfOwners() > 1) { + if (site_sp->GetNumberOfConstituents() > 1) { SetPlanComplete(true); return false; } diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp index ae36d3f..ca7ff5a 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp @@ -432,7 +432,7 @@ PlatformDarwin::GetSoftwareBreakpointTrapOpcode(Target &target, // Auto detect arm/thumb if it wasn't explicitly specified if (!bp_is_thumb) { - lldb::BreakpointLocationSP bp_loc_sp(bp_site->GetOwnerAtIndex(0)); + lldb::BreakpointLocationSP bp_loc_sp(bp_site->GetConstituentAtIndex(0)); if (bp_loc_sp) bp_is_thumb = bp_loc_sp->GetAddress().GetAddressClass() == AddressClass::eCodeAlternateISA; diff --git a/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp b/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp index e0956b4..70bb9aa 100644 --- a/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp +++ b/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp @@ -671,20 +671,6 @@ Status ProcessKDP::DisableBreakpointSite(BreakpointSite *bp_site) { return DisableSoftwareBreakpoint(bp_site); } -Status ProcessKDP::EnableWatchpoint(Watchpoint *wp, bool notify) { - Status error; - error.SetErrorString( - "watchpoints are not supported in kdp remote debugging"); - return error; -} - -Status ProcessKDP::DisableWatchpoint(Watchpoint *wp, bool notify) { - Status error; - error.SetErrorString( - "watchpoints are not supported in kdp remote debugging"); - return error; -} - void ProcessKDP::Clear() { m_thread_list.Clear(); } Status ProcessKDP::DoSignal(int signo) { diff --git a/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h b/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h index 3c12fd4..e5ec591 100644 --- a/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h +++ b/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h @@ -124,13 +124,6 @@ public: lldb_private::Status DisableBreakpointSite(lldb_private::BreakpointSite *bp_site) override; - // Process Watchpoints - lldb_private::Status EnableWatchpoint(lldb_private::Watchpoint *wp, - bool notify = true) override; - - lldb_private::Status DisableWatchpoint(lldb_private::Watchpoint *wp, - bool notify = true) override; - CommunicationKDP &GetCommunication() { return m_comm; } protected: diff --git a/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp b/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp index 5c947bb..565941d 100644 --- a/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp +++ b/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp @@ -491,6 +491,9 @@ static StopInfoSP GetStopInfoForHardwareBP(Thread &thread, Target *target, uint64_t exc_sub_sub_code) { // Try hardware watchpoint. if (target) { + // LWP_TODO: We need to find the WatchpointResource that matches + // the address, and evaluate its Watchpoints. + // The exc_sub_code indicates the data break address. lldb::WatchpointSP wp_sp = target->GetWatchpointList().FindByAddress((lldb::addr_t)exc_sub_code); @@ -666,6 +669,9 @@ StopInfoSP StopInfoMachException::CreateStopReasonWithMachException( case llvm::Triple::thumb: if (exc_code == 0x102) // EXC_ARM_DA_DEBUG { + // LWP_TODO: We need to find the WatchpointResource that matches + // the address, and evaluate its Watchpoints. + // It's a watchpoint, then, if the exc_sub_code indicates a // known/enabled data break address from our watchpoint list. lldb::WatchpointSP wp_sp; @@ -742,6 +748,9 @@ StopInfoSP StopInfoMachException::CreateStopReasonWithMachException( } if (exc_code == 0x102) // EXC_ARM_DA_DEBUG { + // LWP_TODO: We need to find the WatchpointResource that matches + // the address, and evaluate its Watchpoints. + // It's a watchpoint, then, if the exc_sub_code indicates a // known/enabled data break address from our watchpoint list. lldb::WatchpointSP wp_sp; diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp index 91b3216..eb0834b 100644 --- a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp @@ -835,11 +835,11 @@ std::optional<uint32_t> ProcessWindows::GetWatchpointSlotCount() { return RegisterContextWindows::GetNumHardwareBreakpointSlots(); } -Status ProcessWindows::EnableWatchpoint(Watchpoint *wp, bool notify) { +Status ProcessWindows::EnableWatchpoint(WatchpointSP wp_sp, bool notify) { Status error; - if (wp->IsEnabled()) { - wp->SetEnabled(true, notify); + if (wp_sp->IsEnabled()) { + wp_sp->SetEnabled(true, notify); return error; } @@ -851,13 +851,13 @@ Status ProcessWindows::EnableWatchpoint(Watchpoint *wp, bool notify) { break; if (info.slot_id == RegisterContextWindows::GetNumHardwareBreakpointSlots()) { error.SetErrorStringWithFormat("Can't find free slot for watchpoint %i", - wp->GetID()); + wp_sp->GetID()); return error; } - info.address = wp->GetLoadAddress(); - info.size = wp->GetByteSize(); - info.read = wp->WatchpointRead(); - info.write = wp->WatchpointWrite(); + info.address = wp_sp->GetLoadAddress(); + info.size = wp_sp->GetByteSize(); + info.read = wp_sp->WatchpointRead(); + info.write = wp_sp->WatchpointWrite(); for (unsigned i = 0U; i < m_thread_list.GetSize(); i++) { Thread *thread = m_thread_list.GetThreadAtIndex(i).get(); @@ -866,7 +866,7 @@ Status ProcessWindows::EnableWatchpoint(Watchpoint *wp, bool notify) { if (!reg_ctx->AddHardwareBreakpoint(info.slot_id, info.address, info.size, info.read, info.write)) { error.SetErrorStringWithFormat( - "Can't enable watchpoint %i on thread 0x%llx", wp->GetID(), + "Can't enable watchpoint %i on thread 0x%llx", wp_sp->GetID(), thread->GetID()); break; } @@ -881,26 +881,26 @@ Status ProcessWindows::EnableWatchpoint(Watchpoint *wp, bool notify) { return error; } - m_watchpoints[wp->GetID()] = info; - m_watchpoint_ids[info.slot_id] = wp->GetID(); + m_watchpoints[wp_sp->GetID()] = info; + m_watchpoint_ids[info.slot_id] = wp_sp->GetID(); - wp->SetEnabled(true, notify); + wp_sp->SetEnabled(true, notify); return error; } -Status ProcessWindows::DisableWatchpoint(Watchpoint *wp, bool notify) { +Status ProcessWindows::DisableWatchpoint(WatchpointSP wp_sp, bool notify) { Status error; - if (!wp->IsEnabled()) { - wp->SetEnabled(false, notify); + if (!wp_sp->IsEnabled()) { + wp_sp->SetEnabled(false, notify); return error; } - auto it = m_watchpoints.find(wp->GetID()); + auto it = m_watchpoints.find(wp_sp->GetID()); if (it == m_watchpoints.end()) { error.SetErrorStringWithFormat("Info about watchpoint %i is not found", - wp->GetID()); + wp_sp->GetID()); return error; } @@ -910,7 +910,7 @@ Status ProcessWindows::DisableWatchpoint(Watchpoint *wp, bool notify) { thread->GetRegisterContext().get()); if (!reg_ctx->RemoveHardwareBreakpoint(it->second.slot_id)) { error.SetErrorStringWithFormat( - "Can't disable watchpoint %i on thread 0x%llx", wp->GetID(), + "Can't disable watchpoint %i on thread 0x%llx", wp_sp->GetID(), thread->GetID()); break; } @@ -921,7 +921,7 @@ Status ProcessWindows::DisableWatchpoint(Watchpoint *wp, bool notify) { m_watchpoint_ids[it->second.slot_id] = LLDB_INVALID_BREAK_ID; m_watchpoints.erase(it); - wp->SetEnabled(false, notify); + wp_sp->SetEnabled(false, notify); return error; } diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h index ed083b9..e97cfb7 100644 --- a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h +++ b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h @@ -96,8 +96,10 @@ public: void OnDebuggerError(const Status &error, uint32_t type) override; std::optional<uint32_t> GetWatchpointSlotCount() override; - Status EnableWatchpoint(Watchpoint *wp, bool notify = true) override; - Status DisableWatchpoint(Watchpoint *wp, bool notify = true) override; + Status EnableWatchpoint(lldb::WatchpointSP wp_sp, + bool notify = true) override; + Status DisableWatchpoint(lldb::WatchpointSP wp_sp, + bool notify = true) override; protected: ProcessWindows(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp); diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 9648f1f..fb67151 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -24,6 +24,7 @@ #include <sys/types.h> #include "lldb/Breakpoint/Watchpoint.h" +#include "lldb/Breakpoint/WatchpointResource.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" @@ -1798,24 +1799,29 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo( addr_t wp_hit_addr = desc_extractor.GetU64(LLDB_INVALID_ADDRESS); watch_id_t watch_id = LLDB_INVALID_WATCH_ID; bool silently_continue = false; - WatchpointSP wp_sp; + WatchpointResourceSP wp_resource_sp; if (wp_hit_addr != LLDB_INVALID_ADDRESS) { - wp_sp = GetTarget().GetWatchpointList().FindByAddress(wp_hit_addr); + wp_resource_sp = + m_watchpoint_resource_list.FindByAddress(wp_hit_addr); // On MIPS, \a wp_hit_addr outside the range of a watched // region means we should silently continue, it is a false hit. ArchSpec::Core core = GetTarget().GetArchitecture().GetCore(); - if (!wp_sp && core >= ArchSpec::kCore_mips_first && + if (!wp_resource_sp && core >= ArchSpec::kCore_mips_first && core <= ArchSpec::kCore_mips_last) silently_continue = true; } - if (!wp_sp && wp_addr != LLDB_INVALID_ADDRESS) - wp_sp = GetTarget().GetWatchpointList().FindByAddress(wp_addr); - if (wp_sp) { - watch_id = wp_sp->GetID(); - } - if (watch_id == LLDB_INVALID_WATCH_ID) { + if (!wp_resource_sp && wp_addr != LLDB_INVALID_ADDRESS) + wp_resource_sp = m_watchpoint_resource_list.FindByAddress(wp_addr); + if (!wp_resource_sp) { Log *log(GetLog(GDBRLog::Watchpoints)); LLDB_LOGF(log, "failed to find watchpoint"); + watch_id = LLDB_INVALID_SITE_ID; + } else { + // LWP_TODO: This is hardcoding a single Watchpoint in a + // Resource, need to add + // StopInfo::CreateStopReasonWithWatchpointResource which + // represents all watchpoints that were tripped at this stop. + watch_id = wp_resource_sp->GetConstituentAtIndex(0)->GetID(); } thread_sp->SetStopInfo(StopInfo::CreateStopReasonWithWatchpointID( *thread_sp, watch_id, silently_continue)); @@ -2239,8 +2245,8 @@ StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) { lldb::addr_t wp_addr = LLDB_INVALID_ADDRESS; value.getAsInteger(16, wp_addr); - WatchpointSP wp_sp = - GetTarget().GetWatchpointList().FindByAddress(wp_addr); + WatchpointResourceSP wp_resource_sp = + m_watchpoint_resource_list.FindByAddress(wp_addr); // Rewrite gdb standard watch/rwatch/awatch to // "reason:watchpoint" + "description:ADDR", @@ -3109,102 +3115,182 @@ Status ProcessGDBRemote::DisableBreakpointSite(BreakpointSite *bp_site) { } // Pre-requisite: wp != NULL. -static GDBStoppointType GetGDBStoppointType(Watchpoint *wp) { - assert(wp); - bool watch_read = wp->WatchpointRead(); - bool watch_write = wp->WatchpointWrite(); - bool watch_modify = wp->WatchpointModify(); - - // 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)) +static GDBStoppointType +GetGDBStoppointType(const WatchpointResourceSP &wp_res_sp) { + assert(wp_res_sp); + bool read = wp_res_sp->WatchpointResourceRead(); + bool write = wp_res_sp->WatchpointResourceWrite(); + + assert((read || write) && + "WatchpointResource type is neither read nor write"); + if (read && write) return eWatchpointReadWrite; - else if (watch_read) + else if (read) return eWatchpointRead; - else // Must be watch_write or watch_modify, then. + else return eWatchpointWrite; } -Status ProcessGDBRemote::EnableWatchpoint(Watchpoint *wp, bool notify) { +Status ProcessGDBRemote::EnableWatchpoint(WatchpointSP wp_sp, bool notify) { Status error; - if (wp) { - user_id_t watchID = wp->GetID(); - addr_t addr = wp->GetLoadAddress(); - Log *log(GetLog(GDBRLog::Watchpoints)); - LLDB_LOGF(log, "ProcessGDBRemote::EnableWatchpoint(watchID = %" PRIu64 ")", - watchID); - if (wp->IsEnabled()) { - LLDB_LOGF(log, - "ProcessGDBRemote::EnableWatchpoint(watchID = %" PRIu64 - ") addr = 0x%8.8" PRIx64 ": watchpoint already enabled.", - watchID, (uint64_t)addr); - return error; - } + if (!wp_sp) { + error.SetErrorString("No watchpoint specified"); + return error; + } + user_id_t watchID = wp_sp->GetID(); + addr_t addr = wp_sp->GetLoadAddress(); + Log *log(GetLog(GDBRLog::Watchpoints)); + LLDB_LOGF(log, "ProcessGDBRemote::EnableWatchpoint(watchID = %" PRIu64 ")", + watchID); + if (wp_sp->IsEnabled()) { + LLDB_LOGF(log, + "ProcessGDBRemote::EnableWatchpoint(watchID = %" PRIu64 + ") addr = 0x%8.8" PRIx64 ": watchpoint already enabled.", + watchID, (uint64_t)addr); + return error; + } - GDBStoppointType type = GetGDBStoppointType(wp); - // Pass down an appropriate z/Z packet... - if (m_gdb_comm.SupportsGDBStoppointPacket(type)) { - if (m_gdb_comm.SendGDBStoppointTypePacket(type, true, addr, - wp->GetByteSize(), - GetInterruptTimeout()) == 0) { - wp->SetEnabled(true, notify); - return error; - } else - error.SetErrorString("sending gdb watchpoint packet failed"); - } else - error.SetErrorString("watchpoints not supported"); + bool read = wp_sp->WatchpointRead(); + bool write = wp_sp->WatchpointWrite() || wp_sp->WatchpointModify(); + size_t size = wp_sp->GetByteSize(); + + // New WatchpointResources needed to implement this Watchpoint. + std::vector<WatchpointResourceSP> resources; + + // LWP_TODO: Break up the user's request into pieces that can be watched + // given the capabilities of the target cpu / stub software. + // As a default, breaking the watched region up into target-pointer-sized, + // aligned, groups. + // + // Beyond the default, a stub can / should inform us of its capabilities, + // e.g. a stub that can do AArch64 power-of-2 MASK watchpoints. + // + // And the cpu may have unique capabilities. AArch64 BAS watchpoints + // can watch any sequential bytes in a doubleword, but Intel watchpoints + // can only watch 1, 2, 4, 8 bytes within a doubleword. + WatchpointResourceSP wp_res_sp = + std::make_shared<WatchpointResource>(addr, size, read, write); + resources.push_back(wp_res_sp); + + // LWP_TODO: Now that we know the WP Resources needed to implement this + // Watchpoint, we need to look at currently allocated Resources in the + // Process and if they match, or are within the same memory granule, or + // overlapping memory ranges, then we need to combine them. e.g. one + // Watchpoint watching 1 byte at 0x1002 and a second watchpoint watching 1 + // byte at 0x1003, they must use the same hardware watchpoint register + // (Resource) to watch them. + + // This may mean that an existing resource changes its type (read to + // read+write) or address range it is watching, in which case the old + // watchpoint needs to be disabled and the new Resource addr/size/type + // watchpoint enabled. + + // If we modify a shared Resource to accomodate this newly added Watchpoint, + // and we are unable to set all of the Resources for it in the inferior, we + // will return an error for this Watchpoint and the shared Resource should + // be restored. e.g. this Watchpoint requires three Resources, one which + // is shared with another Watchpoint. We extend the shared Resouce to + // handle both Watchpoints and we try to set two new ones. But if we don't + // have sufficient watchpoint register for all 3, we need to show an error + // for creating this Watchpoint and we should reset the shared Resource to + // its original configuration because it is no longer shared. + + bool set_all_resources = true; + std::vector<WatchpointResourceSP> succesfully_set_resources; + for (const auto &wp_res_sp : resources) { + addr_t addr = wp_res_sp->GetLoadAddress(); + size_t size = wp_res_sp->GetByteSize(); + GDBStoppointType type = GetGDBStoppointType(wp_res_sp); + if (!m_gdb_comm.SupportsGDBStoppointPacket(type) || + m_gdb_comm.SendGDBStoppointTypePacket(type, true, addr, size, + GetInterruptTimeout())) { + set_all_resources = false; + break; + } else { + succesfully_set_resources.push_back(wp_res_sp); + } + } + if (set_all_resources) { + wp_sp->SetEnabled(true, notify); + for (const auto &wp_res_sp : resources) { + // LWP_TODO: If we expanded/reused an existing Resource, + // it's already in the WatchpointResourceList. + wp_res_sp->AddConstituent(wp_sp); + m_watchpoint_resource_list.Add(wp_res_sp); + } + return error; } else { - error.SetErrorString("Watchpoint argument was NULL."); + // We failed to allocate one of the resources. Unset all + // of the new resources we did successfully set in the + // process. + for (const auto &wp_res_sp : succesfully_set_resources) { + addr_t addr = wp_res_sp->GetLoadAddress(); + size_t size = wp_res_sp->GetByteSize(); + GDBStoppointType type = GetGDBStoppointType(wp_res_sp); + m_gdb_comm.SendGDBStoppointTypePacket(type, false, addr, size, + GetInterruptTimeout()); + } + error.SetErrorString("Setting one of the watchpoint resources failed"); } - if (error.Success()) - error.SetErrorToGenericError(); return error; } -Status ProcessGDBRemote::DisableWatchpoint(Watchpoint *wp, bool notify) { +Status ProcessGDBRemote::DisableWatchpoint(WatchpointSP wp_sp, bool notify) { Status error; - if (wp) { - user_id_t watchID = wp->GetID(); + if (!wp_sp) { + error.SetErrorString("Watchpoint argument was NULL."); + return error; + } + + user_id_t watchID = wp_sp->GetID(); - Log *log(GetLog(GDBRLog::Watchpoints)); + Log *log(GetLog(GDBRLog::Watchpoints)); - addr_t addr = wp->GetLoadAddress(); + addr_t addr = wp_sp->GetLoadAddress(); + + LLDB_LOGF(log, + "ProcessGDBRemote::DisableWatchpoint (watchID = %" PRIu64 + ") addr = 0x%8.8" PRIx64, + watchID, (uint64_t)addr); + if (!wp_sp->IsEnabled()) { LLDB_LOGF(log, "ProcessGDBRemote::DisableWatchpoint (watchID = %" PRIu64 - ") addr = 0x%8.8" PRIx64, + ") addr = 0x%8.8" PRIx64 " -- SUCCESS (already disabled)", watchID, (uint64_t)addr); + // See also 'class WatchpointSentry' within StopInfo.cpp. This disabling + // attempt might come from the user-supplied actions, we'll route it in + // order for the watchpoint object to intelligently process this action. + wp_sp->SetEnabled(false, notify); + return error; + } - if (!wp->IsEnabled()) { - LLDB_LOGF(log, - "ProcessGDBRemote::DisableWatchpoint (watchID = %" PRIu64 - ") addr = 0x%8.8" PRIx64 " -- SUCCESS (already disabled)", - watchID, (uint64_t)addr); - // See also 'class WatchpointSentry' within StopInfo.cpp. This disabling - // attempt might come from the user-supplied actions, we'll route it in - // order for the watchpoint object to intelligently process this action. - wp->SetEnabled(false, notify); - return error; - } + if (wp_sp->IsHardware()) { + bool disabled_all = true; - if (wp->IsHardware()) { - GDBStoppointType type = GetGDBStoppointType(wp); - // Pass down an appropriate z/Z packet... - if (m_gdb_comm.SendGDBStoppointTypePacket(type, false, addr, - wp->GetByteSize(), - GetInterruptTimeout()) == 0) { - wp->SetEnabled(false, notify); - return error; - } else - error.SetErrorString("sending gdb watchpoint packet failed"); + std::vector<WatchpointResourceSP> unused_resources; + for (const auto &wp_res_sp : m_watchpoint_resource_list.Sites()) { + if (wp_res_sp->ConstituentsContains(wp_sp)) { + GDBStoppointType type = GetGDBStoppointType(wp_res_sp); + addr_t addr = wp_res_sp->GetLoadAddress(); + size_t size = wp_res_sp->GetByteSize(); + if (m_gdb_comm.SendGDBStoppointTypePacket(type, false, addr, size, + GetInterruptTimeout())) { + disabled_all = false; + } else { + wp_res_sp->RemoveConstituent(wp_sp); + if (wp_res_sp->GetNumberOfConstituents() == 0) + unused_resources.push_back(wp_res_sp); + } + } } - // TODO: clear software watchpoints if we implement them - } else { - error.SetErrorString("Watchpoint argument was NULL."); + for (auto &wp_res_sp : unused_resources) + m_watchpoint_resource_list.Remove(wp_res_sp->GetID()); + + wp_sp->SetEnabled(false, notify); + if (!disabled_all) + error.SetErrorString("Failure disabling one of the watchpoint locations"); } - if (error.Success()) - error.SetErrorToGenericError(); return error; } @@ -5456,16 +5542,12 @@ void ProcessGDBRemote::DidForkSwitchHardwareTraps(bool enable) { }); } - WatchpointList &wps = GetTarget().GetWatchpointList(); - size_t wp_count = wps.GetSize(); - for (size_t i = 0; i < wp_count; ++i) { - WatchpointSP wp = wps.GetByIndex(i); - if (wp->IsEnabled()) { - GDBStoppointType type = GetGDBStoppointType(wp.get()); - m_gdb_comm.SendGDBStoppointTypePacket(type, enable, wp->GetLoadAddress(), - wp->GetByteSize(), - GetInterruptTimeout()); - } + for (const auto &wp_res_sp : m_watchpoint_resource_list.Sites()) { + addr_t addr = wp_res_sp->GetLoadAddress(); + size_t size = wp_res_sp->GetByteSize(); + GDBStoppointType type = GetGDBStoppointType(wp_res_sp); + m_gdb_comm.SendGDBStoppointTypePacket(type, true, addr, size, + GetInterruptTimeout()); } } diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index f3787e7..c1ea1cc 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -158,9 +158,11 @@ public: Status DisableBreakpointSite(BreakpointSite *bp_site) override; // Process Watchpoints - Status EnableWatchpoint(Watchpoint *wp, bool notify = true) override; + Status EnableWatchpoint(lldb::WatchpointSP wp_sp, + bool notify = true) override; - Status DisableWatchpoint(Watchpoint *wp, bool notify = true) override; + Status DisableWatchpoint(lldb::WatchpointSP wp_sp, + bool notify = true) override; std::optional<uint32_t> GetWatchpointSlotCount() override; diff --git a/lldb/source/Target/Platform.cpp b/lldb/source/Target/Platform.cpp index c345e33..4ce290d 100644 --- a/lldb/source/Target/Platform.cpp +++ b/lldb/source/Target/Platform.cpp @@ -2014,7 +2014,7 @@ size_t Platform::GetSoftwareBreakpointTrapOpcode(Target &target, static const uint8_t g_arm_breakpoint_opcode[] = {0xf0, 0x01, 0xf0, 0xe7}; static const uint8_t g_thumb_breakpoint_opcode[] = {0x01, 0xde}; - lldb::BreakpointLocationSP bp_loc_sp(bp_site->GetOwnerAtIndex(0)); + lldb::BreakpointLocationSP bp_loc_sp(bp_site->GetConstituentAtIndex(0)); AddressClass addr_class = AddressClass::eUnknown; if (bp_loc_sp) { diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index f3da283..2d77144 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -436,7 +436,7 @@ Process::Process(lldb::TargetSP target_sp, ListenerSP listener_sp, m_exit_status_mutex(), m_thread_mutex(), m_thread_list_real(this), m_thread_list(this), m_thread_plans(*this), m_extended_thread_list(this), m_extended_thread_stop_id(0), m_queue_list(this), m_queue_list_stop_id(0), - m_notifications(), m_image_tokens(), + m_watchpoint_resource_list(), m_notifications(), m_image_tokens(), m_breakpoint_site_list(), m_dynamic_checkers_up(), m_unix_signals_sp(unix_signals_sp), m_abi_sp(), m_process_input_reader(), m_stdio_communication("process.stdio"), m_stdio_communication_mutex(), @@ -547,6 +547,7 @@ void Process::Finalize() { m_extended_thread_list.Destroy(); m_queue_list.Clear(); m_queue_list_stop_id = 0; + m_watchpoint_resource_list.Clear(); std::vector<Notifications> empty_notifications; m_notifications.swap(empty_notifications); m_image_tokens.clear(); @@ -1563,11 +1564,12 @@ void Process::SetDynamicCheckers(DynamicCheckerFunctions *dynamic_checkers) { m_dynamic_checkers_up.reset(dynamic_checkers); } -BreakpointSiteList &Process::GetBreakpointSiteList() { +StopPointSiteList<BreakpointSite> &Process::GetBreakpointSiteList() { return m_breakpoint_site_list; } -const BreakpointSiteList &Process::GetBreakpointSiteList() const { +const StopPointSiteList<BreakpointSite> & +Process::GetBreakpointSiteList() const { return m_breakpoint_site_list; } @@ -1615,7 +1617,7 @@ Status Process::EnableBreakpointSiteByID(lldb::user_id_t break_id) { } lldb::break_id_t -Process::CreateBreakpointSite(const BreakpointLocationSP &owner, +Process::CreateBreakpointSite(const BreakpointLocationSP &constituent, bool use_hardware) { addr_t load_addr = LLDB_INVALID_ADDRESS; @@ -1642,10 +1644,10 @@ Process::CreateBreakpointSite(const BreakpointLocationSP &owner, // Reset the IsIndirect flag here, in case the location changes from pointing // to a indirect symbol to a regular symbol. - owner->SetIsIndirect(false); + constituent->SetIsIndirect(false); - if (owner->ShouldResolveIndirectFunctions()) { - Symbol *symbol = owner->GetAddress().CalculateSymbolContextSymbol(); + if (constituent->ShouldResolveIndirectFunctions()) { + Symbol *symbol = constituent->GetAddress().CalculateSymbolContextSymbol(); if (symbol && symbol->IsIndirect()) { Status error; Address symbol_address = symbol->GetAddress(); @@ -1655,37 +1657,37 @@ Process::CreateBreakpointSite(const BreakpointLocationSP &owner, "warning: failed to resolve indirect function at 0x%" PRIx64 " for breakpoint %i.%i: %s\n", symbol->GetLoadAddress(&GetTarget()), - owner->GetBreakpoint().GetID(), owner->GetID(), + constituent->GetBreakpoint().GetID(), constituent->GetID(), error.AsCString() ? error.AsCString() : "unknown error"); return LLDB_INVALID_BREAK_ID; } Address resolved_address(load_addr); load_addr = resolved_address.GetOpcodeLoadAddress(&GetTarget()); - owner->SetIsIndirect(true); + constituent->SetIsIndirect(true); } else - load_addr = owner->GetAddress().GetOpcodeLoadAddress(&GetTarget()); + load_addr = constituent->GetAddress().GetOpcodeLoadAddress(&GetTarget()); } else - load_addr = owner->GetAddress().GetOpcodeLoadAddress(&GetTarget()); + load_addr = constituent->GetAddress().GetOpcodeLoadAddress(&GetTarget()); if (load_addr != LLDB_INVALID_ADDRESS) { BreakpointSiteSP bp_site_sp; - // Look up this breakpoint site. If it exists, then add this new owner, - // otherwise create a new breakpoint site and add it. + // Look up this breakpoint site. If it exists, then add this new + // constituent, otherwise create a new breakpoint site and add it. bp_site_sp = m_breakpoint_site_list.FindByAddress(load_addr); if (bp_site_sp) { - bp_site_sp->AddOwner(owner); - owner->SetBreakpointSite(bp_site_sp); + bp_site_sp->AddConstituent(constituent); + constituent->SetBreakpointSite(bp_site_sp); return bp_site_sp->GetID(); } else { - bp_site_sp.reset(new BreakpointSite(&m_breakpoint_site_list, owner, - load_addr, use_hardware)); + bp_site_sp.reset( + new BreakpointSite(constituent, load_addr, use_hardware)); if (bp_site_sp) { Status error = EnableBreakpointSite(bp_site_sp.get()); if (error.Success()) { - owner->SetBreakpointSite(bp_site_sp); + constituent->SetBreakpointSite(bp_site_sp); return m_breakpoint_site_list.Add(bp_site_sp); } else { if (show_error || use_hardware) { @@ -1693,7 +1695,8 @@ Process::CreateBreakpointSite(const BreakpointLocationSP &owner, GetTarget().GetDebugger().GetErrorStream().Printf( "warning: failed to set breakpoint site at 0x%" PRIx64 " for breakpoint %i.%i: %s\n", - load_addr, owner->GetBreakpoint().GetID(), owner->GetID(), + load_addr, constituent->GetBreakpoint().GetID(), + constituent->GetID(), error.AsCString() ? error.AsCString() : "unknown error"); } } @@ -1704,11 +1707,12 @@ Process::CreateBreakpointSite(const BreakpointLocationSP &owner, return LLDB_INVALID_BREAK_ID; } -void Process::RemoveOwnerFromBreakpointSite(lldb::user_id_t owner_id, - lldb::user_id_t owner_loc_id, - BreakpointSiteSP &bp_site_sp) { - uint32_t num_owners = bp_site_sp->RemoveOwner(owner_id, owner_loc_id); - if (num_owners == 0) { +void Process::RemoveConstituentFromBreakpointSite( + lldb::user_id_t constituent_id, lldb::user_id_t constituent_loc_id, + BreakpointSiteSP &bp_site_sp) { + uint32_t num_constituents = + bp_site_sp->RemoveConstituent(constituent_id, constituent_loc_id); + if (num_constituents == 0) { // Don't try to disable the site if we don't have a live process anymore. if (IsAlive()) DisableBreakpointSite(bp_site_sp.get()); @@ -1719,7 +1723,7 @@ void Process::RemoveOwnerFromBreakpointSite(lldb::user_id_t owner_id, size_t Process::RemoveBreakpointOpcodesFromBuffer(addr_t bp_addr, size_t size, uint8_t *buf) const { size_t bytes_removed = 0; - BreakpointSiteList bp_sites_in_range; + StopPointSiteList<BreakpointSite> bp_sites_in_range; if (m_breakpoint_site_list.FindInRange(bp_addr, bp_addr + size, bp_sites_in_range)) { @@ -2140,7 +2144,7 @@ size_t Process::WriteMemory(addr_t addr, const void *buf, size_t size, // (enabled software breakpoints) any software traps (breakpoints) that we // may have placed in our tasks memory. - BreakpointSiteList bp_sites_in_range; + StopPointSiteList<BreakpointSite> bp_sites_in_range; if (!m_breakpoint_site_list.FindInRange(addr, addr + size, bp_sites_in_range)) return WriteMemoryPrivate(addr, buf, size, error); @@ -2408,13 +2412,13 @@ bool Process::GetLoadAddressPermissions(lldb::addr_t load_addr, return true; } -Status Process::EnableWatchpoint(Watchpoint *watchpoint, bool notify) { +Status Process::EnableWatchpoint(WatchpointSP wp_sp, bool notify) { Status error; error.SetErrorString("watchpoints are not supported"); return error; } -Status Process::DisableWatchpoint(Watchpoint *watchpoint, bool notify) { +Status Process::DisableWatchpoint(WatchpointSP wp_sp, bool notify) { Status error; error.SetErrorString("watchpoints are not supported"); return error; diff --git a/lldb/source/Target/StackFrameList.cpp b/lldb/source/Target/StackFrameList.cpp index 88cc518..2273e52 100644 --- a/lldb/source/Target/StackFrameList.cpp +++ b/lldb/source/Target/StackFrameList.cpp @@ -156,9 +156,10 @@ void StackFrameList::ResetCurrentInlinedDepth() { m_thread.GetProcess()->GetBreakpointSiteList().FindByID(bp_site_id)); bool all_internal = true; if (bp_site_sp) { - uint32_t num_owners = bp_site_sp->GetNumberOfOwners(); + uint32_t num_owners = bp_site_sp->GetNumberOfConstituents(); for (uint32_t i = 0; i < num_owners; i++) { - Breakpoint &bp_ref = bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint(); + Breakpoint &bp_ref = + bp_site_sp->GetConstituentAtIndex(i)->GetBreakpoint(); if (!bp_ref.IsInternal()) { all_internal = false; } diff --git a/lldb/source/Target/StopInfo.cpp b/lldb/source/Target/StopInfo.cpp index 0b85845..3b65d66 100644 --- a/lldb/source/Target/StopInfo.cpp +++ b/lldb/source/Target/StopInfo.cpp @@ -12,6 +12,7 @@ #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Breakpoint/StoppointCallbackContext.h" #include "lldb/Breakpoint/Watchpoint.h" +#include "lldb/Breakpoint/WatchpointResource.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/ValueObject.h" #include "lldb/Expression/UserExpression.h" @@ -109,9 +110,9 @@ public: BreakpointSiteSP bp_site_sp( thread_sp->GetProcess()->GetBreakpointSiteList().FindByID(m_value)); if (bp_site_sp) { - uint32_t num_owners = bp_site_sp->GetNumberOfOwners(); - if (num_owners == 1) { - BreakpointLocationSP bp_loc_sp = bp_site_sp->GetOwnerAtIndex(0); + uint32_t num_constituents = bp_site_sp->GetNumberOfConstituents(); + if (num_constituents == 1) { + BreakpointLocationSP bp_loc_sp = bp_site_sp->GetConstituentAtIndex(0); if (bp_loc_sp) { Breakpoint & bkpt = bp_loc_sp->GetBreakpoint(); m_break_id = bkpt.GetID(); @@ -120,8 +121,10 @@ public: } } else { m_was_all_internal = true; - for (uint32_t i = 0; i < num_owners; i++) { - if (!bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint().IsInternal()) { + for (uint32_t i = 0; i < num_constituents; i++) { + if (!bp_site_sp->GetConstituentAtIndex(i) + ->GetBreakpoint() + .IsInternal()) { m_was_all_internal = false; break; } @@ -189,9 +192,9 @@ public: // If we have just hit an internal breakpoint, and it has a kind // description, print that instead of the full breakpoint printing: if (bp_site_sp->IsInternal()) { - size_t num_owners = bp_site_sp->GetNumberOfOwners(); - for (size_t idx = 0; idx < num_owners; idx++) { - const char *kind = bp_site_sp->GetOwnerAtIndex(idx) + size_t num_constituents = bp_site_sp->GetNumberOfConstituents(); + for (size_t idx = 0; idx < num_constituents; idx++) { + const char *kind = bp_site_sp->GetConstituentAtIndex(idx) ->GetBreakpoint() .GetBreakpointKind(); if (kind != nullptr) { @@ -284,13 +287,14 @@ protected: // Use this variable to tell us if that is true. bool actually_hit_any_locations = false; if (bp_site_sp) { - // Let's copy the owners list out of the site and store them in a local - // list. That way if one of the breakpoint actions changes the site, - // then we won't be operating on a bad list. + // Let's copy the constituents list out of the site and store them in a + // local list. That way if one of the breakpoint actions changes the + // site, then we won't be operating on a bad list. BreakpointLocationCollection site_locations; - size_t num_owners = bp_site_sp->CopyOwnersList(site_locations); + size_t num_constituents = + bp_site_sp->CopyConstituentsList(site_locations); - if (num_owners == 0) { + if (num_constituents == 0) { m_should_stop = true; actually_hit_any_locations = true; // We're going to stop, don't // change the stop info. @@ -382,20 +386,21 @@ protected: StoppointCallbackContext context(event_ptr, exe_ctx, false); // For safety's sake let's also grab an extra reference to the - // breakpoint owners of the locations we're going to examine, since - // the locations are going to have to get back to their breakpoints, - // and the locations don't keep their owners alive. I'm just - // sticking the BreakpointSP's in a vector since I'm only using it to - // locally increment their retain counts. + // breakpoint constituents of the locations we're going to examine, + // since the locations are going to have to get back to their + // breakpoints, and the locations don't keep their constituents alive. + // I'm just sticking the BreakpointSP's in a vector since I'm only + // using it to locally increment their retain counts. - std::vector<lldb::BreakpointSP> location_owners; + std::vector<lldb::BreakpointSP> location_constituents; - for (size_t j = 0; j < num_owners; j++) { + for (size_t j = 0; j < num_constituents; j++) { BreakpointLocationSP loc(site_locations.GetByIndex(j)); - location_owners.push_back(loc->GetBreakpoint().shared_from_this()); + location_constituents.push_back( + loc->GetBreakpoint().shared_from_this()); } - for (size_t j = 0; j < num_owners; j++) { + for (size_t j = 0; j < num_constituents; j++) { lldb::BreakpointLocationSP bp_loc_sp = site_locations.GetByIndex(j); StreamString loc_desc; if (log) { @@ -631,7 +636,7 @@ public: if (process_sp && watchpoint_sp) { const bool notify = false; watchpoint_sp->TurnOnEphemeralMode(); - process_sp->DisableWatchpoint(watchpoint_sp.get(), notify); + process_sp->DisableWatchpoint(watchpoint_sp, notify); process_sp->AddPreResumeAction(SentryPreResumeAction, this); } } @@ -642,9 +647,9 @@ public: watchpoint_sp->TurnOffEphemeralMode(); const bool notify = false; if (was_disabled) { - process_sp->DisableWatchpoint(watchpoint_sp.get(), notify); + process_sp->DisableWatchpoint(watchpoint_sp, notify); } else { - process_sp->EnableWatchpoint(watchpoint_sp.get(), notify); + process_sp->EnableWatchpoint(watchpoint_sp, notify); } } } @@ -707,7 +712,7 @@ protected: return true; if (!m_did_disable_wp) { - GetThread().GetProcess()->DisableWatchpoint(m_watch_sp.get(), false); + GetThread().GetProcess()->DisableWatchpoint(m_watch_sp, false); m_did_disable_wp = true; } return true; @@ -751,7 +756,7 @@ protected: if (!m_did_disable_wp) return; m_did_disable_wp = true; - GetThread().GetProcess()->EnableWatchpoint(m_watch_sp.get(), true); + GetThread().GetProcess()->EnableWatchpoint(m_watch_sp, true); } private: @@ -991,9 +996,10 @@ protected: Debugger &debugger = exe_ctx.GetTargetRef().GetDebugger(); StreamSP output_sp = debugger.GetAsyncOutputStream(); - wp_sp->DumpSnapshots(output_sp.get()); - output_sp->EOL(); - output_sp->Flush(); + if (wp_sp->DumpSnapshots(output_sp.get())) { + output_sp->EOL(); + output_sp->Flush(); + } } } else { @@ -1366,6 +1372,8 @@ StopInfoSP StopInfo::CreateStopReasonWithBreakpointSiteID(Thread &thread, return StopInfoSP(new StopInfoBreakpoint(thread, break_id, should_stop)); } +// LWP_TODO: We'll need a CreateStopReasonWithWatchpointResourceID akin +// to CreateStopReasonWithBreakpointSiteID StopInfoSP StopInfo::CreateStopReasonWithWatchpointID(Thread &thread, break_id_t watch_id, bool silently_continue) { diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index a6d7148..2e8d1df 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -892,6 +892,18 @@ WatchpointSP Target::CreateWatchpoint(lldb::addr_t addr, size_t size, if (ABISP abi = m_process_sp->GetABI()) addr = abi->FixDataAddress(addr); + // LWP_TODO this sequence is looking for an existing watchpoint + // at the exact same user-specified address, disables the new one + // if addr/size/type match. If type/size differ, disable old one. + // This isn't correct, we need both watchpoints to use a shared + // WatchpointResource in the target, and expand the WatchpointResource + // to handle the needs of both Watchpoints. + // Also, even if the addresses don't match, they may need to be + // supported by the same WatchpointResource, e.g. a watchpoint + // watching 1 byte at 0x102 and a watchpoint watching 1 byte at 0x103. + // They're in the same word and must be watched by a single hardware + // watchpoint register. + std::unique_lock<std::recursive_mutex> lock; this->GetWatchpointList().GetListMutex(lock); WatchpointSP matched_sp = m_watchpoint_list.FindByAddress(addr); @@ -907,7 +919,7 @@ WatchpointSP Target::CreateWatchpoint(lldb::addr_t addr, size_t size, wp_sp->SetEnabled(false, notify); } else { // Nil the matched watchpoint; we will be creating a new one. - m_process_sp->DisableWatchpoint(matched_sp.get(), notify); + m_process_sp->DisableWatchpoint(matched_sp, notify); m_watchpoint_list.Remove(matched_sp->GetID(), true); } } @@ -918,7 +930,7 @@ WatchpointSP Target::CreateWatchpoint(lldb::addr_t addr, size_t size, m_watchpoint_list.Add(wp_sp, true); } - error = m_process_sp->EnableWatchpoint(wp_sp.get(), notify); + error = m_process_sp->EnableWatchpoint(wp_sp, notify); LLDB_LOGF(log, "Target::%s (creation of watchpoint %s with id = %u)\n", __FUNCTION__, error.Success() ? "succeeded" : "failed", wp_sp->GetID()); @@ -927,11 +939,6 @@ WatchpointSP Target::CreateWatchpoint(lldb::addr_t addr, size_t size, // Enabling the watchpoint on the device side failed. Remove the said // watchpoint from the list maintained by the target instance. m_watchpoint_list.Remove(wp_sp->GetID(), true); - // See if we could provide more helpful error message. - if (!OptionGroupWatchpoint::IsWatchSizeSupported(size)) - error.SetErrorStringWithFormat( - "watch size of %" PRIu64 " is not supported", (uint64_t)size); - wp_sp.reset(); } else m_last_created_watchpoint = wp_sp; @@ -1231,7 +1238,7 @@ bool Target::RemoveAllWatchpoints(bool end_to_end) { if (!wp_sp) return false; - Status rc = m_process_sp->DisableWatchpoint(wp_sp.get()); + Status rc = m_process_sp->DisableWatchpoint(wp_sp); if (rc.Fail()) return false; } @@ -1260,7 +1267,7 @@ bool Target::DisableAllWatchpoints(bool end_to_end) { if (!wp_sp) return false; - Status rc = m_process_sp->DisableWatchpoint(wp_sp.get()); + Status rc = m_process_sp->DisableWatchpoint(wp_sp); if (rc.Fail()) return false; } @@ -1287,7 +1294,7 @@ bool Target::EnableAllWatchpoints(bool end_to_end) { if (!wp_sp) return false; - Status rc = m_process_sp->EnableWatchpoint(wp_sp.get()); + Status rc = m_process_sp->EnableWatchpoint(wp_sp); if (rc.Fail()) return false; } @@ -1350,7 +1357,7 @@ bool Target::DisableWatchpointByID(lldb::watch_id_t watch_id) { WatchpointSP wp_sp = m_watchpoint_list.FindByID(watch_id); if (wp_sp) { - Status rc = m_process_sp->DisableWatchpoint(wp_sp.get()); + Status rc = m_process_sp->DisableWatchpoint(wp_sp); if (rc.Success()) return true; @@ -1369,7 +1376,7 @@ bool Target::EnableWatchpointByID(lldb::watch_id_t watch_id) { WatchpointSP wp_sp = m_watchpoint_list.FindByID(watch_id); if (wp_sp) { - Status rc = m_process_sp->EnableWatchpoint(wp_sp.get()); + Status rc = m_process_sp->EnableWatchpoint(wp_sp); if (rc.Success()) return true; diff --git a/lldb/source/Target/ThreadPlanCallFunction.cpp b/lldb/source/Target/ThreadPlanCallFunction.cpp index 31027cd..50dcb66 100644 --- a/lldb/source/Target/ThreadPlanCallFunction.cpp +++ b/lldb/source/Target/ThreadPlanCallFunction.cpp @@ -291,10 +291,10 @@ bool ThreadPlanCallFunction::DoPlanExplainsStop(Event *event_ptr) { BreakpointSiteSP bp_site_sp; bp_site_sp = m_process.GetBreakpointSiteList().FindByID(break_site_id); if (bp_site_sp) { - uint32_t num_owners = bp_site_sp->GetNumberOfOwners(); + uint32_t num_owners = bp_site_sp->GetNumberOfConstituents(); bool is_internal = true; for (uint32_t i = 0; i < num_owners; i++) { - Breakpoint &bp = bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint(); + Breakpoint &bp = bp_site_sp->GetConstituentAtIndex(i)->GetBreakpoint(); LLDB_LOGF(log, "ThreadPlanCallFunction::PlanExplainsStop: hit " "breakpoint %d while calling function", diff --git a/lldb/source/Target/ThreadPlanStepOut.cpp b/lldb/source/Target/ThreadPlanStepOut.cpp index 7bf1d2a..0a1e2ae 100644 --- a/lldb/source/Target/ThreadPlanStepOut.cpp +++ b/lldb/source/Target/ThreadPlanStepOut.cpp @@ -322,7 +322,7 @@ bool ThreadPlanStepOut::DoPlanExplainsStop(Event *event_ptr) { // important to report the user breakpoint than the step out // completion. - if (site_sp->GetNumberOfOwners() == 1) + if (site_sp->GetNumberOfConstituents() == 1) return true; } return false; diff --git a/lldb/source/Target/ThreadPlanStepRange.cpp b/lldb/source/Target/ThreadPlanStepRange.cpp index 0d5144d..bb92adc 100644 --- a/lldb/source/Target/ThreadPlanStepRange.cpp +++ b/lldb/source/Target/ThreadPlanStepRange.cpp @@ -400,14 +400,14 @@ bool ThreadPlanStepRange::NextRangeBreakpointExplainsStop( return false; else { // If we've hit the next branch breakpoint, then clear it. - size_t num_owners = bp_site_sp->GetNumberOfOwners(); + size_t num_constituents = bp_site_sp->GetNumberOfConstituents(); bool explains_stop = true; - // If all the owners are internal, then we are probably just stepping over - // this range from multiple threads, or multiple frames, so we want to + // If all the constituents are internal, then we are probably just stepping + // over this range from multiple threads, or multiple frames, so we want to // continue. If one is not internal, then we should not explain the stop, // and let the user breakpoint handle the stop. - for (size_t i = 0; i < num_owners; i++) { - if (!bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint().IsInternal()) { + for (size_t i = 0; i < num_constituents; i++) { + if (!bp_site_sp->GetConstituentAtIndex(i)->GetBreakpoint().IsInternal()) { explains_stop = false; break; } @@ -415,8 +415,8 @@ bool ThreadPlanStepRange::NextRangeBreakpointExplainsStop( LLDB_LOGF(log, "ThreadPlanStepRange::NextRangeBreakpointExplainsStop - Hit " "next range breakpoint which has %" PRIu64 - " owners - explains stop: %u.", - (uint64_t)num_owners, explains_stop); + " constituents - explains stop: %u.", + (uint64_t)num_constituents, explains_stop); ClearNextBranchBreakpoint(); return explains_stop; } diff --git a/lldb/source/Target/ThreadPlanStepUntil.cpp b/lldb/source/Target/ThreadPlanStepUntil.cpp index f63e97d..ee0f803 100644 --- a/lldb/source/Target/ThreadPlanStepUntil.cpp +++ b/lldb/source/Target/ThreadPlanStepUntil.cpp @@ -182,7 +182,7 @@ void ThreadPlanStepUntil::AnalyzeStop() { } else m_should_stop = false; - if (this_site->GetNumberOfOwners() == 1) + if (this_site->GetNumberOfConstituents() == 1) m_explains_stop = true; else m_explains_stop = false; @@ -228,7 +228,7 @@ void ThreadPlanStepUntil::AnalyzeStop() { // only breakpoint here, then we do explain the stop, and we'll // continue. If not then we should let higher plans handle this // stop. - if (this_site->GetNumberOfOwners() == 1) + if (this_site->GetNumberOfConstituents() == 1) m_explains_stop = true; else { m_should_stop = true; |