//===-- DNBBreakpoint.cpp ---------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // Created by Greg Clayton on 6/29/07. // //===----------------------------------------------------------------------===// #include "DNBBreakpoint.h" #include #include "DNBLog.h" #pragma mark -- DNBBreakpoint DNBBreakpoint::DNBBreakpoint(nub_addr_t addr, nub_size_t byte_size, nub_thread_t tid, bool hardware) : m_breakID(GetNextID()), m_tid(tid), m_byte_size(byte_size), m_opcode(), m_addr(addr), m_enabled(0), m_hw_preferred(hardware), m_is_watchpoint(0), m_watch_read(0), m_watch_write(0), m_hw_index(INVALID_NUB_HW_INDEX), m_hit_count(0), m_ignore_count(0), m_callback(NULL), m_callback_baton(NULL) { } DNBBreakpoint::~DNBBreakpoint() { } nub_break_t DNBBreakpoint::GetNextID() { static uint32_t g_nextBreakID = 0; return ++g_nextBreakID; } void DNBBreakpoint::SetCallback(DNBCallbackBreakpointHit callback, void *callback_baton) { m_callback = callback; m_callback_baton = callback_baton; } // RETURNS - true if we should stop at this breakpoint, false if we // should continue. bool DNBBreakpoint::BreakpointHit(nub_process_t pid, nub_thread_t tid) { m_hit_count++; if (m_hit_count > m_ignore_count) { if (m_callback) return m_callback(pid, tid, GetID(), m_callback_baton); return true; } return false; } void DNBBreakpoint::Dump() const { if (IsBreakpoint()) { DNBLog("DNBBreakpoint %u: tid = %4.4x addr = %8.8p state = %s type = %s breakpoint hw_index = %i hit_count = %-4u ignore_count = %-4u callback = %8.8p baton = %8.8p", m_breakID, m_tid, m_addr, m_enabled ? "enabled " : "disabled", IsHardware() ? "hardware" : "software", GetHardwareIndex(), GetHitCount(), GetIgnoreCount(), m_callback, m_callback_baton); } else { DNBLog("DNBBreakpoint %u: tid = %4.4x addr = %8.8p size = %u state = %s type = %s watchpoint (%s%s) hw_index = %i hit_count = %-4u ignore_count = %-4u callback = %8.8p baton = %8.8p", m_breakID, m_tid, m_addr, m_byte_size, m_enabled ? "enabled " : "disabled", IsHardware() ? "hardware" : "software", m_watch_read ? "r" : "", m_watch_write ? "w" : "", GetHardwareIndex(), GetHitCount(), GetIgnoreCount(), m_callback, m_callback_baton); } } #pragma mark -- DNBBreakpointList DNBBreakpointList::DNBBreakpointList() { } DNBBreakpointList::~DNBBreakpointList() { } nub_break_t DNBBreakpointList::Add(const DNBBreakpoint& bp) { m_breakpoints.push_back(bp); return m_breakpoints.back().GetID(); } bool DNBBreakpointList::ShouldStop(nub_process_t pid, nub_thread_t tid, nub_break_t breakID) { DNBBreakpoint *bp = FindByID (breakID); if (bp) { // Let the breakpoint decide if it should stop here (could not have // reached it's target hit count yet, or it could have a callback // that decided it shouldn't stop (shared library loads/unloads). return bp->BreakpointHit(pid, tid); } // We should stop here since this breakpoint isn't valid anymore or it // doesn't exist. return true; } nub_break_t DNBBreakpointList::FindIDByAddress (nub_addr_t addr) { DNBBreakpoint *bp = FindByAddress (addr); if (bp) { DNBLogThreadedIf(LOG_BREAKPOINTS, "DNBBreakpointList::%s ( addr = 0x%16.16llx ) => %u", __FUNCTION__, (uint64_t)addr, bp->GetID()); return bp->GetID(); } DNBLogThreadedIf(LOG_BREAKPOINTS, "DNBBreakpointList::%s ( addr = 0x%16.16llx ) => NONE", __FUNCTION__, (uint64_t)addr); return INVALID_NUB_BREAK_ID; } bool DNBBreakpointList::Remove (nub_break_t breakID) { iterator pos = GetBreakIDIterator(breakID); // Predicate if (pos != m_breakpoints.end()) { m_breakpoints.erase(pos); return true; } return false; } class BreakpointIDMatches { public: BreakpointIDMatches (nub_break_t breakID) : m_breakID(breakID) {} bool operator() (const DNBBreakpoint& bp) const { return m_breakID == bp.GetID(); } private: const nub_break_t m_breakID; }; class BreakpointAddressMatches { public: BreakpointAddressMatches (nub_addr_t addr) : m_addr(addr) {} bool operator() (const DNBBreakpoint& bp) const { return m_addr == bp.Address(); } private: const nub_addr_t m_addr; }; DNBBreakpointList::iterator DNBBreakpointList::GetBreakIDIterator (nub_break_t breakID) { return std::find_if(m_breakpoints.begin(), m_breakpoints.end(), // Search full range BreakpointIDMatches(breakID)); // Predicate } DNBBreakpointList::const_iterator DNBBreakpointList::GetBreakIDConstIterator (nub_break_t breakID) const { return std::find_if(m_breakpoints.begin(), m_breakpoints.end(), // Search full range BreakpointIDMatches(breakID)); // Predicate } DNBBreakpoint * DNBBreakpointList::FindByID (nub_break_t breakID) { iterator pos = GetBreakIDIterator(breakID); if (pos != m_breakpoints.end()) return &(*pos); return NULL; } const DNBBreakpoint * DNBBreakpointList::FindByID (nub_break_t breakID) const { const_iterator pos = GetBreakIDConstIterator(breakID); if (pos != m_breakpoints.end()) return &(*pos); return NULL; } DNBBreakpoint * DNBBreakpointList::FindByAddress (nub_addr_t addr) { iterator end = m_breakpoints.end(); iterator pos = std::find_if(m_breakpoints.begin(), end, // Search full range BreakpointAddressMatches(addr)); // Predicate if (pos != end) return &(*pos); return NULL; } const DNBBreakpoint * DNBBreakpointList::FindByAddress (nub_addr_t addr) const { const_iterator end = m_breakpoints.end(); const_iterator pos = std::find_if(m_breakpoints.begin(), end, // Search full range BreakpointAddressMatches(addr)); // Predicate if (pos != end) return &(*pos); return NULL; } bool DNBBreakpointList::SetCallback(nub_break_t breakID, DNBCallbackBreakpointHit callback, void *callback_baton) { DNBBreakpoint *bp = FindByID (breakID); if (bp) { bp->SetCallback(callback, callback_baton); return true; } return false; } void DNBBreakpointList::Dump() const { const_iterator pos; const_iterator end = m_breakpoints.end(); for (pos = m_breakpoints.begin(); pos != end; ++pos) (*pos).Dump(); } DNBBreakpoint * DNBBreakpointList::GetByIndex (uint32_t i) { iterator end = m_breakpoints.end(); iterator pos; uint32_t curr_i = 0; for (pos = m_breakpoints.begin(), curr_i = 0; pos != end; ++pos, ++curr_i) { if (curr_i == i) return &(*pos); } return NULL; } const DNBBreakpoint * DNBBreakpointList::GetByIndex (uint32_t i) const { const_iterator end = m_breakpoints.end(); const_iterator pos; uint32_t curr_i = 0; for (pos = m_breakpoints.begin(), curr_i = 0; pos != end; ++pos, ++curr_i) { if (curr_i == i) return &(*pos); } return NULL; }