From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Brian Gianforcaro Date: Sun, 20 Feb 2022 00:32:51 -0800 Subject: [PATCH] serenity: Implement custom wait override for the serenity_nat_target While troubleshooting why gdb wasn't working when attempting to debug serenity programs I noticed two things: - The contract of serenity's `waitpid(..)` appears to be slightly different than the generic ptrace target expects. We need to make sure we pass `WSTOPPED`, and it can return different errno values that we would want to re-try on. - The contract of serenity's `ptrace(..)` implementation appears to diverge as well, as we are expected to call `PT_ATTACH` before we call `PT_CONTINUE`, otherwise `ptrace(..)` will just error out. Allow gdb to understand these differences, I've overloaded the serenity_nat_target::wait(..) method and added the logic there. --- gdb/serenity-nat.c | 62 +++++++++++++++++++++++++++++++++++++++++++++- gdb/serenity-nat.h | 4 +++ 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/gdb/serenity-nat.c b/gdb/serenity-nat.c index ff740d4..b1d39d4 100644 --- a/gdb/serenity-nat.c +++ b/gdb/serenity-nat.c @@ -10,4 +10,64 @@ #include "gdbsupport/gdb_wait.h" #include "inf-child.h" -#include "serenity-nat.h" \ No newline at end of file +#include "serenity-nat.h" + +ptid_t serenity_nat_target::wait (ptid_t ptid, struct target_waitstatus* ourstatus, target_wait_flags) +{ + int pid; + int status, save_errno; + + do + { + set_sigint_trap (); + + do + { + errno = 0; + pid = waitpid (ptid.pid (), &status, WSTOPPED); + if (errno != 0) + { + save_errno = errno; + perror_with_name (("waitpid")); + } + } + while (pid == -1 && (save_errno == EINTR || save_errno == EAGAIN)); + + clear_sigint_trap (); + + if (pid == -1) + { + fprintf_unfiltered (gdb_stderr, + _("Child process unexpectedly missing: %s.\n"), + safe_strerror (save_errno)); + + /* Claim it exited with unknown signal. */ + ourstatus->kind = TARGET_WAITKIND_SIGNALLED; + ourstatus->value.sig = GDB_SIGNAL_UNKNOWN; + return inferior_ptid; + } + + /* Ignore terminated detached child processes. */ + if (!WIFSTOPPED (status) && find_inferior_pid (this, pid) == nullptr) + pid = -1; + } + while (pid == -1); + + store_waitstatus (ourstatus, status); + + /* Serenity requires us to PT_ATTACH before we PT_CONTINUE, however GDB doesn't + * provide a hook for us to do that before we issue the PT_CONTINUE, so we are + * forced to do it here. + */ + if (!m_attach_before_continue_called) { + errno = 0; + ptrace (PT_ATTACH, pid, (PTRACE_TYPE_ARG3)0, 0); + if (errno != 0) { + save_errno = errno; + printf_unfiltered (_("PT_ATTACH failed: %d - %s \n"), save_errno, safe_strerror (save_errno)); + } + m_attach_before_continue_called = true; + } + + return ptid_t (pid); +} diff --git a/gdb/serenity-nat.h b/gdb/serenity-nat.h index dcd24ce..9ae3b87 100644 --- a/gdb/serenity-nat.h +++ b/gdb/serenity-nat.h @@ -11,6 +11,10 @@ class serenity_nat_target : public inf_ptrace_target { + ptid_t wait (ptid_t, struct target_waitstatus *, target_wait_flags) override; + +private: + bool m_attach_before_continue_called { false }; }; #endif /* serenity-nat.h */