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