1 //===-- BreakpointSite.cpp --------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include <inttypes.h> 10 11 #include "lldb/Breakpoint/BreakpointSite.h" 12 13 #include "lldb/Breakpoint/Breakpoint.h" 14 #include "lldb/Breakpoint/BreakpointLocation.h" 15 #include "lldb/Breakpoint/BreakpointSiteList.h" 16 #include "lldb/Utility/Stream.h" 17 18 using namespace lldb; 19 using namespace lldb_private; 20 21 BreakpointSite::BreakpointSite(BreakpointSiteList *list, 22 const BreakpointLocationSP &owner, 23 lldb::addr_t addr, bool use_hardware) 24 : StoppointLocation(GetNextID(), addr, 0, use_hardware), 25 m_type(eSoftware), // Process subclasses need to set this correctly using 26 // SetType() 27 m_saved_opcode(), m_trap_opcode(), 28 m_enabled(false), // Need to create it disabled, so the first enable turns 29 // it on. 30 m_owners(), m_owners_mutex() { 31 m_owners.Add(owner); 32 } 33 34 BreakpointSite::~BreakpointSite() { 35 BreakpointLocationSP bp_loc_sp; 36 const size_t owner_count = m_owners.GetSize(); 37 for (size_t i = 0; i < owner_count; i++) { 38 m_owners.GetByIndex(i)->ClearBreakpointSite(); 39 } 40 } 41 42 break_id_t BreakpointSite::GetNextID() { 43 static break_id_t g_next_id = 0; 44 return ++g_next_id; 45 } 46 47 // RETURNS - true if we should stop at this breakpoint, false if we 48 // should continue. 49 50 bool BreakpointSite::ShouldStop(StoppointCallbackContext *context) { 51 std::lock_guard<std::recursive_mutex> guard(m_owners_mutex); 52 IncrementHitCount(); 53 return m_owners.ShouldStop(context); 54 } 55 56 bool BreakpointSite::IsBreakpointAtThisSite(lldb::break_id_t bp_id) { 57 std::lock_guard<std::recursive_mutex> guard(m_owners_mutex); 58 const size_t owner_count = m_owners.GetSize(); 59 for (size_t i = 0; i < owner_count; i++) { 60 if (m_owners.GetByIndex(i)->GetBreakpoint().GetID() == bp_id) 61 return true; 62 } 63 return false; 64 } 65 66 void BreakpointSite::Dump(Stream *s) const { 67 if (s == nullptr) 68 return; 69 70 s->Printf("BreakpointSite %u: addr = 0x%8.8" PRIx64 71 " type = %s breakpoint hw_index = %i hit_count = %-4u", 72 GetID(), (uint64_t)m_addr, IsHardware() ? "hardware" : "software", 73 GetHardwareIndex(), GetHitCount()); 74 } 75 76 void BreakpointSite::GetDescription(Stream *s, lldb::DescriptionLevel level) { 77 std::lock_guard<std::recursive_mutex> guard(m_owners_mutex); 78 if (level != lldb::eDescriptionLevelBrief) 79 s->Printf("breakpoint site: %d at 0x%8.8" PRIx64, GetID(), 80 GetLoadAddress()); 81 m_owners.GetDescription(s, level); 82 } 83 84 bool BreakpointSite::IsInternal() const { return m_owners.IsInternal(); } 85 86 uint8_t *BreakpointSite::GetTrapOpcodeBytes() { return &m_trap_opcode[0]; } 87 88 const uint8_t *BreakpointSite::GetTrapOpcodeBytes() const { 89 return &m_trap_opcode[0]; 90 } 91 92 size_t BreakpointSite::GetTrapOpcodeMaxByteSize() const { 93 return sizeof(m_trap_opcode); 94 } 95 96 bool BreakpointSite::SetTrapOpcode(const uint8_t *trap_opcode, 97 uint32_t trap_opcode_size) { 98 if (trap_opcode_size > 0 && trap_opcode_size <= sizeof(m_trap_opcode)) { 99 m_byte_size = trap_opcode_size; 100 ::memcpy(m_trap_opcode, trap_opcode, trap_opcode_size); 101 return true; 102 } 103 m_byte_size = 0; 104 return false; 105 } 106 107 uint8_t *BreakpointSite::GetSavedOpcodeBytes() { return &m_saved_opcode[0]; } 108 109 const uint8_t *BreakpointSite::GetSavedOpcodeBytes() const { 110 return &m_saved_opcode[0]; 111 } 112 113 bool BreakpointSite::IsEnabled() const { return m_enabled; } 114 115 void BreakpointSite::SetEnabled(bool enabled) { m_enabled = enabled; } 116 117 void BreakpointSite::AddOwner(const BreakpointLocationSP &owner) { 118 std::lock_guard<std::recursive_mutex> guard(m_owners_mutex); 119 m_owners.Add(owner); 120 } 121 122 size_t BreakpointSite::RemoveOwner(lldb::break_id_t break_id, 123 lldb::break_id_t break_loc_id) { 124 std::lock_guard<std::recursive_mutex> guard(m_owners_mutex); 125 m_owners.Remove(break_id, break_loc_id); 126 return m_owners.GetSize(); 127 } 128 129 size_t BreakpointSite::GetNumberOfOwners() { 130 std::lock_guard<std::recursive_mutex> guard(m_owners_mutex); 131 return m_owners.GetSize(); 132 } 133 134 BreakpointLocationSP BreakpointSite::GetOwnerAtIndex(size_t index) { 135 std::lock_guard<std::recursive_mutex> guard(m_owners_mutex); 136 return m_owners.GetByIndex(index); 137 } 138 139 bool BreakpointSite::ValidForThisThread(Thread *thread) { 140 std::lock_guard<std::recursive_mutex> guard(m_owners_mutex); 141 return m_owners.ValidForThisThread(thread); 142 } 143 144 void BreakpointSite::BumpHitCounts() { 145 std::lock_guard<std::recursive_mutex> guard(m_owners_mutex); 146 for (BreakpointLocationSP loc_sp : m_owners.BreakpointLocations()) { 147 loc_sp->BumpHitCount(); 148 } 149 } 150 151 bool BreakpointSite::IntersectsRange(lldb::addr_t addr, size_t size, 152 lldb::addr_t *intersect_addr, 153 size_t *intersect_size, 154 size_t *opcode_offset) const { 155 // We only use software traps for software breakpoints 156 if (!IsHardware()) { 157 if (m_byte_size > 0) { 158 const lldb::addr_t bp_end_addr = m_addr + m_byte_size; 159 const lldb::addr_t end_addr = addr + size; 160 // Is the breakpoint end address before the passed in start address? 161 if (bp_end_addr <= addr) 162 return false; 163 // Is the breakpoint start address after passed in end address? 164 if (end_addr <= m_addr) 165 return false; 166 if (intersect_addr || intersect_size || opcode_offset) { 167 if (m_addr < addr) { 168 if (intersect_addr) 169 *intersect_addr = addr; 170 if (intersect_size) 171 *intersect_size = 172 std::min<lldb::addr_t>(bp_end_addr, end_addr) - addr; 173 if (opcode_offset) 174 *opcode_offset = addr - m_addr; 175 } else { 176 if (intersect_addr) 177 *intersect_addr = m_addr; 178 if (intersect_size) 179 *intersect_size = 180 std::min<lldb::addr_t>(bp_end_addr, end_addr) - m_addr; 181 if (opcode_offset) 182 *opcode_offset = 0; 183 } 184 } 185 return true; 186 } 187 } 188 return false; 189 } 190 191 size_t 192 BreakpointSite::CopyOwnersList(BreakpointLocationCollection &out_collection) { 193 std::lock_guard<std::recursive_mutex> guard(m_owners_mutex); 194 for (BreakpointLocationSP loc_sp : m_owners.BreakpointLocations()) { 195 out_collection.Add(loc_sp); 196 } 197 return out_collection.GetSize(); 198 } 199