1//===-- BreakpointLocation.cpp --------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "lldb/Breakpoint/BreakpointLocation.h"
10#include "lldb/Breakpoint/BreakpointID.h"
11#include "lldb/Breakpoint/StoppointCallbackContext.h"
12#include "lldb/Core/Debugger.h"
13#include "lldb/Core/Module.h"
14#include "lldb/Expression/DiagnosticManager.h"
15#include "lldb/Expression/ExpressionVariable.h"
16#include "lldb/Expression/UserExpression.h"
17#include "lldb/Symbol/CompileUnit.h"
18#include "lldb/Symbol/Symbol.h"
19#include "lldb/Symbol/TypeSystem.h"
20#include "lldb/Target/Process.h"
21#include "lldb/Target/Target.h"
22#include "lldb/Target/Thread.h"
23#include "lldb/Target/ThreadSpec.h"
24#include "lldb/Utility/LLDBLog.h"
25#include "lldb/Utility/Log.h"
26#include "lldb/Utility/StreamString.h"
27#include "lldb/ValueObject/ValueObject.h"
28
29using namespace lldb;
30using namespace lldb_private;
31
32BreakpointLocation::BreakpointLocation(break_id_t loc_id, Breakpoint &owner,
33 const Address &addr, lldb::tid_t tid,
34 bool hardware, bool check_for_resolver)
35 : m_should_resolve_indirect_functions(false), m_is_reexported(false),
36 m_is_indirect(false), m_address(addr), m_owner(owner),
37 m_condition_hash(0), m_loc_id(loc_id), m_hit_counter() {
38 if (check_for_resolver) {
39 Symbol *symbol = m_address.CalculateSymbolContextSymbol();
40 if (symbol && symbol->IsIndirect()) {
41 SetShouldResolveIndirectFunctions(true);
42 }
43 }
44
45 SetThreadIDInternal(tid);
46}
47
48BreakpointLocation::~BreakpointLocation() { ClearBreakpointSite(); }
49
50lldb::addr_t BreakpointLocation::GetLoadAddress() const {
51 return m_address.GetOpcodeLoadAddress(target: &m_owner.GetTarget());
52}
53
54const BreakpointOptions &BreakpointLocation::GetOptionsSpecifyingKind(
55 BreakpointOptions::OptionKind kind) const {
56 if (m_options_up && m_options_up->IsOptionSet(kind))
57 return *m_options_up;
58 else
59 return m_owner.GetOptions();
60}
61
62Address &BreakpointLocation::GetAddress() { return m_address; }
63
64Breakpoint &BreakpointLocation::GetBreakpoint() { return m_owner; }
65
66Target &BreakpointLocation::GetTarget() { return m_owner.GetTarget(); }
67
68bool BreakpointLocation::IsEnabled() const {
69 if (!m_owner.IsEnabled())
70 return false;
71 else if (m_options_up != nullptr)
72 return m_options_up->IsEnabled();
73 else
74 return true;
75}
76
77void BreakpointLocation::SetEnabled(bool enabled) {
78 GetLocationOptions().SetEnabled(enabled);
79 if (enabled) {
80 ResolveBreakpointSite();
81 } else {
82 ClearBreakpointSite();
83 }
84 SendBreakpointLocationChangedEvent(eventKind: enabled ? eBreakpointEventTypeEnabled
85 : eBreakpointEventTypeDisabled);
86}
87
88bool BreakpointLocation::IsAutoContinue() const {
89 if (m_options_up &&
90 m_options_up->IsOptionSet(kind: BreakpointOptions::eAutoContinue))
91 return m_options_up->IsAutoContinue();
92 else
93 return m_owner.IsAutoContinue();
94}
95
96void BreakpointLocation::SetAutoContinue(bool auto_continue) {
97 GetLocationOptions().SetAutoContinue(auto_continue);
98 SendBreakpointLocationChangedEvent(eventKind: eBreakpointEventTypeAutoContinueChanged);
99}
100
101void BreakpointLocation::SetThreadID(lldb::tid_t thread_id) {
102 SetThreadIDInternal(thread_id);
103 SendBreakpointLocationChangedEvent(eventKind: eBreakpointEventTypeThreadChanged);
104}
105
106lldb::tid_t BreakpointLocation::GetThreadID() {
107 const ThreadSpec *thread_spec =
108 GetOptionsSpecifyingKind(kind: BreakpointOptions::eThreadSpec)
109 .GetThreadSpecNoCreate();
110 if (thread_spec)
111 return thread_spec->GetTID();
112 else
113 return LLDB_INVALID_THREAD_ID;
114}
115
116void BreakpointLocation::SetThreadIndex(uint32_t index) {
117 if (index != 0)
118 GetLocationOptions().GetThreadSpec()->SetIndex(index);
119 else {
120 // If we're resetting this to an invalid thread id, then don't make an
121 // options pointer just to do that.
122 if (m_options_up != nullptr)
123 m_options_up->GetThreadSpec()->SetIndex(index);
124 }
125 SendBreakpointLocationChangedEvent(eventKind: eBreakpointEventTypeThreadChanged);
126}
127
128uint32_t BreakpointLocation::GetThreadIndex() const {
129 const ThreadSpec *thread_spec =
130 GetOptionsSpecifyingKind(kind: BreakpointOptions::eThreadSpec)
131 .GetThreadSpecNoCreate();
132 if (thread_spec)
133 return thread_spec->GetIndex();
134 else
135 return 0;
136}
137
138void BreakpointLocation::SetThreadName(const char *thread_name) {
139 if (thread_name != nullptr)
140 GetLocationOptions().GetThreadSpec()->SetName(thread_name);
141 else {
142 // If we're resetting this to an invalid thread id, then don't make an
143 // options pointer just to do that.
144 if (m_options_up != nullptr)
145 m_options_up->GetThreadSpec()->SetName(thread_name);
146 }
147 SendBreakpointLocationChangedEvent(eventKind: eBreakpointEventTypeThreadChanged);
148}
149
150const char *BreakpointLocation::GetThreadName() const {
151 const ThreadSpec *thread_spec =
152 GetOptionsSpecifyingKind(kind: BreakpointOptions::eThreadSpec)
153 .GetThreadSpecNoCreate();
154 if (thread_spec)
155 return thread_spec->GetName();
156 else
157 return nullptr;
158}
159
160void BreakpointLocation::SetQueueName(const char *queue_name) {
161 if (queue_name != nullptr)
162 GetLocationOptions().GetThreadSpec()->SetQueueName(queue_name);
163 else {
164 // If we're resetting this to an invalid thread id, then don't make an
165 // options pointer just to do that.
166 if (m_options_up != nullptr)
167 m_options_up->GetThreadSpec()->SetQueueName(queue_name);
168 }
169 SendBreakpointLocationChangedEvent(eventKind: eBreakpointEventTypeThreadChanged);
170}
171
172const char *BreakpointLocation::GetQueueName() const {
173 const ThreadSpec *thread_spec =
174 GetOptionsSpecifyingKind(kind: BreakpointOptions::eThreadSpec)
175 .GetThreadSpecNoCreate();
176 if (thread_spec)
177 return thread_spec->GetQueueName();
178 else
179 return nullptr;
180}
181
182bool BreakpointLocation::InvokeCallback(StoppointCallbackContext *context) {
183 if (m_options_up != nullptr && m_options_up->HasCallback())
184 return m_options_up->InvokeCallback(context, break_id: m_owner.GetID(), break_loc_id: GetID());
185 else
186 return m_owner.InvokeCallback(context, bp_loc_id: GetID());
187}
188
189bool BreakpointLocation::IsCallbackSynchronous() {
190 if (m_options_up != nullptr && m_options_up->HasCallback())
191 return m_options_up->IsCallbackSynchronous();
192 else
193 return m_owner.GetOptions().IsCallbackSynchronous();
194}
195
196void BreakpointLocation::SetCallback(BreakpointHitCallback callback,
197 void *baton, bool is_synchronous) {
198 // The default "Baton" class will keep a copy of "baton" and won't free or
199 // delete it when it goes out of scope.
200 GetLocationOptions().SetCallback(
201 callback, baton_sp: std::make_shared<UntypedBaton>(args&: baton), synchronous: is_synchronous);
202 SendBreakpointLocationChangedEvent(eventKind: eBreakpointEventTypeCommandChanged);
203}
204
205void BreakpointLocation::SetCallback(BreakpointHitCallback callback,
206 const BatonSP &baton_sp,
207 bool is_synchronous) {
208 GetLocationOptions().SetCallback(callback, baton_sp, synchronous: is_synchronous);
209 SendBreakpointLocationChangedEvent(eventKind: eBreakpointEventTypeCommandChanged);
210}
211
212void BreakpointLocation::ClearCallback() {
213 GetLocationOptions().ClearCallback();
214}
215
216void BreakpointLocation::SetCondition(const char *condition) {
217 GetLocationOptions().SetCondition(condition);
218 SendBreakpointLocationChangedEvent(eventKind: eBreakpointEventTypeConditionChanged);
219}
220
221const char *BreakpointLocation::GetConditionText(size_t *hash) const {
222 return GetOptionsSpecifyingKind(kind: BreakpointOptions::eCondition)
223 .GetConditionText(hash);
224}
225
226bool BreakpointLocation::ConditionSaysStop(ExecutionContext &exe_ctx,
227 Status &error) {
228 Log *log = GetLog(mask: LLDBLog::Breakpoints);
229
230 std::lock_guard<std::mutex> guard(m_condition_mutex);
231
232 size_t condition_hash;
233 const char *condition_text = GetConditionText(hash: &condition_hash);
234
235 if (!condition_text) {
236 m_user_expression_sp.reset();
237 return false;
238 }
239
240 error.Clear();
241
242 DiagnosticManager diagnostics;
243
244 if (condition_hash != m_condition_hash || !m_user_expression_sp ||
245 !m_user_expression_sp->IsParseCacheable() ||
246 !m_user_expression_sp->MatchesContext(exe_ctx)) {
247 LanguageType language = eLanguageTypeUnknown;
248 // See if we can figure out the language from the frame, otherwise use the
249 // default language:
250 CompileUnit *comp_unit = m_address.CalculateSymbolContextCompileUnit();
251 if (comp_unit)
252 language = comp_unit->GetLanguage();
253
254 m_user_expression_sp.reset(p: GetTarget().GetUserExpressionForLanguage(
255 expr: condition_text, prefix: llvm::StringRef(), language, desired_type: Expression::eResultTypeAny,
256 options: EvaluateExpressionOptions(), ctx_obj: nullptr, error));
257 if (error.Fail()) {
258 LLDB_LOGF(log, "Error getting condition expression: %s.",
259 error.AsCString());
260 m_user_expression_sp.reset();
261 return true;
262 }
263
264 if (!m_user_expression_sp->Parse(diagnostic_manager&: diagnostics, exe_ctx,
265 execution_policy: eExecutionPolicyOnlyWhenNeeded, keep_result_in_memory: true,
266 generate_debug_info: false)) {
267 error = Status::FromError(
268 error: diagnostics.GetAsError(result: lldb::eExpressionParseError,
269 message: "Couldn't parse conditional expression:"));
270
271 m_user_expression_sp.reset();
272 return true;
273 }
274
275 m_condition_hash = condition_hash;
276 }
277
278 // We need to make sure the user sees any parse errors in their condition, so
279 // we'll hook the constructor errors up to the debugger's Async I/O.
280
281 ValueObjectSP result_value_sp;
282
283 EvaluateExpressionOptions options;
284 options.SetUnwindOnError(true);
285 options.SetIgnoreBreakpoints(true);
286 options.SetTryAllThreads(true);
287 options.SetSuppressPersistentResult(
288 true); // Don't generate a user variable for condition expressions.
289
290 Status expr_error;
291
292 diagnostics.Clear();
293
294 ExpressionVariableSP result_variable_sp;
295
296 ExpressionResults result_code = m_user_expression_sp->Execute(
297 diagnostic_manager&: diagnostics, exe_ctx, options, shared_ptr_to_me&: m_user_expression_sp, result&: result_variable_sp);
298
299 bool ret;
300
301 if (result_code == eExpressionCompleted) {
302 if (!result_variable_sp) {
303 error = Status::FromErrorString(str: "Expression did not return a result");
304 return false;
305 }
306
307 result_value_sp = result_variable_sp->GetValueObject();
308
309 if (result_value_sp) {
310 ret = result_value_sp->IsLogicalTrue(error);
311 if (log) {
312 if (error.Success()) {
313 LLDB_LOGF(log, "Condition successfully evaluated, result is %s.\n",
314 ret ? "true" : "false");
315 } else {
316 error = Status::FromErrorString(
317 str: "Failed to get an integer result from the expression");
318 ret = false;
319 }
320 }
321 } else {
322 ret = false;
323 error = Status::FromErrorString(
324 str: "Failed to get any result from the expression");
325 }
326 } else {
327 ret = false;
328 error = Status::FromError(error: diagnostics.GetAsError(
329 result: lldb::eExpressionParseError, message: "Couldn't execute expression:"));
330 }
331
332 return ret;
333}
334
335uint32_t BreakpointLocation::GetIgnoreCount() const {
336 return GetOptionsSpecifyingKind(kind: BreakpointOptions::eIgnoreCount)
337 .GetIgnoreCount();
338}
339
340void BreakpointLocation::SetIgnoreCount(uint32_t n) {
341 GetLocationOptions().SetIgnoreCount(n);
342 SendBreakpointLocationChangedEvent(eventKind: eBreakpointEventTypeIgnoreChanged);
343}
344
345void BreakpointLocation::DecrementIgnoreCount() {
346 if (m_options_up != nullptr) {
347 uint32_t loc_ignore = m_options_up->GetIgnoreCount();
348 if (loc_ignore != 0)
349 m_options_up->SetIgnoreCount(loc_ignore - 1);
350 }
351}
352
353bool BreakpointLocation::IgnoreCountShouldStop() {
354 uint32_t owner_ignore = GetBreakpoint().GetIgnoreCount();
355 uint32_t loc_ignore = 0;
356 if (m_options_up != nullptr)
357 loc_ignore = m_options_up->GetIgnoreCount();
358
359 if (loc_ignore != 0 || owner_ignore != 0) {
360 m_owner.DecrementIgnoreCount();
361 DecrementIgnoreCount(); // Have to decrement our owners' ignore count,
362 // since it won't get a chance to.
363 return false;
364 }
365 return true;
366}
367
368BreakpointOptions &BreakpointLocation::GetLocationOptions() {
369 // If we make the copy we don't copy the callbacks because that is
370 // potentially expensive and we don't want to do that for the simple case
371 // where someone is just disabling the location.
372 if (m_options_up == nullptr)
373 m_options_up = std::make_unique<BreakpointOptions>(args: false);
374
375 return *m_options_up;
376}
377
378bool BreakpointLocation::ValidForThisThread(Thread &thread) {
379 return thread.MatchesSpec(
380 spec: GetOptionsSpecifyingKind(kind: BreakpointOptions::eThreadSpec)
381 .GetThreadSpecNoCreate());
382}
383
384// RETURNS - true if we should stop at this breakpoint, false if we
385// should continue. Note, we don't check the thread spec for the breakpoint
386// here, since if the breakpoint is not for this thread, then the event won't
387// even get reported, so the check is redundant.
388
389bool BreakpointLocation::ShouldStop(StoppointCallbackContext *context) {
390 bool should_stop = true;
391 Log *log = GetLog(mask: LLDBLog::Breakpoints);
392
393 // Do this first, if a location is disabled, it shouldn't increment its hit
394 // count.
395 if (!IsEnabled())
396 return false;
397
398 // We only run synchronous callbacks in ShouldStop:
399 context->is_synchronous = true;
400 should_stop = InvokeCallback(context);
401
402 if (log) {
403 StreamString s;
404 GetDescription(s: &s, level: lldb::eDescriptionLevelVerbose);
405 LLDB_LOGF(log, "Hit breakpoint location: %s, %s.\n", s.GetData(),
406 should_stop ? "stopping" : "continuing");
407 }
408
409 return should_stop;
410}
411
412void BreakpointLocation::BumpHitCount() {
413 if (IsEnabled()) {
414 // Step our hit count, and also step the hit count of the owner.
415 m_hit_counter.Increment();
416 m_owner.m_hit_counter.Increment();
417 }
418}
419
420void BreakpointLocation::UndoBumpHitCount() {
421 if (IsEnabled()) {
422 // Step our hit count, and also step the hit count of the owner.
423 m_hit_counter.Decrement();
424 m_owner.m_hit_counter.Decrement();
425 }
426}
427
428bool BreakpointLocation::IsResolved() const {
429 return m_bp_site_sp.get() != nullptr;
430}
431
432lldb::BreakpointSiteSP BreakpointLocation::GetBreakpointSite() const {
433 return m_bp_site_sp;
434}
435
436bool BreakpointLocation::ResolveBreakpointSite() {
437 if (m_bp_site_sp)
438 return true;
439
440 Process *process = m_owner.GetTarget().GetProcessSP().get();
441 if (process == nullptr)
442 return false;
443
444 lldb::break_id_t new_id =
445 process->CreateBreakpointSite(owner: shared_from_this(), use_hardware: m_owner.IsHardware());
446
447 if (new_id == LLDB_INVALID_BREAK_ID) {
448 Log *log = GetLog(mask: LLDBLog::Breakpoints);
449 if (log)
450 log->Warning(fmt: "Failed to add breakpoint site at 0x%" PRIx64,
451 m_address.GetOpcodeLoadAddress(target: &m_owner.GetTarget()));
452 }
453
454 return IsResolved();
455}
456
457bool BreakpointLocation::SetBreakpointSite(BreakpointSiteSP &bp_site_sp) {
458 m_bp_site_sp = bp_site_sp;
459 SendBreakpointLocationChangedEvent(eventKind: eBreakpointEventTypeLocationsResolved);
460 return true;
461}
462
463bool BreakpointLocation::ClearBreakpointSite() {
464 if (m_bp_site_sp.get()) {
465 ProcessSP process_sp(m_owner.GetTarget().GetProcessSP());
466 // If the process exists, get it to remove the owner, it will remove the
467 // physical implementation of the breakpoint as well if there are no more
468 // owners. Otherwise just remove this owner.
469 if (process_sp)
470 process_sp->RemoveConstituentFromBreakpointSite(site_id: GetBreakpoint().GetID(),
471 constituent_id: GetID(), bp_site_sp&: m_bp_site_sp);
472 else
473 m_bp_site_sp->RemoveConstituent(break_id: GetBreakpoint().GetID(), break_loc_id: GetID());
474
475 m_bp_site_sp.reset();
476 return true;
477 }
478 return false;
479}
480
481void BreakpointLocation::GetDescription(Stream *s,
482 lldb::DescriptionLevel level) {
483 SymbolContext sc;
484
485 // If the description level is "initial" then the breakpoint is printing out
486 // our initial state, and we should let it decide how it wants to print our
487 // label.
488 if (level != eDescriptionLevelInitial) {
489 s->Indent();
490 BreakpointID::GetCanonicalReference(s, break_id: m_owner.GetID(), break_loc_id: GetID());
491 }
492
493 if (level == lldb::eDescriptionLevelBrief)
494 return;
495
496 if (level != eDescriptionLevelInitial)
497 s->PutCString(cstr: ": ");
498
499 if (level == lldb::eDescriptionLevelVerbose)
500 s->IndentMore();
501
502 if (m_address.IsSectionOffset()) {
503 m_address.CalculateSymbolContext(sc: &sc);
504
505 if (level == lldb::eDescriptionLevelFull ||
506 level == eDescriptionLevelInitial) {
507 if (IsReExported())
508 s->PutCString(cstr: "re-exported target = ");
509 else
510 s->PutCString(cstr: "where = ");
511
512 // If there's a preferred line entry for printing, use that.
513 bool show_function_info = true;
514 if (auto preferred = GetPreferredLineEntry()) {
515 sc.line_entry = *preferred;
516 // FIXME: We're going to get the function name wrong when the preferred
517 // line entry is not the lowest one. For now, just leave the function
518 // out in this case, but we really should also figure out how to easily
519 // fake the function name here.
520 show_function_info = false;
521 }
522 sc.DumpStopContext(s, exe_scope: m_owner.GetTarget().GetProcessSP().get(), so_addr: m_address,
523 show_fullpaths: false, show_module: true, show_inlined_frames: false, show_function_arguments: show_function_info,
524 show_function_name: show_function_info, show_function_display_name: show_function_info);
525 } else {
526 if (sc.module_sp) {
527 s->EOL();
528 s->Indent(s: "module = ");
529 sc.module_sp->GetFileSpec().Dump(s&: s->AsRawOstream());
530 }
531
532 if (sc.comp_unit != nullptr) {
533 s->EOL();
534 s->Indent(s: "compile unit = ");
535 sc.comp_unit->GetPrimaryFile().GetFilename().Dump(s);
536
537 if (sc.function != nullptr) {
538 s->EOL();
539 s->Indent(s: "function = ");
540 s->PutCString(cstr: sc.function->GetName().AsCString(value_if_empty: "<unknown>"));
541 if (ConstString mangled_name =
542 sc.function->GetMangled().GetMangledName()) {
543 s->EOL();
544 s->Indent(s: "mangled function = ");
545 s->PutCString(cstr: mangled_name.AsCString());
546 }
547 }
548
549 if (sc.line_entry.line > 0) {
550 s->EOL();
551 s->Indent(s: "location = ");
552 if (auto preferred = GetPreferredLineEntry())
553 preferred->DumpStopContext(s, show_fullpaths: true);
554 else
555 sc.line_entry.DumpStopContext(s, show_fullpaths: true);
556 }
557
558 } else {
559 // If we don't have a comp unit, see if we have a symbol we can print.
560 if (sc.symbol) {
561 s->EOL();
562 if (IsReExported())
563 s->Indent(s: "re-exported target = ");
564 else
565 s->Indent(s: "symbol = ");
566 s->PutCString(cstr: sc.symbol->GetName().AsCString(value_if_empty: "<unknown>"));
567 }
568 }
569 }
570 }
571
572 if (level == lldb::eDescriptionLevelVerbose) {
573 s->EOL();
574 s->Indent();
575 }
576
577 if (m_address.IsSectionOffset() &&
578 (level == eDescriptionLevelFull || level == eDescriptionLevelInitial))
579 s->Printf(format: ", ");
580 s->Printf(format: "address = ");
581
582 ExecutionContextScope *exe_scope = nullptr;
583 Target *target = &m_owner.GetTarget();
584 if (target)
585 exe_scope = target->GetProcessSP().get();
586 if (exe_scope == nullptr)
587 exe_scope = target;
588
589 if (level == eDescriptionLevelInitial)
590 m_address.Dump(s, exe_scope, style: Address::DumpStyleLoadAddress,
591 fallback_style: Address::DumpStyleFileAddress);
592 else
593 m_address.Dump(s, exe_scope, style: Address::DumpStyleLoadAddress,
594 fallback_style: Address::DumpStyleModuleWithFileAddress);
595
596 if (IsIndirect() && m_bp_site_sp) {
597 Address resolved_address;
598 resolved_address.SetLoadAddress(load_addr: m_bp_site_sp->GetLoadAddress(), target);
599 Symbol *resolved_symbol = resolved_address.CalculateSymbolContextSymbol();
600 if (resolved_symbol) {
601 if (level == eDescriptionLevelFull || level == eDescriptionLevelInitial)
602 s->Printf(format: ", ");
603 else if (level == lldb::eDescriptionLevelVerbose) {
604 s->EOL();
605 s->Indent();
606 }
607 s->Printf(format: "indirect target = %s",
608 resolved_symbol->GetName().GetCString());
609 }
610 }
611
612 bool is_resolved = IsResolved();
613 bool is_hardware = is_resolved && m_bp_site_sp->IsHardware();
614
615 if (level == lldb::eDescriptionLevelVerbose) {
616 s->EOL();
617 s->Indent();
618 s->Printf(format: "resolved = %s\n", is_resolved ? "true" : "false");
619 s->Indent();
620 s->Printf(format: "hardware = %s\n", is_hardware ? "true" : "false");
621 s->Indent();
622 s->Printf(format: "hit count = %-4u\n", GetHitCount());
623
624 if (m_options_up) {
625 s->Indent();
626 m_options_up->GetDescription(s, level);
627 s->EOL();
628 }
629 s->IndentLess();
630 } else if (level != eDescriptionLevelInitial) {
631 s->Printf(format: ", %sresolved, %shit count = %u ", (is_resolved ? "" : "un"),
632 (is_hardware ? "hardware, " : ""), GetHitCount());
633 if (m_options_up) {
634 m_options_up->GetDescription(s, level);
635 }
636 }
637}
638
639void BreakpointLocation::Dump(Stream *s) const {
640 if (s == nullptr)
641 return;
642
643 bool is_resolved = IsResolved();
644 bool is_hardware = is_resolved && m_bp_site_sp->IsHardware();
645
646 lldb::tid_t tid = GetOptionsSpecifyingKind(kind: BreakpointOptions::eThreadSpec)
647 .GetThreadSpecNoCreate()
648 ->GetTID();
649 s->Printf(format: "BreakpointLocation %u: tid = %4.4" PRIx64
650 " load addr = 0x%8.8" PRIx64 " state = %s type = %s breakpoint "
651 "hit_count = %-4u ignore_count = %-4u",
652 GetID(), tid,
653 (uint64_t)m_address.GetOpcodeLoadAddress(target: &m_owner.GetTarget()),
654 (m_options_up ? m_options_up->IsEnabled() : m_owner.IsEnabled())
655 ? "enabled "
656 : "disabled",
657 is_hardware ? "hardware" : "software", GetHitCount(),
658 GetOptionsSpecifyingKind(kind: BreakpointOptions::eIgnoreCount)
659 .GetIgnoreCount());
660}
661
662void BreakpointLocation::SendBreakpointLocationChangedEvent(
663 lldb::BreakpointEventType eventKind) {
664 if (!m_owner.IsInternal() && m_owner.GetTarget().EventTypeHasListeners(
665 event_type: Target::eBroadcastBitBreakpointChanged)) {
666 auto data_sp = std::make_shared<Breakpoint::BreakpointEventData>(
667 args&: eventKind, args: m_owner.shared_from_this());
668 data_sp->GetBreakpointLocationCollection().Add(bp_loc_sp: shared_from_this());
669 m_owner.GetTarget().BroadcastEvent(event_type: Target::eBroadcastBitBreakpointChanged,
670 event_data_sp: data_sp);
671 }
672}
673
674std::optional<uint32_t> BreakpointLocation::GetSuggestedStackFrameIndex() {
675 auto preferred_opt = GetPreferredLineEntry();
676 if (!preferred_opt)
677 return {};
678 LineEntry preferred = *preferred_opt;
679 SymbolContext sc;
680 if (!m_address.CalculateSymbolContext(sc: &sc))
681 return {};
682 // Don't return anything special if frame 0 is the preferred line entry.
683 // We not really telling the stack frame list to do anything special in that
684 // case.
685 if (!LineEntry::Compare(lhs: sc.line_entry, rhs: preferred))
686 return {};
687
688 if (!sc.block)
689 return {};
690
691 // Blocks have their line info in Declaration form, so make one here:
692 Declaration preferred_decl(preferred.GetFile(), preferred.line,
693 preferred.column);
694
695 uint32_t depth = 0;
696 Block *inlined_block = sc.block->GetContainingInlinedBlock();
697 while (inlined_block) {
698 // If we've moved to a block that this isn't the start of, that's not
699 // our inlining info or call site, so we can stop here.
700 Address start_address;
701 if (!inlined_block->GetStartAddress(addr&: start_address) ||
702 start_address != m_address)
703 return {};
704
705 const InlineFunctionInfo *info = inlined_block->GetInlinedFunctionInfo();
706 if (info) {
707 if (preferred_decl == info->GetDeclaration())
708 return depth;
709 if (preferred_decl == info->GetCallSite())
710 return depth + 1;
711 }
712 inlined_block = inlined_block->GetInlinedParent();
713 depth++;
714 }
715 return {};
716}
717
718void BreakpointLocation::SwapLocation(BreakpointLocationSP swap_from) {
719 m_address = swap_from->m_address;
720 m_should_resolve_indirect_functions =
721 swap_from->m_should_resolve_indirect_functions;
722 m_is_reexported = swap_from->m_is_reexported;
723 m_is_indirect = swap_from->m_is_indirect;
724 m_user_expression_sp.reset();
725}
726
727void BreakpointLocation::SetThreadIDInternal(lldb::tid_t thread_id) {
728 if (thread_id != LLDB_INVALID_THREAD_ID)
729 GetLocationOptions().SetThreadID(thread_id);
730 else {
731 // If we're resetting this to an invalid thread id, then don't make an
732 // options pointer just to do that.
733 if (m_options_up != nullptr)
734 m_options_up->SetThreadID(thread_id);
735 }
736}
737

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of lldb/source/Breakpoint/BreakpointLocation.cpp