Re: Likely obsolete pieces of GDB

John David Anglin
2007-01-01T16:47:52Z

> > Tried a simple test with this version. Tried to debug gdb itself.
> > Set a break on main and ran gdb with "-v". The exterior gdb dumped
> > core. The cause seems to be that the deprecated_child_ops struct
> > hasn't been initialized. It looks like the stuff in inf-ptrace.c
> > needs to be merged into hpux-thread.c, or we need to setup
> > deprecated_child_ops. Presumably, this was done at some point in
> > the past.
>
> Is this worth fixing? Obviously no one has used it lately.

Don't know but I probably would use it if it worked. I hacked
on this a bit a couple of weeks ago. I mainly pulled code from
inftarg.c with a bit of specialization for hpux. It builds and
some stuff may work...

Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)

Index: gdb/hpux-thread.c
===================================================================
RCS file: /cvs/src/src/gdb/hpux-thread.c,v
retrieving revision 1.32
diff -u -3 -p -r1.32 hpux-thread.c
--- gdb/hpux-thread.c 17 Dec 2005 22:34:01 -0000 1.32
+++ gdb/hpux-thread.c 1 Jan 2007 16:39:37 -0000
@@ -41,6 +41,7 @@
#include <cma_deb_core.h>
#include "gdbthread.h"
#include "target.h"
+#include "command.h"
#include "inferior.h"
#include "regcache.h"
#include <fcntl.h>
@@ -48,6 +49,9 @@
#include "gdb_stat.h"
#include "gdbcore.h"
#include "hppa-tdep.h"
+#include "inflow.h"
+
+#include "gdb_ptrace.h"

extern int child_suppress_run;

@@ -118,7 +122,8 @@ find_tcb (ptid_t ptid)

tcb_ptr = cma__base (queue_ptr, threads, cma__t_int_tcb);

- read_memory ((CORE_ADDR) tcb_ptr, (char *) &cached_tcb, sizeof cached_tcb);
+ read_memory ((CORE_ADDR) tcb_ptr, (char *) &cached_tcb,
+ sizeof cached_tcb);

if (cached_tcb.header.type == cma__c_obj_tcb)
if (cma_thread_get_unique (&cached_tcb.prolog.client_thread) == thread)
@@ -138,18 +143,79 @@ find_tcb (ptid_t ptid)
static void
hpux_thread_open (char *arg, int from_tty)
{
- deprecated_child_ops.to_open (arg, from_tty);
+ error (_("Use the \"run\" command to start a Unix child process."));
+}
+
+/* Start debugging the process whose number is PID. */
+
+static int
+hpux_attach (int pid)
+{
+ errno = 0;
+ ptrace (PT_ATTACH, pid, (PTRACE_TYPE_ARG3) 0, 0);
+ if (errno != 0)
+ perror_with_name (("ptrace"));
+ attach_flag = 1;
+ return pid;
}

/* Attach to process PID, then initialize for debugging it
and wait for the trace-trap that results from attaching. */

+/* XXX - might want to iterate over all the threads and register them. */
+
static void
hpux_thread_attach (char *args, int from_tty)
{
- deprecated_child_ops.to_attach (args, from_tty);
+ char *exec_file;
+ int pid;
+ char *dummy;
+
+ if (!args)
+ error_no_arg (_("process-id to attach"));
+
+ dummy = args;
+ pid = strtol (args, &dummy, 0);
+ /* Some targets don't set errno on errors, grrr! */
+ if ((pid == 0) && (args == dummy))
+ error (_("Illegal process-id: %s."), args);
+
+ if (pid == getpid ()) /* Trying to masturbate? */
+ error (_("I refuse to debug myself!"));
+
+ if (from_tty)
+ {
+ exec_file = (char *) get_exec_file (0);
+
+ if (exec_file)
+ printf_unfiltered (_("Attaching to program: %s, %s\n"), exec_file,
+ target_pid_to_str (pid_to_ptid (pid)));
+ else
+ printf_unfiltered (_("Attaching to %s\n"),
+ target_pid_to_str (pid_to_ptid (pid)));
+
+ gdb_flush (gdb_stdout);
+ }
+
+ hpux_attach (pid);
+
+ inferior_ptid = pid_to_ptid (pid);
+ push_target (&hpux_thread_ops);
+}
+
+/* Stop debugging the process whose number is PID and continue it with
+ signal number SIGNAL. SIGNAL = 0 means just continue it. */
+
+static void
+hpux_detach (int signal)
+{
+ int pid = PIDGET (inferior_ptid);

- /* XXX - might want to iterate over all the threads and register them. */
+ errno = 0;
+ ptrace (PT_DETACH, pid, (PTRACE_TYPE_ARG3) 1, signal);
+ if (errno != 0)
+ perror_with_name (("ptrace"));
+ attach_flag = 0;
}

