[sanitizer] Improve FreeBSD ASLR detection
[llvm-project.git] / lldb / tools / debugserver / source / DNBBreakpoint.cpp
blob9f402b4f0b1abfed6b88dec2bb64e68f717f8366
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() {}
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() {}
50 DNBBreakpointList::~DNBBreakpointList() {}
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 // Finds the next breakpoint at an address greater than or equal to "addr"
86 size_t DNBBreakpointList::FindBreakpointsThatOverlapRange(
87 nub_addr_t addr, nub_addr_t size, std::vector<DNBBreakpoint *> &bps) {
88 bps.clear();
89 iterator end = m_breakpoints.end();
90 // Find the first breakpoint with an address >= to "addr"
91 iterator pos = m_breakpoints.lower_bound(addr);
92 if (pos != end) {
93 if (pos != m_breakpoints.begin()) {
94 // Watch out for a breakpoint at an address less than "addr" that might
95 // still overlap
96 iterator prev_pos = pos;
97 --prev_pos;
98 if (prev_pos->second.IntersectsRange(addr, size, NULL, NULL, NULL))
99 bps.push_back(&pos->second);
102 while (pos != end) {
103 // When we hit a breakpoint whose start address is greater than "addr +
104 // size" we are done.
105 // Do the math in a way that doesn't risk unsigned overflow with bad
106 // input.
107 if ((pos->second.Address() - addr) >= size)
108 break;
110 // Check if this breakpoint overlaps, and if it does, add it to the list
111 if (pos->second.IntersectsRange(addr, size, NULL, NULL, NULL)) {
112 bps.push_back(&pos->second);
113 ++pos;
117 return bps.size();
120 void DNBBreakpointList::Dump() const {
121 const_iterator pos;
122 const_iterator end = m_breakpoints.end();
123 for (pos = m_breakpoints.begin(); pos != end; ++pos)
124 pos->second.Dump();
127 void DNBBreakpointList::DisableAll() {
128 iterator pos, end = m_breakpoints.end();
129 for (pos = m_breakpoints.begin(); pos != end; ++pos)
130 pos->second.SetEnabled(false);
133 void DNBBreakpointList::RemoveTrapsFromBuffer(nub_addr_t addr, nub_size_t size,
134 void *p) const {
135 uint8_t *buf = (uint8_t *)p;
136 const_iterator end = m_breakpoints.end();
137 const_iterator pos = m_breakpoints.lower_bound(addr);
138 while (pos != end && (pos->first < (addr + size))) {
139 nub_addr_t intersect_addr;
140 nub_size_t intersect_size;
141 nub_size_t opcode_offset;
142 const DNBBreakpoint &bp = pos->second;
143 if (bp.IntersectsRange(addr, size, &intersect_addr, &intersect_size,
144 &opcode_offset)) {
145 assert(addr <= intersect_addr && intersect_addr < addr + size);
146 assert(addr < intersect_addr + intersect_size &&
147 intersect_addr + intersect_size <= addr + size);
148 assert(opcode_offset + intersect_size <= bp.ByteSize());
149 nub_size_t buf_offset = intersect_addr - addr;
150 ::memcpy(buf + buf_offset, bp.SavedOpcodeBytes() + opcode_offset,
151 intersect_size);
153 ++pos;
157 void DNBBreakpointList::DisableAllBreakpoints(MachProcess *process) {
158 iterator pos, end = m_breakpoints.end();
159 for (pos = m_breakpoints.begin(); pos != end; ++pos)
160 process->DisableBreakpoint(pos->second.Address(), false);
163 void DNBBreakpointList::DisableAllWatchpoints(MachProcess *process) {
164 iterator pos, end = m_breakpoints.end();
165 for (pos = m_breakpoints.begin(); pos != end; ++pos)
166 process->DisableWatchpoint(pos->second.Address(), false);
169 void DNBBreakpointList::RemoveDisabled() {
170 iterator pos = m_breakpoints.begin();
171 while (pos != m_breakpoints.end()) {
172 if (!pos->second.IsEnabled())
173 pos = m_breakpoints.erase(pos);
174 else
175 ++pos;