forked from OSchip/llvm-project
179 lines
5.9 KiB
C++
179 lines
5.9 KiB
C++
//===-- 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 "DNBLog.h"
|
|
#include "MachProcess.h"
|
|
#include <algorithm>
|
|
#include <assert.h>
|
|
#include <inttypes.h>
|
|
|
|
#pragma mark-- DNBBreakpoint
|
|
DNBBreakpoint::DNBBreakpoint(nub_addr_t addr, nub_size_t byte_size,
|
|
bool hardware)
|
|
: m_retain_count(1), m_byte_size(static_cast<uint32_t>(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) {}
|
|
|
|
DNBBreakpoint::~DNBBreakpoint() {}
|
|
|
|
void DNBBreakpoint::Dump() const {
|
|
if (IsBreakpoint()) {
|
|
DNBLog("DNBBreakpoint addr = 0x%llx state = %s type = %s breakpoint "
|
|
"hw_index = %i",
|
|
(uint64_t)m_addr, m_enabled ? "enabled " : "disabled",
|
|
IsHardware() ? "hardware" : "software", GetHardwareIndex());
|
|
} else {
|
|
DNBLog("DNBBreakpoint addr = 0x%llx size = %llu state = %s type = %s "
|
|
"watchpoint (%s%s) hw_index = %i",
|
|
(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());
|
|
}
|
|
}
|
|
|
|
#pragma mark-- DNBBreakpointList
|
|
|
|
DNBBreakpointList::DNBBreakpointList() {}
|
|
|
|
DNBBreakpointList::~DNBBreakpointList() {}
|
|
|
|
DNBBreakpoint *DNBBreakpointList::Add(nub_addr_t addr, nub_size_t length,
|
|
bool hardware) {
|
|
m_breakpoints.insert(
|
|
std::make_pair(addr, DNBBreakpoint(addr, length, hardware)));
|
|
iterator pos = m_breakpoints.find(addr);
|
|
return &pos->second;
|
|
}
|
|
|
|
bool DNBBreakpointList::Remove(nub_addr_t addr) {
|
|
iterator pos = m_breakpoints.find(addr);
|
|
if (pos != m_breakpoints.end()) {
|
|
m_breakpoints.erase(pos);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
DNBBreakpoint *DNBBreakpointList::FindByAddress(nub_addr_t addr) {
|
|
iterator pos = m_breakpoints.find(addr);
|
|
if (pos != m_breakpoints.end())
|
|
return &pos->second;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
const DNBBreakpoint *DNBBreakpointList::FindByAddress(nub_addr_t addr) const {
|
|
const_iterator pos = m_breakpoints.find(addr);
|
|
if (pos != m_breakpoints.end())
|
|
return &pos->second;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
// Finds the next breakpoint at an address greater than or equal to "addr"
|
|
size_t DNBBreakpointList::FindBreakpointsThatOverlapRange(
|
|
nub_addr_t addr, nub_addr_t size, std::vector<DNBBreakpoint *> &bps) {
|
|
bps.clear();
|
|
iterator end = m_breakpoints.end();
|
|
// Find the first breakpoint with an address >= to "addr"
|
|
iterator pos = m_breakpoints.lower_bound(addr);
|
|
if (pos != end) {
|
|
if (pos != m_breakpoints.begin()) {
|
|
// Watch out for a breakpoint at an address less than "addr" that might
|
|
// still overlap
|
|
iterator prev_pos = pos;
|
|
--prev_pos;
|
|
if (prev_pos->second.IntersectsRange(addr, size, NULL, NULL, NULL))
|
|
bps.push_back(&pos->second);
|
|
}
|
|
|
|
while (pos != end) {
|
|
// When we hit a breakpoint whose start address is greater than "addr +
|
|
// size" we are done.
|
|
// Do the math in a way that doesn't risk unsigned overflow with bad
|
|
// input.
|
|
if ((pos->second.Address() - addr) >= size)
|
|
break;
|
|
|
|
// Check if this breakpoint overlaps, and if it does, add it to the list
|
|
if (pos->second.IntersectsRange(addr, size, NULL, NULL, NULL)) {
|
|
bps.push_back(&pos->second);
|
|
++pos;
|
|
}
|
|
}
|
|
}
|
|
return bps.size();
|
|
}
|
|
|
|
void DNBBreakpointList::Dump() const {
|
|
const_iterator pos;
|
|
const_iterator end = m_breakpoints.end();
|
|
for (pos = m_breakpoints.begin(); pos != end; ++pos)
|
|
pos->second.Dump();
|
|
}
|
|
|
|
void DNBBreakpointList::DisableAll() {
|
|
iterator pos, end = m_breakpoints.end();
|
|
for (pos = m_breakpoints.begin(); pos != end; ++pos)
|
|
pos->second.SetEnabled(false);
|
|
}
|
|
|
|
void DNBBreakpointList::RemoveTrapsFromBuffer(nub_addr_t addr, nub_size_t size,
|
|
void *p) const {
|
|
uint8_t *buf = (uint8_t *)p;
|
|
const_iterator end = m_breakpoints.end();
|
|
const_iterator pos = m_breakpoints.lower_bound(addr);
|
|
while (pos != end && (pos->first < (addr + size))) {
|
|
nub_addr_t intersect_addr;
|
|
nub_size_t intersect_size;
|
|
nub_size_t opcode_offset;
|
|
const DNBBreakpoint &bp = pos->second;
|
|
if (bp.IntersectsRange(addr, size, &intersect_addr, &intersect_size,
|
|
&opcode_offset)) {
|
|
assert(addr <= intersect_addr && intersect_addr < addr + size);
|
|
assert(addr < intersect_addr + intersect_size &&
|
|
intersect_addr + intersect_size <= addr + size);
|
|
assert(opcode_offset + intersect_size <= bp.ByteSize());
|
|
nub_size_t buf_offset = intersect_addr - addr;
|
|
::memcpy(buf + buf_offset, bp.SavedOpcodeBytes() + opcode_offset,
|
|
intersect_size);
|
|
}
|
|
++pos;
|
|
}
|
|
}
|
|
|
|
void DNBBreakpointList::DisableAllBreakpoints(MachProcess *process) {
|
|
iterator pos, end = m_breakpoints.end();
|
|
for (pos = m_breakpoints.begin(); pos != end; ++pos)
|
|
process->DisableBreakpoint(pos->second.Address(), false);
|
|
}
|
|
|
|
void DNBBreakpointList::DisableAllWatchpoints(MachProcess *process) {
|
|
iterator pos, end = m_breakpoints.end();
|
|
for (pos = m_breakpoints.begin(); pos != end; ++pos)
|
|
process->DisableWatchpoint(pos->second.Address(), false);
|
|
}
|
|
|
|
void DNBBreakpointList::RemoveDisabled() {
|
|
iterator pos = m_breakpoints.begin();
|
|
while (pos != m_breakpoints.end()) {
|
|
if (!pos->second.IsEnabled())
|
|
pos = m_breakpoints.erase(pos);
|
|
else
|
|
++pos;
|
|
}
|
|
}
|