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 23DNBBreakpoint::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 37DNBBreakpoint::~DNBBreakpoint() 38{ 39} 40 41void 42DNBBreakpoint::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 67DNBBreakpointList::DNBBreakpointList() 68{ 69} 70 71DNBBreakpointList::~DNBBreakpointList() 72{ 73} 74 75 76DNBBreakpoint * 77DNBBreakpointList::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 84bool 85DNBBreakpointList::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 96DNBBreakpoint * 97DNBBreakpointList::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 106const DNBBreakpoint * 107DNBBreakpointList::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" 117size_t 118DNBBreakpointList::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 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) 162 pos->second.Dump(); 163} 164 165void 166DNBBreakpointList::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 174void 175DNBBreakpointList::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 198void 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} 226