1254721Semaste//===-- BreakpointSite.cpp --------------------------------------*- C++ -*-===//
2254721Semaste//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6254721Semaste//
7254721Semaste//===----------------------------------------------------------------------===//
8254721Semaste
9288943Sdim#include <inttypes.h>
10288943Sdim
11296417Sdim#include "lldb/Breakpoint/BreakpointSite.h"
12296417Sdim
13254721Semaste#include "lldb/Breakpoint/Breakpoint.h"
14254721Semaste#include "lldb/Breakpoint/BreakpointLocation.h"
15254721Semaste#include "lldb/Breakpoint/BreakpointSiteList.h"
16321369Sdim#include "lldb/Utility/Stream.h"
17254721Semaste
18254721Semasteusing namespace lldb;
19254721Semasteusing namespace lldb_private;
20254721Semaste
21314564SdimBreakpointSite::BreakpointSite(BreakpointSiteList *list,
22314564Sdim                               const BreakpointLocationSP &owner,
23314564Sdim                               lldb::addr_t addr, bool use_hardware)
24309124Sdim    : StoppointLocation(GetNextID(), addr, 0, use_hardware),
25314564Sdim      m_type(eSoftware), // Process subclasses need to set this correctly using
26314564Sdim                         // SetType()
27314564Sdim      m_saved_opcode(), m_trap_opcode(),
28314564Sdim      m_enabled(false), // Need to create it disabled, so the first enable turns
29314564Sdim                        // it on.
30314564Sdim      m_owners(), m_owners_mutex() {
31314564Sdim  m_owners.Add(owner);
32254721Semaste}
33254721Semaste
34314564SdimBreakpointSite::~BreakpointSite() {
35314564Sdim  BreakpointLocationSP bp_loc_sp;
36314564Sdim  const size_t owner_count = m_owners.GetSize();
37314564Sdim  for (size_t i = 0; i < owner_count; i++) {
38314564Sdim    m_owners.GetByIndex(i)->ClearBreakpointSite();
39314564Sdim  }
40254721Semaste}
41254721Semaste
42314564Sdimbreak_id_t BreakpointSite::GetNextID() {
43314564Sdim  static break_id_t g_next_id = 0;
44314564Sdim  return ++g_next_id;
45254721Semaste}
46254721Semaste
47254721Semaste// RETURNS - true if we should stop at this breakpoint, false if we
48254721Semaste// should continue.
49254721Semaste
50314564Sdimbool BreakpointSite::ShouldStop(StoppointCallbackContext *context) {
51314564Sdim  IncrementHitCount();
52353358Sdim  // ShouldStop can do a lot of work, and might even come come back and hit
53353358Sdim  // this breakpoint site again.  So don't hold the m_owners_mutex the whole
54353358Sdim  // while.  Instead make a local copy of the collection and call ShouldStop on
55353358Sdim  // the copy.
56353358Sdim  BreakpointLocationCollection owners_copy;
57353358Sdim  {
58353358Sdim    std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
59353358Sdim    owners_copy = m_owners;
60353358Sdim  }
61353358Sdim  return owners_copy.ShouldStop(context);
62254721Semaste}
63254721Semaste
64314564Sdimbool BreakpointSite::IsBreakpointAtThisSite(lldb::break_id_t bp_id) {
65314564Sdim  std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
66314564Sdim  const size_t owner_count = m_owners.GetSize();
67314564Sdim  for (size_t i = 0; i < owner_count; i++) {
68314564Sdim    if (m_owners.GetByIndex(i)->GetBreakpoint().GetID() == bp_id)
69314564Sdim      return true;
70314564Sdim  }
71314564Sdim  return false;
72254721Semaste}
73254721Semaste
74314564Sdimvoid BreakpointSite::Dump(Stream *s) const {
75314564Sdim  if (s == nullptr)
76314564Sdim    return;
77254721Semaste
78314564Sdim  s->Printf("BreakpointSite %u: addr = 0x%8.8" PRIx64
79314564Sdim            "  type = %s breakpoint  hw_index = %i  hit_count = %-4u",
80314564Sdim            GetID(), (uint64_t)m_addr, IsHardware() ? "hardware" : "software",
81314564Sdim            GetHardwareIndex(), GetHitCount());
82254721Semaste}
83254721Semaste
84314564Sdimvoid BreakpointSite::GetDescription(Stream *s, lldb::DescriptionLevel level) {
85314564Sdim  std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
86314564Sdim  if (level != lldb::eDescriptionLevelBrief)
87314564Sdim    s->Printf("breakpoint site: %d at 0x%8.8" PRIx64, GetID(),
88314564Sdim              GetLoadAddress());
89314564Sdim  m_owners.GetDescription(s, level);
90254721Semaste}
91254721Semaste
92314564Sdimbool BreakpointSite::IsInternal() const { return m_owners.IsInternal(); }
93254721Semaste
94314564Sdimuint8_t *BreakpointSite::GetTrapOpcodeBytes() { return &m_trap_opcode[0]; }
95254721Semaste
96314564Sdimconst uint8_t *BreakpointSite::GetTrapOpcodeBytes() const {
97314564Sdim  return &m_trap_opcode[0];
98254721Semaste}
99254721Semaste
100314564Sdimsize_t BreakpointSite::GetTrapOpcodeMaxByteSize() const {
101314564Sdim  return sizeof(m_trap_opcode);
102254721Semaste}
103254721Semaste
104314564Sdimbool BreakpointSite::SetTrapOpcode(const uint8_t *trap_opcode,
105314564Sdim                                   uint32_t trap_opcode_size) {
106314564Sdim  if (trap_opcode_size > 0 && trap_opcode_size <= sizeof(m_trap_opcode)) {
107314564Sdim    m_byte_size = trap_opcode_size;
108314564Sdim    ::memcpy(m_trap_opcode, trap_opcode, trap_opcode_size);
109314564Sdim    return true;
110314564Sdim  }
111314564Sdim  m_byte_size = 0;
112314564Sdim  return false;
113254721Semaste}
114254721Semaste
115314564Sdimuint8_t *BreakpointSite::GetSavedOpcodeBytes() { return &m_saved_opcode[0]; }
116254721Semaste
117314564Sdimconst uint8_t *BreakpointSite::GetSavedOpcodeBytes() const {
118314564Sdim  return &m_saved_opcode[0];
119254721Semaste}
120254721Semaste
121314564Sdimbool BreakpointSite::IsEnabled() const { return m_enabled; }
122254721Semaste
123314564Sdimvoid BreakpointSite::SetEnabled(bool enabled) { m_enabled = enabled; }
124254721Semaste
125314564Sdimvoid BreakpointSite::AddOwner(const BreakpointLocationSP &owner) {
126314564Sdim  std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
127314564Sdim  m_owners.Add(owner);
128254721Semaste}
129254721Semaste
130314564Sdimsize_t BreakpointSite::RemoveOwner(lldb::break_id_t break_id,
131314564Sdim                                   lldb::break_id_t break_loc_id) {
132314564Sdim  std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
133314564Sdim  m_owners.Remove(break_id, break_loc_id);
134314564Sdim  return m_owners.GetSize();
135254721Semaste}
136254721Semaste
137314564Sdimsize_t BreakpointSite::GetNumberOfOwners() {
138314564Sdim  std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
139314564Sdim  return m_owners.GetSize();
140254721Semaste}
141254721Semaste
142314564SdimBreakpointLocationSP BreakpointSite::GetOwnerAtIndex(size_t index) {
143314564Sdim  std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
144314564Sdim  return m_owners.GetByIndex(index);
145254721Semaste}
146254721Semaste
147314564Sdimbool BreakpointSite::ValidForThisThread(Thread *thread) {
148314564Sdim  std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
149314564Sdim  return m_owners.ValidForThisThread(thread);
150254721Semaste}
151254721Semaste
152314564Sdimvoid BreakpointSite::BumpHitCounts() {
153314564Sdim  std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
154314564Sdim  for (BreakpointLocationSP loc_sp : m_owners.BreakpointLocations()) {
155314564Sdim    loc_sp->BumpHitCount();
156314564Sdim  }
157280031Sdim}
158280031Sdim
159314564Sdimbool BreakpointSite::IntersectsRange(lldb::addr_t addr, size_t size,
160314564Sdim                                     lldb::addr_t *intersect_addr,
161314564Sdim                                     size_t *intersect_size,
162314564Sdim                                     size_t *opcode_offset) const {
163314564Sdim  // We only use software traps for software breakpoints
164314564Sdim  if (!IsHardware()) {
165314564Sdim    if (m_byte_size > 0) {
166314564Sdim      const lldb::addr_t bp_end_addr = m_addr + m_byte_size;
167314564Sdim      const lldb::addr_t end_addr = addr + size;
168314564Sdim      // Is the breakpoint end address before the passed in start address?
169314564Sdim      if (bp_end_addr <= addr)
170314564Sdim        return false;
171314564Sdim      // Is the breakpoint start address after passed in end address?
172314564Sdim      if (end_addr <= m_addr)
173314564Sdim        return false;
174314564Sdim      if (intersect_addr || intersect_size || opcode_offset) {
175314564Sdim        if (m_addr < addr) {
176314564Sdim          if (intersect_addr)
177314564Sdim            *intersect_addr = addr;
178314564Sdim          if (intersect_size)
179314564Sdim            *intersect_size =
180314564Sdim                std::min<lldb::addr_t>(bp_end_addr, end_addr) - addr;
181314564Sdim          if (opcode_offset)
182314564Sdim            *opcode_offset = addr - m_addr;
183314564Sdim        } else {
184314564Sdim          if (intersect_addr)
185314564Sdim            *intersect_addr = m_addr;
186314564Sdim          if (intersect_size)
187314564Sdim            *intersect_size =
188314564Sdim                std::min<lldb::addr_t>(bp_end_addr, end_addr) - m_addr;
189314564Sdim          if (opcode_offset)
190314564Sdim            *opcode_offset = 0;
191254721Semaste        }
192314564Sdim      }
193314564Sdim      return true;
194254721Semaste    }
195314564Sdim  }
196314564Sdim  return false;
197254721Semaste}
198296417Sdim
199296417Sdimsize_t
200314564SdimBreakpointSite::CopyOwnersList(BreakpointLocationCollection &out_collection) {
201314564Sdim  std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
202314564Sdim  for (BreakpointLocationSP loc_sp : m_owners.BreakpointLocations()) {
203314564Sdim    out_collection.Add(loc_sp);
204314564Sdim  }
205314564Sdim  return out_collection.GetSize();
206296417Sdim}
207