forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			671 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			671 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			C++
		
	
	
	
//===-- BreakpointLocation.cpp ----------------------------------*- C++ -*-===//
 | 
						|
//
 | 
						|
//                     The LLVM Compiler Infrastructure
 | 
						|
//
 | 
						|
// This file is distributed under the University of Illinois Open Source
 | 
						|
// License. See LICENSE.TXT for details.
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
// C Includes
 | 
						|
// C++ Includes
 | 
						|
// Other libraries and framework includes
 | 
						|
// Project includes
 | 
						|
#include "lldb/Breakpoint/BreakpointLocation.h"
 | 
						|
#include "lldb/Breakpoint/BreakpointID.h"
 | 
						|
#include "lldb/Breakpoint/StoppointCallbackContext.h"
 | 
						|
#include "lldb/Core/Debugger.h"
 | 
						|
#include "lldb/Core/Module.h"
 | 
						|
#include "lldb/Core/ValueObject.h"
 | 
						|
#include "lldb/Expression/DiagnosticManager.h"
 | 
						|
#include "lldb/Expression/ExpressionVariable.h"
 | 
						|
#include "lldb/Expression/UserExpression.h"
 | 
						|
#include "lldb/Symbol/CompileUnit.h"
 | 
						|
#include "lldb/Symbol/Symbol.h"
 | 
						|
#include "lldb/Symbol/TypeSystem.h"
 | 
						|
#include "lldb/Target/Process.h"
 | 
						|
#include "lldb/Target/Target.h"
 | 
						|
#include "lldb/Target/Thread.h"
 | 
						|
#include "lldb/Target/ThreadSpec.h"
 | 
						|
#include "lldb/Utility/Log.h"
 | 
						|
#include "lldb/Utility/StreamString.h"
 | 
						|
 | 
						|
using namespace lldb;
 | 
						|
using namespace lldb_private;
 | 
						|
 | 
						|