/* Take a program previously attached to and detaches it.
@@ -163,7 +229,25 @@ hpux_thread_attach (char *args, int from
static void
hpux_thread_detach (char *args, int from_tty)
{
- deprecated_child_ops.to_detach (args, from_tty);
+ int siggnal = 0;
+ int pid = PIDGET (inferior_ptid);
+
+ if (from_tty)
+ {
+ char *exec_file = get_exec_file (0);
+ if (exec_file == 0)
+ exec_file = "";
+ printf_unfiltered (_("Detaching from program: %s, %s\n"), exec_file,
+ target_pid_to_str (pid_to_ptid (pid)));
+ gdb_flush (gdb_stdout);
+ }
+ if (args)
+ siggnal = atoi (args);
+
+ hpux_detach (siggnal);
+
+ inferior_ptid = null_ptid;
+ unpush_target (&hpux_thread_ops);
}

/* Resume execution of process PID. If STEP is nozero, then
@@ -172,6 +256,40 @@ hpux_thread_detach (char *args, int from
for procfs. */

static void
+hpux_child_resume (ptid_t ptid, int step, enum target_signal signal)
+{
+ int request = PT_CONTINUE;
+ int pid = PIDGET (ptid);
+
+ if (pid == -1)
+ /* Resume all threads. */
+ /* I think this only gets used in the non-threaded case, where "resume
+ all threads" and "resume inferior_ptid" are the same. */
+ pid = PIDGET (inferior_ptid);
+
+ if (step)
+ {
+ /* If this system does not support PT_STEP, a higher level
+ function will have called single_step() to transmute the step
+ request into a continue request (by setting breakpoints on
+ all possible successor instructions), so we don't have to
+ worry about that here. */
+
+ gdb_assert (!SOFTWARE_SINGLE_STEP_P ());
+ request = PT_STEP;
+ }
+
+ /* An address of (PTRACE_TYPE_ARG3)1 tells ptrace to continue from
+ where it was. If GDB wanted it to start some other way, we have
+ already written a new PC value to the child. */
+
+ errno = 0;
+ ptrace (request, pid, (PTRACE_TYPE_ARG3)1, target_signal_to_host (signal));
+ if (errno != 0)
+ perror_with_name (("ptrace"));
+}
+
+static void
hpux_thread_resume (ptid_t ptid, int step, enum target_signal signo)
{
struct cleanup *old_chain;
@@ -190,13 +308,76 @@ hpux_thread_resume (ptid_t ptid, int ste
}
#endif

- deprecated_child_ops.to_resume (ptid, step, signo);
+ hpux_child_resume (ptid, step, signo);

cached_thread = 0;

do_cleanups (old_chain);
}

+/* Wait for child to do something. Return pid of child, or -1 in case
+ of error; store status through argument pointer OURSTATUS. */
+
+static ptid_t
+child_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
+{
+ int save_errno;
+ int status;
+ char *execd_pathname = NULL;
+ int exit_status;
+ int syscall_id;
+ enum target_waitkind kind;
+ int pid;
+
+ do
+ {
+ set_sigint_trap (); /* Causes SIGINT to be passed on to the
+ attached process. */
+ set_sigio_trap ();
+
+ pid = wait (&status);
+
+ save_errno = errno;
+
+ clear_sigio_trap ();
+
+ clear_sigint_trap ();
+
+ if (pid == -1)
+ {
+ if (save_errno == EINTR)
+ continue;
+
+ 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 = TARGET_SIGNAL_UNKNOWN;
+ return pid_to_ptid (-1);
+ }
+
+ /* Did it exit?
+ */
+ if (target_has_exited (pid, status, &exit_status))
+ {
+ /* ??rehrauer: For now, ignore this. */
+ continue;
+ }
+
+ if (!target_thread_alive (pid_to_ptid (pid)))
+ {
+ ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
+ return pid_to_ptid (pid);
+ }
+ } while (pid != PIDGET (inferior_ptid)); /* Some other child died or stopp
+ed */
+
+ store_waitstatus (ourstatus, status);
+ return pid_to_ptid (pid);
+}
+
/* Wait for any threads to stop. We may have to convert PID from a thread id
to a LWP id, and vice versa on the way out. */

