[clang] Fix implicit integer conversion for opaque enums declared in class templates...
[llvm-project.git] / lldb / tools / debugserver / source / DNBBreakpoint.cpp
blobf63ecf24222bd7ff7e69dda4266868b4d7720032
1 //===-- DNBBreakpoint.cpp ---------------------------------------*- C++ -*-===//
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 // Created by Greg Clayton on 6/29/07.
11 //===----------------------------------------------------------------------===//
13 #include "DNBBreakpoint.h"
14 #include "DNBLog.h"
15 #include "MachProcess.h"
16 #include <algorithm>
17 #include <cassert>
18 #include <cinttypes>
20 #pragma mark-- DNBBreakpoint
21 DNBBreakpoint::DNBBreakpoint(nub_addr_t addr, nub_size_t byte_size,
22 bool hardware)
23 : m_retain_count(1), m_byte_size(static_cast<uint32_t>(byte_size)),
24 m_opcode(), m_addr(addr), m_enabled(0), m_hw_preferred(hardware),
25 m_is_watchpoint(0), m_watch_read(0), m_watch_write(0),
26 m_hw_index(INVALID_NUB_HW_INDEX) {}
28 DNBBreakpoint::~DNBBreakpoint() = default;
30 void DNBBreakpoint::Dump() const {
31 if (IsBreakpoint()) {
32 DNBLog("DNBBreakpoint addr = 0x%llx state = %s type = %s breakpoint "
33 "hw_index = %i",
34 (uint64_t)m_addr, m_enabled ? "enabled " : "disabled",
35 IsHardware() ? "hardware" : "software", GetHardwareIndex());
36 } else {
37 DNBLog("DNBBreakpoint addr = 0x%llx size = %llu state = %s type = %s "
38 "watchpoint (%s%s) hw_index = %i",
39 (uint64_t)m_addr, (uint64_t)m_byte_size,
40 m_enabled ? "enabled " : "disabled",
41 IsHardware() ? "hardware" : "software", m_watch_read ? "r" : "",
42 m_watch_write ? "w" : "", GetHardwareIndex());
46 #pragma mark-- DNBBreakpointList
48 DNBBreakpointList::DNBBreakpointList() = default;
50 DNBBreakpointList::~DNBBreakpointList() = default;
52 DNBBreakpoint *DNBBreakpointList::Add(nub_addr_t addr, nub_size_t length,
53 bool hardware) {
54 m_breakpoints.insert(
55 std::make_pair(addr, DNBBreakpoint(addr, length, hardware)));
56 iterator pos = m_breakpoints.find(addr);
57 return &pos->second;
60 bool DNBBreakpointList::Remove(nub_addr_t addr) {
61 iterator pos = m_breakpoints.find(addr);
62 if (pos != m_breakpoints.end()) {
63 m_breakpoints.erase(pos);
64 return true;
66 return false;
69 DNBBreakpoint *DNBBreakpointList::FindByAddress(nub_addr_t addr) {
70 iterator pos = m_breakpoints.find(addr);
71 if (pos != m_breakpoints.end())
72 return &pos->second;
74 return NULL;
77 const DNBBreakpoint *DNBBreakpointList::FindByAddress(nub_addr_t addr) const {
78 const_iterator pos = m_breakpoints.find(addr);
79 if (pos != m_breakpoints.end())
80 return &pos->second;
82 return NULL;
85 const DNBBreakpoint *
86 DNBBreakpointList::FindByHardwareIndex(uint32_t idx) const {
87 for (const auto &pos : m_breakpoints)
88 if (pos.second.GetHardwareIndex() == idx)
89 return &pos.second;
91 return nullptr;
94 const DNBBreakpoint *
95 DNBBreakpointList::FindNearestWatchpoint(nub_addr_t addr) const {
96 // Exact match
97 for (const auto &pos : m_breakpoints) {
98 if (pos.second.IsEnabled()) {
99 nub_addr_t start_addr = pos.second.Address();
100 nub_addr_t end_addr = start_addr + pos.second.ByteSize();
101 if (addr >= start_addr && addr <= end_addr)
102 return &pos.second;
106 // Find watchpoint nearest to this address
107 // before or after the watched region of memory
108 const DNBBreakpoint *closest = nullptr;
109 uint32_t best_match = UINT32_MAX;
110 for (const auto &pos : m_breakpoints) {
111 if (pos.second.IsEnabled()) {
112 nub_addr_t start_addr = pos.second.Address();
113 nub_addr_t end_addr = start_addr + pos.second.ByteSize();
114 uint32_t delta = addr < start_addr ? start_addr - addr : addr - end_addr;
115 if (delta < best_match) {
116 closest = &pos.second;
117 best_match = delta;
121 return closest;
124 // Finds the next breakpoint at an address greater than or equal to "addr"
125 size_t DNBBreakpointList::FindBreakpointsThatOverlapRange(
126 nub_addr_t addr, nub_addr_t size, std::vector<DNBBreakpoint *> &bps) {
127 bps.clear();
128 iterator end = m_breakpoints.end();
129 // Find the first breakpoint with an address >= to "addr"
130 iterator pos = m_breakpoints.lower_bound(addr);
131 if (pos != end) {
132 if (pos != m_breakpoints.begin()) {
133 // Watch out for a breakpoint at an address less than "addr" that might
134 // still overlap
135 iterator prev_pos = pos;
136 --prev_pos;
137 if (prev_pos->second.IntersectsRange(addr, size, NULL, NULL, NULL))
138 bps.push_back(&pos->second);
141 while (pos != end) {
142 // When we hit a breakpoint whose start address is greater than "addr +
143 // size" we are done.
144 // Do the math in a way that doesn't risk unsigned overflow with bad
145 // input.
146 if ((pos->second.Address() - addr) >= size)
147 break;
149 // Check if this breakpoint overlaps, and if it does, add it to the list
150 if (pos->second.IntersectsRange(addr, size, NULL, NULL, NULL)) {
151 bps.push_back(&pos->second);
152 ++pos;
156 return bps.size();
159 void DNBBreakpointList::Dump() const {
160 const_iterator pos;
161 const_iterator end = m_breakpoints.end();
162 for (pos = m_breakpoints.begin(); pos != end; ++pos)
163 pos->second.Dump();
166 void DNBBreakpointList::DisableAll() {
167 iterator pos, end = m_breakpoints.end();
168 for (pos = m_breakpoints.begin(); pos != end; ++pos)
169 pos->second.SetEnabled(false);
172 void DNBBreakpointList::RemoveTrapsFromBuffer(nub_addr_t addr, nub_size_t size,
173 void *p) const {
174 uint8_t *buf = (uint8_t *)p;
175 const_iterator end = m_breakpoints.end();
176 const_iterator pos = m_breakpoints.lower_bound(addr);
177 while (pos != end && (pos->first < (addr + size))) {
178 nub_addr_t intersect_addr;
179 nub_size_t intersect_size;
180 nub_size_t opcode_offset;
181 const DNBBreakpoint &bp = pos->second;
182 if (bp.IntersectsRange(addr, size, &intersect_addr, &intersect_size,
183 &opcode_offset)) {
184 assert(addr <= intersect_addr && intersect_addr < addr + size);
185 assert(addr < intersect_addr + intersect_size &&
186 intersect_addr + intersect_size <= addr + size);
187 assert(opcode_offset + intersect_size <= bp.ByteSize());
188 nub_size_t buf_offset = intersect_addr - addr;
189 ::memcpy(buf + buf_offset, bp.SavedOpcodeBytes() + opcode_offset,
190 intersect_size);
192 ++pos;
196 void DNBBreakpointList::DisableAllBreakpoints(MachProcess *process) {
197 iterator pos, end = m_breakpoints.end();
198 for (pos = m_breakpoints.begin(); pos != end; ++pos)
199 process->DisableBreakpoint(pos->second.Address(), false);
202 void DNBBreakpointList::DisableAllWatchpoints(MachProcess *process) {
203 iterator pos, end = m_breakpoints.end();
204 for (pos = m_breakpoints.begin(); pos != end; ++pos)
205 process->DisableWatchpoint(pos->second.Address(), false);
208 void DNBBreakpointList::RemoveDisabled() {
209 iterator pos = m_breakpoints.begin();
210 while (pos != m_breakpoints.end()) {
211 if (!pos->second.IsEnabled())
212 pos = m_breakpoints.erase(pos);
213 else
214 ++pos;