1 //===-- DNBBreakpoint.cpp ---------------------------------------*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // Created by Greg Clayton on 6/29/07.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "DNBBreakpoint.h"
15 #include "MachProcess.h"
16 #include <assert.h>
17 #include <algorithm>
18 #include <inttypes.h>
19 #include "DNBLog.h"
20
21
22 #pragma mark -- DNBBreakpoint
DNBBreakpoint(nub_addr_t addr,nub_size_t byte_size,bool hardware)23 DNBBreakpoint::DNBBreakpoint(nub_addr_t addr, nub_size_t byte_size, bool hardware) :
24 m_retain_count (1),
25 m_byte_size (byte_size),
26 m_opcode(),
27 m_addr(addr),
28 m_enabled(0),
29 m_hw_preferred(hardware),
30 m_is_watchpoint(0),
31 m_watch_read(0),
32 m_watch_write(0),
33 m_hw_index(INVALID_NUB_HW_INDEX)
34 {
35 }
36
~DNBBreakpoint()37 DNBBreakpoint::~DNBBreakpoint()
38 {
39 }
40
41 void
Dump() const42 DNBBreakpoint::Dump() const
43 {
44 if (IsBreakpoint())
45 {
46 DNBLog ("DNBBreakpoint addr = 0x%llx state = %s type = %s breakpoint hw_index = %i",
47 (uint64_t)m_addr,
48 m_enabled ? "enabled " : "disabled",
49 IsHardware() ? "hardware" : "software",
50 GetHardwareIndex());
51 }
52 else
53 {
54 DNBLog ("DNBBreakpoint addr = 0x%llx size = %llu state = %s type = %s watchpoint (%s%s) hw_index = %i",
55 (uint64_t)m_addr,
56 (uint64_t)m_byte_size,
57 m_enabled ? "enabled " : "disabled",
58 IsHardware() ? "hardware" : "software",
59 m_watch_read ? "r" : "",
60 m_watch_write ? "w" : "",
61 GetHardwareIndex());
62 }
63 }
64
65 #pragma mark -- DNBBreakpointList
66
DNBBreakpointList()67 DNBBreakpointList::DNBBreakpointList()
68 {
69 }
70
~DNBBreakpointList()71 DNBBreakpointList::~DNBBreakpointList()
72 {
73 }
74
75
76 DNBBreakpoint *
Add(nub_addr_t addr,nub_size_t length,bool hardware)77 DNBBreakpointList::Add(nub_addr_t addr, nub_size_t length, bool hardware)
78 {
79 m_breakpoints.insert(std::make_pair(addr, DNBBreakpoint(addr, length, hardware)));
80 iterator pos = m_breakpoints.find (addr);
81 return &pos->second;
82 }
83
84 bool
Remove(nub_addr_t addr)85 DNBBreakpointList::Remove (nub_addr_t addr)
86 {
87 iterator pos = m_breakpoints.find(addr);
88 if (pos != m_breakpoints.end())
89 {
90 m_breakpoints.erase(pos);
91 return true;
92 }
93 return false;
94 }
95
96 DNBBreakpoint *
FindByAddress(nub_addr_t addr)97 DNBBreakpointList::FindByAddress (nub_addr_t addr)
98 {
99 iterator pos = m_breakpoints.find(addr);
100 if (pos != m_breakpoints.end())
101 return &pos->second;
102
103 return NULL;
104 }
105
106 const DNBBreakpoint *
FindByAddress(nub_addr_t addr) const107 DNBBreakpointList::FindByAddress (nub_addr_t addr) const
108 {
109 const_iterator pos = m_breakpoints.find(addr);
110 if (pos != m_breakpoints.end())
111 return &pos->second;
112
113 return NULL;
114 }
115
116 // Finds the next breakpoint at an address greater than or equal to "addr"
117 size_t
FindBreakpointsThatOverlapRange(nub_addr_t addr,nub_addr_t size,std::vector<DNBBreakpoint * > & bps)118 DNBBreakpointList::FindBreakpointsThatOverlapRange (nub_addr_t addr,
119 nub_addr_t size,
120 std::vector<DNBBreakpoint *> &bps)
121 {
122 bps.clear();
123 iterator end = m_breakpoints.end();
124 // Find the first breakpoint with an address >= to "addr"
125 iterator pos = m_breakpoints.lower_bound(addr);
126 if (pos != end)
127 {
128 if (pos != m_breakpoints.begin())
129 {
130 // Watch out for a breakpoint at an address less than "addr" that might still overlap
131 iterator prev_pos = pos;
132 --prev_pos;
133 if (prev_pos->second.IntersectsRange (addr, size, NULL, NULL, NULL))
134 bps.push_back (&pos->second);
135
136 }
137
138 while (pos != end)
139 {
140 // When we hit a breakpoint whose start address is greater than "addr + size" we are done.
141 // Do the math in a way that doesn't risk unsigned overflow with bad input.
142 if ((pos->second.Address() - addr) >= size)
143 break;
144
145 // Check if this breakpoint overlaps, and if it does, add it to the list
146 if (pos->second.IntersectsRange (addr, size, NULL, NULL, NULL))
147 {
148 bps.push_back (&pos->second);
149 ++pos;
150 }
151 }
152 }
153 return bps.size();
154 }
155
156 void
Dump() const157 DNBBreakpointList::Dump() const
158 {
159 const_iterator pos;
160 const_iterator end = m_breakpoints.end();
161 for (pos = m_breakpoints.begin(); pos != end; ++pos)
162 pos->second.Dump();
163 }
164
165 void
DisableAll()166 DNBBreakpointList::DisableAll ()
167 {
168 iterator pos, end = m_breakpoints.end();
169 for (pos = m_breakpoints.begin(); pos != end; ++pos)
170 pos->second.SetEnabled(false);
171 }
172
173
174 void
RemoveTrapsFromBuffer(nub_addr_t addr,nub_size_t size,void * p) const175 DNBBreakpointList::RemoveTrapsFromBuffer (nub_addr_t addr, nub_size_t size, void *p) const
176 {
177 uint8_t *buf = (uint8_t *)p;
178 const_iterator end = m_breakpoints.end();
179 const_iterator pos = m_breakpoints.lower_bound(addr);
180 while (pos != end && (pos->first < (addr + size)))
181 {
182 nub_addr_t intersect_addr;
183 nub_size_t intersect_size;
184 nub_size_t opcode_offset;
185 const DNBBreakpoint &bp = pos->second;
186 if (bp.IntersectsRange(addr, size, &intersect_addr, &intersect_size, &opcode_offset))
187 {
188 assert(addr <= intersect_addr && intersect_addr < addr + size);
189 assert(addr < intersect_addr + intersect_size && intersect_addr + intersect_size <= addr + size);
190 assert(opcode_offset + intersect_size <= bp.ByteSize());
191 nub_size_t buf_offset = intersect_addr - addr;
192 ::memcpy(buf + buf_offset, bp.SavedOpcodeBytes() + opcode_offset, intersect_size);
193 }
194 ++pos;
195 }
196 }
197
198 void
DisableAllBreakpoints(MachProcess * process)199 DNBBreakpointList::DisableAllBreakpoints(MachProcess *process)
200 {
201 iterator pos, end = m_breakpoints.end();
202 for (pos = m_breakpoints.begin(); pos != end; ++pos)
203 process->DisableBreakpoint(pos->second.Address(), false);
204 }
205
206 void
DisableAllWatchpoints(MachProcess * process)207 DNBBreakpointList::DisableAllWatchpoints(MachProcess *process)
208 {
209 iterator pos, end = m_breakpoints.end();
210 for (pos = m_breakpoints.begin(); pos != end; ++pos)
211 process->DisableWatchpoint(pos->second.Address(), false);
212 }
213
214 void
RemoveDisabled()215 DNBBreakpointList::RemoveDisabled()
216 {
217 iterator pos = m_breakpoints.begin();
218 while (pos != m_breakpoints.end())
219 {
220 if (!pos->second.IsEnabled())
221 pos = m_breakpoints.erase(pos);
222 else
223 ++pos;
224 }
225 }
226