1 | //===-- WatchpointResource.cpp --------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include <assert.h> |
10 | |
11 | #include "lldb/Breakpoint/WatchpointResource.h" |
12 | #include "lldb/Utility/Stream.h" |
13 | |
14 | #include <algorithm> |
15 | |
16 | using namespace lldb; |
17 | using namespace lldb_private; |
18 | |
19 | WatchpointResource::WatchpointResource(lldb::addr_t addr, size_t size, |
20 | bool read, bool write) |
21 | : m_id(GetNextID()), m_addr(addr), m_size(size), |
22 | m_watch_read(read), m_watch_write(write) {} |
23 | |
24 | WatchpointResource::~WatchpointResource() { |
25 | std::lock_guard<std::mutex> guard(m_constituents_mutex); |
26 | m_constituents.clear(); |
27 | } |
28 | |
29 | addr_t WatchpointResource::GetLoadAddress() const { return m_addr; } |
30 | |
31 | size_t WatchpointResource::GetByteSize() const { return m_size; } |
32 | |
33 | bool WatchpointResource::WatchpointResourceRead() const { return m_watch_read; } |
34 | |
35 | bool WatchpointResource::WatchpointResourceWrite() const { |
36 | return m_watch_write; |
37 | } |
38 | |
39 | void WatchpointResource::SetType(bool read, bool write) { |
40 | m_watch_read = read; |
41 | m_watch_write = write; |
42 | } |
43 | |
44 | wp_resource_id_t WatchpointResource::GetID() const { return m_id; } |
45 | |
46 | bool WatchpointResource::Contains(addr_t addr) { |
47 | if (addr >= m_addr && addr < m_addr + m_size) |
48 | return true; |
49 | return false; |
50 | } |
51 | |
52 | void WatchpointResource::AddConstituent(const WatchpointSP &wp_sp) { |
53 | std::lock_guard<std::mutex> guard(m_constituents_mutex); |
54 | m_constituents.push_back(x: wp_sp); |
55 | } |
56 | |
57 | void WatchpointResource::RemoveConstituent(WatchpointSP &wp_sp) { |
58 | std::lock_guard<std::mutex> guard(m_constituents_mutex); |
59 | auto it = llvm::find(Range&: m_constituents, Val: wp_sp); |
60 | if (it != m_constituents.end()) |
61 | m_constituents.erase(position: it); |
62 | } |
63 | |
64 | size_t WatchpointResource::GetNumberOfConstituents() { |
65 | std::lock_guard<std::mutex> guard(m_constituents_mutex); |
66 | return m_constituents.size(); |
67 | } |
68 | |
69 | bool WatchpointResource::ConstituentsContains(const WatchpointSP &wp_sp) { |
70 | return ConstituentsContains(wp: wp_sp.get()); |
71 | } |
72 | |
73 | bool WatchpointResource::ConstituentsContains(const Watchpoint *wp) { |
74 | std::lock_guard<std::mutex> guard(m_constituents_mutex); |
75 | return llvm::any_of(Range&: m_constituents, |
76 | P: [&wp](const WatchpointSP &x) { return x.get() == wp; }); |
77 | } |
78 | |
79 | WatchpointSP WatchpointResource::GetConstituentAtIndex(size_t idx) { |
80 | std::lock_guard<std::mutex> guard(m_constituents_mutex); |
81 | assert(idx < m_constituents.size()); |
82 | if (idx >= m_constituents.size()) |
83 | return {}; |
84 | |
85 | return m_constituents[idx]; |
86 | } |
87 | |
88 | WatchpointResource::WatchpointCollection |
89 | WatchpointResource::CopyConstituentsList() { |
90 | std::lock_guard<std::mutex> guard(m_constituents_mutex); |
91 | return m_constituents; |
92 | } |
93 | |
94 | bool WatchpointResource::ShouldStop(StoppointCallbackContext *context) { |
95 | // LWP_TODO: Need to poll all Watchpoint constituents and see if |
96 | // we should stop, like BreakpointSites do. |
97 | #if 0 |
98 | m_hit_counter.Increment(); |
99 | // ShouldStop can do a lot of work, and might even come back and hit |
100 | // this breakpoint site again. So don't hold the m_constituents_mutex the |
101 | // whole while. Instead make a local copy of the collection and call |
102 | // ShouldStop on the copy. |
103 | WatchpointResourceCollection constituents_copy; |
104 | { |
105 | std::lock_guard<std::recursive_mutex> guard(m_constituents_mutex); |
106 | constituents_copy = m_constituents; |
107 | } |
108 | return constituents_copy.ShouldStop(context); |
109 | #endif |
110 | return true; |
111 | } |
112 | |
113 | void WatchpointResource::Dump(Stream *s) const { |
114 | s->Printf(format: "addr = 0x%8.8" PRIx64 " size = %zu" , m_addr, m_size); |
115 | } |
116 | |
117 | wp_resource_id_t WatchpointResource::GetNextID() { |
118 | static wp_resource_id_t g_next_id = 0; |
119 | return ++g_next_id; |
120 | } |
121 | |