@@ -213,7 +394,7 @@ hpux_thread_wait (ptid_t ptid, struct ta
if (!ptid_equal (ptid, minus_one_ptid))
ptid = main_ptid;

- rtnval = deprecated_child_ops.to_wait (ptid, ourstatus);
+ rtnval = child_wait (ptid, ourstatus);

rtnval = find_active_thread ();

@@ -248,6 +429,84 @@ static char regmap[] =
-1, -1, -1, -1, -1, -1, -1, -1, /* fr28 -> fr31 */
};

+#define REGISTER_U_ADDR(addr, blockend, regno) \
+{ addr = (int)(blockend) + regno;}
+
+/* U_REGS_OFFSET is the offset of the registers within the u area. */
+#define U_REGS_OFFSET 0
+
+/* Return the address in the core dump or inferior of register REGNO.
+ BLOCKEND is the address of the end of the user structure. */
+
+static CORE_ADDR
+hpux_register_addr (int regno, CORE_ADDR blockend)
+{
+ int addr;
+
+ if (regno < 0 || regno >= NUM_REGS)
+ error ("Invalid register number %d.", regno);
+
+ REGISTER_U_ADDR (addr, blockend, regno);
+
+ return addr;
+}
+
+/* Fetch register REGNUM from the inferior. */
+
+static void
+fetch_register (int regnum)
+{
+ CORE_ADDR addr;
+ size_t size;
+ PTRACE_TYPE_RET *buf;
+ int tid, i;
+
+ if (CANNOT_FETCH_REGISTER (regnum))
+ {
+ regcache_raw_supply (current_regcache, regnum, NULL);
+ return;
+ }
+
+ /* GNU/Linux LWP ID's are process ID's. */
+ tid = TIDGET (inferior_ptid);
+ if (tid == 0)
+ tid = PIDGET (inferior_ptid); /* Not a threaded program. */
+
+ /* This isn't really an address. But ptrace thinks of it as one. */
+ addr = hpux_register_addr (regnum, U_REGS_OFFSET);
+ size = register_size (current_gdbarch, regnum);
+
+ gdb_assert ((size % sizeof (PTRACE_TYPE_RET)) == 0);
+ buf = alloca (size);
+
+ /* Read the register contents from the inferior a chuck at the time. */
+ for (i = 0; i < size / sizeof (PTRACE_TYPE_RET); i++)
+ {
+ errno = 0;
+ buf[i] = ptrace (PT_READ_U, tid, (PTRACE_TYPE_ARG3) addr, 0);
+ if (errno != 0)
+ error (_("Couldn't read register %s (#%d): %s."),
+ REGISTER_NAME (regnum),
+ regnum, safe_strerror (errno));
+
+ addr += sizeof (PTRACE_TYPE_RET);
+ }
+ regcache_raw_supply (current_regcache, regnum, buf);
+}
+
+/* Fetch register REGNUM from the inferior. If REGNUM is -1, do this
+ for all registers. */
+
+static void
+hpux_fetch_inferior_registers (int regnum)
+{
+ if (regnum == -1)
+ for (regnum = 0; regnum < NUM_REGS; regnum++)
+ fetch_register (regnum);
+ else
+ fetch_register (regnum);
+}
+
static void
hpux_thread_fetch_registers (int regno)
{
@@ -264,7 +523,7 @@ hpux_thread_fetch_registers (int regno)

if (tcb_ptr->state == cma__c_state_running)
{
- deprecated_child_ops.to_fetch_registers (regno);
+ hpux_fetch_inferior_registers (regno);

do_cleanups (old_chain);

@@ -285,7 +544,7 @@ hpux_thread_fetch_registers (int regno)
for (regno = first_regno; regno <= last_regno; regno++)
{
if (regmap[regno] == -1)
- deprecated_child_ops.to_fetch_registers (regno);
+ hpux_fetch_inferior_registers (regno);
else
{
unsigned char buf[MAX_REGISTER_SIZE];
@@ -310,6 +569,58 @@ hpux_thread_fetch_registers (int regno)
do_cleanups (old_chain);
}

+/* Store register REGNUM into the inferior. */
+
+static void
+store_register (int regnum)
+{
+ CORE_ADDR addr;
+ size_t size;
+ PTRACE_TYPE_RET *buf;
+ int tid, i;
+
+ if (CANNOT_STORE_REGISTER (regnum))
+ return;
+
+ /* GNU/Linux LWP ID's are process ID's. */
+ tid = TIDGET (inferior_ptid);
+ if (tid == 0)
+ tid = PIDGET (inferior_ptid); /* Not a threaded program. */
+
+ /* This isn't really an address. But ptrace thinks of it as one. */
+ addr = hpux_register_addr (regnum, U_REGS_OFFSET);
+ size = register_size (current_gdbarch, regnum);
+
+ gdb_assert ((size % sizeof (PTRACE_TYPE_RET)) == 0);
+ buf = alloca (size);
+
+ /* Write the register contents into the inferior a chunk at the time. */
+ regcache_raw_collect (current_regcache, regnum, buf);
+ for (i = 0; i < size / sizeof (PTRACE_TYPE_RET); i++)
+ {
+ errno = 0;
+ ptrace (PT_WRITE_U, tid, (PTRACE_TYPE_ARG3) addr, buf[i]);
+ if (errno != 0)
+ error (_("Couldn't write register %s (#%d): %s."),
+ REGISTER_NAME (regnum), regnum, safe_strerror (errno));
+
+ addr += sizeof (PTRACE_TYPE_RET);
+ }
+}
+
+/* Store register REGNUM back into the inferior. If REGNUM is -1, do
+ this for all registers (including the floating point registers). */
+
+static void
+hpux_store_inferior_registers (int regnum)
+{
+ if (regnum == -1)
+ for (regnum = 0; regnum < NUM_REGS; regnum++)
+ store_register (regnum);
+ else
+ store_register (regnum);
+}
+
static void
hpux_thread_store_registers (int regno)
{
@@ -326,7 +637,7 @@ hpux_thread_store_registers (int regno)

if (tcb_ptr->state == cma__c_state_running)
{
- deprecated_child_ops.to_store_registers (regno);
+ hpux_store_inferior_registers (regno);

do_cleanups (old_chain);

@@ -347,7 +658,7 @@ hpux_thread_store_registers (int regno)
for (regno = first_regno; regno <= last_regno; regno++)
{
if (regmap[regno] == -1)
- deprecated_child_ops.to_store_registers (regno);
+ hpux_store_inferior_registers (regno);
else
{
unsigned char buf[MAX_REGISTER_SIZE];
@@ -356,7 +667,7 @@ hpux_thread_store_registers (int regno)
sp = (CORE_ADDR) tcb_ptr->static_ctx.sp - 160;

if (regno == HPPA_FLAGS_REGNUM)
- deprecated_child_ops.to_store_registers (regno); /* Let lower layer handle this... */
+ hpux_store_inferior_registers (regno);
else if (regno == HPPA_SP_REGNUM)
{
regcache_raw_read (current_regcache, regno, buf);
@@ -392,11 +703,148 @@ hpux_thread_store_registers (int regno)
static void
hpux_thread_prepare_to_store (void)
{
- deprecated_child_ops.to_prepare_to_store ();
+#ifdef CHILD_PREPARE_TO_STORE
+ CHILD_PREPARE_TO_STORE ();
+#endif
}

+/* Set an upper limit on alloca. */
+#ifndef GDB_MAX_ALLOCA
+#define GDB_MAX_ALLOCA 0x1000
+#endif
+
+/* Copy LEN bytes to or from inferior's memory starting at MEMADDR to
+ debugger memory starting at MYADDR. Copy to inferior if WRITE is
+ nonzero. TARGET is ignored.
+
+ Returns the length copied, which is either the LEN argument or
+ zero. This xfer function does not do partial moves, since
+ deprecated_child_ops doesn't allow memory operations to cross below
+ us in the target stack anyway. */
+
static int
-hpux_thread_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len,
+hpux_child_xfer_memory (CORE_ADDR memaddr, gdb_byte *myaddr, int len, int write,
+ struct mem_attrib *attrib, struct target_ops *target)
+{
+ int i;
+ /* Round starting address down to longword boundary. */
+ CORE_ADDR addr = memaddr & -(CORE_ADDR) sizeof (PTRACE_TYPE_RET);
+ /* Round ending address up; get number of longwords that makes. */
+ int count = ((((memaddr + len) - addr) + sizeof (PTRACE_TYPE_RET) - 1)
+ / sizeof (PTRACE_TYPE_RET));
+ int alloc = count * sizeof (PTRACE_TYPE_RET);
+ PTRACE_TYPE_RET *buffer;
+ struct cleanup *old_chain = NULL;
+
+#ifdef PT_IO
+ /* OpenBSD 3.1, NetBSD 1.6 and FreeBSD 5.0 have a new PT_IO request
+ that promises to be much more efficient in reading and writing
+ data in the traced process's address space. */
+
+ {
+ struct ptrace_io_desc piod;
+
+ /* NOTE: We assume that there are no distinct address spaces for
+ instruction and data. */
+ piod.piod_op = write ? PIOD_WRITE_D : PIOD_READ_D;
+ piod.piod_offs = (void *) memaddr;
+ piod.piod_addr = myaddr;
+ piod.piod_len = len;
+
+ if (ptrace (PT_IO, PIDGET (inferior_ptid), (caddr_t) &piod, 0) == -1)
+ {
+ /* If the PT_IO request is somehow not supported, fallback on
+ using PT_WRITE_D/PT_READ_D. Otherwise we will return zero
+ to indicate failure. */
+ if (errno != EINVAL)
+ return 0;
+ }
+ else
+ {
+ /* Return the actual number of bytes read or written. */
+ return piod.piod_len;
+ }
+ }
+#endif
+
+ /* Allocate buffer of that many longwords. */
+ if (len < GDB_MAX_ALLOCA)
+ {
+ buffer = (PTRACE_TYPE_RET *) alloca (alloc);
+ }
+ else
+ {
+ buffer = (PTRACE_TYPE_RET *) xmalloc (alloc);
+ old_chain = make_cleanup (xfree, buffer);
+ }
+
+ if (write)
+ {
+ /* Fill start and end extra bytes of buffer with existing memory
+ data. */
+ if (addr != memaddr || len < (int) sizeof (PTRACE_TYPE_RET))
+ {
+ /* Need part of initial word -- fetch it. */
+ buffer[0] = ptrace (PT_READ_I, PIDGET (inferior_ptid),
+ (PTRACE_TYPE_ARG3) addr, 0);
+ }
+
+ if (count > 1) /* FIXME, avoid if even boundary. */
+ {
+ buffer[count - 1] =
+ ptrace (PT_READ_I, PIDGET (inferior_ptid),
+ ((PTRACE_TYPE_ARG3)
+ (addr + (count - 1) * sizeof (PTRACE_TYPE_RET))), 0);
+ }
+
+ /* Copy data to be written over corresponding part of buffer. */
+ memcpy ((char *) buffer + (memaddr & (sizeof (PTRACE_TYPE_RET) - 1)),
+ myaddr, len);
+
+ /* Write the entire buffer. */
+ for (i = 0; i < count; i++, addr += sizeof (PTRACE_TYPE_RET))
+ {
+ errno = 0;
+ ptrace (PT_WRITE_D, PIDGET (inferior_ptid),
+ (PTRACE_TYPE_ARG3) addr, buffer[i]);
+ if (errno)
+ {
+ /* Using the appropriate one (I or D) is necessary for
+ Gould NP1, at least. */
+ errno = 0;
+ ptrace (PT_WRITE_I, PIDGET (inferior_ptid),
+ (PTRACE_TYPE_ARG3) addr, buffer[i]);
+ }
+ if (errno)
+ return 0;
+ }
+ }
+ else
+ {
+ /* Read all the longwords. */
+ for (i = 0; i < count; i++, addr += sizeof (PTRACE_TYPE_RET))
+ {
+ errno = 0;
+ buffer[i] = ptrace (PT_READ_I, PIDGET (inferior_ptid),
+ (PTRACE_TYPE_ARG3) addr, 0);
+ if (errno)
+ return 0;
+ QUIT;
+ }
+
+ /* Copy appropriate bytes out of the buffer. */
+ memcpy (myaddr,
+ (char *) buffer + (memaddr & (sizeof (PTRACE_TYPE_RET) - 1)),
+ len);
+ }
+
+ if (old_chain != NULL)
+ do_cleanups (old_chain);
+ return len;
+}
+
+static int
+hpux_thread_xfer_memory (CORE_ADDR memaddr, gdb_byte *myaddr, int len,
int dowrite, struct mem_attrib *attribs,
struct target_ops *target)
{
@@ -408,7 +856,7 @@ hpux_thread_xfer_memory (CORE_ADDR memad
inferior_ptid = main_ptid;

retval =
- deprecated_child_ops.deprecated_xfer_memory (memaddr, myaddr, len, dowrite, attribs, target);
+ hpux_child_xfer_memory (memaddr, myaddr, len, dowrite, attribs, target);

do_cleanups (old_chain);

@@ -420,13 +868,40 @@ hpux_thread_xfer_memory (CORE_ADDR memad
static void
hpux_thread_files_info (struct target_ops *ignore)
{
- deprecated_child_ops.to_files_info (ignore);
+ printf_unfiltered (_("\tUsing the running image of %s %s.\n"),
+ attach_flag ? "attached" : "child", target_pid_to_str (inferior_ptid));
+}
+
+/* NOTE: cagney/2004-09-12: Instead of definining this macro, code
+ should call inf_ptrace_target to get a basic ptrace target and then
+ locally update any necessary methods. See ppcnbsd-nat.c. */
+
+static void
+hpux_kill_inferior (void)
+{
+ int status;
+ int pid = PIDGET (inferior_ptid);
+
+ if (pid == 0)
+ return;
+
+ /* This once used to call "kill" to kill the inferior just in case
+ the inferior was still running. As others have noted in the past
+ (kingdon) there shouldn't be any way to get here if the inferior
+ is still running -- else there's a major problem elsewere in gdb
+ and it needs to be fixed.
+
+ The kill call causes problems under hpux10, so it's been removed;
+ if this causes problems we'll deal with them as they arise. */
+ ptrace (PT_KILL, pid, (PTRACE_TYPE_ARG3) 0, 0);
+ wait (&status);
+ target_mourn_inferior ();
}

static void
hpux_thread_kill_inferior (void)
{
- deprecated_child_ops.to_kill ();
+ hpux_kill_inferior ();
}

static void
@@ -435,13 +910,63 @@ hpux_thread_notice_signals (ptid_t ptid)
deprecated_child_ops.to_notice_signals (ptid);
}

+/* Stub function which causes the inferior that runs it, to be ptrace-able
+ by its parent process. */
+
+static void
+ptrace_me (void)
+{
+ /* "Trace me, Dr. Memory!" */
+ ptrace (0, 0, (PTRACE_TYPE_ARG3) 0, 0);
+}
+
+/* Stub function which causes the GDB that runs it, to start ptrace-ing
+ the child process. */
+
+static void
+ptrace_him (int pid)
+{
+ push_target (&deprecated_child_ops);
+
+ /* On some targets, there must be some explicit synchronization
+ between the parent and child processes after the debugger
+ forks, and before the child execs the debuggee program. This
+ call basically gives permission for the child to exec.
+ */
+
+ target_acknowledge_created_inferior (pid);
+
+ /* START_INFERIOR_TRAPS_EXPECTED is defined in inferior.h,
+ * and will be 1 or 2 depending on whether we're starting
+ * without or with a shell.
+ */
+ startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
+
+ /* On some targets, there must be some explicit actions taken after
+ the inferior has been started up.
+ */
+ target_post_startup_inferior (pid_to_ptid (pid));
+}
+
+/* Start an inferior Unix child process and sets inferior_ptid to its pid.
+ EXEC_FILE is the file to run.
+ ALLARGS is a string containing the arguments to the program.
+ ENV is the environment vector to pass. Errors reported with error(). */
+
+static void
+child_create_inferior (char *exec_file, char *allargs, char **env,
+ int from_tty)
+{
+ fork_inferior (exec_file, allargs, env, ptrace_me, ptrace_him, NULL, NULL);
+}
+
/* Fork an inferior process, and start debugging it with /proc. */

static void
hpux_thread_create_inferior (char *exec_file, char *allargs, char **env,
int from_tty)
{
- deprecated_child_ops.to_create_inferior (exec_file, allargs, env, from_tty);
+ child_create_inferior (exec_file, allargs, env, from_tty);

if (hpux_thread_active)
{
@@ -505,7 +1030,8 @@ quit:
static void
hpux_thread_mourn_inferior (void)
{
- deprecated_child_ops.to_mourn_inferior ();
+ unpush_target (&hpux_thread_ops);
+ generic_mourn_inferior ();
}

/* Mark our target-struct as eligible for stray "run" and "attach" commands. */
@@ -522,10 +1048,22 @@ hpux_thread_alive (ptid_t ptid)
return 1;
}

+/* Send a SIGINT to the process group. This acts just like the user typed a
+ ^C on the controlling terminal.
+
+ XXX - This may not be correct for all systems. Some may want to use
+ killpg() instead of kill (-pgrp). */
+
+static void
+child_stop (void)
+{
+ kill (-inferior_process_group, SIGINT);
+}
+
static void
hpux_thread_stop (void)
{
- deprecated_child_ops.to_stop ();
+ child_stop ();
}
\f
/* Convert a pid to printable form. */