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