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; }
// // Execute will execute the code in the target process/thread, // the techinique for PTRACE is to read CPU state, rewrite the // code portion pointed by PC with the code, resuming the process/thread, // wait for the completion, read the CPU state back to grab return // values, then restoring the previous code. // ErrorCode PTrace::execute(ProcessThreadId const &ptid, ProcessInfo const &pinfo, void const *code, size_t length, uint64_t &result) { Architecture::CPUState savedState, resultState; std::string savedCode; if (!ptid.valid() || code == nullptr || length == 0) return kErrorInvalidArgument; // 1. Read and save the CPU state ErrorCode error = readCPUState(ptid, pinfo, savedState); if (error != kSuccess) return error; // 2. Copy the code at PC savedCode.resize(length); error = readMemory(ptid, savedState.pc(), &savedCode[0], length); if (error != kSuccess) return error; // 3. Write the code to execute at PC error = writeMemory(ptid, savedState.pc(), code, length); if (error != kSuccess) goto fail; // 3. Resume and wait error = resume(ptid, pinfo); if (error == kSuccess) { error = wait(ptid); } if (error == kSuccess) { // 4. Read back the CPU state error = readCPUState(ptid, pinfo, resultState); if (error == kSuccess) { // 5. Save the result result = resultState.retval(); } } // 6. Write back the old code error = writeMemory(ptid, savedState.pc(), &savedCode[0], length); if (error != kSuccess) goto fail; // 7. Restore CPU state error = writeCPUState(ptid, pinfo, savedState); if (error != kSuccess) goto fail; // Success!! We injected and executed code! return kSuccess; fail: return kill(ptid, SIGKILL); // we can't really do much at this point :( }
ErrorCode Thread::step(int signal, Address const &address) { // Windows doesn't have a dedicated single-step call. We have to set // the single step flag in eflags and resume the thread. Architecture::CPUState state; ErrorCode error; error = readCPUState(state); if (error != kSuccess) return error; // TF (trap flag) is the 8th bit of eflags. state.gp.eflags |= (1 << 8); error = writeCPUState(state); if (error != kSuccess) return error; return resume(signal, address); }
ErrorCode PTrace::prepareAddressForResume(ProcessThreadId const &ptid, ProcessInfo const &pinfo, Address const &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; } } return kSuccess; }