pkgsrc-WIP-changes archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

edb-debugger-git: DebuggerCore initial port to NetBSD



Module Name:	pkgsrc-wip
Committed By:	Kamil Rytarowski <n54%gmx.com@localhost>
Pushed By:	kamil
Date:		Sun Feb 19 03:05:29 2017 +0100
Changeset:	6f915ca9cf6662dea5fac998459da1fa72eca919

Modified Files:
	edb-debugger-git/distinfo
	edb-debugger-git/patches/patch-include_os_unix_OSTypes.h
	edb-debugger-git/patches/patch-plugins_DebuggerCore_unix_netbsd_DebuggerCore.cpp
	edb-debugger-git/patches/patch-plugins_DebuggerCore_unix_netbsd_DebuggerCore.h
	edb-debugger-git/patches/patch-plugins_DebuggerCore_unix_netbsd_PlatformEvent.h
Added Files:
	edb-debugger-git/patches/patch-plugins_DebuggerCore_unix_netbsd_DialogMemoryAccess.ui

Log Message:
edb-debugger-git: DebuggerCore initial port to NetBSD

Pity that the original FreeBSD code was long dead and irrelevant.

To see a diff of this commit:
https://wip.pkgsrc.org/cgi-bin/gitweb.cgi?p=pkgsrc-wip.git;a=commitdiff;h=6f915ca9cf6662dea5fac998459da1fa72eca919

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

diffstat:
 edb-debugger-git/distinfo                          |   9 +-
 .../patches/patch-include_os_unix_OSTypes.h        |   3 +-
 ...ugins_DebuggerCore_unix_netbsd_DebuggerCore.cpp | 812 +++++++++++++--------
 ...plugins_DebuggerCore_unix_netbsd_DebuggerCore.h | 113 +--
 ..._DebuggerCore_unix_netbsd_DialogMemoryAccess.ui |  95 +++
 ...lugins_DebuggerCore_unix_netbsd_PlatformEvent.h |  11 +-
 6 files changed, 656 insertions(+), 387 deletions(-)

diffs:
diff --git a/edb-debugger-git/distinfo b/edb-debugger-git/distinfo
index 148720eadf..642f3d5fef 100644
--- a/edb-debugger-git/distinfo
+++ b/edb-debugger-git/distinfo
@@ -5,21 +5,22 @@ RMD160 (edb-debugger-0.9.21.tar.gz) = d7821e07b607667090b1158b559053856ef077de
 SHA512 (edb-debugger-0.9.21.tar.gz) = 88a04cafb2c27a3af6bcfc48c841c795fb5bba348f64fe52957716c2c03e4cd056d045b241135c5be7fd7174d2c5a35fa5c95dc2b6aad4fb5c04f4fe36ab4f0d
 Size (edb-debugger-0.9.21.tar.gz) = 996932 bytes
 SHA1 (patch-CMakeLists.txt) = d714177643b1f8b3a37c8d6bd51953c5fb296239
-SHA1 (patch-include_os_unix_OSTypes.h) = bc7d3f584c7e8e40ad029e83141a186629b4c1eb
+SHA1 (patch-include_os_unix_OSTypes.h) = 8209e8cd487b4b93532847df9166c0abecb00c48
 SHA1 (patch-include_os_unix_netbsd_linker.h) = d09a31187b4e7c0d4a20db6c32806cc8fd710538
 SHA1 (patch-plugins_Analyzer_Analyzer.cpp) = 511efa03a82a96612d64fd43b9e6631e4d6aeb76
 SHA1 (patch-plugins_Assembler_DialogAssembler.cpp) = 2bd6418dc078aae0c84c6092f15619e202e43b31
 SHA1 (patch-plugins_DebuggerCore_CMakeLists.txt) = 18b3f0bd7c7c7ec4eaa6526c81b7c4299c7ee3f4
-SHA1 (patch-plugins_DebuggerCore_unix_netbsd_DebuggerCore.cpp) = e48d60ec404717b0822ddd75bb69ea7b2360230e
-SHA1 (patch-plugins_DebuggerCore_unix_netbsd_DebuggerCore.h) = 9ae7087401a657750ceda08e4fafd064ffd8a021
+SHA1 (patch-plugins_DebuggerCore_unix_netbsd_DebuggerCore.cpp) = 716e48cbe859d12cd31a50040fc556e4f26fd659
+SHA1 (patch-plugins_DebuggerCore_unix_netbsd_DebuggerCore.h) = 6dc06aa1d0d05741cce3f8cffbee5d0c3c377be3
 SHA1 (patch-plugins_DebuggerCore_unix_netbsd_DialogMemoryAccess.cpp) = 5096c5fc7b1812545faf70194b1d02985fc1546f
 SHA1 (patch-plugins_DebuggerCore_unix_netbsd_DialogMemoryAccess.h) = 390ce937f71b3b4c5c63dd668dc42115d2e0622c
+SHA1 (patch-plugins_DebuggerCore_unix_netbsd_DialogMemoryAccess.ui) = fb6689928090b65e3cb6f6e69886199a447c2fa6
 SHA1 (patch-plugins_DebuggerCore_unix_netbsd_FeatureDetect.cpp) = d7a577e879e30447122985e09609cc195670157f
 SHA1 (patch-plugins_DebuggerCore_unix_netbsd_FeatureDetect.h) = 4e5a8906e904d76f4fa85a5e1919a37f57083d1e
 SHA1 (patch-plugins_DebuggerCore_unix_netbsd_PlatformCommon.cpp) = b1b07940d1a717ffd24ccd4bb028c098e5a6a8b6
 SHA1 (patch-plugins_DebuggerCore_unix_netbsd_PlatformCommon.h) = 7431b033535e272689814eb7647043aa5c9282c1
 SHA1 (patch-plugins_DebuggerCore_unix_netbsd_PlatformEvent.cpp) = 62e99fc234d072fa4ba82435216349eb76af2076
-SHA1 (patch-plugins_DebuggerCore_unix_netbsd_PlatformEvent.h) = ef2b3d1e4106a137c8474aabbec7f30ee0524eb0
+SHA1 (patch-plugins_DebuggerCore_unix_netbsd_PlatformEvent.h) = 1781ca113c68b2e88051c7bf49bf388f61169ece
 SHA1 (patch-plugins_DebuggerCore_unix_netbsd_PlatformProcess.cpp) = 06bc435f25546ef3f27cf60ba815f7dc9d8f9706
 SHA1 (patch-plugins_DebuggerCore_unix_netbsd_PlatformProcess.h) = a4ddbd5c6f486695d4de27954ed65de4ec8bb288
 SHA1 (patch-plugins_DebuggerCore_unix_netbsd_PlatformRegion.cpp) = dc5b3caa442e041658da7aac8e59d51ccfe0c130
diff --git a/edb-debugger-git/patches/patch-include_os_unix_OSTypes.h b/edb-debugger-git/patches/patch-include_os_unix_OSTypes.h
index 6b38c94399..c450f533eb 100644
--- a/edb-debugger-git/patches/patch-include_os_unix_OSTypes.h
+++ b/edb-debugger-git/patches/patch-include_os_unix_OSTypes.h
@@ -2,11 +2,12 @@ $NetBSD$
 
 --- include/os/unix/OSTypes.h.orig	2017-02-18 21:21:09.000000000 +0000
 +++ include/os/unix/OSTypes.h
