ErrorCode PTrace::readBytes(ProcessThreadId const &ptid, Address const &address, void *buffer, size_t length, size_t *count, bool nullTerm) { pid_t pid; CHK(ptidToPid(ptid, pid)); bool foundNull = false; size_t nread = 0; uintptr_t base = address; uintptr_t *words = (uintptr_t *)buffer; if (length == 0 || buffer == nullptr) { if (count != nullptr) { *count = 0; } return kSuccess; } while (length > 0) { union { uintptr_t word; uint8_t bytes[sizeof(uintptr_t)]; } data; size_t ncopy = std::min(length, sizeof(uintptr_t)); errno = 0; if (ncopy < sizeof(uintptr_t)) { data.word = wrapPtrace(PTRACE_PEEKDATA, pid, base + nread, nullptr); if (errno == 0) { std::memcpy(words, data.bytes, ncopy); } } else { *words = wrapPtrace(PTRACE_PEEKDATA, pid, base + nread, nullptr); } if (errno != 0) break; if (nullTerm && strnlen((char *)words, ncopy) < ncopy) { foundNull = true; break; } length -= ncopy; nread += ncopy; words++; } if (count != nullptr) { *count = nread; } if (errno != 0) return Platform::TranslateError(); if (nullTerm && !foundNull) return kErrorNameTooLong; return kSuccess; }
ErrorCode PTrace::writeMemory(ProcessThreadId const &ptid, Address const &address, void const *buffer, size_t length, size_t *count) { pid_t pid; CHK(ptidToPid(ptid, pid)); size_t nwritten = 0; uintptr_t base = address; uintptr_t const *words = (uintptr_t const *)buffer; if (length == 0 || buffer == nullptr) { if (count != nullptr) { *count = 0; } return kSuccess; } while (length > 0) { union { uintptr_t word; uint8_t bytes[sizeof(uintptr_t)]; } data; size_t ncopy = std::min(length, sizeof(uintptr_t)); errno = 0; if (ncopy < sizeof(uintptr_t)) { data.word = wrapPtrace(PTRACE_PEEKDATA, pid, base + nwritten, nullptr); if (errno == 0) { std::memcpy(data.bytes, words, ncopy); wrapPtrace(PTRACE_POKEDATA, pid, base + nwritten, data.word); } } else { wrapPtrace(PTRACE_POKEDATA, pid, base + nwritten, *words); } if (errno != 0) break; length -= ncopy; nwritten += ncopy; words++; } if (errno != 0) return Platform::TranslateError(); if (count != nullptr) { *count = nwritten; } return kSuccess; }
ErrorCode PTrace::writeCPUState(ProcessThreadId const &ptid, ProcessInfo const &pinfo, Architecture::CPUState const &state) { pid_t pid; if (!ptid.valid()) return kErrorInvalidArgument; if (!(ptid.tid <= kAnyThreadId)) { pid = ptid.tid; } else { pid = ptid.pid; } // // Initialize the CPU state, just in case. // initCPUState(pid); if (pinfo.pointerSize == sizeof(uint32_t) && !state.is32) return kErrorInvalidArgument; else if (pinfo.pointerSize != sizeof(uint32_t) && state.is32) return kErrorInvalidArgument; // // Write GPRs // user_regs_struct gprs; if (state.is32) { state32_to_user(gprs, state.state32); } else { state64_to_user(gprs, state.state64); } if (wrapPtrace(PTRACE_SETREGS, pid, nullptr, &gprs) < 0) return Platform::TranslateError(); // // Write X87 and SSE state // user_fpregs_struct fprs; if (state.is32) { state32_to_user(fprs, state.state32); } else { state64_to_user(fprs, state.state64); } wrapPtrace(PTRACE_SETFPREGS, pid, nullptr, &fprs); return kSuccess; }
ErrorCode PTrace::readCPUState(ProcessThreadId const &ptid, ProcessInfo const &pinfo, Architecture::CPUState &state) { pid_t pid; if (!ptid.valid()) return kErrorInvalidArgument; if (!(ptid.tid <= kAnyThreadId)) { pid = ptid.tid; } else { pid = ptid.pid; } // // Initialize the CPU state, just in case. // initCPUState(pid); // // Read GPRs // user_regs_struct gprs; if (wrapPtrace(PTRACE_GETREGS, pid, nullptr, &gprs) < 0) return Platform::TranslateError(); if (pinfo.pointerSize == sizeof(uint32_t)) { state.is32 = true; user_to_state32(state.state32, gprs); } else { state.is32 = false; user_to_state64(state.state64, gprs); } // // Read X87 and SSE state // user_fpregs_struct fprs; if (wrapPtrace(PTRACE_GETFPREGS, pid, nullptr, &fprs) == 0) { if (pinfo.pointerSize == sizeof(uint32_t)) { user_to_state32(state.state32, fprs); } else { user_to_state64(state.state64, fprs); } } return kSuccess; }
ErrorCode PTrace::writeMemory(ProcessThreadId const &ptid, Address const &address, void const *buffer, size_t length, size_t *count) { pid_t pid; CHK(ptidToPid(ptid, pid)); uintptr_t base = address; struct ptrace_io_desc desc; if (length == 0 || buffer == nullptr) { if (count != nullptr) *count = 0; return kSuccess; } desc.piod_op = PIOD_WRITE_D; desc.piod_offs = (void *)base; desc.piod_addr = (void *)buffer; desc.piod_len = length; if (wrapPtrace(PT_IO, pid, &desc, nullptr) < 0) return Platform::TranslateError(); if (count != nullptr) *count = desc.piod_len; return kSuccess; }
ErrorCode PTrace::resume(ProcessThreadId const &ptid, ProcessInfo const &pinfo, int signal, Address const &address) { pid_t pid; caddr_t addr; if (!ptid.valid()) return kErrorInvalidArgument; if (!(ptid.tid <= kAnyThreadId)) { pid = ptid.tid; } else { pid = ptid.pid; } // // Continuation from address? // if (address.valid()) { addr = (caddr_t)address.value(); } else { // (caddr_t)1 indicate that execution is to pick up where it left off. addr = (caddr_t)1; } if (wrapPtrace(PT_CONTINUE, pid, addr, signal) < 0) return Platform::TranslateError(); return kSuccess; }
ErrorCode PTrace::resume(ProcessThreadId const &ptid, ProcessInfo const &pinfo, int signal, Address const &address) { pid_t pid; caddr_t addr = (caddr_t)1; if (!ptid.valid()) return kErrorInvalidArgument; if (!(ptid.tid <= kAnyThreadId)) { pid = ptid.tid; } else { pid = ptid.pid; } // // Continuation from address? // if (address.valid()) { addr = (caddr_t)address.value(); } if (wrapPtrace(PT_SYSCALL, pid, addr, signal) < 0) return Platform::TranslateError(); return kSuccess; }
ErrorCode PTrace::step(ProcessThreadId const &ptid, ProcessInfo const &pinfo, int signal, Address const &address) { pid_t pid; if (!ptid.valid()) return kErrorInvalidArgument; if (!(ptid.tid <= kAnyThreadId)) { pid = ptid.tid; } else { pid = ptid.pid; } // // Continuation from address? // if (address.valid()) { Architecture::CPUState state; ErrorCode error = readCPUState(ptid, pinfo, state); if (error != kSuccess) return error; state.setPC(address); error = writeCPUState(ptid, pinfo, state); if (error != kSuccess) return error; } // (caddr_t)1 indicate that execution is to pick up where it left off. if (wrapPtrace(PT_STEP, pid, (caddr_t)1, signal) < 0) return Platform::TranslateError(); return kSuccess; }
ErrorCode PTrace::getSigInfo(ProcessThreadId const &ptid, siginfo_t &si) { pid_t pid; CHK(ptidToPid(ptid, pid)); if (wrapPtrace(PTRACE_GETSIGINFO, pid, nullptr, &si) < 0) return Platform::TranslateError(); return kSuccess; }
ErrorCode PTrace::getLwpInfo(ProcessThreadId const &ptid, struct ptrace_lwpinfo *lwpinfo) { pid_t pid; CHK(ptidToPid(ptid, pid)); if (wrapPtrace(PT_LWPINFO, pid, lwpinfo, sizeof(struct ptrace_lwpinfo)) < 0) return Platform::TranslateError(); return kSuccess; }
ErrorCode PTrace::writeRegisterSet(ProcessThreadId const &ptid, int regSetCode, void const *buffer, size_t length) { struct iovec iov = {const_cast<void *>(buffer), length}; if (wrapPtrace(PTRACE_SETREGSET, ptid.validTid() ? ptid.tid : ptid.pid, regSetCode, &iov) < 0) return Platform::TranslateError(); return kSuccess; }
ErrorCode PTrace::detach(ProcessId pid) { if (pid <= kAnyProcessId) return kErrorProcessNotFound; DS2LOG(Debug, "detaching from pid %" PRIu64, (uint64_t)pid); if (wrapPtrace(PT_DETACH, pid, nullptr, nullptr) < 0) return Platform::TranslateError(); return kSuccess; }
ErrorCode PTrace::getSigInfo(ProcessThreadId const &ptid, siginfo_t &si) { struct ptrace_lwpinfo lwpinfo; pid_t pid; CHK(ptidToPid(ptid, pid)); if (wrapPtrace(PT_LWPINFO, pid, &lwpinfo, sizeof lwpinfo) < 0) return Platform::TranslateError(); si = lwpinfo.pl_siginfo; return kSuccess; }
ErrorCode PTrace::attach(ProcessId pid) { if (pid <= kAnyProcessId) return kErrorProcessNotFound; DS2LOG(Debug, "attaching to pid %" PRIu64, (uint64_t)pid); if (wrapPtrace(PT_ATTACH, pid, nullptr, nullptr) < 0) { ErrorCode error = Platform::TranslateError(); DS2LOG(Error, "Unable to attach: %d", error); return error; } return kSuccess; }
ErrorCode PTrace::readRegisterSet(ProcessThreadId const &ptid, int regSetCode, void *buffer, size_t length) { struct iovec iov = {buffer, length}; if (wrapPtrace(PTRACE_GETREGSET, ptid.validTid() ? ptid.tid : ptid.pid, regSetCode, &iov) < 0) return Platform::TranslateError(); // On return, the kernel modifies iov.len to return the number of bytes read. // This should be exactly equal to the number of bytes requested. DS2ASSERT(iov.iov_len == length); return kSuccess; }
ErrorCode PTrace::traceThat(ProcessId pid) { if (pid <= 0) return kErrorInvalidArgument; unsigned long traceFlags = PTRACE_O_TRACECLONE; // // Trace clone and exit events to track threads. // if (wrapPtrace(PTRACE_SETOPTIONS, pid, nullptr, traceFlags) < 0) { DS2LOG(Warning, "unable to set PTRACE_O_TRACECLONE on pid %d, error=%s", pid, strerror(errno)); return Platform::TranslateError(); } return kSuccess; }
ErrorCode PTrace::getLwpInfo(ProcessThreadId const &ptid, struct ptrace_lwpinfo *lwpinfo) { pid_t pid; if (!ptid.valid()) return kErrorInvalidArgument; if (!(ptid.tid <= kAnyThreadId)) { pid = ptid.tid; } else { pid = ptid.pid; } if (wrapPtrace(PT_LWPINFO, pid, lwpinfo, sizeof(struct ptrace_lwpinfo)) < 0) return Platform::TranslateError(); return kSuccess; }
ErrorCode PTrace::getSigInfo(ProcessThreadId const &ptid, siginfo_t &si) { struct ptrace_lwpinfo lwpinfo; pid_t pid; if (!ptid.valid()) return kErrorInvalidArgument; if (!(ptid.tid <= kAnyThreadId)) { pid = ptid.tid; } else { pid = ptid.pid; } if (wrapPtrace(PT_LWPINFO, pid, &lwpinfo, sizeof lwpinfo) < 0) return Platform::TranslateError(); si = lwpinfo.pl_siginfo; return kSuccess; }
ErrorCode PTrace::writeMemory(ProcessThreadId const &ptid, Address const &address, void const *buffer, size_t length, size_t *count) { pid_t pid; if (!ptid.valid() || !address.valid()) return kErrorInvalidArgument; if (!(ptid.tid <= kAnyThreadId)) { pid = ptid.tid; } else { pid = ptid.pid; } uintptr_t base = address; struct ptrace_io_desc desc; if (length == 0 || buffer == nullptr) { if (count != nullptr) *count = 0; return kSuccess; } desc.piod_op = PIOD_WRITE_D; desc.piod_offs = (void *)base; desc.piod_addr = (void *)buffer; desc.piod_len = length; if (wrapPtrace(PT_IO, pid, &desc, nullptr) < 0) return Platform::TranslateError(); if (count != nullptr) *count = desc.piod_len; return kSuccess; }
ErrorCode PTrace::traceMe(bool disableASLR) { if (wrapPtrace(PT_TRACE_ME, 0, nullptr, nullptr) < 0) return Platform::TranslateError(); return kSuccess; }