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 <algorithm> 16 #include <inttypes.h> 17 #include "DNBLog.h" 18 19 20 #pragma mark -- DNBBreakpoint 21 DNBBreakpoint::DNBBreakpoint(nub_addr_t addr, nub_size_t byte_size, nub_thread_t tid, bool hardware) : 22 m_breakID(GetNextID()), 23 m_tid(tid), 24 m_byte_size(byte_size), 25 m_opcode(), 26 m_addr(addr), 27 m_enabled(0), 28 m_hw_preferred(hardware), 29 m_is_watchpoint(0), 30 m_watch_read(0), 31 m_watch_write(0), 32 m_hw_index(INVALID_NUB_HW_INDEX), 33 m_hit_count(0), 34 m_ignore_count(0), 35 m_callback(NULL), 36 m_callback_baton(NULL) 37 { 38 } 39 40 DNBBreakpoint::~DNBBreakpoint() 41 { 42 } 43 44 nub_break_t 45 DNBBreakpoint::GetNextID() 46 { 47 static uint32_t g_nextBreakID = 0; 48 return ++g_nextBreakID; 49 } 50 51 void 52 DNBBreakpoint::SetCallback(DNBCallbackBreakpointHit callback, void *callback_baton) 53 { 54 m_callback = callback; 55 m_callback_baton = callback_baton; 56 } 57 58 59 // RETURNS - true if we should stop at this breakpoint, false if we 60 // should continue. 61 62 bool 63 DNBBreakpoint::BreakpointHit(nub_process_t pid, nub_thread_t tid) 64 { 65 m_hit_count++; 66 67 if (m_hit_count > m_ignore_count) 68 { 69 if (m_callback) 70 return m_callback(pid, tid, GetID(), m_callback_baton); 71 return true; 72 } 73 return false; 74 } 75 76 void 77 DNBBreakpoint::Dump() const 78 { 79 if (IsBreakpoint()) 80 { 81 DNBLog ("DNBBreakpoint %u: tid = %8.8" PRIx64 " addr = 0x%llx state = %s type = %s breakpoint hw_index = %i hit_count = %-4u ignore_count = %-4u callback = %p baton = %p", 82 m_breakID, 83 m_tid, 84 (uint64_t)m_addr, 85 m_enabled ? "enabled " : "disabled", 86 IsHardware() ? "hardware" : "software", 87 GetHardwareIndex(), 88 GetHitCount(), 89 GetIgnoreCount(), 90 m_callback, 91 m_callback_baton); 92 } 93 else 94 { 95 DNBLog ("DNBBreakpoint %u: tid = %8.8" PRIx64 " addr = 0x%llx size = %llu state = %s type = %s watchpoint (%s%s) hw_index = %i hit_count = %-4u ignore_count = %-4u callback = %p baton = %p", 96 m_breakID, 97 m_tid, 98 (uint64_t)m_addr, 99 (uint64_t)m_byte_size, 100 m_enabled ? "enabled " : "disabled", 101 IsHardware() ? "hardware" : "software", 102 m_watch_read ? "r" : "", 103 m_watch_write ? "w" : "", 104 GetHardwareIndex(), 105 GetHitCount(), 106 GetIgnoreCount(), 107 m_callback, 108 m_callback_baton); 109 } 110 } 111 112 #pragma mark -- DNBBreakpointList 113 114 DNBBreakpointList::DNBBreakpointList() 115 { 116 } 117 118 DNBBreakpointList::~DNBBreakpointList() 119 { 120 } 121 122 123 nub_break_t 124 DNBBreakpointList::Add(const DNBBreakpoint& bp) 125 { 126 m_breakpoints.push_back(bp); 127 return m_breakpoints.back().GetID(); 128 } 129 130 bool 131 DNBBreakpointList::ShouldStop(nub_process_t pid, nub_thread_t tid, nub_break_t breakID) 132 { 133 DNBBreakpoint *bp = FindByID (breakID); 134 if (bp) 135 { 136 // Let the breakpoint decide if it should stop here (could not have 137 // reached it's target hit count yet, or it could have a callback 138 // that decided it shouldn't stop (shared library loads/unloads). 139 return bp->BreakpointHit(pid, tid); 140 } 141 // We should stop here since this breakpoint isn't valid anymore or it 142 // doesn't exist. 143 return true; 144 } 145 146 nub_break_t 147 DNBBreakpointList::FindIDByAddress (nub_addr_t addr) 148 { 149 DNBBreakpoint *bp = FindByAddress (addr); 150 if (bp) 151 { 152 DNBLogThreadedIf(LOG_BREAKPOINTS, "DNBBreakpointList::%s ( addr = 0x%16.16llx ) => %u", __FUNCTION__, (uint64_t)addr, bp->GetID()); 153 return bp->GetID(); 154 } 155 DNBLogThreadedIf(LOG_BREAKPOINTS, "DNBBreakpointList::%s ( addr = 0x%16.16llx ) => NONE", __FUNCTION__, (uint64_t)addr); 156 return INVALID_NUB_BREAK_ID; 157 } 158 159 bool 160 DNBBreakpointList::Remove (nub_break_t breakID) 161 { 162 iterator pos = GetBreakIDIterator(breakID); // Predicate 163 if (pos != m_breakpoints.end()) 164 { 165 m_breakpoints.erase(pos); 166 return true; 167 } 168 return false; 169 } 170 171 172 class BreakpointIDMatches 173 { 174 public: 175 BreakpointIDMatches (nub_break_t breakID) : m_breakID(breakID) {} 176 bool operator() (const DNBBreakpoint& bp) const 177 { 178 return m_breakID == bp.GetID(); 179 } 180 private: 181 const nub_break_t m_breakID; 182 }; 183 184 class BreakpointAddressMatches 185 { 186 public: 187 BreakpointAddressMatches (nub_addr_t addr) : m_addr(addr) {} 188 bool operator() (const DNBBreakpoint& bp) const 189 { 190 return m_addr == bp.Address(); 191 } 192 private: 193 const nub_addr_t m_addr; 194 }; 195 196 DNBBreakpointList::iterator 197 DNBBreakpointList::GetBreakIDIterator (nub_break_t breakID) 198 { 199 return std::find_if(m_breakpoints.begin(), m_breakpoints.end(), // Search full range 200 BreakpointIDMatches(breakID)); // Predicate 201 } 202 203 DNBBreakpointList::const_iterator 204 DNBBreakpointList::GetBreakIDConstIterator (nub_break_t breakID) const 205 { 206 return std::find_if(m_breakpoints.begin(), m_breakpoints.end(), // Search full range 207 BreakpointIDMatches(breakID)); // Predicate 208 } 209 210 DNBBreakpoint * 211 DNBBreakpointList::FindByID (nub_break_t breakID) 212 { 213 iterator pos = GetBreakIDIterator(breakID); 214 if (pos != m_breakpoints.end()) 215 return &(*pos); 216 217 return NULL; 218 } 219 220 const DNBBreakpoint * 221 DNBBreakpointList::FindByID (nub_break_t breakID) const 222 { 223 const_iterator pos = GetBreakIDConstIterator(breakID); 224 if (pos != m_breakpoints.end()) 225 return &(*pos); 226 227 return NULL; 228 } 229 230 DNBBreakpoint * 231 DNBBreakpointList::FindByAddress (nub_addr_t addr) 232 { 233 iterator end = m_breakpoints.end(); 234 iterator pos = std::find_if(m_breakpoints.begin(), end, // Search full range 235 BreakpointAddressMatches(addr)); // Predicate 236 if (pos != end) 237 return &(*pos); 238 239 return NULL; 240 } 241 242 const DNBBreakpoint * 243 DNBBreakpointList::FindByAddress (nub_addr_t addr) const 244 { 245 const_iterator end = m_breakpoints.end(); 246 const_iterator pos = std::find_if(m_breakpoints.begin(), end, // Search full range 247 BreakpointAddressMatches(addr)); // Predicate 248 if (pos != end) 249 return &(*pos); 250 251 return NULL; 252 } 253 254 bool 255 DNBBreakpointList::SetCallback(nub_break_t breakID, DNBCallbackBreakpointHit callback, void *callback_baton) 256 { 257 DNBBreakpoint *bp = FindByID (breakID); 258 if (bp) 259 { 260 bp->SetCallback(callback, callback_baton); 261 return true; 262 } 263 return false; 264 } 265 266 267 void 268 DNBBreakpointList::Dump() const 269 { 270 const_iterator pos; 271 const_iterator end = m_breakpoints.end(); 272 for (pos = m_breakpoints.begin(); pos != end; ++pos) 273 (*pos).Dump(); 274 } 275 276 277 DNBBreakpoint * 278 DNBBreakpointList::GetByIndex (uint32_t i) 279 { 280 iterator end = m_breakpoints.end(); 281 iterator pos; 282 uint32_t curr_i = 0; 283 for (pos = m_breakpoints.begin(), curr_i = 0; pos != end; ++pos, ++curr_i) 284 { 285 if (curr_i == i) 286 return &(*pos); 287 } 288 return NULL; 289 } 290 291 void 292 DNBBreakpointList::DisableAll () 293 { 294 iterator pos, end = m_breakpoints.end(); 295 for (pos = m_breakpoints.begin(); pos != end; ++pos) 296 (*pos).SetEnabled(false); 297 } 298 299 300 const DNBBreakpoint * 301 DNBBreakpointList::GetByIndex (uint32_t i) const 302 { 303 const_iterator end = m_breakpoints.end(); 304 const_iterator pos; 305 uint32_t curr_i = 0; 306 for (pos = m_breakpoints.begin(), curr_i = 0; pos != end; ++pos, ++curr_i) 307 { 308 if (curr_i == i) 309 return &(*pos); 310 } 311 return NULL; 312 } 313 314