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 // Other libraries and framework includes
15 // Project includes
16 #include "lldb/Breakpoint/Breakpoint.h"
17 #include "lldb/Breakpoint/BreakpointLocation.h"
18 #include "lldb/Breakpoint/BreakpointSiteList.h"
19 
20 using namespace lldb;
21 using namespace lldb_private;
22 
23 BreakpointSite::BreakpointSite
24 (
25     BreakpointSiteList *list,
26     BreakpointLocationSP& owner,
27     lldb::addr_t addr,
28     lldb::tid_t tid,
29     bool use_hardware
30 ) :
31     StoppointLocation(GetNextID(), addr, tid, use_hardware),
32     m_type (eSoftware), // Process subclasses need to set this correctly using SetType()
33     m_saved_opcode(),
34     m_trap_opcode(),
35     m_enabled(false), // Need to create it disabled, so the first enable turns it on.
36     m_owners()
37 {
38     m_owners.Add(owner);
39 }
40 
41 BreakpointSite::~BreakpointSite()
42 {
43     BreakpointLocationSP bp_loc_sp;
44     const size_t owner_count = m_owners.GetSize();
45     for (size_t i = 0; i < owner_count; i++)
46     {
47         m_owners.GetByIndex(i)->ClearBreakpointSite();
48     }
49 }
50 
51 break_id_t
52 BreakpointSite::GetNextID()
53 {
54     static break_id_t g_next_id = 0;
55     return ++g_next_id;
56 }
57 
58 // RETURNS - true if we should stop at this breakpoint, false if we
59 // should continue.
60 
61 bool
62 BreakpointSite::ShouldStop (StoppointCallbackContext *context)
63 {
64     m_hit_count++;
65     return m_owners.ShouldStop (context);
66 }
67 
68 bool
69 BreakpointSite::IsBreakpointAtThisSite (lldb::break_id_t bp_id)
70 {
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 == NULL)
84         return;
85 
86     s->Printf("BreakpointSite %u: addr = 0x%8.8llx  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     if (level != lldb::eDescriptionLevelBrief)
98         s->Printf ("breakpoint site: %d at 0x%8.8llx", GetID(), GetLoadAddress());
99     m_owners.GetDescription (s, level);
100 }
101 
102 uint8_t *
103 BreakpointSite::GetTrapOpcodeBytes()
104 {
105     return &m_trap_opcode[0];
106 }
107 
108 const uint8_t *
109 BreakpointSite::GetTrapOpcodeBytes() const
110 {
111     return &m_trap_opcode[0];
112 }
113 
114 size_t
115 BreakpointSite::GetTrapOpcodeMaxByteSize() const
116 {
117     return sizeof(m_trap_opcode);
118 }
119 
120 bool
121 BreakpointSite::SetTrapOpcode (const uint8_t *trap_opcode, size_t trap_opcode_size)
122 {
123     if (trap_opcode_size > 0 && trap_opcode_size <= sizeof(m_trap_opcode))
124     {
125         m_byte_size = trap_opcode_size;
126         ::memcpy (m_trap_opcode, trap_opcode, trap_opcode_size);
127         return true;
128     }
129     m_byte_size = 0;
130     return false;
131 }
132 
133 uint8_t *
134 BreakpointSite::GetSavedOpcodeBytes()
135 {
136     return &m_saved_opcode[0];
137 }
138 
139 const uint8_t *
140 BreakpointSite::GetSavedOpcodeBytes() const
141 {
142     return &m_saved_opcode[0];
143 }
144 
145 bool
146 BreakpointSite::IsEnabled () const
147 {
148     return m_enabled;
149 }
150 
151 void
152 BreakpointSite::SetEnabled (bool enabled)
153 {
154     m_enabled = enabled;
155 }
156 
157 void
158 BreakpointSite::AddOwner (BreakpointLocationSP &owner)
159 {
160     m_owners.Add(owner);
161 }
162 
163 uint32_t
164 BreakpointSite::RemoveOwner (lldb::break_id_t break_id, lldb::break_id_t break_loc_id)
165 {
166     m_owners.Remove(break_id, break_loc_id);
167     return m_owners.GetSize();
168 }
169 
170 uint32_t
171 BreakpointSite::GetNumberOfOwners ()
172 {
173     return m_owners.GetSize();
174 }
175 
176 BreakpointLocationSP
177 BreakpointSite::GetOwnerAtIndex (uint32_t index)
178 {
179     return m_owners.GetByIndex (index);
180 }
181 
182 bool
183 BreakpointSite::ValidForThisThread (Thread *thread)
184 {
185     return m_owners.ValidForThisThread(thread);
186 }
187 
188 bool
189 BreakpointSite::IntersectsRange(lldb::addr_t addr, size_t size, lldb::addr_t *intersect_addr, size_t *intersect_size, size_t *opcode_offset) const
190 {
191     // We only use software traps for software breakpoints
192     if (!IsHardware())
193     {
194         if (m_byte_size > 0)
195         {
196             const lldb::addr_t bp_end_addr = m_addr + m_byte_size;
197             const lldb::addr_t end_addr = addr + size;
198             // Is the breakpoint end address before the passed in start address?
199             if (bp_end_addr <= addr)
200                 return false;
201             // Is the breakpoint start address after passed in end address?
202             if (end_addr <= m_addr)
203                 return false;
204             if (intersect_addr || intersect_size || opcode_offset)
205             {
206                 if (m_addr < addr)
207                 {
208                     if (intersect_addr)
209                         *intersect_addr = addr;
210                     if (intersect_size)
211                         *intersect_size = std::min<lldb::addr_t>(bp_end_addr, end_addr) - addr;
212                     if (opcode_offset)
213                         *opcode_offset = addr - m_addr;
214                 }
215                 else
216                 {
217                     if (intersect_addr)
218                         *intersect_addr = m_addr;
219                     if (intersect_size)
220                         *intersect_size = std::min<lldb::addr_t>(bp_end_addr, end_addr) - m_addr;
221                     if (opcode_offset)
222                         *opcode_offset = 0;
223                 }
224             }
225             return true;
226         }
227     }
228     return false;
229 }
230