Index: lldb/trunk/source/API/SystemInitializerFull.cpp =================================================================== --- lldb/trunk/source/API/SystemInitializerFull.cpp +++ lldb/trunk/source/API/SystemInitializerFull.cpp @@ -55,10 +55,6 @@ #include "Plugins/Process/FreeBSD/ProcessFreeBSD.h" #endif -#if defined(__linux__) -#include "Plugins/Process/Linux/ProcessLinux.h" -#endif - #if defined(_MSC_VER) #include "lldb/Host/windows/windows.h" #include "Plugins/Process/Windows/DynamicLoaderWindows.h" @@ -265,12 +261,6 @@ SystemRuntimeMacOSX::Initialize(); RenderScriptRuntime::Initialize(); -#if defined(__linux__) - //---------------------------------------------------------------------- - // Linux hosted plugins - //---------------------------------------------------------------------- - process_linux::ProcessLinux::Initialize(); -#endif #if defined(_MSC_VER) DynamicLoaderWindows::Initialize(); ProcessWindows::Initialize(); @@ -380,10 +370,6 @@ DynamicLoaderWindows::Terminate(); #endif -#if defined(__linux__) - process_linux::ProcessLinux::Terminate(); -#endif - #if defined(__FreeBSD__) ProcessFreeBSD::Terminate(); #endif Index: lldb/trunk/source/Initialization/SystemInitializerCommon.cpp =================================================================== --- lldb/trunk/source/Initialization/SystemInitializerCommon.cpp +++ lldb/trunk/source/Initialization/SystemInitializerCommon.cpp @@ -42,7 +42,6 @@ #endif #if defined(__linux__) -#include "Plugins/Process/Linux/ProcessLinux.h" #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" #endif Index: lldb/trunk/source/Plugins/Platform/Linux/PlatformLinux.h =================================================================== --- lldb/trunk/source/Plugins/Platform/Linux/PlatformLinux.h +++ lldb/trunk/source/Plugins/Platform/Linux/PlatformLinux.h @@ -122,9 +122,6 @@ uint64_t ConvertMmapFlagsToPlatform(unsigned flags) override; - static bool - UseLlgsForLocalDebugging (); - private: DISALLOW_COPY_AND_ASSIGN (PlatformLinux); }; Index: lldb/trunk/source/Plugins/Platform/Linux/PlatformLinux.cpp =================================================================== --- lldb/trunk/source/Plugins/Platform/Linux/PlatformLinux.cpp +++ lldb/trunk/source/Plugins/Platform/Linux/PlatformLinux.cpp @@ -57,11 +57,6 @@ namespace { - enum - { - ePropertyUseLlgsForLocal = 0, - }; - class PlatformLinuxProperties : public Properties { public: @@ -73,9 +68,6 @@ virtual ~PlatformLinuxProperties() = default; - bool - GetUseLlgsForLocal() const; - private: static const PropertyDefinition* GetStaticPropertyDefinitions(); @@ -99,27 +91,15 @@ return g_setting_name; } -bool -PlatformLinuxProperties::GetUseLlgsForLocal() const -{ - const uint32_t idx = ePropertyUseLlgsForLocal; - return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, GetStaticPropertyDefinitions()[idx].default_uint_value != 0); -} - const PropertyDefinition* PlatformLinuxProperties::GetStaticPropertyDefinitions() { static PropertyDefinition g_properties[] = { - { "use-llgs-for-local" , OptionValue::eTypeBoolean, true, true, NULL, NULL, "Control whether the platform uses llgs for local debug sessions." }, { NULL , OptionValue::eTypeInvalid, false, 0 , NULL, NULL, NULL } }; - // Allow environment variable to disable llgs-local. - if (getenv("PLATFORM_LINUX_DISABLE_LLGS_LOCAL")) - g_properties[ePropertyUseLlgsForLocal].default_uint_value = false; - return g_properties; } @@ -678,21 +658,11 @@ } bool -PlatformLinux::UseLlgsForLocalDebugging () -{ - PlatformLinuxPropertiesSP properties_sp = GetGlobalProperties (); - assert (properties_sp && "global properties shared pointer is null"); - return properties_sp ? properties_sp->GetUseLlgsForLocal () : false; -} - -bool PlatformLinux::CanDebugProcess () { if (IsHost ()) { - // The platform only does local debugging (i.e. uses llgs) when the setting indicates we do that. - // Otherwise, we'll use ProcessLinux/ProcessPOSIX to handle with ProcessMonitor. - return UseLlgsForLocalDebugging (); + return true; } else { @@ -724,14 +694,6 @@ ProcessSP process_sp; - // Ensure we're using llgs for local debugging. - if (!UseLlgsForLocalDebugging ()) - { - assert (false && "we're trying to debug a local process but platform.plugin.linux.use-llgs-for-local is false, should never get here"); - error.SetErrorString ("attempted to start gdb-remote-based debugging for local process but platform.plugin.linux.use-llgs-for-local is false"); - return process_sp; - } - // Make sure we stop at the entry point launch_info.GetFlags ().Set (eLaunchFlagDebug); Index: lldb/trunk/source/Plugins/Process/FreeBSD/CMakeLists.txt =================================================================== --- lldb/trunk/source/Plugins/Process/FreeBSD/CMakeLists.txt +++ lldb/trunk/source/Plugins/Process/FreeBSD/CMakeLists.txt @@ -8,4 +8,13 @@ ProcessFreeBSD.cpp FreeBSDThread.cpp ProcessMonitor.cpp + + ProcessPOSIX.cpp + POSIXThread.cpp + POSIXStopInfo.cpp + RegisterContextPOSIXProcessMonitor_arm.cpp + RegisterContextPOSIXProcessMonitor_arm64.cpp + RegisterContextPOSIXProcessMonitor_powerpc.cpp + RegisterContextPOSIXProcessMonitor_x86.cpp + RegisterContextPOSIXProcessMonitor_mips64.cpp ) Index: lldb/trunk/source/Plugins/Process/FreeBSD/POSIXStopInfo.h =================================================================== --- lldb/trunk/source/Plugins/Process/FreeBSD/POSIXStopInfo.h +++ lldb/trunk/source/Plugins/Process/FreeBSD/POSIXStopInfo.h @@ -0,0 +1,110 @@ +//===-- POSIXStopInfo.h -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_POSIXStopInfo_H_ +#define liblldb_POSIXStopInfo_H_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Target/StopInfo.h" + +#include "CrashReason.h" +#include "POSIXThread.h" + +#include + +//===----------------------------------------------------------------------===// +/// @class POSIXStopInfo +/// @brief Simple base class for all POSIX-specific StopInfo objects. +/// +class POSIXStopInfo + : public lldb_private::StopInfo +{ +public: + POSIXStopInfo(lldb_private::Thread &thread, uint32_t status) + : StopInfo(thread, status) + { } +}; + +//===----------------------------------------------------------------------===// +/// @class POSIXLimboStopInfo +/// @brief Represents the stop state of a process ready to exit. +/// +class POSIXLimboStopInfo + : public POSIXStopInfo +{ +public: + POSIXLimboStopInfo(POSIXThread &thread) + : POSIXStopInfo(thread, 0) + { } + + ~POSIXLimboStopInfo(); + + lldb::StopReason + GetStopReason() const; + + const char * + GetDescription(); + + bool + ShouldStop(lldb_private::Event *event_ptr); + + bool + ShouldNotify(lldb_private::Event *event_ptr); +}; + + +//===----------------------------------------------------------------------===// +/// @class POSIXCrashStopInfo +/// @brief Represents the stop state of process that is ready to crash. +/// +class POSIXCrashStopInfo + : public POSIXStopInfo +{ +public: + POSIXCrashStopInfo(POSIXThread &thread, uint32_t status, + CrashReason reason, + lldb::addr_t fault_addr); + ~POSIXCrashStopInfo(); + + lldb::StopReason + GetStopReason() const; +}; + +//===----------------------------------------------------------------------===// +/// @class POSIXNewThreadStopInfo +/// @brief Represents the stop state of process when a new thread is spawned. +/// + +class POSIXNewThreadStopInfo + : public POSIXStopInfo +{ +public: + POSIXNewThreadStopInfo (POSIXThread &thread) + : POSIXStopInfo (thread, 0) + { } + + ~POSIXNewThreadStopInfo(); + + lldb::StopReason + GetStopReason() const; + + const char * + GetDescription(); + + bool + ShouldStop(lldb_private::Event *event_ptr); + + bool + ShouldNotify(lldb_private::Event *event_ptr); +}; + +#endif Index: lldb/trunk/source/Plugins/Process/FreeBSD/POSIXStopInfo.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/FreeBSD/POSIXStopInfo.cpp +++ lldb/trunk/source/Plugins/Process/FreeBSD/POSIXStopInfo.cpp @@ -0,0 +1,92 @@ +//===-- POSIXStopInfo.cpp ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "POSIXStopInfo.h" + +using namespace lldb; +using namespace lldb_private; + + +//===----------------------------------------------------------------------===// +// POSIXLimboStopInfo + +POSIXLimboStopInfo::~POSIXLimboStopInfo() { } + +lldb::StopReason +POSIXLimboStopInfo::GetStopReason() const +{ + return lldb::eStopReasonThreadExiting; +} + +const char * +POSIXLimboStopInfo::GetDescription() +{ + return "thread exiting"; +} + +bool +POSIXLimboStopInfo::ShouldStop(Event *event_ptr) +{ + return false; +} + +bool +POSIXLimboStopInfo::ShouldNotify(Event *event_ptr) +{ + return false; +} + +//===----------------------------------------------------------------------===// +// POSIXCrashStopInfo + +POSIXCrashStopInfo::POSIXCrashStopInfo(POSIXThread &thread, + uint32_t status, + CrashReason reason, + lldb::addr_t fault_addr) + : POSIXStopInfo(thread, status) +{ + m_description = ::GetCrashReasonString(reason, fault_addr); +} + +POSIXCrashStopInfo::~POSIXCrashStopInfo() { } + +lldb::StopReason +POSIXCrashStopInfo::GetStopReason() const +{ + return lldb::eStopReasonException; +} + +//===----------------------------------------------------------------------===// +// POSIXNewThreadStopInfo + +POSIXNewThreadStopInfo::~POSIXNewThreadStopInfo() { } + +lldb::StopReason +POSIXNewThreadStopInfo::GetStopReason() const +{ + return lldb::eStopReasonNone; +} + +const char * +POSIXNewThreadStopInfo::GetDescription() +{ + return "thread spawned"; +} + +bool +POSIXNewThreadStopInfo::ShouldStop(Event *event_ptr) +{ + return false; +} + +bool +POSIXNewThreadStopInfo::ShouldNotify(Event *event_ptr) +{ + return false; +} Index: lldb/trunk/source/Plugins/Process/FreeBSD/POSIXThread.h =================================================================== --- lldb/trunk/source/Plugins/Process/FreeBSD/POSIXThread.h +++ lldb/trunk/source/Plugins/Process/FreeBSD/POSIXThread.h @@ -0,0 +1,132 @@ +//===-- POSIXThread.h -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_POSIXThread_H_ +#define liblldb_POSIXThread_H_ + +// C Includes +// C++ Includes +#include +#include + +// Other libraries and framework includes +#include "lldb/Target/Thread.h" +#include "Plugins/Process/Utility/RegisterContextPOSIX.h" + +class ProcessMessage; +class ProcessMonitor; +class POSIXBreakpointProtocol; + +//------------------------------------------------------------------------------ +// @class POSIXThread +// @brief Abstraction of a POSIX thread. +class POSIXThread + : public lldb_private::Thread +{ +public: + POSIXThread(lldb_private::Process &process, lldb::tid_t tid); + + virtual ~POSIXThread(); + + void + RefreshStateAfterStop() override; + + // This notifies the thread when a private stop occurs. + void + DidStop () override; + + const char * + GetInfo() override; + + void + SetName (const char *name) override; + + const char * + GetName () override; + + lldb::RegisterContextSP + GetRegisterContext() override; + + lldb::RegisterContextSP + CreateRegisterContextForFrame (lldb_private::StackFrame *frame) override; + + lldb::addr_t + GetThreadPointer () override; + + //-------------------------------------------------------------------------- + // These functions provide a mapping from the register offset + // back to the register index or name for use in debugging or log + // output. + + unsigned + GetRegisterIndexFromOffset(unsigned offset); + + const char * + GetRegisterName(unsigned reg); + + const char * + GetRegisterNameFromOffset(unsigned offset); + + //-------------------------------------------------------------------------- + // These methods form a specialized interface to POSIX threads. + // + bool Resume(); + + void Notify(const ProcessMessage &message); + + //-------------------------------------------------------------------------- + // These methods provide an interface to watchpoints + // + bool EnableHardwareWatchpoint(lldb_private::Watchpoint *wp); + + bool DisableHardwareWatchpoint(lldb_private::Watchpoint *wp); + + uint32_t NumSupportedHardwareWatchpoints(); + + uint32_t FindVacantWatchpointIndex(); + +protected: + POSIXBreakpointProtocol * + GetPOSIXBreakpointProtocol () + { + if (!m_reg_context_sp) + m_reg_context_sp = GetRegisterContext(); + return m_posix_thread; + } + + std::unique_ptr m_frame_ap; + + lldb::BreakpointSiteSP m_breakpoint; + + bool m_thread_name_valid; + std::string m_thread_name; + POSIXBreakpointProtocol *m_posix_thread; + + ProcessMonitor & + GetMonitor(); + + bool + CalculateStopInfo() override; + + void BreakNotify(const ProcessMessage &message); + void WatchNotify(const ProcessMessage &message); + virtual void TraceNotify(const ProcessMessage &message); + void LimboNotify(const ProcessMessage &message); + void SignalNotify(const ProcessMessage &message); + void SignalDeliveredNotify(const ProcessMessage &message); + void CrashNotify(const ProcessMessage &message); + void ThreadNotify(const ProcessMessage &message); + void ExitNotify(const ProcessMessage &message); + void ExecNotify(const ProcessMessage &message); + + lldb_private::Unwind * + GetUnwinder() override; +}; + +#endif // #ifndef liblldb_POSIXThread_H_ Index: lldb/trunk/source/Plugins/Process/FreeBSD/POSIXThread.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/FreeBSD/POSIXThread.cpp +++ lldb/trunk/source/Plugins/Process/FreeBSD/POSIXThread.cpp @@ -0,0 +1,667 @@ +//===-- POSIXThread.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 +#include + +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Breakpoint/Watchpoint.h" +#include "lldb/Breakpoint/BreakpointLocation.h" +#include "lldb/Core/Debugger.h" +#include "lldb/Core/State.h" +#include "lldb/Host/Host.h" +#include "lldb/Host/HostNativeThread.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/StopInfo.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/ThreadSpec.h" +#include "llvm/ADT/SmallString.h" +#include "POSIXStopInfo.h" +#include "POSIXThread.h" +#include "ProcessPOSIX.h" +#include "ProcessPOSIXLog.h" +#include "ProcessMonitor.h" +#include "RegisterContextPOSIXProcessMonitor_arm.h" +#include "RegisterContextPOSIXProcessMonitor_arm64.h" +#include "RegisterContextPOSIXProcessMonitor_mips64.h" +#include "RegisterContextPOSIXProcessMonitor_powerpc.h" +#include "RegisterContextPOSIXProcessMonitor_x86.h" +#include "Plugins/Process/Utility/RegisterContextFreeBSD_arm.h" +#include "Plugins/Process/Utility/RegisterContextFreeBSD_i386.h" +#include "Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h" +#include "Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h" +#include "Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h" +#include "Plugins/Process/Utility/UnwindLLDB.h" + +using namespace lldb; +using namespace lldb_private; + + +POSIXThread::POSIXThread(Process &process, lldb::tid_t tid) + : Thread(process, tid), + m_frame_ap (), + m_breakpoint (), + m_thread_name_valid (false), + m_thread_name (), + m_posix_thread(NULL) +{ + Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); + if (log && log->GetMask().Test(POSIX_LOG_VERBOSE)) + log->Printf ("POSIXThread::%s (tid = %" PRIi64 ")", __FUNCTION__, tid); + + // Set the current watchpoints for this thread. + Target &target = GetProcess()->GetTarget(); + const WatchpointList &wp_list = target.GetWatchpointList(); + size_t wp_size = wp_list.GetSize(); + + for (uint32_t wp_idx = 0; wp_idx < wp_size; wp_idx++) + { + lldb::WatchpointSP wp = wp_list.GetByIndex(wp_idx); + if (wp.get() && wp->IsEnabled()) + { + // This watchpoint as been enabled; obviously this "new" thread + // has been created since that watchpoint was enabled. Since + // the POSIXBreakpointProtocol has yet to be initialized, its + // m_watchpoints_initialized member will be FALSE. Attempting to + // read the debug status register to determine if a watchpoint + // has been hit would result in the zeroing of that register. + // Since the active debug registers would have been cloned when + // this thread was created, simply force the m_watchpoints_initized + // member to TRUE and avoid resetting dr6 and dr7. + GetPOSIXBreakpointProtocol()->ForceWatchpointsInitialized(); + } + } +} + +POSIXThread::~POSIXThread() +{ + DestroyThread(); +} + +ProcessMonitor & +POSIXThread::GetMonitor() +{ + ProcessSP base = GetProcess(); + ProcessPOSIX &process = static_cast(*base); + return process.GetMonitor(); +} + +// Overridden by FreeBSDThread; this is used only on Linux. +void +POSIXThread::RefreshStateAfterStop() +{ + // Invalidate all registers in our register context. We don't set "force" to + // true because the stop reply packet might have had some register values + // that were expedited and these will already be copied into the register + // context by the time this function gets called. The KDPRegisterContext + // class has been made smart enough to detect when it needs to invalidate + // which registers are valid by putting hooks in the register read and + // register supply functions where they check the process stop ID and do + // the right thing. + //if (StateIsStoppedState(GetState()) + { + const bool force = false; + GetRegisterContext()->InvalidateIfNeeded (force); + } + // FIXME: This should probably happen somewhere else. + SetResumeState(eStateRunning, true); + Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); + if (log) + log->Printf ("POSIXThread::%s (tid = %" PRIi64 ") setting thread resume state to running", __FUNCTION__, GetID()); +} + +const char * +POSIXThread::GetInfo() +{ + return NULL; +} + +void +POSIXThread::SetName (const char *name) +{ + m_thread_name_valid = (name && name[0]); + if (m_thread_name_valid) + m_thread_name.assign (name); + else + m_thread_name.clear(); +} + +const char * +POSIXThread::GetName () +{ + if (!m_thread_name_valid) + { + llvm::SmallString<32> thread_name; + HostNativeThread::GetName(GetID(), thread_name); + m_thread_name = thread_name.c_str(); + m_thread_name_valid = true; + } + + if (m_thread_name.empty()) + return NULL; + return m_thread_name.c_str(); +} + +lldb::RegisterContextSP +POSIXThread::GetRegisterContext() +{ + if (!m_reg_context_sp) + { + m_posix_thread = NULL; + + RegisterInfoInterface *reg_interface = NULL; + const ArchSpec &target_arch = GetProcess()->GetTarget().GetArchitecture(); + + switch (target_arch.GetTriple().getOS()) + { + case llvm::Triple::FreeBSD: + switch (target_arch.GetMachine()) + { + case llvm::Triple::arm: + reg_interface = new RegisterContextFreeBSD_arm(target_arch); + break; + case llvm::Triple::ppc: +#ifndef __powerpc64__ + reg_interface = new RegisterContextFreeBSD_powerpc32(target_arch); + break; +#endif + case llvm::Triple::ppc64: + reg_interface = new RegisterContextFreeBSD_powerpc64(target_arch); + break; + case llvm::Triple::mips64: + reg_interface = new RegisterContextFreeBSD_mips64(target_arch); + break; + case llvm::Triple::x86: + reg_interface = new RegisterContextFreeBSD_i386(target_arch); + break; + case llvm::Triple::x86_64: + reg_interface = new RegisterContextFreeBSD_x86_64(target_arch); + break; + default: + break; + } + break; + + default: + break; + } + + assert(reg_interface && "OS or CPU not supported!"); + + switch (target_arch.GetMachine()) + { + case llvm::Triple::aarch64: + { + RegisterContextPOSIXProcessMonitor_arm64 *reg_ctx = new RegisterContextPOSIXProcessMonitor_arm64(*this, 0, reg_interface); + m_posix_thread = reg_ctx; + m_reg_context_sp.reset(reg_ctx); + break; + } + case llvm::Triple::arm: + { + RegisterContextPOSIXProcessMonitor_arm *reg_ctx = new RegisterContextPOSIXProcessMonitor_arm(*this, 0, reg_interface); + m_posix_thread = reg_ctx; + m_reg_context_sp.reset(reg_ctx); + break; + } + case llvm::Triple::mips64: + { + RegisterContextPOSIXProcessMonitor_mips64 *reg_ctx = new RegisterContextPOSIXProcessMonitor_mips64(*this, 0, reg_interface); + m_posix_thread = reg_ctx; + m_reg_context_sp.reset(reg_ctx); + break; + } + case llvm::Triple::ppc: + case llvm::Triple::ppc64: + { + RegisterContextPOSIXProcessMonitor_powerpc *reg_ctx = new RegisterContextPOSIXProcessMonitor_powerpc(*this, 0, reg_interface); + m_posix_thread = reg_ctx; + m_reg_context_sp.reset(reg_ctx); + break; + } + case llvm::Triple::x86: + case llvm::Triple::x86_64: + { + RegisterContextPOSIXProcessMonitor_x86_64 *reg_ctx = new RegisterContextPOSIXProcessMonitor_x86_64(*this, 0, reg_interface); + m_posix_thread = reg_ctx; + m_reg_context_sp.reset(reg_ctx); + break; + } + default: + break; + } + } + return m_reg_context_sp; +} + +lldb::RegisterContextSP +POSIXThread::CreateRegisterContextForFrame(lldb_private::StackFrame *frame) +{ + lldb::RegisterContextSP reg_ctx_sp; + uint32_t concrete_frame_idx = 0; + + Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); + if (log && log->GetMask().Test(POSIX_LOG_VERBOSE)) + log->Printf ("POSIXThread::%s ()", __FUNCTION__); + + if (frame) + concrete_frame_idx = frame->GetConcreteFrameIndex(); + + if (concrete_frame_idx == 0) + reg_ctx_sp = GetRegisterContext(); + else + { + assert(GetUnwinder()); + reg_ctx_sp = GetUnwinder()->CreateRegisterContextForFrame(frame); + } + + return reg_ctx_sp; +} + +lldb::addr_t +POSIXThread::GetThreadPointer () +{ + ProcessMonitor &monitor = GetMonitor(); + addr_t addr; + if (monitor.ReadThreadPointer (GetID(), addr)) + return addr; + else + return LLDB_INVALID_ADDRESS; +} + +bool +POSIXThread::CalculateStopInfo() +{ + SetStopInfo (m_stop_info_sp); + return true; +} + +Unwind * +POSIXThread::GetUnwinder() +{ + if (m_unwinder_ap.get() == NULL) + m_unwinder_ap.reset(new UnwindLLDB(*this)); + + return m_unwinder_ap.get(); +} + +void +POSIXThread::DidStop() +{ + // Don't set the thread state to stopped unless we really stopped. +} + +bool +POSIXThread::Resume() +{ + lldb::StateType resume_state = GetResumeState(); + ProcessMonitor &monitor = GetMonitor(); + bool status; + + Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); + if (log) + log->Printf ("POSIXThread::%s (), resume_state = %s", __FUNCTION__, + StateAsCString(resume_state)); + + switch (resume_state) + { + default: + assert(false && "Unexpected state for resume!"); + status = false; + break; + + case lldb::eStateRunning: + SetState(resume_state); + status = monitor.Resume(GetID(), GetResumeSignal()); + break; + + case lldb::eStateStepping: + SetState(resume_state); + status = monitor.SingleStep(GetID(), GetResumeSignal()); + break; + case lldb::eStateStopped: + case lldb::eStateSuspended: + status = true; + break; + } + + return status; +} + +void +POSIXThread::Notify(const ProcessMessage &message) +{ + Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); + if (log) + log->Printf ("POSIXThread::%s () message kind = '%s' for tid %" PRIu64, + __FUNCTION__, message.PrintKind(), GetID()); + + switch (message.GetKind()) + { + default: + assert(false && "Unexpected message kind!"); + break; + + case ProcessMessage::eExitMessage: + // Nothing to be done. + break; + + case ProcessMessage::eLimboMessage: + LimboNotify(message); + break; + + case ProcessMessage::eSignalMessage: + SignalNotify(message); + break; + + case ProcessMessage::eSignalDeliveredMessage: + SignalDeliveredNotify(message); + break; + + case ProcessMessage::eTraceMessage: + TraceNotify(message); + break; + + case ProcessMessage::eBreakpointMessage: + BreakNotify(message); + break; + + case ProcessMessage::eWatchpointMessage: + WatchNotify(message); + break; + + case ProcessMessage::eCrashMessage: + CrashNotify(message); + break; + + case ProcessMessage::eNewThreadMessage: + ThreadNotify(message); + break; + + case ProcessMessage::eExecMessage: + ExecNotify(message); + break; + } +} + +bool +POSIXThread::EnableHardwareWatchpoint(Watchpoint *wp) +{ + bool wp_set = false; + if (wp) + { + addr_t wp_addr = wp->GetLoadAddress(); + size_t wp_size = wp->GetByteSize(); + bool wp_read = wp->WatchpointRead(); + bool wp_write = wp->WatchpointWrite(); + uint32_t wp_hw_index = wp->GetHardwareIndex(); + POSIXBreakpointProtocol* reg_ctx = GetPOSIXBreakpointProtocol(); + if (reg_ctx) + wp_set = reg_ctx->SetHardwareWatchpointWithIndex(wp_addr, wp_size, + wp_read, wp_write, + wp_hw_index); + } + return wp_set; +} + +bool +POSIXThread::DisableHardwareWatchpoint(Watchpoint *wp) +{ + bool result = false; + if (wp) + { + lldb::RegisterContextSP reg_ctx_sp = GetRegisterContext(); + if (reg_ctx_sp.get()) + result = reg_ctx_sp->ClearHardwareWatchpoint(wp->GetHardwareIndex()); + } + return result; +} + +uint32_t +POSIXThread::NumSupportedHardwareWatchpoints() +{ + lldb::RegisterContextSP reg_ctx_sp = GetRegisterContext(); + if (reg_ctx_sp.get()) + return reg_ctx_sp->NumSupportedHardwareWatchpoints(); + return 0; +} + +uint32_t +POSIXThread::FindVacantWatchpointIndex() +{ + uint32_t hw_index = LLDB_INVALID_INDEX32; + uint32_t num_hw_wps = NumSupportedHardwareWatchpoints(); + uint32_t wp_idx; + POSIXBreakpointProtocol* reg_ctx = GetPOSIXBreakpointProtocol(); + if (reg_ctx) + { + for (wp_idx = 0; wp_idx < num_hw_wps; wp_idx++) + { + if (reg_ctx->IsWatchpointVacant(wp_idx)) + { + hw_index = wp_idx; + break; + } + } + } + return hw_index; +} + +void +POSIXThread::BreakNotify(const ProcessMessage &message) +{ + bool status; + Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); + + assert(GetRegisterContext()); + status = GetPOSIXBreakpointProtocol()->UpdateAfterBreakpoint(); + assert(status && "Breakpoint update failed!"); + + // With our register state restored, resolve the breakpoint object + // corresponding to our current PC. + assert(GetRegisterContext()); + lldb::addr_t pc = GetRegisterContext()->GetPC(); + if (log) + log->Printf ("POSIXThread::%s () PC=0x%8.8" PRIx64, __FUNCTION__, pc); + lldb::BreakpointSiteSP bp_site(GetProcess()->GetBreakpointSiteList().FindByAddress(pc)); + + // If the breakpoint is for this thread, then we'll report the hit, but if it is for another thread, + // we create a stop reason with should_stop=false. If there is no breakpoint location, then report + // an invalid stop reason. We don't need to worry about stepping over the breakpoint here, that will + // be taken care of when the thread resumes and notices that there's a breakpoint under the pc. + if (bp_site) + { + lldb::break_id_t bp_id = bp_site->GetID(); + // If we have an operating system plug-in, we might have set a thread specific breakpoint using the + // operating system thread ID, so we can't make any assumptions about the thread ID so we must always + // report the breakpoint regardless of the thread. + if (bp_site->ValidForThisThread(this) || GetProcess()->GetOperatingSystem () != NULL) + SetStopInfo (StopInfo::CreateStopReasonWithBreakpointSiteID(*this, bp_id)); + else + { + const bool should_stop = false; + SetStopInfo (StopInfo::CreateStopReasonWithBreakpointSiteID(*this, bp_id, should_stop)); + } + } + else + SetStopInfo(StopInfoSP()); +} + +void +POSIXThread::WatchNotify(const ProcessMessage &message) +{ + Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); + + lldb::addr_t halt_addr = message.GetHWAddress(); + if (log) + log->Printf ("POSIXThread::%s () Hardware Watchpoint Address = 0x%8.8" + PRIx64, __FUNCTION__, halt_addr); + + POSIXBreakpointProtocol* reg_ctx = GetPOSIXBreakpointProtocol(); + if (reg_ctx) + { + uint32_t num_hw_wps = reg_ctx->NumSupportedHardwareWatchpoints(); + uint32_t wp_idx; + for (wp_idx = 0; wp_idx < num_hw_wps; wp_idx++) + { + if (reg_ctx->IsWatchpointHit(wp_idx)) + { + // Clear the watchpoint hit here + reg_ctx->ClearWatchpointHits(); + break; + } + } + + if (wp_idx == num_hw_wps) + return; + + Target &target = GetProcess()->GetTarget(); + lldb::addr_t wp_monitor_addr = reg_ctx->GetWatchpointAddress(wp_idx); + const WatchpointList &wp_list = target.GetWatchpointList(); + lldb::WatchpointSP wp_sp = wp_list.FindByAddress(wp_monitor_addr); + + assert(wp_sp.get() && "No watchpoint found"); + SetStopInfo (StopInfo::CreateStopReasonWithWatchpointID(*this, + wp_sp->GetID())); + } +} + +void +POSIXThread::TraceNotify(const ProcessMessage &message) +{ + POSIXBreakpointProtocol* reg_ctx = GetPOSIXBreakpointProtocol(); + if (reg_ctx) + { + uint32_t num_hw_wps = reg_ctx->NumSupportedHardwareWatchpoints(); + uint32_t wp_idx; + for (wp_idx = 0; wp_idx < num_hw_wps; wp_idx++) + { + if (reg_ctx->IsWatchpointHit(wp_idx)) + { + WatchNotify(message); + return; + } + } + } + + SetStopInfo (StopInfo::CreateStopReasonToTrace(*this)); +} + +void +POSIXThread::LimboNotify(const ProcessMessage &message) +{ + SetStopInfo (lldb::StopInfoSP(new POSIXLimboStopInfo(*this))); +} + +void +POSIXThread::SignalNotify(const ProcessMessage &message) +{ + int signo = message.GetSignal(); + SetStopInfo (StopInfo::CreateStopReasonWithSignal(*this, signo)); +} + +void +POSIXThread::SignalDeliveredNotify(const ProcessMessage &message) +{ + int signo = message.GetSignal(); + SetStopInfo (StopInfo::CreateStopReasonWithSignal(*this, signo)); +} + +void +POSIXThread::CrashNotify(const ProcessMessage &message) +{ + // FIXME: Update stop reason as per bugzilla 14598 + int signo = message.GetSignal(); + + assert(message.GetKind() == ProcessMessage::eCrashMessage); + + Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); + if (log) + log->Printf ("POSIXThread::%s () signo = %i, reason = '%s'", + __FUNCTION__, signo, message.PrintCrashReason()); + + SetStopInfo (lldb::StopInfoSP(new POSIXCrashStopInfo(*this, signo, + message.GetCrashReason(), + message.GetFaultAddress()))); +} + +void +POSIXThread::ThreadNotify(const ProcessMessage &message) +{ + SetStopInfo (lldb::StopInfoSP(new POSIXNewThreadStopInfo(*this))); +} + +unsigned +POSIXThread::GetRegisterIndexFromOffset(unsigned offset) +{ + unsigned reg = LLDB_INVALID_REGNUM; + ArchSpec arch = HostInfo::GetArchitecture(); + + switch (arch.GetMachine()) + { + default: + llvm_unreachable("CPU type not supported!"); + break; + + case llvm::Triple::aarch64: + case llvm::Triple::arm: + case llvm::Triple::mips64: + case llvm::Triple::ppc: + case llvm::Triple::ppc64: + case llvm::Triple::x86: + case llvm::Triple::x86_64: + { + POSIXBreakpointProtocol* reg_ctx = GetPOSIXBreakpointProtocol(); + reg = reg_ctx->GetRegisterIndexFromOffset(offset); + } + break; + } + return reg; +} + +void +POSIXThread::ExecNotify(const ProcessMessage &message) +{ + SetStopInfo (StopInfo::CreateStopReasonWithExec(*this)); +} + +const char * +POSIXThread::GetRegisterName(unsigned reg) +{ + const char * name = nullptr; + ArchSpec arch = HostInfo::GetArchitecture(); + + switch (arch.GetMachine()) + { + default: + assert(false && "CPU type not supported!"); + break; + + case llvm::Triple::aarch64: + case llvm::Triple::arm: + case llvm::Triple::mips64: + case llvm::Triple::ppc: + case llvm::Triple::ppc64: + case llvm::Triple::x86: + case llvm::Triple::x86_64: + name = GetRegisterContext()->GetRegisterName(reg); + break; + } + return name; +} + +const char * +POSIXThread::GetRegisterNameFromOffset(unsigned offset) +{ + return GetRegisterName(GetRegisterIndexFromOffset(offset)); +} + Index: lldb/trunk/source/Plugins/Process/FreeBSD/ProcessPOSIX.h =================================================================== --- lldb/trunk/source/Plugins/Process/FreeBSD/ProcessPOSIX.h +++ lldb/trunk/source/Plugins/Process/FreeBSD/ProcessPOSIX.h @@ -0,0 +1,210 @@ +//===-- ProcessPOSIX.h ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_ProcessPOSIX_H_ +#define liblldb_ProcessPOSIX_H_ + +// C Includes + +// C++ Includes +#include +#include + +// Other libraries and framework includes +#include "lldb/Target/Process.h" +#include "ProcessMessage.h" + +class ProcessMonitor; +class POSIXThread; + +class ProcessPOSIX : + public lldb_private::Process +{ +public: + + //------------------------------------------------------------------ + // Constructors and destructors + //------------------------------------------------------------------ + ProcessPOSIX(lldb_private::Target& target, + lldb_private::Listener &listener, + lldb_private::UnixSignalsSP &unix_signals_sp); + + virtual + ~ProcessPOSIX(); + + //------------------------------------------------------------------ + // Process protocol. + //------------------------------------------------------------------ + void + Finalize() override; + + bool + CanDebug(lldb_private::Target &target, bool plugin_specified_by_name) override; + + lldb_private::Error + WillLaunch(lldb_private::Module *module) override; + + lldb_private::Error + DoAttachToProcessWithID (lldb::pid_t pid, const lldb_private::ProcessAttachInfo &attach_info) override; + + lldb_private::Error + DoLaunch (lldb_private::Module *exe_module, + lldb_private::ProcessLaunchInfo &launch_info) override; + + void + DidLaunch() override; + + lldb_private::Error + DoResume() override; + + lldb_private::Error + DoHalt(bool &caused_stop) override; + + lldb_private::Error + DoDetach(bool keep_stopped) override = 0; + + lldb_private::Error + DoSignal(int signal) override; + + lldb_private::Error + DoDestroy() override; + + void + DoDidExec() override; + + void + RefreshStateAfterStop() override; + + bool + IsAlive() override; + + size_t + DoReadMemory(lldb::addr_t vm_addr, + void *buf, + size_t size, + lldb_private::Error &error) override; + + size_t + DoWriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size, + lldb_private::Error &error) override; + + lldb::addr_t + DoAllocateMemory(size_t size, uint32_t permissions, + lldb_private::Error &error) override; + + lldb_private::Error + DoDeallocateMemory(lldb::addr_t ptr) override; + + virtual size_t + GetSoftwareBreakpointTrapOpcode(lldb_private::BreakpointSite* bp_site); + + lldb_private::Error + EnableBreakpointSite(lldb_private::BreakpointSite *bp_site) override; + + lldb_private::Error + DisableBreakpointSite(lldb_private::BreakpointSite *bp_site) override; + + lldb_private::Error + EnableWatchpoint(lldb_private::Watchpoint *wp, bool notify = true) override; + + lldb_private::Error + DisableWatchpoint(lldb_private::Watchpoint *wp, bool notify = true) override; + + lldb_private::Error + GetWatchpointSupportInfo(uint32_t &num) override; + + lldb_private::Error + GetWatchpointSupportInfo(uint32_t &num, bool &after) override; + + virtual uint32_t + UpdateThreadListIfNeeded(); + + bool + UpdateThreadList(lldb_private::ThreadList &old_thread_list, + lldb_private::ThreadList &new_thread_list) override = 0; + + virtual lldb::ByteOrder + GetByteOrder() const; + + lldb::addr_t + GetImageInfoAddress() override; + + size_t + PutSTDIN(const char *buf, size_t len, lldb_private::Error &error) override; + + const lldb::DataBufferSP + GetAuxvData () override; + + //-------------------------------------------------------------------------- + // ProcessPOSIX internal API. + + /// Registers the given message with this process. + virtual void + SendMessage(const ProcessMessage &message); + + ProcessMonitor & + GetMonitor() { assert(m_monitor); return *m_monitor; } + + lldb_private::FileSpec + GetFileSpec(const lldb_private::FileAction *file_action, + const lldb_private::FileSpec &default_file_spec, + const lldb_private::FileSpec &dbg_pts_file_spec); + + /// Stops all threads in the process. + /// The \p stop_tid parameter indicates the thread which initiated the stop. + virtual void + StopAllThreads(lldb::tid_t stop_tid); + + /// Adds the thread to the list of threads for which we have received the initial stopping signal. + /// The \p stop_tid parameter indicates the thread which the stop happened for. + bool + AddThreadForInitialStopIfNeeded(lldb::tid_t stop_tid); + + bool + WaitingForInitialStop(lldb::tid_t stop_tid); + + virtual POSIXThread * + CreateNewPOSIXThread(lldb_private::Process &process, lldb::tid_t tid); + +protected: + /// Target byte order. + lldb::ByteOrder m_byte_order; + + /// Process monitor; + ProcessMonitor *m_monitor; + + /// The module we are executing. + lldb_private::Module *m_module; + + /// Message queue notifying this instance of inferior process state changes. + lldb_private::Mutex m_message_mutex; + std::queue m_message_queue; + + /// Drive any exit events to completion. + bool m_exit_now; + + /// Returns true if the process has exited. + bool HasExited(); + + /// Returns true if the process is stopped. + bool IsStopped(); + + /// Returns true if at least one running is currently running + bool IsAThreadRunning(); + + typedef std::map MMapMap; + MMapMap m_addr_to_mmap_size; + + typedef std::set ThreadStopSet; + /// Every thread begins with a stop signal. This keeps track + /// of the threads for which we have received the stop signal. + ThreadStopSet m_seen_initial_stop; +}; + +#endif // liblldb_MacOSXProcess_H_ Index: lldb/trunk/source/Plugins/Process/FreeBSD/ProcessPOSIX.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/FreeBSD/ProcessPOSIX.cpp +++ lldb/trunk/source/Plugins/Process/FreeBSD/ProcessPOSIX.cpp @@ -0,0 +1,950 @@ +//===-- ProcessPOSIX.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 +#include + +// C++ Includes +// Other libraries and framework includes +#include "lldb/Breakpoint/BreakpointLocation.h" +#include "lldb/Breakpoint/Watchpoint.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/State.h" +#include "lldb/Host/FileSpec.h" +#include "lldb/Host/Host.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Target/DynamicLoader.h" +#include "lldb/Target/Platform.h" +#include "lldb/Target/Target.h" + +#include "ProcessPOSIX.h" +#include "ProcessPOSIXLog.h" +#include "Plugins/Process/Utility/InferiorCallPOSIX.h" +#include "POSIXThread.h" +#include "ProcessMonitor.h" + +#include "lldb/Host/posix/Fcntl.h" + +using namespace lldb; +using namespace lldb_private; + +//------------------------------------------------------------------------------ +// Constructors and destructors. + +ProcessPOSIX::ProcessPOSIX(Target& target, Listener &listener, UnixSignalsSP &unix_signals_sp) + : Process(target, listener, unix_signals_sp), + m_byte_order(lldb::endian::InlHostByteOrder()), + m_monitor(NULL), + m_module(NULL), + m_message_mutex (Mutex::eMutexTypeRecursive), + m_exit_now(false), + m_seen_initial_stop() +{ + // FIXME: Putting this code in the ctor and saving the byte order in a + // member variable is a hack to avoid const qual issues in GetByteOrder. + lldb::ModuleSP module = GetTarget().GetExecutableModule(); + if (module && module->GetObjectFile()) + m_byte_order = module->GetObjectFile()->GetByteOrder(); +} + +ProcessPOSIX::~ProcessPOSIX() +{ + delete m_monitor; +} + +//------------------------------------------------------------------------------ +// Process protocol. +void +ProcessPOSIX::Finalize() +{ + Process::Finalize(); + + if (m_monitor) + m_monitor->StopMonitor(); +} + +bool +ProcessPOSIX::CanDebug(Target &target, bool plugin_specified_by_name) +{ + // For now we are just making sure the file exists for a given module + ModuleSP exe_module_sp(target.GetExecutableModule()); + if (exe_module_sp.get()) + return exe_module_sp->GetFileSpec().Exists(); + // If there is no executable module, we return true since we might be preparing to attach. + return true; +} + +Error +ProcessPOSIX::DoAttachToProcessWithID (lldb::pid_t pid, const ProcessAttachInfo &attach_info) +{ + Error error; + assert(m_monitor == NULL); + + Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); + if (log && log->GetMask().Test(POSIX_LOG_VERBOSE)) + log->Printf ("ProcessPOSIX::%s(pid = %" PRIi64 ")", __FUNCTION__, GetID()); + + m_monitor = new ProcessMonitor(this, pid, error); + + if (!error.Success()) + return error; + + PlatformSP platform_sp (m_target.GetPlatform ()); + assert (platform_sp.get()); + if (!platform_sp) + return error; // FIXME: Detatch? + + // Find out what we can about this process + ProcessInstanceInfo process_info; + platform_sp->GetProcessInfo (pid, process_info); + + // Resolve the executable module + ModuleSP exe_module_sp; + FileSpecList executable_search_paths (Target::GetDefaultExecutableSearchPaths()); + ModuleSpec exe_module_spec(process_info.GetExecutableFile(), m_target.GetArchitecture()); + error = platform_sp->ResolveExecutable(exe_module_spec, + exe_module_sp, + executable_search_paths.GetSize() ? &executable_search_paths : NULL); + if (!error.Success()) + return error; + + // Fix the target architecture if necessary + const ArchSpec &module_arch = exe_module_sp->GetArchitecture(); + if (module_arch.IsValid() && !m_target.GetArchitecture().IsExactMatch(module_arch)) + m_target.SetArchitecture(module_arch); + + // Initialize the target module list + m_target.SetExecutableModule (exe_module_sp, true); + + SetSTDIOFileDescriptor(m_monitor->GetTerminalFD()); + + SetID(pid); + + return error; +} + +Error +ProcessPOSIX::WillLaunch(Module* module) +{ + Error error; + return error; +} + +FileSpec +ProcessPOSIX::GetFileSpec(const lldb_private::FileAction *file_action, + const FileSpec &default_file_spec, + const FileSpec &dbg_pts_file_spec) +{ + FileSpec file_spec{}; + + if (file_action && file_action->GetAction() == FileAction::eFileActionOpen) + { + file_spec = file_action->GetFileSpec(); + // By default the stdio paths passed in will be pseudo-terminal + // (/dev/pts). If so, convert to using a different default path + // instead to redirect I/O to the debugger console. This should + // also handle user overrides to /dev/null or a different file. + if (!file_spec || file_spec == dbg_pts_file_spec) + file_spec = default_file_spec; + } + return file_spec; +} + +Error +ProcessPOSIX::DoLaunch (Module *module, + ProcessLaunchInfo &launch_info) +{ + Error error; + assert(m_monitor == NULL); + + FileSpec working_dir = launch_info.GetWorkingDirectory(); + if (working_dir && + (!working_dir.ResolvePath() || + working_dir.GetFileType() != FileSpec::eFileTypeDirectory)) + { + error.SetErrorStringWithFormat("No such file or directory: %s", + working_dir.GetCString()); + return error; + } + + SetPrivateState(eStateLaunching); + + const lldb_private::FileAction *file_action; + + // Default of empty will mean to use existing open file descriptors + FileSpec stdin_file_spec{}; + FileSpec stdout_file_spec{}; + FileSpec stderr_file_spec{}; + + const FileSpec dbg_pts_file_spec{launch_info.GetPTY().GetSlaveName(NULL,0), false}; + + file_action = launch_info.GetFileActionForFD (STDIN_FILENO); + stdin_file_spec = GetFileSpec(file_action, stdin_file_spec, dbg_pts_file_spec); + + file_action = launch_info.GetFileActionForFD (STDOUT_FILENO); + stdout_file_spec = GetFileSpec(file_action, stdout_file_spec, dbg_pts_file_spec); + + file_action = launch_info.GetFileActionForFD (STDERR_FILENO); + stderr_file_spec = GetFileSpec(file_action, stderr_file_spec, dbg_pts_file_spec); + + m_monitor = new ProcessMonitor(this, + module, + launch_info.GetArguments().GetConstArgumentVector(), + launch_info.GetEnvironmentEntries().GetConstArgumentVector(), + stdin_file_spec, + stdout_file_spec, + stderr_file_spec, + working_dir, + launch_info, + error); + + m_module = module; + + if (!error.Success()) + return error; + + int terminal = m_monitor->GetTerminalFD(); + if (terminal >= 0) { + // The reader thread will close the file descriptor when done, so we pass it a copy. + int stdio = fcntl(terminal, F_DUPFD_CLOEXEC, 0); + if (stdio == -1) { + error.SetErrorToErrno(); + return error; + } + SetSTDIOFileDescriptor(stdio); + } + + SetID(m_monitor->GetPID()); + return error; +} + +void +ProcessPOSIX::DidLaunch() +{ +} + +Error +ProcessPOSIX::DoResume() +{ + StateType state = GetPrivateState(); + + assert(state == eStateStopped); + + SetPrivateState(eStateRunning); + + bool did_resume = false; + + Mutex::Locker lock(m_thread_list.GetMutex()); + + uint32_t thread_count = m_thread_list.GetSize(false); + for (uint32_t i = 0; i < thread_count; ++i) + { + POSIXThread *thread = static_cast( + m_thread_list.GetThreadAtIndex(i, false).get()); + did_resume = thread->Resume() || did_resume; + } + assert(did_resume && "Process resume failed!"); + + return Error(); +} + +addr_t +ProcessPOSIX::GetImageInfoAddress() +{ + Target *target = &GetTarget(); + ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile(); + Address addr = obj_file->GetImageInfoAddress(target); + + if (addr.IsValid()) + return addr.GetLoadAddress(target); + return LLDB_INVALID_ADDRESS; +} + +Error +ProcessPOSIX::DoHalt(bool &caused_stop) +{ + Error error; + + if (IsStopped()) + { + caused_stop = false; + } + else if (kill(GetID(), SIGSTOP)) + { + caused_stop = false; + error.SetErrorToErrno(); + } + else + { + caused_stop = true; + } + return error; +} + +Error +ProcessPOSIX::DoSignal(int signal) +{ + Error error; + + if (kill(GetID(), signal)) + error.SetErrorToErrno(); + + return error; +} + +Error +ProcessPOSIX::DoDestroy() +{ + Error error; + + if (!HasExited()) + { + assert(m_monitor); + m_exit_now = true; + if (GetID() == LLDB_INVALID_PROCESS_ID) + { + error.SetErrorString("invalid process id"); + return error; + } + if (!m_monitor->Kill()) + { + error.SetErrorToErrno(); + return error; + } + + SetPrivateState(eStateExited); + } + + return error; +} + +void +ProcessPOSIX::DoDidExec() +{ + Target *target = &GetTarget(); + if (target) + { + PlatformSP platform_sp (target->GetPlatform()); + assert (platform_sp.get()); + if (platform_sp) + { + ProcessInstanceInfo process_info; + platform_sp->GetProcessInfo(GetID(), process_info); + ModuleSP exe_module_sp; + ModuleSpec exe_module_spec(process_info.GetExecutableFile(), target->GetArchitecture()); + FileSpecList executable_search_paths (Target::GetDefaultExecutableSearchPaths()); + Error error = platform_sp->ResolveExecutable(exe_module_spec, + exe_module_sp, + executable_search_paths.GetSize() ? &executable_search_paths : NULL); + if (!error.Success()) + return; + target->SetExecutableModule(exe_module_sp, true); + } + } +} + +void +ProcessPOSIX::SendMessage(const ProcessMessage &message) +{ + Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); + + Mutex::Locker lock(m_message_mutex); + + Mutex::Locker thread_lock(m_thread_list.GetMutex()); + + POSIXThread *thread = static_cast( + m_thread_list.FindThreadByID(message.GetTID(), false).get()); + + switch (message.GetKind()) + { + case ProcessMessage::eInvalidMessage: + return; + + case ProcessMessage::eAttachMessage: + SetPrivateState(eStateStopped); + return; + + case ProcessMessage::eLimboMessage: + assert(thread); + thread->SetState(eStateStopped); + if (message.GetTID() == GetID()) + { + m_exit_status = message.GetExitStatus(); + if (m_exit_now) + { + SetPrivateState(eStateExited); + m_monitor->Detach(GetID()); + } + else + { + StopAllThreads(message.GetTID()); + SetPrivateState(eStateStopped); + } + } + else + { + StopAllThreads(message.GetTID()); + SetPrivateState(eStateStopped); + } + break; + + case ProcessMessage::eExitMessage: + if (thread != nullptr) + thread->SetState(eStateExited); + else + { + if (log) + log->Warning ("ProcessPOSIX::%s eExitMessage for TID %" PRIu64 " failed to find a thread to mark as eStateExited, ignoring", __FUNCTION__, message.GetTID ()); + } + + // FIXME: I'm not sure we need to do this. + if (message.GetTID() == GetID()) + { + SetExitStatus(message.GetExitStatus(), NULL); + } + else if (!IsAThreadRunning()) + SetPrivateState(eStateStopped); + break; + + case ProcessMessage::eSignalMessage: + case ProcessMessage::eSignalDeliveredMessage: + if (message.GetSignal() == SIGSTOP && + AddThreadForInitialStopIfNeeded(message.GetTID())) + return; + // Intentional fall-through + + case ProcessMessage::eBreakpointMessage: + case ProcessMessage::eTraceMessage: + case ProcessMessage::eWatchpointMessage: + case ProcessMessage::eCrashMessage: + assert(thread); + thread->SetState(eStateStopped); + StopAllThreads(message.GetTID()); + SetPrivateState(eStateStopped); + break; + + case ProcessMessage::eNewThreadMessage: + { + lldb::tid_t new_tid = message.GetChildTID(); + if (WaitingForInitialStop(new_tid)) + { + m_monitor->WaitForInitialTIDStop(new_tid); + } + assert(thread); + thread->SetState(eStateStopped); + StopAllThreads(message.GetTID()); + SetPrivateState(eStateStopped); + break; + } + + case ProcessMessage::eExecMessage: + { + assert(thread); + thread->SetState(eStateStopped); + StopAllThreads(message.GetTID()); + SetPrivateState(eStateStopped); + break; + } + } + + + m_message_queue.push(message); +} + +void +ProcessPOSIX::StopAllThreads(lldb::tid_t stop_tid) +{ + // FIXME: Will this work the same way on FreeBSD and Linux? +} + +bool +ProcessPOSIX::AddThreadForInitialStopIfNeeded(lldb::tid_t stop_tid) +{ + bool added_to_set = false; + ThreadStopSet::iterator it = m_seen_initial_stop.find(stop_tid); + if (it == m_seen_initial_stop.end()) + { + m_seen_initial_stop.insert(stop_tid); + added_to_set = true; + } + return added_to_set; +} + +bool +ProcessPOSIX::WaitingForInitialStop(lldb::tid_t stop_tid) +{ + return (m_seen_initial_stop.find(stop_tid) == m_seen_initial_stop.end()); +} + +POSIXThread * +ProcessPOSIX::CreateNewPOSIXThread(lldb_private::Process &process, lldb::tid_t tid) +{ + return new POSIXThread(process, tid); +} + +void +ProcessPOSIX::RefreshStateAfterStop() +{ + Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); + if (log && log->GetMask().Test(POSIX_LOG_VERBOSE)) + log->Printf ("ProcessPOSIX::%s(), message_queue size = %d", __FUNCTION__, (int)m_message_queue.size()); + + Mutex::Locker lock(m_message_mutex); + + // This method used to only handle one message. Changing it to loop allows + // it to handle the case where we hit a breakpoint while handling a different + // breakpoint. + while (!m_message_queue.empty()) + { + ProcessMessage &message = m_message_queue.front(); + + // Resolve the thread this message corresponds to and pass it along. + lldb::tid_t tid = message.GetTID(); + if (log) + log->Printf ("ProcessPOSIX::%s(), message_queue size = %d, pid = %" PRIi64, __FUNCTION__, (int)m_message_queue.size(), tid); + + if (message.GetKind() == ProcessMessage::eNewThreadMessage) + { + if (log) + log->Printf ("ProcessPOSIX::%s() adding thread, tid = %" PRIi64, __FUNCTION__, message.GetChildTID()); + lldb::tid_t child_tid = message.GetChildTID(); + ThreadSP thread_sp; + thread_sp.reset(CreateNewPOSIXThread(*this, child_tid)); + + Mutex::Locker lock(m_thread_list.GetMutex()); + + m_thread_list.AddThread(thread_sp); + } + + m_thread_list.RefreshStateAfterStop(); + + POSIXThread *thread = static_cast( + GetThreadList().FindThreadByID(tid, false).get()); + if (thread) + thread->Notify(message); + + if (message.GetKind() == ProcessMessage::eExitMessage) + { + // FIXME: We should tell the user about this, but the limbo message is probably better for that. + if (log) + log->Printf ("ProcessPOSIX::%s() removing thread, tid = %" PRIi64, __FUNCTION__, tid); + + Mutex::Locker lock(m_thread_list.GetMutex()); + + ThreadSP thread_sp = m_thread_list.RemoveThreadByID(tid, false); + thread_sp.reset(); + m_seen_initial_stop.erase(tid); + } + + m_message_queue.pop(); + } +} + +bool +ProcessPOSIX::IsAlive() +{ + StateType state = GetPrivateState(); + return state != eStateDetached + && state != eStateExited + && state != eStateInvalid + && state != eStateUnloaded; +} + +size_t +ProcessPOSIX::DoReadMemory(addr_t vm_addr, + void *buf, size_t size, Error &error) +{ + assert(m_monitor); + return m_monitor->ReadMemory(vm_addr, buf, size, error); +} + +size_t +ProcessPOSIX::DoWriteMemory(addr_t vm_addr, const void *buf, size_t size, + Error &error) +{ + assert(m_monitor); + return m_monitor->WriteMemory(vm_addr, buf, size, error); +} + +addr_t +ProcessPOSIX::DoAllocateMemory(size_t size, uint32_t permissions, + Error &error) +{ + addr_t allocated_addr = LLDB_INVALID_ADDRESS; + + unsigned prot = 0; + if (permissions & lldb::ePermissionsReadable) + prot |= eMmapProtRead; + if (permissions & lldb::ePermissionsWritable) + prot |= eMmapProtWrite; + if (permissions & lldb::ePermissionsExecutable) + prot |= eMmapProtExec; + + if (InferiorCallMmap(this, allocated_addr, 0, size, prot, + eMmapFlagsAnon | eMmapFlagsPrivate, -1, 0)) { + m_addr_to_mmap_size[allocated_addr] = size; + error.Clear(); + } else { + allocated_addr = LLDB_INVALID_ADDRESS; + error.SetErrorStringWithFormat("unable to allocate %zu bytes of memory with permissions %s", size, GetPermissionsAsCString (permissions)); + } + + return allocated_addr; +} + +Error +ProcessPOSIX::DoDeallocateMemory(lldb::addr_t addr) +{ + Error error; + MMapMap::iterator pos = m_addr_to_mmap_size.find(addr); + if (pos != m_addr_to_mmap_size.end() && + InferiorCallMunmap(this, addr, pos->second)) + m_addr_to_mmap_size.erase (pos); + else + error.SetErrorStringWithFormat("unable to deallocate memory at 0x%" PRIx64, addr); + + return error; +} + +size_t +ProcessPOSIX::GetSoftwareBreakpointTrapOpcode(BreakpointSite* bp_site) +{ + static const uint8_t g_aarch64_opcode[] = { 0x00, 0x00, 0x20, 0xD4 }; + static const uint8_t g_i386_opcode[] = { 0xCC }; + + ArchSpec arch = GetTarget().GetArchitecture(); + const uint8_t *opcode = NULL; + size_t opcode_size = 0; + + switch (arch.GetMachine()) + { + default: + assert(false && "CPU type not supported!"); + break; + + case llvm::Triple::arm: + { + // The ARM reference recommends the use of 0xe7fddefe and 0xdefe + // but the linux kernel does otherwise. + static const uint8_t g_arm_breakpoint_opcode[] = { 0xf0, 0x01, 0xf0, 0xe7 }; + static const uint8_t g_thumb_breakpoint_opcode[] = { 0x01, 0xde }; + + lldb::BreakpointLocationSP bp_loc_sp (bp_site->GetOwnerAtIndex (0)); + AddressClass addr_class = eAddressClassUnknown; + + if (bp_loc_sp) + addr_class = bp_loc_sp->GetAddress ().GetAddressClass (); + + if (addr_class == eAddressClassCodeAlternateISA + || (addr_class == eAddressClassUnknown + && bp_loc_sp->GetAddress().GetOffset() & 1)) + { + opcode = g_thumb_breakpoint_opcode; + opcode_size = sizeof(g_thumb_breakpoint_opcode); + } + else + { + opcode = g_arm_breakpoint_opcode; + opcode_size = sizeof(g_arm_breakpoint_opcode); + } + } + break; + case llvm::Triple::aarch64: + opcode = g_aarch64_opcode; + opcode_size = sizeof(g_aarch64_opcode); + break; + + case llvm::Triple::x86: + case llvm::Triple::x86_64: + opcode = g_i386_opcode; + opcode_size = sizeof(g_i386_opcode); + break; + } + + bp_site->SetTrapOpcode(opcode, opcode_size); + return opcode_size; +} + +Error +ProcessPOSIX::EnableBreakpointSite(BreakpointSite *bp_site) +{ + return EnableSoftwareBreakpoint(bp_site); +} + +Error +ProcessPOSIX::DisableBreakpointSite(BreakpointSite *bp_site) +{ + return DisableSoftwareBreakpoint(bp_site); +} + +Error +ProcessPOSIX::EnableWatchpoint(Watchpoint *wp, bool notify) +{ + Error error; + if (wp) + { + user_id_t watchID = wp->GetID(); + addr_t addr = wp->GetLoadAddress(); + Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); + if (log) + log->Printf ("ProcessPOSIX::EnableWatchpoint(watchID = %" PRIu64 ")", + watchID); + if (wp->IsEnabled()) + { + if (log) + log->Printf("ProcessPOSIX::EnableWatchpoint(watchID = %" PRIu64 + ") addr = 0x%8.8" PRIx64 ": watchpoint already enabled.", + watchID, (uint64_t)addr); + return error; + } + + // Try to find a vacant watchpoint slot in the inferiors' main thread + uint32_t wp_hw_index = LLDB_INVALID_INDEX32; + Mutex::Locker lock(m_thread_list.GetMutex()); + POSIXThread *thread = static_cast( + m_thread_list.GetThreadAtIndex(0, false).get()); + + if (thread) + wp_hw_index = thread->FindVacantWatchpointIndex(); + + if (wp_hw_index == LLDB_INVALID_INDEX32) + { + error.SetErrorString("Setting hardware watchpoint failed."); + } + else + { + wp->SetHardwareIndex(wp_hw_index); + bool wp_enabled = true; + uint32_t thread_count = m_thread_list.GetSize(false); + for (uint32_t i = 0; i < thread_count; ++i) + { + thread = static_cast( + m_thread_list.GetThreadAtIndex(i, false).get()); + if (thread) + wp_enabled &= thread->EnableHardwareWatchpoint(wp); + else + wp_enabled = false; + } + if (wp_enabled) + { + wp->SetEnabled(true, notify); + return error; + } + else + { + // Watchpoint enabling failed on at least one + // of the threads so roll back all of them + DisableWatchpoint(wp, false); + error.SetErrorString("Setting hardware watchpoint failed"); + } + } + } + else + error.SetErrorString("Watchpoint argument was NULL."); + return error; +} + +Error +ProcessPOSIX::DisableWatchpoint(Watchpoint *wp, bool notify) +{ + Error error; + if (wp) + { + user_id_t watchID = wp->GetID(); + addr_t addr = wp->GetLoadAddress(); + Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); + if (log) + log->Printf("ProcessPOSIX::DisableWatchpoint(watchID = %" PRIu64 ")", + watchID); + if (!wp->IsEnabled()) + { + if (log) + log->Printf("ProcessPOSIX::DisableWatchpoint(watchID = %" PRIu64 + ") addr = 0x%8.8" PRIx64 ": watchpoint already disabled.", + watchID, (uint64_t)addr); + // This is needed (for now) to keep watchpoints disabled correctly + wp->SetEnabled(false, notify); + return error; + } + + if (wp->IsHardware()) + { + bool wp_disabled = true; + Mutex::Locker lock(m_thread_list.GetMutex()); + uint32_t thread_count = m_thread_list.GetSize(false); + for (uint32_t i = 0; i < thread_count; ++i) + { + POSIXThread *thread = static_cast( + m_thread_list.GetThreadAtIndex(i, false).get()); + if (thread) + wp_disabled &= thread->DisableHardwareWatchpoint(wp); + else + wp_disabled = false; + } + if (wp_disabled) + { + wp->SetHardwareIndex(LLDB_INVALID_INDEX32); + wp->SetEnabled(false, notify); + return error; + } + else + error.SetErrorString("Disabling hardware watchpoint failed"); + } + } + else + error.SetErrorString("Watchpoint argument was NULL."); + return error; +} + +Error +ProcessPOSIX::GetWatchpointSupportInfo(uint32_t &num) +{ + Error error; + Mutex::Locker lock(m_thread_list.GetMutex()); + POSIXThread *thread = static_cast( + m_thread_list.GetThreadAtIndex(0, false).get()); + if (thread) + num = thread->NumSupportedHardwareWatchpoints(); + else + error.SetErrorString("Process does not exist."); + return error; +} + +Error +ProcessPOSIX::GetWatchpointSupportInfo(uint32_t &num, bool &after) +{ + Error error = GetWatchpointSupportInfo(num); + // Watchpoints trigger and halt the inferior after + // the corresponding instruction has been executed. + after = true; + return error; +} + +uint32_t +ProcessPOSIX::UpdateThreadListIfNeeded() +{ + Mutex::Locker lock(m_thread_list.GetMutex()); + // Do not allow recursive updates. + return m_thread_list.GetSize(false); +} + +bool +ProcessPOSIX::UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_thread_list) +{ + Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); + if (log && log->GetMask().Test(POSIX_LOG_VERBOSE)) + log->Printf ("ProcessPOSIX::%s() (pid = %" PRIi64 ")", __FUNCTION__, GetID()); + + bool has_updated = false; + // Update the process thread list with this new thread. + // FIXME: We should be using tid, not pid. + assert(m_monitor); + ThreadSP thread_sp (old_thread_list.FindThreadByID (GetID(), false)); + if (!thread_sp) { + thread_sp.reset(CreateNewPOSIXThread(*this, GetID())); + has_updated = true; + } + + if (log && log->GetMask().Test(POSIX_LOG_VERBOSE)) + log->Printf ("ProcessPOSIX::%s() updated pid = %" PRIi64, __FUNCTION__, GetID()); + new_thread_list.AddThread(thread_sp); + + return has_updated; // the list has been updated +} + +ByteOrder +ProcessPOSIX::GetByteOrder() const +{ + // FIXME: We should be able to extract this value directly. See comment in + // ProcessPOSIX(). + return m_byte_order; +} + +size_t +ProcessPOSIX::PutSTDIN(const char *buf, size_t len, Error &error) +{ + ssize_t status; + if ((status = write(m_monitor->GetTerminalFD(), buf, len)) < 0) + { + error.SetErrorToErrno(); + return 0; + } + return status; +} + +//------------------------------------------------------------------------------ +// Utility functions. + +bool +ProcessPOSIX::HasExited() +{ + switch (GetPrivateState()) + { + default: + break; + + case eStateDetached: + case eStateExited: + return true; + } + + return false; +} + +bool +ProcessPOSIX::IsStopped() +{ + switch (GetPrivateState()) + { + default: + break; + + case eStateStopped: + case eStateCrashed: + case eStateSuspended: + return true; + } + + return false; +} + +bool +ProcessPOSIX::IsAThreadRunning() +{ + bool is_running = false; + Mutex::Locker lock(m_thread_list.GetMutex()); + uint32_t thread_count = m_thread_list.GetSize(false); + for (uint32_t i = 0; i < thread_count; ++i) + { + POSIXThread *thread = static_cast( + m_thread_list.GetThreadAtIndex(i, false).get()); + StateType thread_state = thread->GetState(); + if (thread_state == eStateRunning || thread_state == eStateStepping) + { + is_running = true; + break; + } + } + return is_running; +} + +const DataBufferSP +ProcessPOSIX::GetAuxvData () +{ + // If we're the local platform, we can ask the host for auxv data. + PlatformSP platform_sp = m_target.GetPlatform (); + if (platform_sp && platform_sp->IsHost ()) + return lldb_private::Host::GetAuxvData(this); + + // Somewhat unexpected - the process is not running locally or we don't have a platform. + assert (false && "no platform or not the host - how did we get here with ProcessPOSIX?"); + return DataBufferSP (); +} Index: lldb/trunk/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.h =================================================================== --- lldb/trunk/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.h +++ lldb/trunk/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.h @@ -0,0 +1,95 @@ +//===-- RegisterContextPOSIXProcessMonitor_arm.h --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContextPOSIXProcessMonitor_arm_H_ +#define liblldb_RegisterContextPOSIXProcessMonitor_arm_H_ + +#include "Plugins/Process/Utility/RegisterContextPOSIX_arm.h" + +class RegisterContextPOSIXProcessMonitor_arm: + public RegisterContextPOSIX_arm, + public POSIXBreakpointProtocol +{ +public: + RegisterContextPOSIXProcessMonitor_arm(lldb_private::Thread &thread, + uint32_t concrete_frame_idx, + lldb_private::RegisterInfoInterface *register_info); + +protected: + bool + ReadGPR(); + + bool + ReadFPR(); + + bool + WriteGPR(); + + bool + WriteFPR(); + + // lldb_private::RegisterContext + bool + ReadRegister(const unsigned reg, lldb_private::RegisterValue &value); + + bool + WriteRegister(const unsigned reg, const lldb_private::RegisterValue &value); + + bool + ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value); + + bool + WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value); + + bool + ReadAllRegisterValues(lldb::DataBufferSP &data_sp); + + bool + WriteAllRegisterValues(const lldb::DataBufferSP &data_sp); + + uint32_t + SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, bool write); + + bool + ClearHardwareWatchpoint(uint32_t hw_index); + + bool + HardwareSingleStep(bool enable); + + // POSIXBreakpointProtocol + bool + UpdateAfterBreakpoint(); + + unsigned + GetRegisterIndexFromOffset(unsigned offset); + + bool + IsWatchpointHit(uint32_t hw_index); + + bool + ClearWatchpointHits(); + + lldb::addr_t + GetWatchpointAddress(uint32_t hw_index); + + bool + IsWatchpointVacant(uint32_t hw_index); + + bool + SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, bool read, bool write, uint32_t hw_index); + + uint32_t + NumSupportedHardwareWatchpoints(); + +private: + ProcessMonitor & + GetMonitor(); +}; + +#endif Index: lldb/trunk/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.cpp +++ lldb/trunk/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.cpp @@ -0,0 +1,322 @@ +//===-- RegisterContextPOSIXProcessMonitor_arm.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/Core/DataBufferHeap.h" +#include "lldb/Core/RegisterValue.h" +#include "lldb/Target/Thread.h" + +#include "RegisterContextPOSIX_arm.h" +#include "ProcessPOSIX.h" +#include "RegisterContextPOSIXProcessMonitor_arm.h" +#include "ProcessMonitor.h" + +using namespace lldb_private; +using namespace lldb; + +#define REG_CONTEXT_SIZE (GetGPRSize()) + +RegisterContextPOSIXProcessMonitor_arm::RegisterContextPOSIXProcessMonitor_arm(Thread &thread, + uint32_t concrete_frame_idx, + lldb_private::RegisterInfoInterface *register_info) + : RegisterContextPOSIX_arm(thread, concrete_frame_idx, register_info) +{ +} + +ProcessMonitor & +RegisterContextPOSIXProcessMonitor_arm::GetMonitor() +{ + ProcessSP base = CalculateProcess(); + ProcessPOSIX *process = static_cast(base.get()); + return process->GetMonitor(); +} + +bool +RegisterContextPOSIXProcessMonitor_arm::ReadGPR() +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadGPR(m_thread.GetID(), &m_gpr_arm, GetGPRSize()); +} + +bool +RegisterContextPOSIXProcessMonitor_arm::ReadFPR() +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadFPR(m_thread.GetID(), &m_fpr, sizeof(m_fpr)); +} + +bool +RegisterContextPOSIXProcessMonitor_arm::WriteGPR() +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.WriteGPR(m_thread.GetID(), &m_gpr_arm, GetGPRSize()); +} + +bool +RegisterContextPOSIXProcessMonitor_arm::WriteFPR() +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.WriteFPR(m_thread.GetID(), &m_fpr, sizeof(m_fpr)); +} + +bool +RegisterContextPOSIXProcessMonitor_arm::ReadRegister(const unsigned reg, + RegisterValue &value) +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadRegisterValue(m_thread.GetID(), + GetRegisterOffset(reg), + GetRegisterName(reg), + GetRegisterSize(reg), + value); +} + +bool +RegisterContextPOSIXProcessMonitor_arm::WriteRegister(const unsigned reg, + const RegisterValue &value) +{ + unsigned reg_to_write = reg; + RegisterValue value_to_write = value; + + // Check if this is a subregister of a full register. + const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); + if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) + { + RegisterValue full_value; + uint32_t full_reg = reg_info->invalidate_regs[0]; + const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg); + + // Read the full register. + if (ReadRegister(full_reg_info, full_value)) + { + Error error; + ByteOrder byte_order = GetByteOrder(); + uint8_t dst[RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the full register. + const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info, + dst, + sizeof(dst), + byte_order, + error); + if (error.Success() && dest_size) + { + uint8_t src[RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the source data. + const uint32_t src_size = value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error); + if (error.Success() && src_size && (src_size < dest_size)) + { + // Copy the src bytes to the destination. + memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size); + // Set this full register as the value to write. + value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order); + value_to_write.SetType(full_reg_info); + reg_to_write = full_reg; + } + } + } + } + + ProcessMonitor &monitor = GetMonitor(); + return monitor.WriteRegisterValue(m_thread.GetID(), + GetRegisterOffset(reg_to_write), + GetRegisterName(reg_to_write), + value_to_write); +} + +bool +RegisterContextPOSIXProcessMonitor_arm::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value) +{ + if (!reg_info) + return false; + + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + + if (IsFPR(reg)) + { + if (!ReadFPR()) + return false; + } + else + { + return ReadRegister(reg, value); + } + + // Get pointer to m_fpr variable and set the data from it. + assert (reg_info->byte_offset < sizeof m_fpr); + uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset; + switch (reg_info->byte_size) + { + case 2: + value.SetUInt16(*(uint16_t *)src); + return true; + case 4: + value.SetUInt32(*(uint32_t *)src); + return true; + case 8: + value.SetUInt64(*(uint64_t *)src); + return true; + default: + assert(false && "Unhandled data size."); + return false; + } +} + +bool +RegisterContextPOSIXProcessMonitor_arm::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value) +{ + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + + if (IsGPR(reg)) + { + return WriteRegister(reg, value); + } + else if (IsFPR(reg)) + { + return WriteFPR(); + } + + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_arm::ReadAllRegisterValues(DataBufferSP &data_sp) +{ + bool success = false; + data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0)); + if (data_sp && ReadGPR () && ReadFPR ()) + { + uint8_t *dst = data_sp->GetBytes(); + success = dst != 0; + + if (success) + { + ::memcpy (dst, &m_gpr_arm, GetGPRSize()); + dst += GetGPRSize(); + ::memcpy (dst, &m_fpr, sizeof(m_fpr)); + } + } + return success; +} + +bool +RegisterContextPOSIXProcessMonitor_arm::WriteAllRegisterValues(const DataBufferSP &data_sp) +{ + bool success = false; + if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) + { + uint8_t *src = data_sp->GetBytes(); + if (src) + { + ::memcpy (&m_gpr_arm, src, GetGPRSize()); + + if (WriteGPR()) + { + src += GetGPRSize(); + ::memcpy (&m_fpr, src, sizeof(m_fpr)); + + success = WriteFPR(); + } + } + } + return success; +} + +uint32_t +RegisterContextPOSIXProcessMonitor_arm::SetHardwareWatchpoint(addr_t addr, size_t size, + bool read, bool write) +{ + const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); + uint32_t hw_index; + + for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index) + { + if (IsWatchpointVacant(hw_index)) + return SetHardwareWatchpointWithIndex(addr, size, + read, write, + hw_index); + } + + return LLDB_INVALID_INDEX32; +} + +bool +RegisterContextPOSIXProcessMonitor_arm::ClearHardwareWatchpoint(uint32_t hw_index) +{ + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_arm::HardwareSingleStep(bool enable) +{ + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_arm::UpdateAfterBreakpoint() +{ + lldb::addr_t pc; + + if ((pc = GetPC()) == LLDB_INVALID_ADDRESS) + return false; + + return true; +} + +unsigned +RegisterContextPOSIXProcessMonitor_arm::GetRegisterIndexFromOffset(unsigned offset) +{ + unsigned reg; + for (reg = 0; reg < k_num_registers_arm; reg++) + { + if (GetRegisterInfo()[reg].byte_offset == offset) + break; + } + assert(reg < k_num_registers_arm && "Invalid register offset."); + return reg; +} + +bool +RegisterContextPOSIXProcessMonitor_arm::IsWatchpointHit(uint32_t hw_index) +{ + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_arm::ClearWatchpointHits() +{ + return false; +} + +addr_t +RegisterContextPOSIXProcessMonitor_arm::GetWatchpointAddress(uint32_t hw_index) +{ + return LLDB_INVALID_ADDRESS; +} + +bool +RegisterContextPOSIXProcessMonitor_arm::IsWatchpointVacant(uint32_t hw_index) +{ + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_arm::SetHardwareWatchpointWithIndex(addr_t addr, size_t size, + bool read, bool write, + uint32_t hw_index) +{ + return false; +} + +uint32_t +RegisterContextPOSIXProcessMonitor_arm::NumSupportedHardwareWatchpoints() +{ + return 0; +} + Index: lldb/trunk/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.h =================================================================== --- lldb/trunk/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.h +++ lldb/trunk/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.h @@ -0,0 +1,95 @@ +//===-- RegisterContextPOSIXProcessMonitor_arm64.h --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContextPOSIXProcessMonitor_arm64_H_ +#define liblldb_RegisterContextPOSIXProcessMonitor_arm64_H_ + +#include "Plugins/Process/Utility/RegisterContextPOSIX_arm64.h" + +class RegisterContextPOSIXProcessMonitor_arm64: + public RegisterContextPOSIX_arm64, + public POSIXBreakpointProtocol +{ +public: + RegisterContextPOSIXProcessMonitor_arm64(lldb_private::Thread &thread, + uint32_t concrete_frame_idx, + lldb_private::RegisterInfoInterface *register_info); + +protected: + bool + ReadGPR(); + + bool + ReadFPR(); + + bool + WriteGPR(); + + bool + WriteFPR(); + + // lldb_private::RegisterContext + bool + ReadRegister(const unsigned reg, lldb_private::RegisterValue &value); + + bool + WriteRegister(const unsigned reg, const lldb_private::RegisterValue &value); + + bool + ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value); + + bool + WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value); + + bool + ReadAllRegisterValues(lldb::DataBufferSP &data_sp); + + bool + WriteAllRegisterValues(const lldb::DataBufferSP &data_sp); + + uint32_t + SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, bool write); + + bool + ClearHardwareWatchpoint(uint32_t hw_index); + + bool + HardwareSingleStep(bool enable); + + // POSIXBreakpointProtocol + bool + UpdateAfterBreakpoint(); + + unsigned + GetRegisterIndexFromOffset(unsigned offset); + + bool + IsWatchpointHit(uint32_t hw_index); + + bool + ClearWatchpointHits(); + + lldb::addr_t + GetWatchpointAddress(uint32_t hw_index); + + bool + IsWatchpointVacant(uint32_t hw_index); + + bool + SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, bool read, bool write, uint32_t hw_index); + + uint32_t + NumSupportedHardwareWatchpoints(); + +private: + ProcessMonitor & + GetMonitor(); +}; + +#endif Index: lldb/trunk/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.cpp +++ lldb/trunk/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.cpp @@ -0,0 +1,322 @@ +//===-- RegisterContextPOSIXProcessMonitor_arm64.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/Core/DataBufferHeap.h" +#include "lldb/Core/RegisterValue.h" +#include "lldb/Target/Thread.h" + +#include "Plugins/Process/Utility/RegisterContextPOSIX_arm64.h" +#include "ProcessPOSIX.h" +#include "ProcessMonitor.h" +#include "RegisterContextPOSIXProcessMonitor_arm64.h" + +#define REG_CONTEXT_SIZE (GetGPRSize()) + +using namespace lldb; +using namespace lldb_private; + +RegisterContextPOSIXProcessMonitor_arm64::RegisterContextPOSIXProcessMonitor_arm64(lldb_private::Thread &thread, + uint32_t concrete_frame_idx, + lldb_private::RegisterInfoInterface *register_info) + : RegisterContextPOSIX_arm64(thread, concrete_frame_idx, register_info) +{ +} + +ProcessMonitor & +RegisterContextPOSIXProcessMonitor_arm64::GetMonitor() +{ + lldb::ProcessSP base = CalculateProcess(); + ProcessPOSIX *process = static_cast(base.get()); + return process->GetMonitor(); +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::ReadGPR() +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadGPR(m_thread.GetID(), &m_gpr_arm64, GetGPRSize()); +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::ReadFPR() +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadFPR(m_thread.GetID(), &m_fpr, sizeof m_fpr); +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::WriteGPR() +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.WriteGPR(m_thread.GetID(), &m_gpr_arm64, GetGPRSize()); +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::WriteFPR() +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.WriteFPR(m_thread.GetID(), &m_fpr, sizeof m_fpr); +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::ReadRegister(const unsigned reg, + lldb_private::RegisterValue &value) +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadRegisterValue(m_thread.GetID(), + GetRegisterOffset(reg), + GetRegisterName(reg), + GetRegisterSize(reg), + value); +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::WriteRegister(const unsigned reg, + const lldb_private::RegisterValue &value) +{ + unsigned reg_to_write = reg; + lldb_private::RegisterValue value_to_write = value; + + // Check if this is a subregister of a full register. + const lldb_private::RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); + if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) + { + lldb_private::RegisterValue full_value; + uint32_t full_reg = reg_info->invalidate_regs[0]; + const lldb_private::RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg); + + // Read the full register. + if (ReadRegister(full_reg_info, full_value)) + { + lldb_private::Error error; + lldb::ByteOrder byte_order = GetByteOrder(); + uint8_t dst[lldb_private::RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the full register. + const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info, + dst, + sizeof(dst), + byte_order, + error); + if (error.Success() && dest_size) + { + uint8_t src[lldb_private::RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the source data. + const uint32_t src_size = value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error); + if (error.Success() && src_size && (src_size < dest_size)) + { + // Copy the src bytes to the destination. + ::memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size); + // Set this full register as the value to write. + value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order); + value_to_write.SetType(full_reg_info); + reg_to_write = full_reg; + } + } + } + } + + ProcessMonitor &monitor = GetMonitor(); + return monitor.WriteRegisterValue(m_thread.GetID(), + GetRegisterOffset(reg_to_write), + GetRegisterName(reg_to_write), + value_to_write); +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value) +{ + if (!reg_info) + return false; + + const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + + if (IsFPR(reg)) + { + if (!ReadFPR()) + return false; + } + else + { + uint32_t full_reg = reg; + bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM); + + if (is_subreg) + { + // Read the full aligned 64-bit register. + full_reg = reg_info->invalidate_regs[0]; + } + return ReadRegister(full_reg, value); + } + + // Get pointer to m_fpr variable and set the data from it. + assert (reg_info->byte_offset < sizeof m_fpr); + uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset; + switch (reg_info->byte_size) + { + case 2: + value.SetUInt16(*(uint16_t *)src); + return true; + case 4: + value.SetUInt32(*(uint32_t *)src); + return true; + case 8: + value.SetUInt64(*(uint64_t *)src); + return true; + default: + assert(false && "Unhandled data size."); + return false; + } +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value) +{ + const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + + if (IsGPR(reg)) + return WriteRegister(reg, value); + + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::ReadAllRegisterValues(lldb::DataBufferSP &data_sp) +{ + bool success = false; + data_sp.reset (new lldb_private::DataBufferHeap (REG_CONTEXT_SIZE, 0)); + if (data_sp && ReadGPR () && ReadFPR ()) + { + uint8_t *dst = data_sp->GetBytes(); + success = dst != 0; + + if (success) + { + ::memcpy (dst, &m_gpr_arm64, GetGPRSize()); + dst += GetGPRSize(); + ::memcpy (dst, &m_fpr, sizeof m_fpr); + } + } + return success; +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) +{ + bool success = false; + if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) + { + uint8_t *src = data_sp->GetBytes(); + if (src) + { + ::memcpy (&m_gpr_arm64, src, GetGPRSize()); + if (WriteGPR()) { + src += GetGPRSize(); + ::memcpy (&m_fpr, src, sizeof m_fpr); + success = WriteFPR(); + } + } + } + return success; +} + +uint32_t +RegisterContextPOSIXProcessMonitor_arm64::SetHardwareWatchpoint(lldb::addr_t addr, size_t size, + bool read, bool write) +{ + const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); + uint32_t hw_index; + + for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index) + { + if (IsWatchpointVacant(hw_index)) + return SetHardwareWatchpointWithIndex(addr, size, + read, write, + hw_index); + } + + return LLDB_INVALID_INDEX32; +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::ClearHardwareWatchpoint(uint32_t hw_index) +{ + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::HardwareSingleStep(bool enable) +{ + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::UpdateAfterBreakpoint() +{ + // PC points one byte past the int3 responsible for the breakpoint. + lldb::addr_t pc; + + if ((pc = GetPC()) == LLDB_INVALID_ADDRESS) + return false; + + SetPC(pc - 1); + return true; +} + +unsigned +RegisterContextPOSIXProcessMonitor_arm64::GetRegisterIndexFromOffset(unsigned offset) +{ + unsigned reg; + for (reg = 0; reg < k_num_registers_arm64; reg++) + { + if (GetRegisterInfo()[reg].byte_offset == offset) + break; + } + assert(reg < k_num_registers_arm64 && "Invalid register offset."); + return reg; +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::IsWatchpointHit(uint32_t hw_index) +{ + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::ClearWatchpointHits() +{ + return false; +} + +lldb::addr_t +RegisterContextPOSIXProcessMonitor_arm64::GetWatchpointAddress(uint32_t hw_index) +{ + return LLDB_INVALID_ADDRESS; +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::IsWatchpointVacant(uint32_t hw_index) +{ + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, + bool read, bool write, + uint32_t hw_index) +{ + return false; +} + +uint32_t +RegisterContextPOSIXProcessMonitor_arm64::NumSupportedHardwareWatchpoints() +{ + return 0; +} Index: lldb/trunk/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.h =================================================================== --- lldb/trunk/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.h +++ lldb/trunk/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.h @@ -0,0 +1,95 @@ +//===-- RegisterContextPOSIXProcessMonitor_mips64.h -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContextPOSIXProcessMonitor_mips64_H_ +#define liblldb_RegisterContextPOSIXProcessMonitor_mips64_H_ + +#include "Plugins/Process/Utility/RegisterContextPOSIX_mips64.h" + +class RegisterContextPOSIXProcessMonitor_mips64: + public RegisterContextPOSIX_mips64, + public POSIXBreakpointProtocol +{ +public: + RegisterContextPOSIXProcessMonitor_mips64(lldb_private::Thread &thread, + uint32_t concrete_frame_idx, + lldb_private::RegisterInfoInterface *register_info); + +protected: + bool + ReadGPR(); + + bool + ReadFPR(); + + bool + WriteGPR(); + + bool + WriteFPR(); + + // lldb_private::RegisterContext + bool + ReadRegister(const unsigned reg, lldb_private::RegisterValue &value); + + bool + WriteRegister(const unsigned reg, const lldb_private::RegisterValue &value); + + bool + ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value); + + bool + WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value); + + bool + ReadAllRegisterValues(lldb::DataBufferSP &data_sp); + + bool + WriteAllRegisterValues(const lldb::DataBufferSP &data_sp); + + uint32_t + SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, bool write); + + bool + ClearHardwareWatchpoint(uint32_t hw_index); + + bool + HardwareSingleStep(bool enable); + + // POSIXBreakpointProtocol + bool + UpdateAfterBreakpoint(); + + unsigned + GetRegisterIndexFromOffset(unsigned offset); + + bool + IsWatchpointHit(uint32_t hw_index); + + bool + ClearWatchpointHits(); + + lldb::addr_t + GetWatchpointAddress(uint32_t hw_index); + + bool + IsWatchpointVacant(uint32_t hw_index); + + bool + SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, bool read, bool write, uint32_t hw_index); + + uint32_t + NumSupportedHardwareWatchpoints(); + +private: + ProcessMonitor & + GetMonitor(); +}; + +#endif Index: lldb/trunk/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.cpp +++ lldb/trunk/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.cpp @@ -0,0 +1,318 @@ +//===-- RegisterContextPOSIXProcessMonitor_mips64.h ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// + +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/RegisterValue.h" +#include "lldb/Target/Thread.h" + +#include "Plugins/Process/Utility/RegisterContextPOSIX_mips64.h" +#include "ProcessPOSIX.h" +#include "ProcessMonitor.h" +#include "RegisterContextPOSIXProcessMonitor_mips64.h" + +using namespace lldb_private; +using namespace lldb; + +#define REG_CONTEXT_SIZE (GetGPRSize()) + +RegisterContextPOSIXProcessMonitor_mips64::RegisterContextPOSIXProcessMonitor_mips64(Thread &thread, + uint32_t concrete_frame_idx, + lldb_private::RegisterInfoInterface *register_info) + : RegisterContextPOSIX_mips64(thread, concrete_frame_idx, register_info) +{ +} + +ProcessMonitor & +RegisterContextPOSIXProcessMonitor_mips64::GetMonitor() +{ + ProcessSP base = CalculateProcess(); + ProcessPOSIX *process = static_cast(base.get()); + return process->GetMonitor(); +} + +bool +RegisterContextPOSIXProcessMonitor_mips64::ReadGPR() +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadGPR(m_thread.GetID(), &m_gpr_mips64, GetGPRSize()); +} + +bool +RegisterContextPOSIXProcessMonitor_mips64::ReadFPR() +{ + // XXX not yet implemented + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_mips64::WriteGPR() +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.WriteGPR(m_thread.GetID(), &m_gpr_mips64, GetGPRSize()); +} + +bool +RegisterContextPOSIXProcessMonitor_mips64::WriteFPR() +{ + // XXX not yet implemented + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_mips64::ReadRegister(const unsigned reg, + RegisterValue &value) +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadRegisterValue(m_thread.GetID(), + GetRegisterOffset(reg), + GetRegisterName(reg), + GetRegisterSize(reg), + value); +} + +bool +RegisterContextPOSIXProcessMonitor_mips64::WriteRegister(const unsigned reg, + const RegisterValue &value) +{ + unsigned reg_to_write = reg; + RegisterValue value_to_write = value; + + // Check if this is a subregister of a full register. + const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); + if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) + { + RegisterValue full_value; + uint32_t full_reg = reg_info->invalidate_regs[0]; + const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg); + + // Read the full register. + if (ReadRegister(full_reg_info, full_value)) + { + Error error; + ByteOrder byte_order = GetByteOrder(); + uint8_t dst[RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the full register. + const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info, + dst, + sizeof(dst), + byte_order, + error); + if (error.Success() && dest_size) + { + uint8_t src[RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the source data. + const uint32_t src_size = value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error); + if (error.Success() && src_size && (src_size < dest_size)) + { + // Copy the src bytes to the destination. + memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size); + // Set this full register as the value to write. + value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order); + value_to_write.SetType(full_reg_info); + reg_to_write = full_reg; + } + } + } + } + + ProcessMonitor &monitor = GetMonitor(); + return monitor.WriteRegisterValue(m_thread.GetID(), + GetRegisterOffset(reg_to_write), + GetRegisterName(reg_to_write), + value_to_write); +} + +bool +RegisterContextPOSIXProcessMonitor_mips64::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value) +{ + if (!reg_info) + return false; + + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + + if (IsFPR(reg)) + { + if (!ReadFPR()) + return false; + } + else + { + uint32_t full_reg = reg; + bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM); + + if (is_subreg) + { + // Read the full aligned 64-bit register. + full_reg = reg_info->invalidate_regs[0]; + } + + bool success = ReadRegister(full_reg, value); + + if (success) + { + // If our read was not aligned (for ah,bh,ch,dh), shift our returned value one byte to the right. + if (is_subreg && (reg_info->byte_offset & 0x1)) + value.SetUInt64(value.GetAsUInt64() >> 8); + + // If our return byte size was greater than the return value reg size, then + // use the type specified by reg_info rather than the uint64_t default + if (value.GetByteSize() > reg_info->byte_size) + value.SetType(reg_info); + } + return success; + } + + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_mips64::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value) +{ + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + + if (IsGPR(reg)) + return WriteRegister(reg, value); + + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_mips64::ReadAllRegisterValues(DataBufferSP &data_sp) +{ + bool success = false; + data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0)); + if (data_sp && ReadGPR () && ReadFPR ()) + { + uint8_t *dst = data_sp->GetBytes(); + success = dst != 0; + + if (success) + { + ::memcpy (dst, &m_gpr_mips64, GetGPRSize()); + } + } + return success; +} + +bool +RegisterContextPOSIXProcessMonitor_mips64::WriteAllRegisterValues(const DataBufferSP &data_sp) +{ + bool success = false; + if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) + { + uint8_t *src = data_sp->GetBytes(); + if (src) + { + ::memcpy (&m_gpr_mips64, src, GetGPRSize()); + + if (WriteGPR()) + { + src += GetGPRSize(); + } + } + } + return success; +} + +uint32_t +RegisterContextPOSIXProcessMonitor_mips64::SetHardwareWatchpoint(addr_t addr, size_t size, + bool read, bool write) +{ + const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); + uint32_t hw_index; + + for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index) + { + if (IsWatchpointVacant(hw_index)) + return SetHardwareWatchpointWithIndex(addr, size, + read, write, + hw_index); + } + + return LLDB_INVALID_INDEX32; +} + +bool +RegisterContextPOSIXProcessMonitor_mips64::ClearHardwareWatchpoint(uint32_t hw_index) +{ + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_mips64::HardwareSingleStep(bool enable) +{ + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_mips64::UpdateAfterBreakpoint() +{ + // PC points one byte past the int3 responsible for the breakpoint. + lldb::addr_t pc; + + if ((pc = GetPC()) == LLDB_INVALID_ADDRESS) + return false; + + SetPC(pc - 1); + return true; +} + +unsigned +RegisterContextPOSIXProcessMonitor_mips64::GetRegisterIndexFromOffset(unsigned offset) +{ + unsigned reg; + for (reg = 0; reg < k_num_registers_mips64; reg++) + { + if (GetRegisterInfo()[reg].byte_offset == offset) + break; + } + assert(reg < k_num_registers_mips64 && "Invalid register offset."); + return reg; +} + +bool +RegisterContextPOSIXProcessMonitor_mips64::IsWatchpointHit(uint32_t hw_index) +{ + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_mips64::ClearWatchpointHits() +{ + return false; +} + +addr_t +RegisterContextPOSIXProcessMonitor_mips64::GetWatchpointAddress(uint32_t hw_index) +{ + return LLDB_INVALID_ADDRESS; +} + +bool +RegisterContextPOSIXProcessMonitor_mips64::IsWatchpointVacant(uint32_t hw_index) +{ + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_mips64::SetHardwareWatchpointWithIndex(addr_t addr, size_t size, + bool read, bool write, + uint32_t hw_index) +{ + return false; +} + +uint32_t +RegisterContextPOSIXProcessMonitor_mips64::NumSupportedHardwareWatchpoints() +{ + return 0; +} + Index: lldb/trunk/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.h =================================================================== --- lldb/trunk/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.h +++ lldb/trunk/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.h @@ -0,0 +1,104 @@ +//===-- RegisterContextPOSIXProcessMonitor_powerpc.h -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContextPOSIXProcessMonitor_powerpc_H_ +#define liblldb_RegisterContextPOSIXProcessMonitor_powerpc_H_ + +#include "Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h" + +class RegisterContextPOSIXProcessMonitor_powerpc: + public RegisterContextPOSIX_powerpc, + public POSIXBreakpointProtocol +{ +public: + RegisterContextPOSIXProcessMonitor_powerpc(lldb_private::Thread &thread, + uint32_t concrete_frame_idx, + lldb_private::RegisterInfoInterface *register_info); + +protected: + bool + IsVMX(); + + bool + ReadGPR(); + + bool + ReadFPR(); + + bool + ReadVMX(); + + bool + WriteGPR(); + + bool + WriteFPR(); + + bool + WriteVMX(); + + // lldb_private::RegisterContext + bool + ReadRegister(const unsigned reg, lldb_private::RegisterValue &value); + + bool + WriteRegister(const unsigned reg, const lldb_private::RegisterValue &value); + + bool + ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value); + + bool + WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value); + + bool + ReadAllRegisterValues(lldb::DataBufferSP &data_sp); + + bool + WriteAllRegisterValues(const lldb::DataBufferSP &data_sp); + + uint32_t + SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, bool write); + + bool + ClearHardwareWatchpoint(uint32_t hw_index); + + bool + HardwareSingleStep(bool enable); + + // POSIXBreakpointProtocol + bool + UpdateAfterBreakpoint(); + + unsigned + GetRegisterIndexFromOffset(unsigned offset); + + bool + IsWatchpointHit(uint32_t hw_index); + + bool + ClearWatchpointHits(); + + lldb::addr_t + GetWatchpointAddress(uint32_t hw_index); + + bool + IsWatchpointVacant(uint32_t hw_index); + + bool + SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, bool read, bool write, uint32_t hw_index); + + uint32_t + NumSupportedHardwareWatchpoints(); + +private: + ProcessMonitor & + GetMonitor(); +}; + +#endif Index: lldb/trunk/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.cpp +++ lldb/trunk/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.cpp @@ -0,0 +1,337 @@ +//===-- RegisterContextPOSIXProcessMonitor_powerpc.h ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// + +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/RegisterValue.h" +#include "lldb/Target/Thread.h" + +#include "RegisterContextPOSIX_powerpc.h" +#include "ProcessPOSIX.h" +#include "RegisterContextPOSIXProcessMonitor_powerpc.h" +#include "ProcessMonitor.h" + +using namespace lldb_private; +using namespace lldb; + +#define REG_CONTEXT_SIZE (GetGPRSize()) + +RegisterContextPOSIXProcessMonitor_powerpc::RegisterContextPOSIXProcessMonitor_powerpc(Thread &thread, + uint32_t concrete_frame_idx, + lldb_private::RegisterInfoInterface *register_info) + : RegisterContextPOSIX_powerpc(thread, concrete_frame_idx, register_info) +{ +} + +ProcessMonitor & +RegisterContextPOSIXProcessMonitor_powerpc::GetMonitor() +{ + ProcessSP base = CalculateProcess(); + ProcessPOSIX *process = static_cast(base.get()); + return process->GetMonitor(); +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::ReadGPR() +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadGPR(m_thread.GetID(), &m_gpr_powerpc, GetGPRSize()); +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::ReadFPR() +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadFPR(m_thread.GetID(), &m_fpr_powerpc, sizeof(m_fpr_powerpc)); +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::ReadVMX() +{ + // XXX: Need a way to read/write process VMX registers with ptrace. + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::WriteGPR() +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.WriteGPR(m_thread.GetID(), &m_gpr_powerpc, GetGPRSize()); +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::WriteFPR() +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.WriteFPR(m_thread.GetID(), &m_fpr_powerpc, sizeof(m_fpr_powerpc)); +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::WriteVMX() +{ + // XXX: Need a way to read/write process VMX registers with ptrace. + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::ReadRegister(const unsigned reg, + RegisterValue &value) +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadRegisterValue(m_thread.GetID(), + GetRegisterOffset(reg), + GetRegisterName(reg), + GetRegisterSize(reg), + value); +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::WriteRegister(const unsigned reg, + const RegisterValue &value) +{ + unsigned reg_to_write = reg; + RegisterValue value_to_write = value; + + // Check if this is a subregister of a full register. + const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); + if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) + { + RegisterValue full_value; + uint32_t full_reg = reg_info->invalidate_regs[0]; + const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg); + + // Read the full register. + if (ReadRegister(full_reg_info, full_value)) + { + Error error; + ByteOrder byte_order = GetByteOrder(); + uint8_t dst[RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the full register. + const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info, + dst, + sizeof(dst), + byte_order, + error); + if (error.Success() && dest_size) + { + uint8_t src[RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the source data. + const uint32_t src_size = value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error); + if (error.Success() && src_size && (src_size < dest_size)) + { + // Copy the src bytes to the destination. + memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size); + // Set this full register as the value to write. + value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order); + value_to_write.SetType(full_reg_info); + reg_to_write = full_reg; + } + } + } + } + + ProcessMonitor &monitor = GetMonitor(); + // Account for the fact that 32-bit targets on powerpc64 really use 64-bit + // registers in ptrace, but expose here 32-bit registers with a higher + // offset. + uint64_t offset = GetRegisterOffset(reg_to_write); + offset &= ~(sizeof(uintptr_t) - 1); + return monitor.WriteRegisterValue(m_thread.GetID(), + offset, + GetRegisterName(reg_to_write), + value_to_write); +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value) +{ + if (!reg_info) + return false; + + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + + if (IsFPR(reg)) + { + if (!ReadFPR()) + return false; + uint8_t *src = (uint8_t *)&m_fpr_powerpc + reg_info->byte_offset; + value.SetUInt64(*(uint64_t*)src); + } + else if (IsGPR(reg)) + { + bool success = ReadRegister(reg, value); + + if (success) + { + // If our return byte size was greater than the return value reg size, then + // use the type specified by reg_info rather than the uint64_t default + if (value.GetByteSize() > reg_info->byte_size) + value.SetType(reg_info); + } + return success; + } + + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value) +{ + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + + if (IsGPR(reg)) + { + return WriteRegister(reg, value); + } + else if (IsFPR(reg)) + { + assert (reg_info->byte_offset < sizeof(m_fpr_powerpc)); + uint8_t *dst = (uint8_t *)&m_fpr_powerpc + reg_info->byte_offset; + *(uint64_t *)dst = value.GetAsUInt64(); + return WriteFPR(); + } + + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::ReadAllRegisterValues(DataBufferSP &data_sp) +{ + bool success = false; + data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0)); + if (data_sp && ReadGPR () && ReadFPR ()) + { + uint8_t *dst = data_sp->GetBytes(); + success = dst != 0; + + if (success) + { + ::memcpy (dst, &m_gpr_powerpc, GetGPRSize()); + dst += GetGPRSize(); + } + } + return success; +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::WriteAllRegisterValues(const DataBufferSP &data_sp) +{ + bool success = false; + if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) + { + uint8_t *src = data_sp->GetBytes(); + if (src) + { + ::memcpy (&m_gpr_powerpc, src, GetGPRSize()); + + if (WriteGPR()) + { + src += GetGPRSize(); + ::memcpy (&m_fpr_powerpc, src, sizeof(m_fpr_powerpc)); + + success = WriteFPR(); + } + } + } + return success; +} + +uint32_t +RegisterContextPOSIXProcessMonitor_powerpc::SetHardwareWatchpoint(addr_t addr, size_t size, + bool read, bool write) +{ + const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); + uint32_t hw_index; + + for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index) + { + if (IsWatchpointVacant(hw_index)) + return SetHardwareWatchpointWithIndex(addr, size, + read, write, + hw_index); + } + + return LLDB_INVALID_INDEX32; +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::ClearHardwareWatchpoint(uint32_t hw_index) +{ + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::HardwareSingleStep(bool enable) +{ + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::UpdateAfterBreakpoint() +{ + lldb::addr_t pc; + + if ((pc = GetPC()) == LLDB_INVALID_ADDRESS) + return false; + + return true; +} + +unsigned +RegisterContextPOSIXProcessMonitor_powerpc::GetRegisterIndexFromOffset(unsigned offset) +{ + unsigned reg; + for (reg = 0; reg < k_num_registers_powerpc; reg++) + { + if (GetRegisterInfo()[reg].byte_offset == offset) + break; + } + assert(reg < k_num_registers_powerpc && "Invalid register offset."); + return reg; +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::IsWatchpointHit(uint32_t hw_index) +{ + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::ClearWatchpointHits() +{ + return false; +} + +addr_t +RegisterContextPOSIXProcessMonitor_powerpc::GetWatchpointAddress(uint32_t hw_index) +{ + return LLDB_INVALID_ADDRESS; +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::IsWatchpointVacant(uint32_t hw_index) +{ + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::SetHardwareWatchpointWithIndex(addr_t addr, size_t size, + bool read, bool write, + uint32_t hw_index) +{ + return false; +} + +uint32_t +RegisterContextPOSIXProcessMonitor_powerpc::NumSupportedHardwareWatchpoints() +{ + return 0; +} + Index: lldb/trunk/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.h =================================================================== --- lldb/trunk/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.h +++ lldb/trunk/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.h @@ -0,0 +1,95 @@ +//===-- RegisterContextPOSIXProcessMonitor_x86.h ----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContextPOSIXProcessMonitor_x86_H_ +#define liblldb_RegisterContextPOSIXProcessMonitor_x86_H_ + +#include "Plugins/Process/Utility/RegisterContextPOSIX_x86.h" + +class RegisterContextPOSIXProcessMonitor_x86_64: + public RegisterContextPOSIX_x86, + public POSIXBreakpointProtocol +{ +public: + RegisterContextPOSIXProcessMonitor_x86_64(lldb_private::Thread &thread, + uint32_t concrete_frame_idx, + lldb_private::RegisterInfoInterface *register_info); + +protected: + bool + ReadGPR(); + + bool + ReadFPR(); + + bool + WriteGPR(); + + bool + WriteFPR(); + + // lldb_private::RegisterContext + bool + ReadRegister(const unsigned reg, lldb_private::RegisterValue &value); + + bool + WriteRegister(const unsigned reg, const lldb_private::RegisterValue &value); + + bool + ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value); + + bool + WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value); + + bool + ReadAllRegisterValues(lldb::DataBufferSP &data_sp); + + bool + WriteAllRegisterValues(const lldb::DataBufferSP &data_sp); + + uint32_t + SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, bool write); + + bool + ClearHardwareWatchpoint(uint32_t hw_index); + + bool + HardwareSingleStep(bool enable); + + // POSIXBreakpointProtocol + bool + UpdateAfterBreakpoint(); + + unsigned + GetRegisterIndexFromOffset(unsigned offset); + + bool + IsWatchpointHit(uint32_t hw_index); + + bool + ClearWatchpointHits(); + + lldb::addr_t + GetWatchpointAddress(uint32_t hw_index); + + bool + IsWatchpointVacant(uint32_t hw_index); + + bool + SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, bool read, bool write, uint32_t hw_index); + + uint32_t + NumSupportedHardwareWatchpoints(); + +private: + ProcessMonitor & + GetMonitor(); +}; + +#endif Index: lldb/trunk/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.cpp +++ lldb/trunk/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.cpp @@ -0,0 +1,650 @@ +//===-- RegisterContextPOSIXProcessMonitor_x86.h ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// + +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/RegisterValue.h" +#include "lldb/Target/Thread.h" + +#include "Plugins/Process/FreeBSD/ProcessPOSIX.h" +#include "RegisterContextPOSIXProcessMonitor_x86.h" +#include "Plugins/Process/FreeBSD/ProcessMonitor.h" + +using namespace lldb_private; +using namespace lldb; + +// Support ptrace extensions even when compiled without required kernel support +#ifndef NT_X86_XSTATE + #define NT_X86_XSTATE 0x202 +#endif + +#define REG_CONTEXT_SIZE (GetGPRSize() + sizeof(FPR)) + +static uint32_t +size_and_rw_bits(size_t size, bool read, bool write) +{ + uint32_t rw; + + if (read) + rw = 0x3; // READ or READ/WRITE + else if (write) + rw = 0x1; // WRITE + else + assert(0 && "read and write cannot both be false"); + + switch (size) + { + case 1: + return rw; + case 2: + return (0x1 << 2) | rw; + case 4: + return (0x3 << 2) | rw; + case 8: + return (0x2 << 2) | rw; + default: + assert(0 && "invalid size, must be one of 1, 2, 4, or 8"); + return 0; // Unreachable. Just to silence compiler. + } +} + +RegisterContextPOSIXProcessMonitor_x86_64::RegisterContextPOSIXProcessMonitor_x86_64(Thread &thread, + uint32_t concrete_frame_idx, + lldb_private::RegisterInfoInterface *register_info) + : RegisterContextPOSIX_x86(thread, concrete_frame_idx, register_info) +{ +} + +ProcessMonitor & +RegisterContextPOSIXProcessMonitor_x86_64::GetMonitor() +{ + ProcessSP base = CalculateProcess(); + ProcessPOSIX *process = static_cast(base.get()); + return process->GetMonitor(); +} + +bool +RegisterContextPOSIXProcessMonitor_x86_64::ReadGPR() +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadGPR(m_thread.GetID(), &m_gpr_x86_64, GetGPRSize()); +} + +bool +RegisterContextPOSIXProcessMonitor_x86_64::ReadFPR() +{ + ProcessMonitor &monitor = GetMonitor(); + if (GetFPRType() == eFXSAVE) + return monitor.ReadFPR(m_thread.GetID(), &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave)); + + if (GetFPRType() == eXSAVE) + return monitor.ReadRegisterSet(m_thread.GetID(), &m_iovec, sizeof(m_fpr.xstate.xsave), NT_X86_XSTATE); + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_x86_64::WriteGPR() +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.WriteGPR(m_thread.GetID(), &m_gpr_x86_64, GetGPRSize()); +} + +bool +RegisterContextPOSIXProcessMonitor_x86_64::WriteFPR() +{ + ProcessMonitor &monitor = GetMonitor(); + if (GetFPRType() == eFXSAVE) + return monitor.WriteFPR(m_thread.GetID(), &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave)); + + if (GetFPRType() == eXSAVE) + return monitor.WriteRegisterSet(m_thread.GetID(), &m_iovec, sizeof(m_fpr.xstate.xsave), NT_X86_XSTATE); + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_x86_64::ReadRegister(const unsigned reg, + RegisterValue &value) +{ + ProcessMonitor &monitor = GetMonitor(); + +#if defined(__FreeBSD__) + if (reg >= m_reg_info.first_dr) + return monitor.ReadDebugRegisterValue(m_thread.GetID(), + GetRegisterOffset(reg), + GetRegisterName(reg), + GetRegisterSize(reg), + value); +#endif + return monitor.ReadRegisterValue(m_thread.GetID(), + GetRegisterOffset(reg), + GetRegisterName(reg), + GetRegisterSize(reg), + value); +} + +bool +RegisterContextPOSIXProcessMonitor_x86_64::WriteRegister(const unsigned reg, + const RegisterValue &value) +{ + unsigned reg_to_write = reg; + RegisterValue value_to_write = value; + + // Check if this is a subregister of a full register. + const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); + if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) + { + RegisterValue full_value; + uint32_t full_reg = reg_info->invalidate_regs[0]; + const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg); + + // Read the full register. + if (ReadRegister(full_reg_info, full_value)) + { + Error error; + ByteOrder byte_order = GetByteOrder(); + uint8_t dst[RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the full register. + const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info, + dst, + sizeof(dst), + byte_order, + error); + if (error.Success() && dest_size) + { + uint8_t src[RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the source data. + const uint32_t src_size = value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error); + if (error.Success() && src_size && (src_size < dest_size)) + { + // Copy the src bytes to the destination. + memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size); + // Set this full register as the value to write. + value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order); + value_to_write.SetType(full_reg_info); + reg_to_write = full_reg; + } + } + } + } + + ProcessMonitor &monitor = GetMonitor(); +#if defined(__FreeBSD__) + if (reg >= m_reg_info.first_dr) + return monitor.WriteDebugRegisterValue(m_thread.GetID(), + GetRegisterOffset(reg_to_write), + GetRegisterName(reg_to_write), + value_to_write); +#endif + return monitor.WriteRegisterValue(m_thread.GetID(), + GetRegisterOffset(reg_to_write), + GetRegisterName(reg_to_write), + value_to_write); +} + +bool +RegisterContextPOSIXProcessMonitor_x86_64::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value) +{ + if (!reg_info) + return false; + + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + + if (IsFPR(reg, GetFPRType())) + { + if (!ReadFPR()) + return false; + } + else + { + uint32_t full_reg = reg; + bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM); + + if (is_subreg) + { + // Read the full aligned 64-bit register. + full_reg = reg_info->invalidate_regs[0]; + } + + bool success = ReadRegister(full_reg, value); + + if (success) + { + // If our read was not aligned (for ah,bh,ch,dh), shift our returned value one byte to the right. + if (is_subreg && (reg_info->byte_offset & 0x1)) + value.SetUInt64(value.GetAsUInt64() >> 8); + + // If our return byte size was greater than the return value reg size, then + // use the type specified by reg_info rather than the uint64_t default + if (value.GetByteSize() > reg_info->byte_size) + value.SetType(reg_info); + } + return success; + } + + if (reg_info->encoding == eEncodingVector) + { + ByteOrder byte_order = GetByteOrder(); + + if (byte_order != ByteOrder::eByteOrderInvalid) + { + if (reg >= m_reg_info.first_st && reg <= m_reg_info.last_st) + value.SetBytes(m_fpr.xstate.fxsave.stmm[reg - m_reg_info.first_st].bytes, reg_info->byte_size, byte_order); + if (reg >= m_reg_info.first_mm && reg <= m_reg_info.last_mm) + value.SetBytes(m_fpr.xstate.fxsave.stmm[reg - m_reg_info.first_mm].bytes, reg_info->byte_size, byte_order); + if (reg >= m_reg_info.first_xmm && reg <= m_reg_info.last_xmm) + value.SetBytes(m_fpr.xstate.fxsave.xmm[reg - m_reg_info.first_xmm].bytes, reg_info->byte_size, byte_order); + if (reg >= m_reg_info.first_ymm && reg <= m_reg_info.last_ymm) + { + // Concatenate ymm using the register halves in xmm.bytes and ymmh.bytes + if (GetFPRType() == eXSAVE && CopyXSTATEtoYMM(reg, byte_order)) + value.SetBytes(m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes, reg_info->byte_size, byte_order); + else + return false; + } + return value.GetType() == RegisterValue::eTypeBytes; + } + return false; + } + + // Get pointer to m_fpr.xstate.fxsave variable and set the data from it. + assert (reg_info->byte_offset < sizeof(m_fpr)); + uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset; + switch (reg_info->byte_size) + { + case 2: + value.SetUInt16(*(uint16_t *)src); + return true; + case 4: + value.SetUInt32(*(uint32_t *)src); + return true; + case 8: + value.SetUInt64(*(uint64_t *)src); + return true; + default: + assert(false && "Unhandled data size."); + return false; + } +} + +bool +RegisterContextPOSIXProcessMonitor_x86_64::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value) +{ + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + + if (IsGPR(reg)) + return WriteRegister(reg, value); + + if (IsFPR(reg, GetFPRType())) + { + if (reg_info->encoding == eEncodingVector) + { + if (reg >= m_reg_info.first_st && reg <= m_reg_info.last_st) + ::memcpy (m_fpr.xstate.fxsave.stmm[reg - m_reg_info.first_st].bytes, value.GetBytes(), value.GetByteSize()); + + if (reg >= m_reg_info.first_mm && reg <= m_reg_info.last_mm) + ::memcpy (m_fpr.xstate.fxsave.stmm[reg - m_reg_info.first_mm].bytes, value.GetBytes(), value.GetByteSize()); + + if (reg >= m_reg_info.first_xmm && reg <= m_reg_info.last_xmm) + ::memcpy (m_fpr.xstate.fxsave.xmm[reg - m_reg_info.first_xmm].bytes, value.GetBytes(), value.GetByteSize()); + + if (reg >= m_reg_info.first_ymm && reg <= m_reg_info.last_ymm) + { + if (GetFPRType() != eXSAVE) + return false; // the target processor does not support AVX + + // Store ymm register content, and split into the register halves in xmm.bytes and ymmh.bytes + ::memcpy (m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes, value.GetBytes(), value.GetByteSize()); + if (false == CopyYMMtoXSTATE(reg, GetByteOrder())) + return false; + } + } + else + { + // Get pointer to m_fpr.xstate.fxsave variable and set the data to it. + assert (reg_info->byte_offset < sizeof(m_fpr)); + uint8_t *dst = (uint8_t *)&m_fpr + reg_info->byte_offset; + switch (reg_info->byte_size) + { + case 2: + *(uint16_t *)dst = value.GetAsUInt16(); + break; + case 4: + *(uint32_t *)dst = value.GetAsUInt32(); + break; + case 8: + *(uint64_t *)dst = value.GetAsUInt64(); + break; + default: + assert(false && "Unhandled data size."); + return false; + } + } + + if (WriteFPR()) + { + if (IsAVX(reg)) + return CopyYMMtoXSTATE(reg, GetByteOrder()); + return true; + } + } + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_x86_64::ReadAllRegisterValues(DataBufferSP &data_sp) +{ + bool success = false; + data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0)); + if (data_sp && ReadGPR () && ReadFPR ()) + { + uint8_t *dst = data_sp->GetBytes(); + success = dst != 0; + + if (success) + { + ::memcpy (dst, &m_gpr_x86_64, GetGPRSize()); + dst += GetGPRSize(); + if (GetFPRType() == eFXSAVE) + ::memcpy (dst, &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave)); + } + + if (GetFPRType() == eXSAVE) + { + ByteOrder byte_order = GetByteOrder(); + + // Assemble the YMM register content from the register halves. + for (uint32_t reg = m_reg_info.first_ymm; success && reg <= m_reg_info.last_ymm; ++reg) + success = CopyXSTATEtoYMM(reg, byte_order); + + if (success) + { + // Copy the extended register state including the assembled ymm registers. + ::memcpy (dst, &m_fpr, sizeof(m_fpr)); + } + } + } + return success; +} + +bool +RegisterContextPOSIXProcessMonitor_x86_64::WriteAllRegisterValues(const DataBufferSP &data_sp) +{ + bool success = false; + if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) + { + uint8_t *src = data_sp->GetBytes(); + if (src) + { + ::memcpy (&m_gpr_x86_64, src, GetGPRSize()); + + if (WriteGPR()) + { + src += GetGPRSize(); + if (GetFPRType() == eFXSAVE) + ::memcpy (&m_fpr.xstate.fxsave, src, sizeof(m_fpr.xstate.fxsave)); + if (GetFPRType() == eXSAVE) + ::memcpy (&m_fpr.xstate.xsave, src, sizeof(m_fpr.xstate.xsave)); + + success = WriteFPR(); + if (success) + { + if (GetFPRType() == eXSAVE) + { + ByteOrder byte_order = GetByteOrder(); + + // Parse the YMM register content from the register halves. + for (uint32_t reg = m_reg_info.first_ymm; success && reg <= m_reg_info.last_ymm; ++reg) + success = CopyYMMtoXSTATE(reg, byte_order); + } + } + } + } + } + return success; +} + +uint32_t +RegisterContextPOSIXProcessMonitor_x86_64::SetHardwareWatchpoint(addr_t addr, size_t size, + bool read, bool write) +{ + const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); + uint32_t hw_index; + + for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index) + { + if (IsWatchpointVacant(hw_index)) + return SetHardwareWatchpointWithIndex(addr, size, + read, write, + hw_index); + } + + return LLDB_INVALID_INDEX32; +} + +bool +RegisterContextPOSIXProcessMonitor_x86_64::ClearHardwareWatchpoint(uint32_t hw_index) +{ + if (hw_index < NumSupportedHardwareWatchpoints()) + { + RegisterValue current_dr7_bits; + + if (ReadRegister(m_reg_info.first_dr + 7, current_dr7_bits)) + { + uint64_t new_dr7_bits = current_dr7_bits.GetAsUInt64() & ~(3 << (2*hw_index)); + + if (WriteRegister(m_reg_info.first_dr + 7, RegisterValue(new_dr7_bits))) + return true; + } + } + + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_x86_64::HardwareSingleStep(bool enable) +{ + enum { TRACE_BIT = 0x100 }; + uint64_t rflags; + + if ((rflags = ReadRegisterAsUnsigned(m_reg_info.gpr_flags, -1UL)) == -1UL) + return false; + + if (enable) + { + if (rflags & TRACE_BIT) + return true; + + rflags |= TRACE_BIT; + } + else + { + if (!(rflags & TRACE_BIT)) + return false; + + rflags &= ~TRACE_BIT; + } + + return WriteRegisterFromUnsigned(m_reg_info.gpr_flags, rflags); +} + +bool +RegisterContextPOSIXProcessMonitor_x86_64::UpdateAfterBreakpoint() +{ + // PC points one byte past the int3 responsible for the breakpoint. + lldb::addr_t pc; + + if ((pc = GetPC()) == LLDB_INVALID_ADDRESS) + return false; + + SetPC(pc - 1); + return true; +} + +unsigned +RegisterContextPOSIXProcessMonitor_x86_64::GetRegisterIndexFromOffset(unsigned offset) +{ + unsigned reg; + for (reg = 0; reg < m_reg_info.num_registers; reg++) + { + if (GetRegisterInfo()[reg].byte_offset == offset) + break; + } + assert(reg < m_reg_info.num_registers && "Invalid register offset."); + return reg; +} + +bool +RegisterContextPOSIXProcessMonitor_x86_64::IsWatchpointHit(uint32_t hw_index) +{ + bool is_hit = false; + + if (m_watchpoints_initialized == false) + { + // Reset the debug status and debug control registers + RegisterValue zero_bits = RegisterValue(uint64_t(0)); + if (!WriteRegister(m_reg_info.first_dr + 6, zero_bits) || !WriteRegister(m_reg_info.first_dr + 7, zero_bits)) + assert(false && "Could not initialize watchpoint registers"); + m_watchpoints_initialized = true; + } + + if (hw_index < NumSupportedHardwareWatchpoints()) + { + RegisterValue value; + + if (ReadRegister(m_reg_info.first_dr + 6, value)) + { + uint64_t val = value.GetAsUInt64(); + is_hit = val & (1 << hw_index); + } + } + + return is_hit; +} + +bool +RegisterContextPOSIXProcessMonitor_x86_64::ClearWatchpointHits() +{ + return WriteRegister(m_reg_info.first_dr + 6, RegisterValue((uint64_t)0)); +} + +addr_t +RegisterContextPOSIXProcessMonitor_x86_64::GetWatchpointAddress(uint32_t hw_index) +{ + addr_t wp_monitor_addr = LLDB_INVALID_ADDRESS; + + if (hw_index < NumSupportedHardwareWatchpoints()) + { + if (!IsWatchpointVacant(hw_index)) + { + RegisterValue value; + + if (ReadRegister(m_reg_info.first_dr + hw_index, value)) + wp_monitor_addr = value.GetAsUInt64(); + } + } + + return wp_monitor_addr; +} + +bool +RegisterContextPOSIXProcessMonitor_x86_64::IsWatchpointVacant(uint32_t hw_index) +{ + bool is_vacant = false; + RegisterValue value; + + assert(hw_index < NumSupportedHardwareWatchpoints()); + + if (m_watchpoints_initialized == false) + { + // Reset the debug status and debug control registers + RegisterValue zero_bits = RegisterValue(uint64_t(0)); + if (!WriteRegister(m_reg_info.first_dr + 6, zero_bits) || !WriteRegister(m_reg_info.first_dr + 7, zero_bits)) + assert(false && "Could not initialize watchpoint registers"); + m_watchpoints_initialized = true; + } + + if (ReadRegister(m_reg_info.first_dr + 7, value)) + { + uint64_t val = value.GetAsUInt64(); + is_vacant = (val & (3 << 2*hw_index)) == 0; + } + + return is_vacant; +} + +bool +RegisterContextPOSIXProcessMonitor_x86_64::SetHardwareWatchpointWithIndex(addr_t addr, size_t size, + bool read, bool write, + uint32_t hw_index) +{ + const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); + + if (num_hw_watchpoints == 0 || hw_index >= num_hw_watchpoints) + return false; + + if (!(size == 1 || size == 2 || size == 4 || size == 8)) + return false; + + if (read == false && write == false) + return false; + + if (!IsWatchpointVacant(hw_index)) + return false; + + // Set both dr7 (debug control register) and dri (debug address register). + + // dr7{7-0} encodes the local/global enable bits: + // global enable --. .-- local enable + // | | + // v v + // dr0 -> bits{1-0} + // dr1 -> bits{3-2} + // dr2 -> bits{5-4} + // dr3 -> bits{7-6} + // + // dr7{31-16} encodes the rw/len bits: + // b_x+3, b_x+2, b_x+1, b_x + // where bits{x+1, x} => rw + // 0b00: execute, 0b01: write, 0b11: read-or-write, + // 0b10: io read-or-write (unused) + // and bits{x+3, x+2} => len + // 0b00: 1-byte, 0b01: 2-byte, 0b11: 4-byte, 0b10: 8-byte + // + // dr0 -> bits{19-16} + // dr1 -> bits{23-20} + // dr2 -> bits{27-24} + // dr3 -> bits{31-28} + if (hw_index < num_hw_watchpoints) + { + RegisterValue current_dr7_bits; + + if (ReadRegister(m_reg_info.first_dr + 7, current_dr7_bits)) + { + uint64_t new_dr7_bits = current_dr7_bits.GetAsUInt64() | + (1 << (2*hw_index) | + size_and_rw_bits(size, read, write) << + (16+4*hw_index)); + + if (WriteRegister(m_reg_info.first_dr + hw_index, RegisterValue(addr)) && + WriteRegister(m_reg_info.first_dr + 7, RegisterValue(new_dr7_bits))) + return true; + } + } + + return false; +} + +uint32_t +RegisterContextPOSIXProcessMonitor_x86_64::NumSupportedHardwareWatchpoints() +{ + // Available debug address registers: dr0, dr1, dr2, dr3 + return 4; +} + Index: lldb/trunk/source/Plugins/Process/Linux/CMakeLists.txt =================================================================== --- lldb/trunk/source/Plugins/Process/Linux/CMakeLists.txt +++ lldb/trunk/source/Plugins/Process/Linux/CMakeLists.txt @@ -5,7 +5,6 @@ include_directories(../Utility) add_lldb_library(lldbPluginProcessLinux - LinuxThread.cpp NativeProcessLinux.cpp NativeRegisterContextLinux.cpp NativeRegisterContextLinux_arm.cpp @@ -13,7 +12,5 @@ NativeRegisterContextLinux_x86_64.cpp NativeRegisterContextLinux_mips64.cpp NativeThreadLinux.cpp - ProcessLinux.cpp - ProcessMonitor.cpp ProcFileReader.cpp ) Index: lldb/trunk/source/Plugins/Process/Linux/LinuxThread.h =================================================================== --- lldb/trunk/source/Plugins/Process/Linux/LinuxThread.h +++ lldb/trunk/source/Plugins/Process/Linux/LinuxThread.h @@ -1,44 +0,0 @@ -//===-- LinuxThread.h -------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_LinuxThread_H_ -#define liblldb_LinuxThread_H_ - -// Other libraries and framework includes -#include "Plugins/Process/POSIX/POSIXThread.h" - -namespace lldb_private { -namespace process_linux { - -//------------------------------------------------------------------------------ -// @class LinuxThread -// @brief Abstraction of a Linux thread. -class LinuxThread : public POSIXThread -{ -public: - - //------------------------------------------------------------------ - // Constructors and destructors - //------------------------------------------------------------------ - LinuxThread(Process &process, lldb::tid_t tid); - - virtual ~LinuxThread(); - - //-------------------------------------------------------------------------- - // LinuxThread internal API. - - // POSIXThread override - void - RefreshStateAfterStop() override; -}; - -} // namespace process_linux -} // namespace lldb_private - -#endif // #ifndef liblldb_LinuxThread_H_ Index: lldb/trunk/source/Plugins/Process/Linux/LinuxThread.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/Linux/LinuxThread.cpp +++ lldb/trunk/source/Plugins/Process/Linux/LinuxThread.cpp @@ -1,43 +0,0 @@ -//===-- LinuxThread.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 "LinuxThread.h" - -using namespace lldb; -using namespace lldb_private; -using namespace lldb_private::process_linux; - -//------------------------------------------------------------------------------ -// Constructors and destructors. - -LinuxThread::LinuxThread(Process &process, lldb::tid_t tid) - : POSIXThread(process, tid) -{ -} - -LinuxThread::~LinuxThread() -{ -} - -//------------------------------------------------------------------------------ -// ProcessInterface protocol. - -void -LinuxThread::RefreshStateAfterStop() -{ - // Invalidate the thread names every time we get a stop event on Linux so we - // will re-read the procfs comm virtual file when folks ask for the thread name. - m_thread_name_valid = false; - - POSIXThread::RefreshStateAfterStop(); -} Index: lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.h =================================================================== --- lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.h +++ lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.h @@ -1,110 +0,0 @@ -//===-- ProcessLinux.h ------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_ProcessLinux_H_ -#define liblldb_ProcessLinux_H_ - -// C Includes - -// C++ Includes -#include - -// Other libraries and framework includes -#include "lldb/Target/Process.h" -#include "Plugins/Process/POSIX/ProcessMessage.h" -#include "Plugins/Process/POSIX/ProcessPOSIX.h" - -class ProcessMonitor; - -namespace lldb_private { -namespace process_linux { - -class ProcessLinux : public ProcessPOSIX -{ -public: - //------------------------------------------------------------------ - // Static functions. - //------------------------------------------------------------------ - static lldb::ProcessSP - CreateInstance(Target& target, - Listener &listener, - const FileSpec *); - - static void - Initialize(); - - static void - Terminate(); - - static ConstString - GetPluginNameStatic(); - - static const char * - GetPluginDescriptionStatic(); - - //------------------------------------------------------------------ - // Constructors and destructors - //------------------------------------------------------------------ - ProcessLinux(Target& target, - Listener &listener, - const FileSpec *core_file); - - Error - DoDetach(bool keep_stopped) override; - - bool - DetachRequiresHalt() override { return true; } - - bool - UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_thread_list) override; - - //------------------------------------------------------------------ - // PluginInterface protocol - //------------------------------------------------------------------ - ConstString - GetPluginName() override; - - uint32_t - GetPluginVersion() override; - - virtual void - GetPluginCommandHelp(const char *command, Stream *strm); - - virtual Error - ExecutePluginCommand(Args &command, - Stream *strm); - - virtual Log * - EnablePluginLogging(Stream *strm, - Args &command); - - bool - CanDebug(Target &target, bool plugin_specified_by_name) override; - - //------------------------------------------------------------------ - // ProcessPOSIX overrides - //------------------------------------------------------------------ - void - StopAllThreads(lldb::tid_t stop_tid) override; - - POSIXThread * - CreateNewPOSIXThread(Process &process, lldb::tid_t tid) override; - -private: - - const FileSpec *m_core_file; - - // Flag to avoid recursion when stopping all threads. - bool m_stopping_threads; -}; - -} // namespace process_linux -} // namespace lldb_private - -#endif // liblldb_ProcessLinux_H_ Index: lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.cpp +++ lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.cpp @@ -1,233 +0,0 @@ -//===-- ProcessLinux.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 -#include - -// C++ Includes -#include - -// Other libraries and framework includes -#include "lldb/Core/PluginManager.h" -#include "lldb/Core/State.h" -#include "lldb/Host/Host.h" -#include "lldb/Symbol/ObjectFile.h" -#include "lldb/Target/DynamicLoader.h" -#include "lldb/Target/Target.h" - -#include "ProcessLinux.h" -#include "Plugins/Platform/Linux/PlatformLinux.h" -#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" -#include "Plugins/Process/Utility/InferiorCallPOSIX.h" -#include "Plugins/Process/Utility/LinuxSignals.h" -#include "ProcessMonitor.h" -#include "LinuxThread.h" - -using namespace lldb; -using namespace lldb_private; -using namespace lldb_private::process_linux; - -namespace -{ - UnixSignalsSP& - GetStaticLinuxSignalsSP () - { - static UnixSignalsSP s_unix_signals_sp (new process_linux::LinuxSignals ()); - return s_unix_signals_sp; - } -} - -//------------------------------------------------------------------------------ -// Static functions. - -ProcessSP -ProcessLinux::CreateInstance(Target &target, Listener &listener, const FileSpec *core_file) -{ - return ProcessSP(new ProcessLinux(target, listener, core_file)); -} - -void -ProcessLinux::Initialize() -{ - static std::once_flag g_once_flag; - - std::call_once(g_once_flag, []() { - PluginManager::RegisterPlugin(GetPluginNameStatic(), - GetPluginDescriptionStatic(), - CreateInstance); - ProcessPOSIXLog::Initialize(GetPluginNameStatic()); - }); -} - -//------------------------------------------------------------------------------ -// Constructors and destructors. - -ProcessLinux::ProcessLinux(Target& target, Listener &listener, const FileSpec *core_file) - : ProcessPOSIX(target, listener, GetStaticLinuxSignalsSP ()), m_core_file(core_file), m_stopping_threads(false) -{ -#if 0 - // FIXME: Putting this code in the ctor and saving the byte order in a - // member variable is a hack to avoid const qual issues in GetByteOrder. - ObjectFile *obj_file = GetTarget().GetExecutableModule()->GetObjectFile(); - m_byte_order = obj_file->GetByteOrder(); -#else - // XXX: Will work only for local processes. - m_byte_order = lldb::endian::InlHostByteOrder(); -#endif -} - -void -ProcessLinux::Terminate() -{ -} - -lldb_private::ConstString -ProcessLinux::GetPluginNameStatic() -{ - static ConstString g_name("linux"); - return g_name; -} - -const char * -ProcessLinux::GetPluginDescriptionStatic() -{ - return "Process plugin for Linux"; -} - - -bool -ProcessLinux::UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_thread_list) -{ - new_thread_list = old_thread_list; - return new_thread_list.GetSize(false) > 0; -} - - -//------------------------------------------------------------------------------ -// ProcessInterface protocol. - -lldb_private::ConstString -ProcessLinux::GetPluginName() -{ - return GetPluginNameStatic(); -} - -uint32_t -ProcessLinux::GetPluginVersion() -{ - return 1; -} - -void -ProcessLinux::GetPluginCommandHelp(const char *command, Stream *strm) -{ -} - -Error -ProcessLinux::ExecutePluginCommand(Args &command, Stream *strm) -{ - return Error(1, eErrorTypeGeneric); -} - -Log * -ProcessLinux::EnablePluginLogging(Stream *strm, Args &command) -{ - return NULL; -} - -Error -ProcessLinux::DoDetach(bool keep_stopped) -{ - Error error; - if (keep_stopped) - { - // FIXME: If you want to implement keep_stopped, - // this would be the place to do it. - error.SetErrorString("Detaching with keep_stopped true is not currently supported on Linux."); - return error; - } - - Mutex::Locker lock(m_thread_list.GetMutex()); - - uint32_t thread_count = m_thread_list.GetSize(false); - for (uint32_t i = 0; i < thread_count; ++i) - { - POSIXThread *thread = static_cast( - m_thread_list.GetThreadAtIndex(i, false).get()); - error = m_monitor->Detach(thread->GetID()); - } - - if (error.Success()) - SetPrivateState(eStateDetached); - - return error; -} - - -// ProcessPOSIX override -void -ProcessLinux::StopAllThreads(lldb::tid_t stop_tid) -{ - // If a breakpoint occurs while we're stopping threads, we'll get back - // here, but we don't want to do it again. Only the MonitorChildProcess - // thread calls this function, so we don't need to protect this flag. - if (m_stopping_threads) - return; - m_stopping_threads = true; - - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); - if (log) - log->Printf ("ProcessLinux::%s() stopping all threads", __FUNCTION__); - - // Walk the thread list and stop the other threads. The thread that caused - // the stop should already be marked as stopped before we get here. - Mutex::Locker thread_list_lock(m_thread_list.GetMutex()); - - uint32_t thread_count = m_thread_list.GetSize(false); - for (uint32_t i = 0; i < thread_count; ++i) - { - POSIXThread *thread = static_cast( - m_thread_list.GetThreadAtIndex(i, false).get()); - assert(thread); - lldb::tid_t tid = thread->GetID(); - if (!StateIsStoppedState(thread->GetState(), false)) - m_monitor->StopThread(tid); - } - - m_stopping_threads = false; - - if (log) - log->Printf ("ProcessLinux::%s() finished", __FUNCTION__); -} - -// ProcessPOSIX override -POSIXThread * -ProcessLinux::CreateNewPOSIXThread(lldb_private::Process &process, lldb::tid_t tid) -{ - return new LinuxThread(process, tid); -} - -bool -ProcessLinux::CanDebug(Target &target, bool plugin_specified_by_name) -{ - if (plugin_specified_by_name) - return true; - - /* If core file is specified then let elf-core plugin handle it */ - if (m_core_file) - return false; - - // If we're using llgs for local debugging, we must not say that this process - // is used for debugging. - if (platform_linux::PlatformLinux::UseLlgsForLocalDebugging ()) - return false; - - return ProcessPOSIX::CanDebug(target, plugin_specified_by_name); -} - Index: lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.h =================================================================== --- lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.h +++ lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.h @@ -1,334 +0,0 @@ -//===-- ProcessMonitor.h -------------------------------------- -*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_ProcessMonitor_H_ -#define liblldb_ProcessMonitor_H_ - -// C Includes -#include -#include - -// C++ Includes -// Other libraries and framework includes -#include "lldb/lldb-types.h" -#include "lldb/Host/FileSpec.h" -#include "lldb/Host/HostThread.h" -#include "lldb/Host/Mutex.h" - -namespace lldb_private { - -class Error; -class Module; -class Scalar; - -namespace process_linux { - -class ProcessLinux; - -} // namespace process_linux - -} // namespace lldb_private - -class Operation; - -/// @class ProcessMonitor -/// @brief Manages communication with the inferior (debugee) process. -/// -/// Upon construction, this class prepares and launches an inferior process for -/// debugging. -/// -/// Changes in the inferior process state are propagated to the associated -/// ProcessLinux instance by calling ProcessLinux::SendMessage with the -/// appropriate ProcessMessage events. -/// -/// A purposely minimal set of operations are provided to interrogate and change -/// the inferior process state. -class ProcessMonitor -{ -public: - - /// Launches an inferior process ready for debugging. Forms the - /// implementation of Process::DoLaunch. - ProcessMonitor(ProcessPOSIX *process, - lldb_private::Module *module, - char const *argv[], - char const *envp[], - const lldb_private::FileSpec &stdin_file_spec, - const lldb_private::FileSpec &stdout_file_spec, - const lldb_private::FileSpec &stderr_file_spec, - const lldb_private::FileSpec &working_dir, - const lldb_private::ProcessLaunchInfo &launch_info, - lldb_private::Error &error); - - ProcessMonitor(ProcessPOSIX *process, - lldb::pid_t pid, - lldb_private::Error &error); - - ~ProcessMonitor(); - - enum ResumeSignals - { - eResumeSignalNone = 0 - }; - - /// Provides the process number of debugee. - lldb::pid_t - GetPID() const { return m_pid; } - - /// Returns the process associated with this ProcessMonitor. - lldb_private::process_linux::ProcessLinux & - GetProcess() { return *m_process; } - - /// Returns a file descriptor to the controlling terminal of the inferior - /// process. - /// - /// Reads from this file descriptor yield both the standard output and - /// standard error of this debugee. Even if stderr and stdout were - /// redirected on launch it may still happen that data is available on this - /// descriptor (if the inferior process opens /dev/tty, for example). This descriptor is - /// closed after a call to StopMonitor(). - /// - /// If this monitor was attached to an existing process this method returns - /// -1. - int - GetTerminalFD() const { return m_terminal_fd; } - - /// Reads @p size bytes from address @vm_adder in the inferior process - /// address space. - /// - /// This method is provided to implement Process::DoReadMemory. - size_t - ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, - lldb_private::Error &error); - - /// Writes @p size bytes from address @p vm_adder in the inferior process - /// address space. - /// - /// This method is provided to implement Process::DoWriteMemory. - size_t - WriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size, - lldb_private::Error &error); - - /// Reads the contents from the register identified by the given (architecture - /// dependent) offset. - /// - /// This method is provided for use by RegisterContextLinux derivatives. - bool - ReadRegisterValue(lldb::tid_t tid, unsigned offset, const char *reg_name, - unsigned size, lldb_private::RegisterValue &value); - - /// Writes the given value to the register identified by the given - /// (architecture dependent) offset. - /// - /// This method is provided for use by RegisterContextLinux derivatives. - bool - WriteRegisterValue(lldb::tid_t tid, unsigned offset, const char *reg_name, - const lldb_private::RegisterValue &value); - - /// Reads all general purpose registers into the specified buffer. - bool - ReadGPR(lldb::tid_t tid, void *buf, size_t buf_size); - - /// Reads generic floating point registers into the specified buffer. - bool - ReadFPR(lldb::tid_t tid, void *buf, size_t buf_size); - -#if defined (__arm64__) || defined (__aarch64__) - /// Reads hardware breakpoints and watchpoints capability information. - bool - ReadHardwareDebugInfo (lldb::tid_t tid, unsigned int &watch_count , - unsigned int &break_count); - - /// Write hardware breakpoint/watchpoint control and address registers. - bool - WriteHardwareDebugRegs (lldb::tid_t tid, lldb::addr_t *addr_buf, - uint32_t *cntrl_buf, int type, int count); -#endif - - /// Reads the specified register set into the specified buffer. - /// For instance, the extended floating-point register set. - bool - ReadRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset); - - /// Writes all general purpose registers into the specified buffer. - bool - WriteGPR(lldb::tid_t tid, void *buf, size_t buf_size); - - /// Writes generic floating point registers into the specified buffer. - bool - WriteFPR(lldb::tid_t tid, void *buf, size_t buf_size); - - /// Writes the specified register set into the specified buffer. - /// For instance, the extended floating-point register set. - bool - WriteRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset); - - /// Reads the value of the thread-specific pointer for a given thread ID. - bool - ReadThreadPointer(lldb::tid_t tid, lldb::addr_t &value); - - /// Writes a siginfo_t structure corresponding to the given thread ID to the - /// memory region pointed to by @p siginfo. - bool - GetSignalInfo(lldb::tid_t tid, void *siginfo, int &ptrace_err); - - /// Writes the raw event message code (vis-a-vis PTRACE_GETEVENTMSG) - /// corresponding to the given thread IDto the memory pointed to by @p - /// message. - bool - GetEventMessage(lldb::tid_t tid, unsigned long *message); - - /// Resumes the given thread. If @p signo is anything but - /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread. - bool - Resume(lldb::tid_t tid, uint32_t signo); - - /// Single steps the given thread. If @p signo is anything but - /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread. - bool - SingleStep(lldb::tid_t tid, uint32_t signo); - - /// Terminate the traced process. - bool - Kill(); - - lldb_private::Error - Detach(lldb::tid_t tid); - - /// Stops the monitoring the child process thread. - void - StopMonitor(); - - /// Stops the requested thread and waits for the stop signal. - bool - StopThread(lldb::tid_t tid); - - // Waits for the initial stop message from a new thread. - bool - WaitForInitialTIDStop(lldb::tid_t tid); - -private: - lldb_private::process_linux::ProcessLinux *m_process; - - lldb_private::HostThread m_operation_thread; - lldb_private::HostThread m_monitor_thread; - lldb::pid_t m_pid; - int m_terminal_fd; - - // current operation which must be executed on the priviliged thread - Operation *m_operation; - lldb_private::Mutex m_operation_mutex; - - // semaphores notified when Operation is ready to be processed and when - // the operation is complete. - sem_t m_operation_pending; - sem_t m_operation_done; - - - struct OperationArgs - { - OperationArgs(ProcessMonitor *monitor); - - ~OperationArgs(); - - ProcessMonitor *m_monitor; // The monitor performing the attach. - sem_t m_semaphore; // Posted to once operation complete. - lldb_private::Error m_error; // Set if process operation failed. - }; - - /// @class LauchArgs - /// - /// @brief Simple structure to pass data to the thread responsible for - /// launching a child process. - struct LaunchArgs : OperationArgs - { - LaunchArgs(ProcessMonitor *monitor, - lldb_private::Module *module, - char const **argv, - char const **envp, - const lldb_private::FileSpec &stdin_file_spec, - const lldb_private::FileSpec &stdout_file_spec, - const lldb_private::FileSpec &stderr_file_spec, - const lldb_private::FileSpec &working_dir, - const lldb_private::ProcessLaunchInfo &launch_info); - - ~LaunchArgs(); - - lldb_private::Module *m_module; // The executable image to launch. - char const **m_argv; // Process arguments. - char const **m_envp; // Process environment. - const lldb_private::FileSpec m_stdin_file_spec; // Redirect stdin or empty. - const lldb_private::FileSpec m_stdout_file_spec; // Redirect stdout or empty. - const lldb_private::FileSpec m_stderr_file_spec; // Redirect stderr or empty. - const lldb_private::FileSpec m_working_dir; // Working directory or empty. - const lldb_private::ProcessLaunchInfo &m_launch_info; - }; - - void - StartLaunchOpThread(LaunchArgs *args, lldb_private::Error &error); - - static void * - LaunchOpThread(void *arg); - - static bool - Launch(LaunchArgs *args); - - struct AttachArgs : OperationArgs - { - AttachArgs(ProcessMonitor *monitor, - lldb::pid_t pid); - - ~AttachArgs(); - - lldb::pid_t m_pid; // pid of the process to be attached. - }; - - void - StartAttachOpThread(AttachArgs *args, lldb_private::Error &error); - - static void * - AttachOpThread(void *args); - - static bool - Attach(AttachArgs *args); - - static bool - SetDefaultPtraceOpts(const lldb::pid_t); - - static void - ServeOperation(OperationArgs *args); - - static bool - DupDescriptor(const lldb_private::FileSpec &file_spec, int fd, int flags); - - static bool - MonitorCallback(void *callback_baton, - lldb::pid_t pid, bool exited, int signal, int status); - - static ProcessMessage - MonitorSIGTRAP(ProcessMonitor *monitor, - const siginfo_t *info, lldb::pid_t pid); - - static ProcessMessage - MonitorSignal(ProcessMonitor *monitor, - const siginfo_t *info, lldb::pid_t pid); - - void - DoOperation(Operation *op); - - /// Stops the child monitor thread. - void - StopMonitoringChildProcess(); - - /// Stops the operation thread used to attach/launch a process. - void - StopOpThread(); -}; - -#endif // #ifndef liblldb_ProcessMonitor_H_ Index: lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp +++ lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp @@ -1,2451 +0,0 @@ -//===-- ProcessMonitor.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 -#include -#include -#include -#include -#include -#include - -// C++ Includes -// Other libraries and framework includes -#include "lldb/Core/Debugger.h" -#include "lldb/Core/Error.h" -#include "lldb/Core/RegisterValue.h" -#include "lldb/Core/Scalar.h" -#include "lldb/Host/Host.h" -#include "lldb/Host/HostNativeThread.h" -#include "lldb/Host/HostThread.h" -#include "lldb/Host/ThreadLauncher.h" -#include "lldb/Target/Thread.h" -#include "lldb/Target/RegisterContext.h" -#include "lldb/Target/UnixSignals.h" -#include "lldb/Utility/PseudoTerminal.h" - -#include "Plugins/Process/POSIX/CrashReason.h" -#include "Plugins/Process/POSIX/POSIXThread.h" -#include "ProcessLinux.h" -#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" -#include "ProcessMonitor.h" -#include "Procfs.h" - -// System includes - They have to be included after framework includes because they define some -// macros which collide with variable names in other modules - -#include "lldb/Host/linux/Personality.h" -#include "lldb/Host/linux/Ptrace.h" -#include "lldb/Host/linux/Signalfd.h" -#include "lldb/Host/android/Android.h" - -#include -#include -#include -#include -#include -#include - -#define LLDB_PERSONALITY_GET_CURRENT_SETTINGS 0xffffffff - -// Support hardware breakpoints in case it has not been defined -#ifndef TRAP_HWBKPT - #define TRAP_HWBKPT 4 -#endif - -// Try to define a macro to encapsulate the tgkill syscall -// fall back on kill() if tgkill isn't available -#define tgkill(pid, tid, sig) \ - syscall(SYS_tgkill, static_cast<::pid_t>(pid), static_cast<::pid_t>(tid), sig) - -using namespace lldb_private; -using namespace lldb_private::process_linux; - -static Operation* EXIT_OPERATION = nullptr; - -// FIXME: this code is host-dependent with respect to types and -// endianness and needs to be fixed. For example, lldb::addr_t is -// hard-coded to uint64_t, but on a 32-bit Linux host, ptrace requires -// 32-bit pointer arguments. This code uses casts to work around the -// problem. - -// We disable the tracing of ptrace calls for integration builds to -// avoid the additional indirection and checks. -#ifndef LLDB_CONFIGURATION_BUILDANDINTEGRATION - -static void -DisplayBytes (lldb_private::StreamString &s, void *bytes, uint32_t count) -{ - uint8_t *ptr = (uint8_t *)bytes; - const uint32_t loop_count = std::min(DEBUG_PTRACE_MAXBYTES, count); - for(uint32_t i=0; iPrintf("PTRACE_POKETEXT %s", buf.GetData()); - break; - } - case PTRACE_POKEDATA: - { - DisplayBytes(buf, &data, 8); - verbose_log->Printf("PTRACE_POKEDATA %s", buf.GetData()); - break; - } - case PTRACE_POKEUSER: - { - DisplayBytes(buf, &data, 8); - verbose_log->Printf("PTRACE_POKEUSER %s", buf.GetData()); - break; - } -#if !defined (__arm64__) && !defined (__aarch64__) - case PTRACE_SETREGS: - { - DisplayBytes(buf, data, data_size); - verbose_log->Printf("PTRACE_SETREGS %s", buf.GetData()); - break; - } - case PTRACE_SETFPREGS: - { - DisplayBytes(buf, data, data_size); - verbose_log->Printf("PTRACE_SETFPREGS %s", buf.GetData()); - break; - } -#endif - case PTRACE_SETSIGINFO: - { - DisplayBytes(buf, data, sizeof(siginfo_t)); - verbose_log->Printf("PTRACE_SETSIGINFO %s", buf.GetData()); - break; - } - case PTRACE_SETREGSET: - { - // Extract iov_base from data, which is a pointer to the struct IOVEC - DisplayBytes(buf, *(void **)data, data_size); - verbose_log->Printf("PTRACE_SETREGSET %s", buf.GetData()); - break; - } - default: - { - } - } - } -} - -// Wrapper for ptrace to catch errors and log calls. -// Note that ptrace sets errno on error because -1 can be a valid result (i.e. for PTRACE_PEEK*) -extern long -PtraceWrapper(int req, lldb::pid_t pid, void *addr, void *data, size_t data_size, - const char* reqName, const char* file, int line) -{ - long int result; - - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PTRACE)); - - PtraceDisplayBytes(req, data, data_size); - - errno = 0; - if (req == PTRACE_GETREGSET || req == PTRACE_SETREGSET) - result = ptrace(static_cast<__ptrace_request>(req), static_cast(pid), *(unsigned int *)addr, data); - else - result = ptrace(static_cast<__ptrace_request>(req), static_cast(pid), addr, data); - - if (log) - log->Printf("ptrace(%s, %" PRIu64 ", %p, %p, %zu)=%lX called from file %s line %d", - reqName, pid, addr, data, data_size, result, file, line); - - PtraceDisplayBytes(req, data, data_size); - - if (log && errno != 0) - { - const char* str; - switch (errno) - { - case ESRCH: str = "ESRCH"; break; - case EINVAL: str = "EINVAL"; break; - case EBUSY: str = "EBUSY"; break; - case EPERM: str = "EPERM"; break; - default: str = ""; - } - log->Printf("ptrace() failed; errno=%d (%s)", errno, str); - } - - return result; -} - -// Wrapper for ptrace when logging is not required. -// Sets errno to 0 prior to calling ptrace. -extern long -PtraceWrapper(int req, pid_t pid, void *addr, void *data, size_t data_size) -{ - long result = 0; - errno = 0; - if (req == PTRACE_GETREGSET || req == PTRACE_SETREGSET) - result = ptrace(static_cast<__ptrace_request>(req), pid, *(unsigned int *)addr, data); - else - result = ptrace(static_cast<__ptrace_request>(req), pid, addr, data); - return result; -} - -#define PTRACE(req, pid, addr, data, data_size) \ - PtraceWrapper((req), (pid), (addr), (data), (data_size), #req, __FILE__, __LINE__) -#else - PtraceWrapper((req), (pid), (addr), (data), (data_size)) -#endif - -//------------------------------------------------------------------------------ -// Static implementations of ProcessMonitor::ReadMemory and -// ProcessMonitor::WriteMemory. This enables mutual recursion between these -// functions without needed to go thru the thread funnel. - -static size_t -DoReadMemory(lldb::pid_t pid, - lldb::addr_t vm_addr, void *buf, size_t size, Error &error) -{ - // ptrace word size is determined by the host, not the child - static const unsigned word_size = sizeof(void*); - unsigned char *dst = static_cast(buf); - size_t bytes_read; - size_t remainder; - long data; - - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_ALL)); - if (log) - ProcessPOSIXLog::IncNestLevel(); - if (log && ProcessPOSIXLog::AtTopNestLevel() && log->GetMask().Test(POSIX_LOG_MEMORY)) - log->Printf ("ProcessMonitor::%s(%" PRIu64 ", %d, %p, %p, %zd, _)", __FUNCTION__, - pid, word_size, (void*)vm_addr, buf, size); - - assert(sizeof(data) >= word_size); - for (bytes_read = 0; bytes_read < size; bytes_read += remainder) - { - errno = 0; - data = PTRACE(PTRACE_PEEKDATA, pid, (void*)vm_addr, NULL, 0); - if (errno) - { - error.SetErrorToErrno(); - if (log) - ProcessPOSIXLog::DecNestLevel(); - return bytes_read; - } - - remainder = size - bytes_read; - remainder = remainder > word_size ? word_size : remainder; - - // Copy the data into our buffer - for (unsigned i = 0; i < remainder; ++i) - dst[i] = ((data >> i*8) & 0xFF); - - if (log && ProcessPOSIXLog::AtTopNestLevel() && - (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_LONG) || - (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_SHORT) && - size <= POSIX_LOG_MEMORY_SHORT_BYTES))) - { - uintptr_t print_dst = 0; - // Format bytes from data by moving into print_dst for log output - for (unsigned i = 0; i < remainder; ++i) - print_dst |= (((data >> i*8) & 0xFF) << i*8); - log->Printf ("ProcessMonitor::%s() [%p]:0x%lx (0x%lx)", __FUNCTION__, - (void*)vm_addr, print_dst, (unsigned long)data); - } - - vm_addr += word_size; - dst += word_size; - } - - if (log) - ProcessPOSIXLog::DecNestLevel(); - return bytes_read; -} - -static size_t -DoWriteMemory(lldb::pid_t pid, - lldb::addr_t vm_addr, const void *buf, size_t size, Error &error) -{ - // ptrace word size is determined by the host, not the child - static const unsigned word_size = sizeof(void*); - const unsigned char *src = static_cast(buf); - size_t bytes_written = 0; - size_t remainder; - - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_ALL)); - if (log) - ProcessPOSIXLog::IncNestLevel(); - if (log && ProcessPOSIXLog::AtTopNestLevel() && log->GetMask().Test(POSIX_LOG_MEMORY)) - log->Printf ("ProcessMonitor::%s(%" PRIu64 ", %d, %p, %p, %zd, _)", __FUNCTION__, - pid, word_size, (void*)vm_addr, buf, size); - - for (bytes_written = 0; bytes_written < size; bytes_written += remainder) - { - remainder = size - bytes_written; - remainder = remainder > word_size ? word_size : remainder; - - if (remainder == word_size) - { - unsigned long data = 0; - assert(sizeof(data) >= word_size); - for (unsigned i = 0; i < word_size; ++i) - data |= (unsigned long)src[i] << i*8; - - if (log && ProcessPOSIXLog::AtTopNestLevel() && - (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_LONG) || - (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_SHORT) && - size <= POSIX_LOG_MEMORY_SHORT_BYTES))) - log->Printf ("ProcessMonitor::%s() [%p]:0x%lx (0x%lx)", __FUNCTION__, - (void*)vm_addr, *(unsigned long*)src, data); - - if (PTRACE(PTRACE_POKEDATA, pid, (void*)vm_addr, (void*)data, 0)) - { - error.SetErrorToErrno(); - if (log) - ProcessPOSIXLog::DecNestLevel(); - return bytes_written; - } - } - else - { - unsigned char buff[8]; - if (DoReadMemory(pid, vm_addr, - buff, word_size, error) != word_size) - { - if (log) - ProcessPOSIXLog::DecNestLevel(); - return bytes_written; - } - - memcpy(buff, src, remainder); - - if (DoWriteMemory(pid, vm_addr, - buff, word_size, error) != word_size) - { - if (log) - ProcessPOSIXLog::DecNestLevel(); - return bytes_written; - } - - if (log && ProcessPOSIXLog::AtTopNestLevel() && - (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_LONG) || - (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_SHORT) && - size <= POSIX_LOG_MEMORY_SHORT_BYTES))) - log->Printf ("ProcessMonitor::%s() [%p]:0x%lx (0x%lx)", __FUNCTION__, - (void*)vm_addr, *(const unsigned long*)src, *(const unsigned long*)buff); - } - - vm_addr += word_size; - src += word_size; - } - if (log) - ProcessPOSIXLog::DecNestLevel(); - return bytes_written; -} - -// Simple helper function to ensure flags are enabled on the given file -// descriptor. -static bool -EnsureFDFlags(int fd, int flags, Error &error) -{ - int status; - - if ((status = fcntl(fd, F_GETFL)) == -1) - { - error.SetErrorToErrno(); - return false; - } - - if (fcntl(fd, F_SETFL, status | flags) == -1) - { - error.SetErrorToErrno(); - return false; - } - - return true; -} - -//------------------------------------------------------------------------------ -/// @class Operation -/// @brief Represents a ProcessMonitor operation. -/// -/// Under Linux, it is not possible to ptrace() from any other thread but the -/// one that spawned or attached to the process from the start. Therefore, when -/// a ProcessMonitor is asked to deliver or change the state of an inferior -/// process the operation must be "funneled" to a specific thread to perform the -/// task. The Operation class provides an abstract base for all services the -/// ProcessMonitor must perform via the single virtual function Execute, thus -/// encapsulating the code that needs to run in the privileged context. -class Operation -{ -public: - virtual ~Operation() {} - virtual void Execute(ProcessMonitor *monitor) = 0; -}; - -//------------------------------------------------------------------------------ -/// @class ReadOperation -/// @brief Implements ProcessMonitor::ReadMemory. -class ReadOperation : public Operation -{ -public: - ReadOperation(lldb::addr_t addr, void *buff, size_t size, - Error &error, size_t &result) - : m_addr(addr), m_buff(buff), m_size(size), - m_error(error), m_result(result) - { } - - void Execute(ProcessMonitor *monitor) override; - -private: - lldb::addr_t m_addr; - void *m_buff; - size_t m_size; - Error &m_error; - size_t &m_result; -}; - -void -ReadOperation::Execute(ProcessMonitor *monitor) -{ - lldb::pid_t pid = monitor->GetPID(); - - m_result = DoReadMemory(pid, m_addr, m_buff, m_size, m_error); -} - -//------------------------------------------------------------------------------ -/// @class WriteOperation -/// @brief Implements ProcessMonitor::WriteMemory. -class WriteOperation : public Operation -{ -public: - WriteOperation(lldb::addr_t addr, const void *buff, size_t size, - Error &error, size_t &result) - : m_addr(addr), m_buff(buff), m_size(size), - m_error(error), m_result(result) - { } - - void Execute(ProcessMonitor *monitor) override; - -private: - lldb::addr_t m_addr; - const void *m_buff; - size_t m_size; - Error &m_error; - size_t &m_result; -}; - -void -WriteOperation::Execute(ProcessMonitor *monitor) -{ - lldb::pid_t pid = monitor->GetPID(); - - m_result = DoWriteMemory(pid, m_addr, m_buff, m_size, m_error); -} - - -//------------------------------------------------------------------------------ -/// @class ReadRegOperation -/// @brief Implements ProcessMonitor::ReadRegisterValue. -class ReadRegOperation : public Operation -{ -public: - ReadRegOperation(lldb::tid_t tid, unsigned offset, const char *reg_name, - RegisterValue &value, bool &result) - : m_tid(tid), m_offset(offset), m_reg_name(reg_name), - m_value(value), m_result(result) - { } - - void Execute(ProcessMonitor *monitor) override; - -private: - lldb::tid_t m_tid; - uintptr_t m_offset; - const char *m_reg_name; - RegisterValue &m_value; - bool &m_result; -}; - -void -ReadRegOperation::Execute(ProcessMonitor *monitor) -{ -#if defined (__arm64__) || defined (__aarch64__) - if (m_offset > sizeof(struct user_pt_regs)) - { - uintptr_t offset = m_offset - sizeof(struct user_pt_regs); - if (offset > sizeof(struct user_fpsimd_state)) - { - m_result = false; - } - else - { - elf_fpregset_t regs; - int regset = NT_FPREGSET; - struct iovec ioVec; - - ioVec.iov_base = ®s; - ioVec.iov_len = sizeof regs; - if (PTRACE(PTRACE_GETREGSET, m_tid, ®set, &ioVec, sizeof regs) < 0) - m_result = false; - else - { - m_result = true; - m_value.SetBytes((void *)(((unsigned char *)(®s)) + offset), 16, monitor->GetProcess().GetByteOrder()); - } - } - } - else - { - elf_gregset_t regs; - int regset = NT_PRSTATUS; - struct iovec ioVec; - - ioVec.iov_base = ®s; - ioVec.iov_len = sizeof regs; - if (PTRACE(PTRACE_GETREGSET, m_tid, ®set, &ioVec, sizeof regs) < 0) - m_result = false; - else - { - m_result = true; - m_value.SetBytes((void *)(((unsigned char *)(regs)) + m_offset), 8, monitor->GetProcess().GetByteOrder()); - } - } -#else - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_REGISTERS)); - - // Set errno to zero so that we can detect a failed peek. - errno = 0; - lldb::addr_t data = PTRACE(PTRACE_PEEKUSER, m_tid, (void*)m_offset, NULL, 0); - if (errno) - m_result = false; - else - { - m_value = data; - m_result = true; - } - if (log) - log->Printf ("ProcessMonitor::%s() reg %s: 0x%" PRIx64, __FUNCTION__, - m_reg_name, data); -#endif -} - -#if defined (__arm64__) || defined (__aarch64__) - //------------------------------------------------------------------------------ - /// @class ReadDBGROperation - /// @brief Implements NativeProcessLinux::ReadDBGR. - class ReadDBGROperation : public Operation - { - public: - ReadDBGROperation(lldb::tid_t tid, unsigned int &count_wp, unsigned int &count_bp) - : m_tid(tid), - m_count_wp(count_wp), - m_count_bp(count_bp) - { } - - void Execute(ProcessMonitor *monitor) override; - - private: - lldb::tid_t m_tid; - unsigned int &m_count_wp; - unsigned int &m_count_bp; - }; - - void - ReadDBGROperation::Execute(ProcessMonitor *monitor) - { - int regset = NT_ARM_HW_WATCH; - struct iovec ioVec; - struct user_hwdebug_state dreg_state; - - ioVec.iov_base = &dreg_state; - ioVec.iov_len = sizeof (dreg_state); - - PTRACE(PTRACE_GETREGSET, m_tid, ®set, &ioVec, ioVec.iov_len); - - m_count_wp = dreg_state.dbg_info & 0xff; - regset = NT_ARM_HW_BREAK; - - PTRACE(PTRACE_GETREGSET, m_tid, ®set, &ioVec, ioVec.iov_len); - m_count_bp = dreg_state.dbg_info & 0xff; - } -#endif - -#if defined (__arm64__) || defined (__aarch64__) - //------------------------------------------------------------------------------ - /// @class WriteDBGROperation - /// @brief Implements NativeProcessLinux::WriteFPR. - class WriteDBGROperation : public Operation - { - public: - WriteDBGROperation(lldb::tid_t tid, lldb::addr_t *addr_buf, uint32_t *cntrl_buf, int type, int count) - : m_tid(tid), - m_addr_buf(addr_buf), - m_cntrl_buf(cntrl_buf), - m_type(type), - m_count(count) - { } - - void Execute(ProcessMonitor *monitor) override; - - private: - lldb::tid_t m_tid; - lldb::addr_t *m_addr_buf; - uint32_t *m_cntrl_buf; - int m_type; - int m_count; - }; - - void - WriteDBGROperation::Execute(ProcessMonitor *monitor) - { - struct iovec ioVec; - struct user_hwdebug_state dreg_state; - - memset (&dreg_state, 0, sizeof (dreg_state)); - ioVec.iov_base = &dreg_state; - ioVec.iov_len = sizeof(dreg_state); - - if (m_type == 0) - m_type = NT_ARM_HW_WATCH; - else - m_type = NT_ARM_HW_BREAK; - - for (int i = 0; i < m_count; i++) - { - dreg_state.dbg_regs[i].addr = m_addr_buf[i]; - dreg_state.dbg_regs[i].ctrl = m_cntrl_buf[i]; - } - - PTRACE(PTRACE_SETREGSET, m_tid, &m_type, &ioVec, ioVec.iov_len); - } -#endif//------------------------------------------------------------------------------ -/// @class WriteRegOperation -/// @brief Implements ProcessMonitor::WriteRegisterValue. -class WriteRegOperation : public Operation -{ -public: - WriteRegOperation(lldb::tid_t tid, unsigned offset, const char *reg_name, - const RegisterValue &value, bool &result) - : m_tid(tid), m_offset(offset), m_reg_name(reg_name), - m_value(value), m_result(result) - { } - - void Execute(ProcessMonitor *monitor) override; - -private: - lldb::tid_t m_tid; - uintptr_t m_offset; - const char *m_reg_name; - const RegisterValue &m_value; - bool &m_result; -}; - -void -WriteRegOperation::Execute(ProcessMonitor *monitor) -{ -#if defined (__arm64__) || defined (__aarch64__) - if (m_offset > sizeof(struct user_pt_regs)) - { - uintptr_t offset = m_offset - sizeof(struct user_pt_regs); - if (offset > sizeof(struct user_fpsimd_state)) - { - m_result = false; - } - else - { - elf_fpregset_t regs; - int regset = NT_FPREGSET; - struct iovec ioVec; - - ioVec.iov_base = ®s; - ioVec.iov_len = sizeof regs; - if (PTRACE(PTRACE_GETREGSET, m_tid, ®set, &ioVec, sizeof regs) < 0) - m_result = false; - else - { - ::memcpy((void *)(((unsigned char *)(®s)) + offset), m_value.GetBytes(), 16); - if (PTRACE(PTRACE_SETREGSET, m_tid, ®set, &ioVec, sizeof regs) < 0) - m_result = false; - else - m_result = true; - } - } - } - else - { - elf_gregset_t regs; - int regset = NT_PRSTATUS; - struct iovec ioVec; - - ioVec.iov_base = ®s; - ioVec.iov_len = sizeof regs; - if (PTRACE(PTRACE_GETREGSET, m_tid, ®set, &ioVec, sizeof regs) < 0) - m_result = false; - else - { - ::memcpy((void *)(((unsigned char *)(®s)) + m_offset), m_value.GetBytes(), 8); - if (PTRACE(PTRACE_SETREGSET, m_tid, ®set, &ioVec, sizeof regs) < 0) - m_result = false; - else - m_result = true; - } - } -#else - void* buf; - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_REGISTERS)); - - buf = (void*) m_value.GetAsUInt64(); - - if (log) - log->Printf ("ProcessMonitor::%s() reg %s: %p", __FUNCTION__, m_reg_name, buf); - if (PTRACE(PTRACE_POKEUSER, m_tid, (void*)m_offset, buf, 0)) - m_result = false; - else - m_result = true; -#endif -} - -//------------------------------------------------------------------------------ -/// @class ReadGPROperation -/// @brief Implements ProcessMonitor::ReadGPR. -class ReadGPROperation : public Operation -{ -public: - ReadGPROperation(lldb::tid_t tid, void *buf, size_t buf_size, bool &result) - : m_tid(tid), m_buf(buf), m_buf_size(buf_size), m_result(result) - { } - - void Execute(ProcessMonitor *monitor) override; - -private: - lldb::tid_t m_tid; - void *m_buf; - size_t m_buf_size; - bool &m_result; -}; - -void -ReadGPROperation::Execute(ProcessMonitor *monitor) -{ -#if defined (__arm64__) || defined (__aarch64__) - int regset = NT_PRSTATUS; - struct iovec ioVec; - - ioVec.iov_base = m_buf; - ioVec.iov_len = m_buf_size; - if (PTRACE(PTRACE_GETREGSET, m_tid, ®set, &ioVec, m_buf_size) < 0) - m_result = false; - else - m_result = true; -#else - if (PTRACE(PTRACE_GETREGS, m_tid, NULL, m_buf, m_buf_size) < 0) - m_result = false; - else - m_result = true; -#endif -} - -//------------------------------------------------------------------------------ -/// @class ReadFPROperation -/// @brief Implements ProcessMonitor::ReadFPR. -class ReadFPROperation : public Operation -{ -public: - ReadFPROperation(lldb::tid_t tid, void *buf, size_t buf_size, bool &result) - : m_tid(tid), m_buf(buf), m_buf_size(buf_size), m_result(result) - { } - - void Execute(ProcessMonitor *monitor) override; - -private: - lldb::tid_t m_tid; - void *m_buf; - size_t m_buf_size; - bool &m_result; -}; - -void -ReadFPROperation::Execute(ProcessMonitor *monitor) -{ -#if defined (__arm64__) || defined (__aarch64__) - int regset = NT_FPREGSET; - struct iovec ioVec; - - ioVec.iov_base = m_buf; - ioVec.iov_len = m_buf_size; - if (PTRACE(PTRACE_GETREGSET, m_tid, ®set, &ioVec, m_buf_size) < 0) - m_result = false; - else - m_result = true; -#else - if (PTRACE(PTRACE_GETFPREGS, m_tid, NULL, m_buf, m_buf_size) < 0) - m_result = false; - else - m_result = true; -#endif -} - -//------------------------------------------------------------------------------ -/// @class ReadRegisterSetOperation -/// @brief Implements ProcessMonitor::ReadRegisterSet. -class ReadRegisterSetOperation : public Operation -{ -public: - ReadRegisterSetOperation(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset, bool &result) - : m_tid(tid), m_buf(buf), m_buf_size(buf_size), m_regset(regset), m_result(result) - { } - - void Execute(ProcessMonitor *monitor) override; - -private: - lldb::tid_t m_tid; - void *m_buf; - size_t m_buf_size; - const unsigned int m_regset; - bool &m_result; -}; - -void -ReadRegisterSetOperation::Execute(ProcessMonitor *monitor) -{ - if (PTRACE(PTRACE_GETREGSET, m_tid, (void *)&m_regset, m_buf, m_buf_size) < 0) - m_result = false; - else - m_result = true; -} - -//------------------------------------------------------------------------------ -/// @class WriteGPROperation -/// @brief Implements ProcessMonitor::WriteGPR. -class WriteGPROperation : public Operation -{ -public: - WriteGPROperation(lldb::tid_t tid, void *buf, size_t buf_size, bool &result) - : m_tid(tid), m_buf(buf), m_buf_size(buf_size), m_result(result) - { } - - void Execute(ProcessMonitor *monitor) override; - -private: - lldb::tid_t m_tid; - void *m_buf; - size_t m_buf_size; - bool &m_result; -}; - -void -WriteGPROperation::Execute(ProcessMonitor *monitor) -{ -#if defined (__arm64__) || defined (__aarch64__) - int regset = NT_PRSTATUS; - struct iovec ioVec; - - ioVec.iov_base = m_buf; - ioVec.iov_len = m_buf_size; - if (PTRACE(PTRACE_SETREGSET, m_tid, ®set, &ioVec, m_buf_size) < 0) - m_result = false; - else - m_result = true; -#else - if (PTRACE(PTRACE_SETREGS, m_tid, NULL, m_buf, m_buf_size) < 0) - m_result = false; - else - m_result = true; -#endif -} - -//------------------------------------------------------------------------------ -/// @class WriteFPROperation -/// @brief Implements ProcessMonitor::WriteFPR. -class WriteFPROperation : public Operation -{ -public: - WriteFPROperation(lldb::tid_t tid, void *buf, size_t buf_size, bool &result) - : m_tid(tid), m_buf(buf), m_buf_size(buf_size), m_result(result) - { } - - void Execute(ProcessMonitor *monitor) override; - -private: - lldb::tid_t m_tid; - void *m_buf; - size_t m_buf_size; - bool &m_result; -}; - -void -WriteFPROperation::Execute(ProcessMonitor *monitor) -{ -#if defined (__arm64__) || defined (__aarch64__) - int regset = NT_FPREGSET; - struct iovec ioVec; - - ioVec.iov_base = m_buf; - ioVec.iov_len = m_buf_size; - if (PTRACE(PTRACE_SETREGSET, m_tid, ®set, &ioVec, m_buf_size) < 0) - m_result = false; - else - m_result = true; -#else - if (PTRACE(PTRACE_SETFPREGS, m_tid, NULL, m_buf, m_buf_size) < 0) - m_result = false; - else - m_result = true; -#endif -} - -//------------------------------------------------------------------------------ -/// @class WriteRegisterSetOperation -/// @brief Implements ProcessMonitor::WriteRegisterSet. -class WriteRegisterSetOperation : public Operation -{ -public: - WriteRegisterSetOperation(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset, bool &result) - : m_tid(tid), m_buf(buf), m_buf_size(buf_size), m_regset(regset), m_result(result) - { } - - void Execute(ProcessMonitor *monitor) override; - -private: - lldb::tid_t m_tid; - void *m_buf; - size_t m_buf_size; - const unsigned int m_regset; - bool &m_result; -}; - -void -WriteRegisterSetOperation::Execute(ProcessMonitor *monitor) -{ - if (PTRACE(PTRACE_SETREGSET, m_tid, (void *)&m_regset, m_buf, m_buf_size) < 0) - m_result = false; - else - m_result = true; -} - -//------------------------------------------------------------------------------ -/// @class ReadThreadPointerOperation -/// @brief Implements ProcessMonitor::ReadThreadPointer. -class ReadThreadPointerOperation : public Operation -{ -public: - ReadThreadPointerOperation(lldb::tid_t tid, lldb::addr_t *addr, bool &result) - : m_tid(tid), m_addr(addr), m_result(result) - { } - - void Execute(ProcessMonitor *monitor) override; - -private: - lldb::tid_t m_tid; - lldb::addr_t *m_addr; - bool &m_result; -}; - -void -ReadThreadPointerOperation::Execute(ProcessMonitor *monitor) -{ - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_REGISTERS)); - if (log) - log->Printf ("ProcessMonitor::%s()", __FUNCTION__); - - // The process for getting the thread area on Linux is - // somewhat... obscure. There's several different ways depending on - // what arch you're on, and what kernel version you have. - - const ArchSpec& arch = monitor->GetProcess().GetTarget().GetArchitecture(); - switch(arch.GetMachine()) - { - case llvm::Triple::aarch64: - { - int regset = LLDB_PTRACE_NT_ARM_TLS; - struct iovec ioVec; - - ioVec.iov_base = m_addr; - ioVec.iov_len = sizeof(lldb::addr_t); - if (PTRACE(PTRACE_GETREGSET, m_tid, ®set, &ioVec, ioVec.iov_len) < 0) - m_result = false; - else - m_result = true; - break; - } -#if defined(__i386__) || defined(__x86_64__) - // Note that struct user below has a field named i387 which is x86-specific. - // Therefore, this case should be compiled only for x86-based systems. - case llvm::Triple::x86: - { - // Find the GS register location for our host architecture. - size_t gs_user_offset = offsetof(struct user, regs); -#ifdef __x86_64__ - gs_user_offset += offsetof(struct user_regs_struct, gs); -#endif -#ifdef __i386__ - gs_user_offset += offsetof(struct user_regs_struct, xgs); -#endif - - // Read the GS register value to get the selector. - errno = 0; - long gs = PTRACE(PTRACE_PEEKUSER, m_tid, (void*)gs_user_offset, NULL, 0); - if (errno) - { - m_result = false; - break; - } - - // Read the LDT base for that selector. - uint32_t tmp[4]; - m_result = (PTRACE(PTRACE_GET_THREAD_AREA, m_tid, (void *)(gs >> 3), &tmp, 0) == 0); - *m_addr = tmp[1]; - break; - } -#endif - case llvm::Triple::x86_64: - // Read the FS register base. - m_result = (PTRACE(PTRACE_ARCH_PRCTL, m_tid, m_addr, (void *)ARCH_GET_FS, 0) == 0); - break; - default: - m_result = false; - break; - } -} - -//------------------------------------------------------------------------------ -/// @class ResumeOperation -/// @brief Implements ProcessMonitor::Resume. -class ResumeOperation : public Operation -{ -public: - ResumeOperation(lldb::tid_t tid, uint32_t signo, bool &result) : - m_tid(tid), m_signo(signo), m_result(result) { } - - void Execute(ProcessMonitor *monitor) override; - -private: - lldb::tid_t m_tid; - uint32_t m_signo; - bool &m_result; -}; - -void -ResumeOperation::Execute(ProcessMonitor *monitor) -{ - intptr_t data = 0; - - if (m_signo != LLDB_INVALID_SIGNAL_NUMBER) - data = m_signo; - - if (PTRACE(PTRACE_CONT, m_tid, NULL, (void*)data, 0)) - { - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); - - if (log) - log->Printf ("ResumeOperation (%" PRIu64 ") failed: %s", m_tid, strerror(errno)); - m_result = false; - } - else - m_result = true; -} - -//------------------------------------------------------------------------------ -/// @class SingleStepOperation -/// @brief Implements ProcessMonitor::SingleStep. -class SingleStepOperation : public Operation -{ -public: - SingleStepOperation(lldb::tid_t tid, uint32_t signo, bool &result) - : m_tid(tid), m_signo(signo), m_result(result) { } - - void Execute(ProcessMonitor *monitor) override; - -private: - lldb::tid_t m_tid; - uint32_t m_signo; - bool &m_result; -}; - -void -SingleStepOperation::Execute(ProcessMonitor *monitor) -{ - intptr_t data = 0; - - if (m_signo != LLDB_INVALID_SIGNAL_NUMBER) - data = m_signo; - - if (PTRACE(PTRACE_SINGLESTEP, m_tid, NULL, (void*)data, 0)) - m_result = false; - else - m_result = true; -} - -//------------------------------------------------------------------------------ -/// @class SiginfoOperation -/// @brief Implements ProcessMonitor::GetSignalInfo. -class SiginfoOperation : public Operation -{ -public: - SiginfoOperation(lldb::tid_t tid, void *info, bool &result, int &ptrace_err) - : m_tid(tid), m_info(info), m_result(result), m_err(ptrace_err) { } - - void Execute(ProcessMonitor *monitor) override; - -private: - lldb::tid_t m_tid; - void *m_info; - bool &m_result; - int &m_err; -}; - -void -SiginfoOperation::Execute(ProcessMonitor *monitor) -{ - if (PTRACE(PTRACE_GETSIGINFO, m_tid, NULL, m_info, 0)) { - m_result = false; - m_err = errno; - } - else - m_result = true; -} - -//------------------------------------------------------------------------------ -/// @class EventMessageOperation -/// @brief Implements ProcessMonitor::GetEventMessage. -class EventMessageOperation : public Operation -{ -public: - EventMessageOperation(lldb::tid_t tid, unsigned long *message, bool &result) - : m_tid(tid), m_message(message), m_result(result) { } - - void Execute(ProcessMonitor *monitor) override; - -private: - lldb::tid_t m_tid; - unsigned long *m_message; - bool &m_result; -}; - -void -EventMessageOperation::Execute(ProcessMonitor *monitor) -{ - if (PTRACE(PTRACE_GETEVENTMSG, m_tid, NULL, m_message, 0)) - m_result = false; - else - m_result = true; -} - -//------------------------------------------------------------------------------ -/// @class DetachOperation -/// @brief Implements ProcessMonitor::Detach. -class DetachOperation : public Operation -{ -public: - DetachOperation(lldb::tid_t tid, Error &result) : m_tid(tid), m_error(result) { } - - void Execute(ProcessMonitor *monitor) override; - -private: - lldb::tid_t m_tid; - Error &m_error; -}; - -void -DetachOperation::Execute(ProcessMonitor *monitor) -{ - if (ptrace(PT_DETACH, m_tid, NULL, 0) < 0) - m_error.SetErrorToErrno(); -} - -ProcessMonitor::OperationArgs::OperationArgs(ProcessMonitor *monitor) - : m_monitor(monitor) -{ - sem_init(&m_semaphore, 0, 0); -} - -ProcessMonitor::OperationArgs::~OperationArgs() -{ - sem_destroy(&m_semaphore); -} - -ProcessMonitor::LaunchArgs::LaunchArgs(ProcessMonitor *monitor, - lldb_private::Module *module, - char const **argv, - char const **envp, - const FileSpec &stdin_file_spec, - const FileSpec &stdout_file_spec, - const FileSpec &stderr_file_spec, - const FileSpec &working_dir, - const lldb_private::ProcessLaunchInfo &launch_info) - : OperationArgs(monitor), - m_module(module), - m_argv(argv), - m_envp(envp), - m_stdin_file_spec(stdin_file_spec), - m_stdout_file_spec(stdout_file_spec), - m_stderr_file_spec(stderr_file_spec), - m_working_dir(working_dir), - m_launch_info(launch_info) -{ -} - -ProcessMonitor::LaunchArgs::~LaunchArgs() -{ } - -ProcessMonitor::AttachArgs::AttachArgs(ProcessMonitor *monitor, - lldb::pid_t pid) - : OperationArgs(monitor), m_pid(pid) { } - -ProcessMonitor::AttachArgs::~AttachArgs() -{ } - -//------------------------------------------------------------------------------ -/// The basic design of the ProcessMonitor is built around two threads. -/// -/// One thread (@see SignalThread) simply blocks on a call to waitpid() looking -/// for changes in the debugee state. When a change is detected a -/// ProcessMessage is sent to the associated ProcessLinux instance. This thread -/// "drives" state changes in the debugger. -/// -/// The second thread (@see OperationThread) is responsible for two things 1) -/// launching or attaching to the inferior process, and then 2) servicing -/// operations such as register reads/writes, stepping, etc. See the comments -/// on the Operation class for more info as to why this is needed. -ProcessMonitor::ProcessMonitor(ProcessPOSIX *process, - Module *module, - const char *argv[], - const char *envp[], - const FileSpec &stdin_file_spec, - const FileSpec &stdout_file_spec, - const FileSpec &stderr_file_spec, - const FileSpec &working_dir, - const lldb_private::ProcessLaunchInfo &launch_info, - lldb_private::Error &error) - : m_process(static_cast(process)), - m_operation_thread(LLDB_INVALID_HOST_THREAD), - m_monitor_thread(LLDB_INVALID_HOST_THREAD), - m_pid(LLDB_INVALID_PROCESS_ID), - m_terminal_fd(-1), - m_operation(0) -{ - std::unique_ptr args(new LaunchArgs(this, module, argv, envp, - stdin_file_spec, - stdout_file_spec, - stderr_file_spec, - working_dir, - launch_info)); - - sem_init(&m_operation_pending, 0, 0); - sem_init(&m_operation_done, 0, 0); - - StartLaunchOpThread(args.get(), error); - if (!error.Success()) - return; - -WAIT_AGAIN: - // Wait for the operation thread to initialize. - if (sem_wait(&args->m_semaphore)) - { - if (errno == EINTR) - goto WAIT_AGAIN; - else - { - error.SetErrorToErrno(); - return; - } - } - - // Check that the launch was a success. - if (!args->m_error.Success()) - { - StopOpThread(); - error = args->m_error; - return; - } - - // Finally, start monitoring the child process for change in state. - m_monitor_thread = Host::StartMonitoringChildProcess( - ProcessMonitor::MonitorCallback, this, GetPID(), true); - if (!m_monitor_thread.IsJoinable()) - { - error.SetErrorToGenericError(); - error.SetErrorString("Process launch failed."); - return; - } -} - -ProcessMonitor::ProcessMonitor(ProcessPOSIX *process, - lldb::pid_t pid, - lldb_private::Error &error) - : m_process(static_cast(process)), - m_operation_thread(LLDB_INVALID_HOST_THREAD), - m_monitor_thread(LLDB_INVALID_HOST_THREAD), - m_pid(LLDB_INVALID_PROCESS_ID), - m_terminal_fd(-1), - m_operation(0) -{ - sem_init(&m_operation_pending, 0, 0); - sem_init(&m_operation_done, 0, 0); - - std::unique_ptr args(new AttachArgs(this, pid)); - - StartAttachOpThread(args.get(), error); - if (!error.Success()) - return; - -WAIT_AGAIN: - // Wait for the operation thread to initialize. - if (sem_wait(&args->m_semaphore)) - { - if (errno == EINTR) - goto WAIT_AGAIN; - else - { - error.SetErrorToErrno(); - return; - } - } - - // Check that the attach was a success. - if (!args->m_error.Success()) - { - StopOpThread(); - error = args->m_error; - return; - } - - // Finally, start monitoring the child process for change in state. - m_monitor_thread = Host::StartMonitoringChildProcess( - ProcessMonitor::MonitorCallback, this, GetPID(), true); - if (!m_monitor_thread.IsJoinable()) - { - error.SetErrorToGenericError(); - error.SetErrorString("Process attach failed."); - return; - } -} - -ProcessMonitor::~ProcessMonitor() -{ - StopMonitor(); -} - -//------------------------------------------------------------------------------ -// Thread setup and tear down. -void -ProcessMonitor::StartLaunchOpThread(LaunchArgs *args, Error &error) -{ - static const char *g_thread_name = "lldb.process.linux.operation"; - - if (m_operation_thread.IsJoinable()) - return; - - m_operation_thread = ThreadLauncher::LaunchThread(g_thread_name, LaunchOpThread, args, &error); -} - -void * -ProcessMonitor::LaunchOpThread(void *arg) -{ - LaunchArgs *args = static_cast(arg); - - if (!Launch(args)) { - sem_post(&args->m_semaphore); - return NULL; - } - - ServeOperation(args); - return NULL; -} - -bool -ProcessMonitor::Launch(LaunchArgs *args) -{ - assert (args && "null args"); - if (!args) - return false; - - ProcessMonitor *monitor = args->m_monitor; - ProcessLinux &process = monitor->GetProcess(); - const char **argv = args->m_argv; - const char **envp = args->m_envp; - const FileSpec &stdin_file_spec = args->m_stdin_file_spec; - const FileSpec &stdout_file_spec = args->m_stdout_file_spec; - const FileSpec &stderr_file_spec = args->m_stderr_file_spec; - const FileSpec &working_dir = args->m_working_dir; - - lldb_utility::PseudoTerminal terminal; - const size_t err_len = 1024; - char err_str[err_len]; - lldb::pid_t pid; - - lldb::ThreadSP inferior; - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); - - // Propagate the environment if one is not supplied. - if (envp == NULL || envp[0] == NULL) - envp = const_cast(environ); - - if ((pid = terminal.Fork(err_str, err_len)) == static_cast(-1)) - { - args->m_error.SetErrorToGenericError(); - args->m_error.SetErrorString("Process fork failed."); - goto FINISH; - } - - // Recognized child exit status codes. - enum { - ePtraceFailed = 1, - eDupStdinFailed, - eDupStdoutFailed, - eDupStderrFailed, - eChdirFailed, - eExecFailed, - eSetGidFailed - }; - - // Child process. - if (pid == 0) - { - // Trace this process. - if (PTRACE(PTRACE_TRACEME, 0, NULL, NULL, 0) < 0) - exit(ePtraceFailed); - - // terminal has already dupped the tty descriptors to stdin/out/err. - // This closes original fd from which they were copied (and avoids - // leaking descriptors to the debugged process. - terminal.CloseSlaveFileDescriptor(); - - // Do not inherit setgid powers. - if (setgid(getgid()) != 0) - exit(eSetGidFailed); - - // Let us have our own process group. - setpgid(0, 0); - - // Dup file descriptors if needed. - // - // FIXME: If two or more of the paths are the same we needlessly open - // the same file multiple times. - if (stdin_file_spec) - if (!DupDescriptor(stdin_file_spec, STDIN_FILENO, O_RDONLY)) - exit(eDupStdinFailed); - - if (stdout_file_spec) - if (!DupDescriptor(stdout_file_spec, STDOUT_FILENO, O_WRONLY | O_CREAT)) - exit(eDupStdoutFailed); - - if (stderr_file_spec) - if (!DupDescriptor(stderr_file_spec, STDERR_FILENO, O_WRONLY | O_CREAT)) - exit(eDupStderrFailed); - - // Change working directory - if (working_dir && 0 != ::chdir(working_dir.GetCString())) - exit(eChdirFailed); - - // Disable ASLR if requested. - if (args->m_launch_info.GetFlags ().Test (lldb::eLaunchFlagDisableASLR)) - { - const int old_personality = personality (LLDB_PERSONALITY_GET_CURRENT_SETTINGS); - if (old_personality == -1) - { - if (log) - log->Printf ("ProcessMonitor::%s retrieval of Linux personality () failed: %s. Cannot disable ASLR.", __FUNCTION__, strerror (errno)); - } - else - { - const int new_personality = personality (ADDR_NO_RANDOMIZE | old_personality); - if (new_personality == -1) - { - if (log) - log->Printf ("ProcessMonitor::%s setting of Linux personality () to disable ASLR failed, ignoring: %s", __FUNCTION__, strerror (errno)); - - } - else - { - if (log) - log->Printf ("ProcessMonitor::%s disabling ASLR: SUCCESS", __FUNCTION__); - - } - } - } - - // Execute. We should never return. - execve(argv[0], - const_cast(argv), - const_cast(envp)); - exit(eExecFailed); - } - - // Wait for the child process to to trap on its call to execve. - lldb::pid_t wpid; - ::pid_t raw_pid; - int status; - - raw_pid = waitpid(pid, &status, 0); - wpid = static_cast (raw_pid); - if (raw_pid < 0) - { - args->m_error.SetErrorToErrno(); - goto FINISH; - } - else if (WIFEXITED(status)) - { - // open, dup or execve likely failed for some reason. - args->m_error.SetErrorToGenericError(); - switch (WEXITSTATUS(status)) - { - case ePtraceFailed: - args->m_error.SetErrorString("Child ptrace failed."); - break; - case eDupStdinFailed: - args->m_error.SetErrorString("Child open stdin failed."); - break; - case eDupStdoutFailed: - args->m_error.SetErrorString("Child open stdout failed."); - break; - case eDupStderrFailed: - args->m_error.SetErrorString("Child open stderr failed."); - break; - case eChdirFailed: - args->m_error.SetErrorString("Child failed to set working directory."); - break; - case eExecFailed: - args->m_error.SetErrorString("Child exec failed."); - break; - case eSetGidFailed: - args->m_error.SetErrorString("Child setgid failed."); - break; - default: - args->m_error.SetErrorString("Child returned unknown exit status."); - break; - } - goto FINISH; - } - assert(WIFSTOPPED(status) && wpid == pid && - "Could not sync with inferior process."); - - if (!SetDefaultPtraceOpts(pid)) - { - args->m_error.SetErrorToErrno(); - goto FINISH; - } - - // Release the master terminal descriptor and pass it off to the - // ProcessMonitor instance. Similarly stash the inferior pid. - monitor->m_terminal_fd = terminal.ReleaseMasterFileDescriptor(); - monitor->m_pid = pid; - - // Set the terminal fd to be in non blocking mode (it simplifies the - // implementation of ProcessLinux::GetSTDOUT to have a non-blocking - // descriptor to read from). - if (!EnsureFDFlags(monitor->m_terminal_fd, O_NONBLOCK, args->m_error)) - goto FINISH; - - // Update the process thread list with this new thread. - // FIXME: should we be letting UpdateThreadList handle this? - // FIXME: by using pids instead of tids, we can only support one thread. - inferior.reset(process.CreateNewPOSIXThread(process, pid)); - - if (log) - log->Printf ("ProcessMonitor::%s() adding pid = %" PRIu64, __FUNCTION__, pid); - process.GetThreadList().AddThread(inferior); - - process.AddThreadForInitialStopIfNeeded(pid); - - // Let our process instance know the thread has stopped. - process.SendMessage(ProcessMessage::Trace(pid)); - -FINISH: - return args->m_error.Success(); -} - -void -ProcessMonitor::StartAttachOpThread(AttachArgs *args, lldb_private::Error &error) -{ - static const char *g_thread_name = "lldb.process.linux.operation"; - - if (m_operation_thread.IsJoinable()) - return; - - m_operation_thread = ThreadLauncher::LaunchThread(g_thread_name, AttachOpThread, args, &error); -} - -void * -ProcessMonitor::AttachOpThread(void *arg) -{ - AttachArgs *args = static_cast(arg); - - if (!Attach(args)) { - sem_post(&args->m_semaphore); - return NULL; - } - - ServeOperation(args); - return NULL; -} - -bool -ProcessMonitor::Attach(AttachArgs *args) -{ - lldb::pid_t pid = args->m_pid; - - ProcessMonitor *monitor = args->m_monitor; - ProcessLinux &process = monitor->GetProcess(); - lldb::ThreadSP inferior; - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); - - // Use a map to keep track of the threads which we have attached/need to attach. - Host::TidMap tids_to_attach; - if (pid <= 1) - { - args->m_error.SetErrorToGenericError(); - args->m_error.SetErrorString("Attaching to process 1 is not allowed."); - goto FINISH; - } - - while (Host::FindProcessThreads(pid, tids_to_attach)) - { - for (Host::TidMap::iterator it = tids_to_attach.begin(); - it != tids_to_attach.end(); ++it) - { - if (it->second == false) - { - lldb::tid_t tid = it->first; - - // Attach to the requested process. - // An attach will cause the thread to stop with a SIGSTOP. - if (PTRACE(PTRACE_ATTACH, tid, NULL, NULL, 0) < 0) - { - // No such thread. The thread may have exited. - // More error handling may be needed. - if (errno == ESRCH) - { - tids_to_attach.erase(it); - continue; - } - else - { - args->m_error.SetErrorToErrno(); - goto FINISH; - } - } - - ::pid_t wpid; - // Need to use __WALL otherwise we receive an error with errno=ECHLD - // At this point we should have a thread stopped if waitpid succeeds. - if ((wpid = waitpid(tid, NULL, __WALL)) < 0) - { - // No such thread. The thread may have exited. - // More error handling may be needed. - if (errno == ESRCH) - { - tids_to_attach.erase(it); - continue; - } - else - { - args->m_error.SetErrorToErrno(); - goto FINISH; - } - } - - if (!SetDefaultPtraceOpts(tid)) - { - args->m_error.SetErrorToErrno(); - goto FINISH; - } - - // Update the process thread list with the attached thread. - inferior.reset(process.CreateNewPOSIXThread(process, tid)); - - if (log) - log->Printf ("ProcessMonitor::%s() adding tid = %" PRIu64, __FUNCTION__, tid); - process.GetThreadList().AddThread(inferior); - it->second = true; - process.AddThreadForInitialStopIfNeeded(tid); - } - } - } - - if (tids_to_attach.size() > 0) - { - monitor->m_pid = pid; - // Let our process instance know the thread has stopped. - process.SendMessage(ProcessMessage::Trace(pid)); - } - else - { - args->m_error.SetErrorToGenericError(); - args->m_error.SetErrorString("No such process."); - } - - FINISH: - return args->m_error.Success(); -} - -bool -ProcessMonitor::SetDefaultPtraceOpts(lldb::pid_t pid) -{ - long ptrace_opts = 0; - - // Have the child raise an event on exit. This is used to keep the child in - // limbo until it is destroyed. - ptrace_opts |= PTRACE_O_TRACEEXIT; - - // Have the tracer trace threads which spawn in the inferior process. - // TODO: if we want to support tracing the inferiors' child, add the - // appropriate ptrace flags here (PTRACE_O_TRACEFORK, PTRACE_O_TRACEVFORK) - ptrace_opts |= PTRACE_O_TRACECLONE; - - // Have the tracer notify us before execve returns - // (needed to disable legacy SIGTRAP generation) - ptrace_opts |= PTRACE_O_TRACEEXEC; - - return PTRACE(PTRACE_SETOPTIONS, pid, NULL, (void*)ptrace_opts, 0) >= 0; -} - -bool -ProcessMonitor::MonitorCallback(void *callback_baton, - lldb::pid_t pid, - bool exited, - int signal, - int status) -{ - ProcessMessage message; - ProcessMonitor *monitor = static_cast(callback_baton); - ProcessLinux *process = monitor->m_process; - assert(process); - bool stop_monitoring; - siginfo_t info; - int ptrace_err; - - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); - - if (exited) - { - if (log) - log->Printf ("ProcessMonitor::%s() got exit signal, tid = %" PRIu64, __FUNCTION__, pid); - message = ProcessMessage::Exit(pid, status); - process->SendMessage(message); - return pid == process->GetID(); - } - - if (!monitor->GetSignalInfo(pid, &info, ptrace_err)) { - if (ptrace_err == EINVAL) { - if (log) - log->Printf ("ProcessMonitor::%s() resuming from group-stop", __FUNCTION__); - // inferior process is in 'group-stop', so deliver SIGSTOP signal - if (!monitor->Resume(pid, SIGSTOP)) { - assert(0 && "SIGSTOP delivery failed while in 'group-stop' state"); - } - stop_monitoring = false; - } else { - // ptrace(GETSIGINFO) failed (but not due to group-stop). Most likely, - // this means the child pid is gone (or not being debugged) therefore - // stop the monitor thread if this is the main pid. - if (log) - log->Printf ("ProcessMonitor::%s() GetSignalInfo failed: %s, tid = %" PRIu64 ", signal = %d, status = %d", - __FUNCTION__, strerror(ptrace_err), pid, signal, status); - stop_monitoring = pid == monitor->m_process->GetID(); - // If we are going to stop monitoring, we need to notify our process object - if (stop_monitoring) - { - message = ProcessMessage::Exit(pid, status); - process->SendMessage(message); - } - } - } - else { - switch (info.si_signo) - { - case SIGTRAP: - message = MonitorSIGTRAP(monitor, &info, pid); - break; - - default: - message = MonitorSignal(monitor, &info, pid); - break; - } - - process->SendMessage(message); - stop_monitoring = false; - } - - return stop_monitoring; -} - -ProcessMessage -ProcessMonitor::MonitorSIGTRAP(ProcessMonitor *monitor, - const siginfo_t *info, lldb::pid_t pid) -{ - ProcessMessage message; - - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); - - assert(monitor); - assert(info && info->si_signo == SIGTRAP && "Unexpected child signal!"); - - switch (info->si_code) - { - default: - assert(false && "Unexpected SIGTRAP code!"); - break; - - // TODO: these two cases are required if we want to support tracing - // of the inferiors' children - // case (SIGTRAP | (PTRACE_EVENT_FORK << 8)): - // case (SIGTRAP | (PTRACE_EVENT_VFORK << 8)): - - case (SIGTRAP | (PTRACE_EVENT_CLONE << 8)): - { - if (log) - log->Printf ("ProcessMonitor::%s() received thread creation event, code = %d", __FUNCTION__, info->si_code ^ SIGTRAP); - - unsigned long tid = 0; - if (!monitor->GetEventMessage(pid, &tid)) - tid = -1; - message = ProcessMessage::NewThread(pid, tid); - break; - } - - case (SIGTRAP | (PTRACE_EVENT_EXEC << 8)): - if (log) - log->Printf ("ProcessMonitor::%s() received exec event, code = %d", __FUNCTION__, info->si_code ^ SIGTRAP); - - message = ProcessMessage::Exec(pid); - break; - - case (SIGTRAP | (PTRACE_EVENT_EXIT << 8)): - { - // The inferior process or one of its threads is about to exit. - // Maintain the process or thread in a state of "limbo" until we are - // explicitly commanded to detach, destroy, resume, etc. - unsigned long data = 0; - if (!monitor->GetEventMessage(pid, &data)) - data = -1; - if (log) - log->Printf ("ProcessMonitor::%s() received limbo event, data = %lx, pid = %" PRIu64, __FUNCTION__, data, pid); - message = ProcessMessage::Limbo(pid, (data >> 8)); - break; - } - - case 0: - case TRAP_TRACE: - if (log) - log->Printf ("ProcessMonitor::%s() received trace event, pid = %" PRIu64, __FUNCTION__, pid); - message = ProcessMessage::Trace(pid); - break; - - case SI_KERNEL: - case TRAP_BRKPT: - if (log) - log->Printf ("ProcessMonitor::%s() received breakpoint event, pid = %" PRIu64, __FUNCTION__, pid); - message = ProcessMessage::Break(pid); - break; - - case TRAP_HWBKPT: - if (log) - log->Printf ("ProcessMonitor::%s() received watchpoint event, pid = %" PRIu64, __FUNCTION__, pid); - message = ProcessMessage::Watch(pid, (lldb::addr_t)info->si_addr); - break; - - case SIGTRAP: - case (SIGTRAP | 0x80): - if (log) - log->Printf ("ProcessMonitor::%s() received system call stop event, pid = %" PRIu64, __FUNCTION__, pid); - // Ignore these signals until we know more about them - monitor->Resume(pid, eResumeSignalNone); - } - - return message; -} - -ProcessMessage -ProcessMonitor::MonitorSignal(ProcessMonitor *monitor, - const siginfo_t *info, lldb::pid_t pid) -{ - ProcessMessage message; - int signo = info->si_signo; - - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); - - // POSIX says that process behaviour is undefined after it ignores a SIGFPE, - // SIGILL, SIGSEGV, or SIGBUS *unless* that signal was generated by a - // kill(2) or raise(3). Similarly for tgkill(2) on Linux. - // - // IOW, user generated signals never generate what we consider to be a - // "crash". - // - // Similarly, ACK signals generated by this monitor. - if (info->si_code == SI_TKILL || info->si_code == SI_USER) - { - if (log) - log->Printf ("ProcessMonitor::%s() received signal %s with code %s, pid = %d", - __FUNCTION__, - monitor->m_process->GetUnixSignals().GetSignalAsCString (signo), - (info->si_code == SI_TKILL ? "SI_TKILL" : "SI_USER"), - info->si_pid); - - if (info->si_pid == getpid()) - return ProcessMessage::SignalDelivered(pid, signo); - else - return ProcessMessage::Signal(pid, signo); - } - - if (log) - log->Printf ("ProcessMonitor::%s() received signal %s", __FUNCTION__, monitor->m_process->GetUnixSignals().GetSignalAsCString (signo)); - - switch (signo) - { - case SIGSEGV: - case SIGILL: - case SIGFPE: - case SIGBUS: - lldb::addr_t fault_addr = reinterpret_cast(info->si_addr); - const auto reason = GetCrashReason(*info); - return ProcessMessage::Crash(pid, reason, signo, fault_addr); - } - - // Everything else is "normal" and does not require any special action on - // our part. - return ProcessMessage::Signal(pid, signo); -} - -// On Linux, when a new thread is created, we receive to notifications, -// (1) a SIGTRAP|PTRACE_EVENT_CLONE from the main process thread with the -// child thread id as additional information, and (2) a SIGSTOP|SI_USER from -// the new child thread indicating that it has is stopped because we attached. -// We have no guarantee of the order in which these arrive, but we need both -// before we are ready to proceed. We currently keep a list of threads which -// have sent the initial SIGSTOP|SI_USER event. Then when we receive the -// SIGTRAP|PTRACE_EVENT_CLONE notification, if the initial stop has not occurred -// we call ProcessMonitor::WaitForInitialTIDStop() to wait for it. - -bool -ProcessMonitor::WaitForInitialTIDStop(lldb::tid_t tid) -{ - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); - if (log) - log->Printf ("ProcessMonitor::%s(%" PRIu64 ") waiting for thread to stop...", __FUNCTION__, tid); - - // Wait for the thread to stop - while (true) - { - int status = -1; - if (log) - log->Printf ("ProcessMonitor::%s(%" PRIu64 ") waitpid...", __FUNCTION__, tid); - ::pid_t wait_pid = waitpid(tid, &status, __WALL); - if (status == -1) - { - // If we got interrupted by a signal (in our process, not the - // inferior) try again. - if (errno == EINTR) - continue; - else - { - if (log) - log->Printf("ProcessMonitor::%s(%" PRIu64 ") waitpid error -- %s", __FUNCTION__, tid, strerror(errno)); - return false; // This is bad, but there's nothing we can do. - } - } - - if (log) - log->Printf ("ProcessMonitor::%s(%" PRIu64 ") waitpid, status = %d", __FUNCTION__, tid, status); - - assert(static_cast(wait_pid) == tid); - - siginfo_t info; - int ptrace_err; - if (!GetSignalInfo(wait_pid, &info, ptrace_err)) - { - if (log) - { - log->Printf ("ProcessMonitor::%s() GetSignalInfo failed. errno=%d (%s)", __FUNCTION__, ptrace_err, strerror(ptrace_err)); - } - return false; - } - - // If this is a thread exit, we won't get any more information. - if (WIFEXITED(status)) - { - m_process->SendMessage(ProcessMessage::Exit(wait_pid, WEXITSTATUS(status))); - if (static_cast(wait_pid) == tid) - return true; - continue; - } - - assert(info.si_code == SI_USER); - assert(WSTOPSIG(status) == SIGSTOP); - - if (log) - log->Printf ("ProcessMonitor::%s(bp) received thread stop signal", __FUNCTION__); - m_process->AddThreadForInitialStopIfNeeded(wait_pid); - return true; - } - return false; -} - -bool -ProcessMonitor::StopThread(lldb::tid_t tid) -{ - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); - - // FIXME: Try to use tgkill or tkill - int ret = tgkill(m_pid, tid, SIGSTOP); - if (log) - log->Printf ("ProcessMonitor::%s(bp) stopping thread, tid = %" PRIu64 ", ret = %d", __FUNCTION__, tid, ret); - - // This can happen if a thread exited while we were trying to stop it. That's OK. - // We'll get the signal for that later. - if (ret < 0) - return false; - - // Wait for the thread to stop - while (true) - { - int status = -1; - if (log) - log->Printf ("ProcessMonitor::%s(bp) waitpid...", __FUNCTION__); - ::pid_t wait_pid = ::waitpid (-1*getpgid(m_pid), &status, __WALL); - if (log) - log->Printf ("ProcessMonitor::%s(bp) waitpid, pid = %" PRIu64 ", status = %d", - __FUNCTION__, static_cast(wait_pid), status); - - if (wait_pid == -1) - { - // If we got interrupted by a signal (in our process, not the - // inferior) try again. - if (errno == EINTR) - continue; - else - return false; // This is bad, but there's nothing we can do. - } - - // If this is a thread exit, we won't get any more information. - if (WIFEXITED(status)) - { - m_process->SendMessage(ProcessMessage::Exit(wait_pid, WEXITSTATUS(status))); - if (static_cast(wait_pid) == tid) - return true; - continue; - } - - siginfo_t info; - int ptrace_err; - if (!GetSignalInfo(wait_pid, &info, ptrace_err)) - { - // another signal causing a StopAllThreads may have been received - // before wait_pid's group-stop was processed, handle it now - if (ptrace_err == EINVAL) - { - assert(WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP); - - if (log) - log->Printf ("ProcessMonitor::%s() resuming from group-stop", __FUNCTION__); - // inferior process is in 'group-stop', so deliver SIGSTOP signal - if (!Resume(wait_pid, SIGSTOP)) { - assert(0 && "SIGSTOP delivery failed while in 'group-stop' state"); - } - continue; - } - - if (log) - log->Printf ("ProcessMonitor::%s() GetSignalInfo failed.", __FUNCTION__); - return false; - } - - // Handle events from other threads - if (log) - log->Printf ("ProcessMonitor::%s(bp) handling event, tid == %" PRIu64, - __FUNCTION__, static_cast(wait_pid)); - - ProcessMessage message; - if (info.si_signo == SIGTRAP) - message = MonitorSIGTRAP(this, &info, wait_pid); - else - message = MonitorSignal(this, &info, wait_pid); - - POSIXThread *thread = static_cast(m_process->GetThreadList().FindThreadByID(wait_pid).get()); - - // When a new thread is created, we may get a SIGSTOP for the new thread - // just before we get the SIGTRAP that we use to add the thread to our - // process thread list. We don't need to worry about that signal here. - assert(thread || message.GetKind() == ProcessMessage::eSignalMessage); - - if (!thread) - { - m_process->SendMessage(message); - continue; - } - - switch (message.GetKind()) - { - case ProcessMessage::eExecMessage: - llvm_unreachable("unexpected message"); - case ProcessMessage::eAttachMessage: - case ProcessMessage::eInvalidMessage: - break; - - // These need special handling because we don't want to send a - // resume even if we already sent a SIGSTOP to this thread. In - // this case the resume will cause the thread to disappear. It is - // unlikely that we'll ever get eExitMessage here, but the same - // reasoning applies. - case ProcessMessage::eLimboMessage: - case ProcessMessage::eExitMessage: - if (log) - log->Printf ("ProcessMonitor::%s(bp) handling message", __FUNCTION__); - // SendMessage will set the thread state as needed. - m_process->SendMessage(message); - // If this is the thread we're waiting for, stop waiting. Even - // though this wasn't the signal we expected, it's the last - // signal we'll see while this thread is alive. - if (static_cast(wait_pid) == tid) - return true; - break; - - case ProcessMessage::eSignalMessage: - if (log) - log->Printf ("ProcessMonitor::%s(bp) handling message", __FUNCTION__); - if (WSTOPSIG(status) == SIGSTOP) - { - m_process->AddThreadForInitialStopIfNeeded(tid); - thread->SetState(lldb::eStateStopped); - } - else - { - m_process->SendMessage(message); - // This isn't the stop we were expecting, but the thread is - // stopped. SendMessage will handle processing of this event, - // but we need to resume here to get the stop we are waiting - // for (otherwise the thread will stop again immediately when - // we try to resume). - if (static_cast(wait_pid) == tid) - Resume(wait_pid, eResumeSignalNone); - } - break; - - case ProcessMessage::eSignalDeliveredMessage: - // This is the stop we're expecting. - if (static_cast(wait_pid) == tid && - WIFSTOPPED(status) && - WSTOPSIG(status) == SIGSTOP && - info.si_code == SI_TKILL) - { - if (log) - log->Printf ("ProcessMonitor::%s(bp) received signal, done waiting", __FUNCTION__); - thread->SetState(lldb::eStateStopped); - return true; - } - // else fall-through - case ProcessMessage::eBreakpointMessage: - case ProcessMessage::eTraceMessage: - case ProcessMessage::eWatchpointMessage: - case ProcessMessage::eCrashMessage: - case ProcessMessage::eNewThreadMessage: - if (log) - log->Printf ("ProcessMonitor::%s(bp) handling message", __FUNCTION__); - // SendMessage will set the thread state as needed. - m_process->SendMessage(message); - // This isn't the stop we were expecting, but the thread is - // stopped. SendMessage will handle processing of this event, - // but we need to resume here to get the stop we are waiting - // for (otherwise the thread will stop again immediately when - // we try to resume). - if (static_cast(wait_pid) == tid) - Resume(wait_pid, eResumeSignalNone); - break; - } - } - return false; -} - -void -ProcessMonitor::ServeOperation(OperationArgs *args) -{ - ProcessMonitor *monitor = args->m_monitor; - - // We are finised with the arguments and are ready to go. Sync with the - // parent thread and start serving operations on the inferior. - sem_post(&args->m_semaphore); - - for(;;) - { - // wait for next pending operation - if (sem_wait(&monitor->m_operation_pending)) - { - if (errno == EINTR) - continue; - assert(false && "Unexpected errno from sem_wait"); - } - - monitor->m_operation->Execute(monitor); - - // notify calling thread that operation is complete - sem_post(&monitor->m_operation_done); - } -} - -void -ProcessMonitor::DoOperation(Operation *op) -{ - Mutex::Locker lock(m_operation_mutex); - - m_operation = op; - - // notify operation thread that an operation is ready to be processed - sem_post(&m_operation_pending); - - // wait for operation to complete - while (sem_wait(&m_operation_done)) - { - if (errno == EINTR) - continue; - assert(false && "Unexpected errno from sem_wait"); - } -} - -size_t -ProcessMonitor::ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, - Error &error) -{ - size_t result; - ReadOperation op(vm_addr, buf, size, error, result); - DoOperation(&op); - return result; -} - -size_t -ProcessMonitor::WriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size, - lldb_private::Error &error) -{ - size_t result; - WriteOperation op(vm_addr, buf, size, error, result); - DoOperation(&op); - return result; -} - -bool -ProcessMonitor::ReadRegisterValue(lldb::tid_t tid, unsigned offset, const char* reg_name, - unsigned size, RegisterValue &value) -{ - bool result; - ReadRegOperation op(tid, offset, reg_name, value, result); - DoOperation(&op); - return result; -} - -#if defined (__arm64__) || defined (__aarch64__) - -bool -ProcessMonitor::ReadHardwareDebugInfo (lldb::tid_t tid, unsigned int &watch_count , unsigned int &break_count) -{ - bool result = true; - ReadDBGROperation op(tid, watch_count, break_count); - DoOperation(&op); - return result; -} - -bool -ProcessMonitor::WriteHardwareDebugRegs (lldb::tid_t tid, lldb::addr_t *addr_buf, uint32_t *cntrl_buf, int type, int count) -{ - bool result = true; - WriteDBGROperation op(tid, addr_buf, cntrl_buf, type, count); - DoOperation(&op); - return result; -} - -#endif -bool -ProcessMonitor::WriteRegisterValue(lldb::tid_t tid, unsigned offset, - const char* reg_name, const RegisterValue &value) -{ - bool result; - WriteRegOperation op(tid, offset, reg_name, value, result); - DoOperation(&op); - return result; -} - -bool -ProcessMonitor::ReadGPR(lldb::tid_t tid, void *buf, size_t buf_size) -{ - bool result; - ReadGPROperation op(tid, buf, buf_size, result); - DoOperation(&op); - return result; -} - -bool -ProcessMonitor::ReadFPR(lldb::tid_t tid, void *buf, size_t buf_size) -{ - bool result; - ReadFPROperation op(tid, buf, buf_size, result); - DoOperation(&op); - return result; -} - -bool -ProcessMonitor::ReadRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset) -{ - bool result; - ReadRegisterSetOperation op(tid, buf, buf_size, regset, result); - DoOperation(&op); - return result; -} - -bool -ProcessMonitor::WriteGPR(lldb::tid_t tid, void *buf, size_t buf_size) -{ - bool result; - WriteGPROperation op(tid, buf, buf_size, result); - DoOperation(&op); - return result; -} - -bool -ProcessMonitor::WriteFPR(lldb::tid_t tid, void *buf, size_t buf_size) -{ - bool result; - WriteFPROperation op(tid, buf, buf_size, result); - DoOperation(&op); - return result; -} - -bool -ProcessMonitor::WriteRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset) -{ - bool result; - WriteRegisterSetOperation op(tid, buf, buf_size, regset, result); - DoOperation(&op); - return result; -} - -bool -ProcessMonitor::ReadThreadPointer(lldb::tid_t tid, lldb::addr_t &value) -{ - bool result; - ReadThreadPointerOperation op(tid, &value, result); - DoOperation(&op); - return result; -} - -bool -ProcessMonitor::Resume(lldb::tid_t tid, uint32_t signo) -{ - bool result; - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); - - if (log) - log->Printf ("ProcessMonitor::%s() resuming thread = %" PRIu64 " with signal %s", __FUNCTION__, tid, - m_process->GetUnixSignals().GetSignalAsCString (signo)); - ResumeOperation op(tid, signo, result); - DoOperation(&op); - if (log) - log->Printf ("ProcessMonitor::%s() resuming result = %s", __FUNCTION__, result ? "true" : "false"); - return result; -} - -bool -ProcessMonitor::SingleStep(lldb::tid_t tid, uint32_t signo) -{ - bool result; - SingleStepOperation op(tid, signo, result); - DoOperation(&op); - return result; -} - -bool -ProcessMonitor::Kill() -{ - return kill(GetPID(), SIGKILL) == 0; -} - -bool -ProcessMonitor::GetSignalInfo(lldb::tid_t tid, void *siginfo, int &ptrace_err) -{ - bool result; - SiginfoOperation op(tid, siginfo, result, ptrace_err); - DoOperation(&op); - return result; -} - -bool -ProcessMonitor::GetEventMessage(lldb::tid_t tid, unsigned long *message) -{ - bool result; - EventMessageOperation op(tid, message, result); - DoOperation(&op); - return result; -} - -lldb_private::Error -ProcessMonitor::Detach(lldb::tid_t tid) -{ - lldb_private::Error error; - if (tid != LLDB_INVALID_THREAD_ID) - { - DetachOperation op(tid, error); - DoOperation(&op); - } - return error; -} - -bool -ProcessMonitor::DupDescriptor(const FileSpec &file_spec, int fd, int flags) -{ - int target_fd = open(file_spec.GetCString(), flags, 0666); - - if (target_fd == -1) - return false; - - if (dup2(target_fd, fd) == -1) - return false; - - return (close(target_fd) == -1) ? false : true; -} - -void -ProcessMonitor::StopMonitoringChildProcess() -{ - if (m_monitor_thread.IsJoinable()) - { - ::pthread_kill(m_monitor_thread.GetNativeThread().GetSystemHandle(), SIGUSR1); - m_monitor_thread.Join(nullptr); - } -} - -void -ProcessMonitor::StopMonitor() -{ - StopMonitoringChildProcess(); - StopOpThread(); - sem_destroy(&m_operation_pending); - sem_destroy(&m_operation_done); - if (m_terminal_fd >= 0) { - close(m_terminal_fd); - m_terminal_fd = -1; - } -} - -void -ProcessMonitor::StopOpThread() -{ - if (!m_operation_thread.IsJoinable()) - return; - - DoOperation(EXIT_OPERATION); - m_operation_thread.Join(nullptr); -} Index: lldb/trunk/source/Plugins/Process/POSIX/CMakeLists.txt =================================================================== --- lldb/trunk/source/Plugins/Process/POSIX/CMakeLists.txt +++ lldb/trunk/source/Plugins/Process/POSIX/CMakeLists.txt @@ -1,19 +1,10 @@ set(LLVM_NO_RTTI 1) include_directories(.) -include_directories(../Linux) include_directories(../Utility) add_lldb_library(lldbPluginProcessPOSIX CrashReason.cpp - POSIXStopInfo.cpp - POSIXThread.cpp ProcessMessage.cpp - ProcessPOSIX.cpp ProcessPOSIXLog.cpp - RegisterContextPOSIXProcessMonitor_arm.cpp - RegisterContextPOSIXProcessMonitor_arm64.cpp - RegisterContextPOSIXProcessMonitor_mips64.cpp - RegisterContextPOSIXProcessMonitor_powerpc.cpp - RegisterContextPOSIXProcessMonitor_x86.cpp ) Index: lldb/trunk/source/Plugins/Process/POSIX/POSIXStopInfo.h =================================================================== --- lldb/trunk/source/Plugins/Process/POSIX/POSIXStopInfo.h +++ lldb/trunk/source/Plugins/Process/POSIX/POSIXStopInfo.h @@ -1,110 +0,0 @@ -//===-- POSIXStopInfo.h -----------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_POSIXStopInfo_H_ -#define liblldb_POSIXStopInfo_H_ - -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes -#include "lldb/Target/StopInfo.h" - -#include "CrashReason.h" -#include "POSIXThread.h" - -#include - -//===----------------------------------------------------------------------===// -/// @class POSIXStopInfo -/// @brief Simple base class for all POSIX-specific StopInfo objects. -/// -class POSIXStopInfo - : public lldb_private::StopInfo -{ -public: - POSIXStopInfo(lldb_private::Thread &thread, uint32_t status) - : StopInfo(thread, status) - { } -}; - -//===----------------------------------------------------------------------===// -/// @class POSIXLimboStopInfo -/// @brief Represents the stop state of a process ready to exit. -/// -class POSIXLimboStopInfo - : public POSIXStopInfo -{ -public: - POSIXLimboStopInfo(POSIXThread &thread) - : POSIXStopInfo(thread, 0) - { } - - ~POSIXLimboStopInfo(); - - lldb::StopReason - GetStopReason() const; - - const char * - GetDescription(); - - bool - ShouldStop(lldb_private::Event *event_ptr); - - bool - ShouldNotify(lldb_private::Event *event_ptr); -}; - - -//===----------------------------------------------------------------------===// -/// @class POSIXCrashStopInfo -/// @brief Represents the stop state of process that is ready to crash. -/// -class POSIXCrashStopInfo - : public POSIXStopInfo -{ -public: - POSIXCrashStopInfo(POSIXThread &thread, uint32_t status, - CrashReason reason, - lldb::addr_t fault_addr); - ~POSIXCrashStopInfo(); - - lldb::StopReason - GetStopReason() const; -}; - -//===----------------------------------------------------------------------===// -/// @class POSIXNewThreadStopInfo -/// @brief Represents the stop state of process when a new thread is spawned. -/// - -class POSIXNewThreadStopInfo - : public POSIXStopInfo -{ -public: - POSIXNewThreadStopInfo (POSIXThread &thread) - : POSIXStopInfo (thread, 0) - { } - - ~POSIXNewThreadStopInfo(); - - lldb::StopReason - GetStopReason() const; - - const char * - GetDescription(); - - bool - ShouldStop(lldb_private::Event *event_ptr); - - bool - ShouldNotify(lldb_private::Event *event_ptr); -}; - -#endif Index: lldb/trunk/source/Plugins/Process/POSIX/POSIXStopInfo.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/POSIX/POSIXStopInfo.cpp +++ lldb/trunk/source/Plugins/Process/POSIX/POSIXStopInfo.cpp @@ -1,92 +0,0 @@ -//===-- POSIXStopInfo.cpp ---------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "POSIXStopInfo.h" - -using namespace lldb; -using namespace lldb_private; - - -//===----------------------------------------------------------------------===// -// POSIXLimboStopInfo - -POSIXLimboStopInfo::~POSIXLimboStopInfo() { } - -lldb::StopReason -POSIXLimboStopInfo::GetStopReason() const -{ - return lldb::eStopReasonThreadExiting; -} - -const char * -POSIXLimboStopInfo::GetDescription() -{ - return "thread exiting"; -} - -bool -POSIXLimboStopInfo::ShouldStop(Event *event_ptr) -{ - return false; -} - -bool -POSIXLimboStopInfo::ShouldNotify(Event *event_ptr) -{ - return false; -} - -//===----------------------------------------------------------------------===// -// POSIXCrashStopInfo - -POSIXCrashStopInfo::POSIXCrashStopInfo(POSIXThread &thread, - uint32_t status, - CrashReason reason, - lldb::addr_t fault_addr) - : POSIXStopInfo(thread, status) -{ - m_description = ::GetCrashReasonString(reason, fault_addr); -} - -POSIXCrashStopInfo::~POSIXCrashStopInfo() { } - -lldb::StopReason -POSIXCrashStopInfo::GetStopReason() const -{ - return lldb::eStopReasonException; -} - -//===----------------------------------------------------------------------===// -// POSIXNewThreadStopInfo - -POSIXNewThreadStopInfo::~POSIXNewThreadStopInfo() { } - -lldb::StopReason -POSIXNewThreadStopInfo::GetStopReason() const -{ - return lldb::eStopReasonNone; -} - -const char * -POSIXNewThreadStopInfo::GetDescription() -{ - return "thread spawned"; -} - -bool -POSIXNewThreadStopInfo::ShouldStop(Event *event_ptr) -{ - return false; -} - -bool -POSIXNewThreadStopInfo::ShouldNotify(Event *event_ptr) -{ - return false; -} Index: lldb/trunk/source/Plugins/Process/POSIX/POSIXThread.h =================================================================== --- lldb/trunk/source/Plugins/Process/POSIX/POSIXThread.h +++ lldb/trunk/source/Plugins/Process/POSIX/POSIXThread.h @@ -1,135 +0,0 @@ -//===-- POSIXThread.h -------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_POSIXThread_H_ -#define liblldb_POSIXThread_H_ - -// C Includes -// C++ Includes -#include -#include - -// Other libraries and framework includes -#include "lldb/Target/Thread.h" -#include "Plugins/Process/Utility/RegisterContextPOSIX.h" - -class ProcessMessage; -class ProcessMonitor; -class POSIXBreakpointProtocol; - -//------------------------------------------------------------------------------ -// @class POSIXThread -// @brief Abstraction of a POSIX thread. -class POSIXThread - : public lldb_private::Thread -{ -public: - POSIXThread(lldb_private::Process &process, lldb::tid_t tid); - - virtual ~POSIXThread(); - - void - RefreshStateAfterStop() override; - - void - WillResume(lldb::StateType resume_state) override; - - // This notifies the thread when a private stop occurs. - void - DidStop () override; - - const char * - GetInfo() override; - - void - SetName (const char *name) override; - - const char * - GetName () override; - - lldb::RegisterContextSP - GetRegisterContext() override; - - lldb::RegisterContextSP - CreateRegisterContextForFrame (lldb_private::StackFrame *frame) override; - - lldb::addr_t - GetThreadPointer () override; - - //-------------------------------------------------------------------------- - // These functions provide a mapping from the register offset - // back to the register index or name for use in debugging or log - // output. - - unsigned - GetRegisterIndexFromOffset(unsigned offset); - - const char * - GetRegisterName(unsigned reg); - - const char * - GetRegisterNameFromOffset(unsigned offset); - - //-------------------------------------------------------------------------- - // These methods form a specialized interface to POSIX threads. - // - bool Resume(); - - void Notify(const ProcessMessage &message); - - //-------------------------------------------------------------------------- - // These methods provide an interface to watchpoints - // - bool EnableHardwareWatchpoint(lldb_private::Watchpoint *wp); - - bool DisableHardwareWatchpoint(lldb_private::Watchpoint *wp); - - uint32_t NumSupportedHardwareWatchpoints(); - - uint32_t FindVacantWatchpointIndex(); - -protected: - POSIXBreakpointProtocol * - GetPOSIXBreakpointProtocol () - { - if (!m_reg_context_sp) - m_reg_context_sp = GetRegisterContext(); - return m_posix_thread; - } - - std::unique_ptr m_frame_ap; - - lldb::BreakpointSiteSP m_breakpoint; - - bool m_thread_name_valid; - std::string m_thread_name; - POSIXBreakpointProtocol *m_posix_thread; - - ProcessMonitor & - GetMonitor(); - - bool - CalculateStopInfo() override; - - void BreakNotify(const ProcessMessage &message); - void WatchNotify(const ProcessMessage &message); - virtual void TraceNotify(const ProcessMessage &message); - void LimboNotify(const ProcessMessage &message); - void SignalNotify(const ProcessMessage &message); - void SignalDeliveredNotify(const ProcessMessage &message); - void CrashNotify(const ProcessMessage &message); - void ThreadNotify(const ProcessMessage &message); - void ExitNotify(const ProcessMessage &message); - void ExecNotify(const ProcessMessage &message); - - lldb_private::Unwind * - GetUnwinder() override; -}; - -#endif // #ifndef liblldb_POSIXThread_H_ Index: lldb/trunk/source/Plugins/Process/POSIX/POSIXThread.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/POSIX/POSIXThread.cpp +++ lldb/trunk/source/Plugins/Process/POSIX/POSIXThread.cpp @@ -1,713 +0,0 @@ -//===-- POSIXThread.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 -#include - -// C++ Includes -// Other libraries and framework includes -// Project includes -#include "lldb/Breakpoint/Watchpoint.h" -#include "lldb/Breakpoint/BreakpointLocation.h" -#include "lldb/Core/Debugger.h" -#include "lldb/Core/State.h" -#include "lldb/Host/Host.h" -#include "lldb/Host/HostNativeThread.h" -#include "lldb/Host/HostInfo.h" -#include "lldb/Target/Process.h" -#include "lldb/Target/StopInfo.h" -#include "lldb/Target/Target.h" -#include "lldb/Target/ThreadSpec.h" -#include "llvm/ADT/SmallString.h" -#include "POSIXStopInfo.h" -#include "POSIXThread.h" -#include "ProcessPOSIX.h" -#include "ProcessPOSIXLog.h" -#include "Plugins/Process/Linux/ProcessMonitor.h" -#include "RegisterContextPOSIXProcessMonitor_arm.h" -#include "RegisterContextPOSIXProcessMonitor_arm64.h" -#include "RegisterContextPOSIXProcessMonitor_mips64.h" -#include "RegisterContextPOSIXProcessMonitor_powerpc.h" -#include "RegisterContextPOSIXProcessMonitor_x86.h" -#include "Plugins/Process/Utility/RegisterContextLinux_arm.h" -#include "Plugins/Process/Utility/RegisterContextLinux_arm64.h" -#include "Plugins/Process/Utility/RegisterContextLinux_i386.h" -#include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h" -#include "Plugins/Process/Utility/RegisterContextFreeBSD_arm.h" -#include "Plugins/Process/Utility/RegisterContextFreeBSD_i386.h" -#include "Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h" -#include "Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h" -#include "Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h" -#include "Plugins/Process/Utility/UnwindLLDB.h" - -using namespace lldb; -using namespace lldb_private; - - -POSIXThread::POSIXThread(Process &process, lldb::tid_t tid) - : Thread(process, tid), - m_frame_ap (), - m_breakpoint (), - m_thread_name_valid (false), - m_thread_name (), - m_posix_thread(NULL) -{ - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); - if (log && log->GetMask().Test(POSIX_LOG_VERBOSE)) - log->Printf ("POSIXThread::%s (tid = %" PRIi64 ")", __FUNCTION__, tid); - - // Set the current watchpoints for this thread. - Target &target = GetProcess()->GetTarget(); - const WatchpointList &wp_list = target.GetWatchpointList(); - size_t wp_size = wp_list.GetSize(); - - for (uint32_t wp_idx = 0; wp_idx < wp_size; wp_idx++) - { - lldb::WatchpointSP wp = wp_list.GetByIndex(wp_idx); - if (wp.get() && wp->IsEnabled()) - { - // This watchpoint as been enabled; obviously this "new" thread - // has been created since that watchpoint was enabled. Since - // the POSIXBreakpointProtocol has yet to be initialized, its - // m_watchpoints_initialized member will be FALSE. Attempting to - // read the debug status register to determine if a watchpoint - // has been hit would result in the zeroing of that register. - // Since the active debug registers would have been cloned when - // this thread was created, simply force the m_watchpoints_initized - // member to TRUE and avoid resetting dr6 and dr7. - GetPOSIXBreakpointProtocol()->ForceWatchpointsInitialized(); - } - } -} - -POSIXThread::~POSIXThread() -{ - DestroyThread(); -} - -ProcessMonitor & -POSIXThread::GetMonitor() -{ - ProcessSP base = GetProcess(); - ProcessPOSIX &process = static_cast(*base); - return process.GetMonitor(); -} - -// Overridden by FreeBSDThread; this is used only on Linux. -void -POSIXThread::RefreshStateAfterStop() -{ - // Invalidate all registers in our register context. We don't set "force" to - // true because the stop reply packet might have had some register values - // that were expedited and these will already be copied into the register - // context by the time this function gets called. The KDPRegisterContext - // class has been made smart enough to detect when it needs to invalidate - // which registers are valid by putting hooks in the register read and - // register supply functions where they check the process stop ID and do - // the right thing. - //if (StateIsStoppedState(GetState()) - { - const bool force = false; - GetRegisterContext()->InvalidateIfNeeded (force); - } - // FIXME: This should probably happen somewhere else. - SetResumeState(eStateRunning, true); - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); - if (log) - log->Printf ("POSIXThread::%s (tid = %" PRIi64 ") setting thread resume state to running", __FUNCTION__, GetID()); -} - -const char * -POSIXThread::GetInfo() -{ - return NULL; -} - -void -POSIXThread::SetName (const char *name) -{ - m_thread_name_valid = (name && name[0]); - if (m_thread_name_valid) - m_thread_name.assign (name); - else - m_thread_name.clear(); -} - -const char * -POSIXThread::GetName () -{ - if (!m_thread_name_valid) - { - llvm::SmallString<32> thread_name; - HostNativeThread::GetName(GetID(), thread_name); - m_thread_name = thread_name.c_str(); - m_thread_name_valid = true; - } - - if (m_thread_name.empty()) - return NULL; - return m_thread_name.c_str(); -} - -lldb::RegisterContextSP -POSIXThread::GetRegisterContext() -{ - if (!m_reg_context_sp) - { - m_posix_thread = NULL; - - RegisterInfoInterface *reg_interface = NULL; - const ArchSpec &target_arch = GetProcess()->GetTarget().GetArchitecture(); - - switch (target_arch.GetTriple().getOS()) - { - case llvm::Triple::FreeBSD: - switch (target_arch.GetMachine()) - { - case llvm::Triple::arm: - reg_interface = new RegisterContextFreeBSD_arm(target_arch); - break; - case llvm::Triple::ppc: -#ifndef __powerpc64__ - reg_interface = new RegisterContextFreeBSD_powerpc32(target_arch); - break; -#endif - case llvm::Triple::ppc64: - reg_interface = new RegisterContextFreeBSD_powerpc64(target_arch); - break; - case llvm::Triple::mips64: - reg_interface = new RegisterContextFreeBSD_mips64(target_arch); - break; - case llvm::Triple::x86: - reg_interface = new RegisterContextFreeBSD_i386(target_arch); - break; - case llvm::Triple::x86_64: - reg_interface = new RegisterContextFreeBSD_x86_64(target_arch); - break; - default: - break; - } - break; - - case llvm::Triple::Linux: - switch (target_arch.GetMachine()) - { - case llvm::Triple::aarch64: - assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) && "Register setting path assumes this is a 64-bit host"); - reg_interface = static_cast(new RegisterContextLinux_arm64(target_arch)); - break; - case llvm::Triple::arm: - assert(HostInfo::GetArchitecture().GetAddressByteSize() == 4); - reg_interface = static_cast(new RegisterContextLinux_arm(target_arch)); - break; - case llvm::Triple::x86: - case llvm::Triple::x86_64: - if (HostInfo::GetArchitecture().GetAddressByteSize() == 4) - { - // 32-bit hosts run with a RegisterContextLinux_i386 context. - reg_interface = static_cast(new RegisterContextLinux_i386(target_arch)); - } - else - { - assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) && - "Register setting path assumes this is a 64-bit host"); - // X86_64 hosts know how to work with 64-bit and 32-bit EXEs using the x86_64 register context. - reg_interface = static_cast(new RegisterContextLinux_x86_64(target_arch)); - } - break; - default: - break; - } - - default: - break; - } - - assert(reg_interface && "OS or CPU not supported!"); - - switch (target_arch.GetMachine()) - { - case llvm::Triple::aarch64: - { - RegisterContextPOSIXProcessMonitor_arm64 *reg_ctx = new RegisterContextPOSIXProcessMonitor_arm64(*this, 0, reg_interface); - m_posix_thread = reg_ctx; - m_reg_context_sp.reset(reg_ctx); - break; - } - case llvm::Triple::arm: - { - RegisterContextPOSIXProcessMonitor_arm *reg_ctx = new RegisterContextPOSIXProcessMonitor_arm(*this, 0, reg_interface); - m_posix_thread = reg_ctx; - m_reg_context_sp.reset(reg_ctx); - break; - } - case llvm::Triple::mips64: - { - RegisterContextPOSIXProcessMonitor_mips64 *reg_ctx = new RegisterContextPOSIXProcessMonitor_mips64(*this, 0, reg_interface); - m_posix_thread = reg_ctx; - m_reg_context_sp.reset(reg_ctx); - break; - } - case llvm::Triple::ppc: - case llvm::Triple::ppc64: - { - RegisterContextPOSIXProcessMonitor_powerpc *reg_ctx = new RegisterContextPOSIXProcessMonitor_powerpc(*this, 0, reg_interface); - m_posix_thread = reg_ctx; - m_reg_context_sp.reset(reg_ctx); - break; - } - case llvm::Triple::x86: - case llvm::Triple::x86_64: - { - RegisterContextPOSIXProcessMonitor_x86_64 *reg_ctx = new RegisterContextPOSIXProcessMonitor_x86_64(*this, 0, reg_interface); - m_posix_thread = reg_ctx; - m_reg_context_sp.reset(reg_ctx); - break; - } - default: - break; - } - } - return m_reg_context_sp; -} - -lldb::RegisterContextSP -POSIXThread::CreateRegisterContextForFrame(lldb_private::StackFrame *frame) -{ - lldb::RegisterContextSP reg_ctx_sp; - uint32_t concrete_frame_idx = 0; - - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); - if (log && log->GetMask().Test(POSIX_LOG_VERBOSE)) - log->Printf ("POSIXThread::%s ()", __FUNCTION__); - - if (frame) - concrete_frame_idx = frame->GetConcreteFrameIndex(); - - if (concrete_frame_idx == 0) - reg_ctx_sp = GetRegisterContext(); - else - { - assert(GetUnwinder()); - reg_ctx_sp = GetUnwinder()->CreateRegisterContextForFrame(frame); - } - - return reg_ctx_sp; -} - -lldb::addr_t -POSIXThread::GetThreadPointer () -{ - ProcessMonitor &monitor = GetMonitor(); - addr_t addr; - if (monitor.ReadThreadPointer (GetID(), addr)) - return addr; - else - return LLDB_INVALID_ADDRESS; -} - -bool -POSIXThread::CalculateStopInfo() -{ - SetStopInfo (m_stop_info_sp); - return true; -} - -Unwind * -POSIXThread::GetUnwinder() -{ - if (m_unwinder_ap.get() == NULL) - m_unwinder_ap.reset(new UnwindLLDB(*this)); - - return m_unwinder_ap.get(); -} - -// Overridden by FreeBSDThread; this is used only on Linux. -void -POSIXThread::WillResume(lldb::StateType resume_state) -{ - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); - if (log) - log->Printf ("POSIXThread::%s (tid = %" PRIi64 ") setting thread resume state to %s", __FUNCTION__, GetID(), StateAsCString(resume_state)); - // TODO: the line below shouldn't really be done, but - // the POSIXThread might rely on this so I will leave this in for now - SetResumeState(resume_state); -} - -void -POSIXThread::DidStop() -{ - // Don't set the thread state to stopped unless we really stopped. -} - -bool -POSIXThread::Resume() -{ - lldb::StateType resume_state = GetResumeState(); - ProcessMonitor &monitor = GetMonitor(); - bool status; - - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); - if (log) - log->Printf ("POSIXThread::%s (), resume_state = %s", __FUNCTION__, - StateAsCString(resume_state)); - - switch (resume_state) - { - default: - assert(false && "Unexpected state for resume!"); - status = false; - break; - - case lldb::eStateRunning: - SetState(resume_state); - status = monitor.Resume(GetID(), GetResumeSignal()); - break; - - case lldb::eStateStepping: - SetState(resume_state); - status = monitor.SingleStep(GetID(), GetResumeSignal()); - break; - case lldb::eStateStopped: - case lldb::eStateSuspended: - status = true; - break; - } - - return status; -} - -void -POSIXThread::Notify(const ProcessMessage &message) -{ - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); - if (log) - log->Printf ("POSIXThread::%s () message kind = '%s' for tid %" PRIu64, - __FUNCTION__, message.PrintKind(), GetID()); - - switch (message.GetKind()) - { - default: - assert(false && "Unexpected message kind!"); - break; - - case ProcessMessage::eExitMessage: - // Nothing to be done. - break; - - case ProcessMessage::eLimboMessage: - LimboNotify(message); - break; - - case ProcessMessage::eSignalMessage: - SignalNotify(message); - break; - - case ProcessMessage::eSignalDeliveredMessage: - SignalDeliveredNotify(message); - break; - - case ProcessMessage::eTraceMessage: - TraceNotify(message); - break; - - case ProcessMessage::eBreakpointMessage: - BreakNotify(message); - break; - - case ProcessMessage::eWatchpointMessage: - WatchNotify(message); - break; - - case ProcessMessage::eCrashMessage: - CrashNotify(message); - break; - - case ProcessMessage::eNewThreadMessage: - ThreadNotify(message); - break; - - case ProcessMessage::eExecMessage: - ExecNotify(message); - break; - } -} - -bool -POSIXThread::EnableHardwareWatchpoint(Watchpoint *wp) -{ - bool wp_set = false; - if (wp) - { - addr_t wp_addr = wp->GetLoadAddress(); - size_t wp_size = wp->GetByteSize(); - bool wp_read = wp->WatchpointRead(); - bool wp_write = wp->WatchpointWrite(); - uint32_t wp_hw_index = wp->GetHardwareIndex(); - POSIXBreakpointProtocol* reg_ctx = GetPOSIXBreakpointProtocol(); - if (reg_ctx) - wp_set = reg_ctx->SetHardwareWatchpointWithIndex(wp_addr, wp_size, - wp_read, wp_write, - wp_hw_index); - } - return wp_set; -} - -bool -POSIXThread::DisableHardwareWatchpoint(Watchpoint *wp) -{ - bool result = false; - if (wp) - { - lldb::RegisterContextSP reg_ctx_sp = GetRegisterContext(); - if (reg_ctx_sp.get()) - result = reg_ctx_sp->ClearHardwareWatchpoint(wp->GetHardwareIndex()); - } - return result; -} - -uint32_t -POSIXThread::NumSupportedHardwareWatchpoints() -{ - lldb::RegisterContextSP reg_ctx_sp = GetRegisterContext(); - if (reg_ctx_sp.get()) - return reg_ctx_sp->NumSupportedHardwareWatchpoints(); - return 0; -} - -uint32_t -POSIXThread::FindVacantWatchpointIndex() -{ - uint32_t hw_index = LLDB_INVALID_INDEX32; - uint32_t num_hw_wps = NumSupportedHardwareWatchpoints(); - uint32_t wp_idx; - POSIXBreakpointProtocol* reg_ctx = GetPOSIXBreakpointProtocol(); - if (reg_ctx) - { - for (wp_idx = 0; wp_idx < num_hw_wps; wp_idx++) - { - if (reg_ctx->IsWatchpointVacant(wp_idx)) - { - hw_index = wp_idx; - break; - } - } - } - return hw_index; -} - -void -POSIXThread::BreakNotify(const ProcessMessage &message) -{ - bool status; - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); - - assert(GetRegisterContext()); - status = GetPOSIXBreakpointProtocol()->UpdateAfterBreakpoint(); - assert(status && "Breakpoint update failed!"); - - // With our register state restored, resolve the breakpoint object - // corresponding to our current PC. - assert(GetRegisterContext()); - lldb::addr_t pc = GetRegisterContext()->GetPC(); - if (log) - log->Printf ("POSIXThread::%s () PC=0x%8.8" PRIx64, __FUNCTION__, pc); - lldb::BreakpointSiteSP bp_site(GetProcess()->GetBreakpointSiteList().FindByAddress(pc)); - - // If the breakpoint is for this thread, then we'll report the hit, but if it is for another thread, - // we create a stop reason with should_stop=false. If there is no breakpoint location, then report - // an invalid stop reason. We don't need to worry about stepping over the breakpoint here, that will - // be taken care of when the thread resumes and notices that there's a breakpoint under the pc. - if (bp_site) - { - lldb::break_id_t bp_id = bp_site->GetID(); - // If we have an operating system plug-in, we might have set a thread specific breakpoint using the - // operating system thread ID, so we can't make any assumptions about the thread ID so we must always - // report the breakpoint regardless of the thread. - if (bp_site->ValidForThisThread(this) || GetProcess()->GetOperatingSystem () != NULL) - SetStopInfo (StopInfo::CreateStopReasonWithBreakpointSiteID(*this, bp_id)); - else - { - const bool should_stop = false; - SetStopInfo (StopInfo::CreateStopReasonWithBreakpointSiteID(*this, bp_id, should_stop)); - } - } - else - SetStopInfo(StopInfoSP()); -} - -void -POSIXThread::WatchNotify(const ProcessMessage &message) -{ - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); - - lldb::addr_t halt_addr = message.GetHWAddress(); - if (log) - log->Printf ("POSIXThread::%s () Hardware Watchpoint Address = 0x%8.8" - PRIx64, __FUNCTION__, halt_addr); - - POSIXBreakpointProtocol* reg_ctx = GetPOSIXBreakpointProtocol(); - if (reg_ctx) - { - uint32_t num_hw_wps = reg_ctx->NumSupportedHardwareWatchpoints(); - uint32_t wp_idx; - for (wp_idx = 0; wp_idx < num_hw_wps; wp_idx++) - { - if (reg_ctx->IsWatchpointHit(wp_idx)) - { - // Clear the watchpoint hit here - reg_ctx->ClearWatchpointHits(); - break; - } - } - - if (wp_idx == num_hw_wps) - return; - - Target &target = GetProcess()->GetTarget(); - lldb::addr_t wp_monitor_addr = reg_ctx->GetWatchpointAddress(wp_idx); - const WatchpointList &wp_list = target.GetWatchpointList(); - lldb::WatchpointSP wp_sp = wp_list.FindByAddress(wp_monitor_addr); - - assert(wp_sp.get() && "No watchpoint found"); - SetStopInfo (StopInfo::CreateStopReasonWithWatchpointID(*this, - wp_sp->GetID())); - } -} - -void -POSIXThread::TraceNotify(const ProcessMessage &message) -{ - POSIXBreakpointProtocol* reg_ctx = GetPOSIXBreakpointProtocol(); - if (reg_ctx) - { - uint32_t num_hw_wps = reg_ctx->NumSupportedHardwareWatchpoints(); - uint32_t wp_idx; - for (wp_idx = 0; wp_idx < num_hw_wps; wp_idx++) - { - if (reg_ctx->IsWatchpointHit(wp_idx)) - { - WatchNotify(message); - return; - } - } - } - - SetStopInfo (StopInfo::CreateStopReasonToTrace(*this)); -} - -void -POSIXThread::LimboNotify(const ProcessMessage &message) -{ - SetStopInfo (lldb::StopInfoSP(new POSIXLimboStopInfo(*this))); -} - -void -POSIXThread::SignalNotify(const ProcessMessage &message) -{ - int signo = message.GetSignal(); - SetStopInfo (StopInfo::CreateStopReasonWithSignal(*this, signo)); -} - -void -POSIXThread::SignalDeliveredNotify(const ProcessMessage &message) -{ - int signo = message.GetSignal(); - SetStopInfo (StopInfo::CreateStopReasonWithSignal(*this, signo)); -} - -void -POSIXThread::CrashNotify(const ProcessMessage &message) -{ - // FIXME: Update stop reason as per bugzilla 14598 - int signo = message.GetSignal(); - - assert(message.GetKind() == ProcessMessage::eCrashMessage); - - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); - if (log) - log->Printf ("POSIXThread::%s () signo = %i, reason = '%s'", - __FUNCTION__, signo, message.PrintCrashReason()); - - SetStopInfo (lldb::StopInfoSP(new POSIXCrashStopInfo(*this, signo, - message.GetCrashReason(), - message.GetFaultAddress()))); -} - -void -POSIXThread::ThreadNotify(const ProcessMessage &message) -{ - SetStopInfo (lldb::StopInfoSP(new POSIXNewThreadStopInfo(*this))); -} - -unsigned -POSIXThread::GetRegisterIndexFromOffset(unsigned offset) -{ - unsigned reg = LLDB_INVALID_REGNUM; - ArchSpec arch = HostInfo::GetArchitecture(); - - switch (arch.GetMachine()) - { - default: - llvm_unreachable("CPU type not supported!"); - break; - - case llvm::Triple::aarch64: - case llvm::Triple::arm: - case llvm::Triple::mips64: - case llvm::Triple::ppc: - case llvm::Triple::ppc64: - case llvm::Triple::x86: - case llvm::Triple::x86_64: - { - POSIXBreakpointProtocol* reg_ctx = GetPOSIXBreakpointProtocol(); - reg = reg_ctx->GetRegisterIndexFromOffset(offset); - } - break; - } - return reg; -} - -void -POSIXThread::ExecNotify(const ProcessMessage &message) -{ - SetStopInfo (StopInfo::CreateStopReasonWithExec(*this)); -} - -const char * -POSIXThread::GetRegisterName(unsigned reg) -{ - const char * name = nullptr; - ArchSpec arch = HostInfo::GetArchitecture(); - - switch (arch.GetMachine()) - { - default: - assert(false && "CPU type not supported!"); - break; - - case llvm::Triple::aarch64: - case llvm::Triple::arm: - case llvm::Triple::mips64: - case llvm::Triple::ppc: - case llvm::Triple::ppc64: - case llvm::Triple::x86: - case llvm::Triple::x86_64: - name = GetRegisterContext()->GetRegisterName(reg); - break; - } - return name; -} - -const char * -POSIXThread::GetRegisterNameFromOffset(unsigned offset) -{ - return GetRegisterName(GetRegisterIndexFromOffset(offset)); -} - Index: lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.h =================================================================== --- lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.h +++ lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.h @@ -1,210 +0,0 @@ -//===-- ProcessPOSIX.h ------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_ProcessPOSIX_H_ -#define liblldb_ProcessPOSIX_H_ - -// C Includes - -// C++ Includes -#include -#include - -// Other libraries and framework includes -#include "lldb/Target/Process.h" -#include "ProcessMessage.h" - -class ProcessMonitor; -class POSIXThread; - -class ProcessPOSIX : - public lldb_private::Process -{ -public: - - //------------------------------------------------------------------ - // Constructors and destructors - //------------------------------------------------------------------ - ProcessPOSIX(lldb_private::Target& target, - lldb_private::Listener &listener, - lldb_private::UnixSignalsSP &unix_signals_sp); - - virtual - ~ProcessPOSIX(); - - //------------------------------------------------------------------ - // Process protocol. - //------------------------------------------------------------------ - void - Finalize() override; - - bool - CanDebug(lldb_private::Target &target, bool plugin_specified_by_name) override; - - lldb_private::Error - WillLaunch(lldb_private::Module *module) override; - - lldb_private::Error - DoAttachToProcessWithID (lldb::pid_t pid, const lldb_private::ProcessAttachInfo &attach_info) override; - - lldb_private::Error - DoLaunch (lldb_private::Module *exe_module, - lldb_private::ProcessLaunchInfo &launch_info) override; - - void - DidLaunch() override; - - lldb_private::Error - DoResume() override; - - lldb_private::Error - DoHalt(bool &caused_stop) override; - - lldb_private::Error - DoDetach(bool keep_stopped) override = 0; - - lldb_private::Error - DoSignal(int signal) override; - - lldb_private::Error - DoDestroy() override; - - void - DoDidExec() override; - - void - RefreshStateAfterStop() override; - - bool - IsAlive() override; - - size_t - DoReadMemory(lldb::addr_t vm_addr, - void *buf, - size_t size, - lldb_private::Error &error) override; - - size_t - DoWriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size, - lldb_private::Error &error) override; - - lldb::addr_t - DoAllocateMemory(size_t size, uint32_t permissions, - lldb_private::Error &error) override; - - lldb_private::Error - DoDeallocateMemory(lldb::addr_t ptr) override; - - virtual size_t - GetSoftwareBreakpointTrapOpcode(lldb_private::BreakpointSite* bp_site); - - lldb_private::Error - EnableBreakpointSite(lldb_private::BreakpointSite *bp_site) override; - - lldb_private::Error - DisableBreakpointSite(lldb_private::BreakpointSite *bp_site) override; - - lldb_private::Error - EnableWatchpoint(lldb_private::Watchpoint *wp, bool notify = true) override; - - lldb_private::Error - DisableWatchpoint(lldb_private::Watchpoint *wp, bool notify = true) override; - - lldb_private::Error - GetWatchpointSupportInfo(uint32_t &num) override; - - lldb_private::Error - GetWatchpointSupportInfo(uint32_t &num, bool &after) override; - - virtual uint32_t - UpdateThreadListIfNeeded(); - - bool - UpdateThreadList(lldb_private::ThreadList &old_thread_list, - lldb_private::ThreadList &new_thread_list) override = 0; - - virtual lldb::ByteOrder - GetByteOrder() const; - - lldb::addr_t - GetImageInfoAddress() override; - - size_t - PutSTDIN(const char *buf, size_t len, lldb_private::Error &error) override; - - const lldb::DataBufferSP - GetAuxvData () override; - - //-------------------------------------------------------------------------- - // ProcessPOSIX internal API. - - /// Registers the given message with this process. - virtual void - SendMessage(const ProcessMessage &message); - - ProcessMonitor & - GetMonitor() { assert(m_monitor); return *m_monitor; } - - lldb_private::FileSpec - GetFileSpec(const lldb_private::FileAction *file_action, - const lldb_private::FileSpec &default_file_spec, - const lldb_private::FileSpec &dbg_pts_file_spec); - - /// Stops all threads in the process. - /// The \p stop_tid parameter indicates the thread which initiated the stop. - virtual void - StopAllThreads(lldb::tid_t stop_tid); - - /// Adds the thread to the list of threads for which we have received the initial stopping signal. - /// The \p stop_tid parameter indicates the thread which the stop happened for. - bool - AddThreadForInitialStopIfNeeded(lldb::tid_t stop_tid); - - bool - WaitingForInitialStop(lldb::tid_t stop_tid); - - virtual POSIXThread * - CreateNewPOSIXThread(lldb_private::Process &process, lldb::tid_t tid); - -protected: - /// Target byte order. - lldb::ByteOrder m_byte_order; - - /// Process monitor; - ProcessMonitor *m_monitor; - - /// The module we are executing. - lldb_private::Module *m_module; - - /// Message queue notifying this instance of inferior process state changes. - lldb_private::Mutex m_message_mutex; - std::queue m_message_queue; - - /// Drive any exit events to completion. - bool m_exit_now; - - /// Returns true if the process has exited. - bool HasExited(); - - /// Returns true if the process is stopped. - bool IsStopped(); - - /// Returns true if at least one running is currently running - bool IsAThreadRunning(); - - typedef std::map MMapMap; - MMapMap m_addr_to_mmap_size; - - typedef std::set ThreadStopSet; - /// Every thread begins with a stop signal. This keeps track - /// of the threads for which we have received the stop signal. - ThreadStopSet m_seen_initial_stop; -}; - -#endif // liblldb_MacOSXProcess_H_ Index: lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.cpp +++ lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.cpp @@ -1,950 +0,0 @@ -//===-- ProcessPOSIX.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 -#include - -// C++ Includes -// Other libraries and framework includes -#include "lldb/Breakpoint/BreakpointLocation.h" -#include "lldb/Breakpoint/Watchpoint.h" -#include "lldb/Core/Module.h" -#include "lldb/Core/ModuleSpec.h" -#include "lldb/Core/PluginManager.h" -#include "lldb/Core/State.h" -#include "lldb/Host/FileSpec.h" -#include "lldb/Host/Host.h" -#include "lldb/Symbol/ObjectFile.h" -#include "lldb/Target/DynamicLoader.h" -#include "lldb/Target/Platform.h" -#include "lldb/Target/Target.h" - -#include "ProcessPOSIX.h" -#include "ProcessPOSIXLog.h" -#include "Plugins/Process/Utility/InferiorCallPOSIX.h" -#include "Plugins/Process/Linux/ProcessMonitor.h" -#include "POSIXThread.h" - -#include "lldb/Host/posix/Fcntl.h" - -using namespace lldb; -using namespace lldb_private; - -//------------------------------------------------------------------------------ -// Constructors and destructors. - -ProcessPOSIX::ProcessPOSIX(Target& target, Listener &listener, UnixSignalsSP &unix_signals_sp) - : Process(target, listener, unix_signals_sp), - m_byte_order(lldb::endian::InlHostByteOrder()), - m_monitor(NULL), - m_module(NULL), - m_message_mutex (Mutex::eMutexTypeRecursive), - m_exit_now(false), - m_seen_initial_stop() -{ - // FIXME: Putting this code in the ctor and saving the byte order in a - // member variable is a hack to avoid const qual issues in GetByteOrder. - lldb::ModuleSP module = GetTarget().GetExecutableModule(); - if (module && module->GetObjectFile()) - m_byte_order = module->GetObjectFile()->GetByteOrder(); -} - -ProcessPOSIX::~ProcessPOSIX() -{ - delete m_monitor; -} - -//------------------------------------------------------------------------------ -// Process protocol. -void -ProcessPOSIX::Finalize() -{ - Process::Finalize(); - - if (m_monitor) - m_monitor->StopMonitor(); -} - -bool -ProcessPOSIX::CanDebug(Target &target, bool plugin_specified_by_name) -{ - // For now we are just making sure the file exists for a given module - ModuleSP exe_module_sp(target.GetExecutableModule()); - if (exe_module_sp.get()) - return exe_module_sp->GetFileSpec().Exists(); - // If there is no executable module, we return true since we might be preparing to attach. - return true; -} - -Error -ProcessPOSIX::DoAttachToProcessWithID (lldb::pid_t pid, const ProcessAttachInfo &attach_info) -{ - Error error; - assert(m_monitor == NULL); - - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); - if (log && log->GetMask().Test(POSIX_LOG_VERBOSE)) - log->Printf ("ProcessPOSIX::%s(pid = %" PRIi64 ")", __FUNCTION__, GetID()); - - m_monitor = new ProcessMonitor(this, pid, error); - - if (!error.Success()) - return error; - - PlatformSP platform_sp (m_target.GetPlatform ()); - assert (platform_sp.get()); - if (!platform_sp) - return error; // FIXME: Detatch? - - // Find out what we can about this process - ProcessInstanceInfo process_info; - platform_sp->GetProcessInfo (pid, process_info); - - // Resolve the executable module - ModuleSP exe_module_sp; - FileSpecList executable_search_paths (Target::GetDefaultExecutableSearchPaths()); - ModuleSpec exe_module_spec(process_info.GetExecutableFile(), m_target.GetArchitecture()); - error = platform_sp->ResolveExecutable(exe_module_spec, - exe_module_sp, - executable_search_paths.GetSize() ? &executable_search_paths : NULL); - if (!error.Success()) - return error; - - // Fix the target architecture if necessary - const ArchSpec &module_arch = exe_module_sp->GetArchitecture(); - if (module_arch.IsValid() && !m_target.GetArchitecture().IsExactMatch(module_arch)) - m_target.SetArchitecture(module_arch); - - // Initialize the target module list - m_target.SetExecutableModule (exe_module_sp, true); - - SetSTDIOFileDescriptor(m_monitor->GetTerminalFD()); - - SetID(pid); - - return error; -} - -Error -ProcessPOSIX::WillLaunch(Module* module) -{ - Error error; - return error; -} - -FileSpec -ProcessPOSIX::GetFileSpec(const lldb_private::FileAction *file_action, - const FileSpec &default_file_spec, - const FileSpec &dbg_pts_file_spec) -{ - FileSpec file_spec{}; - - if (file_action && file_action->GetAction() == FileAction::eFileActionOpen) - { - file_spec = file_action->GetFileSpec(); - // By default the stdio paths passed in will be pseudo-terminal - // (/dev/pts). If so, convert to using a different default path - // instead to redirect I/O to the debugger console. This should - // also handle user overrides to /dev/null or a different file. - if (!file_spec || file_spec == dbg_pts_file_spec) - file_spec = default_file_spec; - } - return file_spec; -} - -Error -ProcessPOSIX::DoLaunch (Module *module, - ProcessLaunchInfo &launch_info) -{ - Error error; - assert(m_monitor == NULL); - - FileSpec working_dir = launch_info.GetWorkingDirectory(); - if (working_dir && - (!working_dir.ResolvePath() || - working_dir.GetFileType() != FileSpec::eFileTypeDirectory)) - { - error.SetErrorStringWithFormat("No such file or directory: %s", - working_dir.GetCString()); - return error; - } - - SetPrivateState(eStateLaunching); - - const lldb_private::FileAction *file_action; - - // Default of empty will mean to use existing open file descriptors - FileSpec stdin_file_spec{}; - FileSpec stdout_file_spec{}; - FileSpec stderr_file_spec{}; - - const FileSpec dbg_pts_file_spec{launch_info.GetPTY().GetSlaveName(NULL,0), false}; - - file_action = launch_info.GetFileActionForFD (STDIN_FILENO); - stdin_file_spec = GetFileSpec(file_action, stdin_file_spec, dbg_pts_file_spec); - - file_action = launch_info.GetFileActionForFD (STDOUT_FILENO); - stdout_file_spec = GetFileSpec(file_action, stdout_file_spec, dbg_pts_file_spec); - - file_action = launch_info.GetFileActionForFD (STDERR_FILENO); - stderr_file_spec = GetFileSpec(file_action, stderr_file_spec, dbg_pts_file_spec); - - m_monitor = new ProcessMonitor(this, - module, - launch_info.GetArguments().GetConstArgumentVector(), - launch_info.GetEnvironmentEntries().GetConstArgumentVector(), - stdin_file_spec, - stdout_file_spec, - stderr_file_spec, - working_dir, - launch_info, - error); - - m_module = module; - - if (!error.Success()) - return error; - - int terminal = m_monitor->GetTerminalFD(); - if (terminal >= 0) { - // The reader thread will close the file descriptor when done, so we pass it a copy. - int stdio = fcntl(terminal, F_DUPFD_CLOEXEC, 0); - if (stdio == -1) { - error.SetErrorToErrno(); - return error; - } - SetSTDIOFileDescriptor(stdio); - } - - SetID(m_monitor->GetPID()); - return error; -} - -void -ProcessPOSIX::DidLaunch() -{ -} - -Error -ProcessPOSIX::DoResume() -{ - StateType state = GetPrivateState(); - - assert(state == eStateStopped); - - SetPrivateState(eStateRunning); - - bool did_resume = false; - - Mutex::Locker lock(m_thread_list.GetMutex()); - - uint32_t thread_count = m_thread_list.GetSize(false); - for (uint32_t i = 0; i < thread_count; ++i) - { - POSIXThread *thread = static_cast( - m_thread_list.GetThreadAtIndex(i, false).get()); - did_resume = thread->Resume() || did_resume; - } - assert(did_resume && "Process resume failed!"); - - return Error(); -} - -addr_t -ProcessPOSIX::GetImageInfoAddress() -{ - Target *target = &GetTarget(); - ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile(); - Address addr = obj_file->GetImageInfoAddress(target); - - if (addr.IsValid()) - return addr.GetLoadAddress(target); - return LLDB_INVALID_ADDRESS; -} - -Error -ProcessPOSIX::DoHalt(bool &caused_stop) -{ - Error error; - - if (IsStopped()) - { - caused_stop = false; - } - else if (kill(GetID(), SIGSTOP)) - { - caused_stop = false; - error.SetErrorToErrno(); - } - else - { - caused_stop = true; - } - return error; -} - -Error -ProcessPOSIX::DoSignal(int signal) -{ - Error error; - - if (kill(GetID(), signal)) - error.SetErrorToErrno(); - - return error; -} - -Error -ProcessPOSIX::DoDestroy() -{ - Error error; - - if (!HasExited()) - { - assert(m_monitor); - m_exit_now = true; - if (GetID() == LLDB_INVALID_PROCESS_ID) - { - error.SetErrorString("invalid process id"); - return error; - } - if (!m_monitor->Kill()) - { - error.SetErrorToErrno(); - return error; - } - - SetPrivateState(eStateExited); - } - - return error; -} - -void -ProcessPOSIX::DoDidExec() -{ - Target *target = &GetTarget(); - if (target) - { - PlatformSP platform_sp (target->GetPlatform()); - assert (platform_sp.get()); - if (platform_sp) - { - ProcessInstanceInfo process_info; - platform_sp->GetProcessInfo(GetID(), process_info); - ModuleSP exe_module_sp; - ModuleSpec exe_module_spec(process_info.GetExecutableFile(), target->GetArchitecture()); - FileSpecList executable_search_paths (Target::GetDefaultExecutableSearchPaths()); - Error error = platform_sp->ResolveExecutable(exe_module_spec, - exe_module_sp, - executable_search_paths.GetSize() ? &executable_search_paths : NULL); - if (!error.Success()) - return; - target->SetExecutableModule(exe_module_sp, true); - } - } -} - -void -ProcessPOSIX::SendMessage(const ProcessMessage &message) -{ - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); - - Mutex::Locker lock(m_message_mutex); - - Mutex::Locker thread_lock(m_thread_list.GetMutex()); - - POSIXThread *thread = static_cast( - m_thread_list.FindThreadByID(message.GetTID(), false).get()); - - switch (message.GetKind()) - { - case ProcessMessage::eInvalidMessage: - return; - - case ProcessMessage::eAttachMessage: - SetPrivateState(eStateStopped); - return; - - case ProcessMessage::eLimboMessage: - assert(thread); - thread->SetState(eStateStopped); - if (message.GetTID() == GetID()) - { - m_exit_status = message.GetExitStatus(); - if (m_exit_now) - { - SetPrivateState(eStateExited); - m_monitor->Detach(GetID()); - } - else - { - StopAllThreads(message.GetTID()); - SetPrivateState(eStateStopped); - } - } - else - { - StopAllThreads(message.GetTID()); - SetPrivateState(eStateStopped); - } - break; - - case ProcessMessage::eExitMessage: - if (thread != nullptr) - thread->SetState(eStateExited); - else - { - if (log) - log->Warning ("ProcessPOSIX::%s eExitMessage for TID %" PRIu64 " failed to find a thread to mark as eStateExited, ignoring", __FUNCTION__, message.GetTID ()); - } - - // FIXME: I'm not sure we need to do this. - if (message.GetTID() == GetID()) - { - SetExitStatus(message.GetExitStatus(), NULL); - } - else if (!IsAThreadRunning()) - SetPrivateState(eStateStopped); - break; - - case ProcessMessage::eSignalMessage: - case ProcessMessage::eSignalDeliveredMessage: - if (message.GetSignal() == SIGSTOP && - AddThreadForInitialStopIfNeeded(message.GetTID())) - return; - // Intentional fall-through - - case ProcessMessage::eBreakpointMessage: - case ProcessMessage::eTraceMessage: - case ProcessMessage::eWatchpointMessage: - case ProcessMessage::eCrashMessage: - assert(thread); - thread->SetState(eStateStopped); - StopAllThreads(message.GetTID()); - SetPrivateState(eStateStopped); - break; - - case ProcessMessage::eNewThreadMessage: - { - lldb::tid_t new_tid = message.GetChildTID(); - if (WaitingForInitialStop(new_tid)) - { - m_monitor->WaitForInitialTIDStop(new_tid); - } - assert(thread); - thread->SetState(eStateStopped); - StopAllThreads(message.GetTID()); - SetPrivateState(eStateStopped); - break; - } - - case ProcessMessage::eExecMessage: - { - assert(thread); - thread->SetState(eStateStopped); - StopAllThreads(message.GetTID()); - SetPrivateState(eStateStopped); - break; - } - } - - - m_message_queue.push(message); -} - -void -ProcessPOSIX::StopAllThreads(lldb::tid_t stop_tid) -{ - // FIXME: Will this work the same way on FreeBSD and Linux? -} - -bool -ProcessPOSIX::AddThreadForInitialStopIfNeeded(lldb::tid_t stop_tid) -{ - bool added_to_set = false; - ThreadStopSet::iterator it = m_seen_initial_stop.find(stop_tid); - if (it == m_seen_initial_stop.end()) - { - m_seen_initial_stop.insert(stop_tid); - added_to_set = true; - } - return added_to_set; -} - -bool -ProcessPOSIX::WaitingForInitialStop(lldb::tid_t stop_tid) -{ - return (m_seen_initial_stop.find(stop_tid) == m_seen_initial_stop.end()); -} - -POSIXThread * -ProcessPOSIX::CreateNewPOSIXThread(lldb_private::Process &process, lldb::tid_t tid) -{ - return new POSIXThread(process, tid); -} - -void -ProcessPOSIX::RefreshStateAfterStop() -{ - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); - if (log && log->GetMask().Test(POSIX_LOG_VERBOSE)) - log->Printf ("ProcessPOSIX::%s(), message_queue size = %d", __FUNCTION__, (int)m_message_queue.size()); - - Mutex::Locker lock(m_message_mutex); - - // This method used to only handle one message. Changing it to loop allows - // it to handle the case where we hit a breakpoint while handling a different - // breakpoint. - while (!m_message_queue.empty()) - { - ProcessMessage &message = m_message_queue.front(); - - // Resolve the thread this message corresponds to and pass it along. - lldb::tid_t tid = message.GetTID(); - if (log) - log->Printf ("ProcessPOSIX::%s(), message_queue size = %d, pid = %" PRIi64, __FUNCTION__, (int)m_message_queue.size(), tid); - - if (message.GetKind() == ProcessMessage::eNewThreadMessage) - { - if (log) - log->Printf ("ProcessPOSIX::%s() adding thread, tid = %" PRIi64, __FUNCTION__, message.GetChildTID()); - lldb::tid_t child_tid = message.GetChildTID(); - ThreadSP thread_sp; - thread_sp.reset(CreateNewPOSIXThread(*this, child_tid)); - - Mutex::Locker lock(m_thread_list.GetMutex()); - - m_thread_list.AddThread(thread_sp); - } - - m_thread_list.RefreshStateAfterStop(); - - POSIXThread *thread = static_cast( - GetThreadList().FindThreadByID(tid, false).get()); - if (thread) - thread->Notify(message); - - if (message.GetKind() == ProcessMessage::eExitMessage) - { - // FIXME: We should tell the user about this, but the limbo message is probably better for that. - if (log) - log->Printf ("ProcessPOSIX::%s() removing thread, tid = %" PRIi64, __FUNCTION__, tid); - - Mutex::Locker lock(m_thread_list.GetMutex()); - - ThreadSP thread_sp = m_thread_list.RemoveThreadByID(tid, false); - thread_sp.reset(); - m_seen_initial_stop.erase(tid); - } - - m_message_queue.pop(); - } -} - -bool -ProcessPOSIX::IsAlive() -{ - StateType state = GetPrivateState(); - return state != eStateDetached - && state != eStateExited - && state != eStateInvalid - && state != eStateUnloaded; -} - -size_t -ProcessPOSIX::DoReadMemory(addr_t vm_addr, - void *buf, size_t size, Error &error) -{ - assert(m_monitor); - return m_monitor->ReadMemory(vm_addr, buf, size, error); -} - -size_t -ProcessPOSIX::DoWriteMemory(addr_t vm_addr, const void *buf, size_t size, - Error &error) -{ - assert(m_monitor); - return m_monitor->WriteMemory(vm_addr, buf, size, error); -} - -addr_t -ProcessPOSIX::DoAllocateMemory(size_t size, uint32_t permissions, - Error &error) -{ - addr_t allocated_addr = LLDB_INVALID_ADDRESS; - - unsigned prot = 0; - if (permissions & lldb::ePermissionsReadable) - prot |= eMmapProtRead; - if (permissions & lldb::ePermissionsWritable) - prot |= eMmapProtWrite; - if (permissions & lldb::ePermissionsExecutable) - prot |= eMmapProtExec; - - if (InferiorCallMmap(this, allocated_addr, 0, size, prot, - eMmapFlagsAnon | eMmapFlagsPrivate, -1, 0)) { - m_addr_to_mmap_size[allocated_addr] = size; - error.Clear(); - } else { - allocated_addr = LLDB_INVALID_ADDRESS; - error.SetErrorStringWithFormat("unable to allocate %zu bytes of memory with permissions %s", size, GetPermissionsAsCString (permissions)); - } - - return allocated_addr; -} - -Error -ProcessPOSIX::DoDeallocateMemory(lldb::addr_t addr) -{ - Error error; - MMapMap::iterator pos = m_addr_to_mmap_size.find(addr); - if (pos != m_addr_to_mmap_size.end() && - InferiorCallMunmap(this, addr, pos->second)) - m_addr_to_mmap_size.erase (pos); - else - error.SetErrorStringWithFormat("unable to deallocate memory at 0x%" PRIx64, addr); - - return error; -} - -size_t -ProcessPOSIX::GetSoftwareBreakpointTrapOpcode(BreakpointSite* bp_site) -{ - static const uint8_t g_aarch64_opcode[] = { 0x00, 0x00, 0x20, 0xD4 }; - static const uint8_t g_i386_opcode[] = { 0xCC }; - - ArchSpec arch = GetTarget().GetArchitecture(); - const uint8_t *opcode = NULL; - size_t opcode_size = 0; - - switch (arch.GetMachine()) - { - default: - assert(false && "CPU type not supported!"); - break; - - case llvm::Triple::arm: - { - // The ARM reference recommends the use of 0xe7fddefe and 0xdefe - // but the linux kernel does otherwise. - static const uint8_t g_arm_breakpoint_opcode[] = { 0xf0, 0x01, 0xf0, 0xe7 }; - static const uint8_t g_thumb_breakpoint_opcode[] = { 0x01, 0xde }; - - lldb::BreakpointLocationSP bp_loc_sp (bp_site->GetOwnerAtIndex (0)); - AddressClass addr_class = eAddressClassUnknown; - - if (bp_loc_sp) - addr_class = bp_loc_sp->GetAddress ().GetAddressClass (); - - if (addr_class == eAddressClassCodeAlternateISA - || (addr_class == eAddressClassUnknown - && bp_loc_sp->GetAddress().GetOffset() & 1)) - { - opcode = g_thumb_breakpoint_opcode; - opcode_size = sizeof(g_thumb_breakpoint_opcode); - } - else - { - opcode = g_arm_breakpoint_opcode; - opcode_size = sizeof(g_arm_breakpoint_opcode); - } - } - break; - case llvm::Triple::aarch64: - opcode = g_aarch64_opcode; - opcode_size = sizeof(g_aarch64_opcode); - break; - - case llvm::Triple::x86: - case llvm::Triple::x86_64: - opcode = g_i386_opcode; - opcode_size = sizeof(g_i386_opcode); - break; - } - - bp_site->SetTrapOpcode(opcode, opcode_size); - return opcode_size; -} - -Error -ProcessPOSIX::EnableBreakpointSite(BreakpointSite *bp_site) -{ - return EnableSoftwareBreakpoint(bp_site); -} - -Error -ProcessPOSIX::DisableBreakpointSite(BreakpointSite *bp_site) -{ - return DisableSoftwareBreakpoint(bp_site); -} - -Error -ProcessPOSIX::EnableWatchpoint(Watchpoint *wp, bool notify) -{ - Error error; - if (wp) - { - user_id_t watchID = wp->GetID(); - addr_t addr = wp->GetLoadAddress(); - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - if (log) - log->Printf ("ProcessPOSIX::EnableWatchpoint(watchID = %" PRIu64 ")", - watchID); - if (wp->IsEnabled()) - { - if (log) - log->Printf("ProcessPOSIX::EnableWatchpoint(watchID = %" PRIu64 - ") addr = 0x%8.8" PRIx64 ": watchpoint already enabled.", - watchID, (uint64_t)addr); - return error; - } - - // Try to find a vacant watchpoint slot in the inferiors' main thread - uint32_t wp_hw_index = LLDB_INVALID_INDEX32; - Mutex::Locker lock(m_thread_list.GetMutex()); - POSIXThread *thread = static_cast( - m_thread_list.GetThreadAtIndex(0, false).get()); - - if (thread) - wp_hw_index = thread->FindVacantWatchpointIndex(); - - if (wp_hw_index == LLDB_INVALID_INDEX32) - { - error.SetErrorString("Setting hardware watchpoint failed."); - } - else - { - wp->SetHardwareIndex(wp_hw_index); - bool wp_enabled = true; - uint32_t thread_count = m_thread_list.GetSize(false); - for (uint32_t i = 0; i < thread_count; ++i) - { - thread = static_cast( - m_thread_list.GetThreadAtIndex(i, false).get()); - if (thread) - wp_enabled &= thread->EnableHardwareWatchpoint(wp); - else - wp_enabled = false; - } - if (wp_enabled) - { - wp->SetEnabled(true, notify); - return error; - } - else - { - // Watchpoint enabling failed on at least one - // of the threads so roll back all of them - DisableWatchpoint(wp, false); - error.SetErrorString("Setting hardware watchpoint failed"); - } - } - } - else - error.SetErrorString("Watchpoint argument was NULL."); - return error; -} - -Error -ProcessPOSIX::DisableWatchpoint(Watchpoint *wp, bool notify) -{ - Error error; - if (wp) - { - user_id_t watchID = wp->GetID(); - addr_t addr = wp->GetLoadAddress(); - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - if (log) - log->Printf("ProcessPOSIX::DisableWatchpoint(watchID = %" PRIu64 ")", - watchID); - if (!wp->IsEnabled()) - { - if (log) - log->Printf("ProcessPOSIX::DisableWatchpoint(watchID = %" PRIu64 - ") addr = 0x%8.8" PRIx64 ": watchpoint already disabled.", - watchID, (uint64_t)addr); - // This is needed (for now) to keep watchpoints disabled correctly - wp->SetEnabled(false, notify); - return error; - } - - if (wp->IsHardware()) - { - bool wp_disabled = true; - Mutex::Locker lock(m_thread_list.GetMutex()); - uint32_t thread_count = m_thread_list.GetSize(false); - for (uint32_t i = 0; i < thread_count; ++i) - { - POSIXThread *thread = static_cast( - m_thread_list.GetThreadAtIndex(i, false).get()); - if (thread) - wp_disabled &= thread->DisableHardwareWatchpoint(wp); - else - wp_disabled = false; - } - if (wp_disabled) - { - wp->SetHardwareIndex(LLDB_INVALID_INDEX32); - wp->SetEnabled(false, notify); - return error; - } - else - error.SetErrorString("Disabling hardware watchpoint failed"); - } - } - else - error.SetErrorString("Watchpoint argument was NULL."); - return error; -} - -Error -ProcessPOSIX::GetWatchpointSupportInfo(uint32_t &num) -{ - Error error; - Mutex::Locker lock(m_thread_list.GetMutex()); - POSIXThread *thread = static_cast( - m_thread_list.GetThreadAtIndex(0, false).get()); - if (thread) - num = thread->NumSupportedHardwareWatchpoints(); - else - error.SetErrorString("Process does not exist."); - return error; -} - -Error -ProcessPOSIX::GetWatchpointSupportInfo(uint32_t &num, bool &after) -{ - Error error = GetWatchpointSupportInfo(num); - // Watchpoints trigger and halt the inferior after - // the corresponding instruction has been executed. - after = true; - return error; -} - -uint32_t -ProcessPOSIX::UpdateThreadListIfNeeded() -{ - Mutex::Locker lock(m_thread_list.GetMutex()); - // Do not allow recursive updates. - return m_thread_list.GetSize(false); -} - -bool -ProcessPOSIX::UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_thread_list) -{ - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); - if (log && log->GetMask().Test(POSIX_LOG_VERBOSE)) - log->Printf ("ProcessPOSIX::%s() (pid = %" PRIi64 ")", __FUNCTION__, GetID()); - - bool has_updated = false; - // Update the process thread list with this new thread. - // FIXME: We should be using tid, not pid. - assert(m_monitor); - ThreadSP thread_sp (old_thread_list.FindThreadByID (GetID(), false)); - if (!thread_sp) { - thread_sp.reset(CreateNewPOSIXThread(*this, GetID())); - has_updated = true; - } - - if (log && log->GetMask().Test(POSIX_LOG_VERBOSE)) - log->Printf ("ProcessPOSIX::%s() updated pid = %" PRIi64, __FUNCTION__, GetID()); - new_thread_list.AddThread(thread_sp); - - return has_updated; // the list has been updated -} - -ByteOrder -ProcessPOSIX::GetByteOrder() const -{ - // FIXME: We should be able to extract this value directly. See comment in - // ProcessPOSIX(). - return m_byte_order; -} - -size_t -ProcessPOSIX::PutSTDIN(const char *buf, size_t len, Error &error) -{ - ssize_t status; - if ((status = write(m_monitor->GetTerminalFD(), buf, len)) < 0) - { - error.SetErrorToErrno(); - return 0; - } - return status; -} - -//------------------------------------------------------------------------------ -// Utility functions. - -bool -ProcessPOSIX::HasExited() -{ - switch (GetPrivateState()) - { - default: - break; - - case eStateDetached: - case eStateExited: - return true; - } - - return false; -} - -bool -ProcessPOSIX::IsStopped() -{ - switch (GetPrivateState()) - { - default: - break; - - case eStateStopped: - case eStateCrashed: - case eStateSuspended: - return true; - } - - return false; -} - -bool -ProcessPOSIX::IsAThreadRunning() -{ - bool is_running = false; - Mutex::Locker lock(m_thread_list.GetMutex()); - uint32_t thread_count = m_thread_list.GetSize(false); - for (uint32_t i = 0; i < thread_count; ++i) - { - POSIXThread *thread = static_cast( - m_thread_list.GetThreadAtIndex(i, false).get()); - StateType thread_state = thread->GetState(); - if (thread_state == eStateRunning || thread_state == eStateStepping) - { - is_running = true; - break; - } - } - return is_running; -} - -const DataBufferSP -ProcessPOSIX::GetAuxvData () -{ - // If we're the local platform, we can ask the host for auxv data. - PlatformSP platform_sp = m_target.GetPlatform (); - if (platform_sp && platform_sp->IsHost ()) - return lldb_private::Host::GetAuxvData(this); - - // Somewhat unexpected - the process is not running locally or we don't have a platform. - assert (false && "no platform or not the host - how did we get here with ProcessPOSIX?"); - return DataBufferSP (); -} Index: lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp +++ lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp @@ -14,7 +14,6 @@ #include "lldb/Interpreter/Args.h" #include "lldb/Core/StreamFile.h" -#include "ProcessPOSIX.h" #include "ProcessPOSIXLog.h" using namespace lldb; Index: lldb/trunk/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm.h =================================================================== --- lldb/trunk/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm.h +++ lldb/trunk/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm.h @@ -1,95 +0,0 @@ -//===-- RegisterContextPOSIXProcessMonitor_arm.h --------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_RegisterContextPOSIXProcessMonitor_arm_H_ -#define liblldb_RegisterContextPOSIXProcessMonitor_arm_H_ - -#include "Plugins/Process/Utility/RegisterContextPOSIX_arm.h" - -class RegisterContextPOSIXProcessMonitor_arm: - public RegisterContextPOSIX_arm, - public POSIXBreakpointProtocol -{ -public: - RegisterContextPOSIXProcessMonitor_arm(lldb_private::Thread &thread, - uint32_t concrete_frame_idx, - lldb_private::RegisterInfoInterface *register_info); - -protected: - bool - ReadGPR(); - - bool - ReadFPR(); - - bool - WriteGPR(); - - bool - WriteFPR(); - - // lldb_private::RegisterContext - bool - ReadRegister(const unsigned reg, lldb_private::RegisterValue &value); - - bool - WriteRegister(const unsigned reg, const lldb_private::RegisterValue &value); - - bool - ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value); - - bool - WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value); - - bool - ReadAllRegisterValues(lldb::DataBufferSP &data_sp); - - bool - WriteAllRegisterValues(const lldb::DataBufferSP &data_sp); - - uint32_t - SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, bool write); - - bool - ClearHardwareWatchpoint(uint32_t hw_index); - - bool - HardwareSingleStep(bool enable); - - // POSIXBreakpointProtocol - bool - UpdateAfterBreakpoint(); - - unsigned - GetRegisterIndexFromOffset(unsigned offset); - - bool - IsWatchpointHit(uint32_t hw_index); - - bool - ClearWatchpointHits(); - - lldb::addr_t - GetWatchpointAddress(uint32_t hw_index); - - bool - IsWatchpointVacant(uint32_t hw_index); - - bool - SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, bool read, bool write, uint32_t hw_index); - - uint32_t - NumSupportedHardwareWatchpoints(); - -private: - ProcessMonitor & - GetMonitor(); -}; - -#endif Index: lldb/trunk/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm.cpp +++ lldb/trunk/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm.cpp @@ -1,322 +0,0 @@ -//===-- RegisterContextPOSIXProcessMonitor_arm.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/Core/DataBufferHeap.h" -#include "lldb/Core/RegisterValue.h" -#include "lldb/Target/Thread.h" - -#include "RegisterContextPOSIX_arm.h" -#include "ProcessPOSIX.h" -#include "RegisterContextPOSIXProcessMonitor_arm.h" -#include "ProcessMonitor.h" - -using namespace lldb_private; -using namespace lldb; - -#define REG_CONTEXT_SIZE (GetGPRSize()) - -RegisterContextPOSIXProcessMonitor_arm::RegisterContextPOSIXProcessMonitor_arm(Thread &thread, - uint32_t concrete_frame_idx, - lldb_private::RegisterInfoInterface *register_info) - : RegisterContextPOSIX_arm(thread, concrete_frame_idx, register_info) -{ -} - -ProcessMonitor & -RegisterContextPOSIXProcessMonitor_arm::GetMonitor() -{ - ProcessSP base = CalculateProcess(); - ProcessPOSIX *process = static_cast(base.get()); - return process->GetMonitor(); -} - -bool -RegisterContextPOSIXProcessMonitor_arm::ReadGPR() -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.ReadGPR(m_thread.GetID(), &m_gpr_arm, GetGPRSize()); -} - -bool -RegisterContextPOSIXProcessMonitor_arm::ReadFPR() -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.ReadFPR(m_thread.GetID(), &m_fpr, sizeof(m_fpr)); -} - -bool -RegisterContextPOSIXProcessMonitor_arm::WriteGPR() -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.WriteGPR(m_thread.GetID(), &m_gpr_arm, GetGPRSize()); -} - -bool -RegisterContextPOSIXProcessMonitor_arm::WriteFPR() -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.WriteFPR(m_thread.GetID(), &m_fpr, sizeof(m_fpr)); -} - -bool -RegisterContextPOSIXProcessMonitor_arm::ReadRegister(const unsigned reg, - RegisterValue &value) -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.ReadRegisterValue(m_thread.GetID(), - GetRegisterOffset(reg), - GetRegisterName(reg), - GetRegisterSize(reg), - value); -} - -bool -RegisterContextPOSIXProcessMonitor_arm::WriteRegister(const unsigned reg, - const RegisterValue &value) -{ - unsigned reg_to_write = reg; - RegisterValue value_to_write = value; - - // Check if this is a subregister of a full register. - const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); - if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) - { - RegisterValue full_value; - uint32_t full_reg = reg_info->invalidate_regs[0]; - const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg); - - // Read the full register. - if (ReadRegister(full_reg_info, full_value)) - { - Error error; - ByteOrder byte_order = GetByteOrder(); - uint8_t dst[RegisterValue::kMaxRegisterByteSize]; - - // Get the bytes for the full register. - const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info, - dst, - sizeof(dst), - byte_order, - error); - if (error.Success() && dest_size) - { - uint8_t src[RegisterValue::kMaxRegisterByteSize]; - - // Get the bytes for the source data. - const uint32_t src_size = value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error); - if (error.Success() && src_size && (src_size < dest_size)) - { - // Copy the src bytes to the destination. - memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size); - // Set this full register as the value to write. - value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order); - value_to_write.SetType(full_reg_info); - reg_to_write = full_reg; - } - } - } - } - - ProcessMonitor &monitor = GetMonitor(); - return monitor.WriteRegisterValue(m_thread.GetID(), - GetRegisterOffset(reg_to_write), - GetRegisterName(reg_to_write), - value_to_write); -} - -bool -RegisterContextPOSIXProcessMonitor_arm::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value) -{ - if (!reg_info) - return false; - - const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - - if (IsFPR(reg)) - { - if (!ReadFPR()) - return false; - } - else - { - return ReadRegister(reg, value); - } - - // Get pointer to m_fpr variable and set the data from it. - assert (reg_info->byte_offset < sizeof m_fpr); - uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset; - switch (reg_info->byte_size) - { - case 2: - value.SetUInt16(*(uint16_t *)src); - return true; - case 4: - value.SetUInt32(*(uint32_t *)src); - return true; - case 8: - value.SetUInt64(*(uint64_t *)src); - return true; - default: - assert(false && "Unhandled data size."); - return false; - } -} - -bool -RegisterContextPOSIXProcessMonitor_arm::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value) -{ - const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - - if (IsGPR(reg)) - { - return WriteRegister(reg, value); - } - else if (IsFPR(reg)) - { - return WriteFPR(); - } - - return false; -} - -bool -RegisterContextPOSIXProcessMonitor_arm::ReadAllRegisterValues(DataBufferSP &data_sp) -{ - bool success = false; - data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0)); - if (data_sp && ReadGPR () && ReadFPR ()) - { - uint8_t *dst = data_sp->GetBytes(); - success = dst != 0; - - if (success) - { - ::memcpy (dst, &m_gpr_arm, GetGPRSize()); - dst += GetGPRSize(); - ::memcpy (dst, &m_fpr, sizeof(m_fpr)); - } - } - return success; -} - -bool -RegisterContextPOSIXProcessMonitor_arm::WriteAllRegisterValues(const DataBufferSP &data_sp) -{ - bool success = false; - if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) - { - uint8_t *src = data_sp->GetBytes(); - if (src) - { - ::memcpy (&m_gpr_arm, src, GetGPRSize()); - - if (WriteGPR()) - { - src += GetGPRSize(); - ::memcpy (&m_fpr, src, sizeof(m_fpr)); - - success = WriteFPR(); - } - } - } - return success; -} - -uint32_t -RegisterContextPOSIXProcessMonitor_arm::SetHardwareWatchpoint(addr_t addr, size_t size, - bool read, bool write) -{ - const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); - uint32_t hw_index; - - for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index) - { - if (IsWatchpointVacant(hw_index)) - return SetHardwareWatchpointWithIndex(addr, size, - read, write, - hw_index); - } - - return LLDB_INVALID_INDEX32; -} - -bool -RegisterContextPOSIXProcessMonitor_arm::ClearHardwareWatchpoint(uint32_t hw_index) -{ - return false; -} - -bool -RegisterContextPOSIXProcessMonitor_arm::HardwareSingleStep(bool enable) -{ - return false; -} - -bool -RegisterContextPOSIXProcessMonitor_arm::UpdateAfterBreakpoint() -{ - lldb::addr_t pc; - - if ((pc = GetPC()) == LLDB_INVALID_ADDRESS) - return false; - - return true; -} - -unsigned -RegisterContextPOSIXProcessMonitor_arm::GetRegisterIndexFromOffset(unsigned offset) -{ - unsigned reg; - for (reg = 0; reg < k_num_registers_arm; reg++) - { - if (GetRegisterInfo()[reg].byte_offset == offset) - break; - } - assert(reg < k_num_registers_arm && "Invalid register offset."); - return reg; -} - -bool -RegisterContextPOSIXProcessMonitor_arm::IsWatchpointHit(uint32_t hw_index) -{ - return false; -} - -bool -RegisterContextPOSIXProcessMonitor_arm::ClearWatchpointHits() -{ - return false; -} - -addr_t -RegisterContextPOSIXProcessMonitor_arm::GetWatchpointAddress(uint32_t hw_index) -{ - return LLDB_INVALID_ADDRESS; -} - -bool -RegisterContextPOSIXProcessMonitor_arm::IsWatchpointVacant(uint32_t hw_index) -{ - return false; -} - -bool -RegisterContextPOSIXProcessMonitor_arm::SetHardwareWatchpointWithIndex(addr_t addr, size_t size, - bool read, bool write, - uint32_t hw_index) -{ - return false; -} - -uint32_t -RegisterContextPOSIXProcessMonitor_arm::NumSupportedHardwareWatchpoints() -{ - return 0; -} - Index: lldb/trunk/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.h =================================================================== --- lldb/trunk/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.h +++ lldb/trunk/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.h @@ -1,95 +0,0 @@ -//===-- RegisterContextPOSIXProcessMonitor_arm64.h --------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_RegisterContextPOSIXProcessMonitor_arm64_H_ -#define liblldb_RegisterContextPOSIXProcessMonitor_arm64_H_ - -#include "Plugins/Process/Utility/RegisterContextPOSIX_arm64.h" - -class RegisterContextPOSIXProcessMonitor_arm64: - public RegisterContextPOSIX_arm64, - public POSIXBreakpointProtocol -{ -public: - RegisterContextPOSIXProcessMonitor_arm64(lldb_private::Thread &thread, - uint32_t concrete_frame_idx, - lldb_private::RegisterInfoInterface *register_info); - -protected: - bool - ReadGPR(); - - bool - ReadFPR(); - - bool - WriteGPR(); - - bool - WriteFPR(); - - // lldb_private::RegisterContext - bool - ReadRegister(const unsigned reg, lldb_private::RegisterValue &value); - - bool - WriteRegister(const unsigned reg, const lldb_private::RegisterValue &value); - - bool - ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value); - - bool - WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value); - - bool - ReadAllRegisterValues(lldb::DataBufferSP &data_sp); - - bool - WriteAllRegisterValues(const lldb::DataBufferSP &data_sp); - - uint32_t - SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, bool write); - - bool - ClearHardwareWatchpoint(uint32_t hw_index); - - bool - HardwareSingleStep(bool enable); - - // POSIXBreakpointProtocol - bool - UpdateAfterBreakpoint(); - - unsigned - GetRegisterIndexFromOffset(unsigned offset); - - bool - IsWatchpointHit(uint32_t hw_index); - - bool - ClearWatchpointHits(); - - lldb::addr_t - GetWatchpointAddress(uint32_t hw_index); - - bool - IsWatchpointVacant(uint32_t hw_index); - - bool - SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, bool read, bool write, uint32_t hw_index); - - uint32_t - NumSupportedHardwareWatchpoints(); - -private: - ProcessMonitor & - GetMonitor(); -}; - -#endif Index: lldb/trunk/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.cpp +++ lldb/trunk/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.cpp @@ -1,322 +0,0 @@ -//===-- RegisterContextPOSIXProcessMonitor_arm64.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/Core/DataBufferHeap.h" -#include "lldb/Core/RegisterValue.h" -#include "lldb/Target/Thread.h" - -#include "Plugins/Process/Utility/RegisterContextPOSIX_arm64.h" -#include "ProcessPOSIX.h" -#include "RegisterContextPOSIXProcessMonitor_arm64.h" -#include "Plugins/Process/Linux/ProcessMonitor.h" - -#define REG_CONTEXT_SIZE (GetGPRSize()) - -using namespace lldb; -using namespace lldb_private; - -RegisterContextPOSIXProcessMonitor_arm64::RegisterContextPOSIXProcessMonitor_arm64(lldb_private::Thread &thread, - uint32_t concrete_frame_idx, - lldb_private::RegisterInfoInterface *register_info) - : RegisterContextPOSIX_arm64(thread, concrete_frame_idx, register_info) -{ -} - -ProcessMonitor & -RegisterContextPOSIXProcessMonitor_arm64::GetMonitor() -{ - lldb::ProcessSP base = CalculateProcess(); - ProcessPOSIX *process = static_cast(base.get()); - return process->GetMonitor(); -} - -bool -RegisterContextPOSIXProcessMonitor_arm64::ReadGPR() -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.ReadGPR(m_thread.GetID(), &m_gpr_arm64, GetGPRSize()); -} - -bool -RegisterContextPOSIXProcessMonitor_arm64::ReadFPR() -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.ReadFPR(m_thread.GetID(), &m_fpr, sizeof m_fpr); -} - -bool -RegisterContextPOSIXProcessMonitor_arm64::WriteGPR() -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.WriteGPR(m_thread.GetID(), &m_gpr_arm64, GetGPRSize()); -} - -bool -RegisterContextPOSIXProcessMonitor_arm64::WriteFPR() -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.WriteFPR(m_thread.GetID(), &m_fpr, sizeof m_fpr); -} - -bool -RegisterContextPOSIXProcessMonitor_arm64::ReadRegister(const unsigned reg, - lldb_private::RegisterValue &value) -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.ReadRegisterValue(m_thread.GetID(), - GetRegisterOffset(reg), - GetRegisterName(reg), - GetRegisterSize(reg), - value); -} - -bool -RegisterContextPOSIXProcessMonitor_arm64::WriteRegister(const unsigned reg, - const lldb_private::RegisterValue &value) -{ - unsigned reg_to_write = reg; - lldb_private::RegisterValue value_to_write = value; - - // Check if this is a subregister of a full register. - const lldb_private::RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); - if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) - { - lldb_private::RegisterValue full_value; - uint32_t full_reg = reg_info->invalidate_regs[0]; - const lldb_private::RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg); - - // Read the full register. - if (ReadRegister(full_reg_info, full_value)) - { - lldb_private::Error error; - lldb::ByteOrder byte_order = GetByteOrder(); - uint8_t dst[lldb_private::RegisterValue::kMaxRegisterByteSize]; - - // Get the bytes for the full register. - const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info, - dst, - sizeof(dst), - byte_order, - error); - if (error.Success() && dest_size) - { - uint8_t src[lldb_private::RegisterValue::kMaxRegisterByteSize]; - - // Get the bytes for the source data. - const uint32_t src_size = value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error); - if (error.Success() && src_size && (src_size < dest_size)) - { - // Copy the src bytes to the destination. - ::memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size); - // Set this full register as the value to write. - value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order); - value_to_write.SetType(full_reg_info); - reg_to_write = full_reg; - } - } - } - } - - ProcessMonitor &monitor = GetMonitor(); - return monitor.WriteRegisterValue(m_thread.GetID(), - GetRegisterOffset(reg_to_write), - GetRegisterName(reg_to_write), - value_to_write); -} - -bool -RegisterContextPOSIXProcessMonitor_arm64::ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value) -{ - if (!reg_info) - return false; - - const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; - - if (IsFPR(reg)) - { - if (!ReadFPR()) - return false; - } - else - { - uint32_t full_reg = reg; - bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM); - - if (is_subreg) - { - // Read the full aligned 64-bit register. - full_reg = reg_info->invalidate_regs[0]; - } - return ReadRegister(full_reg, value); - } - - // Get pointer to m_fpr variable and set the data from it. - assert (reg_info->byte_offset < sizeof m_fpr); - uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset; - switch (reg_info->byte_size) - { - case 2: - value.SetUInt16(*(uint16_t *)src); - return true; - case 4: - value.SetUInt32(*(uint32_t *)src); - return true; - case 8: - value.SetUInt64(*(uint64_t *)src); - return true; - default: - assert(false && "Unhandled data size."); - return false; - } -} - -bool -RegisterContextPOSIXProcessMonitor_arm64::WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value) -{ - const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; - - if (IsGPR(reg)) - return WriteRegister(reg, value); - - return false; -} - -bool -RegisterContextPOSIXProcessMonitor_arm64::ReadAllRegisterValues(lldb::DataBufferSP &data_sp) -{ - bool success = false; - data_sp.reset (new lldb_private::DataBufferHeap (REG_CONTEXT_SIZE, 0)); - if (data_sp && ReadGPR () && ReadFPR ()) - { - uint8_t *dst = data_sp->GetBytes(); - success = dst != 0; - - if (success) - { - ::memcpy (dst, &m_gpr_arm64, GetGPRSize()); - dst += GetGPRSize(); - ::memcpy (dst, &m_fpr, sizeof m_fpr); - } - } - return success; -} - -bool -RegisterContextPOSIXProcessMonitor_arm64::WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) -{ - bool success = false; - if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) - { - uint8_t *src = data_sp->GetBytes(); - if (src) - { - ::memcpy (&m_gpr_arm64, src, GetGPRSize()); - if (WriteGPR()) { - src += GetGPRSize(); - ::memcpy (&m_fpr, src, sizeof m_fpr); - success = WriteFPR(); - } - } - } - return success; -} - -uint32_t -RegisterContextPOSIXProcessMonitor_arm64::SetHardwareWatchpoint(lldb::addr_t addr, size_t size, - bool read, bool write) -{ - const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); - uint32_t hw_index; - - for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index) - { - if (IsWatchpointVacant(hw_index)) - return SetHardwareWatchpointWithIndex(addr, size, - read, write, - hw_index); - } - - return LLDB_INVALID_INDEX32; -} - -bool -RegisterContextPOSIXProcessMonitor_arm64::ClearHardwareWatchpoint(uint32_t hw_index) -{ - return false; -} - -bool -RegisterContextPOSIXProcessMonitor_arm64::HardwareSingleStep(bool enable) -{ - return false; -} - -bool -RegisterContextPOSIXProcessMonitor_arm64::UpdateAfterBreakpoint() -{ - // PC points one byte past the int3 responsible for the breakpoint. - lldb::addr_t pc; - - if ((pc = GetPC()) == LLDB_INVALID_ADDRESS) - return false; - - SetPC(pc - 1); - return true; -} - -unsigned -RegisterContextPOSIXProcessMonitor_arm64::GetRegisterIndexFromOffset(unsigned offset) -{ - unsigned reg; - for (reg = 0; reg < k_num_registers_arm64; reg++) - { - if (GetRegisterInfo()[reg].byte_offset == offset) - break; - } - assert(reg < k_num_registers_arm64 && "Invalid register offset."); - return reg; -} - -bool -RegisterContextPOSIXProcessMonitor_arm64::IsWatchpointHit(uint32_t hw_index) -{ - return false; -} - -bool -RegisterContextPOSIXProcessMonitor_arm64::ClearWatchpointHits() -{ - return false; -} - -lldb::addr_t -RegisterContextPOSIXProcessMonitor_arm64::GetWatchpointAddress(uint32_t hw_index) -{ - return LLDB_INVALID_ADDRESS; -} - -bool -RegisterContextPOSIXProcessMonitor_arm64::IsWatchpointVacant(uint32_t hw_index) -{ - return false; -} - -bool -RegisterContextPOSIXProcessMonitor_arm64::SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, - bool read, bool write, - uint32_t hw_index) -{ - return false; -} - -uint32_t -RegisterContextPOSIXProcessMonitor_arm64::NumSupportedHardwareWatchpoints() -{ - return 0; -} Index: lldb/trunk/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.h =================================================================== --- lldb/trunk/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.h +++ lldb/trunk/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.h @@ -1,95 +0,0 @@ -//===-- RegisterContextPOSIXProcessMonitor_mips64.h -------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_RegisterContextPOSIXProcessMonitor_mips64_H_ -#define liblldb_RegisterContextPOSIXProcessMonitor_mips64_H_ - -#include "Plugins/Process/Utility/RegisterContextPOSIX_mips64.h" - -class RegisterContextPOSIXProcessMonitor_mips64: - public RegisterContextPOSIX_mips64, - public POSIXBreakpointProtocol -{ -public: - RegisterContextPOSIXProcessMonitor_mips64(lldb_private::Thread &thread, - uint32_t concrete_frame_idx, - lldb_private::RegisterInfoInterface *register_info); - -protected: - bool - ReadGPR(); - - bool - ReadFPR(); - - bool - WriteGPR(); - - bool - WriteFPR(); - - // lldb_private::RegisterContext - bool - ReadRegister(const unsigned reg, lldb_private::RegisterValue &value); - - bool - WriteRegister(const unsigned reg, const lldb_private::RegisterValue &value); - - bool - ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value); - - bool - WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value); - - bool - ReadAllRegisterValues(lldb::DataBufferSP &data_sp); - - bool - WriteAllRegisterValues(const lldb::DataBufferSP &data_sp); - - uint32_t - SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, bool write); - - bool - ClearHardwareWatchpoint(uint32_t hw_index); - - bool - HardwareSingleStep(bool enable); - - // POSIXBreakpointProtocol - bool - UpdateAfterBreakpoint(); - - unsigned - GetRegisterIndexFromOffset(unsigned offset); - - bool - IsWatchpointHit(uint32_t hw_index); - - bool - ClearWatchpointHits(); - - lldb::addr_t - GetWatchpointAddress(uint32_t hw_index); - - bool - IsWatchpointVacant(uint32_t hw_index); - - bool - SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, bool read, bool write, uint32_t hw_index); - - uint32_t - NumSupportedHardwareWatchpoints(); - -private: - ProcessMonitor & - GetMonitor(); -}; - -#endif Index: lldb/trunk/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.cpp +++ lldb/trunk/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.cpp @@ -1,318 +0,0 @@ -//===-- RegisterContextPOSIXProcessMonitor_mips64.h ------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===---------------------------------------------------------------------===// - -#include "lldb/Core/DataBufferHeap.h" -#include "lldb/Core/RegisterValue.h" -#include "lldb/Target/Thread.h" - -#include "Plugins/Process/Utility/RegisterContextPOSIX_mips64.h" -#include "ProcessPOSIX.h" -#include "RegisterContextPOSIXProcessMonitor_mips64.h" -#include "Plugins/Process/Linux/ProcessMonitor.h" - -using namespace lldb_private; -using namespace lldb; - -#define REG_CONTEXT_SIZE (GetGPRSize()) - -RegisterContextPOSIXProcessMonitor_mips64::RegisterContextPOSIXProcessMonitor_mips64(Thread &thread, - uint32_t concrete_frame_idx, - lldb_private::RegisterInfoInterface *register_info) - : RegisterContextPOSIX_mips64(thread, concrete_frame_idx, register_info) -{ -} - -ProcessMonitor & -RegisterContextPOSIXProcessMonitor_mips64::GetMonitor() -{ - ProcessSP base = CalculateProcess(); - ProcessPOSIX *process = static_cast(base.get()); - return process->GetMonitor(); -} - -bool -RegisterContextPOSIXProcessMonitor_mips64::ReadGPR() -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.ReadGPR(m_thread.GetID(), &m_gpr_mips64, GetGPRSize()); -} - -bool -RegisterContextPOSIXProcessMonitor_mips64::ReadFPR() -{ - // XXX not yet implemented - return false; -} - -bool -RegisterContextPOSIXProcessMonitor_mips64::WriteGPR() -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.WriteGPR(m_thread.GetID(), &m_gpr_mips64, GetGPRSize()); -} - -bool -RegisterContextPOSIXProcessMonitor_mips64::WriteFPR() -{ - // XXX not yet implemented - return false; -} - -bool -RegisterContextPOSIXProcessMonitor_mips64::ReadRegister(const unsigned reg, - RegisterValue &value) -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.ReadRegisterValue(m_thread.GetID(), - GetRegisterOffset(reg), - GetRegisterName(reg), - GetRegisterSize(reg), - value); -} - -bool -RegisterContextPOSIXProcessMonitor_mips64::WriteRegister(const unsigned reg, - const RegisterValue &value) -{ - unsigned reg_to_write = reg; - RegisterValue value_to_write = value; - - // Check if this is a subregister of a full register. - const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); - if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) - { - RegisterValue full_value; - uint32_t full_reg = reg_info->invalidate_regs[0]; - const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg); - - // Read the full register. - if (ReadRegister(full_reg_info, full_value)) - { - Error error; - ByteOrder byte_order = GetByteOrder(); - uint8_t dst[RegisterValue::kMaxRegisterByteSize]; - - // Get the bytes for the full register. - const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info, - dst, - sizeof(dst), - byte_order, - error); - if (error.Success() && dest_size) - { - uint8_t src[RegisterValue::kMaxRegisterByteSize]; - - // Get the bytes for the source data. - const uint32_t src_size = value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error); - if (error.Success() && src_size && (src_size < dest_size)) - { - // Copy the src bytes to the destination. - memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size); - // Set this full register as the value to write. - value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order); - value_to_write.SetType(full_reg_info); - reg_to_write = full_reg; - } - } - } - } - - ProcessMonitor &monitor = GetMonitor(); - return monitor.WriteRegisterValue(m_thread.GetID(), - GetRegisterOffset(reg_to_write), - GetRegisterName(reg_to_write), - value_to_write); -} - -bool -RegisterContextPOSIXProcessMonitor_mips64::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value) -{ - if (!reg_info) - return false; - - const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - - if (IsFPR(reg)) - { - if (!ReadFPR()) - return false; - } - else - { - uint32_t full_reg = reg; - bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM); - - if (is_subreg) - { - // Read the full aligned 64-bit register. - full_reg = reg_info->invalidate_regs[0]; - } - - bool success = ReadRegister(full_reg, value); - - if (success) - { - // If our read was not aligned (for ah,bh,ch,dh), shift our returned value one byte to the right. - if (is_subreg && (reg_info->byte_offset & 0x1)) - value.SetUInt64(value.GetAsUInt64() >> 8); - - // If our return byte size was greater than the return value reg size, then - // use the type specified by reg_info rather than the uint64_t default - if (value.GetByteSize() > reg_info->byte_size) - value.SetType(reg_info); - } - return success; - } - - return false; -} - -bool -RegisterContextPOSIXProcessMonitor_mips64::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value) -{ - const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - - if (IsGPR(reg)) - return WriteRegister(reg, value); - - return false; -} - -bool -RegisterContextPOSIXProcessMonitor_mips64::ReadAllRegisterValues(DataBufferSP &data_sp) -{ - bool success = false; - data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0)); - if (data_sp && ReadGPR () && ReadFPR ()) - { - uint8_t *dst = data_sp->GetBytes(); - success = dst != 0; - - if (success) - { - ::memcpy (dst, &m_gpr_mips64, GetGPRSize()); - } - } - return success; -} - -bool -RegisterContextPOSIXProcessMonitor_mips64::WriteAllRegisterValues(const DataBufferSP &data_sp) -{ - bool success = false; - if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) - { - uint8_t *src = data_sp->GetBytes(); - if (src) - { - ::memcpy (&m_gpr_mips64, src, GetGPRSize()); - - if (WriteGPR()) - { - src += GetGPRSize(); - } - } - } - return success; -} - -uint32_t -RegisterContextPOSIXProcessMonitor_mips64::SetHardwareWatchpoint(addr_t addr, size_t size, - bool read, bool write) -{ - const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); - uint32_t hw_index; - - for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index) - { - if (IsWatchpointVacant(hw_index)) - return SetHardwareWatchpointWithIndex(addr, size, - read, write, - hw_index); - } - - return LLDB_INVALID_INDEX32; -} - -bool -RegisterContextPOSIXProcessMonitor_mips64::ClearHardwareWatchpoint(uint32_t hw_index) -{ - return false; -} - -bool -RegisterContextPOSIXProcessMonitor_mips64::HardwareSingleStep(bool enable) -{ - return false; -} - -bool -RegisterContextPOSIXProcessMonitor_mips64::UpdateAfterBreakpoint() -{ - // PC points one byte past the int3 responsible for the breakpoint. - lldb::addr_t pc; - - if ((pc = GetPC()) == LLDB_INVALID_ADDRESS) - return false; - - SetPC(pc - 1); - return true; -} - -unsigned -RegisterContextPOSIXProcessMonitor_mips64::GetRegisterIndexFromOffset(unsigned offset) -{ - unsigned reg; - for (reg = 0; reg < k_num_registers_mips64; reg++) - { - if (GetRegisterInfo()[reg].byte_offset == offset) - break; - } - assert(reg < k_num_registers_mips64 && "Invalid register offset."); - return reg; -} - -bool -RegisterContextPOSIXProcessMonitor_mips64::IsWatchpointHit(uint32_t hw_index) -{ - return false; -} - -bool -RegisterContextPOSIXProcessMonitor_mips64::ClearWatchpointHits() -{ - return false; -} - -addr_t -RegisterContextPOSIXProcessMonitor_mips64::GetWatchpointAddress(uint32_t hw_index) -{ - return LLDB_INVALID_ADDRESS; -} - -bool -RegisterContextPOSIXProcessMonitor_mips64::IsWatchpointVacant(uint32_t hw_index) -{ - return false; -} - -bool -RegisterContextPOSIXProcessMonitor_mips64::SetHardwareWatchpointWithIndex(addr_t addr, size_t size, - bool read, bool write, - uint32_t hw_index) -{ - return false; -} - -uint32_t -RegisterContextPOSIXProcessMonitor_mips64::NumSupportedHardwareWatchpoints() -{ - return 0; -} - Index: lldb/trunk/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_powerpc.h =================================================================== --- lldb/trunk/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_powerpc.h +++ lldb/trunk/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_powerpc.h @@ -1,104 +0,0 @@ -//===-- RegisterContextPOSIXProcessMonitor_powerpc.h -------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_RegisterContextPOSIXProcessMonitor_powerpc_H_ -#define liblldb_RegisterContextPOSIXProcessMonitor_powerpc_H_ - -#include "Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h" - -class RegisterContextPOSIXProcessMonitor_powerpc: - public RegisterContextPOSIX_powerpc, - public POSIXBreakpointProtocol -{ -public: - RegisterContextPOSIXProcessMonitor_powerpc(lldb_private::Thread &thread, - uint32_t concrete_frame_idx, - lldb_private::RegisterInfoInterface *register_info); - -protected: - bool - IsVMX(); - - bool - ReadGPR(); - - bool - ReadFPR(); - - bool - ReadVMX(); - - bool - WriteGPR(); - - bool - WriteFPR(); - - bool - WriteVMX(); - - // lldb_private::RegisterContext - bool - ReadRegister(const unsigned reg, lldb_private::RegisterValue &value); - - bool - WriteRegister(const unsigned reg, const lldb_private::RegisterValue &value); - - bool - ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value); - - bool - WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value); - - bool - ReadAllRegisterValues(lldb::DataBufferSP &data_sp); - - bool - WriteAllRegisterValues(const lldb::DataBufferSP &data_sp); - - uint32_t - SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, bool write); - - bool - ClearHardwareWatchpoint(uint32_t hw_index); - - bool - HardwareSingleStep(bool enable); - - // POSIXBreakpointProtocol - bool - UpdateAfterBreakpoint(); - - unsigned - GetRegisterIndexFromOffset(unsigned offset); - - bool - IsWatchpointHit(uint32_t hw_index); - - bool - ClearWatchpointHits(); - - lldb::addr_t - GetWatchpointAddress(uint32_t hw_index); - - bool - IsWatchpointVacant(uint32_t hw_index); - - bool - SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, bool read, bool write, uint32_t hw_index); - - uint32_t - NumSupportedHardwareWatchpoints(); - -private: - ProcessMonitor & - GetMonitor(); -}; - -#endif Index: lldb/trunk/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_powerpc.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_powerpc.cpp +++ lldb/trunk/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_powerpc.cpp @@ -1,337 +0,0 @@ -//===-- RegisterContextPOSIXProcessMonitor_powerpc.h ------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===---------------------------------------------------------------------===// - -#include "lldb/Core/DataBufferHeap.h" -#include "lldb/Core/RegisterValue.h" -#include "lldb/Target/Thread.h" - -#include "RegisterContextPOSIX_powerpc.h" -#include "ProcessPOSIX.h" -#include "RegisterContextPOSIXProcessMonitor_powerpc.h" -#include "ProcessMonitor.h" - -using namespace lldb_private; -using namespace lldb; - -#define REG_CONTEXT_SIZE (GetGPRSize()) - -RegisterContextPOSIXProcessMonitor_powerpc::RegisterContextPOSIXProcessMonitor_powerpc(Thread &thread, - uint32_t concrete_frame_idx, - lldb_private::RegisterInfoInterface *register_info) - : RegisterContextPOSIX_powerpc(thread, concrete_frame_idx, register_info) -{ -} - -ProcessMonitor & -RegisterContextPOSIXProcessMonitor_powerpc::GetMonitor() -{ - ProcessSP base = CalculateProcess(); - ProcessPOSIX *process = static_cast(base.get()); - return process->GetMonitor(); -} - -bool -RegisterContextPOSIXProcessMonitor_powerpc::ReadGPR() -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.ReadGPR(m_thread.GetID(), &m_gpr_powerpc, GetGPRSize()); -} - -bool -RegisterContextPOSIXProcessMonitor_powerpc::ReadFPR() -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.ReadFPR(m_thread.GetID(), &m_fpr_powerpc, sizeof(m_fpr_powerpc)); -} - -bool -RegisterContextPOSIXProcessMonitor_powerpc::ReadVMX() -{ - // XXX: Need a way to read/write process VMX registers with ptrace. - return false; -} - -bool -RegisterContextPOSIXProcessMonitor_powerpc::WriteGPR() -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.WriteGPR(m_thread.GetID(), &m_gpr_powerpc, GetGPRSize()); -} - -bool -RegisterContextPOSIXProcessMonitor_powerpc::WriteFPR() -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.WriteFPR(m_thread.GetID(), &m_fpr_powerpc, sizeof(m_fpr_powerpc)); -} - -bool -RegisterContextPOSIXProcessMonitor_powerpc::WriteVMX() -{ - // XXX: Need a way to read/write process VMX registers with ptrace. - return false; -} - -bool -RegisterContextPOSIXProcessMonitor_powerpc::ReadRegister(const unsigned reg, - RegisterValue &value) -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.ReadRegisterValue(m_thread.GetID(), - GetRegisterOffset(reg), - GetRegisterName(reg), - GetRegisterSize(reg), - value); -} - -bool -RegisterContextPOSIXProcessMonitor_powerpc::WriteRegister(const unsigned reg, - const RegisterValue &value) -{ - unsigned reg_to_write = reg; - RegisterValue value_to_write = value; - - // Check if this is a subregister of a full register. - const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); - if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) - { - RegisterValue full_value; - uint32_t full_reg = reg_info->invalidate_regs[0]; - const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg); - - // Read the full register. - if (ReadRegister(full_reg_info, full_value)) - { - Error error; - ByteOrder byte_order = GetByteOrder(); - uint8_t dst[RegisterValue::kMaxRegisterByteSize]; - - // Get the bytes for the full register. - const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info, - dst, - sizeof(dst), - byte_order, - error); - if (error.Success() && dest_size) - { - uint8_t src[RegisterValue::kMaxRegisterByteSize]; - - // Get the bytes for the source data. - const uint32_t src_size = value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error); - if (error.Success() && src_size && (src_size < dest_size)) - { - // Copy the src bytes to the destination. - memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size); - // Set this full register as the value to write. - value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order); - value_to_write.SetType(full_reg_info); - reg_to_write = full_reg; - } - } - } - } - - ProcessMonitor &monitor = GetMonitor(); - // Account for the fact that 32-bit targets on powerpc64 really use 64-bit - // registers in ptrace, but expose here 32-bit registers with a higher - // offset. - uint64_t offset = GetRegisterOffset(reg_to_write); - offset &= ~(sizeof(uintptr_t) - 1); - return monitor.WriteRegisterValue(m_thread.GetID(), - offset, - GetRegisterName(reg_to_write), - value_to_write); -} - -bool -RegisterContextPOSIXProcessMonitor_powerpc::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value) -{ - if (!reg_info) - return false; - - const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - - if (IsFPR(reg)) - { - if (!ReadFPR()) - return false; - uint8_t *src = (uint8_t *)&m_fpr_powerpc + reg_info->byte_offset; - value.SetUInt64(*(uint64_t*)src); - } - else if (IsGPR(reg)) - { - bool success = ReadRegister(reg, value); - - if (success) - { - // If our return byte size was greater than the return value reg size, then - // use the type specified by reg_info rather than the uint64_t default - if (value.GetByteSize() > reg_info->byte_size) - value.SetType(reg_info); - } - return success; - } - - return false; -} - -bool -RegisterContextPOSIXProcessMonitor_powerpc::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value) -{ - const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - - if (IsGPR(reg)) - { - return WriteRegister(reg, value); - } - else if (IsFPR(reg)) - { - assert (reg_info->byte_offset < sizeof(m_fpr_powerpc)); - uint8_t *dst = (uint8_t *)&m_fpr_powerpc + reg_info->byte_offset; - *(uint64_t *)dst = value.GetAsUInt64(); - return WriteFPR(); - } - - return false; -} - -bool -RegisterContextPOSIXProcessMonitor_powerpc::ReadAllRegisterValues(DataBufferSP &data_sp) -{ - bool success = false; - data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0)); - if (data_sp && ReadGPR () && ReadFPR ()) - { - uint8_t *dst = data_sp->GetBytes(); - success = dst != 0; - - if (success) - { - ::memcpy (dst, &m_gpr_powerpc, GetGPRSize()); - dst += GetGPRSize(); - } - } - return success; -} - -bool -RegisterContextPOSIXProcessMonitor_powerpc::WriteAllRegisterValues(const DataBufferSP &data_sp) -{ - bool success = false; - if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) - { - uint8_t *src = data_sp->GetBytes(); - if (src) - { - ::memcpy (&m_gpr_powerpc, src, GetGPRSize()); - - if (WriteGPR()) - { - src += GetGPRSize(); - ::memcpy (&m_fpr_powerpc, src, sizeof(m_fpr_powerpc)); - - success = WriteFPR(); - } - } - } - return success; -} - -uint32_t -RegisterContextPOSIXProcessMonitor_powerpc::SetHardwareWatchpoint(addr_t addr, size_t size, - bool read, bool write) -{ - const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); - uint32_t hw_index; - - for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index) - { - if (IsWatchpointVacant(hw_index)) - return SetHardwareWatchpointWithIndex(addr, size, - read, write, - hw_index); - } - - return LLDB_INVALID_INDEX32; -} - -bool -RegisterContextPOSIXProcessMonitor_powerpc::ClearHardwareWatchpoint(uint32_t hw_index) -{ - return false; -} - -bool -RegisterContextPOSIXProcessMonitor_powerpc::HardwareSingleStep(bool enable) -{ - return false; -} - -bool -RegisterContextPOSIXProcessMonitor_powerpc::UpdateAfterBreakpoint() -{ - lldb::addr_t pc; - - if ((pc = GetPC()) == LLDB_INVALID_ADDRESS) - return false; - - return true; -} - -unsigned -RegisterContextPOSIXProcessMonitor_powerpc::GetRegisterIndexFromOffset(unsigned offset) -{ - unsigned reg; - for (reg = 0; reg < k_num_registers_powerpc; reg++) - { - if (GetRegisterInfo()[reg].byte_offset == offset) - break; - } - assert(reg < k_num_registers_powerpc && "Invalid register offset."); - return reg; -} - -bool -RegisterContextPOSIXProcessMonitor_powerpc::IsWatchpointHit(uint32_t hw_index) -{ - return false; -} - -bool -RegisterContextPOSIXProcessMonitor_powerpc::ClearWatchpointHits() -{ - return false; -} - -addr_t -RegisterContextPOSIXProcessMonitor_powerpc::GetWatchpointAddress(uint32_t hw_index) -{ - return LLDB_INVALID_ADDRESS; -} - -bool -RegisterContextPOSIXProcessMonitor_powerpc::IsWatchpointVacant(uint32_t hw_index) -{ - return false; -} - -bool -RegisterContextPOSIXProcessMonitor_powerpc::SetHardwareWatchpointWithIndex(addr_t addr, size_t size, - bool read, bool write, - uint32_t hw_index) -{ - return false; -} - -uint32_t -RegisterContextPOSIXProcessMonitor_powerpc::NumSupportedHardwareWatchpoints() -{ - return 0; -} - Index: lldb/trunk/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.h =================================================================== --- lldb/trunk/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.h +++ lldb/trunk/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.h @@ -1,95 +0,0 @@ -//===-- RegisterContextPOSIXProcessMonitor_x86.h ----------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_RegisterContextPOSIXProcessMonitor_x86_H_ -#define liblldb_RegisterContextPOSIXProcessMonitor_x86_H_ - -#include "Plugins/Process/Utility/RegisterContextPOSIX_x86.h" - -class RegisterContextPOSIXProcessMonitor_x86_64: - public RegisterContextPOSIX_x86, - public POSIXBreakpointProtocol -{ -public: - RegisterContextPOSIXProcessMonitor_x86_64(lldb_private::Thread &thread, - uint32_t concrete_frame_idx, - lldb_private::RegisterInfoInterface *register_info); - -protected: - bool - ReadGPR(); - - bool - ReadFPR(); - - bool - WriteGPR(); - - bool - WriteFPR(); - - // lldb_private::RegisterContext - bool - ReadRegister(const unsigned reg, lldb_private::RegisterValue &value); - - bool - WriteRegister(const unsigned reg, const lldb_private::RegisterValue &value); - - bool - ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value); - - bool - WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value); - - bool - ReadAllRegisterValues(lldb::DataBufferSP &data_sp); - - bool - WriteAllRegisterValues(const lldb::DataBufferSP &data_sp); - - uint32_t - SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, bool write); - - bool - ClearHardwareWatchpoint(uint32_t hw_index); - - bool - HardwareSingleStep(bool enable); - - // POSIXBreakpointProtocol - bool - UpdateAfterBreakpoint(); - - unsigned - GetRegisterIndexFromOffset(unsigned offset); - - bool - IsWatchpointHit(uint32_t hw_index); - - bool - ClearWatchpointHits(); - - lldb::addr_t - GetWatchpointAddress(uint32_t hw_index); - - bool - IsWatchpointVacant(uint32_t hw_index); - - bool - SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, bool read, bool write, uint32_t hw_index); - - uint32_t - NumSupportedHardwareWatchpoints(); - -private: - ProcessMonitor & - GetMonitor(); -}; - -#endif Index: lldb/trunk/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.cpp +++ lldb/trunk/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.cpp @@ -1,654 +0,0 @@ -//===-- RegisterContextPOSIXProcessMonitor_x86.h ---------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===---------------------------------------------------------------------===// - -#include "lldb/Core/DataBufferHeap.h" -#include "lldb/Core/RegisterValue.h" -#include "lldb/Target/Thread.h" - -#include "Plugins/Process/POSIX/ProcessPOSIX.h" -#include "RegisterContextPOSIXProcessMonitor_x86.h" -#if defined(__FreeBSD__) -#include "Plugins/Process/FreeBSD/ProcessMonitor.h" -#else -#include "Plugins/Process/Linux/ProcessMonitor.h" -#endif - -using namespace lldb_private; -using namespace lldb; - -// Support ptrace extensions even when compiled without required kernel support -#ifndef NT_X86_XSTATE - #define NT_X86_XSTATE 0x202 -#endif - -#define REG_CONTEXT_SIZE (GetGPRSize() + sizeof(FPR)) - -static uint32_t -size_and_rw_bits(size_t size, bool read, bool write) -{ - uint32_t rw; - - if (read) - rw = 0x3; // READ or READ/WRITE - else if (write) - rw = 0x1; // WRITE - else - assert(0 && "read and write cannot both be false"); - - switch (size) - { - case 1: - return rw; - case 2: - return (0x1 << 2) | rw; - case 4: - return (0x3 << 2) | rw; - case 8: - return (0x2 << 2) | rw; - default: - assert(0 && "invalid size, must be one of 1, 2, 4, or 8"); - return 0; // Unreachable. Just to silence compiler. - } -} - -RegisterContextPOSIXProcessMonitor_x86_64::RegisterContextPOSIXProcessMonitor_x86_64(Thread &thread, - uint32_t concrete_frame_idx, - lldb_private::RegisterInfoInterface *register_info) - : RegisterContextPOSIX_x86(thread, concrete_frame_idx, register_info) -{ -} - -ProcessMonitor & -RegisterContextPOSIXProcessMonitor_x86_64::GetMonitor() -{ - ProcessSP base = CalculateProcess(); - ProcessPOSIX *process = static_cast(base.get()); - return process->GetMonitor(); -} - -bool -RegisterContextPOSIXProcessMonitor_x86_64::ReadGPR() -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.ReadGPR(m_thread.GetID(), &m_gpr_x86_64, GetGPRSize()); -} - -bool -RegisterContextPOSIXProcessMonitor_x86_64::ReadFPR() -{ - ProcessMonitor &monitor = GetMonitor(); - if (GetFPRType() == eFXSAVE) - return monitor.ReadFPR(m_thread.GetID(), &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave)); - - if (GetFPRType() == eXSAVE) - return monitor.ReadRegisterSet(m_thread.GetID(), &m_iovec, sizeof(m_fpr.xstate.xsave), NT_X86_XSTATE); - return false; -} - -bool -RegisterContextPOSIXProcessMonitor_x86_64::WriteGPR() -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.WriteGPR(m_thread.GetID(), &m_gpr_x86_64, GetGPRSize()); -} - -bool -RegisterContextPOSIXProcessMonitor_x86_64::WriteFPR() -{ - ProcessMonitor &monitor = GetMonitor(); - if (GetFPRType() == eFXSAVE) - return monitor.WriteFPR(m_thread.GetID(), &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave)); - - if (GetFPRType() == eXSAVE) - return monitor.WriteRegisterSet(m_thread.GetID(), &m_iovec, sizeof(m_fpr.xstate.xsave), NT_X86_XSTATE); - return false; -} - -bool -RegisterContextPOSIXProcessMonitor_x86_64::ReadRegister(const unsigned reg, - RegisterValue &value) -{ - ProcessMonitor &monitor = GetMonitor(); - -#if defined(__FreeBSD__) - if (reg >= m_reg_info.first_dr) - return monitor.ReadDebugRegisterValue(m_thread.GetID(), - GetRegisterOffset(reg), - GetRegisterName(reg), - GetRegisterSize(reg), - value); -#endif - return monitor.ReadRegisterValue(m_thread.GetID(), - GetRegisterOffset(reg), - GetRegisterName(reg), - GetRegisterSize(reg), - value); -} - -bool -RegisterContextPOSIXProcessMonitor_x86_64::WriteRegister(const unsigned reg, - const RegisterValue &value) -{ - unsigned reg_to_write = reg; - RegisterValue value_to_write = value; - - // Check if this is a subregister of a full register. - const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); - if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) - { - RegisterValue full_value; - uint32_t full_reg = reg_info->invalidate_regs[0]; - const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg); - - // Read the full register. - if (ReadRegister(full_reg_info, full_value)) - { - Error error; - ByteOrder byte_order = GetByteOrder(); - uint8_t dst[RegisterValue::kMaxRegisterByteSize]; - - // Get the bytes for the full register. - const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info, - dst, - sizeof(dst), - byte_order, - error); - if (error.Success() && dest_size) - { - uint8_t src[RegisterValue::kMaxRegisterByteSize]; - - // Get the bytes for the source data. - const uint32_t src_size = value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error); - if (error.Success() && src_size && (src_size < dest_size)) - { - // Copy the src bytes to the destination. - memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size); - // Set this full register as the value to write. - value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order); - value_to_write.SetType(full_reg_info); - reg_to_write = full_reg; - } - } - } - } - - ProcessMonitor &monitor = GetMonitor(); -#if defined(__FreeBSD__) - if (reg >= m_reg_info.first_dr) - return monitor.WriteDebugRegisterValue(m_thread.GetID(), - GetRegisterOffset(reg_to_write), - GetRegisterName(reg_to_write), - value_to_write); -#endif - return monitor.WriteRegisterValue(m_thread.GetID(), - GetRegisterOffset(reg_to_write), - GetRegisterName(reg_to_write), - value_to_write); -} - -bool -RegisterContextPOSIXProcessMonitor_x86_64::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value) -{ - if (!reg_info) - return false; - - const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - - if (IsFPR(reg, GetFPRType())) - { - if (!ReadFPR()) - return false; - } - else - { - uint32_t full_reg = reg; - bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM); - - if (is_subreg) - { - // Read the full aligned 64-bit register. - full_reg = reg_info->invalidate_regs[0]; - } - - bool success = ReadRegister(full_reg, value); - - if (success) - { - // If our read was not aligned (for ah,bh,ch,dh), shift our returned value one byte to the right. - if (is_subreg && (reg_info->byte_offset & 0x1)) - value.SetUInt64(value.GetAsUInt64() >> 8); - - // If our return byte size was greater than the return value reg size, then - // use the type specified by reg_info rather than the uint64_t default - if (value.GetByteSize() > reg_info->byte_size) - value.SetType(reg_info); - } - return success; - } - - if (reg_info->encoding == eEncodingVector) - { - ByteOrder byte_order = GetByteOrder(); - - if (byte_order != ByteOrder::eByteOrderInvalid) - { - if (reg >= m_reg_info.first_st && reg <= m_reg_info.last_st) - value.SetBytes(m_fpr.xstate.fxsave.stmm[reg - m_reg_info.first_st].bytes, reg_info->byte_size, byte_order); - if (reg >= m_reg_info.first_mm && reg <= m_reg_info.last_mm) - value.SetBytes(m_fpr.xstate.fxsave.stmm[reg - m_reg_info.first_mm].bytes, reg_info->byte_size, byte_order); - if (reg >= m_reg_info.first_xmm && reg <= m_reg_info.last_xmm) - value.SetBytes(m_fpr.xstate.fxsave.xmm[reg - m_reg_info.first_xmm].bytes, reg_info->byte_size, byte_order); - if (reg >= m_reg_info.first_ymm && reg <= m_reg_info.last_ymm) - { - // Concatenate ymm using the register halves in xmm.bytes and ymmh.bytes - if (GetFPRType() == eXSAVE && CopyXSTATEtoYMM(reg, byte_order)) - value.SetBytes(m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes, reg_info->byte_size, byte_order); - else - return false; - } - return value.GetType() == RegisterValue::eTypeBytes; - } - return false; - } - - // Get pointer to m_fpr.xstate.fxsave variable and set the data from it. - assert (reg_info->byte_offset < sizeof(m_fpr)); - uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset; - switch (reg_info->byte_size) - { - case 2: - value.SetUInt16(*(uint16_t *)src); - return true; - case 4: - value.SetUInt32(*(uint32_t *)src); - return true; - case 8: - value.SetUInt64(*(uint64_t *)src); - return true; - default: - assert(false && "Unhandled data size."); - return false; - } -} - -bool -RegisterContextPOSIXProcessMonitor_x86_64::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value) -{ - const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - - if (IsGPR(reg)) - return WriteRegister(reg, value); - - if (IsFPR(reg, GetFPRType())) - { - if (reg_info->encoding == eEncodingVector) - { - if (reg >= m_reg_info.first_st && reg <= m_reg_info.last_st) - ::memcpy (m_fpr.xstate.fxsave.stmm[reg - m_reg_info.first_st].bytes, value.GetBytes(), value.GetByteSize()); - - if (reg >= m_reg_info.first_mm && reg <= m_reg_info.last_mm) - ::memcpy (m_fpr.xstate.fxsave.stmm[reg - m_reg_info.first_mm].bytes, value.GetBytes(), value.GetByteSize()); - - if (reg >= m_reg_info.first_xmm && reg <= m_reg_info.last_xmm) - ::memcpy (m_fpr.xstate.fxsave.xmm[reg - m_reg_info.first_xmm].bytes, value.GetBytes(), value.GetByteSize()); - - if (reg >= m_reg_info.first_ymm && reg <= m_reg_info.last_ymm) - { - if (GetFPRType() != eXSAVE) - return false; // the target processor does not support AVX - - // Store ymm register content, and split into the register halves in xmm.bytes and ymmh.bytes - ::memcpy (m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes, value.GetBytes(), value.GetByteSize()); - if (false == CopyYMMtoXSTATE(reg, GetByteOrder())) - return false; - } - } - else - { - // Get pointer to m_fpr.xstate.fxsave variable and set the data to it. - assert (reg_info->byte_offset < sizeof(m_fpr)); - uint8_t *dst = (uint8_t *)&m_fpr + reg_info->byte_offset; - switch (reg_info->byte_size) - { - case 2: - *(uint16_t *)dst = value.GetAsUInt16(); - break; - case 4: - *(uint32_t *)dst = value.GetAsUInt32(); - break; - case 8: - *(uint64_t *)dst = value.GetAsUInt64(); - break; - default: - assert(false && "Unhandled data size."); - return false; - } - } - - if (WriteFPR()) - { - if (IsAVX(reg)) - return CopyYMMtoXSTATE(reg, GetByteOrder()); - return true; - } - } - return false; -} - -bool -RegisterContextPOSIXProcessMonitor_x86_64::ReadAllRegisterValues(DataBufferSP &data_sp) -{ - bool success = false; - data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0)); - if (data_sp && ReadGPR () && ReadFPR ()) - { - uint8_t *dst = data_sp->GetBytes(); - success = dst != 0; - - if (success) - { - ::memcpy (dst, &m_gpr_x86_64, GetGPRSize()); - dst += GetGPRSize(); - if (GetFPRType() == eFXSAVE) - ::memcpy (dst, &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave)); - } - - if (GetFPRType() == eXSAVE) - { - ByteOrder byte_order = GetByteOrder(); - - // Assemble the YMM register content from the register halves. - for (uint32_t reg = m_reg_info.first_ymm; success && reg <= m_reg_info.last_ymm; ++reg) - success = CopyXSTATEtoYMM(reg, byte_order); - - if (success) - { - // Copy the extended register state including the assembled ymm registers. - ::memcpy (dst, &m_fpr, sizeof(m_fpr)); - } - } - } - return success; -} - -bool -RegisterContextPOSIXProcessMonitor_x86_64::WriteAllRegisterValues(const DataBufferSP &data_sp) -{ - bool success = false; - if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) - { - uint8_t *src = data_sp->GetBytes(); - if (src) - { - ::memcpy (&m_gpr_x86_64, src, GetGPRSize()); - - if (WriteGPR()) - { - src += GetGPRSize(); - if (GetFPRType() == eFXSAVE) - ::memcpy (&m_fpr.xstate.fxsave, src, sizeof(m_fpr.xstate.fxsave)); - if (GetFPRType() == eXSAVE) - ::memcpy (&m_fpr.xstate.xsave, src, sizeof(m_fpr.xstate.xsave)); - - success = WriteFPR(); - if (success) - { - if (GetFPRType() == eXSAVE) - { - ByteOrder byte_order = GetByteOrder(); - - // Parse the YMM register content from the register halves. - for (uint32_t reg = m_reg_info.first_ymm; success && reg <= m_reg_info.last_ymm; ++reg) - success = CopyYMMtoXSTATE(reg, byte_order); - } - } - } - } - } - return success; -} - -uint32_t -RegisterContextPOSIXProcessMonitor_x86_64::SetHardwareWatchpoint(addr_t addr, size_t size, - bool read, bool write) -{ - const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); - uint32_t hw_index; - - for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index) - { - if (IsWatchpointVacant(hw_index)) - return SetHardwareWatchpointWithIndex(addr, size, - read, write, - hw_index); - } - - return LLDB_INVALID_INDEX32; -} - -bool -RegisterContextPOSIXProcessMonitor_x86_64::ClearHardwareWatchpoint(uint32_t hw_index) -{ - if (hw_index < NumSupportedHardwareWatchpoints()) - { - RegisterValue current_dr7_bits; - - if (ReadRegister(m_reg_info.first_dr + 7, current_dr7_bits)) - { - uint64_t new_dr7_bits = current_dr7_bits.GetAsUInt64() & ~(3 << (2*hw_index)); - - if (WriteRegister(m_reg_info.first_dr + 7, RegisterValue(new_dr7_bits))) - return true; - } - } - - return false; -} - -bool -RegisterContextPOSIXProcessMonitor_x86_64::HardwareSingleStep(bool enable) -{ - enum { TRACE_BIT = 0x100 }; - uint64_t rflags; - - if ((rflags = ReadRegisterAsUnsigned(m_reg_info.gpr_flags, -1UL)) == -1UL) - return false; - - if (enable) - { - if (rflags & TRACE_BIT) - return true; - - rflags |= TRACE_BIT; - } - else - { - if (!(rflags & TRACE_BIT)) - return false; - - rflags &= ~TRACE_BIT; - } - - return WriteRegisterFromUnsigned(m_reg_info.gpr_flags, rflags); -} - -bool -RegisterContextPOSIXProcessMonitor_x86_64::UpdateAfterBreakpoint() -{ - // PC points one byte past the int3 responsible for the breakpoint. - lldb::addr_t pc; - - if ((pc = GetPC()) == LLDB_INVALID_ADDRESS) - return false; - - SetPC(pc - 1); - return true; -} - -unsigned -RegisterContextPOSIXProcessMonitor_x86_64::GetRegisterIndexFromOffset(unsigned offset) -{ - unsigned reg; - for (reg = 0; reg < m_reg_info.num_registers; reg++) - { - if (GetRegisterInfo()[reg].byte_offset == offset) - break; - } - assert(reg < m_reg_info.num_registers && "Invalid register offset."); - return reg; -} - -bool -RegisterContextPOSIXProcessMonitor_x86_64::IsWatchpointHit(uint32_t hw_index) -{ - bool is_hit = false; - - if (m_watchpoints_initialized == false) - { - // Reset the debug status and debug control registers - RegisterValue zero_bits = RegisterValue(uint64_t(0)); - if (!WriteRegister(m_reg_info.first_dr + 6, zero_bits) || !WriteRegister(m_reg_info.first_dr + 7, zero_bits)) - assert(false && "Could not initialize watchpoint registers"); - m_watchpoints_initialized = true; - } - - if (hw_index < NumSupportedHardwareWatchpoints()) - { - RegisterValue value; - - if (ReadRegister(m_reg_info.first_dr + 6, value)) - { - uint64_t val = value.GetAsUInt64(); - is_hit = val & (1 << hw_index); - } - } - - return is_hit; -} - -bool -RegisterContextPOSIXProcessMonitor_x86_64::ClearWatchpointHits() -{ - return WriteRegister(m_reg_info.first_dr + 6, RegisterValue((uint64_t)0)); -} - -addr_t -RegisterContextPOSIXProcessMonitor_x86_64::GetWatchpointAddress(uint32_t hw_index) -{ - addr_t wp_monitor_addr = LLDB_INVALID_ADDRESS; - - if (hw_index < NumSupportedHardwareWatchpoints()) - { - if (!IsWatchpointVacant(hw_index)) - { - RegisterValue value; - - if (ReadRegister(m_reg_info.first_dr + hw_index, value)) - wp_monitor_addr = value.GetAsUInt64(); - } - } - - return wp_monitor_addr; -} - -bool -RegisterContextPOSIXProcessMonitor_x86_64::IsWatchpointVacant(uint32_t hw_index) -{ - bool is_vacant = false; - RegisterValue value; - - assert(hw_index < NumSupportedHardwareWatchpoints()); - - if (m_watchpoints_initialized == false) - { - // Reset the debug status and debug control registers - RegisterValue zero_bits = RegisterValue(uint64_t(0)); - if (!WriteRegister(m_reg_info.first_dr + 6, zero_bits) || !WriteRegister(m_reg_info.first_dr + 7, zero_bits)) - assert(false && "Could not initialize watchpoint registers"); - m_watchpoints_initialized = true; - } - - if (ReadRegister(m_reg_info.first_dr + 7, value)) - { - uint64_t val = value.GetAsUInt64(); - is_vacant = (val & (3 << 2*hw_index)) == 0; - } - - return is_vacant; -} - -bool -RegisterContextPOSIXProcessMonitor_x86_64::SetHardwareWatchpointWithIndex(addr_t addr, size_t size, - bool read, bool write, - uint32_t hw_index) -{ - const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); - - if (num_hw_watchpoints == 0 || hw_index >= num_hw_watchpoints) - return false; - - if (!(size == 1 || size == 2 || size == 4 || size == 8)) - return false; - - if (read == false && write == false) - return false; - - if (!IsWatchpointVacant(hw_index)) - return false; - - // Set both dr7 (debug control register) and dri (debug address register). - - // dr7{7-0} encodes the local/global enable bits: - // global enable --. .-- local enable - // | | - // v v - // dr0 -> bits{1-0} - // dr1 -> bits{3-2} - // dr2 -> bits{5-4} - // dr3 -> bits{7-6} - // - // dr7{31-16} encodes the rw/len bits: - // b_x+3, b_x+2, b_x+1, b_x - // where bits{x+1, x} => rw - // 0b00: execute, 0b01: write, 0b11: read-or-write, - // 0b10: io read-or-write (unused) - // and bits{x+3, x+2} => len - // 0b00: 1-byte, 0b01: 2-byte, 0b11: 4-byte, 0b10: 8-byte - // - // dr0 -> bits{19-16} - // dr1 -> bits{23-20} - // dr2 -> bits{27-24} - // dr3 -> bits{31-28} - if (hw_index < num_hw_watchpoints) - { - RegisterValue current_dr7_bits; - - if (ReadRegister(m_reg_info.first_dr + 7, current_dr7_bits)) - { - uint64_t new_dr7_bits = current_dr7_bits.GetAsUInt64() | - (1 << (2*hw_index) | - size_and_rw_bits(size, read, write) << - (16+4*hw_index)); - - if (WriteRegister(m_reg_info.first_dr + hw_index, RegisterValue(addr)) && - WriteRegister(m_reg_info.first_dr + 7, RegisterValue(new_dr7_bits))) - return true; - } - } - - return false; -} - -uint32_t -RegisterContextPOSIXProcessMonitor_x86_64::NumSupportedHardwareWatchpoints() -{ - // Available debug address registers: dr0, dr1, dr2, dr3 - return 4; -} - Index: lldb/trunk/test/functionalities/process_launch/TestProcessLaunch.py =================================================================== --- lldb/trunk/test/functionalities/process_launch/TestProcessLaunch.py +++ lldb/trunk/test/functionalities/process_launch/TestProcessLaunch.py @@ -128,7 +128,7 @@ @skipIfFreeBSD # llvm.org/pr16684 @expectedFailureDarwin("llvm.org/pr20265") - @expectedFailureLLGS("llvm.org/pr20265") + @expectedFailureLinux("llvm.org/pr20265") @dwarf_test def test_set_working_dir_with_dwarf (self): """Test that '-w dir' sets the working dir when running the inferior.""" Index: lldb/trunk/test/functionalities/thread/break_after_join/TestBreakAfterJoin.py =================================================================== --- lldb/trunk/test/functionalities/thread/break_after_join/TestBreakAfterJoin.py +++ lldb/trunk/test/functionalities/thread/break_after_join/TestBreakAfterJoin.py @@ -22,7 +22,7 @@ @expectedFailureDarwin("llvm.org/pr15824") # thread states not properly maintained @expectedFailureFreeBSD("llvm.org/pr18190") # thread states not properly maintained - @expectedFailureLLGS("llvm.org/pr15824") # thread states not properly maintained + @expectedFailureLinux("llvm.org/pr15824") # thread states not properly maintained @dwarf_test def test_with_dwarf(self): """Test breakpoint handling after a thread join.""" Index: lldb/trunk/test/functionalities/thread/create_during_step/TestCreateDuringStep.py =================================================================== --- lldb/trunk/test/functionalities/thread/create_during_step/TestCreateDuringStep.py +++ lldb/trunk/test/functionalities/thread/create_during_step/TestCreateDuringStep.py @@ -38,7 +38,7 @@ @expectedFailureDarwin("llvm.org/pr15824") # thread states not properly maintained @expectedFailureFreeBSD("llvm.org/pr18190") # thread states not properly maintained - @expectedFailureLLGS("llvm.org/pr15824") # thread states not properly maintained + @expectedFailureLinux("llvm.org/pr15824") # thread states not properly maintained @dwarf_test def test_step_inst_with_dwarf(self): """Test thread creation during step-inst handling.""" @@ -47,7 +47,7 @@ @expectedFailureDarwin("llvm.org/pr15824") # thread states not properly maintained @expectedFailureFreeBSD("llvm.org/pr18190") # thread states not properly maintained - @expectedFailureLLGS("llvm.org/pr15824") # thread states not properly maintained + @expectedFailureLinux("llvm.org/pr15824") # thread states not properly maintained @dwarf_test def test_step_over_with_dwarf(self): """Test thread creation during step-over handling.""" @@ -56,7 +56,7 @@ @expectedFailureDarwin("llvm.org/pr15824") # thread states not properly maintained @expectedFailureFreeBSD("llvm.org/pr18190") # thread states not properly maintained - @expectedFailureLLGS("llvm.org/pr15824") # thread states not properly maintained + @expectedFailureLinux("llvm.org/pr15824") # thread states not properly maintained @dwarf_test def test_step_in_with_dwarf(self): """Test thread creation during step-in handling.""" Index: lldb/trunk/test/functionalities/thread/exit_during_break/TestExitDuringBreak.py =================================================================== --- lldb/trunk/test/functionalities/thread/exit_during_break/TestExitDuringBreak.py +++ lldb/trunk/test/functionalities/thread/exit_during_break/TestExitDuringBreak.py @@ -22,7 +22,7 @@ @expectedFailureDarwin("llvm.org/pr15824") # thread states not properly maintained @expectedFailureFreeBSD("llvm.org/pr18190") # thread states not properly maintained - @expectedFailureLLGS("llvm.org/pr15824") # thread states not properly maintained + @expectedFailureLinux("llvm.org/pr15824") # thread states not properly maintained @dwarf_test def test_with_dwarf(self): """Test thread exit during breakpoint handling.""" Index: lldb/trunk/test/functionalities/thread/exit_during_step/TestExitDuringStep.py =================================================================== --- lldb/trunk/test/functionalities/thread/exit_during_step/TestExitDuringStep.py +++ lldb/trunk/test/functionalities/thread/exit_during_step/TestExitDuringStep.py @@ -22,7 +22,7 @@ @expectedFailureDarwin("llvm.org/pr15824") # thread states not properly maintained @expectedFailureFreeBSD("llvm.org/pr18190") # thread states not properly maintained - @expectedFailureLLGS("llvm.org/pr15824") # thread states not properly maintained + @expectedFailureLinux("llvm.org/pr15824") # thread states not properly maintained @dwarf_test def test_thread_state_is_stopped_with_dwarf(self): """Test thread exit during step handling.""" @@ -58,7 +58,7 @@ self.exit_during_step_inst_test() @skipIfFreeBSD # llvm.org/pr21411: test is hanging - @expectedFailureLLGS("llvm.org/pr15824") # thread states not properly maintained + @expectedFailureLinux("llvm.org/pr15824") # thread states not properly maintained @dwarf_test def test_step_over_with_dwarf(self): """Test thread exit during step-over handling.""" @@ -66,7 +66,7 @@ self.exit_during_step_over_test() @skipIfFreeBSD # llvm.org/pr21411: test is hanging - @expectedFailureLLGS("llvm.org/pr15824") # thread states not properly maintained + @expectedFailureLinux("llvm.org/pr15824") # thread states not properly maintained @dwarf_test def test_step_in_with_dwarf(self): """Test thread exit during step-in handling.""" Index: lldb/trunk/test/functionalities/thread/multi_break/TestMultipleBreakpoints.py =================================================================== --- lldb/trunk/test/functionalities/thread/multi_break/TestMultipleBreakpoints.py +++ lldb/trunk/test/functionalities/thread/multi_break/TestMultipleBreakpoints.py @@ -22,7 +22,7 @@ @expectedFailureDarwin("llvm.org/pr15824") # thread states not properly maintained @expectedFailureFreeBSD("llvm.org/pr18190") # thread states not properly maintained - @expectedFailureLLGS("llvm.org/pr15824") # thread states not properly maintained + @expectedFailureLinux("llvm.org/pr15824") # thread states not properly maintained @dwarf_test def test_with_dwarf(self): """Test simultaneous breakpoints in multiple threads.""" Index: lldb/trunk/test/functionalities/thread/state/TestThreadStates.py =================================================================== --- lldb/trunk/test/functionalities/thread/state/TestThreadStates.py +++ lldb/trunk/test/functionalities/thread/state/TestThreadStates.py @@ -22,7 +22,7 @@ @expectedFailureDarwin("rdar://15367566") @expectedFailureFreeBSD('llvm.org/pr15824') - @expectedFailureLLGS("llvm.org/pr15824") # thread states not properly maintained + @expectedFailureLinux("llvm.org/pr15824") # thread states not properly maintained @dwarf_test def test_state_after_breakpoint_with_dwarf(self): """Test thread state after breakpoint.""" Index: lldb/trunk/test/lldbtest.py =================================================================== --- lldb/trunk/test/lldbtest.py +++ lldb/trunk/test/lldbtest.py @@ -712,15 +712,6 @@ return expectedFailure(fn, bugnumber) -def expectedFailureLLGS(bugnumber=None, compilers=None): - def fn(self): - # llgs local is only an option on Linux targets - if self.getPlatform() != 'linux': - return False - self.runCmd('settings show platform.plugin.linux.use-llgs-for-local') - return 'true' in self.res.GetOutput() and self.expectedCompiler(compilers) - return expectedFailure(fn, bugnumber) - def skipIfRemote(func): """Decorate the item to skip tests if testing remotely.""" if isinstance(func, type) and issubclass(func, unittest2.TestCase):