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

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