1 //===-- BreakpointSite.cpp --------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 // C Includes
11 // C++ Includes
12 #include <inttypes.h>
13 
14 // Other libraries and framework includes
15 // Project includes
16 #include "lldb/Breakpoint/BreakpointSite.h"
17 
18 #include "lldb/Breakpoint/Breakpoint.h"
19 #include "lldb/Breakpoint/BreakpointLocation.h"
20 #include "lldb/Breakpoint/BreakpointSiteList.h"
21 #include "lldb/Core/Stream.h"
22 
23 using namespace lldb;
24 using namespace lldb_private;
25 
26 BreakpointSite::BreakpointSite(BreakpointSiteList *list, const BreakpointLocationSP &owner, lldb::addr_t addr,
27                                bool use_hardware)
28     : StoppointLocation(GetNextID(), addr, 0, use_hardware),
29       m_type(eSoftware), // Process subclasses need to set this correctly using SetType()
30       m_saved_opcode(),
31       m_trap_opcode(),
32       m_enabled(false), // Need to create it disabled, so the first enable turns it on.
33       m_owners(),
34       m_owners_mutex()
35 {
36     m_owners.Add(owner);
37 }
38 
39 BreakpointSite::~BreakpointSite()
40 {
41     BreakpointLocationSP bp_loc_sp;
42     const size_t owner_count = m_owners.GetSize();
43     for (size_t i = 0; i < owner_count; i++)
44     {
45         m_owners.GetByIndex(i)->ClearBreakpointSite();
46     }
47 }
48 
49 break_id_t
50 BreakpointSite::GetNextID()
51 {
52     static break_id_t g_next_id = 0;
53     return ++g_next_id;
54 }
55 
56 // RETURNS - true if we should stop at this breakpoint, false if we
57 // should continue.
58 
59 bool
60 BreakpointSite::ShouldStop (StoppointCallbackContext *context)
61 {
62     std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
63     IncrementHitCount();
64     return m_owners.ShouldStop (context);
65 }
66 
67 bool
68 BreakpointSite::IsBreakpointAtThisSite (lldb::break_id_t bp_id)
69 {
70     std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
71     const size_t owner_count = m_owners.GetSize();
72     for (size_t i = 0; i < owner_count; i++)
73     {
74         if (m_owners.GetByIndex(i)->GetBreakpoint().GetID() == bp_id)
75             return true;
76     }
77     return false;
78 }
79 
80 void
81 BreakpointSite::Dump(Stream *s) const
82 {
83     if (s == nullptr)
84         return;
85 
86     s->Printf("BreakpointSite %u: addr = 0x%8.8" PRIx64 "  type = %s breakpoint  hw_index = %i  hit_count = %-4u",
87             GetID(),
88             (uint64_t)m_addr,
89             IsHardware() ? "hardware" : "software",
90             GetHardwareIndex(),
91             GetHitCount());
92 }
93 
94 void
95 BreakpointSite::GetDescription (Stream *s, lldb::DescriptionLevel level)
96 {
97     std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
98     if (level != lldb::eDescriptionLevelBrief)
99         s->Printf ("breakpoint site: %d at 0x%8.8" PRIx64, GetID(), GetLoadAddress());
100     m_owners.GetDescription (s, level);
101 }
102 
103 bool
104 BreakpointSite::IsInternal() const
105 {
106     return m_owners.IsInternal();
107 }
108 
109 uint8_t *
110 BreakpointSite::GetTrapOpcodeBytes()
111 {
112     return &m_trap_opcode[0];
113 }
114 
115 const uint8_t *
116 BreakpointSite::GetTrapOpcodeBytes() const
117 {
118     return &m_trap_opcode[0];
119 }
120 
121 size_t
122 BreakpointSite::GetTrapOpcodeMaxByteSize() const
123 {
124     return sizeof(m_trap_opcode);
125 }
126 
127 bool
128 BreakpointSite::SetTrapOpcode (const uint8_t *trap_opcode, uint32_t trap_opcode_size)
129 {
130     if (trap_opcode_size > 0 && trap_opcode_size <= sizeof(m_trap_opcode))
131     {
132         m_byte_size = trap_opcode_size;
133         ::memcpy (m_trap_opcode, trap_opcode, trap_opcode_size);
134         return true;
135     }
136     m_byte_size = 0;
137     return false;
138 }
139 
140 uint8_t *
141 BreakpointSite::GetSavedOpcodeBytes()
142 {
143     return &m_saved_opcode[0];
144 }
145 
146 const uint8_t *
147 BreakpointSite::GetSavedOpcodeBytes() const
148 {
149     return &m_saved_opcode[0];
150 }
151 
152 bool
153 BreakpointSite::IsEnabled () const
154 {
155     return m_enabled;
156 }
157 
158 void
159 BreakpointSite::SetEnabled (bool enabled)
160 {
161     m_enabled = enabled;
162 }
163 
164 void
165 BreakpointSite::AddOwner (const BreakpointLocationSP &owner)
166 {
167     std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
168     m_owners.Add(owner);
169 }
170 
171 size_t
172 BreakpointSite::RemoveOwner (lldb::break_id_t break_id, lldb::break_id_t break_loc_id)
173 {
174     std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
175     m_owners.Remove(break_id, break_loc_id);
176     return m_owners.GetSize();
177 }
178 
179 size_t
180 BreakpointSite::GetNumberOfOwners ()
181 {
182     std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
183     return m_owners.GetSize();
184 }
185 
186 BreakpointLocationSP
187 BreakpointSite::GetOwnerAtIndex (size_t index)
188 {
189     std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
190     return m_owners.GetByIndex (index);
191 }
192 
193 bool
194 BreakpointSite::ValidForThisThread (Thread *thread)
195 {
196     std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
197     return m_owners.ValidForThisThread(thread);
198 }
199 
200 void
201 BreakpointSite::BumpHitCounts()
202 {
203     std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
204     for (BreakpointLocationSP loc_sp : m_owners.BreakpointLocations())
205     {
206         loc_sp->BumpHitCount();
207     }
208 }
209 
210 bool
211 BreakpointSite::IntersectsRange(lldb::addr_t addr, size_t size, lldb::addr_t *intersect_addr, size_t *intersect_size, size_t *opcode_offset) const
212 {
213     // We only use software traps for software breakpoints
214     if (!IsHardware())
215     {
216         if (m_byte_size > 0)
217         {
218             const lldb::addr_t bp_end_addr = m_addr + m_byte_size;
219             const lldb::addr_t end_addr = addr + size;
220             // Is the breakpoint end address before the passed in start address?
221             if (bp_end_addr <= addr)
222                 return false;
223             // Is the breakpoint start address after passed in end address?
224             if (end_addr <= m_addr)
225                 return false;
226             if (intersect_addr || intersect_size || opcode_offset)
227             {
228                 if (m_addr < addr)
229                 {
230                     if (intersect_addr)
231                         *intersect_addr = addr;
232                     if (intersect_size)
233                         *intersect_size = std::min<lldb::addr_t>(bp_end_addr, end_addr) - addr;
234                     if (opcode_offset)
235                         *opcode_offset = addr - m_addr;
236                 }
237                 else
238                 {
239                     if (intersect_addr)
240                         *intersect_addr = m_addr;
241                     if (intersect_size)
242                         *intersect_size = std::min<lldb::addr_t>(bp_end_addr, end_addr) - m_addr;
243                     if (opcode_offset)
244                         *opcode_offset = 0;
245                 }
246             }
247             return true;
248         }
249     }
250     return false;
251 }
252 
253 size_t
254 BreakpointSite::CopyOwnersList (BreakpointLocationCollection &out_collection)
255 {
256     std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
257     for (BreakpointLocationSP loc_sp : m_owners.BreakpointLocations())
258     {
259         out_collection.Add(loc_sp);
260     }
261     return out_collection.GetSize();
262 }
263