binutils-gdb/gdb/obsd-nat.c
Andrew Burgess 200fd2874d gdb: make post_startup_inferior a virtual method on inf_ptrace_target
While working on a later patch that required me to understand how GDB
starts up inferiors, I was confused by the
target_ops::post_startup_inferior method.

The post_startup_inferior target function is only called from
inf_ptrace_target::create_inferior.

Part of the target class hierarchy looks like this:

  inf_child_target
     |
     '-- inf_ptrace_target
            |
            |-- linux_nat_target
            |
            |-- fbsd_nat_target
            |
            |-- nbsd_nat_target
            |
            |-- obsd_nat_target
            |
            '-- rs6000_nat_target

Every sub-class of inf_ptrace_target, except rs6000_nat_target,
implements ::post_startup_inferior.  The rs6000_nat_target picks up
the implementation of ::post_startup_inferior not from
inf_ptrace_target, but from inf_child_target.

No descendent of inf_child_target, outside the inf_ptrace_target
sub-tree, implements ::post_startup_inferior, which isn't really
surprising, as they would never see the method called (remember, the
method is only called from inf_ptrace_target::create_inferior).

What I find confusing is the role inf_child_target plays in
implementing, what is really a helper function for just one of its
descendents.

In this commit I propose that we formally make ::post_startup_inferior
a helper function of inf_ptrace_target.  To do this I will remove the
::post_startup_inferior from the target_ops API, and instead make this
a protected, pure virtual function on inf_ptrace_target.

I'll remove the empty implementation of ::post_startup_inferior from
the inf_child_target class, and add a new empty implementation to the
rs6000_nat_target class.

All the other descendents of inf_ptrace_target already provide an
implementation of this method and so don't need to change beyond
making the method protected within their class declarations.

To me, this makes much more sense now.  The helper function, which is
only called from within the inf_ptrace_target class, is now a part of
the inf_ptrace_target class.

The only way in which this change is visible to a user is if the user
turns on 'set debug target 1'.  With this debug flag on, prior to this
patch the user would see something like:

  -> native->post_startup_inferior (...)
  <- native->post_startup_inferior (2588939)

After this patch these lines are no longer present, as the
post_startup_inferior is no longer a top level target method.  For me,
this is an acceptable change.
2021-12-13 11:10:29 +00:00

187 lines
4.7 KiB
C

/* Native-dependent code for OpenBSD.
Copyright (C) 2012-2021 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 <http://www.gnu.org/licenses/>. */
#include "defs.h"
#include "gdbthread.h"
#include "inferior.h"
#include "target.h"
#include <sys/types.h>
#include <sys/ptrace.h>
#include "gdbsupport/gdb_wait.h"
#include "inf-ptrace.h"
#include "obsd-nat.h"
/* OpenBSD 5.2 and later include rthreads which uses a thread model
that maps userland threads directly onto kernel threads in a 1:1
fashion. */
std::string
obsd_nat_target::pid_to_str (ptid_t ptid)
{
if (ptid.lwp () != 0)
return string_printf ("thread %ld of process %d", ptid.lwp (), ptid.pid ());
return normal_pid_to_str (ptid);
}
void
obsd_nat_target::update_thread_list ()
{
pid_t pid = inferior_ptid.pid ();
struct ptrace_thread_state pts;
prune_threads ();
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_t (pid, pts.pts_tid, 0);
if (!in_thread_list (this, ptid))
{
if (inferior_ptid.lwp () == 0)
thread_change_ptid (this, inferior_ptid, ptid);
else
add_thread (this, ptid);
}
if (ptrace (PT_GET_THREAD_NEXT, pid, (caddr_t)&pts, sizeof pts) == -1)
perror_with_name (("ptrace"));
}
}
/* Enable additional event reporting on a new or existing process. */
static void
obsd_enable_proc_events (pid_t pid)
{
ptrace_event_t pe;
/* Set the initial event mask. */
memset (&pe, 0, sizeof pe);
pe.pe_set_event |= PTRACE_FORK;
if (ptrace (PT_SET_EVENT_MASK, pid,
(PTRACE_TYPE_ARG3)&pe, sizeof pe) == -1)
perror_with_name (("ptrace"));
}
ptid_t
obsd_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
target_wait_flags options)
{
ptid_t wptid = inf_ptrace_target::wait (ptid, ourstatus, options);
if (ourstatus->kind () == TARGET_WAITKIND_STOPPED)
{
ptrace_state_t pe;
pid_t pid = wptid.pid ();
if (ptrace (PT_GET_PROCESS_STATE, pid, (caddr_t)&pe, sizeof pe) == -1)
perror_with_name (("ptrace"));
wptid = ptid_t (pid, pe.pe_tid, 0);
switch (pe.pe_report_event)
{
case PTRACE_FORK:
ourstatus->set_forked (ptid_t (pe.pe_other_pid));
/* Make sure the other end of the fork is stopped too. */
pid_t fpid = waitpid (pe.pe_other_pid, nullptr, 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 (find_inferior_pid (this, fpid) != nullptr)
{
ourstatus->set_forked (ptid_t (pe.pe_other_pid));
wptid = ptid_t (fpid, pe.pe_tid, 0);
}
obsd_enable_proc_events (ourstatus->child_ptid ().pid ());
break;
}
/* Ensure the ptid is updated with an LWP id on the first stop
of a process. */
if (!in_thread_list (this, wptid))
{
if (in_thread_list (this, ptid_t (pid)))
thread_change_ptid (this, ptid_t (pid), wptid);
else
add_thread (this, wptid);
}
}
return wptid;
}
void
obsd_nat_target::post_attach (int pid)
{
obsd_enable_proc_events (pid);
}
/* Implement the virtual inf_ptrace_target::post_startup_inferior method. */
void
obsd_nat_target::post_startup_inferior (ptid_t pid)
{
obsd_enable_proc_events (pid.pid ());
}
/* Target hook for follow_fork. */
void
obsd_nat_target::follow_fork (inferior *child_inf, ptid_t child_ptid,
target_waitkind fork_kind,
bool follow_child, bool detach_fork)
{
inf_ptrace_target::follow_fork (child_inf, child_ptid, fork_kind,
follow_child, detach_fork);
if (!follow_child && detach_fork)
{
/* Breakpoints have already been detached from the child by
infrun.c. */
if (ptrace (PT_DETACH, child_ptid.pid (), (PTRACE_TYPE_ARG3)1, 0) == -1)
perror_with_name (("ptrace"));
}
}
int
obsd_nat_target::insert_fork_catchpoint (int pid)
{
return 0;
}
int
obsd_nat_target::remove_fork_catchpoint (int pid)
{
return 0;
}