1dda28197Spatrick //===-- BreakpointSite.cpp ------------------------------------------------===// 2061da546Spatrick // 3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information. 5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6061da546Spatrick // 7061da546Spatrick //===----------------------------------------------------------------------===// 8061da546Spatrick 9*be691f3bSpatrick #include <cinttypes> 10061da546Spatrick 11061da546Spatrick #include "lldb/Breakpoint/BreakpointSite.h" 12061da546Spatrick 13061da546Spatrick #include "lldb/Breakpoint/Breakpoint.h" 14061da546Spatrick #include "lldb/Breakpoint/BreakpointLocation.h" 15061da546Spatrick #include "lldb/Breakpoint/BreakpointSiteList.h" 16061da546Spatrick #include "lldb/Utility/Stream.h" 17061da546Spatrick 18061da546Spatrick using namespace lldb; 19061da546Spatrick using namespace lldb_private; 20061da546Spatrick 21061da546Spatrick BreakpointSite::BreakpointSite(BreakpointSiteList *list, 22061da546Spatrick const BreakpointLocationSP &owner, 23061da546Spatrick lldb::addr_t addr, bool use_hardware) 24*be691f3bSpatrick : StoppointSite(GetNextID(), addr, 0, use_hardware), 25061da546Spatrick m_type(eSoftware), // Process subclasses need to set this correctly using 26061da546Spatrick // SetType() 27061da546Spatrick m_saved_opcode(), m_trap_opcode(), 28061da546Spatrick m_enabled(false), // Need to create it disabled, so the first enable turns 29061da546Spatrick // it on. 30061da546Spatrick m_owners(), m_owners_mutex() { 31061da546Spatrick m_owners.Add(owner); 32061da546Spatrick } 33061da546Spatrick 34061da546Spatrick BreakpointSite::~BreakpointSite() { 35061da546Spatrick BreakpointLocationSP bp_loc_sp; 36061da546Spatrick const size_t owner_count = m_owners.GetSize(); 37061da546Spatrick for (size_t i = 0; i < owner_count; i++) { 38061da546Spatrick m_owners.GetByIndex(i)->ClearBreakpointSite(); 39061da546Spatrick } 40061da546Spatrick } 41061da546Spatrick 42061da546Spatrick break_id_t BreakpointSite::GetNextID() { 43061da546Spatrick static break_id_t g_next_id = 0; 44061da546Spatrick return ++g_next_id; 45061da546Spatrick } 46061da546Spatrick 47061da546Spatrick // RETURNS - true if we should stop at this breakpoint, false if we 48061da546Spatrick // should continue. 49061da546Spatrick 50061da546Spatrick bool BreakpointSite::ShouldStop(StoppointCallbackContext *context) { 51*be691f3bSpatrick m_hit_counter.Increment(); 52061da546Spatrick // ShouldStop can do a lot of work, and might even come come back and hit 53061da546Spatrick // this breakpoint site again. So don't hold the m_owners_mutex the whole 54061da546Spatrick // while. Instead make a local copy of the collection and call ShouldStop on 55061da546Spatrick // the copy. 56061da546Spatrick BreakpointLocationCollection owners_copy; 57061da546Spatrick { 58061da546Spatrick std::lock_guard<std::recursive_mutex> guard(m_owners_mutex); 59061da546Spatrick owners_copy = m_owners; 60061da546Spatrick } 61061da546Spatrick return owners_copy.ShouldStop(context); 62061da546Spatrick } 63061da546Spatrick 64061da546Spatrick bool BreakpointSite::IsBreakpointAtThisSite(lldb::break_id_t bp_id) { 65061da546Spatrick std::lock_guard<std::recursive_mutex> guard(m_owners_mutex); 66061da546Spatrick const size_t owner_count = m_owners.GetSize(); 67061da546Spatrick for (size_t i = 0; i < owner_count; i++) { 68061da546Spatrick if (m_owners.GetByIndex(i)->GetBreakpoint().GetID() == bp_id) 69061da546Spatrick return true; 70061da546Spatrick } 71061da546Spatrick return false; 72061da546Spatrick } 73061da546Spatrick 74061da546Spatrick void BreakpointSite::Dump(Stream *s) const { 75061da546Spatrick if (s == nullptr) 76061da546Spatrick return; 77061da546Spatrick 78061da546Spatrick s->Printf("BreakpointSite %u: addr = 0x%8.8" PRIx64 79061da546Spatrick " type = %s breakpoint hw_index = %i hit_count = %-4u", 80061da546Spatrick GetID(), (uint64_t)m_addr, IsHardware() ? "hardware" : "software", 81061da546Spatrick GetHardwareIndex(), GetHitCount()); 82061da546Spatrick } 83061da546Spatrick 84061da546Spatrick void BreakpointSite::GetDescription(Stream *s, lldb::DescriptionLevel level) { 85061da546Spatrick std::lock_guard<std::recursive_mutex> guard(m_owners_mutex); 86061da546Spatrick if (level != lldb::eDescriptionLevelBrief) 87061da546Spatrick s->Printf("breakpoint site: %d at 0x%8.8" PRIx64, GetID(), 88061da546Spatrick GetLoadAddress()); 89061da546Spatrick m_owners.GetDescription(s, level); 90061da546Spatrick } 91061da546Spatrick 92061da546Spatrick bool BreakpointSite::IsInternal() const { return m_owners.IsInternal(); } 93061da546Spatrick 94061da546Spatrick uint8_t *BreakpointSite::GetTrapOpcodeBytes() { return &m_trap_opcode[0]; } 95061da546Spatrick 96061da546Spatrick const uint8_t *BreakpointSite::GetTrapOpcodeBytes() const { 97061da546Spatrick return &m_trap_opcode[0]; 98061da546Spatrick } 99061da546Spatrick 100061da546Spatrick size_t BreakpointSite::GetTrapOpcodeMaxByteSize() const { 101061da546Spatrick return sizeof(m_trap_opcode); 102061da546Spatrick } 103061da546Spatrick 104061da546Spatrick bool BreakpointSite::SetTrapOpcode(const uint8_t *trap_opcode, 105061da546Spatrick uint32_t trap_opcode_size) { 106061da546Spatrick if (trap_opcode_size > 0 && trap_opcode_size <= sizeof(m_trap_opcode)) { 107061da546Spatrick m_byte_size = trap_opcode_size; 108061da546Spatrick ::memcpy(m_trap_opcode, trap_opcode, trap_opcode_size); 109061da546Spatrick return true; 110061da546Spatrick } 111061da546Spatrick m_byte_size = 0; 112061da546Spatrick return false; 113061da546Spatrick } 114061da546Spatrick 115061da546Spatrick uint8_t *BreakpointSite::GetSavedOpcodeBytes() { return &m_saved_opcode[0]; } 116061da546Spatrick 117061da546Spatrick const uint8_t *BreakpointSite::GetSavedOpcodeBytes() const { 118061da546Spatrick return &m_saved_opcode[0]; 119061da546Spatrick } 120061da546Spatrick 121061da546Spatrick bool BreakpointSite::IsEnabled() const { return m_enabled; } 122061da546Spatrick 123061da546Spatrick void BreakpointSite::SetEnabled(bool enabled) { m_enabled = enabled; } 124061da546Spatrick 125061da546Spatrick void BreakpointSite::AddOwner(const BreakpointLocationSP &owner) { 126061da546Spatrick std::lock_guard<std::recursive_mutex> guard(m_owners_mutex); 127061da546Spatrick m_owners.Add(owner); 128061da546Spatrick } 129061da546Spatrick 130061da546Spatrick size_t BreakpointSite::RemoveOwner(lldb::break_id_t break_id, 131061da546Spatrick lldb::break_id_t break_loc_id) { 132061da546Spatrick std::lock_guard<std::recursive_mutex> guard(m_owners_mutex); 133061da546Spatrick m_owners.Remove(break_id, break_loc_id); 134061da546Spatrick return m_owners.GetSize(); 135061da546Spatrick } 136061da546Spatrick 137061da546Spatrick size_t BreakpointSite::GetNumberOfOwners() { 138061da546Spatrick std::lock_guard<std::recursive_mutex> guard(m_owners_mutex); 139061da546Spatrick return m_owners.GetSize(); 140061da546Spatrick } 141061da546Spatrick 142061da546Spatrick BreakpointLocationSP BreakpointSite::GetOwnerAtIndex(size_t index) { 143061da546Spatrick std::lock_guard<std::recursive_mutex> guard(m_owners_mutex); 144061da546Spatrick return m_owners.GetByIndex(index); 145061da546Spatrick } 146061da546Spatrick 147*be691f3bSpatrick bool BreakpointSite::ValidForThisThread(Thread &thread) { 148061da546Spatrick std::lock_guard<std::recursive_mutex> guard(m_owners_mutex); 149061da546Spatrick return m_owners.ValidForThisThread(thread); 150061da546Spatrick } 151061da546Spatrick 152061da546Spatrick void BreakpointSite::BumpHitCounts() { 153061da546Spatrick std::lock_guard<std::recursive_mutex> guard(m_owners_mutex); 154061da546Spatrick for (BreakpointLocationSP loc_sp : m_owners.BreakpointLocations()) { 155061da546Spatrick loc_sp->BumpHitCount(); 156061da546Spatrick } 157061da546Spatrick } 158061da546Spatrick 159061da546Spatrick bool BreakpointSite::IntersectsRange(lldb::addr_t addr, size_t size, 160061da546Spatrick lldb::addr_t *intersect_addr, 161061da546Spatrick size_t *intersect_size, 162061da546Spatrick size_t *opcode_offset) const { 163*be691f3bSpatrick // The function should be called only for software breakpoints. 164*be691f3bSpatrick lldbassert(GetType() == Type::eSoftware); 165*be691f3bSpatrick 166*be691f3bSpatrick if (m_byte_size == 0) 167*be691f3bSpatrick return false; 168*be691f3bSpatrick 169061da546Spatrick const lldb::addr_t bp_end_addr = m_addr + m_byte_size; 170061da546Spatrick const lldb::addr_t end_addr = addr + size; 171061da546Spatrick // Is the breakpoint end address before the passed in start address? 172061da546Spatrick if (bp_end_addr <= addr) 173061da546Spatrick return false; 174*be691f3bSpatrick 175061da546Spatrick // Is the breakpoint start address after passed in end address? 176061da546Spatrick if (end_addr <= m_addr) 177061da546Spatrick return false; 178*be691f3bSpatrick 179061da546Spatrick if (intersect_addr || intersect_size || opcode_offset) { 180061da546Spatrick if (m_addr < addr) { 181061da546Spatrick if (intersect_addr) 182061da546Spatrick *intersect_addr = addr; 183061da546Spatrick if (intersect_size) 184061da546Spatrick *intersect_size = 185061da546Spatrick std::min<lldb::addr_t>(bp_end_addr, end_addr) - addr; 186061da546Spatrick if (opcode_offset) 187061da546Spatrick *opcode_offset = addr - m_addr; 188061da546Spatrick } else { 189061da546Spatrick if (intersect_addr) 190061da546Spatrick *intersect_addr = m_addr; 191061da546Spatrick if (intersect_size) 192061da546Spatrick *intersect_size = 193061da546Spatrick std::min<lldb::addr_t>(bp_end_addr, end_addr) - m_addr; 194061da546Spatrick if (opcode_offset) 195061da546Spatrick *opcode_offset = 0; 196061da546Spatrick } 197061da546Spatrick } 198061da546Spatrick return true; 199061da546Spatrick } 200061da546Spatrick 201061da546Spatrick size_t 202061da546Spatrick BreakpointSite::CopyOwnersList(BreakpointLocationCollection &out_collection) { 203061da546Spatrick std::lock_guard<std::recursive_mutex> guard(m_owners_mutex); 204061da546Spatrick for (BreakpointLocationSP loc_sp : m_owners.BreakpointLocations()) { 205061da546Spatrick out_collection.Add(loc_sp); 206061da546Spatrick } 207061da546Spatrick return out_collection.GetSize(); 208061da546Spatrick } 209