diff options
Diffstat (limited to 'contrib/llvm/tools/lldb/source/Breakpoint/BreakpointLocation.cpp')
-rw-r--r-- | contrib/llvm/tools/lldb/source/Breakpoint/BreakpointLocation.cpp | 677 |
1 files changed, 677 insertions, 0 deletions
diff --git a/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointLocation.cpp b/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointLocation.cpp new file mode 100644 index 0000000..1ec726d --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointLocation.cpp @@ -0,0 +1,677 @@ +//===-- BreakpointLocation.cpp ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/lldb-python.h" + +// C Includes +// C++ Includes +#include <string> + +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-private-log.h" +#include "lldb/Breakpoint/BreakpointLocation.h" +#include "lldb/Breakpoint/BreakpointID.h" +#include "lldb/Breakpoint/StoppointCallbackContext.h" +#include "lldb/Core/Debugger.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/StreamString.h" +#include "lldb/Symbol/CompileUnit.h" +#include "lldb/Symbol/Symbol.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Thread.h" +#include "lldb/Target/ThreadSpec.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 +) : + StoppointLocation (loc_id, addr.GetOpcodeLoadAddress(&owner.GetTarget()), hardware), + m_being_created(true), + m_address (addr), + m_owner (owner), + m_options_ap (), + m_bp_site_sp (), + m_condition_mutex () +{ + SetThreadID (tid); + m_being_created = false; +} + +BreakpointLocation::~BreakpointLocation() +{ + ClearBreakpointSite(); +} + +lldb::addr_t +BreakpointLocation::GetLoadAddress () const +{ + return m_address.GetOpcodeLoadAddress (&m_owner.GetTarget()); +} + +Address & +BreakpointLocation::GetAddress () +{ + return m_address; +} + +Breakpoint & +BreakpointLocation::GetBreakpoint () +{ + return m_owner; +} + +bool +BreakpointLocation::IsEnabled () const +{ + if (!m_owner.IsEnabled()) + return false; + else if (m_options_ap.get() != NULL) + 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); +} + +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() != NULL) + m_options_ap->SetThreadID (thread_id); + } + SendBreakpointLocationChangedEvent (eBreakpointEventTypeThreadChanged); +} + +lldb::tid_t +BreakpointLocation::GetThreadID () +{ + if (GetOptionsNoCreate()->GetThreadSpecNoCreate()) + return GetOptionsNoCreate()->GetThreadSpecNoCreate()->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() != NULL) + m_options_ap->GetThreadSpec()->SetIndex(index); + } + SendBreakpointLocationChangedEvent (eBreakpointEventTypeThreadChanged); + +} + +uint32_t +BreakpointLocation::GetThreadIndex() const +{ + if (GetOptionsNoCreate()->GetThreadSpecNoCreate()) + return GetOptionsNoCreate()->GetThreadSpecNoCreate()->GetIndex(); + else + return 0; +} + +void +BreakpointLocation::SetThreadName (const char *thread_name) +{ + if (thread_name != NULL) + 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() != NULL) + m_options_ap->GetThreadSpec()->SetName(thread_name); + } + SendBreakpointLocationChangedEvent (eBreakpointEventTypeThreadChanged); +} + +const char * +BreakpointLocation::GetThreadName () const +{ + if (GetOptionsNoCreate()->GetThreadSpecNoCreate()) + return GetOptionsNoCreate()->GetThreadSpecNoCreate()->GetName(); + else + return NULL; +} + +void +BreakpointLocation::SetQueueName (const char *queue_name) +{ + if (queue_name != NULL) + 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() != NULL) + m_options_ap->GetThreadSpec()->SetQueueName(queue_name); + } + SendBreakpointLocationChangedEvent (eBreakpointEventTypeThreadChanged); +} + +const char * +BreakpointLocation::GetQueueName () const +{ + if (GetOptionsNoCreate()->GetThreadSpecNoCreate()) + return GetOptionsNoCreate()->GetThreadSpecNoCreate()->GetQueueName(); + else + return NULL; +} + +bool +BreakpointLocation::InvokeCallback (StoppointCallbackContext *context) +{ + if (m_options_ap.get() != NULL && 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, BatonSP (new Baton(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 GetOptionsNoCreate()->GetConditionText(hash); +} + +bool +BreakpointLocation::ConditionSaysStop (ExecutionContext &exe_ctx, Error &error) +{ + Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS); + + Mutex::Locker evaluation_locker(m_condition_mutex); + + size_t condition_hash; + const char *condition_text = GetConditionText(&condition_hash); + + if (!condition_text) + { + m_user_expression_sp.reset(); + return false; + } + + if (condition_hash != m_condition_hash || + !m_user_expression_sp || + !m_user_expression_sp->MatchesContext(exe_ctx)) + { + m_user_expression_sp.reset(new ClangUserExpression(condition_text, + NULL, + lldb::eLanguageTypeUnknown, + ClangUserExpression::eResultTypeAny)); + + StreamString errors; + + if (!m_user_expression_sp->Parse(errors, + exe_ctx, + eExecutionPolicyOnlyWhenNeeded, + true)) + { + error.SetErrorStringWithFormat("Couldn't parse conditional expression:\n%s", + errors.GetData()); + m_user_expression_sp.reset(); + return false; + } + + 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; + const bool unwind_on_error = true; + const bool ignore_breakpoints = true; + const bool try_all_threads = true; + + Error expr_error; + + StreamString execution_errors; + + ClangExpressionVariableSP result_variable_sp; + + ExecutionResults result_code = + m_user_expression_sp->Execute(execution_errors, + exe_ctx, + unwind_on_error, + ignore_breakpoints, + m_user_expression_sp, + result_variable_sp, + try_all_threads, + ClangUserExpression::kDefaultTimeout); + + bool ret; + + if (result_code == eExecutionCompleted) + { + if (!result_variable_sp) + { + ret = false; + error.SetErrorString("Expression did not return a result"); + return false; + } + + result_value_sp = result_variable_sp->GetValueObject(); + + if (result_value_sp) + { + Scalar scalar_value; + if (result_value_sp->ResolveValue (scalar_value)) + { + if (scalar_value.ULongLong(1) == 0) + ret = false; + else + ret = true; + if (log) + log->Printf("Condition successfully evaluated, result is %s.\n", + ret ? "true" : "false"); + } + else + { + ret = false; + error.SetErrorString("Failed to get an integer result from the expression"); + } + } + else + { + ret = false; + error.SetErrorString("Failed to get any result from the expression"); + } + } + else + { + ret = false; + error.SetErrorStringWithFormat("Couldn't execute expression:\n%s", execution_errors.GetData()); + } + + return ret; +} + +uint32_t +BreakpointLocation::GetIgnoreCount () +{ + return GetOptionsNoCreate()->GetIgnoreCount(); +} + +void +BreakpointLocation::SetIgnoreCount (uint32_t n) +{ + GetLocationOptions()->SetIgnoreCount(n); + SendBreakpointLocationChangedEvent (eBreakpointEventTypeIgnoreChanged); +} + +void +BreakpointLocation::DecrementIgnoreCount() +{ + if (m_options_ap.get() != NULL) + { + 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() != NULL) + { + 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; +} + +const BreakpointOptions * +BreakpointLocation::GetOptionsNoCreate () const +{ + if (m_options_ap.get() != NULL) + return m_options_ap.get(); + else + return m_owner.GetOptions (); +} + +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() == NULL) + m_options_ap.reset(BreakpointOptions::CopyOptionsNoCallback(*m_owner.GetOptions ())); + + return m_options_ap.get(); +} + +bool +BreakpointLocation::ValidForThisThread (Thread *thread) +{ + return thread->MatchesSpec(GetOptionsNoCreate()->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); + + IncrementHitCount(); + + 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; +} + +bool +BreakpointLocation::IsResolved () const +{ + return m_bp_site_sp.get() != NULL; +} + +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 == NULL) + return false; + + lldb::break_id_t new_id = process->CreateBreakpointSite (shared_from_this(), false); + + 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; + return true; +} + +bool +BreakpointLocation::ClearBreakpointSite () +{ + if (m_bp_site_sp.get()) + { + m_owner.GetTarget().GetProcessSP()->RemoveOwnerFromBreakpointSite (GetBreakpoint().GetID(), + GetID(), m_bp_site_sp); + 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) + { + s->PutCString("where = "); + sc.DumpStopContext (s, m_owner.GetTarget().GetProcessSP().get(), m_address, false, true, false); + } + else + { + if (sc.module_sp) + { + s->EOL(); + s->Indent("module = "); + sc.module_sp->GetFileSpec().Dump (s); + } + + if (sc.comp_unit != NULL) + { + s->EOL(); + s->Indent("compile unit = "); + static_cast<FileSpec*>(sc.comp_unit)->GetFilename().Dump (s); + + if (sc.function != NULL) + { + s->EOL(); + s->Indent("function = "); + s->PutCString (sc.function->GetMangled().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(); + s->Indent("symbol = "); + s->PutCString(sc.symbol->GetMangled().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 = NULL; + Target *target = &m_owner.GetTarget(); + if (target) + exe_scope = target->GetProcessSP().get(); + if (exe_scope == NULL) + exe_scope = target; + + if (eDescriptionLevelInitial) + m_address.Dump(s, exe_scope, Address::DumpStyleLoadAddress, Address::DumpStyleFileAddress); + else + m_address.Dump(s, exe_scope, Address::DumpStyleLoadAddress, Address::DumpStyleModuleWithFileAddress); + + 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 == NULL) + return; + + 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(), + GetOptionsNoCreate()->GetThreadSpecNoCreate()->GetTID(), + (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(), + GetOptionsNoCreate()->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); + } +} + |