blob: 66706870305c0613e1041e8bedae3c507ddc5ff0 [file] [log] [blame]
//===-- 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 <algorithm>
#include <inttypes.h>
#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 = %8.8" PRIx64 " addr = 0x%llx state = %s type = %s breakpoint hw_index = %i hit_count = %-4u ignore_count = %-4u callback = %p baton = %p",
m_breakID,
m_tid,
(uint64_t)m_addr,
m_enabled ? "enabled " : "disabled",
IsHardware() ? "hardware" : "software",
GetHardwareIndex(),
GetHitCount(),
GetIgnoreCount(),
m_callback,
m_callback_baton);
}
else
{
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",
m_breakID,
m_tid,
(uint64_t)m_addr,
(uint64_t)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;
}
void
DNBBreakpointList::DisableAll ()
{
iterator pos, end = m_breakpoints.end();
for (pos = m_breakpoints.begin(); pos != end; ++pos)
(*pos).SetEnabled(false);
}
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;
}