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><html><head/><body><p>EDB has detected that on this kernel, access to debugee memory <br/>does not work through <span style=" font-family:'Courier New,courier';">/proc/&lt;pid&gt;/mem</span>. </p><p>Possible causes include: </p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">EDB's feature detection has a bug</li></ul><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The kernel is older and restricts writes to <span style=" font-family:'Courier New,cour
ier';">/proc/&lt;pid&gt;/mem</span></li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The kernel has <span style=" font-weight:600;">grsecurity</span> enabled</li></ul><p>EDB has a fallback method of accessing debugee memory, <br/>but it may have a negative impact on performance. <br/>If you experience poor performance, please file a bug report at:</p><p><a href="http://github.com/eteran/edb-debugger/issues"><span style=" text-decoration: underline; color:#2980b9;">http://github.com/eteran/edb-debugger/issues</span></a>.</p></body></html></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