Skip to content

Commit 0f4c009

Browse files
committed
Fix races between watchdog and main thread
1 parent 23e026a commit 0f4c009

1 file changed

Lines changed: 31 additions & 9 deletions

File tree

Linux/debugger.cpp

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -470,25 +470,47 @@ static unsigned char syscall_buf32[] = {
470470

471471
#endif
472472

473+
pid_t waitpid_debug(pid_t pid, int *stat_loc, int options, const char *callsite = "") {
474+
pid_t ret = waitpid(pid, stat_loc, options);
475+
// printf("Waitpid %s returned pid %d status %x\n", callsite, ret, *stat_loc);
476+
return ret;
477+
}
478+
473479
void Debugger::RemoteSyscall() {
480+
// disable watchdog when doing remore syscalls
481+
// we still might get stopped by the watchdog
482+
// but at least it won't happen repeatedly
483+
bool saved_watchdog_state = watchdog_enabled;
484+
watchdog_enabled = false;
485+
474486
SetRegister(ARCH_PC, syscall_address);
475487

476488
uint64_t rsp = GetRegister(ARCH_SP);
477489

478490
ptrace_check(PTRACE_SINGLESTEP, current_pid, nullptr, nullptr);
479491

480-
int status = 0;
481-
int wait_ret = waitpid(current_pid, &status, __WALL);
482-
if(wait_ret != current_pid) {
483-
FATAL("Unexpected wait result after syscall");
492+
while(true) {
493+
int status = 0;
494+
int wait_ret = waitpid_debug(current_pid, &status, __WALL, "remote syscall");
495+
if(WIFSTOPPED(status) && (WSTOPSIG(status) == SIGSTOP)) {
496+
// possible race with watchdog but we don't want to break in the middle of syscall
497+
ptrace(ptrace_continue_request, current_pid, 0, 0);
498+
continue;
499+
}
500+
if(wait_ret != current_pid) {
501+
FATAL("Unexpected wait result after syscall");
502+
}
503+
break;
484504
}
505+
485506
// printf("syscall status: %x\n", status);
486507

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

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

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

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

19451967
watchdog_mutex.lock();
19461968
watchdog_enabled = false;
1947-
if(killed_by_watchdog) {
1969+
if(killed_by_watchdog && WIFSTOPPED(status) && (WSTOPSIG(status) == SIGSTOP)) {
19481970
watchdog_mutex.unlock();
19491971
return DEBUGGER_HANGED;
19501972
}
@@ -2021,7 +2043,7 @@ DebuggerStatus Debugger::Run(int argc, char **argv, uint32_t timeout) {
20212043
}
20222044

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

0 commit comments

Comments
 (0)