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