From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 5557 invoked by alias); 1 Jan 2007 16:47:52 -0000 Received: (qmail 5549 invoked by uid 22791); 1 Jan 2007 16:47:51 -0000 X-Spam-Check-By: sourceware.org Received: from hiauly1.hia.nrc.ca (HELO hiauly1.hia.nrc.ca) (132.246.100.193) by sourceware.org (qpsmtpd/0.31) with ESMTP; Mon, 01 Jan 2007 16:47:46 +0000 Received: from hiauly1.hia.nrc.ca (hiauly1.hia.nrc.ca [127.0.0.1] (may be forged)) by hiauly1.hia.nrc.ca (8.13.7/8.13.7) with ESMTP id l01Gko4H026701; Mon, 1 Jan 2007 11:46:51 -0500 (EST) Received: (from dave@localhost) by hiauly1.hia.nrc.ca (8.13.7/8.13.7/Submit) id l01GkoxX026700; Mon, 1 Jan 2007 11:46:50 -0500 (EST) Message-Id: <200701011646.l01GkoxX026700@hiauly1.hia.nrc.ca> Subject: Re: Likely obsolete pieces of GDB To: drow@false.org (Daniel Jacobowitz) Date: Mon, 01 Jan 2007 16:47:00 -0000 From: "John David Anglin" Cc: gdb@sourceware.org, dave.anglin@nrc-cnrc.gc.ca, brobecker@adacore.com, kettenis@gnu.org In-Reply-To: <20070101163255.GA13802@nevyn.them.org> from "Daniel Jacobowitz" at Jan 1, 2007 11:32:55 am X-Mailer: ELM [version 2.4 PL25] MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Mailing-List: contact gdb-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-owner@sourceware.org X-SW-Source: 2007-01/txt/msg00003.txt.bz2 > > 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 #include "gdbthread.h" #include "target.h" +#include "command.h" #include "inferior.h" #include "regcache.h" #include @@ -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 (); } /* Convert a pid to printable form. */