blob: 890bde024bf0c8f7d5462ab3d4acbcc554b72448 [file] [log] [blame]
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001//===-- DNBBreakpoint.cpp ---------------------------------------*- C++ -*-===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Chris Lattner30fdc8d2010-06-08 16:52:24 +00006//
7//===----------------------------------------------------------------------===//
8//
9// Created by Greg Clayton on 6/29/07.
10//
11//===----------------------------------------------------------------------===//
12
13#include "DNBBreakpoint.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000014#include "DNBLog.h"
Kate Stoneb9c1b512016-09-06 20:57:50 +000015#include "MachProcess.h"
16#include <algorithm>
17#include <assert.h>
18#include <inttypes.h>
Chris Lattner30fdc8d2010-06-08 16:52:24 +000019
Kate Stoneb9c1b512016-09-06 20:57:50 +000020#pragma mark-- DNBBreakpoint
21DNBBreakpoint::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) {}
Chris Lattner30fdc8d2010-06-08 16:52:24 +000027
Kate Stoneb9c1b512016-09-06 20:57:50 +000028DNBBreakpoint::~DNBBreakpoint() {}
29
30void 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());
43 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +000044}
45
Kate Stoneb9c1b512016-09-06 20:57:50 +000046#pragma mark-- DNBBreakpointList
47
48DNBBreakpointList::DNBBreakpointList() {}
49
50DNBBreakpointList::~DNBBreakpointList() {}
51
52DNBBreakpoint *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;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000058}
59
Kate Stoneb9c1b512016-09-06 20:57:50 +000060bool 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;
65 }
66 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000067}
68
Kate Stoneb9c1b512016-09-06 20:57:50 +000069DNBBreakpoint *DNBBreakpointList::FindByAddress(nub_addr_t addr) {
70 iterator pos = m_breakpoints.find(addr);
71 if (pos != m_breakpoints.end())
Greg Claytond8cf1a12013-06-12 00:46:38 +000072 return &pos->second;
Kate Stoneb9c1b512016-09-06 20:57:50 +000073
74 return NULL;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000075}
76
Kate Stoneb9c1b512016-09-06 20:57:50 +000077const 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;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000081
Kate Stoneb9c1b512016-09-06 20:57:50 +000082 return NULL;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000083}
84
Greg Claytond8cf1a12013-06-12 00:46:38 +000085// Finds the next breakpoint at an address greater than or equal to "addr"
Kate Stoneb9c1b512016-09-06 20:57:50 +000086size_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);
Greg Claytond8cf1a12013-06-12 00:46:38 +0000100 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000101
Kate Stoneb9c1b512016-09-06 20:57:50 +0000102 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;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000109
Kate Stoneb9c1b512016-09-06 20:57:50 +0000110 // 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);
Greg Claytond8cf1a12013-06-12 00:46:38 +0000113 ++pos;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000114 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000115 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000116 }
117 return bps.size();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000118}
119
Kate Stoneb9c1b512016-09-06 20:57:50 +0000120void 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();
Greg Claytond8cf1a12013-06-12 00:46:38 +0000125}
126
Kate Stoneb9c1b512016-09-06 20:57:50 +0000127void DNBBreakpointList::DisableAll() {
128 iterator pos, end = m_breakpoints.end();
129 for (pos = m_breakpoints.begin(); pos != end; ++pos)
130 pos->second.SetEnabled(false);
Greg Claytond8cf1a12013-06-12 00:46:38 +0000131}
132
Kate Stoneb9c1b512016-09-06 20:57:50 +0000133void 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);
Greg Claytond8cf1a12013-06-12 00:46:38 +0000152 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000153 ++pos;
154 }
155}
156
157void 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);
161}
162
163void 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);
167}
168
169void 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;
176 }
Greg Claytond8cf1a12013-06-12 00:46:38 +0000177}