Skip to content

Commit

Permalink
Fix races between watchdog and main thread
Browse files Browse the repository at this point in the history
  • Loading branch information
ifratric committed Sep 24, 2024
1 parent 23e026a commit 0f4c009
Showing 1 changed file with 31 additions and 9 deletions.
40 changes: 31 additions & 9 deletions Linux/debugger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -470,25 +470,47 @@ static unsigned char syscall_buf32[] = {

#endif

pid_t waitpid_debug(pid_t pid, int *stat_loc, int options, const char *callsite = "") {
pid_t ret = waitpid(pid, stat_loc, options);
// printf("Waitpid %s returned pid %d status %x\n", callsite, ret, *stat_loc);
return ret;
}

void Debugger::RemoteSyscall() {
// disable watchdog when doing remore syscalls
// we still might get stopped by the watchdog
// but at least it won't happen repeatedly
bool saved_watchdog_state = watchdog_enabled;
watchdog_enabled = false;

SetRegister(ARCH_PC, syscall_address);

uint64_t rsp = GetRegister(ARCH_SP);

ptrace_check(PTRACE_SINGLESTEP, current_pid, nullptr, nullptr);

int status = 0;
int wait_ret = waitpid(current_pid, &status, __WALL);
if(wait_ret != current_pid) {
FATAL("Unexpected wait result after syscall");
while(true) {
int status = 0;
int wait_ret = waitpid_debug(current_pid, &status, __WALL, "remote syscall");
if(WIFSTOPPED(status) && (WSTOPSIG(status) == SIGSTOP)) {
// possible race with watchdog but we don't want to break in the middle of syscall
ptrace(ptrace_continue_request, current_pid, 0, 0);
continue;
}
if(wait_ret != current_pid) {
FATAL("Unexpected wait result after syscall");
}
break;
}

// printf("syscall status: %x\n", status);

// uint64_t rip = GetRegister(RIP);
// printf("rip: %lx, syscall_address: %lx\n", rip, syscall_address);

if(rsp != GetRegister(ARCH_SP)) FATAL("rsp mismatch %lx %lx", rsp, GetRegister(ARCH_SP));
// printf("Syscall status: %x\n", status);
watchdog_enabled = saved_watchdog_state;
}

void Debugger::SetSyscallArguments(uint64_t *args, size_t num_args) {
Expand Down Expand Up @@ -1819,7 +1841,7 @@ DebuggerStatus Debugger::HandleStopped(int status) {
if (trace_debug_events) printf("Debugger: New thread, pid: %d\n", new_thread_pid);
if(threads.find(new_thread_pid) == threads.end()) {
int new_thread_status = 0;
pid_t ret_pid = waitpid(new_thread_pid, &new_thread_status, __WALL);
pid_t ret_pid = waitpid_debug(new_thread_pid, &new_thread_status, __WALL, "thread");
if(ret_pid != new_thread_pid) FATAL("Unexpected waitpid result waiting for new thread\n");
if(!WIFSTOPPED(new_thread_status)) FATAL("Unexpected status from a new thread");
SetThreadOptions(new_thread_pid);
Expand Down Expand Up @@ -1932,7 +1954,7 @@ DebuggerStatus Debugger::DebugLoop(uint32_t timeout) {
int status;
// printf("waiting...\n");
if(timeout != 0xFFFFFFFF) watchdog_enabled = true;
current_pid = waitpid(-1, &status, __WNOTHREAD);
current_pid = waitpid_debug(-1, &status, __WNOTHREAD, "debugloop");

// printf("done, %d %d\n", current_pid, main_pid);
//printf("RIP: %lx\n", GetRegister(RIP));
Expand All @@ -1944,7 +1966,7 @@ DebuggerStatus Debugger::DebugLoop(uint32_t timeout) {

watchdog_mutex.lock();
watchdog_enabled = false;
if(killed_by_watchdog) {
if(killed_by_watchdog && WIFSTOPPED(status) && (WSTOPSIG(status) == SIGSTOP)) {
watchdog_mutex.unlock();
return DEBUGGER_HANGED;
}
Expand Down Expand Up @@ -2021,7 +2043,7 @@ DebuggerStatus Debugger::Run(int argc, char **argv, uint32_t timeout) {
}

int status;
pid_t ret = waitpid(child_pid, &status, 0);
pid_t ret = waitpid_debug(child_pid, &status, 0, "run");
if ((ret != child_pid) || !WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP)) {
FATAL("Child process didn't start correctly");
}
Expand Down Expand Up @@ -2100,7 +2122,7 @@ DebuggerStatus Debugger::Attach(unsigned int pid, uint32_t timeout) {
for(auto iter = threads.begin(); iter != threads.end(); ++iter) {
// printf("waiting for %d\n", *iter);
int new_thread_status = 0;
pid_t ret_pid = waitpid(*iter, &new_thread_status, __WALL);
pid_t ret_pid = waitpid_debug(*iter, &new_thread_status, __WALL, "attach");
if(ret_pid != *iter) FATAL("Unexpected waitpid result waiting for new thread\n");
// printf("status: %x\n", new_thread_status);
if(!WIFSTOPPED(new_thread_status)) FATAL("Unexpected status from a new thread");
Expand Down

0 comments on commit 0f4c009

Please sign in to comment.