llvm-project/lldb/source/Host/common/NativeBreakpointList.cpp

221 lines
7.3 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 = %lu, 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 = %lu, 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 = %lu, 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();
}