xref: /freebsd-src/contrib/llvm-project/lldb/source/Breakpoint/BreakpointLocation.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
15ffd83dbSDimitry Andric //===-- BreakpointLocation.cpp --------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "lldb/Breakpoint/BreakpointLocation.h"
100b57cec5SDimitry Andric #include "lldb/Breakpoint/BreakpointID.h"
110b57cec5SDimitry Andric #include "lldb/Breakpoint/StoppointCallbackContext.h"
120b57cec5SDimitry Andric #include "lldb/Core/Debugger.h"
130b57cec5SDimitry Andric #include "lldb/Core/Module.h"
140b57cec5SDimitry Andric #include "lldb/Core/ValueObject.h"
150b57cec5SDimitry Andric #include "lldb/Expression/DiagnosticManager.h"
160b57cec5SDimitry Andric #include "lldb/Expression/ExpressionVariable.h"
170b57cec5SDimitry Andric #include "lldb/Expression/UserExpression.h"
180b57cec5SDimitry Andric #include "lldb/Symbol/CompileUnit.h"
190b57cec5SDimitry Andric #include "lldb/Symbol/Symbol.h"
200b57cec5SDimitry Andric #include "lldb/Symbol/TypeSystem.h"
210b57cec5SDimitry Andric #include "lldb/Target/Process.h"
220b57cec5SDimitry Andric #include "lldb/Target/Target.h"
230b57cec5SDimitry Andric #include "lldb/Target/Thread.h"
240b57cec5SDimitry Andric #include "lldb/Target/ThreadSpec.h"
2581ad6265SDimitry Andric #include "lldb/Utility/LLDBLog.h"
260b57cec5SDimitry Andric #include "lldb/Utility/Log.h"
270b57cec5SDimitry Andric #include "lldb/Utility/StreamString.h"
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric using namespace lldb;
300b57cec5SDimitry Andric using namespace lldb_private;
310b57cec5SDimitry Andric 
320b57cec5SDimitry Andric BreakpointLocation::BreakpointLocation(break_id_t loc_id, Breakpoint &owner,
330b57cec5SDimitry Andric                                        const Address &addr, lldb::tid_t tid,
340b57cec5SDimitry Andric                                        bool hardware, bool check_for_resolver)
35*0fca6ea1SDimitry Andric     : m_should_resolve_indirect_functions(false), m_is_reexported(false),
36*0fca6ea1SDimitry Andric       m_is_indirect(false), m_address(addr), m_owner(owner),
37*0fca6ea1SDimitry Andric       m_condition_hash(0), m_loc_id(loc_id), m_hit_counter() {
380b57cec5SDimitry Andric   if (check_for_resolver) {
390b57cec5SDimitry Andric     Symbol *symbol = m_address.CalculateSymbolContextSymbol();
400b57cec5SDimitry Andric     if (symbol && symbol->IsIndirect()) {
410b57cec5SDimitry Andric       SetShouldResolveIndirectFunctions(true);
420b57cec5SDimitry Andric     }
430b57cec5SDimitry Andric   }
440b57cec5SDimitry Andric 
45*0fca6ea1SDimitry Andric   SetThreadIDInternal(tid);
460b57cec5SDimitry Andric }
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric BreakpointLocation::~BreakpointLocation() { ClearBreakpointSite(); }
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric lldb::addr_t BreakpointLocation::GetLoadAddress() const {
510b57cec5SDimitry Andric   return m_address.GetOpcodeLoadAddress(&m_owner.GetTarget());
520b57cec5SDimitry Andric }
530b57cec5SDimitry Andric 
54fe6060f1SDimitry Andric const BreakpointOptions &BreakpointLocation::GetOptionsSpecifyingKind(
55fe6060f1SDimitry Andric     BreakpointOptions::OptionKind kind) const {
560b57cec5SDimitry Andric   if (m_options_up && m_options_up->IsOptionSet(kind))
57fe6060f1SDimitry Andric     return *m_options_up;
580b57cec5SDimitry Andric   else
590b57cec5SDimitry Andric     return m_owner.GetOptions();
600b57cec5SDimitry Andric }
610b57cec5SDimitry Andric 
620b57cec5SDimitry Andric Address &BreakpointLocation::GetAddress() { return m_address; }
630b57cec5SDimitry Andric 
640b57cec5SDimitry Andric Breakpoint &BreakpointLocation::GetBreakpoint() { return m_owner; }
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric Target &BreakpointLocation::GetTarget() { return m_owner.GetTarget(); }
670b57cec5SDimitry Andric 
680b57cec5SDimitry Andric bool BreakpointLocation::IsEnabled() const {
690b57cec5SDimitry Andric   if (!m_owner.IsEnabled())
700b57cec5SDimitry Andric     return false;
710b57cec5SDimitry Andric   else if (m_options_up != nullptr)
720b57cec5SDimitry Andric     return m_options_up->IsEnabled();
730b57cec5SDimitry Andric   else
740b57cec5SDimitry Andric     return true;
750b57cec5SDimitry Andric }
760b57cec5SDimitry Andric 
770b57cec5SDimitry Andric void BreakpointLocation::SetEnabled(bool enabled) {
78fe6060f1SDimitry Andric   GetLocationOptions().SetEnabled(enabled);
790b57cec5SDimitry Andric   if (enabled) {
800b57cec5SDimitry Andric     ResolveBreakpointSite();
810b57cec5SDimitry Andric   } else {
820b57cec5SDimitry Andric     ClearBreakpointSite();
830b57cec5SDimitry Andric   }
840b57cec5SDimitry Andric   SendBreakpointLocationChangedEvent(enabled ? eBreakpointEventTypeEnabled
850b57cec5SDimitry Andric                                              : eBreakpointEventTypeDisabled);
860b57cec5SDimitry Andric }
870b57cec5SDimitry Andric 
880b57cec5SDimitry Andric bool BreakpointLocation::IsAutoContinue() const {
890b57cec5SDimitry Andric   if (m_options_up &&
900b57cec5SDimitry Andric       m_options_up->IsOptionSet(BreakpointOptions::eAutoContinue))
910b57cec5SDimitry Andric     return m_options_up->IsAutoContinue();
920b57cec5SDimitry Andric   else
930b57cec5SDimitry Andric     return m_owner.IsAutoContinue();
940b57cec5SDimitry Andric }
950b57cec5SDimitry Andric 
960b57cec5SDimitry Andric void BreakpointLocation::SetAutoContinue(bool auto_continue) {
97fe6060f1SDimitry Andric   GetLocationOptions().SetAutoContinue(auto_continue);
980b57cec5SDimitry Andric   SendBreakpointLocationChangedEvent(eBreakpointEventTypeAutoContinueChanged);
990b57cec5SDimitry Andric }
1000b57cec5SDimitry Andric 
1010b57cec5SDimitry Andric void BreakpointLocation::SetThreadID(lldb::tid_t thread_id) {
102*0fca6ea1SDimitry Andric   SetThreadIDInternal(thread_id);
1030b57cec5SDimitry Andric   SendBreakpointLocationChangedEvent(eBreakpointEventTypeThreadChanged);
1040b57cec5SDimitry Andric }
1050b57cec5SDimitry Andric 
1060b57cec5SDimitry Andric lldb::tid_t BreakpointLocation::GetThreadID() {
1070b57cec5SDimitry Andric   const ThreadSpec *thread_spec =
1080b57cec5SDimitry Andric       GetOptionsSpecifyingKind(BreakpointOptions::eThreadSpec)
109fe6060f1SDimitry Andric           .GetThreadSpecNoCreate();
1100b57cec5SDimitry Andric   if (thread_spec)
1110b57cec5SDimitry Andric     return thread_spec->GetTID();
1120b57cec5SDimitry Andric   else
1130b57cec5SDimitry Andric     return LLDB_INVALID_THREAD_ID;
1140b57cec5SDimitry Andric }
1150b57cec5SDimitry Andric 
1160b57cec5SDimitry Andric void BreakpointLocation::SetThreadIndex(uint32_t index) {
1170b57cec5SDimitry Andric   if (index != 0)
118fe6060f1SDimitry Andric     GetLocationOptions().GetThreadSpec()->SetIndex(index);
1190b57cec5SDimitry Andric   else {
1200b57cec5SDimitry Andric     // If we're resetting this to an invalid thread id, then don't make an
1210b57cec5SDimitry Andric     // options pointer just to do that.
1220b57cec5SDimitry Andric     if (m_options_up != nullptr)
1230b57cec5SDimitry Andric       m_options_up->GetThreadSpec()->SetIndex(index);
1240b57cec5SDimitry Andric   }
1250b57cec5SDimitry Andric   SendBreakpointLocationChangedEvent(eBreakpointEventTypeThreadChanged);
1260b57cec5SDimitry Andric }
1270b57cec5SDimitry Andric 
1280b57cec5SDimitry Andric uint32_t BreakpointLocation::GetThreadIndex() const {
1290b57cec5SDimitry Andric   const ThreadSpec *thread_spec =
1300b57cec5SDimitry Andric       GetOptionsSpecifyingKind(BreakpointOptions::eThreadSpec)
131fe6060f1SDimitry Andric           .GetThreadSpecNoCreate();
1320b57cec5SDimitry Andric   if (thread_spec)
1330b57cec5SDimitry Andric     return thread_spec->GetIndex();
1340b57cec5SDimitry Andric   else
1350b57cec5SDimitry Andric     return 0;
1360b57cec5SDimitry Andric }
1370b57cec5SDimitry Andric 
1380b57cec5SDimitry Andric void BreakpointLocation::SetThreadName(const char *thread_name) {
1390b57cec5SDimitry Andric   if (thread_name != nullptr)
140fe6060f1SDimitry Andric     GetLocationOptions().GetThreadSpec()->SetName(thread_name);
1410b57cec5SDimitry Andric   else {
1420b57cec5SDimitry Andric     // If we're resetting this to an invalid thread id, then don't make an
1430b57cec5SDimitry Andric     // options pointer just to do that.
1440b57cec5SDimitry Andric     if (m_options_up != nullptr)
1450b57cec5SDimitry Andric       m_options_up->GetThreadSpec()->SetName(thread_name);
1460b57cec5SDimitry Andric   }
1470b57cec5SDimitry Andric   SendBreakpointLocationChangedEvent(eBreakpointEventTypeThreadChanged);
1480b57cec5SDimitry Andric }
1490b57cec5SDimitry Andric 
1500b57cec5SDimitry Andric const char *BreakpointLocation::GetThreadName() const {
1510b57cec5SDimitry Andric   const ThreadSpec *thread_spec =
1520b57cec5SDimitry Andric       GetOptionsSpecifyingKind(BreakpointOptions::eThreadSpec)
153fe6060f1SDimitry Andric           .GetThreadSpecNoCreate();
1540b57cec5SDimitry Andric   if (thread_spec)
1550b57cec5SDimitry Andric     return thread_spec->GetName();
1560b57cec5SDimitry Andric   else
1570b57cec5SDimitry Andric     return nullptr;
1580b57cec5SDimitry Andric }
1590b57cec5SDimitry Andric 
1600b57cec5SDimitry Andric void BreakpointLocation::SetQueueName(const char *queue_name) {
1610b57cec5SDimitry Andric   if (queue_name != nullptr)
162fe6060f1SDimitry Andric     GetLocationOptions().GetThreadSpec()->SetQueueName(queue_name);
1630b57cec5SDimitry Andric   else {
1640b57cec5SDimitry Andric     // If we're resetting this to an invalid thread id, then don't make an
1650b57cec5SDimitry Andric     // options pointer just to do that.
1660b57cec5SDimitry Andric     if (m_options_up != nullptr)
1670b57cec5SDimitry Andric       m_options_up->GetThreadSpec()->SetQueueName(queue_name);
1680b57cec5SDimitry Andric   }
1690b57cec5SDimitry Andric   SendBreakpointLocationChangedEvent(eBreakpointEventTypeThreadChanged);
1700b57cec5SDimitry Andric }
1710b57cec5SDimitry Andric 
1720b57cec5SDimitry Andric const char *BreakpointLocation::GetQueueName() const {
1730b57cec5SDimitry Andric   const ThreadSpec *thread_spec =
1740b57cec5SDimitry Andric       GetOptionsSpecifyingKind(BreakpointOptions::eThreadSpec)
175fe6060f1SDimitry Andric           .GetThreadSpecNoCreate();
1760b57cec5SDimitry Andric   if (thread_spec)
1770b57cec5SDimitry Andric     return thread_spec->GetQueueName();
1780b57cec5SDimitry Andric   else
1790b57cec5SDimitry Andric     return nullptr;
1800b57cec5SDimitry Andric }
1810b57cec5SDimitry Andric 
1820b57cec5SDimitry Andric bool BreakpointLocation::InvokeCallback(StoppointCallbackContext *context) {
1830b57cec5SDimitry Andric   if (m_options_up != nullptr && m_options_up->HasCallback())
1840b57cec5SDimitry Andric     return m_options_up->InvokeCallback(context, m_owner.GetID(), GetID());
1850b57cec5SDimitry Andric   else
1860b57cec5SDimitry Andric     return m_owner.InvokeCallback(context, GetID());
1870b57cec5SDimitry Andric }
1880b57cec5SDimitry Andric 
189fe6060f1SDimitry Andric bool BreakpointLocation::IsCallbackSynchronous() {
190fe6060f1SDimitry Andric   if (m_options_up != nullptr && m_options_up->HasCallback())
191fe6060f1SDimitry Andric     return m_options_up->IsCallbackSynchronous();
192fe6060f1SDimitry Andric   else
193fe6060f1SDimitry Andric     return m_owner.GetOptions().IsCallbackSynchronous();
194fe6060f1SDimitry Andric }
195fe6060f1SDimitry Andric 
1960b57cec5SDimitry Andric void BreakpointLocation::SetCallback(BreakpointHitCallback callback,
1970b57cec5SDimitry Andric                                      void *baton, bool is_synchronous) {
1980b57cec5SDimitry Andric   // The default "Baton" class will keep a copy of "baton" and won't free or
1995f757f3fSDimitry Andric   // delete it when it goes out of scope.
200fe6060f1SDimitry Andric   GetLocationOptions().SetCallback(
2010b57cec5SDimitry Andric       callback, std::make_shared<UntypedBaton>(baton), is_synchronous);
2020b57cec5SDimitry Andric   SendBreakpointLocationChangedEvent(eBreakpointEventTypeCommandChanged);
2030b57cec5SDimitry Andric }
2040b57cec5SDimitry Andric 
2050b57cec5SDimitry Andric void BreakpointLocation::SetCallback(BreakpointHitCallback callback,
2060b57cec5SDimitry Andric                                      const BatonSP &baton_sp,
2070b57cec5SDimitry Andric                                      bool is_synchronous) {
208fe6060f1SDimitry Andric   GetLocationOptions().SetCallback(callback, baton_sp, is_synchronous);
2090b57cec5SDimitry Andric   SendBreakpointLocationChangedEvent(eBreakpointEventTypeCommandChanged);
2100b57cec5SDimitry Andric }
2110b57cec5SDimitry Andric 
2120b57cec5SDimitry Andric void BreakpointLocation::ClearCallback() {
213fe6060f1SDimitry Andric   GetLocationOptions().ClearCallback();
2140b57cec5SDimitry Andric }
2150b57cec5SDimitry Andric 
2160b57cec5SDimitry Andric void BreakpointLocation::SetCondition(const char *condition) {
217fe6060f1SDimitry Andric   GetLocationOptions().SetCondition(condition);
2180b57cec5SDimitry Andric   SendBreakpointLocationChangedEvent(eBreakpointEventTypeConditionChanged);
2190b57cec5SDimitry Andric }
2200b57cec5SDimitry Andric 
2210b57cec5SDimitry Andric const char *BreakpointLocation::GetConditionText(size_t *hash) const {
2220b57cec5SDimitry Andric   return GetOptionsSpecifyingKind(BreakpointOptions::eCondition)
223fe6060f1SDimitry Andric       .GetConditionText(hash);
2240b57cec5SDimitry Andric }
2250b57cec5SDimitry Andric 
2260b57cec5SDimitry Andric bool BreakpointLocation::ConditionSaysStop(ExecutionContext &exe_ctx,
2270b57cec5SDimitry Andric                                            Status &error) {
22881ad6265SDimitry Andric   Log *log = GetLog(LLDBLog::Breakpoints);
2290b57cec5SDimitry Andric 
2300b57cec5SDimitry Andric   std::lock_guard<std::mutex> guard(m_condition_mutex);
2310b57cec5SDimitry Andric 
2320b57cec5SDimitry Andric   size_t condition_hash;
2330b57cec5SDimitry Andric   const char *condition_text = GetConditionText(&condition_hash);
2340b57cec5SDimitry Andric 
2350b57cec5SDimitry Andric   if (!condition_text) {
2360b57cec5SDimitry Andric     m_user_expression_sp.reset();
2370b57cec5SDimitry Andric     return false;
2380b57cec5SDimitry Andric   }
2390b57cec5SDimitry Andric 
2400b57cec5SDimitry Andric   error.Clear();
2410b57cec5SDimitry Andric 
2420b57cec5SDimitry Andric   DiagnosticManager diagnostics;
2430b57cec5SDimitry Andric 
2440b57cec5SDimitry Andric   if (condition_hash != m_condition_hash || !m_user_expression_sp ||
2455f757f3fSDimitry Andric       !m_user_expression_sp->IsParseCacheable() ||
2460b57cec5SDimitry Andric       !m_user_expression_sp->MatchesContext(exe_ctx)) {
2470b57cec5SDimitry Andric     LanguageType language = eLanguageTypeUnknown;
2480b57cec5SDimitry Andric     // See if we can figure out the language from the frame, otherwise use the
2490b57cec5SDimitry Andric     // default language:
2500b57cec5SDimitry Andric     CompileUnit *comp_unit = m_address.CalculateSymbolContextCompileUnit();
2510b57cec5SDimitry Andric     if (comp_unit)
2520b57cec5SDimitry Andric       language = comp_unit->GetLanguage();
2530b57cec5SDimitry Andric 
2540b57cec5SDimitry Andric     m_user_expression_sp.reset(GetTarget().GetUserExpressionForLanguage(
2550b57cec5SDimitry Andric         condition_text, llvm::StringRef(), language, Expression::eResultTypeAny,
2560b57cec5SDimitry Andric         EvaluateExpressionOptions(), nullptr, error));
2570b57cec5SDimitry Andric     if (error.Fail()) {
2589dba64beSDimitry Andric       LLDB_LOGF(log, "Error getting condition expression: %s.",
2590b57cec5SDimitry Andric                 error.AsCString());
2600b57cec5SDimitry Andric       m_user_expression_sp.reset();
2610b57cec5SDimitry Andric       return true;
2620b57cec5SDimitry Andric     }
2630b57cec5SDimitry Andric 
2640b57cec5SDimitry Andric     if (!m_user_expression_sp->Parse(diagnostics, exe_ctx,
2650b57cec5SDimitry Andric                                      eExecutionPolicyOnlyWhenNeeded, true,
2660b57cec5SDimitry Andric                                      false)) {
2670b57cec5SDimitry Andric       error.SetErrorStringWithFormat(
2680b57cec5SDimitry Andric           "Couldn't parse conditional expression:\n%s",
2690b57cec5SDimitry Andric           diagnostics.GetString().c_str());
2700b57cec5SDimitry Andric       m_user_expression_sp.reset();
2710b57cec5SDimitry Andric       return true;
2720b57cec5SDimitry Andric     }
2730b57cec5SDimitry Andric 
2740b57cec5SDimitry Andric     m_condition_hash = condition_hash;
2750b57cec5SDimitry Andric   }
2760b57cec5SDimitry Andric 
2770b57cec5SDimitry Andric   // We need to make sure the user sees any parse errors in their condition, so
2780b57cec5SDimitry Andric   // we'll hook the constructor errors up to the debugger's Async I/O.
2790b57cec5SDimitry Andric 
2800b57cec5SDimitry Andric   ValueObjectSP result_value_sp;
2810b57cec5SDimitry Andric 
2820b57cec5SDimitry Andric   EvaluateExpressionOptions options;
2830b57cec5SDimitry Andric   options.SetUnwindOnError(true);
2840b57cec5SDimitry Andric   options.SetIgnoreBreakpoints(true);
2850b57cec5SDimitry Andric   options.SetTryAllThreads(true);
28606c3fb27SDimitry Andric   options.SetSuppressPersistentResult(
2870b57cec5SDimitry Andric       true); // Don't generate a user variable for condition expressions.
2880b57cec5SDimitry Andric 
2890b57cec5SDimitry Andric   Status expr_error;
2900b57cec5SDimitry Andric 
2910b57cec5SDimitry Andric   diagnostics.Clear();
2920b57cec5SDimitry Andric 
2930b57cec5SDimitry Andric   ExpressionVariableSP result_variable_sp;
2940b57cec5SDimitry Andric 
2950b57cec5SDimitry Andric   ExpressionResults result_code = m_user_expression_sp->Execute(
2960b57cec5SDimitry Andric       diagnostics, exe_ctx, options, m_user_expression_sp, result_variable_sp);
2970b57cec5SDimitry Andric 
2980b57cec5SDimitry Andric   bool ret;
2990b57cec5SDimitry Andric 
3000b57cec5SDimitry Andric   if (result_code == eExpressionCompleted) {
3010b57cec5SDimitry Andric     if (!result_variable_sp) {
3020b57cec5SDimitry Andric       error.SetErrorString("Expression did not return a result");
3030b57cec5SDimitry Andric       return false;
3040b57cec5SDimitry Andric     }
3050b57cec5SDimitry Andric 
3060b57cec5SDimitry Andric     result_value_sp = result_variable_sp->GetValueObject();
3070b57cec5SDimitry Andric 
3080b57cec5SDimitry Andric     if (result_value_sp) {
3090b57cec5SDimitry Andric       ret = result_value_sp->IsLogicalTrue(error);
3100b57cec5SDimitry Andric       if (log) {
3110b57cec5SDimitry Andric         if (error.Success()) {
3129dba64beSDimitry Andric           LLDB_LOGF(log, "Condition successfully evaluated, result is %s.\n",
3130b57cec5SDimitry Andric                     ret ? "true" : "false");
3140b57cec5SDimitry Andric         } else {
3150b57cec5SDimitry Andric           error.SetErrorString(
3160b57cec5SDimitry Andric               "Failed to get an integer result from the expression");
3170b57cec5SDimitry Andric           ret = false;
3180b57cec5SDimitry Andric         }
3190b57cec5SDimitry Andric       }
3200b57cec5SDimitry Andric     } else {
3210b57cec5SDimitry Andric       ret = false;
3220b57cec5SDimitry Andric       error.SetErrorString("Failed to get any result from the expression");
3230b57cec5SDimitry Andric     }
3240b57cec5SDimitry Andric   } else {
3250b57cec5SDimitry Andric     ret = false;
3260b57cec5SDimitry Andric     error.SetErrorStringWithFormat("Couldn't execute expression:\n%s",
3270b57cec5SDimitry Andric                                    diagnostics.GetString().c_str());
3280b57cec5SDimitry Andric   }
3290b57cec5SDimitry Andric 
3300b57cec5SDimitry Andric   return ret;
3310b57cec5SDimitry Andric }
3320b57cec5SDimitry Andric 
333e8d8bef9SDimitry Andric uint32_t BreakpointLocation::GetIgnoreCount() const {
3340b57cec5SDimitry Andric   return GetOptionsSpecifyingKind(BreakpointOptions::eIgnoreCount)
335fe6060f1SDimitry Andric       .GetIgnoreCount();
3360b57cec5SDimitry Andric }
3370b57cec5SDimitry Andric 
3380b57cec5SDimitry Andric void BreakpointLocation::SetIgnoreCount(uint32_t n) {
339fe6060f1SDimitry Andric   GetLocationOptions().SetIgnoreCount(n);
3400b57cec5SDimitry Andric   SendBreakpointLocationChangedEvent(eBreakpointEventTypeIgnoreChanged);
3410b57cec5SDimitry Andric }
3420b57cec5SDimitry Andric 
3430b57cec5SDimitry Andric void BreakpointLocation::DecrementIgnoreCount() {
3440b57cec5SDimitry Andric   if (m_options_up != nullptr) {
3450b57cec5SDimitry Andric     uint32_t loc_ignore = m_options_up->GetIgnoreCount();
3460b57cec5SDimitry Andric     if (loc_ignore != 0)
3470b57cec5SDimitry Andric       m_options_up->SetIgnoreCount(loc_ignore - 1);
3480b57cec5SDimitry Andric   }
3490b57cec5SDimitry Andric }
3500b57cec5SDimitry Andric 
3510b57cec5SDimitry Andric bool BreakpointLocation::IgnoreCountShouldStop() {
352fe6060f1SDimitry Andric   uint32_t owner_ignore = GetBreakpoint().GetIgnoreCount();
353fe6060f1SDimitry Andric   uint32_t loc_ignore = 0;
354fe6060f1SDimitry Andric   if (m_options_up != nullptr)
355fe6060f1SDimitry Andric     loc_ignore = m_options_up->GetIgnoreCount();
356fe6060f1SDimitry Andric 
357fe6060f1SDimitry Andric   if (loc_ignore != 0 || owner_ignore != 0) {
3580b57cec5SDimitry Andric     m_owner.DecrementIgnoreCount();
3590b57cec5SDimitry Andric     DecrementIgnoreCount(); // Have to decrement our owners' ignore count,
360fe6060f1SDimitry Andric                             // since it won't get a chance to.
3610b57cec5SDimitry Andric     return false;
3620b57cec5SDimitry Andric   }
3630b57cec5SDimitry Andric   return true;
3640b57cec5SDimitry Andric }
3650b57cec5SDimitry Andric 
366fe6060f1SDimitry Andric BreakpointOptions &BreakpointLocation::GetLocationOptions() {
3670b57cec5SDimitry Andric   // If we make the copy we don't copy the callbacks because that is
3680b57cec5SDimitry Andric   // potentially expensive and we don't want to do that for the simple case
3690b57cec5SDimitry Andric   // where someone is just disabling the location.
3700b57cec5SDimitry Andric   if (m_options_up == nullptr)
3715ffd83dbSDimitry Andric     m_options_up = std::make_unique<BreakpointOptions>(false);
3720b57cec5SDimitry Andric 
373fe6060f1SDimitry Andric   return *m_options_up;
3740b57cec5SDimitry Andric }
3750b57cec5SDimitry Andric 
376fe6060f1SDimitry Andric bool BreakpointLocation::ValidForThisThread(Thread &thread) {
377fe6060f1SDimitry Andric   return thread.MatchesSpec(
378fe6060f1SDimitry Andric       GetOptionsSpecifyingKind(BreakpointOptions::eThreadSpec)
379fe6060f1SDimitry Andric           .GetThreadSpecNoCreate());
3800b57cec5SDimitry Andric }
3810b57cec5SDimitry Andric 
3820b57cec5SDimitry Andric // RETURNS - true if we should stop at this breakpoint, false if we
3830b57cec5SDimitry Andric // should continue.  Note, we don't check the thread spec for the breakpoint
3840b57cec5SDimitry Andric // here, since if the breakpoint is not for this thread, then the event won't
3850b57cec5SDimitry Andric // even get reported, so the check is redundant.
3860b57cec5SDimitry Andric 
3870b57cec5SDimitry Andric bool BreakpointLocation::ShouldStop(StoppointCallbackContext *context) {
3880b57cec5SDimitry Andric   bool should_stop = true;
38981ad6265SDimitry Andric   Log *log = GetLog(LLDBLog::Breakpoints);
3900b57cec5SDimitry Andric 
3910b57cec5SDimitry Andric   // Do this first, if a location is disabled, it shouldn't increment its hit
3920b57cec5SDimitry Andric   // count.
3930b57cec5SDimitry Andric   if (!IsEnabled())
3940b57cec5SDimitry Andric     return false;
3950b57cec5SDimitry Andric 
3960b57cec5SDimitry Andric   // We only run synchronous callbacks in ShouldStop:
3970b57cec5SDimitry Andric   context->is_synchronous = true;
3980b57cec5SDimitry Andric   should_stop = InvokeCallback(context);
3990b57cec5SDimitry Andric 
4000b57cec5SDimitry Andric   if (log) {
4010b57cec5SDimitry Andric     StreamString s;
4020b57cec5SDimitry Andric     GetDescription(&s, lldb::eDescriptionLevelVerbose);
4039dba64beSDimitry Andric     LLDB_LOGF(log, "Hit breakpoint location: %s, %s.\n", s.GetData(),
4040b57cec5SDimitry Andric               should_stop ? "stopping" : "continuing");
4050b57cec5SDimitry Andric   }
4060b57cec5SDimitry Andric 
4070b57cec5SDimitry Andric   return should_stop;
4080b57cec5SDimitry Andric }
4090b57cec5SDimitry Andric 
4100b57cec5SDimitry Andric void BreakpointLocation::BumpHitCount() {
4110b57cec5SDimitry Andric   if (IsEnabled()) {
4120b57cec5SDimitry Andric     // Step our hit count, and also step the hit count of the owner.
413e8d8bef9SDimitry Andric     m_hit_counter.Increment();
414e8d8bef9SDimitry Andric     m_owner.m_hit_counter.Increment();
4150b57cec5SDimitry Andric   }
4160b57cec5SDimitry Andric }
4170b57cec5SDimitry Andric 
4180b57cec5SDimitry Andric void BreakpointLocation::UndoBumpHitCount() {
4190b57cec5SDimitry Andric   if (IsEnabled()) {
4200b57cec5SDimitry Andric     // Step our hit count, and also step the hit count of the owner.
421e8d8bef9SDimitry Andric     m_hit_counter.Decrement();
422e8d8bef9SDimitry Andric     m_owner.m_hit_counter.Decrement();
4230b57cec5SDimitry Andric   }
4240b57cec5SDimitry Andric }
4250b57cec5SDimitry Andric 
4260b57cec5SDimitry Andric bool BreakpointLocation::IsResolved() const {
4270b57cec5SDimitry Andric   return m_bp_site_sp.get() != nullptr;
4280b57cec5SDimitry Andric }
4290b57cec5SDimitry Andric 
4300b57cec5SDimitry Andric lldb::BreakpointSiteSP BreakpointLocation::GetBreakpointSite() const {
4310b57cec5SDimitry Andric   return m_bp_site_sp;
4320b57cec5SDimitry Andric }
4330b57cec5SDimitry Andric 
4340b57cec5SDimitry Andric bool BreakpointLocation::ResolveBreakpointSite() {
4350b57cec5SDimitry Andric   if (m_bp_site_sp)
4360b57cec5SDimitry Andric     return true;
4370b57cec5SDimitry Andric 
4380b57cec5SDimitry Andric   Process *process = m_owner.GetTarget().GetProcessSP().get();
4390b57cec5SDimitry Andric   if (process == nullptr)
4400b57cec5SDimitry Andric     return false;
4410b57cec5SDimitry Andric 
4420b57cec5SDimitry Andric   lldb::break_id_t new_id =
4430b57cec5SDimitry Andric       process->CreateBreakpointSite(shared_from_this(), m_owner.IsHardware());
4440b57cec5SDimitry Andric 
4450b57cec5SDimitry Andric   if (new_id == LLDB_INVALID_BREAK_ID) {
44681ad6265SDimitry Andric     Log *log = GetLog(LLDBLog::Breakpoints);
4470b57cec5SDimitry Andric     if (log)
4480b57cec5SDimitry Andric       log->Warning("Failed to add breakpoint site at 0x%" PRIx64,
4490b57cec5SDimitry Andric                    m_address.GetOpcodeLoadAddress(&m_owner.GetTarget()));
4500b57cec5SDimitry Andric   }
4510b57cec5SDimitry Andric 
4520b57cec5SDimitry Andric   return IsResolved();
4530b57cec5SDimitry Andric }
4540b57cec5SDimitry Andric 
4550b57cec5SDimitry Andric bool BreakpointLocation::SetBreakpointSite(BreakpointSiteSP &bp_site_sp) {
4560b57cec5SDimitry Andric   m_bp_site_sp = bp_site_sp;
4570b57cec5SDimitry Andric   SendBreakpointLocationChangedEvent(eBreakpointEventTypeLocationsResolved);
4580b57cec5SDimitry Andric   return true;
4590b57cec5SDimitry Andric }
4600b57cec5SDimitry Andric 
4610b57cec5SDimitry Andric bool BreakpointLocation::ClearBreakpointSite() {
4620b57cec5SDimitry Andric   if (m_bp_site_sp.get()) {
4630b57cec5SDimitry Andric     ProcessSP process_sp(m_owner.GetTarget().GetProcessSP());
4640b57cec5SDimitry Andric     // If the process exists, get it to remove the owner, it will remove the
4650b57cec5SDimitry Andric     // physical implementation of the breakpoint as well if there are no more
4660b57cec5SDimitry Andric     // owners.  Otherwise just remove this owner.
4670b57cec5SDimitry Andric     if (process_sp)
4685f757f3fSDimitry Andric       process_sp->RemoveConstituentFromBreakpointSite(GetBreakpoint().GetID(),
4690b57cec5SDimitry Andric                                                       GetID(), m_bp_site_sp);
4700b57cec5SDimitry Andric     else
4715f757f3fSDimitry Andric       m_bp_site_sp->RemoveConstituent(GetBreakpoint().GetID(), GetID());
4720b57cec5SDimitry Andric 
4730b57cec5SDimitry Andric     m_bp_site_sp.reset();
4740b57cec5SDimitry Andric     return true;
4750b57cec5SDimitry Andric   }
4760b57cec5SDimitry Andric   return false;
4770b57cec5SDimitry Andric }
4780b57cec5SDimitry Andric 
4790b57cec5SDimitry Andric void BreakpointLocation::GetDescription(Stream *s,
4800b57cec5SDimitry Andric                                         lldb::DescriptionLevel level) {
4810b57cec5SDimitry Andric   SymbolContext sc;
4820b57cec5SDimitry Andric 
4830b57cec5SDimitry Andric   // If the description level is "initial" then the breakpoint is printing out
4840b57cec5SDimitry Andric   // our initial state, and we should let it decide how it wants to print our
4850b57cec5SDimitry Andric   // label.
4860b57cec5SDimitry Andric   if (level != eDescriptionLevelInitial) {
4870b57cec5SDimitry Andric     s->Indent();
4880b57cec5SDimitry Andric     BreakpointID::GetCanonicalReference(s, m_owner.GetID(), GetID());
4890b57cec5SDimitry Andric   }
4900b57cec5SDimitry Andric 
4910b57cec5SDimitry Andric   if (level == lldb::eDescriptionLevelBrief)
4920b57cec5SDimitry Andric     return;
4930b57cec5SDimitry Andric 
4940b57cec5SDimitry Andric   if (level != eDescriptionLevelInitial)
4950b57cec5SDimitry Andric     s->PutCString(": ");
4960b57cec5SDimitry Andric 
4970b57cec5SDimitry Andric   if (level == lldb::eDescriptionLevelVerbose)
4980b57cec5SDimitry Andric     s->IndentMore();
4990b57cec5SDimitry Andric 
5000b57cec5SDimitry Andric   if (m_address.IsSectionOffset()) {
5010b57cec5SDimitry Andric     m_address.CalculateSymbolContext(&sc);
5020b57cec5SDimitry Andric 
5030b57cec5SDimitry Andric     if (level == lldb::eDescriptionLevelFull ||
5040b57cec5SDimitry Andric         level == eDescriptionLevelInitial) {
5050b57cec5SDimitry Andric       if (IsReExported())
5060b57cec5SDimitry Andric         s->PutCString("re-exported target = ");
5070b57cec5SDimitry Andric       else
5080b57cec5SDimitry Andric         s->PutCString("where = ");
5090b57cec5SDimitry Andric       sc.DumpStopContext(s, m_owner.GetTarget().GetProcessSP().get(), m_address,
510*0fca6ea1SDimitry Andric                          false, true, false, true, true, true);
5110b57cec5SDimitry Andric     } else {
5120b57cec5SDimitry Andric       if (sc.module_sp) {
5130b57cec5SDimitry Andric         s->EOL();
5140b57cec5SDimitry Andric         s->Indent("module = ");
515480093f4SDimitry Andric         sc.module_sp->GetFileSpec().Dump(s->AsRawOstream());
5160b57cec5SDimitry Andric       }
5170b57cec5SDimitry Andric 
5180b57cec5SDimitry Andric       if (sc.comp_unit != nullptr) {
5190b57cec5SDimitry Andric         s->EOL();
5200b57cec5SDimitry Andric         s->Indent("compile unit = ");
521480093f4SDimitry Andric         sc.comp_unit->GetPrimaryFile().GetFilename().Dump(s);
5220b57cec5SDimitry Andric 
5230b57cec5SDimitry Andric         if (sc.function != nullptr) {
5240b57cec5SDimitry Andric           s->EOL();
5250b57cec5SDimitry Andric           s->Indent("function = ");
5260b57cec5SDimitry Andric           s->PutCString(sc.function->GetName().AsCString("<unknown>"));
527*0fca6ea1SDimitry Andric           if (ConstString mangled_name =
528*0fca6ea1SDimitry Andric                   sc.function->GetMangled().GetMangledName()) {
529*0fca6ea1SDimitry Andric             s->EOL();
530*0fca6ea1SDimitry Andric             s->Indent("mangled function = ");
531*0fca6ea1SDimitry Andric             s->PutCString(mangled_name.AsCString());
532*0fca6ea1SDimitry Andric           }
5330b57cec5SDimitry Andric         }
5340b57cec5SDimitry Andric 
5350b57cec5SDimitry Andric         if (sc.line_entry.line > 0) {
5360b57cec5SDimitry Andric           s->EOL();
5370b57cec5SDimitry Andric           s->Indent("location = ");
5380b57cec5SDimitry Andric           sc.line_entry.DumpStopContext(s, true);
5390b57cec5SDimitry Andric         }
5400b57cec5SDimitry Andric 
5410b57cec5SDimitry Andric       } else {
5420b57cec5SDimitry Andric         // If we don't have a comp unit, see if we have a symbol we can print.
5430b57cec5SDimitry Andric         if (sc.symbol) {
5440b57cec5SDimitry Andric           s->EOL();
5450b57cec5SDimitry Andric           if (IsReExported())
5460b57cec5SDimitry Andric             s->Indent("re-exported target = ");
5470b57cec5SDimitry Andric           else
5480b57cec5SDimitry Andric             s->Indent("symbol = ");
5490b57cec5SDimitry Andric           s->PutCString(sc.symbol->GetName().AsCString("<unknown>"));
5500b57cec5SDimitry Andric         }
5510b57cec5SDimitry Andric       }
5520b57cec5SDimitry Andric     }
5530b57cec5SDimitry Andric   }
5540b57cec5SDimitry Andric 
5550b57cec5SDimitry Andric   if (level == lldb::eDescriptionLevelVerbose) {
5560b57cec5SDimitry Andric     s->EOL();
5570b57cec5SDimitry Andric     s->Indent();
5580b57cec5SDimitry Andric   }
5590b57cec5SDimitry Andric 
5600b57cec5SDimitry Andric   if (m_address.IsSectionOffset() &&
5610b57cec5SDimitry Andric       (level == eDescriptionLevelFull || level == eDescriptionLevelInitial))
5620b57cec5SDimitry Andric     s->Printf(", ");
5630b57cec5SDimitry Andric   s->Printf("address = ");
5640b57cec5SDimitry Andric 
5650b57cec5SDimitry Andric   ExecutionContextScope *exe_scope = nullptr;
5660b57cec5SDimitry Andric   Target *target = &m_owner.GetTarget();
5670b57cec5SDimitry Andric   if (target)
5680b57cec5SDimitry Andric     exe_scope = target->GetProcessSP().get();
5690b57cec5SDimitry Andric   if (exe_scope == nullptr)
5700b57cec5SDimitry Andric     exe_scope = target;
5710b57cec5SDimitry Andric 
5720b57cec5SDimitry Andric   if (level == eDescriptionLevelInitial)
5730b57cec5SDimitry Andric     m_address.Dump(s, exe_scope, Address::DumpStyleLoadAddress,
5740b57cec5SDimitry Andric                    Address::DumpStyleFileAddress);
5750b57cec5SDimitry Andric   else
5760b57cec5SDimitry Andric     m_address.Dump(s, exe_scope, Address::DumpStyleLoadAddress,
5770b57cec5SDimitry Andric                    Address::DumpStyleModuleWithFileAddress);
5780b57cec5SDimitry Andric 
5790b57cec5SDimitry Andric   if (IsIndirect() && m_bp_site_sp) {
5800b57cec5SDimitry Andric     Address resolved_address;
5810b57cec5SDimitry Andric     resolved_address.SetLoadAddress(m_bp_site_sp->GetLoadAddress(), target);
5820b57cec5SDimitry Andric     Symbol *resolved_symbol = resolved_address.CalculateSymbolContextSymbol();
5830b57cec5SDimitry Andric     if (resolved_symbol) {
5840b57cec5SDimitry Andric       if (level == eDescriptionLevelFull || level == eDescriptionLevelInitial)
5850b57cec5SDimitry Andric         s->Printf(", ");
5860b57cec5SDimitry Andric       else if (level == lldb::eDescriptionLevelVerbose) {
5870b57cec5SDimitry Andric         s->EOL();
5880b57cec5SDimitry Andric         s->Indent();
5890b57cec5SDimitry Andric       }
5900b57cec5SDimitry Andric       s->Printf("indirect target = %s",
5910b57cec5SDimitry Andric                 resolved_symbol->GetName().GetCString());
5920b57cec5SDimitry Andric     }
5930b57cec5SDimitry Andric   }
5940b57cec5SDimitry Andric 
595e8d8bef9SDimitry Andric   bool is_resolved = IsResolved();
596e8d8bef9SDimitry Andric   bool is_hardware = is_resolved && m_bp_site_sp->IsHardware();
597e8d8bef9SDimitry Andric 
5980b57cec5SDimitry Andric   if (level == lldb::eDescriptionLevelVerbose) {
5990b57cec5SDimitry Andric     s->EOL();
6000b57cec5SDimitry Andric     s->Indent();
601e8d8bef9SDimitry Andric     s->Printf("resolved = %s\n", is_resolved ? "true" : "false");
6025ffd83dbSDimitry Andric     s->Indent();
603e8d8bef9SDimitry Andric     s->Printf("hardware = %s\n", is_hardware ? "true" : "false");
6040b57cec5SDimitry Andric     s->Indent();
6050b57cec5SDimitry Andric     s->Printf("hit count = %-4u\n", GetHitCount());
6060b57cec5SDimitry Andric 
6070b57cec5SDimitry Andric     if (m_options_up) {
6080b57cec5SDimitry Andric       s->Indent();
6090b57cec5SDimitry Andric       m_options_up->GetDescription(s, level);
6100b57cec5SDimitry Andric       s->EOL();
6110b57cec5SDimitry Andric     }
6120b57cec5SDimitry Andric     s->IndentLess();
6130b57cec5SDimitry Andric   } else if (level != eDescriptionLevelInitial) {
614e8d8bef9SDimitry Andric     s->Printf(", %sresolved, %shit count = %u ", (is_resolved ? "" : "un"),
615e8d8bef9SDimitry Andric               (is_hardware ? "hardware, " : ""), GetHitCount());
6160b57cec5SDimitry Andric     if (m_options_up) {
6170b57cec5SDimitry Andric       m_options_up->GetDescription(s, level);
6180b57cec5SDimitry Andric     }
6190b57cec5SDimitry Andric   }
6200b57cec5SDimitry Andric }
6210b57cec5SDimitry Andric 
6220b57cec5SDimitry Andric void BreakpointLocation::Dump(Stream *s) const {
6230b57cec5SDimitry Andric   if (s == nullptr)
6240b57cec5SDimitry Andric     return;
6250b57cec5SDimitry Andric 
626e8d8bef9SDimitry Andric   bool is_resolved = IsResolved();
627e8d8bef9SDimitry Andric   bool is_hardware = is_resolved && m_bp_site_sp->IsHardware();
628e8d8bef9SDimitry Andric 
6290b57cec5SDimitry Andric   lldb::tid_t tid = GetOptionsSpecifyingKind(BreakpointOptions::eThreadSpec)
630fe6060f1SDimitry Andric                         .GetThreadSpecNoCreate()
631fe6060f1SDimitry Andric                         ->GetTID();
6320b57cec5SDimitry Andric   s->Printf("BreakpointLocation %u: tid = %4.4" PRIx64
6330b57cec5SDimitry Andric             "  load addr = 0x%8.8" PRIx64 "  state = %s  type = %s breakpoint  "
6345f757f3fSDimitry Andric             "hit_count = %-4u  ignore_count = %-4u",
6350b57cec5SDimitry Andric             GetID(), tid,
6360b57cec5SDimitry Andric             (uint64_t)m_address.GetOpcodeLoadAddress(&m_owner.GetTarget()),
6370b57cec5SDimitry Andric             (m_options_up ? m_options_up->IsEnabled() : m_owner.IsEnabled())
6380b57cec5SDimitry Andric                 ? "enabled "
6390b57cec5SDimitry Andric                 : "disabled",
6405f757f3fSDimitry Andric             is_hardware ? "hardware" : "software", GetHitCount(),
6410b57cec5SDimitry Andric             GetOptionsSpecifyingKind(BreakpointOptions::eIgnoreCount)
642fe6060f1SDimitry Andric                 .GetIgnoreCount());
6430b57cec5SDimitry Andric }
6440b57cec5SDimitry Andric 
6450b57cec5SDimitry Andric void BreakpointLocation::SendBreakpointLocationChangedEvent(
6460b57cec5SDimitry Andric     lldb::BreakpointEventType eventKind) {
647*0fca6ea1SDimitry Andric   if (!m_owner.IsInternal() && m_owner.GetTarget().EventTypeHasListeners(
6480b57cec5SDimitry Andric                                    Target::eBroadcastBitBreakpointChanged)) {
6497a6dacacSDimitry Andric     auto data_sp = std::make_shared<Breakpoint::BreakpointEventData>(
6500b57cec5SDimitry Andric         eventKind, m_owner.shared_from_this());
6517a6dacacSDimitry Andric     data_sp->GetBreakpointLocationCollection().Add(shared_from_this());
6520b57cec5SDimitry Andric     m_owner.GetTarget().BroadcastEvent(Target::eBroadcastBitBreakpointChanged,
6537a6dacacSDimitry Andric                                        data_sp);
6540b57cec5SDimitry Andric   }
6550b57cec5SDimitry Andric }
6560b57cec5SDimitry Andric 
6570b57cec5SDimitry Andric void BreakpointLocation::SwapLocation(BreakpointLocationSP swap_from) {
6580b57cec5SDimitry Andric   m_address = swap_from->m_address;
6590b57cec5SDimitry Andric   m_should_resolve_indirect_functions =
6600b57cec5SDimitry Andric       swap_from->m_should_resolve_indirect_functions;
6610b57cec5SDimitry Andric   m_is_reexported = swap_from->m_is_reexported;
6620b57cec5SDimitry Andric   m_is_indirect = swap_from->m_is_indirect;
6630b57cec5SDimitry Andric   m_user_expression_sp.reset();
6640b57cec5SDimitry Andric }
665*0fca6ea1SDimitry Andric 
666*0fca6ea1SDimitry Andric void BreakpointLocation::SetThreadIDInternal(lldb::tid_t thread_id) {
667*0fca6ea1SDimitry Andric   if (thread_id != LLDB_INVALID_THREAD_ID)
668*0fca6ea1SDimitry Andric     GetLocationOptions().SetThreadID(thread_id);
669*0fca6ea1SDimitry Andric   else {
670*0fca6ea1SDimitry Andric     // If we're resetting this to an invalid thread id, then don't make an
671*0fca6ea1SDimitry Andric     // options pointer just to do that.
672*0fca6ea1SDimitry Andric     if (m_options_up != nullptr)
673*0fca6ea1SDimitry Andric       m_options_up->SetThreadID(thread_id);
674*0fca6ea1SDimitry Andric   }
675*0fca6ea1SDimitry Andric }
676