-@@ -24,7 +24,11 @@ along with this program.  If not, see <h
+@@ -24,7 +24,12 @@ along with this program.  If not, see <h
  namespace edb {
  	using   ::pid_t;
  	using   ::uid_t;
 +#if defined(__NetBSD__)
++	typedef ::pid_t pid_t;
 +	typedef ::lwpid_t tid_t;
 +#else
  	typedef ::pid_t tid_t;
diff --git a/edb-debugger-git/patches/patch-plugins_DebuggerCore_unix_netbsd_DebuggerCore.cpp b/edb-debugger-git/patches/patch-plugins_DebuggerCore_unix_netbsd_DebuggerCore.cpp
index 2f96331dc7..d4f570d5c4 100644
--- a/edb-debugger-git/patches/patch-plugins_DebuggerCore_unix_netbsd_DebuggerCore.cpp
+++ b/edb-debugger-git/patches/patch-plugins_DebuggerCore_unix_netbsd_DebuggerCore.cpp
@@ -2,7 +2,7 @@ $NetBSD$
 
 --- plugins/DebuggerCore/unix/netbsd/DebuggerCore.cpp.orig	2017-02-19 00:51:04.557463589 +0000
 +++ plugins/DebuggerCore/unix/netbsd/DebuggerCore.cpp
-@@ -0,0 +1,596 @@
+@@ -0,0 +1,760 @@
 +/*
 +Copyright (C) 2006 - 2015 Evan Teran
 +                          evan.teran%gmail.com@localhost
@@ -21,69 +21,149 @@ $NetBSD$
 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +*/
 +
++
++// TODO(eteran): research usage of process_vm_readv, process_vm_writev
++
 +#include "DebuggerCore.h"
++#include "Configuration.h"
++#include "FeatureDetect.h"
++#include "MemoryRegions.h"
++#include "PlatformCommon.h"
 +#include "PlatformEvent.h"
++#include "PlatformProcess.h"
 +#include "PlatformRegion.h"
 +#include "PlatformState.h"
++#include "DialogMemoryAccess.h"
 +#include "State.h"
++#include "edb.h"
 +#include "string_hash.h"
 +
 +#include <QDebug>
-+#include <QMessageBox>
++#include <QDir>
++#include <QSettings>
 +
 +#include <cerrno>
 +#include <cstring>
 +
-+#include <fcntl.h>
-+#include <kvm.h>
-+#include <machine/reg.h>
-+#include <paths.h>
-+#include <signal.h>
-+#include <sys/mman.h>
-+#include <sys/param.h>
++#include <cpuid.h>
 +#include <sys/ptrace.h>
-+#include <sys/sysctl.h>
-+#include <sys/user.h>
++#include <sys/mman.h>
 +#include <sys/wait.h>
 +#include <unistd.h>
 +
-+namespace DebuggerCore {
++namespace DebuggerCorePlugin {
 +
 +namespace {
 +
-+void SET_OK(bool &ok, long value) {
-+	ok = (value != -1) || (errno == 0);
-+}
++const edb::address_t PageSize = getpagesize();
++
++//------------------------------------------------------------------------------
++// Name: is_numeric
++// Desc: returns true if the string only contains decimal digits
++//------------------------------------------------------------------------------
++bool is_numeric(const QString &s) {
++	for(QChar ch: s) {
++		if(!ch.isDigit()) {
++			return false;
++		}
++	}
 +
-+int resume_code(int status) {
-+	if(WIFSIGNALED(status)) {
-+		return WTERMSIG(status);
-+	} else if(WIFSTOPPED(status)) {
-+		return WSTOPSIG(status);
++	return true;
++}
++
++bool in64BitSegment() {
++	bool edbIsIn64BitSegment;
++	// Check that we're running in 64 bit segment: this can be in cases
++	// of LP64 and ILP32 programming models, so we can't rely on sizeof(void*)
++	asm(R"(
++		   .byte 0x33,0xc0 # XOR EAX,EAX
++		   .byte 0x48      # DEC EAX for 32 bit, REX prefix for 64 bit
++		   .byte 0xff,0xc0 # INC EAX for 32 bit, INC RAX due to REX.W in 64 bit
++		 )":"=a"(edbIsIn64BitSegment));
++	return edbIsIn64BitSegment;
++}
++
++bool os64Bit(bool edbIsIn64BitSegment) {
++	bool osIs64Bit;
++	if(edbIsIn64BitSegment)
++		osIs64Bit=true;
++	else {
++		// We want to be really sure the OS is 32 bit, so we can't rely on such easy
++		// to (even unintentionally) fake mechanisms as uname(2) (e.g. see setarch(8))
++		asm(R"(.intel_syntax noprefix
++			   mov eax,cs
++			   cmp ax,0x23 # this value is set for 32-bit processes on 64-bit kernel
++			   mov ah,0    # not sure this is really needed: usually the compiler will do
++						   # MOVZX EAX,AL, but we have to be certain the result is correct
++			   sete al
++			   .att_syntax # restore default syntax
++			   )":"=a"(osIs64Bit));
 +	}
-+	return 0;
++	return osIs64Bit;
 +}
++
++
++
++
 +}
 +
 +//------------------------------------------------------------------------------
 +// Name: DebuggerCore
 +// Desc: constructor
 +//------------------------------------------------------------------------------
-+DebuggerCore::DebuggerCore() {
-+#if defined(_SC_PAGESIZE)
-+	page_size_ = sysconf(_SC_PAGESIZE);
-+#elif defined(_SC_PAGE_SIZE)
-+	page_size_ = sysconf(_SC_PAGE_SIZE);
-+#else
-+	page_size_ = PAGE_SIZE;
-+#endif
++DebuggerCore::DebuggerCore() :
++	binary_info_(nullptr),
++	process_(0),
++	pointer_size_(sizeof(void*)),
++	edbIsIn64BitSegment(in64BitSegment()),
++	osIs64Bit(os64Bit(edbIsIn64BitSegment)),
++	USER_CS_32(osIs64Bit?0x23:0x73),
++	USER_CS_64(osIs64Bit?0x33:0xfff8), // RPL 0 can't appear in user segment registers, so 0xfff8 is safe
++	USER_SS(osIs64Bit?0x2b:0x7b)
++{
++	qDebug() << "EDB is in" << (edbIsIn64BitSegment?"64":"32") << "bit segment";
++	qDebug() << "OS is" << (osIs64Bit?"64":"32") << "bit";
 +}
 +
 +//------------------------------------------------------------------------------
-+// Name:
++// Name: has_extension
 +// Desc:
 +//------------------------------------------------------------------------------
 +bool DebuggerCore::has_extension(quint64 ext) const {
++
++	const auto mmxHash=edb::string_hash("MMX");
++	const auto xmmHash=edb::string_hash("XMM");
++	const auto ymmHash=edb::string_hash("YMM");
++	if(EDB_IS_64_BIT && (ext==xmmHash || ext==mmxHash))
++		return true;
++
++	quint32 eax;
++	quint32 ebx;
++	quint32 ecx;
++	quint32 edx;
++	__cpuid(1, eax, ebx, ecx, edx);
++
++	switch(ext) {
++	case mmxHash:
++		return (edx & bit_MMX);
++	case xmmHash:
++		return (edx & bit_SSE);
++	case ymmHash:
++	{
++		// Check OSXSAVE and AVX feature flags
++		if((ecx&0x18000000)!=0x18000000)
++			return false;
++		// Get XCR0, must be exactly after OSXSAVE feature check, otherwise #UD
++		asm volatile("xgetbv" : "=a"(eax),"=d"(edx) : "c"(0));
++		// Check that the OS has enabled XMM and YMM state support
++		if((eax&0x6)!=0x6)
++			return false;
++		return true;
++	}
++	default:
++		return false;
++	}
++
 +	return false;
 +}
 +
@@ -92,184 +172,283 @@ $NetBSD$
 +// Desc: returns the size of a page on this system
 +//------------------------------------------------------------------------------
 +edb::address_t DebuggerCore::page_size() const {
-+	return page_size_;
++	return PageSize;
++}
++
++std::size_t DebuggerCore::pointer_size() const {
++	return pointer_size_;
 +}
 +
 +//------------------------------------------------------------------------------
 +// Name: ~DebuggerCore
-+// Desc:
++// Desc: destructor
 +//------------------------------------------------------------------------------
 +DebuggerCore::~DebuggerCore() {
-+	detach();
++	end_debug_session();
 +}
 +
 +//------------------------------------------------------------------------------
-+// Name: wait_debug_event
-+// Desc: waits for a debug event, msecs is a timeout
-+//      it will return false if an error or timeout occurs
++// Name: ptrace_getsiginfo
++// Desc:
 +//------------------------------------------------------------------------------
-+IDebugEvent::const_pointer DebuggerCore::wait_debug_event(int msecs) {
-+	if(attached()) {
-+		int status;
-+		bool timeout;
-+
-+		const edb::tid_t tid = native::waitpid_timeout(pid(), &status, 0, msecs, &timeout);
-+		if(!timeout) {
-+			if(tid > 0) {
-+
-+				// normal event
-+				auto e = std::make_shared<PlatformEvent>();
-+				e->pid    = pid();
-+				e->tid    = tid;
-+				e->status = status;
-+
-+				char errbuf[_POSIX2_LINE_MAX];
-+				if(kvm_t *const kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf)) {
-+					int rc;
-+					struct kinfo_proc *const proc = kvm_getprocs(kd, KERN_PROC_PID, pid(), &rc);
-+
-+					struct proc p;
-+					kvm_read(kd, (unsigned long)proc->ki_paddr, &p, sizeof(p));
-+
-+					struct ksiginfo siginfo;
-+					kvm_read(kd, (unsigned long)p.p_ksi, &siginfo, sizeof(siginfo));
-+
-+					// TODO: why doesn't this get the fault address correctly?
-+					// perhaps I need to target the tid instead?
-+					e->fault_code_    = siginfo.ksi_code;
-+					e->fault_address_ = siginfo.ksi_addr;
-+
-+					//printf("ps_sig   : %d\n", siginfo.ksi_signo);
-+					//printf("ps_type  : %d\n", p.p_stype);
-+					kvm_close(kd);
-+				} else {
-+					e->fault_code_    = 0;
-+					e->fault_address_ = 0;
-+				}
-+
-+				active_thread_       = tid;
-+				threads_[tid].status = status;
-+				return e;
-+			}
-+		}
-+	}
-+	return nullptr;
++long DebuggerCore::ptrace_getsiginfo(edb::pid_t pid, ptrace_siginfo_t *siginfo) {
++	Q_ASSERT(siginfo != 0);
++	return ptrace(PT_GET_SIGINFO, pid, siginfo, sizeof(struct ptrace_siginfo));
 +}
 +
 +//------------------------------------------------------------------------------
-+// Name: read_data
++// Name: ptrace_traceme
 +// Desc:
 +//------------------------------------------------------------------------------
-+long DebuggerCore::read_data(edb::address_t address, bool *ok) {
++long DebuggerCore::ptrace_traceme() {
++	return ptrace(PT_TRACE_ME, 0, NULL, 0);
++}
 +
-+	Q_ASSERT(ok);
-+	errno = 0;
-+	const long v = ptrace(PT_READ_D, pid(), reinterpret_cast<char*>(address), 0);
-+	SET_OK(*ok, v);
-+	return v;
++//------------------------------------------------------------------------------
++// Name: ptrace_continue
++// Desc:
++//------------------------------------------------------------------------------
++long DebuggerCore::ptrace_continue(edb::pid_t pid, long status) {
++	Q_ASSERT(pid != 0);
++	return ptrace(PT_CONTINUE, pid, (void *)1, status);
 +}
 +
 +//------------------------------------------------------------------------------
-+// Name: write_data
++// Name: ptrace_step
 +// Desc:
 +//------------------------------------------------------------------------------
-+bool DebuggerCore::write_data(edb::address_t address, long value) {
-+	return ptrace(PT_WRITE_D, pid(), reinterpret_cast<char*>(address), value) != -1;
++long DebuggerCore::ptrace_step(edb::pid_t pid, long status) {
++	Q_ASSERT(pid != 0);
++	return ptrace(PT_STEP, pid, (void *)1, status);
 +}
 +
 +//------------------------------------------------------------------------------
-+// Name: attach
++// Name: handle_event
 +// Desc:
 +//------------------------------------------------------------------------------
-+bool DebuggerCore::attach(edb::pid_t pid) {
-+	detach();
++IDebugEvent::const_pointer DebuggerCore::handle_event(edb::pid_t pid, int status) {
 +
-+	const long ret = ptrace(PT_ATTACH, pid, 0, 0);
-+	if(ret == 0) {
-+		pid_           = pid;
-+		active_thread_ = pid;
++	// was it a thread exit event?
++	if(WIFEXITED(status)) {
 +		threads_.clear();
-+		threads_.insert(pid, thread_info());
-+
-+		// TODO: attach to all of the threads
++		return nullptr;
 +	}
 +
-+	return ret == 0;
++	auto e = std::make_shared<PlatformEvent>();
++
++	e->pid_    = pid();
++	e->tid_    = tid;
++	e->status_ = status;
++	ptrace_getsiginfo(tid, &e->siginfo_);
++
++	return e;
 +}
 +
 +//------------------------------------------------------------------------------
-+// Name: detach
++// Name: stop_threads
 +// Desc:
 +//------------------------------------------------------------------------------
-+void DebuggerCore::detach() {
-+	if(attached()) {
++void DebuggerCore::stop_threads() {
++	if(process_) {
++		for(auto &thread: process_->threads()) {
++			const edb::tid_t tid = thread->tid();
 +
-+		// TODO: do i need to stop each thread first, and wait for them?
++			if(!waited_threads_.contains(tid)) {
 +
-+		clear_breakpoints();
-+		for(auto it = threads_.begin(); it != threads_.end(); ++it) {
-+			ptrace(PT_DETACH, it.key(), 0, 0);
++				if(auto thread_ptr = std::static_pointer_cast<PlatformThread>(thread)) {
++
++					thread->stop();
++
++					int thread_status;
++					if(native::waitpid(tid, &thread_status, __WALL) > 0) {
++						waited_threads_.insert(tid);
++						thread_ptr->status_ = thread_status;
++
++						if(!WIFSTOPPED(thread_status) || WSTOPSIG(thread_status) != SIGSTOP) {
++							qDebug("stop_threads(): [warning] paused thread [%d] received an event besides SIGSTOP: status=0x%x", tid,thread_status);
++						}
++					}
++				}
++			}
 +		}
++	}
++}
 +
-+		pid_ = 0;
-+		threads_.clear();
++//------------------------------------------------------------------------------
++// Name: wait_debug_event
++// Desc: waits for a debug event, msecs is a timeout
++//      it will return false if an error or timeout occurs
++//------------------------------------------------------------------------------
++IDebugEvent::const_pointer DebuggerCore::wait_debug_event(int msecs) {
++
++	if(process_) {
++		if(!native::wait_for_sigchld(msecs)) {
++			int status;
++			const edb::pid_t pid = native::waitpid(thread->tid(), &status, __WALL | WNOHANG);
++			if(pid > 0) {
++				return handle_event(tid, status);
++			}
++		}
 +	}
++	return nullptr;
 +}
 +
 +//------------------------------------------------------------------------------
-+// Name: kill
-+// Desc:
++// Name: attach_thread
++// Desc: returns 0 if successful, errno if failed
 +//------------------------------------------------------------------------------
-+void DebuggerCore::kill() {
-+	if(attached()) {
-+		clear_breakpoints();
-+		ptrace(PT_KILL, pid(), 0, 0);
-+		native::waitpid(pid(), 0, WAIT_ANY);
-+		pid_ = 0;
-+		threads_.clear();
++int DebuggerCore::attach_thread(edb::tid_t tid) {
++	if(ptrace(PTRACE_ATTACH, tid, 0, 0) == 0) {
++		// I *think* that the PTRACE_O_TRACECLONE is only valid on
++		// stopped threads
++		int status;
++		const auto ret=native::waitpid(tid, &status, __WALL);
++		if(ret > 0) {
++
++			auto newThread            = std::make_shared<PlatformThread>(this, process_, tid);
++			newThread->status_        = status;
++			newThread->signal_status_ = PlatformThread::Stopped;
++
++			threads_[tid] = newThread;
++
++			waited_threads_.insert(tid);
++			if(ptrace_set_options(tid, PTRACE_O_TRACECLONE) == -1) {
++				qDebug("[DebuggerCore] failed to set PTRACE_O_TRACECLONE: [%d] %s", tid, strerror(errno));
++			}
++
++			if(edb::v1::config().close_behavior==Configuration::Kill ||
++			   (edb::v1::config().close_behavior==Configuration::KillIfLaunchedDetachIfAttached &&
++				  last_means_of_capture()==MeansOfCapture::Launch)) {
++				if(ptrace_set_options(tid, PTRACE_O_EXITKILL) == -1) {
++					qDebug("[DebuggerCore] failed to set PTRACE_O_EXITKILL: [%d] %s", tid, strerror(errno));
++				}
++			}
++			return 0;
++		}
++		else if(ret==-1) {
++			return errno;
++		}
++		else return -1; // unknown error
 +	}
++	else return errno;
 +}
 +
 +//------------------------------------------------------------------------------
-+// Name: pause
-+// Desc: stops *all* threads of a process
++// Name: attach
++// Desc:
 +//------------------------------------------------------------------------------
-+void DebuggerCore::pause() {
-+	if(attached()) {
-+		for(auto it = threads_.begin(); it != threads_.end(); ++it) {
-+			::kill(it.key(), SIGSTOP);
++QString DebuggerCore::attach(edb::pid_t pid) {
++
++	static const QString statusOK{};
++
++	end_debug_session();
++
++	lastMeansOfCapture=MeansOfCapture::Attach;
++
++	// create this, so the threads created can refer to it
++	process_ = new PlatformProcess(this, pid);
++
++	int lastErr=attach_thread(pid); // Fail early if we are going to
++	if(lastErr) return std::strerror(lastErr);
++	lastErr=-2;
++	bool attached;
++	do {
++		attached = false;
++		QDir proc_directory(QString("/proc/%1/task/").arg(pid));
++		for(const QString &s: proc_directory.entryList(QDir::NoDotAndDotDot | QDir::Dirs)) {
++			// this can get tricky if the threads decide to spawn new threads
++			// when we are attaching. I wish that linux had an atomic way to do this
++			// all in one shot
++			const edb::tid_t tid = s.toUInt();
++			if(!threads_.contains(tid)) {
++				const auto errnum=attach_thread(tid);
++				if(errnum==0)
++					attached = true;
++				else
++					lastErr=errnum;
++			}
 +		}
++	} while(attached);
++
++
++	if(!threads_.empty()) {
++		pid_            = pid;
++		active_thread_  = pid;
++		binary_info_    = edb::v1::get_binary_info(edb::v1::primary_code_region());
++		detectDebuggeeBitness();
++		return statusOK;
++	} else {
++		delete process_;
++		process_ = nullptr;
 +	}
++
++	return std::strerror(lastErr);
 +}
 +
 +//------------------------------------------------------------------------------
-+// Name: resume
++// Name: detach
 +// Desc:
 +//------------------------------------------------------------------------------
-+void DebuggerCore::resume(edb::EVENT_STATUS status) {
-+	// TODO: assert that we are paused
++void DebuggerCore::detach() {
++	if(process_) {
 +
-+	if(attached()) {
-+		if(status != edb::DEBUG_STOP) {
-+			const edb::tid_t tid = active_thread();
-+			const int code = (status == edb::DEBUG_EXCEPTION_NOT_HANDLED) ? resume_code(threads_[tid].status) : 0;
-+			ptrace(PT_CONTINUE, tid, reinterpret_cast<caddr_t>(1), code);
++		stop_threads();
++
++		clear_breakpoints();
++
++		for(auto thread: process_->threads()) {
++			ptrace(PTRACE_DETACH, thread->tid(), 0, 0);
 +		}
++
++		delete process_;
++		process_ = nullptr;
++
++		reset();
 +	}
 +}
 +
 +//------------------------------------------------------------------------------
-+// Name: step
++// Name: kill
 +// Desc:
 +//------------------------------------------------------------------------------
-+void DebuggerCore::step(edb::EVENT_STATUS status) {
-+	// TODO: assert that we are paused
-+
++void DebuggerCore::kill() {
 +	if(attached()) {
-+		if(status != edb::DEBUG_STOP) {
-+			const edb::tid_t tid = active_thread();
-+			const int code = (status == edb::DEBUG_EXCEPTION_NOT_HANDLED) ? resume_code(threads_[tid].status) : 0;
-+			ptrace(PT_STEP, tid, reinterpret_cast<caddr_t>(1), code);
++		clear_breakpoints();
++
++		::kill(pid(), SIGKILL);
++
++		// TODO: do i need to actually do this wait?
++		native::waitpid(pid(), 0, __WALL);
++
++		delete process_;
++		process_ = 0;
++
++		reset();
++	}
++}
++
++void DebuggerCore::detectDebuggeeBitness() {
++
++	const size_t offset=EDB_IS_64_BIT ?
++						offsetof(UserRegsStructX86_64, cs) :
++						offsetof(UserRegsStructX86,   xcs);
++	errno=0;
++	const edb::seg_reg_t cs=ptrace(PTRACE_PEEKUSER, active_thread_, offset, 0);
++	if(!errno) {
++		if(cs==USER_CS_32) {
++			if(pointer_size_==sizeof(quint64)) {
++				qDebug() << "Debuggee is now 32 bit";
++				CapstoneEDB::init(CapstoneEDB::Architecture::ARCH_X86);
++			}
++			pointer_size_=sizeof(quint32);
++			return;
++		} else if(cs==USER_CS_64) {
++			if(pointer_size_==sizeof(quint32)) {
++				qDebug() << "Debuggee is now 64 bit";
++				CapstoneEDB::init(CapstoneEDB::Architecture::ARCH_AMD64);
++			}
++			pointer_size_=sizeof(quint64);
++			return;
 +		}
 +	}
 +}
@@ -279,23 +458,11 @@ $NetBSD$
 +// Desc:
 +//------------------------------------------------------------------------------
 +void DebuggerCore::get_state(State *state) {
-+
-+	Q_ASSERT(state);
-+
 +	// TODO: assert that we are paused
-+
-+	auto state_impl = static_cast<PlatformState *>(state->impl_);
-+
-+	if(attached()) {
-+	#if defined(EDB_X86)
-+		if(ptrace(PT_GETREGS, active_thread(), reinterpret_cast<char*>(&state_impl->regs_), 0) != -1) {
-+			state_impl->gs_base = 0;
-+			state_impl->fs_base = 0;
++	if(process_) {
++		if(IThread::pointer thread = process_->current_thread()) {
++			thread->get_state(state);
 +		}
-+	#endif
-+		// TODO implement this
-+	} else {
-+		state->clear();
 +	}
 +}
 +
@@ -306,13 +473,10 @@ $NetBSD$
 +void DebuggerCore::set_state(const State &state) {
 +
 +	// TODO: assert that we are paused
-+
-+	auto state_impl = static_cast<PlatformState *>(state.impl_);
-+
-+	if(attached()) {
-+		ptrace(PT_SETREGS, active_thread(), reinterpret_cast<char*>(&state_impl->regs_), 0);
-+		// TODO: FPU
-+		// TODO: Debug Registers
++	if(process_) {
++		if(IThread::pointer thread = process_->current_thread()) {
++			thread->set_state(state);
++		}
 +	}
 +}
 +
@@ -320,16 +484,25 @@ $NetBSD$
 +// Name: open
 +// Desc:
 +//------------------------------------------------------------------------------
-+bool DebuggerCore::open(const QString &path, const QString &cwd, const QList<QByteArray> &args, const QString &tty) {
-+	detach();
-+	pid_t pid;
++QString DebuggerCore::open(const QString &path, const QString &cwd, const QList<QByteArray> &args, const QString &tty) {
++
++	static const QString statusOK{};
++
++	end_debug_session();
 +
-+	switch(pid = fork()) {
++	lastMeansOfCapture=MeansOfCapture::Launch;
++
++	static constexpr std::size_t sharedMemSize=4096;
++	const auto sharedMem=static_cast<QChar*>(::mmap(nullptr,sharedMemSize,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0));
++	std::memset(sharedMem,0,sharedMemSize);
++
++	switch(pid_t pid = fork()) {
 +	case 0:
++	{
 +		// we are in the child now...
 +
 +		// set ourselves (the child proc) up to be traced
-+		ptrace(PT_TRACE_ME, 0, 0, 0);
++		ptrace_traceme();
 +
 +		// redirect it's I/O
 +		if(!tty.isEmpty()) {
@@ -342,256 +515,247 @@ $NetBSD$
 +			Q_UNUSED(std_err);
 +		}
 +
++		if(edb::v1::config().disableASLR) {
++			const auto curPers=::personality(UINT32_MAX);
++			// This shouldn't fail, but let's at least perror if it does anyway
++			if(curPers==-1)
++				perror("Failed to get current personality");
++			else if(::personality(curPers|ADDR_NO_RANDOMIZE)==-1)
++				perror("Failed to disable ASLR");
++		}
++
++		if(edb::v1::config().disableLazyBinding && setenv("LD_BIND_NOW","1",true)==-1)
++			perror("Failed to disable lazy binding");
++
 +		// do the actual exec
-+		execute_process(path, cwd, args);
++		const QString error=execute_process(path, cwd, args);
++#if defined __GNUG__ && __GNUC__ >= 5 || !defined __GNUG__ || \
++		defined __clang__ && __clang_major__*100+__clang_minor__>=306
++		static_assert(std::is_trivially_copyable<QChar>::value,"Can't copy string of QChar to shared memory");
++#endif
++		std::memcpy(sharedMem,error.constData(),std::min(sizeof(QChar)*error.size(),sharedMemSize-sizeof(QChar)/*prevent overwriting of last null*/));
 +
 +		// we should never get here!
 +		abort();
 +		break;
++	}
 +	case -1:
-+		// error!
-+		pid_ = 0;
-+		return false;
++		// error! for some reason we couldn't fork
++		reset();
++		return QObject::tr("Failed to fork");
 +	default:
 +		// parent
 +		do {
-+			threads_.clear();
++			reset();
 +
 +			int status;
-+			if(native::waitpid(pid, &status, 0) == -1) {
-+				return false;
-+			}
++			const auto wpidRet=native::waitpid(pid, &status, __WALL);
++			const QString childError(sharedMem);
++			::munmap(sharedMem,sharedMemSize);
++
++			if(wpidRet == -1)
++				return QObject::tr("waitpid() failed: %1").arg(std::strerror(errno))+(childError.isEmpty()?"":QObject::tr(".\nError returned by child:\n%1.").arg(childError));
++
++			if(WIFEXITED(status))
++				return QObject::tr("The child unexpectedly exited with code %1. Error returned by child:\n%2").arg(WEXITSTATUS(status)).arg(childError);
++			if(WIFSIGNALED(status))
++				return QObject::tr("The child was unexpectedly killed by signal %1. Error returned by child:\n%2").arg(WTERMSIG(status)).arg(childError);
++
++			// This happens when exec failed, but just in case it's something another return some description.
++			if(WIFSTOPPED(status) && WSTOPSIG(status) == SIGABRT)
++				return childError.isEmpty() ? QObject::tr("The child unexpectedly aborted") : childError;
 +
 +			// the very first event should be a STOP of type SIGTRAP
 +			if(!WIFSTOPPED(status) || WSTOPSIG(status) != SIGTRAP) {
-+				detach();
-+				return false;
++				end_debug_session();
++				return QObject::tr("First event after waitpid() should be a STOP of type SIGTRAP, but wasn't, instead status=0x%1")
++											.arg(status,0,16)+(childError.isEmpty()?"":QObject::tr(".\nError returned by child:\n%1.").arg(childError));
++			}
++
++			waited_threads_.insert(pid);
++
++			// enable following clones (threads)
++			if(ptrace_set_options(pid, PTRACE_O_TRACECLONE) == -1) {
++				const auto strerr=strerror(errno); // NOTE: must be called before end_debug_session, otherwise errno can change
++				end_debug_session();
++				return QObject::tr("[DebuggerCore] failed to set PTRACE_O_TRACECLONE: %1").arg(strerr);
++			}
++
++#ifdef PTRACE_O_EXITKILL
++			if(ptrace_set_options(pid, PTRACE_O_EXITKILL) == -1) {
++				const auto strerr=strerror(errno); // NOTE: must be called before any other syscall, otherwise errno can change
++				// Don't consider the error fatal: the option is only supported since Linux 3.8
++				qDebug() << "[DebuggerCore] failed to set PTRACE_O_EXITKILL:" << strerr;
 +			}
++#endif
 +
 +			// setup the first event data for the primary thread
-+			threads_.insert(pid, thread_info());
-+			pid_                 = pid;
-+			active_thread_       = pid;
-+			threads_[pid].status = status;
-+			return true;
-+		} while(0);
-+		break;
-+	}
-+}
++			waited_threads_.insert(pid);
 +
-+//------------------------------------------------------------------------------
-+// Name: set_active_thread
-+// Desc:
-+//------------------------------------------------------------------------------
-+void DebuggerCore::set_active_thread(edb::tid_t tid) {
-+	Q_ASSERT(threads_.contains(tid));
-+	active_thread_ = tid;
-+}
++			// create the process
++			process_ = new PlatformProcess(this, pid);
 +
-+//------------------------------------------------------------------------------
-+// Name: create_state
-+// Desc:
-+//------------------------------------------------------------------------------
-+IState *DebuggerCore::create_state() const {
-+	return new PlatformState;
-+}
 +
-+//------------------------------------------------------------------------------
-+// Name: enumerate_processes
-+// Desc:
-+//------------------------------------------------------------------------------
-+QMap<edb::pid_t, ProcessInfo> DebuggerCore::enumerate_processes() const {
-+	QMap<edb::pid_t, ProcessInfo> ret;
++			// the PID == primary TID
++			auto newThread            = std::make_shared<PlatformThread>(this, process_, pid);
++			newThread->status_        = status;
++			newThread->signal_status_ = PlatformThread::Stopped;
 +
-+	char ebuffer[_POSIX2_LINE_MAX];
-+	int numprocs;
-+	if(kvm_t *const kaccess = kvm_openfiles(_PATH_DEVNULL, _PATH_DEVNULL, 0, O_RDONLY, ebuffer)) {
-+		if(struct kinfo_proc *const kprocaccess = kvm_getprocs(kaccess, KERN_PROC_ALL, 0, &numprocs)) {
-+			for(int i = 0; i < numprocs; ++i) {
-+				ProcessInfo procInfo;
++			threads_[pid]   = newThread;
 +
-+				procInfo.pid   = kprocaccess[i].ki_pid;
-+				procInfo.uid   = kprocaccess[i].ki_uid;
-+				procInfo.name  = kprocaccess[i].ki_comm;
-+				ret.insert(procInfo.pid, procInfo);
-+			}
-+		}
-+		kvm_close(kaccess);
-+	} else {
-+		QMessageBox::warning(0, "Error Listing Processes", ebuffer);
-+	}
++			pid_            = pid;
++			active_thread_   = pid;
++			binary_info_    = edb::v1::get_binary_info(edb::v1::primary_code_region());
 +
-+	return ret;
++			detectDebuggeeBitness();
++
++			return statusOK;
++		} while(0);
++		break;
++	}
 +}
 +
++
 +//------------------------------------------------------------------------------
-+// Name:
-+// Desc:
++// Name: last_means_of_capture
++// Desc: Returns how the last process was captured to debug
 +//------------------------------------------------------------------------------
-+QString DebuggerCore::process_exe(edb::pid_t pid) const {
-+	// TODO: implement this
-+	return QString();
++DebuggerCore::MeansOfCapture DebuggerCore::last_means_of_capture() {
++	return lastMeansOfCapture;
 +}
 +
 +//------------------------------------------------------------------------------
-+// Name:
++// Name: reset
 +// Desc:
 +//------------------------------------------------------------------------------
-+QString DebuggerCore::process_cwd(edb::pid_t pid) const {
-+	// TODO: implement this
-+	return QString();
++void DebuggerCore::reset() {
++	threads_.clear();
++	waited_threads_.clear();
++	pid_           = 0;
++	active_thread_ = 0;
++	binary_info_   = nullptr;
 +}
 +
 +//------------------------------------------------------------------------------
-+// Name:
++// Name: create_state
 +// Desc:
 +//------------------------------------------------------------------------------
-+edb::pid_t DebuggerCore::parent_pid(edb::pid_t pid) const {
-+	// TODO: implement this
-+	return -1;
++IState *DebuggerCore::create_state() const {
++	return new PlatformState;
 +}
 +
 +//------------------------------------------------------------------------------
-+// Name:
++// Name: enumerate_processes
 +// Desc:
 +//------------------------------------------------------------------------------
-+QList<IRegion::pointer> DebuggerCore::memory_regions() const {
-+	QList<IRegion::pointer> regions;
-+
-+	if(pid_ != 0) {
-+		char buffer[PATH_MAX] = {};
-+		struct ptrace_vm_entry vm_entry;
-+		memset(&vm_entry, 0, sizeof(vm_entry));
-+		vm_entry.pve_entry = 0;
++QMap<edb::pid_t, IProcess::pointer> DebuggerCore::enumerate_processes() const {
++	QMap<edb::pid_t, IProcess::pointer> ret;
 +
-+		while(ptrace(PT_VM_ENTRY, pid_, reinterpret_cast<char*>(&vm_entry), NULL) == 0) {
-+			vm_entry.pve_path    = buffer;
-+			vm_entry.pve_pathlen = sizeof(buffer);
++	QDir proc_directory("/proc/");
++	QFileInfoList entries = proc_directory.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
 +
-+			const edb::address_t start               = vm_entry.pve_start;
-+			const edb::address_t end                 = vm_entry.pve_end;
-+			const edb::address_t base                = vm_entry.pve_start - vm_entry.pve_offset;
-+			const QString name                       = vm_entry.pve_path;
-+			const IRegion::permissions_t permissions = vm_entry.pve_prot;
++	for(const QFileInfo &info: entries) {
++		const QString filename = info.fileName();
++		if(is_numeric(filename)) {
++			const edb::pid_t pid = filename.toULong();
 +
-+			regions.push_back(std::make_shared<PlatformRegion>(start, end, base, name, permissions));
-+			memset(buffer, 0, sizeof(buffer));
++			// NOTE(eteran): the const_cast is reasonable here.
++			// While we don't want THIS function to mutate the DebuggerCore object
++			// we do want the associated PlatformProcess to be able to trigger
++			// non-const operations in the future, at least hypothetically.
++			ret.insert(pid, std::make_shared<PlatformProcess>(const_cast<DebuggerCore*>(this), pid));
 +		}
 +	}
 +
-+	return regions;
++	return ret;
 +}
 +
++
 +//------------------------------------------------------------------------------
 +// Name:
 +// Desc:
 +//------------------------------------------------------------------------------
-+QList<QByteArray> DebuggerCore::process_args(edb::pid_t pid) const {
-+	QList<QByteArray> ret;
-+	if(pid != 0) {
-+		// TODO: assert attached!
-+	}
-+	return ret;
++edb::pid_t DebuggerCore::parent_pid(edb::pid_t pid) const {
 +
-+}
++	struct user_stat user_stat;
++	int n = get_user_stat(pid, &user_stat);
++	if(n >= 4) {
++		return user_stat.ppid;
++	}
 +
-+//------------------------------------------------------------------------------
-+// Name:
-+// Desc:
-+//------------------------------------------------------------------------------
-+edb::address_t DebuggerCore::process_code_address() const {
-+	qDebug() << "TODO: implement DebuggerCore::process_code_address";
 +	return 0;
 +}
 +
 +//------------------------------------------------------------------------------
 +// Name:
-+// Desc:
++// Desc: Returns EDB's native CPU type
 +//------------------------------------------------------------------------------
-+edb::address_t DebuggerCore::process_data_address() const {
-+	qDebug() << "TODO: implement DebuggerCore::process_data_address";
-+	return 0;
++quint64 DebuggerCore::cpu_type() const {
++	if(EDB_IS_32_BIT)
++		return edb::string_hash("x86");
++	else
++		return edb::string_hash("x86-64");
 +}
 +
-+//------------------------------------------------------------------------------
-+// Name:
-+// Desc:
-+//------------------------------------------------------------------------------
-+QList<Module> DebuggerCore::loaded_modules() const {
-+    QList<Module> modules;
-+	qDebug() << "TODO: implement DebuggerCore::loaded_modules";
-+    return modules;
-+}
 +
 +//------------------------------------------------------------------------------
 +// Name:
 +// Desc:
 +//------------------------------------------------------------------------------
-+QDateTime DebuggerCore::process_start(edb::pid_t pid) const {
-+	qDebug() << "TODO: implement DebuggerCore::process_start";
-+	return QDateTime();
++QString DebuggerCore::format_pointer(edb::address_t address) const {
++	return address.toPointerString();
 +}
 +
 +//------------------------------------------------------------------------------
 +// Name:
 +// Desc:
 +//------------------------------------------------------------------------------
-+quint64 DebuggerCore::cpu_type() const {
-+#ifdef EDB_X86
-+	return edb::string_hash<'x', '8', '6'>::value;
-+#elif defined(EDB_X86_64)
-+	return edb::string_hash<'x', '8', '6', '-', '6', '4'>::value;
-+#endif
++QString DebuggerCore::stack_pointer() const {
++	if(edb::v1::debuggeeIs32Bit())
++		return "esp";
++	else
++		return "rsp";
 +}
 +
 +//------------------------------------------------------------------------------
 +// Name:
 +// Desc:
 +//------------------------------------------------------------------------------
-+QString DebuggerCore::format_pointer(edb::address_t address) const {
-+	char buf[32];
-+#ifdef EDB_X86
-+	qsnprintf(buf, sizeof(buf), "%08x", address);
-+#elif defined(EDB_X86_64)
-+	qsnprintf(buf, sizeof(buf), "%016llx", address);
-+#endif
-+	return buf;
++QString DebuggerCore::frame_pointer() const {
++	if(edb::v1::debuggeeIs32Bit())
++		return "ebp";
++	else
++		return "rbp";
 +}
 +
 +//------------------------------------------------------------------------------
 +// Name:
 +// Desc:
 +//------------------------------------------------------------------------------
-+QString DebuggerCore::stack_pointer() const {
-+#ifdef EDB_X86
-+	return "esp";
-+#elif defined(EDB_X86_64)
-+	return "rsp";
-+#endif
++QString DebuggerCore::instruction_pointer() const {
++	if(edb::v1::debuggeeIs32Bit())
++		return "eip";
++	else
++		return "rip";
 +}
 +
 +//------------------------------------------------------------------------------
-+// Name:
-+// Desc:
++// Name: flag_register
++// Desc: Returns the name of the flag register as a QString.
 +//------------------------------------------------------------------------------
-+QString DebuggerCore::frame_pointer() const {
-+#ifdef EDB_X86
-+	return "ebp";
-+#elif defined(EDB_X86_64)
-+	return "rbp";
-+#endif
++QString DebuggerCore::flag_register() const {
++	if(edb::v1::debuggeeIs32Bit())
++		return "eflags";
++	else
++		return "rflags";
 +}
 +
 +//------------------------------------------------------------------------------
-+// Name:
++// Name: process
 +// Desc:
 +//------------------------------------------------------------------------------
-+QString DebuggerCore::instruction_pointer() const {
-+#ifdef EDB_X86
-+	return "eip";
-+#elif defined(EDB_X86_64)
-+	return "rip";
-+#endif
++IProcess *DebuggerCore::process() const {
++	return process_;
 +}
 +
 +#if QT_VERSION < 0x050000
diff --git a/edb-debugger-git/patches/patch-plugins_DebuggerCore_unix_netbsd_DebuggerCore.h b/edb-debugger-git/patches/patch-plugins_DebuggerCore_unix_netbsd_DebuggerCore.h
index 4c84f87662..eefd58e805 100644
--- a/edb-debugger-git/patches/patch-plugins_DebuggerCore_unix_netbsd_DebuggerCore.h
+++ b/edb-debugger-git/patches/patch-plugins_DebuggerCore_unix_netbsd_DebuggerCore.h
@@ -2,7 +2,7 @@ $NetBSD$
 
 --- plugins/DebuggerCore/unix/netbsd/DebuggerCore.h.orig	2017-02-19 00:51:04.563698490 +0000
 +++ plugins/DebuggerCore/unix/netbsd/DebuggerCore.h
-@@ -0,0 +1,110 @@
+@@ -0,0 +1,119 @@
 +/*
 +Copyright (C) 2006 - 2015 Evan Teran
 +                          evan.teran%gmail.com@localhost
@@ -25,89 +25,98 @@ $NetBSD$
 +#define DEBUGGERCORE_20090529_H_
 +
 +#include "DebuggerCoreUNIX.h"
++#include "PlatformState.h"
++#include "PlatformThread.h"
 +#include <QHash>
++#include <QSet>
++#include <csignal>
++#include <sys/syscall.h>   /* For SYS_xxx definitions */
++#include <unistd.h>
++#include <sys/ptrace.h>
 +
-+namespace DebuggerCore {
++class IBinary;
++
++namespace DebuggerCorePlugin {
 +
 +class DebuggerCore : public DebuggerCoreUNIX {
 +	Q_OBJECT
++#if QT_VERSION >= 0x050000
++	Q_PLUGIN_METADATA(IID "edb.IDebugger/1.0")
++#endif
 +	Q_INTERFACES(IDebugger)
 +	Q_CLASSINFO("author", "Evan Teran")
 +	Q_CLASSINFO("url", "http://www.codef00.com";)
++	friend class PlatformProcess;
++	friend class PlatformThread;
 +
 +public:
 +	DebuggerCore();
-+	virtual ~DebuggerCore();
++	virtual ~DebuggerCore() override;
 +
 +public:
-+	virtual edb::address_t page_size() const;
-+	virtual bool has_extension(quint64 ext) const;
-+	virtual IDebugEvent::const_pointer wait_debug_event(int msecs);
-+	virtual bool attach(edb::pid_t pid);
-+	virtual void detach();
-+	virtual void kill();
-+	virtual void pause();
-+	virtual void resume(edb::EVENT_STATUS status);
-+	virtual void step(edb::EVENT_STATUS status);
-+	virtual void get_state(State *state);
-+	virtual void set_state(const State &state);
-+	virtual bool open(const QString &path, const QString &cwd, const QList<QByteArray> &args, const QString &tty);
++	virtual std::size_t pointer_size() const override;
++	virtual edb::address_t page_size() const override;
++	virtual bool has_extension(quint64 ext) const override;
++	virtual IDebugEvent::const_pointer wait_debug_event(int msecs) override;
++	virtual QString attach(edb::pid_t pid) override;
++	virtual void detach() override;
++	virtual void kill() override;
++	virtual void get_state(State *state) override;
++	virtual void set_state(const State &state) override;
++	virtual QString open(const QString &path, const QString &cwd, const QList<QByteArray> &args, const QString &tty) override;
++	virtual MeansOfCapture last_means_of_capture() override;
 +
 +public:
-+	// thread support stuff (optional)
-+	virtual QList<edb::tid_t> thread_ids() const { return threads_.keys(); }
-+	virtual edb::tid_t active_thread() const     { return active_thread_; }
-+	virtual void set_active_thread(edb::tid_t);
++	virtual edb::pid_t parent_pid(edb::pid_t pid) const override;
 +
 +public:
-+	virtual QList<IRegion::pointer> memory_regions() const;
-+	virtual edb::address_t process_code_address() const;
-+	virtual edb::address_t process_data_address() const;
++	virtual IState *create_state() const override;
 +
 +public:
-+	virtual IState *create_state() const;
++	virtual quint64 cpu_type() const override;
 +
-+public:
-+	// process properties
-+	virtual QList<QByteArray> process_args(edb::pid_t pid) const;
-+	virtual QString process_exe(edb::pid_t pid) const;
-+	virtual QString process_cwd(edb::pid_t pid) const;
-+	virtual edb::pid_t parent_pid(edb::pid_t pid) const;
-+	virtual QDateTime process_start(edb::pid_t pid) const;
-+	virtual quint64 cpu_type() const;
++private:
++	virtual QMap<edb::pid_t, IProcess::pointer> enumerate_processes() const override;
 +
 +public:
-+	virtual QMap<edb::pid_t, ProcessInfo> enumerate_processes() const;
-+	virtual QList<Module> loaded_modules() const;
++	virtual QString stack_pointer() const override;
++	virtual QString frame_pointer() const override;
++	virtual QString instruction_pointer() const override;
++	virtual QString flag_register() const override;
 +
 +public:
-+	virtual QString stack_pointer() const;
-+	virtual QString frame_pointer() const;
-+	virtual QString instruction_pointer() const;
++	virtual QString format_pointer(edb::address_t address) const override;
 +
 +public:
-+	virtual QString format_pointer(edb::address_t address) const;
++	virtual IProcess *process() const override;
 +
 +private:
-+	virtual long read_data(edb::address_t address, bool *ok);
-+	virtual bool write_data(edb::address_t address, long value);
++	long ptrace_getsiginfo(edb::pid_t tid, ptrace_siginfo_t *siginfo);
++	long ptrace_continue(edb::pid_t tid, long status);
++	long ptrace_step(edb::pid_t tid, long status);
++	long ptrace_traceme();
 +
 +private:
-+	struct thread_info {
-+	public:
-+		thread_info() : status(0) {
-+		}
++	void reset();
++	void stop_threads();
++	IDebugEvent::const_pointer handle_event(edb::tid_t tid, int status);
++	int attach_thread(edb::tid_t tid);
++	void detectDebuggeeBitness();
 +
-+		thread_info(int s) : status(s) {
-+		}
-+
-+		int status;
-+	};
-+
-+	typedef QHash<edb::tid_t, thread_info> threadmap_t;
++private:
++	typedef QHash<edb::tid_t, PlatformThread::pointer> threadmap_t;
 +
-+	edb::address_t page_size_;
-+	threadmap_t    threads_;
++private:
++	threadmap_t              threads_;
++	std::unique_ptr<IBinary> binary_info_;
++	IProcess                *process_;
++	std::size_t              pointer_size_;
++	const bool               edbIsIn64BitSegment;
++	const bool               osIs64Bit;
++	const edb::seg_reg_t     USER_CS_32;
++	const edb::seg_reg_t     USER_CS_64;
++	const edb::seg_reg_t     USER_SS;
++	MeansOfCapture	         lastMeansOfCapture = MeansOfCapture::NeverCaptured;
 +};
 +
 +}
diff --git a/edb-debugger-git/patches/patch-plugins_DebuggerCore_unix_netbsd_DialogMemoryAccess.ui b/edb-debugger-git/patches/patch-plugins_DebuggerCore_unix_netbsd_DialogMemoryAccess.ui
new file mode 100644
index 0000000000..987b9770e3
--- /dev/null
+++ b/edb-debugger-git/patches/patch-plugins_DebuggerCore_unix_netbsd_DialogMemoryAccess.ui
@@ -0,0 +1,95 @@
+$NetBSD$
+
+--- plugins/DebuggerCore/unix/netbsd/DialogMemoryAccess.ui.orig	2017-02-19 01:11:03.492521515 +0000
++++ plugins/DebuggerCore/unix/netbsd/DialogMemoryAccess.ui
+@@ -0,0 +1,90 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<ui version="4.0">
++ <class>DebuggerCorePlugin::DialogMemoryAccess</class>
++ <widget class="QDialog" name="DialogMemoryAccess">
++  <property name="geometry">
++   <rect>
++    <x>0</x>
++    <y>0</y>
++    <width>360</width>
++    <height>276</height>
++   </rect>
++  </property>
++  <property name="windowTitle">
++   <string>Memory Access Error</string>
++  </property>
++  <property name="modal">
++   <bool>true</bool>
++  </property>
++  <layout class="QVBoxLayout" name="verticalLayout">
++   <item>
++    <widget class="QLabel" name="label">
++     <property name="text">
++      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;EDB has detected that on this kernel, access to debugee memory &lt;br/&gt;does not work through &lt;span style=&quot; font-family:'Courier New,courier';&quot;&gt;/proc/&amp;lt;pid&amp;gt;/mem&lt;/span&gt;. &lt;/p&gt;&lt;p&gt;Possible causes include: &lt;/p&gt;&lt;ul style=&quot;margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;&quot;&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;EDB's feature detection has a bug&lt;/li&gt;&lt;/ul&gt;&lt;ul style=&quot;margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;&quot;&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;The kernel is older and restricts writes to &lt;span style=&quot; font-family:'Courier New,cour
ier';&quot;&gt;/proc/&amp;lt;pid&amp;gt;/mem&lt;/span&gt;&lt;/li&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;The kernel has &lt;span style=&quot; font-weight:600;&quot;&gt;grsecurity&lt;/span&gt; enabled&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;EDB has a fallback method of accessing debugee memory, &lt;br/&gt;but it may have a negative impact on performance. &lt;br/&gt;If you experience poor performance, please file a bug report at:&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://github.com/eteran/edb-debugger/issues&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#2980b9;&quot;&gt;http://github.com/eteran/edb-debugger/issues&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
++     </property>
++     <property name="textFormat">
++      <enum>Qt::RichText</enum>
++     </property>
++     <property name="openExternalLinks">
++      <bool>false</bool>
++     </property>
++    </widget>
++   </item>
++   <item>
++    <widget class="QCheckBox" name="checkNeverShowAgain">
++     <property name="text">
++      <string>Never show this message again</string>
++     </property>
++     <property name="checked">
++      <bool>true</bool>
++     </property>
++    </widget>
++   </item>
++   <item>
++    <widget class="QDialogButtonBox" name="buttonBox">
++     <property name="orientation">
++      <enum>Qt::Horizontal</enum>
++     </property>
++     <property name="standardButtons">
++      <set>QDialogButtonBox::Ok</set>
++     </property>
++    </widget>
++   </item>
++  </layout>
++ </widget>
++ <resources/>
++ <connections>
++  <connection>
++   <sender>buttonBox</sender>
++   <signal>accepted()</signal>
++   <receiver>DialogMemoryAccess</receiver>
++   <slot>accept()</slot>
++   <hints>
++    <hint type="sourcelabel">
++     <x>248</x>
++     <y>254</y>
++    </hint>
++    <hint type="destinationlabel">
++     <x>157</x>
++     <y>274</y>
++    </hint>
++   </hints>
++  </connection>
++  <connection>
++   <sender>buttonBox</sender>
++   <signal>rejected()</signal>
++   <receiver>DialogMemoryAccess</receiver>
++   <slot>reject()</slot>
++   <hints>
++    <hint type="sourcelabel">
++     <x>316</x>
++     <y>260</y>
++    </hint>
++    <hint type="destinationlabel">
++     <x>286</x>
++     <y>274</y>
++    </hint>
++   </hints>
++  </connection>
++ </connections>
++</ui>
diff --git a/edb-debugger-git/patches/patch-plugins_DebuggerCore_unix_netbsd_PlatformEvent.h b/edb-debugger-git/patches/patch-plugins_DebuggerCore_unix_netbsd_PlatformEvent.h
index d79c27f69d..33ce6485b9 100644
--- a/edb-debugger-git/patches/patch-plugins_DebuggerCore_unix_netbsd_PlatformEvent.h
+++ b/edb-debugger-git/patches/patch-plugins_DebuggerCore_unix_netbsd_PlatformEvent.h
@@ -2,7 +2,7 @@ $NetBSD$
 
 --- plugins/DebuggerCore/unix/netbsd/PlatformEvent.h.orig	2017-02-19 00:51:04.612693828 +0000
 +++ plugins/DebuggerCore/unix/netbsd/PlatformEvent.h
-@@ -0,0 +1,62 @@
+@@ -0,0 +1,61 @@
 +/*
 +Copyright (C) 2006 - 2015 Evan Teran
 +                          evan.teran%gmail.com@localhost
@@ -55,11 +55,10 @@ $NetBSD$
 +	virtual int code() const;
 +
 +private:
-+	int        status;
-+	edb::pid_t pid;
-+	edb::tid_t tid;
-+	void *     fault_address_;
-+	long       fault_code_;
++	ptrace_siginfo_t siginfo_;
++	edb::pid_t       pid_;
++	edb::tid_t       tid_;
++	int              status_;
 +};
 +
 +}


Home | Main Index | Thread Index | Old Index