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/Utility/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() {}
 | |
| 
 | |
| Status 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 Status();
 | |
|   }
 | |
| 
 | |
|   // 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;
 | |
|   Status 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;
 | |
| }
 | |
| 
 | |
| Status NativeBreakpointList::DecRef(lldb::addr_t addr) {
 | |
|   Status 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;
 | |
| }
 | |
| 
 | |
| Status 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 Status("breakpoint not found");
 | |
|   }
 | |
| 
 | |
|   // Enable it.
 | |
|   return iter->second->Enable();
 | |
| }
 | |
| 
 | |
| Status 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 Status("breakpoint not found");
 | |
|   }
 | |
| 
 | |
|   // Disable it.
 | |
|   return iter->second->Disable();
 | |
| }
 | |
| 
 | |
| Status 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 Status("breakpoint not found");
 | |
|   }
 | |
| 
 | |
|   // Disable it.
 | |
|   breakpoint_sp = iter->second;
 | |
|   return Status();
 | |
| }
 | |
| 
 | |
| Status 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 Status();
 | |
| }
 |