1 //===-- BreakpointLocation.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 <string>
13 
14 // Other libraries and framework includes
15 // Project includes
16 #include "lldb/Breakpoint/BreakpointLocation.h"
17 #include "lldb/Breakpoint/BreakpointID.h"
18 #include "lldb/Breakpoint/StoppointCallbackContext.h"
19 #include "lldb/Core/Log.h"
20 #include "lldb/Target/Target.h"
21 #include "lldb/Target/Process.h"
22 #include "lldb/Core/StreamString.h"
23 #include "lldb/lldb-private-log.h"
24 #include "lldb/Target/Thread.h"
25 
26 using namespace lldb;
27 using namespace lldb_private;
28 
29 BreakpointLocation::BreakpointLocation
30 (
31     break_id_t loc_id,
32     Breakpoint &owner,
33     Address &addr,
34     lldb::tid_t tid,
35     bool hardware
36 ) :
37     StoppointLocation (loc_id, addr.GetLoadAddress(owner.GetTarget().GetProcessSP().get()), tid, hardware),
38     m_address (addr),
39     m_owner (owner),
40     m_options_ap (),
41     m_bp_site_sp ()
42 {
43 }
44 
45 BreakpointLocation::~BreakpointLocation()
46 {
47     ClearBreakpointSite();
48 }
49 
50 lldb::addr_t
51 BreakpointLocation::GetLoadAddress ()
52 {
53     return m_address.GetLoadAddress(m_owner.GetTarget().GetProcessSP().get());
54 }
55 
56 Address &
57 BreakpointLocation::GetAddress ()
58 {
59     return m_address;
60 }
61 
62 Breakpoint &
63 BreakpointLocation::GetBreakpoint ()
64 {
65     return m_owner;
66 }
67 
68 bool
69 BreakpointLocation::IsEnabled ()
70 {
71     if (!m_owner.IsEnabled())
72         return false;
73     else if (m_options_ap.get() != NULL)
74         return m_options_ap->IsEnabled();
75     else
76         return true;
77 }
78 
79 void
80 BreakpointLocation::SetEnabled (bool enabled)
81 {
82     GetLocationOptions()->SetEnabled(enabled);
83     if (enabled)
84     {
85         ResolveBreakpointSite();
86     }
87     else
88     {
89         ClearBreakpointSite();
90     }
91 }
92 
93 void
94 BreakpointLocation::SetThreadID (lldb::tid_t thread_id)
95 {
96     GetLocationOptions()->SetThreadID(thread_id);
97 }
98 
99 lldb::tid_t
100 BreakpointLocation::GetThreadID ()
101 {
102     return GetOptionsNoCopy()->GetThreadID();
103 }
104 
105 bool
106 BreakpointLocation::InvokeCallback (StoppointCallbackContext *context)
107 {
108     bool owner_result;
109 
110     owner_result = m_owner.InvokeCallback (context, GetID());
111     if (owner_result == false)
112         return false;
113     else if (m_options_ap.get() != NULL)
114         return m_options_ap->InvokeCallback (context, m_owner.GetID(), GetID());
115     else
116         return true;
117 }
118 
119 void
120 BreakpointLocation::SetCallback (BreakpointHitCallback callback, void *baton,
121                  bool is_synchronous)
122 {
123     // The default "Baton" class will keep a copy of "baton" and won't free
124     // or delete it when it goes goes out of scope.
125     GetLocationOptions()->SetCallback(callback, BatonSP (new Baton(baton)), is_synchronous);
126 }
127 
128 void
129 BreakpointLocation::SetCallback (BreakpointHitCallback callback, const BatonSP &baton_sp,
130                  bool is_synchronous)
131 {
132     GetLocationOptions()->SetCallback (callback, baton_sp, is_synchronous);
133 }
134 
135 void
136 BreakpointLocation::ClearCallback ()
137 {
138     GetLocationOptions()->ClearCallback();
139 }
140 
141 int32_t
142 BreakpointLocation::GetIgnoreCount ()
143 {
144     return GetOptionsNoCopy()->GetIgnoreCount();
145 }
146 
147 void
148 BreakpointLocation::SetIgnoreCount (int32_t n)
149 {
150     GetLocationOptions()->SetIgnoreCount(n);
151 }
152 
153 BreakpointOptions *
154 BreakpointLocation::GetOptionsNoCopy ()
155 {
156     if (m_options_ap.get() != NULL)
157         return m_options_ap.get();
158     else
159         return m_owner.GetOptions ();
160 }
161 
162 BreakpointOptions *
163 BreakpointLocation::GetLocationOptions ()
164 {
165     if (m_options_ap.get() == NULL)
166         m_options_ap.reset(new BreakpointOptions (*m_owner.GetOptions ()));
167 
168     return m_options_ap.get();
169 }
170 
171 // RETURNS - true if we should stop at this breakpoint, false if we
172 // should continue.
173 
174 bool
175 BreakpointLocation::ShouldStop (StoppointCallbackContext *context)
176 {
177     bool should_stop = true;
178 
179     m_hit_count++;
180 
181     if (!IsEnabled())
182         return false;
183 
184     if (GetThreadID() != LLDB_INVALID_THREAD_ID
185           && context->context.thread->GetID() != GetThreadID())
186         return false;
187 
188     if (m_hit_count <= GetIgnoreCount())
189         return false;
190 
191     // Tell if the callback is synchronous here.
192     context->is_synchronous = true;
193     should_stop = InvokeCallback (context);
194 
195     if (should_stop)
196     {
197         Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS);
198         if (log)
199         {
200             StreamString s;
201             GetDescription (&s, lldb::eDescriptionLevelVerbose);
202             log->Printf ("Hit breakpoint location: %s\n", s.GetData());
203         }
204     }
205     return should_stop;
206 }
207 
208 bool
209 BreakpointLocation::IsResolved () const
210 {
211     return m_bp_site_sp.get() != NULL;
212 }
213 
214 bool
215 BreakpointLocation::ResolveBreakpointSite ()
216 {
217     if (m_bp_site_sp)
218         return true;
219 
220     Process* process = m_owner.GetTarget().GetProcessSP().get();
221     if (process == NULL)
222         return false;
223 
224     BreakpointLocationSP myself_sp(m_owner.GetLocationSP (this));
225 
226     lldb::user_id_t new_id = process->CreateBreakpointSite (myself_sp, false);
227 
228     if (new_id == LLDB_INVALID_UID)
229     {
230         Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS);
231         if (log)
232             log->Warning ("Tried to add breakpoint site at 0x%llx but it was already present.\n",
233                           m_address.GetLoadAddress(process));
234         return false;
235     }
236 
237     return true;
238 }
239 
240 bool
241 BreakpointLocation::SetBreakpointSite (BreakpointSiteSP& bp_site_sp)
242 {
243     m_bp_site_sp = bp_site_sp;
244     return true;
245 }
246 
247 bool
248 BreakpointLocation::ClearBreakpointSite ()
249 {
250     if (m_bp_site_sp.get())
251     {
252         m_owner.GetTarget().GetProcessSP()->RemoveOwnerFromBreakpointSite (GetBreakpoint().GetID(), GetID(), m_bp_site_sp);
253         m_bp_site_sp.reset();
254         return true;
255     }
256     return false;
257 }
258 
259 void
260 BreakpointLocation::GetDescription (Stream *s, lldb::DescriptionLevel level)
261 {
262     SymbolContext sc;
263     s->Indent();
264     BreakpointID::GetCanonicalReference(s, m_owner.GetID(), GetID());
265 
266     if (level == lldb::eDescriptionLevelBrief)
267         return;
268 
269     s->PutCString(": ");
270 
271     if (level == lldb::eDescriptionLevelVerbose)
272         s->IndentMore();
273 
274     if (m_address.IsSectionOffset())
275     {
276         m_address.CalculateSymbolContext(&sc);
277 
278         if (level == lldb::eDescriptionLevelFull)
279         {
280             s->PutCString("where = ");
281             sc.DumpStopContext (s, m_owner.GetTarget().GetProcessSP().get(), m_address);
282         }
283         else
284         {
285             if (sc.module_sp)
286             {
287                 s->EOL();
288                 s->Indent("module = ");
289                 sc.module_sp->GetFileSpec().Dump (s);
290             }
291 
292             if (sc.comp_unit != NULL)
293             {
294                 s->EOL();
295                 s->Indent("compile unit = ");
296                 dynamic_cast<FileSpec*>(sc.comp_unit)->GetFilename().Dump (s);
297 
298                 if (sc.function != NULL)
299                 {
300                     s->EOL();
301                     s->Indent("function = ");
302                     s->PutCString (sc.function->GetMangled().GetName().AsCString("<unknown>"));
303                 }
304 
305                 if (sc.line_entry.line > 0)
306                 {
307                     s->EOL();
308                     s->Indent("location = ");
309                     sc.line_entry.DumpStopContext (s);
310                 }
311 
312             }
313             else
314             {
315                 // If we don't have a comp unit, see if we have a symbol we can print.
316                 if (sc.symbol)
317                 {
318                     s->EOL();
319                     s->Indent("symbol = ");
320                     s->PutCString(sc.symbol->GetMangled().GetName().AsCString("<unknown>"));
321                 }
322             }
323         }
324     }
325 
326     if (level == lldb::eDescriptionLevelVerbose)
327     {
328         s->EOL();
329         s->Indent();
330     }
331     s->Printf ("%saddress = ", (level == lldb::eDescriptionLevelFull && m_address.IsSectionOffset()) ? ", " : "");
332     ExecutionContextScope *exe_scope = NULL;
333     Target *target = &m_owner.GetTarget();
334     if (target)
335         exe_scope = target->GetProcessSP().get();
336     if (exe_scope == NULL)
337         exe_scope = target;
338 
339     m_address.Dump(s, exe_scope, Address::DumpStyleLoadAddress, Address::DumpStyleModuleWithFileAddress);
340 
341     if (level == lldb::eDescriptionLevelVerbose)
342     {
343         s->EOL();
344         s->Indent();
345         s->Printf("resolved = %s\n", IsResolved() ? "true" : "false");
346 
347         s->Indent();
348         s->Printf("enabled = %s\n", IsEnabled() ? "true" : "false");
349 
350         s->Indent();
351         s->Printf ("hit count = %-4u\n", GetHitCount());
352 
353         if (m_options_ap.get())
354         {
355             Baton *baton = m_options_ap->GetBaton();
356             if (baton)
357             {
358                 s->Indent();
359                 baton->GetDescription (s, level);
360                 s->EOL();
361             }
362         }
363         s->IndentLess();
364     }
365     else
366     {
367         s->Printf(", %sresolved, %s, hit count = %u",
368                   (IsResolved() ? "" : "un"),
369                   (IsEnabled() ? "enabled" : "disabled"),
370                   GetHitCount());
371     }
372 }
373 
374 void
375 BreakpointLocation::Dump(Stream *s) const
376 {
377     if (s == NULL)
378         return;
379 
380     s->Printf("BreakpointLocation %u: tid = %4.4x  load addr = 0x%8.8llx  state = %s  type = %s breakpoint  hw_index = %i  hit_count = %-4u  ignore_count = %-4u",
381             GetID(),
382             m_tid,
383             (uint64_t) m_address.GetLoadAddress(m_owner.GetTarget().GetProcessSP().get()),
384             (m_options_ap.get() ? m_options_ap->IsEnabled() : m_owner.IsEnabled()) ? "enabled " : "disabled",
385             IsHardware() ? "hardware" : "software",
386             GetHardwareIndex(),
387             GetHitCount(),
388             m_options_ap.get() ? m_options_ap->GetIgnoreCount() : m_owner.GetIgnoreCount());
389 }
390