blob: 89a91287f9e34c8440d8296fee311b09939d1ce5 [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"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000015#include "DNBLog.h"
Kate Stoneb9c1b512016-09-06 20:57:50 +000016#include "MachProcess.h"
17#include <algorithm>
18#include <assert.h>
19#include <inttypes.h>
Chris Lattner30fdc8d2010-06-08 16:52:24 +000020
Kate Stoneb9c1b512016-09-06 20:57:50 +000021#pragma mark-- DNBBreakpoint
22DNBBreakpoint::DNBBreakpoint(nub_addr_t addr, nub_size_t byte_size,
23 bool hardware)
24 : m_retain_count(1), m_byte_size(static_cast<uint32_t>(byte_size)),
25 m_opcode(), m_addr(addr), m_enabled(0), m_hw_preferred(hardware),
26 m_is_watchpoint(0), m_watch_read(0), m_watch_write(0),
27 m_hw_index(INVALID_NUB_HW_INDEX) {}
Chris Lattner30fdc8d2010-06-08 16:52:24 +000028
Kate Stoneb9c1b512016-09-06 20:57:50 +000029DNBBreakpoint::~DNBBreakpoint() {}
30
31void DNBBreakpoint::Dump() const {
32 if (IsBreakpoint()) {
33 DNBLog("DNBBreakpoint addr = 0x%llx state = %s type = %s breakpoint "
34 "hw_index = %i",
35 (uint64_t)m_addr, m_enabled ? "enabled " : "disabled",
36 IsHardware() ? "hardware" : "software", GetHardwareIndex());
37 } else {
38 DNBLog("DNBBreakpoint addr = 0x%llx size = %llu state = %s type = %s "
39 "watchpoint (%s%s) hw_index = %i",
40 (uint64_t)m_addr, (uint64_t)m_byte_size,
41 m_enabled ? "enabled " : "disabled",
42 IsHardware() ? "hardware" : "software", m_watch_read ? "r" : "",
43 m_watch_write ? "w" : "", GetHardwareIndex());
44 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +000045}
46
Kate Stoneb9c1b512016-09-06 20:57:50 +000047#pragma mark-- DNBBreakpointList
48
49DNBBreakpointList::DNBBreakpointList() {}
50
51DNBBreakpointList::~DNBBreakpointList() {}
52
53DNBBreakpoint *DNBBreakpointList::Add(nub_addr_t addr, nub_size_t length,
54 bool hardware) {
55 m_breakpoints.insert(
56 std::make_pair(addr, DNBBreakpoint(addr, length, hardware)));
57 iterator pos = m_breakpoints.find(addr);
58 return &pos->second;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000059}
60
Kate Stoneb9c1b512016-09-06 20:57:50 +000061bool DNBBreakpointList::Remove(nub_addr_t addr) {
62 iterator pos = m_breakpoints.find(addr);
63 if (pos != m_breakpoints.end()) {
64 m_breakpoints.erase(pos);
65 return true;
66 }
67 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000068}
69
Kate Stoneb9c1b512016-09-06 20:57:50 +000070DNBBreakpoint *DNBBreakpointList::FindByAddress(nub_addr_t addr) {
71 iterator pos = m_breakpoints.find(addr);
72 if (pos != m_breakpoints.end())
Greg Claytond8cf1a12013-06-12 00:46:38 +000073 return &pos->second;
Kate Stoneb9c1b512016-09-06 20:57:50 +000074
75 return NULL;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000076}
77
Kate Stoneb9c1b512016-09-06 20:57:50 +000078const DNBBreakpoint *DNBBreakpointList::FindByAddress(nub_addr_t addr) const {
79 const_iterator pos = m_breakpoints.find(addr);
80 if (pos != m_breakpoints.end())
81 return &pos->second;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000082
Kate Stoneb9c1b512016-09-06 20:57:50 +000083 return NULL;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000084}
85
Greg Claytond8cf1a12013-06-12 00:46:38 +000086// Finds the next breakpoint at an address greater than or equal to "addr"
Kate Stoneb9c1b512016-09-06 20:57:50 +000087size_t DNBBreakpointList::FindBreakpointsThatOverlapRange(
88 nub_addr_t addr, nub_addr_t size, std::vector<DNBBreakpoint *> &bps) {
89 bps.clear();
90 iterator end = m_breakpoints.end();
91 // Find the first breakpoint with an address >= to "addr"
92 iterator pos = m_breakpoints.lower_bound(addr);
93 if (pos != end) {
94 if (pos != m_breakpoints.begin()) {
95 // Watch out for a breakpoint at an address less than "addr" that might
96 // still overlap
97 iterator prev_pos = pos;
98 --prev_pos;
99 if (prev_pos->second.IntersectsRange(addr, size, NULL, NULL, NULL))
100 bps.push_back(&pos->second);
Greg Claytond8cf1a12013-06-12 00:46:38 +0000101 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000102
Kate Stoneb9c1b512016-09-06 20:57:50 +0000103 while (pos != end) {
104 // When we hit a breakpoint whose start address is greater than "addr +
105 // size" we are done.
106 // Do the math in a way that doesn't risk unsigned overflow with bad
107 // input.
108 if ((pos->second.Address() - addr) >= size)
109 break;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000110
Kate Stoneb9c1b512016-09-06 20:57:50 +0000111 // Check if this breakpoint overlaps, and if it does, add it to the list
112 if (pos->second.IntersectsRange(addr, size, NULL, NULL, NULL)) {
113 bps.push_back(&pos->second);
Greg Claytond8cf1a12013-06-12 00:46:38 +0000114 ++pos;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000115 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000116 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000117 }
118 return bps.size();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000119}
120
Kate Stoneb9c1b512016-09-06 20:57:50 +0000121void DNBBreakpointList::Dump() const {
122 const_iterator pos;
123 const_iterator end = m_breakpoints.end();
124 for (pos = m_breakpoints.begin(); pos != end; ++pos)
125 pos->second.Dump();
Greg Claytond8cf1a12013-06-12 00:46:38 +0000126}
127
Kate Stoneb9c1b512016-09-06 20:57:50 +0000128void DNBBreakpointList::DisableAll() {
129 iterator pos, end = m_breakpoints.end();
130 for (pos = m_breakpoints.begin(); pos != end; ++pos)
131 pos->second.SetEnabled(false);
Greg Claytond8cf1a12013-06-12 00:46:38 +0000132}
133
Kate Stoneb9c1b512016-09-06 20:57:50 +0000134void DNBBreakpointList::RemoveTrapsFromBuffer(nub_addr_t addr, nub_size_t size,
135 void *p) const {
136 uint8_t *buf = (uint8_t *)p;
137 const_iterator end = m_breakpoints.end();
138 const_iterator pos = m_breakpoints.lower_bound(addr);
139 while (pos != end && (pos->first < (addr + size))) {
140 nub_addr_t intersect_addr;
141 nub_size_t intersect_size;
142 nub_size_t opcode_offset;
143 const DNBBreakpoint &bp = pos->second;
144 if (bp.IntersectsRange(addr, size, &intersect_addr, &intersect_size,
145 &opcode_offset)) {
146 assert(addr <= intersect_addr && intersect_addr < addr + size);
147 assert(addr < intersect_addr + intersect_size &&
148 intersect_addr + intersect_size <= addr + size);
149 assert(opcode_offset + intersect_size <= bp.ByteSize());
150 nub_size_t buf_offset = intersect_addr - addr;
151 ::memcpy(buf + buf_offset, bp.SavedOpcodeBytes() + opcode_offset,
152 intersect_size);
Greg Claytond8cf1a12013-06-12 00:46:38 +0000153 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000154 ++pos;
155 }
156}
157
158void DNBBreakpointList::DisableAllBreakpoints(MachProcess *process) {
159 iterator pos, end = m_breakpoints.end();
160 for (pos = m_breakpoints.begin(); pos != end; ++pos)
161 process->DisableBreakpoint(pos->second.Address(), false);
162}
163
164void DNBBreakpointList::DisableAllWatchpoints(MachProcess *process) {
165 iterator pos, end = m_breakpoints.end();
166 for (pos = m_breakpoints.begin(); pos != end; ++pos)
167 process->DisableWatchpoint(pos->second.Address(), false);
168}
169
170void DNBBreakpointList::RemoveDisabled() {
171 iterator pos = m_breakpoints.begin();
172 while (pos != m_breakpoints.end()) {
173 if (!pos->second.IsEnabled())
174 pos = m_breakpoints.erase(pos);
175 else
176 ++pos;
177 }
Greg Claytond8cf1a12013-06-12 00:46:38 +0000178}