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 "DNBLog.h" 16 #include "MachProcess.h" 17 #include <algorithm> 18 #include <assert.h> 19 #include <inttypes.h> 20 21 #pragma mark-- DNBBreakpoint 22 DNBBreakpoint::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) {} 28 29 DNBBreakpoint::~DNBBreakpoint() {} 30 31 void 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 } 45 } 46 47 #pragma mark-- DNBBreakpointList 48 49 DNBBreakpointList::DNBBreakpointList() {} 50 51 DNBBreakpointList::~DNBBreakpointList() {} 52 53 DNBBreakpoint *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; 59 } 60 61 bool 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; 68 } 69 70 DNBBreakpoint *DNBBreakpointList::FindByAddress(nub_addr_t addr) { 71 iterator pos = m_breakpoints.find(addr); 72 if (pos != m_breakpoints.end()) 73 return &pos->second; 74 75 return NULL; 76 } 77 78 const 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; 82 83 return NULL; 84 } 85 86 // Finds the next breakpoint at an address greater than or equal to "addr" 87 size_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); 101 } 102 103 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; 110 111 // 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); 114 ++pos; 115 } 116 } 117 } 118 return bps.size(); 119 } 120 121 void 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(); 126 } 127 128 void DNBBreakpointList::DisableAll() { 129 iterator pos, end = m_breakpoints.end(); 130 for (pos = m_breakpoints.begin(); pos != end; ++pos) 131 pos->second.SetEnabled(false); 132 } 133 134 void 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); 153 } 154 ++pos; 155 } 156 } 157 158 void 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 164 void 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 170 void 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 } 178 } 179