//------------------------------------------------------------------------------ // Name: attach_thread // Desc: //------------------------------------------------------------------------------ bool 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 // on stopped threads int status; if(native::waitpid(tid, &status, __WALL) > 0) { auto newThread = std::make_shared<PlatformThread>(this, process_, tid); newThread->status_ = status; newThread->state_ = 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)); } #ifdef PTRACE_O_EXITKILL if(ptrace_set_options(tid, PTRACE_O_EXITKILL) == -1) { qDebug("[DebuggerCore] failed to set PTRACE_O_EXITKILL: [%d] %s", tid, strerror(errno)); } #endif } return true; } return false; }
//------------------------------------------------------------------------------ // Name: attach_thread // Desc: //------------------------------------------------------------------------------ bool 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 // on stopped threads int status; if(native::waitpid(tid, &status, __WALL) > 0) { const thread_info info = { status, thread_info::THREAD_STOPPED }; threads_[tid] = info; 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)); } } return true; } return false; }
//------------------------------------------------------------------------------ // Name: open // Desc: //------------------------------------------------------------------------------ bool DebuggerCore::open(const QString &path, const QString &cwd, const QList<QByteArray> &args, const QString &tty) { detach(); switch(pid_t pid = fork()) { case 0: // we are in the child now... // set ourselves (the child proc) up to be traced ptrace_traceme(); // redirect it's I/O if(!tty.isEmpty()) { FILE *const std_out = freopen(qPrintable(tty), "r+b", stdout); FILE *const std_in = freopen(qPrintable(tty), "r+b", stdin); FILE *const std_err = freopen(qPrintable(tty), "r+b", stderr); Q_UNUSED(std_out); Q_UNUSED(std_in); Q_UNUSED(std_err); } // do the actual exec execute_process(path, cwd, args); // we should never get here! abort(); break; case -1: // error! for some reason we couldn't fork reset(); return false; default: // parent do { reset(); int status; if(native::waitpid(pid, &status, __WALL) == -1) { return false; } // the very first event should be a STOP of type SIGTRAP if(!WIFSTOPPED(status) || WSTOPSIG(status) != SIGTRAP) { detach(); return false; } waited_threads_.insert(pid); // enable following clones (threads) if(ptrace_set_options(pid, PTRACE_O_TRACECLONE) == -1) { qDebug("[DebuggerCore] failed to set PTRACE_SETOPTIONS: %s", strerror(errno)); detach(); return false; } #ifdef PTRACE_O_EXITKILL if(ptrace_set_options(pid, PTRACE_O_EXITKILL) == -1) { qDebug("[DebuggerCore] failed to set PTRACE_SETOPTIONS: %s", strerror(errno)); detach(); return false; } #endif // setup the first event data for the primary thread waited_threads_.insert(pid); // create the process process_ = new PlatformProcess(this, pid); // the PID == primary TID auto newThread = std::make_shared<PlatformThread>(this, process_, pid); newThread->status_ = status; newThread->state_ = PlatformThread::Stopped; threads_[pid] = newThread; pid_ = pid; active_thread_ = pid; binary_info_ = edb::v1::get_binary_info(edb::v1::primary_code_region()); detectDebuggeeBitness(); return true; } while(0); break; } }