BreakpointLocation::BreakpointLocation(break_id_t loc_id, Breakpoint &owner,
 | 
						|
                                       const Address &addr, lldb::tid_t tid,
 | 
						|
                                       bool hardware, bool check_for_resolver)
 | 
						|
    : StoppointLocation(loc_id, addr.GetOpcodeLoadAddress(&owner.GetTarget()),
 | 
						|
                        hardware),
 | 
						|
      m_being_created(true), m_should_resolve_indirect_functions(false),
 | 
						|
      m_is_reexported(false), m_is_indirect(false), m_address(addr),
 | 
						|
      m_owner(owner), m_options_ap(), m_bp_site_sp(), m_condition_mutex() {
 | 
						|
  if (check_for_resolver) {
 | 
						|
    Symbol *symbol = m_address.CalculateSymbolContextSymbol();
 | 
						|
    if (symbol && symbol->IsIndirect()) {
 | 
						|
      SetShouldResolveIndirectFunctions(true);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  SetThreadID(tid);
 | 
						|
  m_being_created = false;
 | 
						|
}
 | 
						|
 | 
						|
BreakpointLocation::~BreakpointLocation() { ClearBreakpointSite(); }
 | 
						|
 | 
						|
lldb::addr_t BreakpointLocation::GetLoadAddress() const {
 | 
						|
  return m_address.GetOpcodeLoadAddress(&m_owner.GetTarget());
 | 
						|
}
 | 
						|
 | 
						|
const BreakpointOptions *
 | 
						|
BreakpointLocation::GetOptionsSpecifyingKind(BreakpointOptions::OptionKind kind)
 | 
						|
const {
 | 
						|
    if (m_options_ap && m_options_ap->IsOptionSet(kind))
 | 
						|
      return m_options_ap.get();
 | 
						|
    else
 | 
						|
      return m_owner.GetOptions();
 | 
						|
}
 | 
						|
 | 
						|
Address &BreakpointLocation::GetAddress() { return m_address; }
 | 
						|
 | 
						|
Breakpoint &BreakpointLocation::GetBreakpoint() { return m_owner; }
 | 
						|
 | 
						|
Target &BreakpointLocation::GetTarget() { return m_owner.GetTarget(); }
 | 
						|
 | 
						|
bool BreakpointLocation::IsEnabled() const {
 | 
						|
  if (!m_owner.IsEnabled())
 | 
						|
    return false;
 | 
						|
  else if (m_options_ap.get() != nullptr)
 | 
						|
    return m_options_ap->IsEnabled();
 | 
						|
  else
 | 
						|
    return true;
 | 
						|
}
 | 
						|
 | 
						|
void BreakpointLocation::SetEnabled(bool enabled) {
 | 
						|
  GetLocationOptions()->SetEnabled(enabled);
 | 
						|
  if (enabled) {
 | 
						|
    ResolveBreakpointSite();
 | 
						|
  } else {
 | 
						|
    ClearBreakpointSite();
 | 
						|
  }
 | 
						|
  SendBreakpointLocationChangedEvent(enabled ? eBreakpointEventTypeEnabled
 | 
						|
                                             : eBreakpointEventTypeDisabled);
 | 
						|
}
 | 
						|
 | 
						|
bool BreakpointLocation::IsAutoContinue() const {
 | 
						|
  if (m_options_ap 
 | 
						|
      && m_options_ap->IsOptionSet(BreakpointOptions::eAutoContinue))
 | 
						|
    return m_options_ap->IsAutoContinue();
 | 
						|
  else
 | 
						|
    return m_owner.IsAutoContinue();
 | 
						|
}
 | 
						|
 | 
						|
void BreakpointLocation::SetAutoContinue(bool auto_continue) {
 | 
						|
  GetLocationOptions()->SetAutoContinue(auto_continue);
 | 
						|
  SendBreakpointLocationChangedEvent(eBreakpointEventTypeAutoContinueChanged);
 | 
						|
}
 | 
						|
 | 
						|
void BreakpointLocation::SetThreadID(lldb::tid_t thread_id) {
 | 
						|
  if (thread_id != LLDB_INVALID_THREAD_ID)
 | 
						|
    GetLocationOptions()->SetThreadID(thread_id);
 | 
						|
  else {
 | 
						|
    // If we're resetting this to an invalid thread id, then
 | 
						|
    // don't make an options pointer just to do that.
 | 
						|
    if (m_options_ap.get() != nullptr)
 | 
						|
      m_options_ap->SetThreadID(thread_id);
 | 
						|
  }
 | 
						|
  SendBreakpointLocationChangedEvent(eBreakpointEventTypeThreadChanged);
 | 
						|
}
 | 
						|
 | 
						|
lldb::tid_t BreakpointLocation::GetThreadID() {
 | 
						|
  const ThreadSpec *thread_spec = 
 | 
						|
      GetOptionsSpecifyingKind(BreakpointOptions::eThreadSpec)
 | 
						|
          ->GetThreadSpecNoCreate();
 | 
						|
  if (thread_spec)
 | 
						|
    return thread_spec->GetTID();
 | 
						|
  else
 | 
						|
    return LLDB_INVALID_THREAD_ID;
 | 
						|
}
 | 
						|
 | 
						|
void BreakpointLocation::SetThreadIndex(uint32_t index) {
 | 
						|
  if (index != 0)
 | 
						|
    GetLocationOptions()->GetThreadSpec()->SetIndex(index);
 | 
						|
  else {
 | 
						|
    // If we're resetting this to an invalid thread id, then
 | 
						|
    // don't make an options pointer just to do that.
 | 
						|
    if (m_options_ap.get() != nullptr)
 | 
						|
      m_options_ap->GetThreadSpec()->SetIndex(index);
 | 
						|
  }
 | 
						|
  SendBreakpointLocationChangedEvent(eBreakpointEventTypeThreadChanged);
 | 
						|
}
 | 
						|
 | 
						|
uint32_t BreakpointLocation::GetThreadIndex() const {
 | 
						|
  const ThreadSpec *thread_spec = 
 | 
						|
      GetOptionsSpecifyingKind(BreakpointOptions::eThreadSpec)
 | 
						|
          ->GetThreadSpecNoCreate();
 | 
						|
  if (thread_spec)
 | 
						|
    return thread_spec->GetIndex();
 | 
						|
  else
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
void BreakpointLocation::SetThreadName(const char *thread_name) {
 | 
						|
  if (thread_name != nullptr)
 | 
						|
    GetLocationOptions()->GetThreadSpec()->SetName(thread_name);
 | 
						|
  else {
 | 
						|
    // If we're resetting this to an invalid thread id, then
 | 
						|
    // don't make an options pointer just to do that.
 | 
						|
    if (m_options_ap.get() != nullptr)
 | 
						|
      m_options_ap->GetThreadSpec()->SetName(thread_name);
 | 
						|
  }
 | 
						|
  SendBreakpointLocationChangedEvent(eBreakpointEventTypeThreadChanged);
 | 
						|
}
 | 
						|
 | 
						|
const char *BreakpointLocation::GetThreadName() const {
 | 
						|
  const ThreadSpec *thread_spec = 
 | 
						|
      GetOptionsSpecifyingKind(BreakpointOptions::eThreadSpec)
 | 
						|
          ->GetThreadSpecNoCreate();
 | 
						|
  if (thread_spec)
 | 
						|
    return thread_spec->GetName();
 | 
						|
  else
 | 
						|
    return nullptr;
 | 
						|
}
 | 
						|
 | 
						|
void BreakpointLocation::SetQueueName(const char *queue_name) {
 | 
						|
  if (queue_name != nullptr)
 | 
						|
    GetLocationOptions()->GetThreadSpec()->SetQueueName(queue_name);
 | 
						|
  else {
 | 
						|
    // If we're resetting this to an invalid thread id, then
 | 
						|
    // don't make an options pointer just to do that.
 | 
						|
    if (m_options_ap.get() != nullptr)
 | 
						|
      m_options_ap->GetThreadSpec()->SetQueueName(queue_name);
 | 
						|
  }
 | 
						|
  SendBreakpointLocationChangedEvent(eBreakpointEventTypeThreadChanged);
 | 
						|
}
 | 
						|
 | 
						|
const char *BreakpointLocation::GetQueueName() const {
 | 
						|
  const ThreadSpec *thread_spec = 
 | 
						|
      GetOptionsSpecifyingKind(BreakpointOptions::eThreadSpec)
 | 
						|
          ->GetThreadSpecNoCreate();
 | 
						|
  if (thread_spec)
 | 
						|
    return thread_spec->GetQueueName();
 | 
						|
  else
 | 
						|
    return nullptr;
 | 
						|
}
 | 
						|
 | 
						|
bool BreakpointLocation::InvokeCallback(StoppointCallbackContext *context) {
 | 
						|
  if (m_options_ap.get() != nullptr && m_options_ap->HasCallback())
 | 
						|
    return m_options_ap->InvokeCallback(context, m_owner.GetID(), GetID());
 | 
						|
  else
 | 
						|
    return m_owner.InvokeCallback(context, GetID());
 | 
						|
}
 | 
						|
 | 
						|
void BreakpointLocation::SetCallback(BreakpointHitCallback callback,
 | 
						|
                                     void *baton, bool is_synchronous) {
 | 
						|
  // The default "Baton" class will keep a copy of "baton" and won't free
 | 
						|
  // or delete it when it goes goes out of scope.
 | 
						|
  GetLocationOptions()->SetCallback(
 | 
						|
      callback, std::make_shared<UntypedBaton>(baton), is_synchronous);
 | 
						|
  SendBreakpointLocationChangedEvent(eBreakpointEventTypeCommandChanged);
 | 
						|
}
 | 
						|
 | 
						|
void BreakpointLocation::SetCallback(BreakpointHitCallback callback,
 | 
						|
                                     const BatonSP &baton_sp,
 | 
						|
                                     bool is_synchronous) {
 | 
						|
  GetLocationOptions()->SetCallback(callback, baton_sp, is_synchronous);
 | 
						|
  SendBreakpointLocationChangedEvent(eBreakpointEventTypeCommandChanged);
 | 
						|
}
 | 
						|
 | 
						|
void BreakpointLocation::ClearCallback() {
 | 
						|
  GetLocationOptions()->ClearCallback();
 | 
						|
}
 | 
						|
 | 
						|
void BreakpointLocation::SetCondition(const char *condition) {
 | 
						|
  GetLocationOptions()->SetCondition(condition);
 | 
						|
  SendBreakpointLocationChangedEvent(eBreakpointEventTypeConditionChanged);
 | 
						|
}
 | 
						|
 | 
						|
const char *BreakpointLocation::GetConditionText(size_t *hash) const {
 | 
						|
  return GetOptionsSpecifyingKind(BreakpointOptions::eCondition)
 | 
						|
      ->GetConditionText(hash);
 | 
						|
}
 | 
						|
 | 
						|
bool BreakpointLocation::ConditionSaysStop(ExecutionContext &exe_ctx,
 | 
						|
                                           Status &error) {
 | 
						|
  Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS);
 | 
						|
 | 
						|
  std::lock_guard<std::mutex> guard(m_condition_mutex);
 | 
						|
 | 
						|
  size_t condition_hash;
 | 
						|
  const char *condition_text = GetConditionText(&condition_hash);
 | 
						|
 | 
						|
  if (!condition_text) {
 | 
						|
    m_user_expression_sp.reset();
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  error.Clear();
 | 
						|
 | 
						|
  DiagnosticManager diagnostics;
 | 
						|
 | 
						|
  if (condition_hash != m_condition_hash || !m_user_expression_sp ||
 | 
						|
      !m_user_expression_sp->MatchesContext(exe_ctx)) {
 | 
						|
    LanguageType language = eLanguageTypeUnknown;
 | 
						|
    // See if we can figure out the language from the frame, otherwise use the
 | 
						|
    // default language:
 | 
						|
    CompileUnit *comp_unit = m_address.CalculateSymbolContextCompileUnit();
 | 
						|
    if (comp_unit)
 | 
						|
      language = comp_unit->GetLanguage();
 | 
						|
 | 
						|
    m_user_expression_sp.reset(GetTarget().GetUserExpressionForLanguage(
 | 
						|
        condition_text, llvm::StringRef(), language, Expression::eResultTypeAny,
 | 
						|
        EvaluateExpressionOptions(), error));
 | 
						|
    if (error.Fail()) {
 | 
						|
      if (log)
 | 
						|
        log->Printf("Error getting condition expression: %s.",
 | 
						|
                    error.AsCString());
 | 
						|
      m_user_expression_sp.reset();
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
 | 
						|
    if (!m_user_expression_sp->Parse(diagnostics, exe_ctx,
 | 
						|
                                     eExecutionPolicyOnlyWhenNeeded, true,
 | 
						|
                                     false)) {
 | 
						|
      error.SetErrorStringWithFormat(
 | 
						|
          "Couldn't parse conditional expression:\n%s",
 | 
						|
          diagnostics.GetString().c_str());
 | 
						|
      m_user_expression_sp.reset();
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
 | 
						|
    m_condition_hash = condition_hash;
 | 
						|
  }
 | 
						|
 | 
						|
  // We need to make sure the user sees any parse errors in their condition, so
 | 
						|
  // we'll hook the
 | 
						|
  // constructor errors up to the debugger's Async I/O.
 | 
						|
 | 
						|
  ValueObjectSP result_value_sp;
 | 
						|
 | 
						|
  EvaluateExpressionOptions options;
 | 
						|
  options.SetUnwindOnError(true);
 | 
						|
  options.SetIgnoreBreakpoints(true);
 | 
						|
  options.SetTryAllThreads(true);
 | 
						|
  options.SetResultIsInternal(
 | 
						|
      true); // Don't generate a user variable for condition expressions.
 | 
						|
 | 
						|
  Status expr_error;
 | 
						|
 | 
						|
  diagnostics.Clear();
 | 
						|
 | 
						|
  ExpressionVariableSP result_variable_sp;
 | 
						|
 | 
						|
  ExpressionResults result_code = m_user_expression_sp->Execute(
 | 
						|
      diagnostics, exe_ctx, options, m_user_expression_sp, result_variable_sp);
 | 
						|
 | 
						|
  bool ret;
 | 
						|
 | 
						|
  if (result_code == eExpressionCompleted) {
 | 
						|
    if (!result_variable_sp) {
 | 
						|
      error.SetErrorString("Expression did not return a result");
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
 | 
						|
    result_value_sp = result_variable_sp->GetValueObject();
 | 
						|
 | 
						|
    if (result_value_sp) {
 | 
						|
      ret = result_value_sp->IsLogicalTrue(error);
 | 
						|
      if (log) {
 | 
						|
        if (error.Success()) {
 | 
						|
          log->Printf("Condition successfully evaluated, result is %s.\n",
 | 
						|
                      ret ? "true" : "false");
 | 
						|
        } else {
 | 
						|
          error.SetErrorString(
 | 
						|
              "Failed to get an integer result from the expression");
 | 
						|
          ret = false;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      ret = false;
 | 
						|
      error.SetErrorString("Failed to get any result from the expression");
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    ret = false;
 | 
						|
    error.SetErrorStringWithFormat("Couldn't execute expression:\n%s",
 | 
						|
                                   diagnostics.GetString().c_str());
 | 
						|
  }
 | 
						|
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
uint32_t BreakpointLocation::GetIgnoreCount() {
 | 
						|
  return GetOptionsSpecifyingKind(BreakpointOptions::eIgnoreCount)
 | 
						|
      ->GetIgnoreCount();
 | 
						|
}
 | 
						|
 | 
						|
void BreakpointLocation::SetIgnoreCount(uint32_t n) {
 | 
						|
  GetLocationOptions()->SetIgnoreCount(n);
 | 
						|
  SendBreakpointLocationChangedEvent(eBreakpointEventTypeIgnoreChanged);
 | 
						|
}
 | 
						|
 | 
						|
void BreakpointLocation::DecrementIgnoreCount() {
 | 
						|
  if (m_options_ap.get() != nullptr) {
 | 
						|
    uint32_t loc_ignore = m_options_ap->GetIgnoreCount();
 | 
						|
    if (loc_ignore != 0)
 | 
						|
      m_options_ap->SetIgnoreCount(loc_ignore - 1);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
bool BreakpointLocation::IgnoreCountShouldStop() {
 | 
						|
  if (m_options_ap.get() != nullptr) {
 | 
						|
    uint32_t loc_ignore = m_options_ap->GetIgnoreCount();
 | 
						|
    if (loc_ignore != 0) {
 | 
						|
      m_owner.DecrementIgnoreCount();
 | 
						|
      DecrementIgnoreCount(); // Have to decrement our owners' ignore count,
 | 
						|
                              // since it won't get a
 | 
						|
                              // chance to.
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
BreakpointOptions *BreakpointLocation::GetLocationOptions() {
 | 
						|
  // If we make the copy we don't copy the callbacks because that is potentially
 | 
						|
  // expensive and we don't want to do that for the simple case where someone is
 | 
						|
  // just disabling the location.
 | 
						|
  if (m_options_ap.get() == nullptr)
 | 
						|
    m_options_ap.reset(
 | 
						|
        new BreakpointOptions(false));
 | 
						|
 | 
						|
  return m_options_ap.get();
 | 
						|
}
 | 
						|
 | 
						|
bool BreakpointLocation::ValidForThisThread(Thread *thread) {
 | 
						|
  return thread
 | 
						|
      ->MatchesSpec(GetOptionsSpecifyingKind(BreakpointOptions::eThreadSpec)
 | 
						|
      ->GetThreadSpecNoCreate());
 | 
						|
}
 | 
						|
 | 
						|
// RETURNS - true if we should stop at this breakpoint, false if we
 | 
						|
// should continue.  Note, we don't check the thread spec for the breakpoint
 | 
						|
// here, since if the breakpoint is not for this thread, then the event won't
 | 
						|
// even get reported, so the check is redundant.
 | 
						|
 | 
						|
bool BreakpointLocation::ShouldStop(StoppointCallbackContext *context) {
 | 
						|
  bool should_stop = true;
 | 
						|
  Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS);
 | 
						|
 | 
						|
  // Do this first, if a location is disabled, it shouldn't increment its hit
 | 
						|
  // count.
 | 
						|
  if (!IsEnabled())
 | 
						|
    return false;
 | 
						|
 | 
						|
  if (!IgnoreCountShouldStop())
 | 
						|
    return false;
 | 
						|
 | 
						|
  if (!m_owner.IgnoreCountShouldStop())
 | 
						|
    return false;
 | 
						|
 | 
						|
  // We only run synchronous callbacks in ShouldStop:
 | 
						|
  context->is_synchronous = true;
 | 
						|
  should_stop = InvokeCallback(context);
 | 
						|
 | 
						|
  if (log) {
 | 
						|
    StreamString s;
 | 
						|
    GetDescription(&s, lldb::eDescriptionLevelVerbose);
 | 
						|
    log->Printf("Hit breakpoint location: %s, %s.\n", s.GetData(),
 | 
						|
                should_stop ? "stopping" : "continuing");
 | 
						|
  }
 | 
						|
 | 
						|
  return should_stop;
 | 
						|
}
 | 
						|
 | 
						|
void BreakpointLocation::BumpHitCount() {
 | 
						|
  if (IsEnabled()) {
 | 
						|
    // Step our hit count, and also step the hit count of the owner.
 | 
						|
    IncrementHitCount();
 | 
						|
    m_owner.IncrementHitCount();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void BreakpointLocation::UndoBumpHitCount() {
 | 
						|
  if (IsEnabled()) {
 | 
						|
    // Step our hit count, and also step the hit count of the owner.
 | 
						|
    DecrementHitCount();
 | 
						|
    m_owner.DecrementHitCount();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
bool BreakpointLocation::IsResolved() const {
 | 
						|
  return m_bp_site_sp.get() != nullptr;
 | 
						|
}
 | 
						|
 | 
						|
lldb::BreakpointSiteSP BreakpointLocation::GetBreakpointSite() const {
 | 
						|
  return m_bp_site_sp;
 | 
						|
}
 | 
						|
 | 
						|
bool BreakpointLocation::ResolveBreakpointSite() {
 | 
						|
  if (m_bp_site_sp)
 | 
						|
    return true;
 | 
						|
 | 
						|
  Process *process = m_owner.GetTarget().GetProcessSP().get();
 | 
						|
  if (process == nullptr)
 | 
						|
    return false;
 | 
						|
 | 
						|
  lldb::break_id_t new_id =
 | 
						|
      process->CreateBreakpointSite(shared_from_this(), m_owner.IsHardware());
 | 
						|
 | 
						|
  if (new_id == LLDB_INVALID_BREAK_ID) {
 | 
						|
    Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS);
 | 
						|
    if (log)
 | 
						|
      log->Warning("Tried to add breakpoint site at 0x%" PRIx64
 | 
						|
                   " but it was already present.\n",
 | 
						|
                   m_address.GetOpcodeLoadAddress(&m_owner.GetTarget()));
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
bool BreakpointLocation::SetBreakpointSite(BreakpointSiteSP &bp_site_sp) {
 | 
						|
  m_bp_site_sp = bp_site_sp;
 | 
						|
  SendBreakpointLocationChangedEvent(eBreakpointEventTypeLocationsResolved);
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
bool BreakpointLocation::ClearBreakpointSite() {
 | 
						|
  if (m_bp_site_sp.get()) {
 | 
						|
    ProcessSP process_sp(m_owner.GetTarget().GetProcessSP());
 | 
						|
    // If the process exists, get it to remove the owner, it will remove the
 | 
						|
    // physical implementation
 | 
						|
    // of the breakpoint as well if there are no more owners.  Otherwise just
 | 
						|
    // remove this owner.
 | 
						|
    if (process_sp)
 | 
						|
      process_sp->RemoveOwnerFromBreakpointSite(GetBreakpoint().GetID(),
 | 
						|
                                                GetID(), m_bp_site_sp);
 | 
						|
    else
 | 
						|
      m_bp_site_sp->RemoveOwner(GetBreakpoint().GetID(), GetID());
 | 
						|
 | 
						|
    m_bp_site_sp.reset();
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
void BreakpointLocation::GetDescription(Stream *s,
 | 
						|
                                        lldb::DescriptionLevel level) {
 | 
						|
  SymbolContext sc;
 | 
						|
 | 
						|
  // If the description level is "initial" then the breakpoint is printing out
 | 
						|
  // our initial state,
 | 
						|
  // and we should let it decide how it wants to print our label.
 | 
						|
  if (level != eDescriptionLevelInitial) {
 | 
						|
    s->Indent();
 | 
						|
    BreakpointID::GetCanonicalReference(s, m_owner.GetID(), GetID());
 | 
						|
  }
 | 
						|
 | 
						|
  if (level == lldb::eDescriptionLevelBrief)
 | 
						|
    return;
 | 
						|
 | 
						|
  if (level != eDescriptionLevelInitial)
 | 
						|
    s->PutCString(": ");
 | 
						|
 | 
						|
  if (level == lldb::eDescriptionLevelVerbose)
 | 
						|
    s->IndentMore();
 | 
						|
 | 
						|
  if (m_address.IsSectionOffset()) {
 | 
						|
    m_address.CalculateSymbolContext(&sc);
 | 
						|
 | 
						|
    if (level == lldb::eDescriptionLevelFull ||
 | 
						|
        level == eDescriptionLevelInitial) {
 | 
						|
      if (IsReExported())
 | 
						|
        s->PutCString("re-exported target = ");
 | 
						|
      else
 | 
						|
        s->PutCString("where = ");
 | 
						|
      sc.DumpStopContext(s, m_owner.GetTarget().GetProcessSP().get(), m_address,
 | 
						|
                         false, true, false, true, true);
 | 
						|
    } else {
 | 
						|
      if (sc.module_sp) {
 | 
						|
        s->EOL();
 | 
						|
        s->Indent("module = ");
 | 
						|
        sc.module_sp->GetFileSpec().Dump(s);
 | 
						|
      }
 | 
						|
 | 
						|
      if (sc.comp_unit != nullptr) {
 | 
						|
        s->EOL();
 | 
						|
        s->Indent("compile unit = ");
 | 
						|
        static_cast<FileSpec *>(sc.comp_unit)->GetFilename().Dump(s);
 | 
						|
 | 
						|
        if (sc.function != nullptr) {
 | 
						|
          s->EOL();
 | 
						|
          s->Indent("function = ");
 | 
						|
          s->PutCString(sc.function->GetName().AsCString("<unknown>"));
 | 
						|
        }
 | 
						|
 | 
						|
        if (sc.line_entry.line > 0) {
 | 
						|
          s->EOL();
 | 
						|
          s->Indent("location = ");
 | 
						|
          sc.line_entry.DumpStopContext(s, true);
 | 
						|
        }
 | 
						|
 | 
						|
      } else {
 | 
						|
        // If we don't have a comp unit, see if we have a symbol we can print.
 | 
						|
        if (sc.symbol) {
 | 
						|
          s->EOL();
 | 
						|
          if (IsReExported())
 | 
						|
            s->Indent("re-exported target = ");
 | 
						|
          else
 | 
						|
            s->Indent("symbol = ");
 | 
						|
          s->PutCString(sc.symbol->GetName().AsCString("<unknown>"));
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (level == lldb::eDescriptionLevelVerbose) {
 | 
						|
    s->EOL();
 | 
						|
    s->Indent();
 | 
						|
  }
 | 
						|
 | 
						|
  if (m_address.IsSectionOffset() &&
 | 
						|
      (level == eDescriptionLevelFull || level == eDescriptionLevelInitial))
 | 
						|
    s->Printf(", ");
 | 
						|
  s->Printf("address = ");
 | 
						|
 | 
						|
  ExecutionContextScope *exe_scope = nullptr;
 | 
						|
  Target *target = &m_owner.GetTarget();
 | 
						|
  if (target)
 | 
						|
    exe_scope = target->GetProcessSP().get();
 | 
						|
  if (exe_scope == nullptr)
 | 
						|
    exe_scope = target;
 | 
						|
 | 
						|
  if (level == eDescriptionLevelInitial)
 | 
						|
    m_address.Dump(s, exe_scope, Address::DumpStyleLoadAddress,
 | 
						|
                   Address::DumpStyleFileAddress);
 | 
						|
  else
 | 
						|
    m_address.Dump(s, exe_scope, Address::DumpStyleLoadAddress,
 | 
						|
                   Address::DumpStyleModuleWithFileAddress);
 | 
						|
 | 
						|
  if (IsIndirect() && m_bp_site_sp) {
 | 
						|
    Address resolved_address;
 | 
						|
    resolved_address.SetLoadAddress(m_bp_site_sp->GetLoadAddress(), target);
 | 
						|
    Symbol *resolved_symbol = resolved_address.CalculateSymbolContextSymbol();
 | 
						|
    if (resolved_symbol) {
 | 
						|
      if (level == eDescriptionLevelFull || level == eDescriptionLevelInitial)
 | 
						|
        s->Printf(", ");
 | 
						|
      else if (level == lldb::eDescriptionLevelVerbose) {
 | 
						|
        s->EOL();
 | 
						|
        s->Indent();
 | 
						|
      }
 | 
						|
      s->Printf("indirect target = %s",
 | 
						|
                resolved_symbol->GetName().GetCString());
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (level == lldb::eDescriptionLevelVerbose) {
 | 
						|
    s->EOL();
 | 
						|
    s->Indent();
 | 
						|
    s->Printf("resolved = %s\n", IsResolved() ? "true" : "false");
 | 
						|
 | 
						|
    s->Indent();
 | 
						|
    s->Printf("hit count = %-4u\n", GetHitCount());
 | 
						|
 | 
						|
    if (m_options_ap.get()) {
 | 
						|
      s->Indent();
 | 
						|
      m_options_ap->GetDescription(s, level);
 | 
						|
      s->EOL();
 | 
						|
    }
 | 
						|
    s->IndentLess();
 | 
						|
  } else if (level != eDescriptionLevelInitial) {
 | 
						|
    s->Printf(", %sresolved, hit count = %u ", (IsResolved() ? "" : "un"),
 | 
						|
              GetHitCount());
 | 
						|
    if (m_options_ap.get()) {
 | 
						|
      m_options_ap->GetDescription(s, level);
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void BreakpointLocation::Dump(Stream *s) const {
 | 
						|
  if (s == nullptr)
 | 
						|
    return;
 | 
						|
 | 
						|
  lldb::tid_t tid = GetOptionsSpecifyingKind(BreakpointOptions::eThreadSpec)
 | 
						|
      ->GetThreadSpecNoCreate()->GetTID();
 | 
						|
  s->Printf(
 | 
						|
      "BreakpointLocation %u: tid = %4.4" PRIx64 "  load addr = 0x%8.8" PRIx64
 | 
						|
      "  state = %s  type = %s breakpoint  "
 | 
						|
      "hw_index = %i  hit_count = %-4u  ignore_count = %-4u",
 | 
						|
      GetID(), tid,
 | 
						|
      (uint64_t)m_address.GetOpcodeLoadAddress(&m_owner.GetTarget()),
 | 
						|
      (m_options_ap.get() ? m_options_ap->IsEnabled() : m_owner.IsEnabled())
 | 
						|
          ? "enabled "
 | 
						|
          : "disabled",
 | 
						|
      IsHardware() ? "hardware" : "software", GetHardwareIndex(), GetHitCount(),
 | 
						|
      GetOptionsSpecifyingKind(BreakpointOptions::eIgnoreCount)
 | 
						|
          ->GetIgnoreCount());
 | 
						|
}
 | 
						|
 | 
						|
void BreakpointLocation::SendBreakpointLocationChangedEvent(
 | 
						|
    lldb::BreakpointEventType eventKind) {
 | 
						|
  if (!m_being_created && !m_owner.IsInternal() &&
 | 
						|
      m_owner.GetTarget().EventTypeHasListeners(
 | 
						|
          Target::eBroadcastBitBreakpointChanged)) {
 | 
						|
    Breakpoint::BreakpointEventData *data = new Breakpoint::BreakpointEventData(
 | 
						|
        eventKind, m_owner.shared_from_this());
 | 
						|
    data->GetBreakpointLocationCollection().Add(shared_from_this());
 | 
						|
    m_owner.GetTarget().BroadcastEvent(Target::eBroadcastBitBreakpointChanged,
 | 
						|
                                       data);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void BreakpointLocation::SwapLocation(BreakpointLocationSP swap_from) {
 | 
						|
  m_address = swap_from->m_address;
 | 
						|
  m_should_resolve_indirect_functions =
 | 
						|
      swap_from->m_should_resolve_indirect_functions;
 | 
						|
  m_is_reexported = swap_from->m_is_reexported;
 | 
						|
  m_is_indirect = swap_from->m_is_indirect;
 | 
						|
  m_user_expression_sp.reset();
 | 
						|
}
 |