diff options
author | Greg Clayton <gclayton@apple.com> | 2013-05-01 21:54:04 +0000 |
---|---|---|
committer | Greg Clayton <gclayton@apple.com> | 2013-05-01 21:54:04 +0000 |
commit | 160c9d81e07fec2d6299a9f31bb004f1b97419a6 (patch) | |
tree | 01aef16f7f4a45a2eb3c37b5083eda3c8e9cc429 /lldb/source/Plugins/Process/Utility | |
parent | 5ed5181178f256f99954f2662547658a49335088 (diff) | |
download | bcm5719-llvm-160c9d81e07fec2d6299a9f31bb004f1b97419a6.tar.gz bcm5719-llvm-160c9d81e07fec2d6299a9f31bb004f1b97419a6.zip |
<rdar://problem/13700260>
<rdar://problem/13723772>
Modified the lldb_private::Thread to work much better with the OperatingSystem plug-ins. Operating system plug-ins can now return have a "core" key/value pair in each thread dictionary for the OperatingSystemPython plug-ins which allows the core threads to be contained with memory threads. It also allows these memory threads to be stepped, resumed, and controlled just as if they were the actual backing threads themselves.
A few things are introduced:
- lldb_private::Thread now has a GetProtocolID() method which returns the thread protocol ID for a given thread. The protocol ID (Thread::GetProtocolID()) is usually the same as the thread id (Thread::GetID()), but it can differ when a memory thread has its own id, but is backed by an actual API thread.
- Cleaned up the Thread::WillResume() code to do the mandatory parts in Thread::ShouldResume(), and let the thread subclasses override the Thread::WillResume() which is now just a notification.
- Cleaned up ClearStackFrames() implementations so that fewer thread subclasses needed to override them
- Changed the POSIXThread class a bit since it overrode Thread::WillResume(). It is doing the wrong thing by calling "Thread::SetResumeState()" on its own, this shouldn't be done by thread subclasses, but the current code might rely on it so I left it in with a TODO comment with an explanation.
llvm-svn: 180886
Diffstat (limited to 'lldb/source/Plugins/Process/Utility')
4 files changed, 571 insertions, 33 deletions
diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp new file mode 100644 index 00000000000..1cef63d1e22 --- /dev/null +++ b/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp @@ -0,0 +1,256 @@ +//===-- RegisterContextThreadMemory.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-private.h" +#include "lldb/Core/Error.h" +#include "lldb/Target/OperatingSystem.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Thread.h" + +#include "RegisterContextThreadMemory.h" + +using namespace lldb; +using namespace lldb_private; + +RegisterContextThreadMemory::RegisterContextThreadMemory (Thread &thread, + lldb::addr_t register_data_addr) : + RegisterContext (thread, 0), + m_thread_wp (thread.shared_from_this()), + m_reg_ctx_sp (), + m_register_data_addr (register_data_addr), + m_stop_id(0) +{ +} + +RegisterContextThreadMemory::~RegisterContextThreadMemory() +{ +} + +void +RegisterContextThreadMemory::UpdateRegisterContext () +{ + ThreadSP thread_sp (m_thread_wp.lock()); + if (thread_sp) + { + ProcessSP process_sp (thread_sp->GetProcess()); + + if (process_sp) + { + const uint32_t stop_id = process_sp->GetModID().GetStopID(); + if (m_stop_id != stop_id) + { + m_stop_id = stop_id; + m_reg_ctx_sp.reset(); + } + if (!m_reg_ctx_sp) + { + OperatingSystem *os = process_sp->GetOperatingSystem (); + if (os->IsOperatingSystemPluginThread (thread_sp)) + m_reg_ctx_sp = os->CreateRegisterContextForThread (thread_sp.get(), LLDB_INVALID_ADDRESS); + else + { + + ThreadSP backing_thread_sp (thread_sp->GetBackingThread()); + if (backing_thread_sp) + m_reg_ctx_sp = backing_thread_sp->GetRegisterContext(); + } + } + } + } + else + { + m_reg_ctx_sp.reset(); + } +} + +//------------------------------------------------------------------ +// Subclasses must override these functions +//------------------------------------------------------------------ +void +RegisterContextThreadMemory::InvalidateAllRegisters () +{ + UpdateRegisterContext (); + if (m_reg_ctx_sp) + m_reg_ctx_sp->InvalidateAllRegisters(); +} + +size_t +RegisterContextThreadMemory::GetRegisterCount () +{ + UpdateRegisterContext (); + if (m_reg_ctx_sp) + return m_reg_ctx_sp->GetRegisterCount(); + return 0; +} + +const RegisterInfo * +RegisterContextThreadMemory::GetRegisterInfoAtIndex (size_t reg) +{ + UpdateRegisterContext (); + if (m_reg_ctx_sp) + return m_reg_ctx_sp->GetRegisterInfoAtIndex(reg); + return NULL; +} + +size_t +RegisterContextThreadMemory::GetRegisterSetCount () +{ + UpdateRegisterContext (); + if (m_reg_ctx_sp) + return m_reg_ctx_sp->GetRegisterSetCount(); + return 0; +} + +const RegisterSet * +RegisterContextThreadMemory::GetRegisterSet (size_t reg_set) +{ + UpdateRegisterContext (); + if (m_reg_ctx_sp) + return m_reg_ctx_sp->GetRegisterSet(reg_set); + return NULL; +} + +bool +RegisterContextThreadMemory::ReadRegister (const RegisterInfo *reg_info, RegisterValue ®_value) +{ + UpdateRegisterContext (); + if (m_reg_ctx_sp) + return m_reg_ctx_sp->ReadRegister(reg_info, reg_value); + return false; +} + +bool +RegisterContextThreadMemory::WriteRegister (const RegisterInfo *reg_info, const RegisterValue ®_value) +{ + UpdateRegisterContext (); + if (m_reg_ctx_sp) + return m_reg_ctx_sp->WriteRegister (reg_info, reg_value); + return false; +} + +bool +RegisterContextThreadMemory::ReadAllRegisterValues (lldb::DataBufferSP &data_sp) +{ + UpdateRegisterContext (); + if (m_reg_ctx_sp) + return m_reg_ctx_sp->ReadAllRegisterValues(data_sp); + return false; +} + +bool +RegisterContextThreadMemory::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) +{ + UpdateRegisterContext (); + if (m_reg_ctx_sp) + return m_reg_ctx_sp->WriteAllRegisterValues (data_sp); + return false; +} + +bool +RegisterContextThreadMemory::CopyFromRegisterContext (lldb::RegisterContextSP reg_ctx_sp) +{ + UpdateRegisterContext (); + if (m_reg_ctx_sp) + return m_reg_ctx_sp->CopyFromRegisterContext(reg_ctx_sp); + return false; +} + +uint32_t +RegisterContextThreadMemory::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) +{ + UpdateRegisterContext (); + if (m_reg_ctx_sp) + return m_reg_ctx_sp->ConvertRegisterKindToRegisterNumber(kind, num); + return false; +} + +uint32_t +RegisterContextThreadMemory::NumSupportedHardwareBreakpoints () +{ + UpdateRegisterContext (); + if (m_reg_ctx_sp) + return m_reg_ctx_sp->NumSupportedHardwareBreakpoints(); + return false; +} + +uint32_t +RegisterContextThreadMemory::SetHardwareBreakpoint (lldb::addr_t addr, size_t size) +{ + UpdateRegisterContext (); + if (m_reg_ctx_sp) + return m_reg_ctx_sp->SetHardwareBreakpoint(addr, size); + return 0; +} + +bool +RegisterContextThreadMemory::ClearHardwareBreakpoint (uint32_t hw_idx) +{ + UpdateRegisterContext (); + if (m_reg_ctx_sp) + return m_reg_ctx_sp->ClearHardwareBreakpoint (hw_idx); + return false; +} + +uint32_t +RegisterContextThreadMemory::NumSupportedHardwareWatchpoints () +{ + UpdateRegisterContext (); + if (m_reg_ctx_sp) + return m_reg_ctx_sp->NumSupportedHardwareWatchpoints(); + return 0; +} + +uint32_t +RegisterContextThreadMemory::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write) +{ + UpdateRegisterContext (); + if (m_reg_ctx_sp) + return m_reg_ctx_sp->SetHardwareWatchpoint(addr, size, read, write); + return 0; +} + +bool +RegisterContextThreadMemory::ClearHardwareWatchpoint (uint32_t hw_index) +{ + UpdateRegisterContext (); + if (m_reg_ctx_sp) + return m_reg_ctx_sp->ClearHardwareWatchpoint(hw_index); + return false; +} + +bool +RegisterContextThreadMemory::HardwareSingleStep (bool enable) +{ + UpdateRegisterContext (); + if (m_reg_ctx_sp) + return m_reg_ctx_sp->HardwareSingleStep(enable); + return false; +} + +Error +RegisterContextThreadMemory::ReadRegisterValueFromMemory (const lldb_private::RegisterInfo *reg_info, lldb::addr_t src_addr, uint32_t src_len, RegisterValue ®_value) +{ + UpdateRegisterContext (); + if (m_reg_ctx_sp) + return m_reg_ctx_sp->ReadRegisterValueFromMemory (reg_info, src_addr, src_len, reg_value); + Error error; + error.SetErrorString("invalid register context"); + return error; +} + +Error +RegisterContextThreadMemory::WriteRegisterValueToMemory (const lldb_private::RegisterInfo *reg_info, lldb::addr_t dst_addr, uint32_t dst_len, const RegisterValue ®_value) +{ + UpdateRegisterContext (); + if (m_reg_ctx_sp) + return m_reg_ctx_sp->WriteRegisterValueToMemory (reg_info, dst_addr, dst_len, reg_value); + Error error; + error.SetErrorString("invalid register context"); + return error; +} diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.h b/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.h new file mode 100644 index 00000000000..8d7a4b622fe --- /dev/null +++ b/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.h @@ -0,0 +1,114 @@ +//===-- RegisterContextThreadMemory.h ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_RegisterContextThreadMemory_h_ +#define lldb_RegisterContextThreadMemory_h_ + +#include <vector> + +#include "lldb/lldb-private.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Symbol/SymbolContext.h" + +namespace lldb_private { + +class RegisterContextThreadMemory : public lldb_private::RegisterContext +{ +public: + RegisterContextThreadMemory (Thread &thread, + lldb::addr_t register_data_addr); + + virtual ~RegisterContextThreadMemory(); + //------------------------------------------------------------------ + // Subclasses must override these functions + //------------------------------------------------------------------ + virtual void + InvalidateAllRegisters (); + + virtual size_t + GetRegisterCount (); + + virtual const RegisterInfo * + GetRegisterInfoAtIndex (size_t reg); + + virtual size_t + GetRegisterSetCount (); + + virtual const RegisterSet * + GetRegisterSet (size_t reg_set); + + virtual bool + ReadRegister (const RegisterInfo *reg_info, RegisterValue ®_value); + + virtual bool + WriteRegister (const RegisterInfo *reg_info, const RegisterValue ®_value); + + // These two functions are used to implement "push" and "pop" of register states. They are used primarily + // for expression evaluation, where we need to push a new state (storing the old one in data_sp) and then + // restoring the original state by passing the data_sp we got from ReadAllRegisters to WriteAllRegisterValues. + // ReadAllRegisters will do what is necessary to return a coherent set of register values for this thread, which + // may mean e.g. interrupting a thread that is sitting in a kernel trap. That is a somewhat disruptive operation, + // so these API's should only be used when this behavior is needed. + + virtual bool + ReadAllRegisterValues (lldb::DataBufferSP &data_sp); + + virtual bool + WriteAllRegisterValues (const lldb::DataBufferSP &data_sp); + + bool + CopyFromRegisterContext (lldb::RegisterContextSP context); + + virtual uint32_t + ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num); + + //------------------------------------------------------------------ + // Subclasses can override these functions if desired + //------------------------------------------------------------------ + virtual uint32_t + NumSupportedHardwareBreakpoints (); + + virtual uint32_t + SetHardwareBreakpoint (lldb::addr_t addr, size_t size); + + virtual bool + ClearHardwareBreakpoint (uint32_t hw_idx); + + virtual uint32_t + NumSupportedHardwareWatchpoints (); + + virtual uint32_t + SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write); + + virtual bool + ClearHardwareWatchpoint (uint32_t hw_index); + + virtual bool + HardwareSingleStep (bool enable); + + virtual Error + ReadRegisterValueFromMemory (const lldb_private::RegisterInfo *reg_info, lldb::addr_t src_addr, uint32_t src_len, RegisterValue ®_value); + + virtual Error + WriteRegisterValueToMemory (const lldb_private::RegisterInfo *reg_info, lldb::addr_t dst_addr, uint32_t dst_len, const RegisterValue ®_value); + +protected: + void + UpdateRegisterContext (); + + lldb::ThreadWP m_thread_wp; + lldb::RegisterContextSP m_reg_ctx_sp; + lldb::addr_t m_register_data_addr; + uint32_t m_stop_id; +private: + DISALLOW_COPY_AND_ASSIGN (RegisterContextThreadMemory); +}; +} // namespace lldb_private + +#endif // lldb_RegisterContextThreadMemory_h_ diff --git a/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp b/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp index 62c6aeb9c75..3d08026cf98 100644 --- a/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp +++ b/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp @@ -13,6 +13,7 @@ #include "lldb/Target/Process.h" #include "lldb/Target/StopInfo.h" #include "lldb/Target/Unwind.h" +#include "Plugins/Process/Utility/RegisterContextThreadMemory.h" using namespace lldb; using namespace lldb_private; @@ -53,42 +54,32 @@ ThreadMemory::~ThreadMemory() DestroyThread(); } -bool +void ThreadMemory::WillResume (StateType resume_state) { - ClearStackFrames(); - Thread::WillResume(resume_state); + if (m_backing_thread_sp) + m_backing_thread_sp->WillResume(resume_state); +} +void +ThreadMemory::ClearStackFrames () +{ if (m_backing_thread_sp) - return m_backing_thread_sp->WillResume(resume_state); - return true; + m_backing_thread_sp->ClearStackFrames(); + Thread::ClearStackFrames(); } RegisterContextSP ThreadMemory::GetRegisterContext () { - if (m_backing_thread_sp) - return m_backing_thread_sp->GetRegisterContext(); - if (!m_reg_context_sp) - { - ProcessSP process_sp (GetProcess()); - if (process_sp) - { - OperatingSystem *os = process_sp->GetOperatingSystem (); - if (os) - m_reg_context_sp = os->CreateRegisterContextForThread (this, m_register_data_addr); - } - } + m_reg_context_sp.reset (new RegisterContextThreadMemory (*this, m_register_data_addr)); return m_reg_context_sp; } RegisterContextSP ThreadMemory::CreateRegisterContextForFrame (StackFrame *frame) { - if (m_backing_thread_sp) - return m_backing_thread_sp->CreateRegisterContextForFrame(frame); - RegisterContextSP reg_ctx_sp; uint32_t concrete_frame_idx = 0; @@ -108,11 +99,179 @@ ThreadMemory::CreateRegisterContextForFrame (StackFrame *frame) return reg_ctx_sp; } + +//class StopInfoThreadMemory : public StopInfo +//{ +//public: +// //------------------------------------------------------------------ +// // Constructors and Destructors +// //------------------------------------------------------------------ +// StopInfoThreadMemory (Thread &thread, +// uint64_t value, +// StopInfoSP &backing_stop_info_sp) : +// StopInfo (thread, value), +// m_backing_stop_info_sp (backing_stop_info_sp) +// { +// } +// +// virtual +// ~StopInfoThreadMemory() +// { +// } +// +// virtual bool +// IsValid () const +// { +// ThreadSP backing_thread_sp (m_thread.GetBackingThread()); +// if (backing_thread_sp) +// return backing_thread_sp->IsValid(); +// return StopInfo::IsValid(); +// } +// +// virtual Thread & +// GetThread() +// { +// return m_thread; +// } +// +// virtual const Thread & +// GetThread() const +// { +// return m_thread; +// } +// +// virtual uint64_t +// GetValue() const +// { +// if (m_backing_stop_info_sp) +// return m_backing_stop_info_sp->GetValue(); +// return StopInfo::GetValue(); +// } +// +// virtual lldb::StopReason +// GetStopReason () const +// { +// if (m_backing_stop_info_sp) +// return m_backing_stop_info_sp->GetStopReason(); +// return eStopReasonNone; +// } +// +// // ShouldStopSynchronous will get called before any thread plans are consulted, and if it says we should +// // resume the target, then we will just immediately resume. This should not run any code in or resume the +// // target. +// +// virtual bool +// ShouldStopSynchronous (Event *event_ptr) +// { +// if (m_backing_stop_info_sp) +// return m_backing_stop_info_sp->ShouldStopSynchronous(event_ptr); +// return StopInfo::ShouldStopSynchronous (event_ptr); +// } +// +// // If should stop returns false, check if we should notify of this event +// virtual bool +// ShouldNotify (Event *event_ptr) +// { +// if (m_backing_stop_info_sp) +// return m_backing_stop_info_sp->ShouldNotify(event_ptr); +// return StopInfo::ShouldNotify (event_ptr); +// } +// +// virtual void +// WillResume (lldb::StateType resume_state) +// { +// if (m_backing_stop_info_sp) +// return m_backing_stop_info_sp->WillResume(resume_state); +// return StopInfo::WillResume (resume_state); +// } +// +// virtual const char * +// GetDescription () +// { +// if (m_backing_stop_info_sp) +// return m_backing_stop_info_sp->GetDescription(); +// return StopInfo::GetDescription(); +// } +// +// virtual void +// SetDescription (const char *desc_cstr) +// { +// if (m_backing_stop_info_sp) +// m_backing_stop_info_sp->SetDescription(desc_cstr); +// StopInfo::SetDescription(desc_cstr); +// } +// +// // Sometimes the thread plan logic will know that it wants a given stop to stop or not, +// // regardless of what the ordinary logic for that StopInfo would dictate. The main example +// // of this is the ThreadPlanCallFunction, which for instance knows - based on how that particular +// // expression was executed - whether it wants all breakpoints to auto-continue or not. +// // Use OverrideShouldStop on the StopInfo to implement this. +// +// virtual void +// OverrideShouldStop (bool override_value) +// { +// if (m_backing_stop_info_sp) +// m_backing_stop_info_sp->OverrideShouldStop(override_value); +// StopInfo::OverrideShouldStop (override_value); +// } +// +// virtual bool +// GetOverrideShouldStop() +// { +// if (m_backing_stop_info_sp) +// return m_backing_stop_info_sp->GetOverrideShouldStop(); +// return StopInfo::GetOverrideShouldStop(); +// } +// +// virtual bool +// GetOverriddenShouldStopValue () +// { +// if (m_backing_stop_info_sp) +// return m_backing_stop_info_sp->GetOverriddenShouldStopValue(); +// return StopInfo::GetOverriddenShouldStopValue(); +// } +// +// virtual void +// PerformAction (Event *event_ptr) +// { +// if (m_backing_stop_info_sp) +// return m_backing_stop_info_sp->PerformAction(event_ptr); +// return StopInfo::PerformAction(event_ptr); +// } +// +// virtual bool +// ShouldStop (Event *event_ptr) +// { +// if (m_backing_stop_info_sp) +// return m_backing_stop_info_sp->ShouldStop(event_ptr); +// return StopInfo::ShouldStop(event_ptr); +// } +// +// +//protected: +// StopInfoSP m_backing_stop_info_sp; +// +//private: +// DISALLOW_COPY_AND_ASSIGN (StopInfoThreadMemory); +//}; + + lldb::StopInfoSP ThreadMemory::GetPrivateStopReason () { + if (m_actual_stop_info_sp) + return m_actual_stop_info_sp; + if (m_backing_thread_sp) - return m_backing_thread_sp->GetPrivateStopReason(); + { + lldb::StopInfoSP backing_stop_info_sp (m_backing_thread_sp->GetPrivateStopReason()); + if (backing_stop_info_sp) + { + m_actual_stop_info_sp = backing_stop_info_sp; + m_actual_stop_info_sp->SetThread (shared_from_this()); + return m_actual_stop_info_sp; + } + } ProcessSP process_sp (GetProcess()); @@ -150,15 +309,4 @@ ThreadMemory::RefreshStateAfterStop() { if (m_backing_thread_sp) return m_backing_thread_sp->RefreshStateAfterStop(); - - - // Don't fetch the registers by calling Thread::GetRegisterContext() below. - // We might not have fetched any registers yet and we don't want to fetch - // the registers just to call invalidate on them... - RegisterContextSP reg_ctx_sp(m_reg_context_sp); - if (reg_ctx_sp) - { - const bool force = true; - reg_ctx_sp->InvalidateIfNeeded (force); - } } diff --git a/lldb/source/Plugins/Process/Utility/ThreadMemory.h b/lldb/source/Plugins/Process/Utility/ThreadMemory.h index 51a2486f709..2a1f7d6b67d 100644 --- a/lldb/source/Plugins/Process/Utility/ThreadMemory.h +++ b/lldb/source/Plugins/Process/Utility/ThreadMemory.h @@ -70,7 +70,7 @@ public: return NULL; } - virtual bool + virtual void WillResume (lldb::StateType resume_state); virtual void @@ -79,6 +79,14 @@ public: if (m_backing_thread_sp) m_backing_thread_sp->DidResume(); } + + virtual lldb::user_id_t + GetProtocolID () const + { + if (m_backing_thread_sp) + return m_backing_thread_sp->GetProtocolID(); + return Thread::GetProtocolID(); + } virtual void RefreshStateAfterStop(); @@ -90,6 +98,9 @@ public: } virtual void + ClearStackFrames (); + + virtual void ClearBackingThread () { m_backing_thread_sp.reset(); @@ -98,6 +109,7 @@ public: virtual bool SetBackingThread (const lldb::ThreadSP &thread_sp) { + //printf ("Thread 0x%llx is being backed by thread 0x%llx\n", GetID(), thread_sp->GetID()); m_backing_thread_sp = thread_sp; return (bool)thread_sp; } @@ -109,6 +121,14 @@ public: } protected: + + virtual bool + IsOperatingSystemPluginThread () const + { + return true; + } + + //------------------------------------------------------------------ // For ThreadMemory and subclasses //------------------------------------------------------------------ |