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 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 37 DNBBreakpoint::~DNBBreakpoint() 38 { 39 } 40 41 void 42 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 67 DNBBreakpointList::DNBBreakpointList() 68 { 69 } 70 71 DNBBreakpointList::~DNBBreakpointList() 72 { 73 } 74 75 76 DNBBreakpoint * 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 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 * 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 * 107 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 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 157 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 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 175 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 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 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 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