pkgsrc-WIP-changes archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
lldb-git: Resume work on Process plugin @ NetBSD
Module Name: pkgsrc-wip
Committed By: Kamil Rytarowski <n54%gmx.com@localhost>
Pushed By: kamil
Date: Tue May 3 21:48:25 2016 +0200
Changeset: 5420d03b3b106d5ae46d70e883221d112557dc3f
Modified Files:
lldb-git/distinfo
Added Files:
lldb-git/patches/patch-source_Plugins_Process_CMakeLists.txt
lldb-git/patches/patch-source_Plugins_Process_NetBSD_CMakeLists.txt
lldb-git/patches/patch-source_Plugins_Process_NetBSD_NetBSDThread.cpp
lldb-git/patches/patch-source_Plugins_Process_NetBSD_NetBSDThread.h
lldb-git/patches/patch-source_Plugins_Process_NetBSD_POSIXStopInfo.cpp
lldb-git/patches/patch-source_Plugins_Process_NetBSD_POSIXStopInfo.h
lldb-git/patches/patch-source_Plugins_Process_NetBSD_ProcessMonitor.cpp
lldb-git/patches/patch-source_Plugins_Process_NetBSD_ProcessMonitor.h
lldb-git/patches/patch-source_Plugins_Process_NetBSD_ProcessNetBSD.cpp
lldb-git/patches/patch-source_Plugins_Process_NetBSD_ProcessNetBSD.h
lldb-git/patches/patch-source_Plugins_Process_NetBSD_RegisterContextPOSIX.h
lldb-git/patches/patch-source_Plugins_Process_NetBSD_RegisterContextPOSIXProcessMonitor__x86.cpp
lldb-git/patches/patch-source_Plugins_Process_NetBSD_RegisterContextPOSIXProcessMonitor__x86.h
Log Message:
lldb-git: Resume work on Process plugin @ NetBSD
To see a diff of this commit:
https://wip.pkgsrc.org/cgi-bin/gitweb.cgi?p=pkgsrc-wip.git;a=commitdiff;h=5420d03b3b106d5ae46d70e883221d112557dc3f
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
diffstat:
lldb-git/distinfo | 14 +
.../patch-source_Plugins_Process_CMakeLists.txt | 12 +
...ch-source_Plugins_Process_NetBSD_CMakeLists.txt | 17 +
...-source_Plugins_Process_NetBSD_NetBSDThread.cpp | 632 +++++++++
...ch-source_Plugins_Process_NetBSD_NetBSDThread.h | 147 +++
...source_Plugins_Process_NetBSD_POSIXStopInfo.cpp | 97 ++
...h-source_Plugins_Process_NetBSD_POSIXStopInfo.h | 115 ++
...ource_Plugins_Process_NetBSD_ProcessMonitor.cpp | 1349 ++++++++++++++++++++
...-source_Plugins_Process_NetBSD_ProcessMonitor.h | 308 +++++
...source_Plugins_Process_NetBSD_ProcessNetBSD.cpp | 941 ++++++++++++++
...h-source_Plugins_Process_NetBSD_ProcessNetBSD.h | 254 ++++
...e_Plugins_Process_NetBSD_RegisterContextPOSIX.h | 84 ++
...BSD_RegisterContextPOSIXProcessMonitor__x86.cpp | 623 +++++++++
...etBSD_RegisterContextPOSIXProcessMonitor__x86.h | 102 ++
14 files changed, 4695 insertions(+)
diffs:
diff --git a/lldb-git/distinfo b/lldb-git/distinfo
index faf5775..4b2ab8e 100644
--- a/lldb-git/distinfo
+++ b/lldb-git/distinfo
@@ -20,6 +20,20 @@ SHA1 (patch-include_lldb_Utility_regex2.h) = 822a47b1221368ec5442bfbdbc20fe4e370
SHA1 (patch-include_lldb_Utility_regex__impl.h) = 4d99669a756bd662ae28abc8cefe6e1538ef84b6
SHA1 (patch-include_lldb_Utility_regutils.h) = ea36409f8cd05dcf9b81144cbc136abc5fc3a190
SHA1 (patch-scripts_CMakeLists.txt) = 1f9515a9c615aab15ac6955894664e2187a5da88
+SHA1 (patch-source_Host_netbsd_HostThreadNetBSD.cpp) = 23a310a2d899d1e92008f399d59d8dd0648bdccc
+SHA1 (patch-source_Plugins_Process_CMakeLists.txt) = 895b469f32c4bec510a98d34b6af3a642523d4f2
+SHA1 (patch-source_Plugins_Process_NetBSD_CMakeLists.txt) = 86a06bff3059f5305f761f02362eed40c28537a6
+SHA1 (patch-source_Plugins_Process_NetBSD_NetBSDThread.cpp) = beaabe8555b152d95278d29bdf89a6d471ac924b
+SHA1 (patch-source_Plugins_Process_NetBSD_NetBSDThread.h) = ee37571f6aaf67c63371df3dfed1277794bb4d56
+SHA1 (patch-source_Plugins_Process_NetBSD_POSIXStopInfo.cpp) = 71110d7da7c6ad902591b8ac274577c88c140ea6
+SHA1 (patch-source_Plugins_Process_NetBSD_POSIXStopInfo.h) = 583821e5ebd35dc0612d39db00afbc09761b43b5
+SHA1 (patch-source_Plugins_Process_NetBSD_ProcessMonitor.cpp) = 41da9eccdf39fca23ea74f1913d625d4b72201d1
+SHA1 (patch-source_Plugins_Process_NetBSD_ProcessMonitor.h) = ff772445702c8fc00cbb47f93e8cda386284c5f3
+SHA1 (patch-source_Plugins_Process_NetBSD_ProcessNetBSD.cpp) = e35148da4957197ada44ad45da72e67ffe9f6b73
+SHA1 (patch-source_Plugins_Process_NetBSD_ProcessNetBSD.h) = 6e1c6a96bafd0ba7466c4551fad6990b3ada1a07
+SHA1 (patch-source_Plugins_Process_NetBSD_RegisterContextPOSIX.h) = 9eb4ccf2af59707ed532f8c23ffff9dab8c0631f
+SHA1 (patch-source_Plugins_Process_NetBSD_RegisterContextPOSIXProcessMonitor__x86.cpp) = 0aa01f8bdb096eaf4b1af5f0c729fddd3dcda648
+SHA1 (patch-source_Plugins_Process_NetBSD_RegisterContextPOSIXProcessMonitor__x86.h) = 63301063f6b73b2d06b37e44dfb98862d18575ae
SHA1 (patch-source_Plugins_SymbolFile_PDB_CMakeLists.txt) = 3465152684eabea85f4ae6250db7bf01fe06cf90
SHA1 (patch-source_Utility_CMakeLists.txt) = 5b10fe94d76135d8d5ba31862066841394dd45c1
SHA1 (patch-source_Utility_regcomp.c) = bd315000773bab38b6fe6d119420afbcb5b83a59
diff --git a/lldb-git/patches/patch-source_Plugins_Process_CMakeLists.txt b/lldb-git/patches/patch-source_Plugins_Process_CMakeLists.txt
new file mode 100644
index 0000000..fa6d2da
--- /dev/null
+++ b/lldb-git/patches/patch-source_Plugins_Process_CMakeLists.txt
@@ -0,0 +1,12 @@
+$NetBSD$
+
+--- source/Plugins/Process/CMakeLists.txt.orig 2016-05-01 10:39:36.000000000 +0000
++++ source/Plugins/Process/CMakeLists.txt
+@@ -5,6 +5,7 @@ elseif (CMAKE_SYSTEM_NAME MATCHES "FreeB
+ add_subdirectory(FreeBSD)
+ add_subdirectory(POSIX)
+ elseif (CMAKE_SYSTEM_NAME MATCHES "NetBSD")
++ add_subdirectory(NetBSD)
+ add_subdirectory(POSIX)
+ elseif (CMAKE_SYSTEM_NAME MATCHES "Windows")
+ add_subdirectory(Windows/Live)
diff --git a/lldb-git/patches/patch-source_Plugins_Process_NetBSD_CMakeLists.txt b/lldb-git/patches/patch-source_Plugins_Process_NetBSD_CMakeLists.txt
new file mode 100644
index 0000000..b13c07e
--- /dev/null
+++ b/lldb-git/patches/patch-source_Plugins_Process_NetBSD_CMakeLists.txt
@@ -0,0 +1,17 @@
+$NetBSD$
+
+--- source/Plugins/Process/NetBSD/CMakeLists.txt.orig 2016-05-03 20:18:09.414601924 +0000
++++ source/Plugins/Process/NetBSD/CMakeLists.txt
+@@ -0,0 +1,12 @@
++include_directories(.)
++include_directories(../POSIX)
++include_directories(../Utility)
++
++add_lldb_library(lldbPluginProcessNetBSD
++ ProcessNetBSD.cpp
++ NetBSDThread.cpp
++ ProcessMonitor.cpp
++
++ POSIXStopInfo.cpp
++ RegisterContextPOSIXProcessMonitor_x86.cpp
++ )
diff --git a/lldb-git/patches/patch-source_Plugins_Process_NetBSD_NetBSDThread.cpp b/lldb-git/patches/patch-source_Plugins_Process_NetBSD_NetBSDThread.cpp
new file mode 100644
index 0000000..4742fca
--- /dev/null
+++ b/lldb-git/patches/patch-source_Plugins_Process_NetBSD_NetBSDThread.cpp
@@ -0,0 +1,632 @@
+$NetBSD$
+
+--- source/Plugins/Process/NetBSD/NetBSDThread.cpp.orig 2016-05-03 20:18:09.420439886 +0000
++++ source/Plugins/Process/NetBSD/NetBSDThread.cpp
+@@ -0,0 +1,627 @@
++//===-- NetBSDThread.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 <errno.h>
++
++// C++ Includes
++// Other libraries and framework includes
++#include "lldb/Core/State.h"
++#include "lldb/Target/UnixSignals.h"
++
++// 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 "NetBSDThread.h"
++#include "ProcessNetBSD.h"
++#include "ProcessPOSIXLog.h"
++#include "ProcessMonitor.h"
++#include "RegisterContextPOSIXProcessMonitor_x86.h"
++#include "Plugins/Process/Utility/RegisterContextNetBSD_x86_64.h"
++#include "Plugins/Process/Utility/UnwindLLDB.h"
++
++using namespace lldb;
++using namespace lldb_private;
++
++NetBSDThread::NetBSDThread(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 ("NetBSDThread::%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();
++ }
++ }
++}
++
++NetBSDThread::~NetBSDThread()
++{
++ DestroyThread();
++}
++
++ProcessMonitor &
++NetBSDThread::GetMonitor()
++{
++ ProcessSP base = GetProcess();
++ ProcessNetBSD &process = static_cast<ProcessNetBSD&>(*base);
++ return process.GetMonitor();
++}
++
++void
++NetBSDThread::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);
++ }
++}
++
++const char *
++NetBSDThread::GetInfo()
++{
++ return NULL;
++}
++
++void
++NetBSDThread::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 *
++NetBSDThread::GetName ()
++{
++ if (!m_thread_name_valid)
++ {
++ llvm::SmallString<32> thread_name;
++ HostNativeThread::GetName(/*GetID()*/ ::pthread_self(), 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
++NetBSDThread::GetRegisterContext()
++{
++ if (!m_reg_context_sp)
++ {
++ m_posix_thread = NULL;
++
++ RegisterInfoInterface *reg_interface = NULL;
++ const ArchSpec &target_arch = GetProcess()->GetTarget().GetArchitecture();
++
++ assert(target_arch.GetTriple().getOS() == llvm::Triple::NetBSD);
++ switch (target_arch.GetMachine())
++ {
++ case llvm::Triple::x86_64:
++ reg_interface = new RegisterContextNetBSD_x86_64(target_arch);
++ break;
++ default:
++ llvm_unreachable("CPU not supported");
++ }
++
++ switch (target_arch.GetMachine())
++ {
++ 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
++NetBSDThread::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 ("NetBSDThread::%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
++NetBSDThread::GetThreadPointer ()
++{
++ ProcessMonitor &monitor = GetMonitor();
++ addr_t addr;
++ if (monitor.ReadThreadPointer (GetID(), addr))
++ return addr;
++ else
++ return LLDB_INVALID_ADDRESS;
++}
++
++bool
++NetBSDThread::CalculateStopInfo()
++{
++ SetStopInfo (m_stop_info_sp);
++ return true;
++}
++
++Unwind *
++NetBSDThread::GetUnwinder()
++{
++ if (m_unwinder_ap.get() == NULL)
++ m_unwinder_ap.reset(new UnwindLLDB(*this));
++
++ return m_unwinder_ap.get();
++}
++
++void
++NetBSDThread::DidStop()
++{
++ // Don't set the thread state to stopped unless we really stopped.
++}
++
++void
++NetBSDThread::WillResume(lldb::StateType resume_state)
++{
++ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
++ if (log)
++ log->Printf("tid %lu resume_state = %s", GetID(),
++ lldb_private::StateAsCString(resume_state));
++ ProcessSP process_sp(GetProcess());
++ ProcessNetBSD *process = static_cast<ProcessNetBSD *>(process_sp.get());
++ int signo = GetResumeSignal();
++ bool signo_valid = process->GetUnixSignals()->SignalIsValid(signo);
++
++ switch (resume_state)
++ {
++ case eStateSuspended:
++ case eStateStopped:
++ process->m_suspend_tids.push_back(GetID());
++ break;
++ case eStateRunning:
++ process->m_run_tids.push_back(GetID());
++ if (signo_valid)
++ process->m_resume_signo = signo;
++ break;
++ case eStateStepping:
++ process->m_step_tids.push_back(GetID());
++ if (signo_valid)
++ process->m_resume_signo = signo;
++ break;
++ default:
++ break;
++ }
++}
++
++bool
++NetBSDThread::Resume()
++{
++ lldb::StateType resume_state = GetResumeState();
++ ProcessMonitor &monitor = GetMonitor();
++ bool status;
++
++ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
++ if (log)
++ log->Printf ("NetBSDThread::%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
++NetBSDThread::Notify(const ProcessMessage &message)
++{
++ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
++ if (log)
++ log->Printf ("NetBSDThread::%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::eExecMessage:
++ ExecNotify(message);
++ break;
++ }
++}
++
++bool
++NetBSDThread::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
++NetBSDThread::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
++NetBSDThread::NumSupportedHardwareWatchpoints()
++{
++ lldb::RegisterContextSP reg_ctx_sp = GetRegisterContext();
++ if (reg_ctx_sp.get())
++ return reg_ctx_sp->NumSupportedHardwareWatchpoints();
++ return 0;
++}
++
++uint32_t
++NetBSDThread::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
++NetBSDThread::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 ("NetBSDThread::%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
++NetBSDThread::WatchNotify(const ProcessMessage &message)
++{
++ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
++
++ lldb::addr_t halt_addr = message.GetHWAddress();
++ if (log)
++ log->Printf ("NetBSDThread::%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
++NetBSDThread::TraceNotify(const ProcessMessage &message)
++{
++ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
++
++ // Try to resolve the breakpoint object corresponding to the current PC.
++ assert(GetRegisterContext());
++ lldb::addr_t pc = GetRegisterContext()->GetPC();
++ if (log)
++ log->Printf ("NetBSDThread::%s () PC=0x%8.8" PRIx64, __FUNCTION__, pc);
++ lldb::BreakpointSiteSP bp_site(GetProcess()->GetBreakpointSiteList().FindByAddress(pc));
++
++ // If the current pc is a breakpoint site then set the StopInfo to Breakpoint.
++ // Otherwise, set the StopInfo to Watchpoint or Trace.
++ // 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 && (bp_site->ValidForThisThread(this) || GetProcess()->GetOperatingSystem () != NULL))
++ SetStopInfo(StopInfo::CreateStopReasonWithBreakpointSiteID(*this, bp_site->GetID()));
++ else
++ {
++ 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
++NetBSDThread::LimboNotify(const ProcessMessage &message)
++{
++ SetStopInfo (lldb::StopInfoSP(new POSIXLimboStopInfo(*this)));
++}
++
++void
++NetBSDThread::SignalNotify(const ProcessMessage &message)
++{
++ int signo = message.GetSignal();
++ SetStopInfo (StopInfo::CreateStopReasonWithSignal(*this, signo));
++}
++
++void
++NetBSDThread::SignalDeliveredNotify(const ProcessMessage &message)
++{
++ int signo = message.GetSignal();
++ SetStopInfo (StopInfo::CreateStopReasonWithSignal(*this, signo));
++}
++
++void
++NetBSDThread::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 ("NetBSDThread::%s () signo = %i, reason = '%s'",
++ __FUNCTION__, signo, message.PrintCrashReason());
++
++ SetStopInfo (lldb::StopInfoSP(new POSIXCrashStopInfo(*this, signo,
++ message.GetCrashReason(),
++ message.GetFaultAddress())));
++}
++
++unsigned
++NetBSDThread::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::x86_64:
++ {
++ POSIXBreakpointProtocol* reg_ctx = GetPOSIXBreakpointProtocol();
++ reg = reg_ctx->GetRegisterIndexFromOffset(offset);
++ }
++ break;
++ }
++ return reg;
++}
++
++void
++NetBSDThread::ExecNotify(const ProcessMessage &message)
++{
++ SetStopInfo (StopInfo::CreateStopReasonWithExec(*this));
++}
++
++const char *
++NetBSDThread::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::x86_64:
++ name = GetRegisterContext()->GetRegisterName(reg);
++ break;
++ }
++ return name;
++}
++
++const char *
++NetBSDThread::GetRegisterNameFromOffset(unsigned offset)
++{
++ return GetRegisterName(GetRegisterIndexFromOffset(offset));
++}
diff --git a/lldb-git/patches/patch-source_Plugins_Process_NetBSD_NetBSDThread.h b/lldb-git/patches/patch-source_Plugins_Process_NetBSD_NetBSDThread.h
new file mode 100644
index 0000000..cdc72bb
--- /dev/null
+++ b/lldb-git/patches/patch-source_Plugins_Process_NetBSD_NetBSDThread.h
@@ -0,0 +1,147 @@
+$NetBSD$
+
+--- source/Plugins/Process/NetBSD/NetBSDThread.h.orig 2016-05-03 20:18:09.426252287 +0000
++++ source/Plugins/Process/NetBSD/NetBSDThread.h
+@@ -0,0 +1,142 @@
++//===-- NetBSDThread.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_NetBSDThread_H_
++#define liblldb_NetBSDThread_H_
++
++// C++ Includes
++#include <memory>
++#include <string>
++
++// Other libraries and framework includes
++#include "lldb/Target/Thread.h"
++#include "RegisterContextPOSIX.h"
++
++class ProcessMessage;
++class ProcessMonitor;
++class POSIXBreakpointProtocol;
++
++//------------------------------------------------------------------------------
++// @class NetBSDThread
++// @brief Abstraction of a NetBSD thread.
++class NetBSDThread
++ : public lldb_private::Thread
++{
++public:
++
++ //------------------------------------------------------------------
++ // Constructors and destructors
++ //------------------------------------------------------------------
++ NetBSDThread(lldb_private::Process &process, lldb::tid_t tid);
++
++ virtual ~NetBSDThread();
++
++ // 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<lldb_private::StackFrame> 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 ExitNotify(const ProcessMessage &message);
++ void ExecNotify(const ProcessMessage &message);
++
++ lldb_private::Unwind *
++ GetUnwinder() override;
++
++ //--------------------------------------------------------------------------
++ // NetBSDThread internal API.
++
++ // POSIXThread override
++ virtual void
++ WillResume(lldb::StateType resume_state) override;
++};
++
++#endif // #ifndef liblldb_NetBSDThread_H_
diff --git a/lldb-git/patches/patch-source_Plugins_Process_NetBSD_POSIXStopInfo.cpp b/lldb-git/patches/patch-source_Plugins_Process_NetBSD_POSIXStopInfo.cpp
new file mode 100644
index 0000000..fee5c89
--- /dev/null
+++ b/lldb-git/patches/patch-source_Plugins_Process_NetBSD_POSIXStopInfo.cpp
@@ -0,0 +1,97 @@
+$NetBSD$
+
+--- source/Plugins/Process/NetBSD/POSIXStopInfo.cpp.orig 2016-05-03 20:18:09.431983532 +0000
++++ source/Plugins/Process/NetBSD/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(NetBSDThread &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;
++}
diff --git a/lldb-git/patches/patch-source_Plugins_Process_NetBSD_POSIXStopInfo.h b/lldb-git/patches/patch-source_Plugins_Process_NetBSD_POSIXStopInfo.h
new file mode 100644
index 0000000..c455c5a
--- /dev/null
+++ b/lldb-git/patches/patch-source_Plugins_Process_NetBSD_POSIXStopInfo.h
@@ -0,0 +1,115 @@
+$NetBSD$
+
+--- source/Plugins/Process/NetBSD/POSIXStopInfo.h.orig 2016-05-03 20:18:09.437595209 +0000
++++ source/Plugins/Process/NetBSD/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 "NetBSDThread.h"
++
++#include <string>
++
++//===----------------------------------------------------------------------===//
++/// @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(NetBSDThread &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(NetBSDThread &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 (NetBSDThread &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
diff --git a/lldb-git/patches/patch-source_Plugins_Process_NetBSD_ProcessMonitor.cpp b/lldb-git/patches/patch-source_Plugins_Process_NetBSD_ProcessMonitor.cpp
new file mode 100644
index 0000000..4b4f1c3
--- /dev/null
+++ b/lldb-git/patches/patch-source_Plugins_Process_NetBSD_ProcessMonitor.cpp
@@ -0,0 +1,1349 @@
+$NetBSD$
+
+--- source/Plugins/Process/NetBSD/ProcessMonitor.cpp.orig 2016-05-03 20:18:09.443684111 +0000
++++ source/Plugins/Process/NetBSD/ProcessMonitor.cpp
+@@ -0,0 +1,1344 @@
++//===-- 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 <errno.h>
++#include <poll.h>
++#include <string.h>
++#include <stdint.h>
++#include <unistd.h>
++#include <signal.h>
++#include <sys/ptrace.h>
++#include <sys/socket.h>
++#include <sys/types.h>
++#include <sys/wait.h>
++
++// C++ Includes
++// Other libraries and framework includes
++#include "lldb/Core/Error.h"
++#include "lldb/Core/RegisterValue.h"
++#include "lldb/Core/Scalar.h"
++#include "lldb/Host/Host.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 "NetBSDThread.h"
++#include "ProcessNetBSD.h"
++#include "ProcessPOSIXLog.h"
++#include "ProcessMonitor.h"
++
++extern "C" {
++ extern char ** environ;
++ }
++
++using namespace lldb;
++using namespace lldb_private;
++
++// We disable the tracing of ptrace calls for integration builds to
++// avoid the additional indirection and checks.
++#ifndef LLDB_CONFIGURATION_BUILDANDINTEGRATION
++// Wrapper for ptrace to catch errors and log calls.
++
++const char *
++Get_PT_IO_OP(int op)
++{
++ switch (op) {
++ case PIOD_READ_D: return "READ_D";
++ case PIOD_WRITE_D: return "WRITE_D";
++ case PIOD_READ_I: return "READ_I";
++ case PIOD_WRITE_I: return "WRITE_I";
++ default: return "Unknown op";
++ }
++}
++
++// Wrapper for ptrace to catch errors and log calls.
++// Note that ptrace sets errno on error because -1 is reserved as a valid result.
++extern long
++PtraceWrapper(int req, lldb::pid_t pid, void *addr, int data,
++ const char* reqName, const char* file, int line)
++{
++ long int result;
++
++ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
++
++ if (log) {
++ log->Printf("ptrace(%s, %" PRIu64 ", %p, %x) called from file %s line %d",
++ reqName, pid, addr, data, file, line);
++ if (req == PT_IO) {
++ struct ptrace_io_desc *pi = (struct ptrace_io_desc *) addr;
++
++ log->Printf("PT_IO: op=%s offs=%zx size=%zu",
++ Get_PT_IO_OP(pi->piod_op), (size_t)pi->piod_offs, pi->piod_len);
++ }
++ }
++
++ //PtraceDisplayBytes(req, data);
++
++ errno = 0;
++ result = ptrace(req, pid, (caddr_t) addr, data);
++
++ //PtraceDisplayBytes(req, data);
++
++ 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 = "<unknown>";
++ }
++ log->Printf("ptrace() failed; errno=%d (%s)", errno, str);
++ }
++
++ if (log) {
++#ifdef __amd64__
++ if (req == PT_GETREGS) {
++ struct reg *r = (struct reg *) addr;
++
++ log->Printf("PT_GETREGS: rip=0x%lx rsp=0x%lx rbp=0x%lx rax=0x%lx",
++ r->regs[_REG_RIP], r->regs[_REG_RSP], r->regs[_REG_RBP], r->regs[_REG_RAX]);
++ }
++#endif
++ }
++
++ return result;
++}
++
++// Wrapper for ptrace when logging is not required.
++// Sets errno to 0 prior to calling ptrace.
++extern long
++PtraceWrapper(int req, lldb::pid_t pid, void *addr, int data)
++{
++ long result = 0;
++ errno = 0;
++ result = ptrace(req, pid, (caddr_t)addr, data);
++ return result;
++}
++
++#define PTRACE(req, pid, addr, data) \
++ PtraceWrapper((req), (pid), (addr), (data), #req, __FILE__, __LINE__)
++#else
++ PtraceWrapper((req), (pid), (addr), (data))
++#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)
++{
++ struct ptrace_io_desc pi_desc;
++
++ pi_desc.piod_op = PIOD_READ_D;
++ pi_desc.piod_offs = (void *)vm_addr;
++ pi_desc.piod_addr = buf;
++ pi_desc.piod_len = size;
++
++ if (PTRACE(PT_IO, pid, (caddr_t)&pi_desc, 0) < 0)
++ error.SetErrorToErrno();
++ return pi_desc.piod_len;
++}
++
++static size_t
++DoWriteMemory(lldb::pid_t pid, lldb::addr_t vm_addr, const void *buf,
++ size_t size, Error &error)
++{
++ struct ptrace_io_desc pi_desc;
++
++ pi_desc.piod_op = PIOD_WRITE_D;
++ pi_desc.piod_offs = (void *)vm_addr;
++ pi_desc.piod_addr = (void *)buf;
++ pi_desc.piod_len = size;
++
++ if (PTRACE(PT_IO, pid, (caddr_t)&pi_desc, 0) < 0)
++ error.SetErrorToErrno();
++ return pi_desc.piod_len;
++}
++
++// 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 NetBSD, 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);
++
++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);
++
++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, unsigned size,
++ RegisterValue &value, bool &result)
++ : m_tid(tid), m_offset(offset), m_size(size),
++ m_value(value), m_result(result)
++ { }
++
++ void Execute(ProcessMonitor *monitor);
++
++private:
++ lldb::tid_t m_tid;
++ unsigned m_offset;
++ unsigned m_size;
++ RegisterValue &m_value;
++ bool &m_result;
++};
++
++void
++ReadRegOperation::Execute(ProcessMonitor *monitor)
++{
++ struct reg regs;
++ int rc;
++
++ if ((rc = PTRACE(PT_GETREGS, m_tid, (caddr_t)®s, 0)) < 0) {
++ m_result = false;
++ } else {
++ // 'struct reg' contains only 32- or 64-bit register values. Punt on
++ // others. Also, not all entries may be uintptr_t sized, such as 32-bit
++ // processes on powerpc64 (probably the same for i386 on amd64)
++ if (m_size == sizeof(uint32_t))
++ m_value = *(uint32_t *)(((caddr_t)®s) + m_offset);
++ else if (m_size == sizeof(uint64_t))
++ m_value = *(uint64_t *)(((caddr_t)®s) + m_offset);
++ else
++ memcpy((void *)&m_value, (((caddr_t)®s) + m_offset), m_size);
++ m_result = true;
++ }
++}
++
++//------------------------------------------------------------------------------
++/// @class WriteRegOperation
++/// @brief Implements ProcessMonitor::WriteRegisterValue.
++class WriteRegOperation : public Operation
++{
++public:
++ WriteRegOperation(lldb::tid_t tid, unsigned offset,
++ const RegisterValue &value, bool &result)
++ : m_tid(tid), m_offset(offset),
++ m_value(value), m_result(result)
++ { }
++
++ void Execute(ProcessMonitor *monitor);
++
++private:
++ lldb::tid_t m_tid;
++ unsigned m_offset;
++ const RegisterValue &m_value;
++ bool &m_result;
++};
++
++void
++WriteRegOperation::Execute(ProcessMonitor *monitor)
++{
++ struct reg regs;
++
++ if (PTRACE(PT_GETREGS, m_tid, (caddr_t)®s, 0) < 0) {
++ m_result = false;
++ return;
++ }
++ *(uintptr_t *)(((caddr_t)®s) + m_offset) = (uintptr_t)m_value.GetAsUInt64();
++ if (PTRACE(PT_SETREGS, m_tid, (caddr_t)®s, 0) < 0)
++ m_result = false;
++ else
++ m_result = true;
++}
++
++//------------------------------------------------------------------------------
++/// @class ReadGPROperation
++/// @brief Implements ProcessMonitor::ReadGPR.
++class ReadGPROperation : public Operation
++{
++public:
++ ReadGPROperation(lldb::tid_t tid, void *buf, bool &result)
++ : m_tid(tid), m_buf(buf), m_result(result)
++ { }
++
++ void Execute(ProcessMonitor *monitor);
++
++private:
++ lldb::tid_t m_tid;
++ void *m_buf;
++ bool &m_result;
++};
++
++void
++ReadGPROperation::Execute(ProcessMonitor *monitor)
++{
++ int rc;
++
++ errno = 0;
++ rc = PTRACE(PT_GETREGS, m_tid, (caddr_t)m_buf, 0);
++ if (errno != 0)
++ m_result = false;
++ else
++ m_result = true;
++}
++
++//------------------------------------------------------------------------------
++/// @class ReadFPROperation
++/// @brief Implements ProcessMonitor::ReadFPR.
++class ReadFPROperation : public Operation
++{
++public:
++ ReadFPROperation(lldb::tid_t tid, void *buf, bool &result)
++ : m_tid(tid), m_buf(buf), m_result(result)
++ { }
++
++ void Execute(ProcessMonitor *monitor);
++
++private:
++ lldb::tid_t m_tid;
++ void *m_buf;
++ bool &m_result;
++};
++
++void
++ReadFPROperation::Execute(ProcessMonitor *monitor)
++{
++ if (PTRACE(PT_GETFPREGS, m_tid, (caddr_t)m_buf, 0) < 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, bool &result)
++ : m_tid(tid), m_buf(buf), m_result(result)
++ { }
++
++ void Execute(ProcessMonitor *monitor);
++
++private:
++ lldb::tid_t m_tid;
++ void *m_buf;
++ bool &m_result;
++};
++
++void
++WriteGPROperation::Execute(ProcessMonitor *monitor)
++{
++ if (PTRACE(PT_SETREGS, m_tid, (caddr_t)m_buf, 0) < 0)
++ m_result = false;
++ else
++ m_result = true;
++}
++
++//------------------------------------------------------------------------------
++/// @class WriteFPROperation
++/// @brief Implements ProcessMonitor::WriteFPR.
++class WriteFPROperation : public Operation
++{
++public:
++ WriteFPROperation(lldb::tid_t tid, void *buf, bool &result)
++ : m_tid(tid), m_buf(buf), m_result(result)
++ { }
++
++ void Execute(ProcessMonitor *monitor);
++
++private:
++ lldb::tid_t m_tid;
++ void *m_buf;
++ bool &m_result;
++};
++
++void
++WriteFPROperation::Execute(ProcessMonitor *monitor)
++{
++ if (PTRACE(PT_SETFPREGS, m_tid, (caddr_t)m_buf, 0) < 0)
++ m_result = false;
++ else
++ m_result = true;
++}
++
++//------------------------------------------------------------------------------
++/// @class ResumeOperation
++/// @brief Implements ProcessMonitor::Resume.
++class ResumeOperation : public Operation
++{
++public:
++ ResumeOperation(uint32_t signo, bool &result) :
++ m_signo(signo), m_result(result) { }
++
++ void Execute(ProcessMonitor *monitor);
++
++private:
++ uint32_t m_signo;
++ bool &m_result;
++};
++
++void
++ResumeOperation::Execute(ProcessMonitor *monitor)
++{
++ lldb::pid_t pid = monitor->GetPID();
++ int data = 0;
++
++ if (m_signo != LLDB_INVALID_SIGNAL_NUMBER)
++ data = m_signo;
++
++ if (PTRACE(PT_CONTINUE, pid, (caddr_t)1, data))
++ {
++ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
++
++ if (log)
++ log->Printf ("ResumeOperation (%" PRIu64 ") failed: %s", pid, strerror(errno));
++ m_result = false;
++ }
++ else
++ m_result = true;
++}
++
++//------------------------------------------------------------------------------
++/// @class SingleStepOperation
++/// @brief Implements ProcessMonitor::SingleStep.
++class SingleStepOperation : public Operation
++{
++public:
++ SingleStepOperation(uint32_t signo, bool &result)
++ : m_signo(signo), m_result(result) { }
++
++ void Execute(ProcessMonitor *monitor);
++
++private:
++ uint32_t m_signo;
++ bool &m_result;
++};
++
++void
++SingleStepOperation::Execute(ProcessMonitor *monitor)
++{
++ lldb::pid_t pid = monitor->GetPID();
++ int data = 0;
++
++ if (m_signo != LLDB_INVALID_SIGNAL_NUMBER)
++ data = m_signo;
++
++ if (PTRACE(PT_STEP, pid, NULL, data))
++ m_result = false;
++ else
++ m_result = true;
++}
++
++//------------------------------------------------------------------------------
++/// @class LwpInfoOperation
++/// @brief Implements ProcessMonitor::GetLwpInfo.
++class LwpInfoOperation : public Operation
++{
++public:
++ LwpInfoOperation(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);
++
++private:
++ lldb::tid_t m_tid;
++ void *m_info;
++ bool &m_result;
++ int &m_err;
++};
++
++void
++LwpInfoOperation::Execute(ProcessMonitor *monitor)
++{
++ struct ptrace_lwpinfo plwp;
++
++ if (PTRACE(PT_LWPINFO, m_tid, (caddr_t)&plwp, sizeof(plwp))) {
++ m_result = false;
++ m_err = errno;
++ } else {
++ memcpy(m_info, &plwp, sizeof(plwp));
++ m_result = true;
++ }
++}
++
++//------------------------------------------------------------------------------
++/// @class ThreadSuspendOperation
++/// @brief Implements ProcessMonitor::ThreadSuspend.
++class ThreadSuspendOperation : public Operation
++{
++public:
++ ThreadSuspendOperation(lldb::tid_t tid, bool suspend, bool &result)
++ : m_tid(tid), m_suspend(suspend), m_result(result) { }
++
++ void Execute(ProcessMonitor *monitor);
++
++private:
++ lldb::tid_t m_tid;
++ bool m_suspend;
++ bool &m_result;
++} ;
++
++//------------------------------------------------------------------------------
++/// @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);
++
++private:
++ lldb::tid_t m_tid;
++ unsigned long *m_message;
++ bool &m_result;
++};
++
++void
++EventMessageOperation::Execute(ProcessMonitor *monitor)
++{
++ struct ptrace_lwpinfo plwp;
++
++ if (PTRACE(PT_LWPINFO, m_tid, (caddr_t)&plwp, sizeof(plwp)))
++ m_result = false;
++ else
++ m_result = true;
++}
++
++//------------------------------------------------------------------------------
++/// @class KillOperation
++/// @brief Implements ProcessMonitor::Kill.
++class KillOperation : public Operation
++{
++public:
++ KillOperation(bool &result) : m_result(result) { }
++
++ void Execute(ProcessMonitor *monitor);
++
++private:
++ bool &m_result;
++};
++
++void
++KillOperation::Execute(ProcessMonitor *monitor)
++{
++ lldb::pid_t pid = monitor->GetPID();
++
++ if (PTRACE(PT_KILL, pid, NULL, 0))
++ m_result = false;
++ else
++ m_result = true;
++}
++
++//------------------------------------------------------------------------------
++/// @class DetachOperation
++/// @brief Implements ProcessMonitor::Detach.
++class DetachOperation : public Operation
++{
++public:
++ DetachOperation(Error &result) : m_error(result) { }
++
++ void Execute(ProcessMonitor *monitor);
++
++private:
++ Error &m_error;
++};
++
++void
++DetachOperation::Execute(ProcessMonitor *monitor)
++{
++ lldb::pid_t pid = monitor->GetPID();
++
++ if (PTRACE(PT_DETACH, pid, 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)
++ : 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) { }
++
++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 ProcessNetBSD 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(ProcessNetBSD *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<ProcessNetBSD *>(process)),
++ m_pid(LLDB_INVALID_PROCESS_ID),
++ m_terminal_fd(-1),
++ m_operation(0)
++{
++ std::unique_ptr<LaunchArgs> args(new LaunchArgs(this, module, argv, envp,
++ stdin_file_spec,
++ stdout_file_spec,
++ stderr_file_spec,
++ working_dir));
++
++
++ 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(ProcessNetBSD *process,
++ lldb::pid_t pid,
++ lldb_private::Error &error)
++ : m_process(static_cast<ProcessNetBSD *>(process)),
++ m_pid(pid),
++ m_terminal_fd(-1),
++ m_operation(0)
++{
++ sem_init(&m_operation_pending, 0, 0);
++ sem_init(&m_operation_done, 0, 0);
++
++
++ std::unique_ptr<AttachArgs> 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.netbsd.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<LaunchArgs*>(arg);
++
++ if (!Launch(args)) {
++ sem_post(&args->m_semaphore);
++ return NULL;
++ }
++
++ ServeOperation(args);
++ return NULL;
++}
++
++bool
++ProcessMonitor::Launch(LaunchArgs *args)
++{
++ ProcessMonitor *monitor = args->m_monitor;
++ ProcessNetBSD &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];
++ ::pid_t pid;
++
++ // Propagate the environment if one is not supplied.
++ if (envp == NULL || envp[0] == NULL)
++ envp = const_cast<const char **>(environ);
++
++ if ((pid = terminal.Fork(err_str, err_len)) == -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(PT_TRACE_ME, 0, 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);
++
++ // Execute. We should never return.
++ execve(argv[0],
++ const_cast<char *const *>(argv),
++ const_cast<char *const *>(envp));
++ exit(eExecFailed);
++ }
++
++ // Wait for the child process to to trap on its call to execve.
++ ::pid_t wpid;
++ int status;
++ if ((wpid = waitpid(pid, &status, 0)) < 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_t)pid &&
++ "Could not sync with inferior process.");
++
++#ifdef notyet
++ // Have the child raise an event on exit. This is used to keep the child in
++ // limbo until it is destroyed.
++ if (PTRACE(PTRACE_SETOPTIONS, pid, NULL, PTRACE_O_TRACEEXIT) < 0)
++ {
++ args->m_error.SetErrorToErrno();
++ goto FINISH;
++ }
++#endif
++ // 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 ProcessNetBSD::GetSTDOUT to have a non-blocking
++ // descriptor to read from).
++ if (!EnsureFDFlags(monitor->m_terminal_fd, O_NONBLOCK, args->m_error))
++ goto FINISH;
++
++ process.SendMessage(ProcessMessage::Attach(pid));
++
++FINISH:
++ return args->m_error.Success();
++}
++
++void
++ProcessMonitor::StartAttachOpThread(AttachArgs *args, lldb_private::Error &error)
++{
++ static const char *g_thread_name = "lldb.process.netbsd.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<AttachArgs*>(arg);
++
++ Attach(args);
++
++ ServeOperation(args);
++ return NULL;
++}
++
++void
++ProcessMonitor::Attach(AttachArgs *args)
++{
++ lldb::pid_t pid = args->m_pid;
++
++ ProcessMonitor *monitor = args->m_monitor;
++ ProcessNetBSD &process = monitor->GetProcess();
++
++ if (pid <= 1)
++ {
++ args->m_error.SetErrorToGenericError();
++ args->m_error.SetErrorString("Attaching to process 1 is not allowed.");
++ return;
++ }
++
++ // Attach to the requested process.
++ if (PTRACE(PT_ATTACH, pid, NULL, 0) < 0)
++ {
++ args->m_error.SetErrorToErrno();
++ return;
++ }
++
++ int status;
++ if ((status = waitpid(pid, NULL, 0)) < 0)
++ {
++ args->m_error.SetErrorToErrno();
++ return;
++ }
++
++ process.SendMessage(ProcessMessage::Attach(pid));
++}
++
++bool
++ProcessMonitor::MonitorCallback(void *callback_baton,
++ lldb::pid_t pid,
++ bool exited,
++ int signal,
++ int status)
++{
++ ProcessMessage message;
++ ProcessMonitor *monitor = static_cast<ProcessMonitor*>(callback_baton);
++ ProcessNetBSD *process = monitor->m_process;
++ assert(process);
++ bool stop_monitoring;
++ struct ptrace_lwpinfo plwp;
++ 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->GetLwpInfo(pid, &plwp, ptrace_err))
++ {
++ stop_monitoring = true; // pid is gone. Bail.
++ }
++
++ return stop_monitoring;
++}
++
++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
++ sem_wait(&monitor->m_operation_pending);
++
++ 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
++ sem_wait(&m_operation_done);
++}
++
++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, size, value, result);
++ DoOperation(&op);
++ return result;
++}
++
++bool
++ProcessMonitor::WriteRegisterValue(lldb::tid_t tid, unsigned offset,
++ const char* reg_name, const RegisterValue &value)
++{
++ bool result;
++ WriteRegOperation op(tid, offset, 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, result);
++ DoOperation(&op);
++ return result;
++}
++
++bool
++ProcessMonitor::ReadFPR(lldb::tid_t tid, void *buf, size_t buf_size)
++{
++ bool result;
++ ReadFPROperation op(tid, buf, result);
++ DoOperation(&op);
++ return result;
++}
++
++bool
++ProcessMonitor::ReadRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset)
++{
++ return false;
++}
++
++bool
++ProcessMonitor::WriteGPR(lldb::tid_t tid, void *buf, size_t buf_size)
++{
++ bool result;
++ WriteGPROperation op(tid, buf, result);
++ DoOperation(&op);
++ return result;
++}
++
++bool
++ProcessMonitor::WriteFPR(lldb::tid_t tid, void *buf, size_t buf_size)
++{
++ bool result;
++ WriteFPROperation op(tid, buf, result);
++ DoOperation(&op);
++ return result;
++}
++
++bool
++ProcessMonitor::WriteRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset)
++{
++ return false;
++}
++
++bool
++ProcessMonitor::ReadThreadPointer(lldb::tid_t tid, lldb::addr_t &value)
++{
++ return false;
++}
++
++bool
++ProcessMonitor::SingleStep(lldb::tid_t unused, uint32_t signo)
++{
++ bool result;
++ SingleStepOperation op(signo, result);
++ DoOperation(&op);
++ return result;
++}
++
++bool
++ProcessMonitor::Kill()
++{
++ bool result;
++ KillOperation op(result);
++ DoOperation(&op);
++ return result;
++}
++
++bool
++ProcessMonitor::GetLwpInfo(lldb::tid_t tid, void *lwpinfo, int &ptrace_err)
++{
++ bool result;
++ LwpInfoOperation op(tid, lwpinfo, 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(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())
++ {
++ m_monitor_thread.Cancel();
++ m_monitor_thread.Join(nullptr);
++ m_monitor_thread.Reset();
++ }
++}
++
++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;
++ }
++}
++
++// FIXME: 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.
++//
++// Right now, the above logic is in ProcessPOSIX, so we need a definition of
++// this function in the NetBSD ProcessMonitor implementation even if it isn't
++// logically needed.
++//
++// We really should figure out what actually happens on NetBSD and move the
++// Linux-specific logic out of ProcessPOSIX as needed.
++
++bool
++ProcessMonitor::WaitForInitialTIDStop(lldb::tid_t tid)
++{
++ return true;
++}
++
++void
++ProcessMonitor::StopOpThread()
++{
++ if (!m_operation_thread.IsJoinable())
++ return;
++
++ m_operation_thread.Cancel();
++ m_operation_thread.Join(nullptr);
++ m_operation_thread.Reset();
++}
diff --git a/lldb-git/patches/patch-source_Plugins_Process_NetBSD_ProcessMonitor.h b/lldb-git/patches/patch-source_Plugins_Process_NetBSD_ProcessMonitor.h
new file mode 100644
index 0000000..f887f0a
--- /dev/null
+++ b/lldb-git/patches/patch-source_Plugins_Process_NetBSD_ProcessMonitor.h
@@ -0,0 +1,308 @@
+$NetBSD$
+
+--- source/Plugins/Process/NetBSD/ProcessMonitor.h.orig 2016-05-03 20:18:09.450107065 +0000
++++ source/Plugins/Process/NetBSD/ProcessMonitor.h
+@@ -0,0 +1,303 @@
++//===-- 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 <semaphore.h>
++#include <signal.h>
++
++// 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;
++} // End lldb_private namespace.
++
++class ProcessNetBSD;
++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
++/// ProcessNetBSD instance by calling ProcessNetBSD::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(ProcessNetBSD *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(ProcessNetBSD *process,
++ lldb::pid_t pid,
++ lldb_private::Error &error);
++
++ ~ProcessMonitor();
++
++ /// Provides the process number of debugee.
++ lldb::pid_t
++ GetPID() const { return m_pid; }
++
++ /// Returns the process associated with this ProcessMonitor.
++ ProcessNetBSD &
++ 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 RegisterContextNetBSD 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 RegisterContextNetBSD 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 all floating point registers into the specified buffer.
++ bool
++ ReadFPR(lldb::tid_t tid, void *buf, size_t buf_size);
++
++ /// Reads the specified register set into the specified buffer.
++ ///
++ /// This method is provided for use by RegisterContextNetBSD derivatives.
++ 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 all 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.
++ ///
++ /// This method is provided for use by RegisterContextNetBSD derivatives.
++ 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);
++
++ /// Returns current thread IDs in process
++ size_t
++ GetCurrentThreadIDs(std::vector<lldb::tid_t> &thread_ids);
++
++ /// Writes a ptrace_lwpinfo structure corresponding to the given thread ID
++ /// to the memory region pointed to by @p lwpinfo.
++ bool
++ GetLwpInfo(lldb::tid_t tid, void *lwpinfo, int &error_no);
++
++ /// Suspends or unsuspends a thread prior to process resume or step.
++ bool
++ ThreadSuspend(lldb::tid_t tid, bool suspend);
++
++ /// 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 process. If @p signo is anything but
++ /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the process.
++ bool
++ Resume(lldb::tid_t unused, uint32_t signo);
++
++ /// Single steps the process. If @p signo is anything but
++ /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the process.
++ bool
++ SingleStep(lldb::tid_t unused, uint32_t signo);
++
++ /// Terminate the traced process.
++ bool
++ Kill();
++
++ lldb_private::Error
++ Detach(lldb::tid_t tid);
++
++ void
++ StopMonitor();
++
++ // Waits for the initial stop message from a new thread.
++ bool
++ WaitForInitialTIDStop(lldb::tid_t tid);
++
++private:
++ ProcessNetBSD *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 privileged 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);
++
++ ~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.
++ };
++
++ 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 void
++ Attach(AttachArgs *args);
++
++ 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);
++
++ 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_
diff --git a/lldb-git/patches/patch-source_Plugins_Process_NetBSD_ProcessNetBSD.cpp b/lldb-git/patches/patch-source_Plugins_Process_NetBSD_ProcessNetBSD.cpp
new file mode 100644
index 0000000..2b48e6c
--- /dev/null
+++ b/lldb-git/patches/patch-source_Plugins_Process_NetBSD_ProcessNetBSD.cpp
@@ -0,0 +1,941 @@
+$NetBSD$
+
+--- source/Plugins/Process/NetBSD/ProcessNetBSD.cpp.orig 2016-05-03 20:18:09.456132900 +0000
++++ source/Plugins/Process/NetBSD/ProcessNetBSD.cpp
+@@ -0,0 +1,936 @@
++//===-- ProcessNetBSD.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 <errno.h>
++
++// C++ Includes
++#include <mutex>
++
++// 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 "ProcessNetBSD.h"
++#include "ProcessPOSIXLog.h"
++#include "Plugins/Process/Utility/InferiorCallPOSIX.h"
++#include "Plugins/Process/Utility/NetBSDSignals.h"
++#include "ProcessMonitor.h"
++#include "NetBSDThread.h"
++
++// 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 "lldb/Host/posix/Fcntl.h"
++
++
++using namespace lldb;
++using namespace lldb_private;
++
++namespace
++{
++ UnixSignalsSP&
++ GetNetBSDSignals ()
++ {
++ static UnixSignalsSP s_netbsd_signals_sp (new NetBSDSignals ());
++ return s_netbsd_signals_sp;
++ }
++}
++
++//------------------------------------------------------------------------------
++// Static functions.
++
++lldb::ProcessSP
++ProcessNetBSD::CreateInstance(lldb::TargetSP target_sp,
++ lldb::ListenerSP listener_sp,
++ const FileSpec *crash_file_path)
++{
++ lldb::ProcessSP process_sp;
++ if (crash_file_path == NULL)
++ process_sp.reset(new ProcessNetBSD (target_sp, listener_sp, GetNetBSDSignals()));
++ return process_sp;
++}
++
++void
++ProcessNetBSD::Initialize()
++{
++ static std::once_flag g_once_flag;
++
++ std::call_once(g_once_flag, []() {
++ PluginManager::RegisterPlugin(GetPluginNameStatic(),
++ GetPluginDescriptionStatic(),
++ CreateInstance);
++ ProcessPOSIXLog::Initialize(GetPluginNameStatic());
++ });
++}
++
++lldb_private::ConstString
++ProcessNetBSD::GetPluginNameStatic()
++{
++ static ConstString g_name("netbsd");
++ return g_name;
++}
++
++const char *
++ProcessNetBSD::GetPluginDescriptionStatic()
++{
++ return "Process plugin for NetBSD";
++}
++
++//------------------------------------------------------------------------------
++// ProcessInterface protocol.
++
++lldb_private::ConstString
++ProcessNetBSD::GetPluginName()
++{
++ return GetPluginNameStatic();
++}
++
++uint32_t
++ProcessNetBSD::GetPluginVersion()
++{
++ return 1;
++}
++
++void
++ProcessNetBSD::Terminate()
++{
++}
++
++Error
++ProcessNetBSD::DoDetach(bool keep_stopped)
++{
++ Error error;
++ if (keep_stopped)
++ {
++ error.SetErrorString("Detaching with keep_stopped true is not currently supported on NetBSD.");
++ return error;
++ }
++
++ error = m_monitor->Detach(GetID());
++
++ if (error.Success())
++ SetPrivateState(eStateDetached);
++
++ return error;
++}
++
++bool
++ProcessNetBSD::UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_thread_list)
++{
++ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
++ if (log)
++ log->Printf("ProcessNetBSD::%s (pid = %" PRIu64 ")", __FUNCTION__, GetID());
++
++ std::vector<lldb::pid_t> tds;
++ if (!GetMonitor().GetCurrentThreadIDs(tds))
++ {
++ return false;
++ }
++
++ ThreadList old_thread_list_copy(old_thread_list);
++ for (size_t i = 0; i < tds.size(); ++i)
++ {
++ tid_t tid = tds[i];
++ ThreadSP thread_sp (old_thread_list_copy.RemoveThreadByID(tid, false));
++ if (!thread_sp)
++ {
++ thread_sp.reset(new NetBSDThread(*this, tid));
++ if (log)
++ log->Printf("ProcessNetBSD::%s new tid = %" PRIu64, __FUNCTION__, tid);
++ }
++ else
++ {
++ if (log)
++ log->Printf("ProcessNetBSD::%s existing tid = %" PRIu64, __FUNCTION__, tid);
++ }
++ new_thread_list.AddThread(thread_sp);
++ }
++ for (size_t i = 0; i < old_thread_list_copy.GetSize(false); ++i)
++ {
++ ThreadSP old_thread_sp(old_thread_list_copy.GetThreadAtIndex(i, false));
++ if (old_thread_sp)
++ {
++ if (log)
++ log->Printf("ProcessNetBSD::%s remove tid", __FUNCTION__);
++ }
++ }
++
++ return true;
++}
++
++Error
++ProcessNetBSD::WillResume()
++{
++ m_resume_signo = 0;
++ m_suspend_tids.clear();
++ m_run_tids.clear();
++ m_step_tids.clear();
++ return Process::WillResume();
++}
++
++void
++ProcessNetBSD::SendMessage(const ProcessMessage &message)
++{
++ Mutex::Locker lock(m_message_mutex);
++
++ switch (message.GetKind())
++ {
++ case ProcessMessage::eInvalidMessage:
++ return;
++
++ case ProcessMessage::eAttachMessage:
++ SetPrivateState(eStateStopped);
++ return;
++
++ case ProcessMessage::eLimboMessage:
++ case ProcessMessage::eExitMessage:
++ SetExitStatus(message.GetExitStatus(), NULL);
++ break;
++
++ case ProcessMessage::eSignalMessage:
++ case ProcessMessage::eSignalDeliveredMessage:
++ case ProcessMessage::eBreakpointMessage:
++ case ProcessMessage::eTraceMessage:
++ case ProcessMessage::eWatchpointMessage:
++ case ProcessMessage::eCrashMessage:
++ SetPrivateState(eStateStopped);
++ break;
++
++ case ProcessMessage::eNewThreadMessage:
++ llvm_unreachable("eNewThreadMessage unexpected on NetBSD");
++ break;
++
++ case ProcessMessage::eExecMessage:
++ SetPrivateState(eStateStopped);
++ break;
++ }
++
++ m_message_queue.push(message);
++}
++
++//------------------------------------------------------------------------------
++// Constructors and destructors.
++
++ProcessNetBSD::ProcessNetBSD(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, UnixSignalsSP &unix_signals_sp)
++ : Process(target_sp, listener_sp, unix_signals_sp),
++ m_byte_order(endian::InlHostByteOrder()),
++ m_monitor(NULL),
++ m_module(NULL),
++ m_message_mutex (Mutex::eMutexTypeRecursive),
++ m_exit_now(false),
++ m_seen_initial_stop(),
++ m_resume_signo(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.
++ lldb::ModuleSP module = GetTarget().GetExecutableModule();
++ if (module && module->GetObjectFile())
++ m_byte_order = module->GetObjectFile()->GetByteOrder();
++}
++
++ProcessNetBSD::~ProcessNetBSD()
++{
++ delete m_monitor;
++}
++
++//------------------------------------------------------------------------------
++// Process protocol.
++void
++ProcessNetBSD::Finalize()
++{
++ Process::Finalize();
++
++ if (m_monitor)
++ m_monitor->StopMonitor();
++}
++
++bool
++ProcessNetBSD::CanDebug(lldb::TargetSP target_sp, bool plugin_specified_by_name)
++{
++ // For now we are just making sure the file exists for a given module
++ ModuleSP exe_module_sp(target_sp->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
++ProcessNetBSD::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 ("ProcessNetBSD::%s(pid = %" PRIi64 ")", __FUNCTION__, GetID());
++
++ m_monitor = new ProcessMonitor(this, pid, error);
++
++ if (!error.Success())
++ return error;
++
++ PlatformSP platform_sp (GetTarget().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(), GetTarget().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() && !GetTarget().GetArchitecture().IsExactMatch(module_arch))
++ GetTarget().SetArchitecture(module_arch);
++
++ // Initialize the target module list
++ GetTarget().SetExecutableModule (exe_module_sp, true);
++
++ SetSTDIOFileDescriptor(m_monitor->GetTerminalFD());
++
++ SetID(pid);
++
++ return error;
++}
++
++Error
++ProcessNetBSD::WillLaunch(Module* module)
++{
++ Error error;
++ return error;
++}
++
++FileSpec
++ProcessNetBSD::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
++ProcessNetBSD::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
++ProcessNetBSD::DidLaunch()
++{
++}
++
++addr_t
++ProcessNetBSD::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
++ProcessNetBSD::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
++ProcessNetBSD::DoSignal(int signal)
++{
++ Error error;
++
++ if (kill(GetID(), signal))
++ error.SetErrorToErrno();
++
++ return error;
++}
++
++Error
++ProcessNetBSD::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
++ProcessNetBSD::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);
++ }
++ }
++}
++
++bool
++ProcessNetBSD::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
++ProcessNetBSD::WaitingForInitialStop(lldb::tid_t stop_tid)
++{
++ return (m_seen_initial_stop.find(stop_tid) == m_seen_initial_stop.end());
++}
++
++NetBSDThread *
++ProcessNetBSD::CreateNewNetBSDThread(lldb_private::Process &process, lldb::tid_t tid)
++{
++ return new NetBSDThread(process, tid);
++}
++
++void
++ProcessNetBSD::RefreshStateAfterStop()
++{
++ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
++ if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
++ log->Printf ("ProcessNetBSD::%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 ("ProcessNetBSD::%s(), message_queue size = %d, pid = %" PRIi64, __FUNCTION__, (int)m_message_queue.size(), tid);
++
++ m_thread_list.RefreshStateAfterStop();
++
++ NetBSDThread *thread = static_cast<NetBSDThread*>(
++ 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 ("ProcessNetBSD::%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
++ProcessNetBSD::IsAlive()
++{
++ StateType state = GetPrivateState();
++ return state != eStateDetached
++ && state != eStateExited
++ && state != eStateInvalid
++ && state != eStateUnloaded;
++}
++
++size_t
++ProcessNetBSD::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
++ProcessNetBSD::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
++ProcessNetBSD::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
++ProcessNetBSD::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
++ProcessNetBSD::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::x86_64:
++ opcode = g_i386_opcode;
++ opcode_size = sizeof(g_i386_opcode);
++ break;
++ }
++
++ bp_site->SetTrapOpcode(opcode, opcode_size);
++ return opcode_size;
++}
++
++Error
++ProcessNetBSD::EnableBreakpointSite(BreakpointSite *bp_site)
++{
++ return EnableSoftwareBreakpoint(bp_site);
++}
++
++Error
++ProcessNetBSD::DisableBreakpointSite(BreakpointSite *bp_site)
++{
++ return DisableSoftwareBreakpoint(bp_site);
++}
++
++Error
++ProcessNetBSD::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 ("ProcessNetBSD::EnableWatchpoint(watchID = %" PRIu64 ")",
++ watchID);
++ if (wp->IsEnabled())
++ {
++ if (log)
++ log->Printf("ProcessNetBSD::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());
++ NetBSDThread *thread = static_cast<NetBSDThread*>(
++ 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<NetBSDThread*>(
++ 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
++ProcessNetBSD::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("ProcessNetBSD::DisableWatchpoint(watchID = %" PRIu64 ")",
++ watchID);
++ if (!wp->IsEnabled())
++ {
++ if (log)
++ log->Printf("ProcessNetBSD::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)
++ {
++ NetBSDThread *thread = static_cast<NetBSDThread*>(
++ 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
++ProcessNetBSD::GetWatchpointSupportInfo(uint32_t &num)
++{
++ Error error;
++ Mutex::Locker lock(m_thread_list.GetMutex());
++ NetBSDThread *thread = static_cast<NetBSDThread*>(
++ m_thread_list.GetThreadAtIndex(0, false).get());
++ if (thread)
++ num = thread->NumSupportedHardwareWatchpoints();
++ else
++ error.SetErrorString("Process does not exist.");
++ return error;
++}
++
++Error
++ProcessNetBSD::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
++ProcessNetBSD::UpdateThreadListIfNeeded()
++{
++ Mutex::Locker lock(m_thread_list.GetMutex());
++ // Do not allow recursive updates.
++ return m_thread_list.GetSize(false);
++}
++
++ByteOrder
++ProcessNetBSD::GetByteOrder() const
++{
++ // FIXME: We should be able to extract this value directly. See comment in
++ // ProcessNetBSD().
++ return m_byte_order;
++}
++
++size_t
++ProcessNetBSD::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
++ProcessNetBSD::HasExited()
++{
++ switch (GetPrivateState())
++ {
++ default:
++ break;
++
++ case eStateDetached:
++ case eStateExited:
++ return true;
++ }
++
++ return false;
++}
++
++bool
++ProcessNetBSD::IsStopped()
++{
++ switch (GetPrivateState())
++ {
++ default:
++ break;
++
++ case eStateStopped:
++ case eStateCrashed:
++ case eStateSuspended:
++ return true;
++ }
++
++ return false;
++}
++
++bool
++ProcessNetBSD::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)
++ {
++ NetBSDThread *thread = static_cast<NetBSDThread*>(
++ 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
++ProcessNetBSD::GetAuxvData ()
++{
++ // If we're the local platform, we can ask the host for auxv data.
++ PlatformSP platform_sp = GetTarget().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 ProcessNetBSD?");
++ return DataBufferSP ();
++}
diff --git a/lldb-git/patches/patch-source_Plugins_Process_NetBSD_ProcessNetBSD.h b/lldb-git/patches/patch-source_Plugins_Process_NetBSD_ProcessNetBSD.h
new file mode 100644
index 0000000..f2807e8
--- /dev/null
+++ b/lldb-git/patches/patch-source_Plugins_Process_NetBSD_ProcessNetBSD.h
@@ -0,0 +1,254 @@
+$NetBSD$
+
+--- source/Plugins/Process/NetBSD/ProcessNetBSD.h.orig 2016-05-03 20:18:09.462107752 +0000
++++ source/Plugins/Process/NetBSD/ProcessNetBSD.h
+@@ -0,0 +1,249 @@
++//===-- ProcessNetBSD.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_ProcessNetBSD_H_
++#define liblldb_ProcessNetBSD_H_
++
++// C Includes
++
++// C++ Includes
++#include <set>
++#include <queue>
++
++// Other libraries and framework includes
++#include "lldb/Target/Process.h"
++#include "lldb/Target/ThreadList.h"
++#include "ProcessMessage.h"
++#include "ProcessNetBSD.h"
++
++class ProcessMonitor;
++class NetBSDThread;
++
++class ProcessNetBSD :
++ public lldb_private::Process
++{
++
++public:
++ //------------------------------------------------------------------
++ // Static functions.
++ //------------------------------------------------------------------
++ static lldb::ProcessSP
++ CreateInstance(lldb::TargetSP target_sp,
++ lldb::ListenerSP listener_sp,
++ const lldb_private::FileSpec *crash_file_path);
++
++ static void
++ Initialize();
++
++ static void
++ Terminate();
++
++ static lldb_private::ConstString
++ GetPluginNameStatic();
++
++ static const char *
++ GetPluginDescriptionStatic();
++
++ //------------------------------------------------------------------
++ // Constructors and destructors
++ //------------------------------------------------------------------
++ ProcessNetBSD(lldb::TargetSP target_sp,
++ lldb::ListenerSP listener_sp,
++ lldb::UnixSignalsSP &unix_signals_sp);
++
++ ~ProcessNetBSD();
++
++ virtual lldb_private::Error
++ WillResume() override;
++
++ //------------------------------------------------------------------
++ // PluginInterface protocol
++ //------------------------------------------------------------------
++ virtual lldb_private::ConstString
++ GetPluginName() override;
++
++ virtual uint32_t
++ GetPluginVersion() override;
++
++public:
++ //------------------------------------------------------------------
++ // Process protocol.
++ //------------------------------------------------------------------
++ void
++ Finalize() override;
++
++ bool
++ CanDebug(lldb::TargetSP target_sp, 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;
++
++ 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;
++
++ 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;
++
++ //--------------------------------------------------------------------------
++ // ProcessNetBSD 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);
++
++ /// 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 NetBSDThread *
++ CreateNewNetBSDThread(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<ProcessMessage> 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<lldb::addr_t, lldb::addr_t> MMapMap;
++ MMapMap m_addr_to_mmap_size;
++
++ typedef std::set<lldb::tid_t> 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;
++
++ friend class NetBSDThread;
++
++ typedef std::vector<lldb::tid_t> tid_collection;
++ tid_collection m_suspend_tids;
++ tid_collection m_run_tids;
++ tid_collection m_step_tids;
++
++ int m_resume_signo;
++
++};
++
++#endif // liblldb_ProcessNetBSD_H_
diff --git a/lldb-git/patches/patch-source_Plugins_Process_NetBSD_RegisterContextPOSIX.h b/lldb-git/patches/patch-source_Plugins_Process_NetBSD_RegisterContextPOSIX.h
new file mode 100644
index 0000000..7d0c92b
--- /dev/null
+++ b/lldb-git/patches/patch-source_Plugins_Process_NetBSD_RegisterContextPOSIX.h
@@ -0,0 +1,84 @@
+$NetBSD$
+
+--- source/Plugins/Process/NetBSD/RegisterContextPOSIX.h.orig 2016-05-03 20:18:09.467970089 +0000
++++ source/Plugins/Process/NetBSD/RegisterContextPOSIX.h
+@@ -0,0 +1,79 @@
++//===-- RegisterContextPOSIX.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_RegisterContextPOSIX_H_
++#define liblldb_RegisterContextPOSIX_H_
++
++// C Includes
++// C++ Includes
++// Other libraries and framework includes
++#include "lldb/Core/ArchSpec.h"
++#include "lldb/Target/RegisterContext.h"
++#include "RegisterInfoInterface.h"
++
++//------------------------------------------------------------------------------
++/// @class POSIXBreakpointProtocol
++///
++/// @brief Extends RegisterClass with a few virtual operations useful on POSIX.
++class POSIXBreakpointProtocol
++{
++public:
++ POSIXBreakpointProtocol()
++ { m_watchpoints_initialized = false; }
++ virtual ~POSIXBreakpointProtocol() {}
++
++ /// Updates the register state of the associated thread after hitting a
++ /// breakpoint (if that make sense for the architecture). Default
++ /// implementation simply returns true for architectures which do not
++ /// require any update.
++ ///
++ /// @return
++ /// True if the operation succeeded and false otherwise.
++ virtual bool UpdateAfterBreakpoint() = 0;
++
++ /// Determines the index in lldb's register file given a kernel byte offset.
++ virtual unsigned
++ GetRegisterIndexFromOffset(unsigned offset) = 0;
++
++ // Checks to see if a watchpoint specified by hw_index caused the inferior
++ // to stop.
++ virtual bool
++ IsWatchpointHit (uint32_t hw_index) = 0;
++
++ // Resets any watchpoints that have been hit.
++ virtual bool
++ ClearWatchpointHits () = 0;
++
++ // Returns the watchpoint address associated with a watchpoint hardware
++ // index.
++ virtual lldb::addr_t
++ GetWatchpointAddress (uint32_t hw_index) = 0;
++
++ virtual bool
++ IsWatchpointVacant (uint32_t hw_index) = 0;
++
++ virtual bool
++ SetHardwareWatchpointWithIndex (lldb::addr_t addr, size_t size,
++ bool read, bool write,
++ uint32_t hw_index) = 0;
++
++ // From lldb_private::RegisterContext
++ virtual uint32_t
++ NumSupportedHardwareWatchpoints () = 0;
++
++ // Force m_watchpoints_initialized to TRUE
++ void
++ ForceWatchpointsInitialized () {m_watchpoints_initialized = true;}
++
++protected:
++ bool m_watchpoints_initialized;
++};
++
++#endif // #ifndef liblldb_RegisterContextPOSIX_H_
++
diff --git a/lldb-git/patches/patch-source_Plugins_Process_NetBSD_RegisterContextPOSIXProcessMonitor__x86.cpp b/lldb-git/patches/patch-source_Plugins_Process_NetBSD_RegisterContextPOSIXProcessMonitor__x86.cpp
new file mode 100644
index 0000000..906e4a3
--- /dev/null
+++ b/lldb-git/patches/patch-source_Plugins_Process_NetBSD_RegisterContextPOSIXProcessMonitor__x86.cpp
@@ -0,0 +1,623 @@
+$NetBSD$
+
+--- source/Plugins/Process/NetBSD/RegisterContextPOSIXProcessMonitor_x86.cpp.orig 2016-05-03 20:18:09.474357842 +0000
++++ source/Plugins/Process/NetBSD/RegisterContextPOSIXProcessMonitor_x86.cpp
+@@ -0,0 +1,618 @@
++//===-- 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/NetBSD/ProcessNetBSD.h"
++#include "RegisterContextPOSIXProcessMonitor_x86.h"
++#include "Plugins/Process/NetBSD/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)
++{
++ // Store byte offset of fctrl (i.e. first register of FPR) wrt 'UserArea'
++ const RegisterInfo *reg_info_fctrl = GetRegisterInfoByName("fctrl");
++ m_fctrl_offset_in_userarea = reg_info_fctrl->byte_offset;
++}
++
++ProcessMonitor &
++RegisterContextPOSIXProcessMonitor_x86_64::GetMonitor()
++{
++ ProcessSP base = CalculateProcess();
++ ProcessNetBSD *process = static_cast<ProcessNetBSD*>(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();
++
++ 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();
++
++ 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.
++ // Byte offsets of all registers are calculated wrt 'UserArea' structure.
++ // However, ReadFPR() reads fpu registers {using ptrace(PT_GETFPREGS,..)}
++ // and stores them in 'm_fpr' (of type FPR structure). To extract values of fpu
++ // registers, m_fpr should be read at byte offsets calculated wrt to FPR structure.
++
++ // Since, FPR structure is also one of the member of UserArea structure.
++ // byte_offset(fpu wrt FPR) = byte_offset(fpu wrt UserArea) - byte_offset(fctrl wrt UserArea)
++ assert ( (reg_info->byte_offset - m_fctrl_offset_in_userarea) < sizeof(m_fpr));
++ uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset - m_fctrl_offset_in_userarea;
++ switch (reg_info->byte_size)
++ {
++ case 1:
++ value.SetUInt8(*(uint8_t *)src);
++ return true;
++ 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.
++ // Byte offsets of all registers are calculated wrt 'UserArea' structure.
++ // However, WriteFPR() takes m_fpr (of type FPR structure) and writes only fpu
++ // registers using ptrace(PT_SETFPREGS,..) API. Hence fpu registers should
++ // be written in m_fpr at byte offsets calculated wrt FPR structure.
++
++ // Since, FPR structure is also one of the member of UserArea structure.
++ // byte_offset(fpu wrt FPR) = byte_offset(fpu wrt UserArea) - byte_offset(fctrl wrt UserArea)
++ assert ( (reg_info->byte_offset - m_fctrl_offset_in_userarea) < sizeof(m_fpr));
++ uint8_t *dst = (uint8_t *)&m_fpr + reg_info->byte_offset - m_fctrl_offset_in_userarea;
++ switch (reg_info->byte_size)
++ {
++ case 1:
++ *(uint8_t *)dst = value.GetAsUInt8();
++ break;
++ 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;
++
++ return false;
++}
++
++uint32_t
++RegisterContextPOSIXProcessMonitor_x86_64::NumSupportedHardwareWatchpoints()
++{
++ // Available debug address registers: NONE
++ return 0;
++}
diff --git a/lldb-git/patches/patch-source_Plugins_Process_NetBSD_RegisterContextPOSIXProcessMonitor__x86.h b/lldb-git/patches/patch-source_Plugins_Process_NetBSD_RegisterContextPOSIXProcessMonitor__x86.h
new file mode 100644
index 0000000..7e8485c
--- /dev/null
+++ b/lldb-git/patches/patch-source_Plugins_Process_NetBSD_RegisterContextPOSIXProcessMonitor__x86.h
@@ -0,0 +1,102 @@
+$NetBSD$
+
+--- source/Plugins/Process/NetBSD/RegisterContextPOSIXProcessMonitor_x86.h.orig 2016-05-03 20:18:09.480714306 +0000
++++ source/Plugins/Process/NetBSD/RegisterContextPOSIXProcessMonitor_x86.h
+@@ -0,0 +1,97 @@
++//===-- 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 "RegisterContextPOSIX.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();
++ uint32_t m_fctrl_offset_in_userarea; // Offset of 'fctrl' in 'UserArea' Structure
++};
++
++#endif
Home |
Main Index |
Thread Index |
Old Index