blob: 246797c8daeabea0a5e2482b49dbf2b457fefbf4 [file] [log] [blame]
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001//===-- 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"
Greg Claytond8cf1a12013-06-12 00:46:38 +000015#include "MachProcess.h"
16#include <assert.h>
Chris Lattner30fdc8d2010-06-08 16:52:24 +000017#include <algorithm>
Jason Molenda1c739112013-02-22 07:27:08 +000018#include <inttypes.h>
Chris Lattner30fdc8d2010-06-08 16:52:24 +000019#include "DNBLog.h"
20
21
22#pragma mark -- DNBBreakpoint
Greg Claytond8cf1a12013-06-12 00:46:38 +000023DNBBreakpoint::DNBBreakpoint(nub_addr_t addr, nub_size_t byte_size, bool hardware) :
24 m_retain_count (1),
25 m_byte_size (byte_size),
Chris Lattner30fdc8d2010-06-08 16:52:24 +000026 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),
Greg Claytond8cf1a12013-06-12 00:46:38 +000033 m_hw_index(INVALID_NUB_HW_INDEX)
Chris Lattner30fdc8d2010-06-08 16:52:24 +000034{
35}
36
37DNBBreakpoint::~DNBBreakpoint()
38{
39}
40
Chris Lattner30fdc8d2010-06-08 16:52:24 +000041void
42DNBBreakpoint::Dump() const
43{
44 if (IsBreakpoint())
45 {
Greg Claytond8cf1a12013-06-12 00:46:38 +000046 DNBLog ("DNBBreakpoint addr = 0x%llx state = %s type = %s breakpoint hw_index = %i",
Greg Clayton490fbbe2011-10-28 22:59:14 +000047 (uint64_t)m_addr,
48 m_enabled ? "enabled " : "disabled",
49 IsHardware() ? "hardware" : "software",
Greg Claytond8cf1a12013-06-12 00:46:38 +000050 GetHardwareIndex());
Chris Lattner30fdc8d2010-06-08 16:52:24 +000051 }
52 else
53 {
Greg Claytond8cf1a12013-06-12 00:46:38 +000054 DNBLog ("DNBBreakpoint addr = 0x%llx size = %llu state = %s type = %s watchpoint (%s%s) hw_index = %i",
Greg Clayton490fbbe2011-10-28 22:59:14 +000055 (uint64_t)m_addr,
Greg Clayton43e0af02012-09-18 18:04:04 +000056 (uint64_t)m_byte_size,
Greg Clayton490fbbe2011-10-28 22:59:14 +000057 m_enabled ? "enabled " : "disabled",
58 IsHardware() ? "hardware" : "software",
59 m_watch_read ? "r" : "",
60 m_watch_write ? "w" : "",
Greg Claytond8cf1a12013-06-12 00:46:38 +000061 GetHardwareIndex());
Chris Lattner30fdc8d2010-06-08 16:52:24 +000062 }
63}
64
65#pragma mark -- DNBBreakpointList
66
67DNBBreakpointList::DNBBreakpointList()
68{
69}
70
71DNBBreakpointList::~DNBBreakpointList()
72{
73}
74
75
Greg Claytond8cf1a12013-06-12 00:46:38 +000076DNBBreakpoint *
77DNBBreakpointList::Add(nub_addr_t addr, nub_size_t length, bool hardware)
Chris Lattner30fdc8d2010-06-08 16:52:24 +000078{
Greg Claytond8cf1a12013-06-12 00:46:38 +000079 m_breakpoints.insert(std::make_pair(addr, DNBBreakpoint(addr, length, hardware)));
80 iterator pos = m_breakpoints.find (addr);
81 return &pos->second;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000082}
83
84bool
Greg Claytond8cf1a12013-06-12 00:46:38 +000085DNBBreakpointList::Remove (nub_addr_t addr)
Chris Lattner30fdc8d2010-06-08 16:52:24 +000086{
Greg Claytond8cf1a12013-06-12 00:46:38 +000087 iterator pos = m_breakpoints.find(addr);
Chris Lattner30fdc8d2010-06-08 16:52:24 +000088 if (pos != m_breakpoints.end())
89 {
90 m_breakpoints.erase(pos);
91 return true;
92 }
93 return false;
94}
95
Chris Lattner30fdc8d2010-06-08 16:52:24 +000096DNBBreakpoint *
97DNBBreakpointList::FindByAddress (nub_addr_t addr)
98{
Greg Claytond8cf1a12013-06-12 00:46:38 +000099 iterator pos = m_breakpoints.find(addr);
100 if (pos != m_breakpoints.end())
101 return &pos->second;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000102
103 return NULL;
104}
105
106const DNBBreakpoint *
107DNBBreakpointList::FindByAddress (nub_addr_t addr) const
108{
Greg Claytond8cf1a12013-06-12 00:46:38 +0000109 const_iterator pos = m_breakpoints.find(addr);
110 if (pos != m_breakpoints.end())
111 return &pos->second;
112
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000113 return NULL;
114}
115
Greg Claytond8cf1a12013-06-12 00:46:38 +0000116// Finds the next breakpoint at an address greater than or equal to "addr"
117size_t
118DNBBreakpointList::FindBreakpointsThatOverlapRange (nub_addr_t addr,
119 nub_addr_t size,
120 std::vector<DNBBreakpoint *> &bps)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000121{
Greg Claytond8cf1a12013-06-12 00:46:38 +0000122 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)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000127 {
Greg Claytond8cf1a12013-06-12 00:46:38 +0000128 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 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000137
Greg Claytond8cf1a12013-06-12 00:46:38 +0000138 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}
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000155
156void
157DNBBreakpointList::Dump() const
158{
159 const_iterator pos;
160 const_iterator end = m_breakpoints.end();
161 for (pos = m_breakpoints.begin(); pos != end; ++pos)
Greg Claytond8cf1a12013-06-12 00:46:38 +0000162 pos->second.Dump();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000163}
164
Greg Clayton15fc2be2013-05-21 01:00:52 +0000165void
166DNBBreakpointList::DisableAll ()
167{
168 iterator pos, end = m_breakpoints.end();
169 for (pos = m_breakpoints.begin(); pos != end; ++pos)
Greg Claytond8cf1a12013-06-12 00:46:38 +0000170 pos->second.SetEnabled(false);
Greg Clayton15fc2be2013-05-21 01:00:52 +0000171}
172
173
Greg Claytond8cf1a12013-06-12 00:46:38 +0000174void
175DNBBreakpointList::RemoveTrapsFromBuffer (nub_addr_t addr, nub_size_t size, void *p) const
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000176{
Greg Claytond8cf1a12013-06-12 00:46:38 +0000177 uint8_t *buf = (uint8_t *)p;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000178 const_iterator end = m_breakpoints.end();
Greg Claytond8cf1a12013-06-12 00:46:38 +0000179 const_iterator pos = m_breakpoints.lower_bound(addr);
180 while (pos != end && (pos->first < (addr + size)))
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000181 {
Greg Claytond8cf1a12013-06-12 00:46:38 +0000182 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;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000195 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000196}
197
Greg Claytond8cf1a12013-06-12 00:46:38 +0000198void
199DNBBreakpointList::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
206void
207DNBBreakpointList::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
214void
215DNBBreakpointList::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}