forked from OSchip/llvm-project
230 lines
7.5 KiB
C++
230 lines
7.5 KiB
C++
//===-- NativeBreakpointList.cpp --------------------------------*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "lldb/Host/common/NativeBreakpointList.h"
|
|
|
|
#include "lldb/Core/Log.h"
|
|
|
|
#include "lldb/Host/common/NativeBreakpoint.h"
|
|
#include "lldb/Host/common/SoftwareBreakpoint.h"
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
|
|
NativeBreakpointList::NativeBreakpointList() : m_mutex() {}
|
|
|
|
Error NativeBreakpointList::AddRef(lldb::addr_t addr, size_t size_hint,
|
|
bool hardware,
|
|
CreateBreakpointFunc create_func) {
|
|
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
|
|
if (log)
|
|
log->Printf("NativeBreakpointList::%s addr = 0x%" PRIx64
|
|
", size_hint = %zu, hardware = %s",
|
|
__FUNCTION__, addr, size_hint, hardware ? "true" : "false");
|
|
|
|
std::lock_guard<std::recursive_mutex> guard(m_mutex);
|
|
|
|
// Check if the breakpoint is already set.
|
|
auto iter = m_breakpoints.find(addr);
|
|
if (iter != m_breakpoints.end()) {
|
|
// Yes - bump up ref count.
|
|
if (log)
|
|
log->Printf("NativeBreakpointList::%s addr = 0x%" PRIx64
|
|
" -- already enabled, upping ref count",
|
|
__FUNCTION__, addr);
|
|
|
|
iter->second->AddRef();
|
|
return Error();
|
|
}
|
|
|
|
// Create a new breakpoint using the given create func.
|
|
if (log)
|
|
log->Printf(
|
|
"NativeBreakpointList::%s creating breakpoint for addr = 0x%" PRIx64
|
|
", size_hint = %zu, hardware = %s",
|
|
__FUNCTION__, addr, size_hint, hardware ? "true" : "false");
|
|
|
|
NativeBreakpointSP breakpoint_sp;
|
|
Error error = create_func(addr, size_hint, hardware, breakpoint_sp);
|
|
if (error.Fail()) {
|
|
if (log)
|
|
log->Printf(
|
|
"NativeBreakpointList::%s creating breakpoint for addr = 0x%" PRIx64
|
|
", size_hint = %zu, hardware = %s -- FAILED: %s",
|
|
__FUNCTION__, addr, size_hint, hardware ? "true" : "false",
|
|
error.AsCString());
|
|
return error;
|
|
}
|
|
|
|
// Remember the breakpoint.
|
|
assert(breakpoint_sp && "NativeBreakpoint create function succeeded but "
|
|
"returned NULL breakpoint");
|
|
m_breakpoints.insert(BreakpointMap::value_type(addr, breakpoint_sp));
|
|
|
|
return error;
|
|
}
|
|
|
|
Error NativeBreakpointList::DecRef(lldb::addr_t addr) {
|
|
Error error;
|
|
|
|
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
|
|
if (log)
|
|
log->Printf("NativeBreakpointList::%s addr = 0x%" PRIx64, __FUNCTION__,
|
|
addr);
|
|
|
|
std::lock_guard<std::recursive_mutex> guard(m_mutex);
|
|
|
|
// Check if the breakpoint is already set.
|
|
auto iter = m_breakpoints.find(addr);
|
|
if (iter == m_breakpoints.end()) {
|
|
// Not found!
|
|
if (log)
|
|
log->Printf("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- NOT FOUND",
|
|
__FUNCTION__, addr);
|
|
error.SetErrorString("breakpoint not found");
|
|
return error;
|
|
}
|
|
|
|
// Decrement ref count.
|
|
const int32_t new_ref_count = iter->second->DecRef();
|
|
assert(new_ref_count >= 0 && "NativeBreakpoint ref count went negative");
|
|
|
|
if (new_ref_count > 0) {
|
|
// Still references to this breakpoint. Leave it alone.
|
|
if (log)
|
|
log->Printf("NativeBreakpointList::%s addr = 0x%" PRIx64
|
|
" -- new breakpoint ref count %" PRIu32,
|
|
__FUNCTION__, addr, new_ref_count);
|
|
return error;
|
|
}
|
|
|
|
// Breakpoint has no more references. Disable it if it's not
|
|
// already disabled.
|
|
if (log)
|
|
log->Printf("NativeBreakpointList::%s addr = 0x%" PRIx64
|
|
" -- removing due to no remaining references",
|
|
__FUNCTION__, addr);
|
|
|
|
// If it's enabled, we need to disable it.
|
|
if (iter->second->IsEnabled()) {
|
|
if (log)
|
|
log->Printf("NativeBreakpointList::%s addr = 0x%" PRIx64
|
|
" -- currently enabled, now disabling",
|
|
__FUNCTION__, addr);
|
|
error = iter->second->Disable();
|
|
if (error.Fail()) {
|
|
if (log)
|
|
log->Printf("NativeBreakpointList::%s addr = 0x%" PRIx64
|
|
" -- removal FAILED: %s",
|
|
__FUNCTION__, addr, error.AsCString());
|
|
// Continue since we still want to take it out of the breakpoint list.
|
|
}
|
|
} else {
|
|
if (log)
|
|
log->Printf("NativeBreakpointList::%s addr = 0x%" PRIx64
|
|
" -- already disabled, nothing to do",
|
|
__FUNCTION__, addr);
|
|
}
|
|
|
|
// Take the breakpoint out of the list.
|
|
if (log)
|
|
log->Printf("NativeBreakpointList::%s addr = 0x%" PRIx64
|
|
" -- removed from breakpoint map",
|
|
__FUNCTION__, addr);
|
|
|
|
m_breakpoints.erase(iter);
|
|
return error;
|
|
}
|
|
|
|
Error NativeBreakpointList::EnableBreakpoint(lldb::addr_t addr) {
|
|
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
|
|
if (log)
|
|
log->Printf("NativeBreakpointList::%s addr = 0x%" PRIx64, __FUNCTION__,
|
|
addr);
|
|
|
|
std::lock_guard<std::recursive_mutex> guard(m_mutex);
|
|
|
|
// Ensure we have said breakpoint.
|
|
auto iter = m_breakpoints.find(addr);
|
|
if (iter == m_breakpoints.end()) {
|
|
// Not found!
|
|
if (log)
|
|
log->Printf("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- NOT FOUND",
|
|
__FUNCTION__, addr);
|
|
return Error("breakpoint not found");
|
|
}
|
|
|
|
// Enable it.
|
|
return iter->second->Enable();
|
|
}
|
|
|
|
Error NativeBreakpointList::DisableBreakpoint(lldb::addr_t addr) {
|
|
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
|
|
if (log)
|
|
log->Printf("NativeBreakpointList::%s addr = 0x%" PRIx64, __FUNCTION__,
|
|
addr);
|
|
|
|
std::lock_guard<std::recursive_mutex> guard(m_mutex);
|
|
|
|
// Ensure we have said breakpoint.
|
|
auto iter = m_breakpoints.find(addr);
|
|
if (iter == m_breakpoints.end()) {
|
|
// Not found!
|
|
if (log)
|
|
log->Printf("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- NOT FOUND",
|
|
__FUNCTION__, addr);
|
|
return Error("breakpoint not found");
|
|
}
|
|
|
|
// Disable it.
|
|
return iter->second->Disable();
|
|
}
|
|
|
|
Error NativeBreakpointList::GetBreakpoint(lldb::addr_t addr,
|
|
NativeBreakpointSP &breakpoint_sp) {
|
|
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
|
|
if (log)
|
|
log->Printf("NativeBreakpointList::%s addr = 0x%" PRIx64, __FUNCTION__,
|
|
addr);
|
|
|
|
std::lock_guard<std::recursive_mutex> guard(m_mutex);
|
|
|
|
// Ensure we have said breakpoint.
|
|
auto iter = m_breakpoints.find(addr);
|
|
if (iter == m_breakpoints.end()) {
|
|
// Not found!
|
|
breakpoint_sp.reset();
|
|
return Error("breakpoint not found");
|
|
}
|
|
|
|
// Disable it.
|
|
breakpoint_sp = iter->second;
|
|
return Error();
|
|
}
|
|
|
|
Error NativeBreakpointList::RemoveTrapsFromBuffer(lldb::addr_t addr, void *buf,
|
|
size_t size) const {
|
|
for (const auto &map : m_breakpoints) {
|
|
lldb::addr_t bp_addr = map.first;
|
|
// Breapoint not in range, ignore
|
|
if (bp_addr < addr || addr + size <= bp_addr)
|
|
continue;
|
|
const auto &bp_sp = map.second;
|
|
// Not software breakpoint, ignore
|
|
if (!bp_sp->IsSoftwareBreakpoint())
|
|
continue;
|
|
auto software_bp_sp = std::static_pointer_cast<SoftwareBreakpoint>(bp_sp);
|
|
auto opcode_addr = static_cast<char *>(buf) + bp_addr - addr;
|
|
auto saved_opcodes = software_bp_sp->m_saved_opcodes;
|
|
auto opcode_size = software_bp_sp->m_opcode_size;
|
|
::memcpy(opcode_addr, saved_opcodes, opcode_size);
|
|
}
|
|
return Error();
|
|
}
|