//===-- ExecutionContext.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/Target/ExecutionContext.h" #include "lldb/Core/State.h" #include "lldb/Target/ExecutionContextScope.h" #include "lldb/Target/StackFrame.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" using namespace lldb_private; ExecutionContext::ExecutionContext() : m_target_sp (), m_process_sp (), m_thread_sp (), m_frame_sp () { } ExecutionContext::ExecutionContext (const ExecutionContext &rhs) : m_target_sp(rhs.m_target_sp), m_process_sp(rhs.m_process_sp), m_thread_sp(rhs.m_thread_sp), m_frame_sp(rhs.m_frame_sp) { } ExecutionContext::ExecutionContext (const lldb::TargetSP &target_sp, bool get_process) : m_target_sp (), m_process_sp (), m_thread_sp (), m_frame_sp () { if (target_sp) SetContext (target_sp, get_process); } ExecutionContext::ExecutionContext (const lldb::ProcessSP &process_sp) : m_target_sp (), m_process_sp (), m_thread_sp (), m_frame_sp () { if (process_sp) SetContext (process_sp); } ExecutionContext::ExecutionContext (const lldb::ThreadSP &thread_sp) : m_target_sp (), m_process_sp (), m_thread_sp (), m_frame_sp () { if (thread_sp) SetContext (thread_sp); } ExecutionContext::ExecutionContext (const lldb::StackFrameSP &frame_sp) : m_target_sp (), m_process_sp (), m_thread_sp (), m_frame_sp () { if (frame_sp) SetContext (frame_sp); } ExecutionContext::ExecutionContext (const lldb::TargetWP &target_wp, bool get_process) : m_target_sp (), m_process_sp (), m_thread_sp (), m_frame_sp () { lldb::TargetSP target_sp(target_wp.lock()); if (target_sp) SetContext (target_sp, get_process); } ExecutionContext::ExecutionContext (const lldb::ProcessWP &process_wp) : m_target_sp (), m_process_sp (), m_thread_sp (), m_frame_sp () { lldb::ProcessSP process_sp(process_wp.lock()); if (process_sp) SetContext (process_sp); } ExecutionContext::ExecutionContext (const lldb::ThreadWP &thread_wp) : m_target_sp (), m_process_sp (), m_thread_sp (), m_frame_sp () { lldb::ThreadSP thread_sp(thread_wp.lock()); if (thread_sp) SetContext (thread_sp); } ExecutionContext::ExecutionContext (const lldb::StackFrameWP &frame_wp) : m_target_sp (), m_process_sp (), m_thread_sp (), m_frame_sp () { lldb::StackFrameSP frame_sp(frame_wp.lock()); if (frame_sp) SetContext (frame_sp); } ExecutionContext::ExecutionContext (Target* t, bool fill_current_process_thread_frame) : m_target_sp (t->shared_from_this()), m_process_sp (), m_thread_sp (), m_frame_sp () { if (t && fill_current_process_thread_frame) { m_process_sp = t->GetProcessSP(); if (m_process_sp) { m_thread_sp = m_process_sp->GetThreadList().GetSelectedThread(); if (m_thread_sp) m_frame_sp = m_thread_sp->GetSelectedFrame(); } } } ExecutionContext::ExecutionContext(Process* process, Thread *thread, StackFrame *frame) : m_target_sp (), m_process_sp (process->shared_from_this()), m_thread_sp (thread->shared_from_this()), m_frame_sp (frame->shared_from_this()) { if (process) m_target_sp = process->GetTarget().shared_from_this(); } ExecutionContext::ExecutionContext (const ExecutionContextRef &exe_ctx_ref) : m_target_sp (exe_ctx_ref.GetTargetSP()), m_process_sp (exe_ctx_ref.GetProcessSP()), m_thread_sp (exe_ctx_ref.GetThreadSP()), m_frame_sp (exe_ctx_ref.GetFrameSP()) { } ExecutionContext::ExecutionContext (const ExecutionContextRef *exe_ctx_ref_ptr) : m_target_sp (), m_process_sp (), m_thread_sp (), m_frame_sp () { if (exe_ctx_ref_ptr) { m_target_sp = exe_ctx_ref_ptr->GetTargetSP(); m_process_sp = exe_ctx_ref_ptr->GetProcessSP(); m_thread_sp = exe_ctx_ref_ptr->GetThreadSP(); m_frame_sp = exe_ctx_ref_ptr->GetFrameSP(); } } ExecutionContext::ExecutionContext (const ExecutionContextRef *exe_ctx_ref_ptr, Mutex::Locker &locker) : m_target_sp (), m_process_sp (), m_thread_sp (), m_frame_sp () { if (exe_ctx_ref_ptr) { m_target_sp = exe_ctx_ref_ptr->GetTargetSP(); if (m_target_sp) { locker.Lock(m_target_sp->GetAPIMutex()); m_process_sp = exe_ctx_ref_ptr->GetProcessSP(); m_thread_sp = exe_ctx_ref_ptr->GetThreadSP(); m_frame_sp = exe_ctx_ref_ptr->GetFrameSP(); } } } ExecutionContext::ExecutionContext (const ExecutionContextRef &exe_ctx_ref, Mutex::Locker &locker) : m_target_sp (exe_ctx_ref.GetTargetSP()), m_process_sp (), m_thread_sp (), m_frame_sp () { if (m_target_sp) { locker.Lock(m_target_sp->GetAPIMutex()); m_process_sp = exe_ctx_ref.GetProcessSP(); m_thread_sp = exe_ctx_ref.GetThreadSP(); m_frame_sp = exe_ctx_ref.GetFrameSP(); } } ExecutionContext::ExecutionContext (ExecutionContextScope *exe_scope_ptr) : m_target_sp (), m_process_sp (), m_thread_sp (), m_frame_sp () { if (exe_scope_ptr) exe_scope_ptr->CalculateExecutionContext (*this); } ExecutionContext::ExecutionContext (ExecutionContextScope &exe_scope_ref) { exe_scope_ref.CalculateExecutionContext (*this); } void ExecutionContext::Clear() { m_target_sp.reset(); m_process_sp.reset(); m_thread_sp.reset(); m_frame_sp.reset(); } ExecutionContext::~ExecutionContext() { } uint32_t ExecutionContext::GetAddressByteSize() const { if (m_target_sp && m_target_sp->GetArchitecture().IsValid()) m_target_sp->GetArchitecture().GetAddressByteSize(); if (m_process_sp) m_process_sp->GetAddressByteSize(); return sizeof(void *); } RegisterContext * ExecutionContext::GetRegisterContext () const { if (m_frame_sp) return m_frame_sp->GetRegisterContext().get(); else if (m_thread_sp) return m_thread_sp->GetRegisterContext().get(); return NULL; } Target * ExecutionContext::GetTargetPtr () const { if (m_target_sp) return m_target_sp.get(); if (m_process_sp) return &m_process_sp->GetTarget(); return NULL; } Process * ExecutionContext::GetProcessPtr () const { if (m_process_sp) return m_process_sp.get(); if (m_target_sp) return m_target_sp->GetProcessSP().get(); return NULL; } ExecutionContextScope * ExecutionContext::GetBestExecutionContextScope () const { if (m_frame_sp) return m_frame_sp.get(); if (m_thread_sp) return m_thread_sp.get(); if (m_process_sp) return m_process_sp.get(); return m_target_sp.get(); } Target & ExecutionContext::GetTargetRef () const { #if defined (LLDB_CONFIGURATION_DEBUG) || defined (LLDB_CONFIGURATION_RELEASE) assert (m_target_sp.get()); #endif return *m_target_sp; } Process & ExecutionContext::GetProcessRef () const { #if defined (LLDB_CONFIGURATION_DEBUG) || defined (LLDB_CONFIGURATION_RELEASE) assert (m_process_sp.get()); #endif return *m_process_sp; } Thread & ExecutionContext::GetThreadRef () const { #if defined (LLDB_CONFIGURATION_DEBUG) || defined (LLDB_CONFIGURATION_RELEASE) assert (m_thread_sp.get()); #endif return *m_thread_sp; } StackFrame & ExecutionContext::GetFrameRef () const { #if defined (LLDB_CONFIGURATION_DEBUG) || defined (LLDB_CONFIGURATION_RELEASE) assert (m_frame_sp.get()); #endif return *m_frame_sp; } void ExecutionContext::SetTargetSP (const lldb::TargetSP &target_sp) { m_target_sp = target_sp; } void ExecutionContext::SetProcessSP (const lldb::ProcessSP &process_sp) { m_process_sp = process_sp; } void ExecutionContext::SetThreadSP (const lldb::ThreadSP &thread_sp) { m_thread_sp = thread_sp; } void ExecutionContext::SetFrameSP (const lldb::StackFrameSP &frame_sp) { m_frame_sp = frame_sp; } void ExecutionContext::SetTargetPtr (Target* target) { if (target) m_target_sp = target->shared_from_this(); else m_target_sp.reset(); } void ExecutionContext::SetProcessPtr (Process *process) { if (process) m_process_sp = process->shared_from_this(); else m_process_sp.reset(); } void ExecutionContext::SetThreadPtr (Thread *thread) { if (thread) m_thread_sp = thread->shared_from_this(); else m_thread_sp.reset(); } void ExecutionContext::SetFramePtr (StackFrame *frame) { if (frame) m_frame_sp = frame->shared_from_this(); else m_frame_sp.reset(); } void ExecutionContext::SetContext (const lldb::TargetSP &target_sp, bool get_process) { m_target_sp = target_sp; if (get_process && target_sp) m_process_sp = target_sp->GetProcessSP(); else m_process_sp.reset(); m_thread_sp.reset(); m_frame_sp.reset(); } void ExecutionContext::SetContext (const lldb::ProcessSP &process_sp) { m_process_sp = process_sp; if (process_sp) m_target_sp = process_sp->GetTarget().shared_from_this(); else m_target_sp.reset(); m_thread_sp.reset(); m_frame_sp.reset(); } void ExecutionContext::SetContext (const lldb::ThreadSP &thread_sp) { m_frame_sp.reset(); m_thread_sp = thread_sp; if (thread_sp) { m_process_sp = thread_sp->GetProcess(); if (m_process_sp) m_target_sp = m_process_sp->GetTarget().shared_from_this(); else m_target_sp.reset(); } else { m_target_sp.reset(); m_process_sp.reset(); } } void ExecutionContext::SetContext (const lldb::StackFrameSP &frame_sp) { m_frame_sp = frame_sp; if (frame_sp) { m_thread_sp = frame_sp->CalculateThread(); if (m_thread_sp) { m_process_sp = m_thread_sp->GetProcess(); if (m_process_sp) m_target_sp = m_process_sp->GetTarget().shared_from_this(); else m_target_sp.reset(); } else { m_target_sp.reset(); m_process_sp.reset(); } } else { m_target_sp.reset(); m_process_sp.reset(); m_thread_sp.reset(); } } ExecutionContext & ExecutionContext::operator =(const ExecutionContext &rhs) { if (this != &rhs) { m_target_sp = rhs.m_target_sp; m_process_sp = rhs.m_process_sp; m_thread_sp = rhs.m_thread_sp; m_frame_sp = rhs.m_frame_sp; } return *this; } bool ExecutionContext::operator ==(const ExecutionContext &rhs) const { // Check that the frame shared pointers match, or both are valid and their stack // IDs match since sometimes we get new objects that represent the same // frame within a thread. if ((m_frame_sp == rhs.m_frame_sp) || (m_frame_sp && rhs.m_frame_sp && m_frame_sp->GetStackID() == rhs.m_frame_sp->GetStackID())) { // Check that the thread shared pointers match, or both are valid and // their thread IDs match since sometimes we get new objects that // represent the same thread within a process. if ((m_thread_sp == rhs.m_thread_sp) || (m_thread_sp && rhs.m_thread_sp && m_thread_sp->GetID() == rhs.m_thread_sp->GetID())) { // Processes and targets don't change much return m_process_sp == rhs.m_process_sp && m_target_sp == rhs.m_target_sp; } } return false; } bool ExecutionContext::operator !=(const ExecutionContext &rhs) const { return !(*this == rhs); } bool ExecutionContext::HasTargetScope () const { return ((bool) m_target_sp && m_target_sp->IsValid()); } bool ExecutionContext::HasProcessScope () const { return (HasTargetScope() && ((bool) m_process_sp && m_process_sp->IsValid())); } bool ExecutionContext::HasThreadScope () const { return (HasProcessScope() && ((bool) m_thread_sp && m_thread_sp->IsValid())); } bool ExecutionContext::HasFrameScope () const { return HasThreadScope() && m_frame_sp; } ExecutionContextRef::ExecutionContextRef() : m_target_wp (), m_process_wp (), m_thread_wp (), m_tid(LLDB_INVALID_THREAD_ID), m_stack_id () { } ExecutionContextRef::ExecutionContextRef (const ExecutionContext *exe_ctx) : m_target_wp (), m_process_wp (), m_thread_wp (), m_tid(LLDB_INVALID_THREAD_ID), m_stack_id () { if (exe_ctx) *this = *exe_ctx; } ExecutionContextRef::ExecutionContextRef (const ExecutionContext &exe_ctx) : m_target_wp (), m_process_wp (), m_thread_wp (), m_tid(LLDB_INVALID_THREAD_ID), m_stack_id () { *this = exe_ctx; } ExecutionContextRef::ExecutionContextRef (Target *target, bool adopt_selected) : m_target_wp(), m_process_wp(), m_thread_wp(), m_tid(LLDB_INVALID_THREAD_ID), m_stack_id () { SetTargetPtr (target, adopt_selected); } ExecutionContextRef::ExecutionContextRef (const ExecutionContextRef &rhs) : m_target_wp (rhs.m_target_wp), m_process_wp(rhs.m_process_wp), m_thread_wp (rhs.m_thread_wp), m_tid (rhs.m_tid), m_stack_id (rhs.m_stack_id) { } ExecutionContextRef & ExecutionContextRef::operator =(const ExecutionContextRef &rhs) { if (this != &rhs) { m_target_wp = rhs.m_target_wp; m_process_wp = rhs.m_process_wp; m_thread_wp = rhs.m_thread_wp; m_tid = rhs.m_tid; m_stack_id = rhs.m_stack_id; } return *this; } ExecutionContextRef & ExecutionContextRef::operator =(const ExecutionContext &exe_ctx) { m_target_wp = exe_ctx.GetTargetSP(); m_process_wp = exe_ctx.GetProcessSP(); lldb::ThreadSP thread_sp (exe_ctx.GetThreadSP()); m_thread_wp = thread_sp; if (thread_sp) m_tid = thread_sp->GetID(); else m_tid = LLDB_INVALID_THREAD_ID; lldb::StackFrameSP frame_sp (exe_ctx.GetFrameSP()); if (frame_sp) m_stack_id = frame_sp->GetStackID(); else m_stack_id.Clear(); return *this; } void ExecutionContextRef::Clear() { m_target_wp.reset(); m_process_wp.reset(); ClearThread(); ClearFrame(); } ExecutionContextRef::~ExecutionContextRef() { } void ExecutionContextRef::SetTargetSP (const lldb::TargetSP &target_sp) { m_target_wp = target_sp; } void ExecutionContextRef::SetProcessSP (const lldb::ProcessSP &process_sp) { if (process_sp) { m_process_wp = process_sp; SetTargetSP (process_sp->GetTarget().shared_from_this()); } else { m_process_wp.reset(); m_target_wp.reset(); } } void ExecutionContextRef::SetThreadSP (const lldb::ThreadSP &thread_sp) { if (thread_sp) { m_thread_wp = thread_sp; m_tid = thread_sp->GetID(); SetProcessSP (thread_sp->GetProcess()); } else { ClearThread(); m_process_wp.reset(); m_target_wp.reset(); } } void ExecutionContextRef::SetFrameSP (const lldb::StackFrameSP &frame_sp) { if (frame_sp) { m_stack_id = frame_sp->GetStackID(); SetThreadSP (frame_sp->GetThread()); } else { ClearFrame(); ClearThread(); m_process_wp.reset(); m_target_wp.reset(); } } void ExecutionContextRef::SetTargetPtr (Target* target, bool adopt_selected) { Clear(); if (target) { lldb::TargetSP target_sp (target->shared_from_this()); if (target_sp) { m_target_wp = target_sp; if (adopt_selected) { lldb::ProcessSP process_sp (target_sp->GetProcessSP()); if (process_sp) { m_process_wp = process_sp; if (process_sp) { // Only fill in the thread and frame if our process is stopped if (StateIsStoppedState (process_sp->GetState(), true)) { lldb::ThreadSP thread_sp (process_sp->GetThreadList().GetSelectedThread()); if (!thread_sp) thread_sp = process_sp->GetThreadList().GetThreadAtIndex(0); if (thread_sp) { SetThreadSP (thread_sp); lldb::StackFrameSP frame_sp (thread_sp->GetSelectedFrame()); if (!frame_sp) frame_sp = thread_sp->GetStackFrameAtIndex(0); if (frame_sp) SetFrameSP (frame_sp); } } } } } } } } void ExecutionContextRef::SetProcessPtr (Process *process) { if (process) { SetProcessSP(process->shared_from_this()); } else { m_process_wp.reset(); m_target_wp.reset(); } } void ExecutionContextRef::SetThreadPtr (Thread *thread) { if (thread) { SetThreadSP (thread->shared_from_this()); } else { ClearThread(); m_process_wp.reset(); m_target_wp.reset(); } } void ExecutionContextRef::SetFramePtr (StackFrame *frame) { if (frame) SetFrameSP (frame->shared_from_this()); else Clear(); } lldb::TargetSP ExecutionContextRef::GetTargetSP () const { lldb::TargetSP target_sp(m_target_wp.lock()); if (target_sp && !target_sp->IsValid()) target_sp.reset(); return target_sp; } lldb::ProcessSP ExecutionContextRef::GetProcessSP () const { lldb::ProcessSP process_sp(m_process_wp.lock()); if (process_sp && !process_sp->IsValid()) process_sp.reset(); return process_sp; } lldb::ThreadSP ExecutionContextRef::GetThreadSP () const { lldb::ThreadSP thread_sp (m_thread_wp.lock()); if (m_tid != LLDB_INVALID_THREAD_ID) { // We check if the thread has been destroyed in cases where clients // might still have shared pointer to a thread, but the thread is // not valid anymore (not part of the process) if (!thread_sp || !thread_sp->IsValid()) { lldb::ProcessSP process_sp(GetProcessSP()); if (process_sp && process_sp->IsValid()) { thread_sp = process_sp->GetThreadList().FindThreadByID(m_tid); m_thread_wp = thread_sp; } } } // Check that we aren't about to return an invalid thread sp. We might return a NULL thread_sp, // but don't return an invalid one. if (thread_sp && !thread_sp->IsValid()) thread_sp.reset(); return thread_sp; } lldb::StackFrameSP ExecutionContextRef::GetFrameSP () const { if (m_stack_id.IsValid()) { lldb::ThreadSP thread_sp (GetThreadSP()); if (thread_sp) return thread_sp->GetFrameWithStackID (m_stack_id); } return lldb::StackFrameSP(); } ExecutionContext ExecutionContextRef::Lock () const { return ExecutionContext(this); }