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 ()
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     lldb::BreakpointLocationSP this_sp(this);
153     if (m_options_ap.get())
154         return m_options_ap->GetThreadPlanToTestCondition (exe_ctx, this_sp, error);
155     else
156         return m_owner.GetThreadPlanToTestCondition (exe_ctx, this_sp, error);
157 }
158 
159 const char *
160 BreakpointLocation::GetConditionText () const
161 {
162     return GetOptionsNoCreate()->GetConditionText();
163 }
164 
165 uint32_t
166 BreakpointLocation::GetIgnoreCount ()
167 {
168     return GetOptionsNoCreate()->GetIgnoreCount();
169 }
170 
171 void
172 BreakpointLocation::SetIgnoreCount (uint32_t n)
173 {
174     GetLocationOptions()->SetIgnoreCount(n);
175 }
176 
177 const BreakpointOptions *
178 BreakpointLocation::GetOptionsNoCreate () const
179 {
180     if (m_options_ap.get() != NULL)
181         return m_options_ap.get();
182     else
183         return m_owner.GetOptions ();
184 }
185 
186 BreakpointOptions *
187 BreakpointLocation::GetLocationOptions ()
188 {
189     // If we make the copy we don't copy the callbacks because that is potentially
190     // expensive and we don't want to do that for the simple case where someone is
191     // just disabling the location.
192     if (m_options_ap.get() == NULL)
193         m_options_ap.reset(BreakpointOptions::CopyOptionsNoCallback(*m_owner.GetOptions ()));
194 
195     return m_options_ap.get();
196 }
197 
198 bool
199 BreakpointLocation::ValidForThisThread (Thread *thread)
200 {
201     return thread->MatchesSpec(GetOptionsNoCreate()->GetThreadSpecNoCreate());
202 }
203 
204 // RETURNS - true if we should stop at this breakpoint, false if we
205 // should continue.  Note, we don't check the thread spec for the breakpoint
206 // here, since if the breakpoint is not for this thread, then the event won't
207 // even get reported, so the check is redundant.
208 
209 bool
210 BreakpointLocation::ShouldStop (StoppointCallbackContext *context)
211 {
212     bool should_stop = true;
213     LogSP log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS);
214 
215     m_hit_count++;
216 
217     if (!IsEnabled())
218         return false;
219 
220     if (m_hit_count <= GetIgnoreCount())
221         return false;
222 
223     // We only run synchronous callbacks in ShouldStop:
224     context->is_synchronous = true;
225     should_stop = InvokeCallback (context);
226 
227     if (log)
228     {
229         StreamString s;
230         GetDescription (&s, lldb::eDescriptionLevelVerbose);
231         log->Printf ("Hit breakpoint location: %s, %s.\n", s.GetData(), should_stop ? "stopping" : "continuing");
232     }
233 
234     return should_stop;
235 }
236 
237 bool
238 BreakpointLocation::IsResolved () const
239 {
240     return m_bp_site_sp.get() != NULL;
241 }
242 
243 lldb::BreakpointSiteSP
244 BreakpointLocation::GetBreakpointSite() const
245 {
246     return m_bp_site_sp;
247 }
248 
249 bool
250 BreakpointLocation::ResolveBreakpointSite ()
251 {
252     if (m_bp_site_sp)
253         return true;
254 
255     Process *process = m_owner.GetTarget().GetProcessSP().get();
256     if (process == NULL)
257         return false;
258 
259     if (m_owner.GetTarget().GetSectionLoadList().IsEmpty())
260         return false;
261 
262     BreakpointLocationSP this_sp(this);
263 
264     lldb::break_id_t new_id = process->CreateBreakpointSite (this_sp, false);
265 
266     if (new_id == LLDB_INVALID_BREAK_ID)
267     {
268         LogSP log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS);
269         if (log)
270             log->Warning ("Tried to add breakpoint site at 0x%llx but it was already present.\n",
271                           m_address.GetOpcodeLoadAddress (&m_owner.GetTarget()));
272         return false;
273     }
274 
275     return true;
276 }
277 
278 bool
279 BreakpointLocation::SetBreakpointSite (BreakpointSiteSP& bp_site_sp)
280 {
281     m_bp_site_sp = bp_site_sp;
282     return true;
283 }
284 
285 bool
286 BreakpointLocation::ClearBreakpointSite ()
287 {
288     if (m_bp_site_sp.get())
289     {
290         m_owner.GetTarget().GetProcessSP()->RemoveOwnerFromBreakpointSite (GetBreakpoint().GetID(),
291                                                                            GetID(), m_bp_site_sp);
292         m_bp_site_sp.reset();
293         return true;
294     }
295     return false;
296 }
297 
298 void
299 BreakpointLocation::GetDescription (Stream *s, lldb::DescriptionLevel level)
300 {
301     SymbolContext sc;
302     s->Indent();
303     BreakpointID::GetCanonicalReference(s, m_owner.GetID(), GetID());
304 
305     if (level == lldb::eDescriptionLevelBrief)
306         return;
307 
308     s->PutCString(": ");
309 
310     if (level == lldb::eDescriptionLevelVerbose)
311         s->IndentMore();
312 
313     if (m_address.IsSectionOffset())
314     {
315         m_address.CalculateSymbolContext(&sc);
316 
317         if (level == lldb::eDescriptionLevelFull)
318         {
319             s->PutCString("where = ");
320             sc.DumpStopContext (s, m_owner.GetTarget().GetProcessSP().get(), m_address, false, true, false);
321         }
322         else
323         {
324             if (sc.module_sp)
325             {
326                 s->EOL();
327                 s->Indent("module = ");
328                 sc.module_sp->GetFileSpec().Dump (s);
329             }
330 
331             if (sc.comp_unit != NULL)
332             {
333                 s->EOL();
334                 s->Indent("compile unit = ");
335                 static_cast<FileSpec*>(sc.comp_unit)->GetFilename().Dump (s);
336 
337                 if (sc.function != NULL)
338                 {
339                     s->EOL();
340                     s->Indent("function = ");
341                     s->PutCString (sc.function->GetMangled().GetName().AsCString("<unknown>"));
342                 }
343 
344                 if (sc.line_entry.line > 0)
345                 {
346                     s->EOL();
347                     s->Indent("location = ");
348                     sc.line_entry.DumpStopContext (s, true);
349                 }
350 
351             }
352             else
353             {
354                 // If we don't have a comp unit, see if we have a symbol we can print.
355                 if (sc.symbol)
356                 {
357                     s->EOL();
358                     s->Indent("symbol = ");
359                     s->PutCString(sc.symbol->GetMangled().GetName().AsCString("<unknown>"));
360                 }
361             }
362         }
363     }
364 
365     if (level == lldb::eDescriptionLevelVerbose)
366     {
367         s->EOL();
368         s->Indent();
369     }
370     s->Printf ("%saddress = ", (level == lldb::eDescriptionLevelFull && m_address.IsSectionOffset()) ? ", " : "");
371     ExecutionContextScope *exe_scope = NULL;
372     Target *target = &m_owner.GetTarget();
373     if (target)
374         exe_scope = target->GetProcessSP().get();
375     if (exe_scope == NULL)
376         exe_scope = target;
377 
378     m_address.Dump(s, exe_scope, Address::DumpStyleLoadAddress, Address::DumpStyleModuleWithFileAddress);
379 
380     if (level == lldb::eDescriptionLevelVerbose)
381     {
382         s->EOL();
383         s->Indent();
384         s->Printf("resolved = %s\n", IsResolved() ? "true" : "false");
385 
386         s->Indent();
387         s->Printf ("hit count = %-4u\n", GetHitCount());
388 
389         if (m_options_ap.get())
390         {
391             s->Indent();
392             m_options_ap->GetDescription (s, level);
393             s->EOL();
394         }
395         s->IndentLess();
396     }
397     else
398     {
399         s->Printf(", %sresolved, hit count = %u ",
400                   (IsResolved() ? "" : "un"),
401                   GetHitCount());
402         if (m_options_ap.get())
403         {
404             m_options_ap->GetDescription (s, level);
405         }
406     }
407 }
408 
409 void
410 BreakpointLocation::Dump(Stream *s) const
411 {
412     if (s == NULL)
413         return;
414 
415     s->Printf("BreakpointLocation %u: tid = %4.4x  load addr = 0x%8.8llx  state = %s  type = %s breakpoint  "
416               "hw_index = %i  hit_count = %-4u  ignore_count = %-4u",
417             GetID(),
418             GetOptionsNoCreate()->GetThreadSpecNoCreate()->GetTID(),
419             (uint64_t) m_address.GetOpcodeLoadAddress (&m_owner.GetTarget()),
420             (m_options_ap.get() ? m_options_ap->IsEnabled() : m_owner.IsEnabled()) ? "enabled " : "disabled",
421             IsHardware() ? "hardware" : "software",
422             GetHardwareIndex(),
423             GetHitCount(),
424             m_options_ap.get() ? m_options_ap->GetIgnoreCount() : m_owner.GetIgnoreCount());
425 }
426