xref: /openbsd-src/gnu/llvm/lldb/source/Breakpoint/BreakpointSite.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
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 
9be691f3bSpatrick #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 
BreakpointSite(BreakpointSiteList * list,const BreakpointLocationSP & owner,lldb::addr_t addr,bool use_hardware)21061da546Spatrick BreakpointSite::BreakpointSite(BreakpointSiteList *list,
22061da546Spatrick                                const BreakpointLocationSP &owner,
23061da546Spatrick                                lldb::addr_t addr, bool use_hardware)
24be691f3bSpatrick     : 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(),
28*f6aab3d8Srobert       m_enabled(false) // Need to create it disabled, so the first enable turns
29061da546Spatrick                        // it on.
30*f6aab3d8Srobert {
31061da546Spatrick   m_owners.Add(owner);
32061da546Spatrick }
33061da546Spatrick 
~BreakpointSite()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 
GetNextID()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 
ShouldStop(StoppointCallbackContext * context)50061da546Spatrick bool BreakpointSite::ShouldStop(StoppointCallbackContext *context) {
51be691f3bSpatrick   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 
IsBreakpointAtThisSite(lldb::break_id_t bp_id)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 
Dump(Stream * s) const74061da546Spatrick 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 
GetDescription(Stream * s,lldb::DescriptionLevel level)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 
IsInternal() const92061da546Spatrick bool BreakpointSite::IsInternal() const { return m_owners.IsInternal(); }
93061da546Spatrick 
GetTrapOpcodeBytes()94061da546Spatrick uint8_t *BreakpointSite::GetTrapOpcodeBytes() { return &m_trap_opcode[0]; }
95061da546Spatrick 
GetTrapOpcodeBytes() const96061da546Spatrick const uint8_t *BreakpointSite::GetTrapOpcodeBytes() const {
97061da546Spatrick   return &m_trap_opcode[0];
98061da546Spatrick }
99061da546Spatrick 
GetTrapOpcodeMaxByteSize() const100061da546Spatrick size_t BreakpointSite::GetTrapOpcodeMaxByteSize() const {
101061da546Spatrick   return sizeof(m_trap_opcode);
102061da546Spatrick }
103061da546Spatrick 
SetTrapOpcode(const uint8_t * trap_opcode,uint32_t trap_opcode_size)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 
GetSavedOpcodeBytes()115061da546Spatrick uint8_t *BreakpointSite::GetSavedOpcodeBytes() { return &m_saved_opcode[0]; }
116061da546Spatrick 
GetSavedOpcodeBytes() const117061da546Spatrick const uint8_t *BreakpointSite::GetSavedOpcodeBytes() const {
118061da546Spatrick   return &m_saved_opcode[0];
119061da546Spatrick }
120061da546Spatrick 
IsEnabled() const121061da546Spatrick bool BreakpointSite::IsEnabled() const { return m_enabled; }
122061da546Spatrick 
SetEnabled(bool enabled)123061da546Spatrick void BreakpointSite::SetEnabled(bool enabled) { m_enabled = enabled; }
124061da546Spatrick 
AddOwner(const BreakpointLocationSP & owner)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 
RemoveOwner(lldb::break_id_t break_id,lldb::break_id_t break_loc_id)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 
GetNumberOfOwners()137061da546Spatrick size_t BreakpointSite::GetNumberOfOwners() {
138061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
139061da546Spatrick   return m_owners.GetSize();
140061da546Spatrick }
141061da546Spatrick 
GetOwnerAtIndex(size_t index)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 
ValidForThisThread(Thread & thread)147be691f3bSpatrick bool BreakpointSite::ValidForThisThread(Thread &thread) {
148061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
149061da546Spatrick   return m_owners.ValidForThisThread(thread);
150061da546Spatrick }
151061da546Spatrick 
BumpHitCounts()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 
IntersectsRange(lldb::addr_t addr,size_t size,lldb::addr_t * intersect_addr,size_t * intersect_size,size_t * opcode_offset) const159061da546Spatrick 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 {
163be691f3bSpatrick   // The function should be called only for software breakpoints.
164be691f3bSpatrick   lldbassert(GetType() == Type::eSoftware);
165be691f3bSpatrick 
166be691f3bSpatrick   if (m_byte_size == 0)
167be691f3bSpatrick     return false;
168be691f3bSpatrick 
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;
174be691f3bSpatrick 
175061da546Spatrick   // Is the breakpoint start address after passed in end address?
176061da546Spatrick   if (end_addr <= m_addr)
177061da546Spatrick     return false;
178be691f3bSpatrick 
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
CopyOwnersList(BreakpointLocationCollection & out_collection)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