1 //===-- DNBBreakpoint.cpp ---------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // Created by Greg Clayton on 6/29/07.
11 //===----------------------------------------------------------------------===//
13 #include "DNBBreakpoint.h"
15 #include "MachProcess.h"
20 #pragma mark-- DNBBreakpoint
21 DNBBreakpoint::DNBBreakpoint(nub_addr_t addr
, nub_size_t byte_size
,
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 {
32 DNBLog("DNBBreakpoint addr = 0x%llx state = %s type = %s breakpoint "
34 (uint64_t)m_addr
, m_enabled
? "enabled " : "disabled",
35 IsHardware() ? "hardware" : "software", GetHardwareIndex());
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
,
55 std::make_pair(addr
, DNBBreakpoint(addr
, length
, hardware
)));
56 iterator pos
= m_breakpoints
.find(addr
);
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
);
69 DNBBreakpoint
*DNBBreakpointList::FindByAddress(nub_addr_t addr
) {
70 iterator pos
= m_breakpoints
.find(addr
);
71 if (pos
!= m_breakpoints
.end())
77 const DNBBreakpoint
*DNBBreakpointList::FindByAddress(nub_addr_t addr
) const {
78 const_iterator pos
= m_breakpoints
.find(addr
);
79 if (pos
!= m_breakpoints
.end())
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
) {
89 iterator end
= m_breakpoints
.end();
90 // Find the first breakpoint with an address >= to "addr"
91 iterator pos
= m_breakpoints
.lower_bound(addr
);
93 if (pos
!= m_breakpoints
.begin()) {
94 // Watch out for a breakpoint at an address less than "addr" that might
96 iterator prev_pos
= pos
;
98 if (prev_pos
->second
.IntersectsRange(addr
, size
, NULL
, NULL
, NULL
))
99 bps
.push_back(&pos
->second
);
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
107 if ((pos
->second
.Address() - addr
) >= size
)
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
);
120 void DNBBreakpointList::Dump() const {
122 const_iterator end
= m_breakpoints
.end();
123 for (pos
= m_breakpoints
.begin(); pos
!= end
; ++pos
)
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
,
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
,
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
,
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
);