From 863e4da4b6713fbd0b3a19fe3a7f7be1ea34f704 Mon Sep 17 00:00:00 2001 From: Mark Kettenis Date: Thu, 27 Feb 2014 23:23:46 +0100 Subject: [PATCH] Support rthreads on OpenBSD 5.2 and later. OpenBSD 5.2 and later have a proper threads implementation based on kernel threads. Debugging support is provided through additional ptrace(2) requests, so this diff extends the generic code in inf-ptrace.c with OpenBSD-specific code to discover additional threads. gdb/ChangeLog: * obsd-nat.h: New file. * obsd-nat.c: New file. * Makefile.in (HFILES_NO_SRCDIR): Add obsd-nat.h. (ALLDEPFILES): Add obsd-nat.c. --- gdb/ChangeLog | 7 ++ gdb/Makefile.in | 4 +- gdb/obsd-nat.c | 185 ++++++++++++++++++++++++++++++++++++++++++++++++ gdb/obsd-nat.h | 25 +++++++ 4 files changed, 219 insertions(+), 2 deletions(-) create mode 100644 gdb/obsd-nat.c create mode 100644 gdb/obsd-nat.h diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 2c615be3f1..063382945f 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,10 @@ +2014-02-28 Mark Kettenis + + * obsd-nat.h: New file. + * obsd-nat.c: New file. + * Makefile.in (HFILES_NO_SRCDIR): Add obsd-nat.h. + (ALLDEPFILES): Add obsd-nat.c. + 2014-02-28 Tom Tromey * cli-out.c (cli_ui_out_impl): Now const. Remove comment. diff --git a/gdb/Makefile.in b/gdb/Makefile.in index fe069883c3..c8e2c9db84 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -864,7 +864,7 @@ gnulib/import/string.in.h gnulib/import/str-two-way.h \ gnulib/import/stdint.in.h remote.h remote-notif.h gdb.h sparc-nat.h \ gdbthread.h dwarf2-frame.h dwarf2-frame-tailcall.h nbsd-nat.h dcache.h \ amd64-nat.h s390-linux-tdep.h arm-linux-tdep.h exceptions.h macroscope.h \ -gdbarch.h bsd-uthread.h memory-map.h memrange.h \ +gdbarch.h bsd-uthread.h memory-map.h memrange.h obsd-nat.h \ mdebugread.h m88k-tdep.h stabsread.h hppa-linux-offsets.h linux-fork.h \ ser-unix.h inf-ptrace.h terminal.h ui-out.h frame-base.h \ f-lang.h dwarf2loc.h value.h sparc-tdep.h defs.h target-descriptions.h \ @@ -1639,7 +1639,7 @@ ALLDEPFILES = \ mips64obsd-nat.c mips64obsd-tdep.c \ msp430-tdep.c \ nios2-tdep.c nios2-linux-tdep.c \ - nbsd-nat.c nbsd-tdep.c obsd-tdep.c \ + nbsd-nat.c nbsd-tdep.c obsd-nat.c obsd-tdep.c \ solib-osf.c \ somread.c solib-som.c \ posix-hdep.c \ diff --git a/gdb/obsd-nat.c b/gdb/obsd-nat.c new file mode 100644 index 0000000000..c17a5658fa --- /dev/null +++ b/gdb/obsd-nat.c @@ -0,0 +1,185 @@ +/* Native-dependent code for OpenBSD. + + Copyright (C) 2012-2014 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "defs.h" +#include "gdbthread.h" +#include "inferior.h" +#include "target.h" + +#include "gdb_assert.h" +#include +#include +#include + +#include "inf-child.h" +#include "obsd-nat.h" + +/* OpenBSD 5.2 and later include rthreads which uses a thread model + that maps userlan threads directly onto kernel threads in a 1:1 + fashion. */ + +#ifdef PT_GET_THREAD_FIRST + +static char * +obsd_pid_to_str (struct target_ops *ops, ptid_t ptid) +{ + if (ptid_get_lwp (ptid) != 0) + { + static char buf[64]; + + xsnprintf (buf, sizeof buf, "thread %ld", ptid_get_lwp (ptid)); + return buf; + } + + return normal_pid_to_str (ptid); +} + +static void +obsd_find_new_threads (struct target_ops *ops) +{ + pid_t pid = ptid_get_pid (inferior_ptid); + struct ptrace_thread_state pts; + + if (ptrace(PT_GET_THREAD_FIRST, pid, (caddr_t)&pts, sizeof pts) == -1) + perror_with_name (("ptrace")); + + while (pts.pts_tid != -1) + { + ptid_t ptid = ptid_build (pid, pts.pts_tid, 0); + + if (!in_thread_list (ptid)) + { + if (ptid_get_lwp (inferior_ptid) == 0) + thread_change_ptid (inferior_ptid, ptid); + else + add_thread (ptid); + } + + if (ptrace(PT_GET_THREAD_NEXT, pid, (caddr_t)&pts, sizeof pts) == -1) + perror_with_name (("ptrace")); + } +} + +static ptid_t +obsd_wait (struct target_ops *ops, + ptid_t ptid, struct target_waitstatus *ourstatus, int options) +{ + pid_t pid; + int status, save_errno; + + do + { + set_sigint_trap (); + + do + { + pid = waitpid (ptid_get_pid (ptid), &status, 0); + save_errno = errno; + } + while (pid == -1 && errno == EINTR); + + 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) && pid != ptid_get_pid (inferior_ptid)) + pid = -1; + } + while (pid == -1); + + ptid = pid_to_ptid (pid); + + if (WIFSTOPPED (status)) + { + ptrace_state_t pe; + pid_t fpid; + + if (ptrace (PT_GET_PROCESS_STATE, pid, (caddr_t)&pe, sizeof pe) == -1) + perror_with_name (("ptrace")); + + switch (pe.pe_report_event) + { + case PTRACE_FORK: + ourstatus->kind = TARGET_WAITKIND_FORKED; + ourstatus->value.related_pid = pid_to_ptid (pe.pe_other_pid); + + /* Make sure the other end of the fork is stopped too. */ + fpid = waitpid (pe.pe_other_pid, &status, 0); + if (fpid == -1) + perror_with_name (("waitpid")); + + if (ptrace (PT_GET_PROCESS_STATE, fpid, + (caddr_t)&pe, sizeof pe) == -1) + perror_with_name (("ptrace")); + + gdb_assert (pe.pe_report_event == PTRACE_FORK); + gdb_assert (pe.pe_other_pid == pid); + if (fpid == ptid_get_pid (inferior_ptid)) + { + ourstatus->value.related_pid = pid_to_ptid (pe.pe_other_pid); + return pid_to_ptid (fpid); + } + + return pid_to_ptid (pid); + } + + ptid = ptid_build (pid, pe.pe_tid, 0); + if (!in_thread_list (ptid)) + { + if (ptid_get_lwp (inferior_ptid) == 0) + thread_change_ptid (inferior_ptid, ptid); + else + add_thread (ptid); + } + } + + store_waitstatus (ourstatus, status); + return ptid; +} + +void +obsd_add_target (struct target_ops *t) +{ + /* Override some methods to support threads. */ + t->to_pid_to_str = obsd_pid_to_str; + t->to_find_new_threads = obsd_find_new_threads; + t->to_wait = obsd_wait; + add_target (t); +} + +#else + +void +obsd_add_target (struct target_ops *t) +{ + add_target (t); +} + +#endif /* PT_GET_THREAD_FIRST */ diff --git a/gdb/obsd-nat.h b/gdb/obsd-nat.h new file mode 100644 index 0000000000..ad021fc4a8 --- /dev/null +++ b/gdb/obsd-nat.h @@ -0,0 +1,25 @@ +/* Native-dependent code for OpenBSD. + + Copyright (C) 2014 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#ifndef OBSD_NAT_H +#define OBSD_NAT_H + +extern void obsd_add_target (struct target_ops *); + +#endif /* obsd-nat.h */ -- 2.34.1