/* Low level Unix child interface to ptrace, for GDB when running under Unix.
- Copyright 1988, 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
This file is part of GDB.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "defs.h"
#include "frame.h"
#include "inferior.h"
#include "target.h"
+#include "gdb_string.h"
+#include "wait.h"
+#include "command.h"
#ifdef USG
#include <sys/types.h>
#endif
#endif /* NO_PTRACE_H */
-#if !defined (PT_KILL)
-#define PT_KILL 8
+#if !defined (PT_READ_I)
+#define PT_READ_I 1 /* Read word from text space */
+#endif
+#if !defined (PT_READ_D)
+#define PT_READ_D 2 /* Read word from data space */
+#endif
+#if !defined (PT_READ_U)
+#define PT_READ_U 3 /* Read word from kernel user struct */
+#endif
+#if !defined (PT_WRITE_I)
+#define PT_WRITE_I 4 /* Write word to text space */
+#endif
+#if !defined (PT_WRITE_D)
+#define PT_WRITE_D 5 /* Write word to data space */
+#endif
+#if !defined (PT_WRITE_U)
+#define PT_WRITE_U 6 /* Write word to kernel user struct */
+#endif
+#if !defined (PT_CONTINUE)
+#define PT_CONTINUE 7 /* Continue after signal */
#endif
-
#if !defined (PT_STEP)
-#define PT_STEP 9
-#define PT_CONTINUE 7
-#define PT_READ_U 3
-#define PT_WRITE_U 6
-#define PT_READ_I 1
-#define PT_READ_D 2
-#define PT_WRITE_I 4
-#define PT_WRITE_D 5
-#endif /* No PT_STEP. */
+#define PT_STEP 9 /* Set flag for single stepping */
+#endif
+#if !defined (PT_KILL)
+#define PT_KILL 8 /* Send child a SIGKILL signal */
+#endif
#ifndef PT_ATTACH
#define PT_ATTACH PTRACE_ATTACH
/* Don't think this is used anymore. On the sequent (not sure whether it's
dynix or ptx or both), it is included unconditionally by sys/user.h and
not protected against multiple inclusion. */
-#include <sys/stat.h>
+#include "gdb_stat.h"
#endif
#if !defined (FETCH_INFERIOR_REGISTERS)
#endif /* KERNEL_U_ADDR_BSD. */
#endif /* !FETCH_INFERIOR_REGISTERS */
+#if !defined (CHILD_XFER_MEMORY)
+static void udot_info PARAMS ((char *, int));
+#endif
+
+#if !defined (FETCH_INFERIOR_REGISTERS)
+static void fetch_register PARAMS ((int));
+static void store_register PARAMS ((int));
+#endif
+
\f
/* This function simply calls ptrace with the given arguments.
It exists so that all calls to ptrace are isolated in this
{
if (inferior_pid == 0)
return;
- /* ptrace PT_KILL only works if process is stopped!!! So stop it with
- a real signal first, if we can. */
- kill (inferior_pid, SIGKILL);
+
+ /* 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, inferior_pid, (PTRACE_ARG3_TYPE) 0, 0);
wait ((int *)0);
target_mourn_inferior ();
}
+#ifndef CHILD_RESUME
+
/* Resume execution of the inferior process.
If STEP is nonzero, single-step it.
If SIGNAL is nonzero, give it that signal. */
child_resume (pid, step, signal)
int pid;
int step;
- int signal;
+ enum target_signal signal;
{
errno = 0;
if (pid == -1)
-#ifdef PIDGET /* XXX Lynx */
- pid = PIDGET (inferior_pid);
-#else
+ /* Resume all threads. */
+ /* I think this only gets used in the non-threaded case, where "resume
+ all threads" and "resume inferior_pid" are the same. */
pid = inferior_pid;
-#endif
/* An address of (PTRACE_ARG3_TYPE)1 tells ptrace to continue from where
it was. (If GDB wanted it to start some other way, we have already
instructions), so we don't have to worry about that here. */
if (step)
- ptrace (PT_STEP, pid, (PTRACE_ARG3_TYPE) 1, signal);
+ {
+#ifdef NO_SINGLE_STEP
+ abort(); /* Make sure this doesn't happen. */
+#else
+ ptrace (PT_STEP, pid, (PTRACE_ARG3_TYPE) 1,
+ target_signal_to_host (signal));
+#endif /* NO_SINGLE_STEP */
+ }
else
- ptrace (PT_CONTINUE, pid, (PTRACE_ARG3_TYPE) 1, signal);
+ ptrace (PT_CONTINUE, pid, (PTRACE_ARG3_TYPE) 1,
+ target_signal_to_host (signal));
if (errno)
perror_with_name ("ptrace");
}
+#endif /* CHILD_RESUME */
+
\f
#ifdef ATTACH_DETACH
/* Start debugging the process whose number is PID. */
fetch_register (regno)
int regno;
{
- register unsigned int regaddr;
- char buf[MAX_REGISTER_RAW_SIZE];
+ /* This isn't really an address. But ptrace thinks of it as one. */
+ CORE_ADDR regaddr;
char mess[128]; /* For messages */
register int i;
-
- /* Offset of registers within the u area. */
- unsigned int offset;
+ unsigned int offset; /* Offset of registers within the u area. */
+ char buf[MAX_REGISTER_RAW_SIZE];
if (CANNOT_FETCH_REGISTER (regno))
{
}
-/* Fetch all registers, or just one, from the child process. */
+/* Fetch register values from the inferior.
+ If REGNO is negative, do this for all registers.
+ Otherwise, REGNO specifies which register (so we can save time). */
void
fetch_inferior_registers (regno)
int regno;
{
- if (regno == -1)
- for (regno = 0; regno < NUM_REGS; regno++)
+ if (regno >= 0)
+ {
fetch_register (regno);
+ }
else
- fetch_register (regno);
+ {
+ for (regno = 0; regno < ARCH_NUM_REGS; regno++)
+ {
+ fetch_register (regno);
+ }
+ }
}
/* Registers we shouldn't try to store. */
#define CANNOT_STORE_REGISTER(regno) 0
#endif
-/* Store our register values back into the inferior.
- If REGNO is -1, do this for all registers.
- Otherwise, REGNO specifies which register (so we can save time). */
+/* Store one register. */
-void
-store_inferior_registers (regno)
+static void
+store_register (regno)
int regno;
{
- register unsigned int regaddr;
- char buf[80];
+ /* This isn't really an address. But ptrace thinks of it as one. */
+ CORE_ADDR regaddr;
+ char mess[128]; /* For messages */
register int i;
+ unsigned int offset; /* Offset of registers within the u area. */
+
+ if (CANNOT_STORE_REGISTER (regno))
+ {
+ return;
+ }
- unsigned int offset = U_REGS_OFFSET;
+ offset = U_REGS_OFFSET;
- if (regno >= 0)
+ regaddr = register_addr (regno, offset);
+ for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof(PTRACE_XFER_TYPE))
{
- regaddr = register_addr (regno, offset);
- for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof(PTRACE_XFER_TYPE))
+ errno = 0;
+ ptrace (PT_WRITE_U, inferior_pid, (PTRACE_ARG3_TYPE) regaddr,
+ *(PTRACE_XFER_TYPE *) ®isters[REGISTER_BYTE (regno) + i]);
+ regaddr += sizeof (PTRACE_XFER_TYPE);
+ if (errno != 0)
{
- errno = 0;
- ptrace (PT_WRITE_U, inferior_pid, (PTRACE_ARG3_TYPE) regaddr,
- *(PTRACE_XFER_TYPE *) ®isters[REGISTER_BYTE (regno) + i]);
- if (errno != 0)
- {
- sprintf (buf, "writing register number %d(%d)", regno, i);
- perror_with_name (buf);
- }
- regaddr += sizeof(PTRACE_XFER_TYPE);
+ sprintf (mess, "writing register %s (#%d)", reg_names[regno], regno);
+ perror_with_name (mess);
}
}
+}
+
+/* Store our register values back into the inferior.
+ If REGNO is negative, do this for all registers.
+ Otherwise, REGNO specifies which register (so we can save time). */
+
+void
+store_inferior_registers (regno)
+ int regno;
+{
+ if (regno >= 0)
+ {
+ store_register (regno);
+ }
else
{
- for (regno = 0; regno < NUM_REGS; regno++)
+ for (regno = 0; regno < ARCH_NUM_REGS; regno++)
{
- if (CANNOT_STORE_REGISTER (regno))
- continue;
- regaddr = register_addr (regno, offset);
- for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof(PTRACE_XFER_TYPE))
- {
- errno = 0;
- ptrace (PT_WRITE_U, inferior_pid, (PTRACE_ARG3_TYPE) regaddr,
- *(PTRACE_XFER_TYPE *) ®isters[REGISTER_BYTE (regno) + i]);
- if (errno != 0)
- {
- sprintf (buf, "writing register number %d(%d)", regno, i);
- perror_with_name (buf);
- }
- regaddr += sizeof(PTRACE_XFER_TYPE);
- }
+ store_register (regno);
}
}
}
#endif /* !defined (FETCH_INFERIOR_REGISTERS). */
\f
+
+#if !defined (CHILD_XFER_MEMORY)
/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory
in the NEW_SUN_PTRACE case.
It ought to be straightforward. But it appears that writing did
}
return len;
}
+
+\f
+static void
+udot_info (dummy1, dummy2)
+ char *dummy1;
+ int dummy2;
+{
+#if defined (KERNEL_U_SIZE)
+ int udot_off; /* Offset into user struct */
+ int udot_val; /* Value from user struct at udot_off */
+ char mess[128]; /* For messages */
+#endif
+
+ if (!target_has_execution)
+ {
+ error ("The program is not being run.");
+ }
+
+#if !defined (KERNEL_U_SIZE)
+
+ /* Adding support for this command is easy. Typically you just add a
+ routine, called "kernel_u_size" that returns the size of the user
+ struct, to the appropriate *-nat.c file and then add to the native
+ config file "#define KERNEL_U_SIZE kernel_u_size()" */
+ error ("Don't know how large ``struct user'' is in this version of gdb.");
+
+#else
+
+ for (udot_off = 0; udot_off < KERNEL_U_SIZE; udot_off += sizeof (udot_val))
+ {
+ if ((udot_off % 24) == 0)
+ {
+ if (udot_off > 0)
+ {
+ printf_filtered ("\n");
+ }
+ printf_filtered ("%04x:", udot_off);
+ }
+ udot_val = ptrace (PT_READ_U, inferior_pid, (PTRACE_ARG3_TYPE) udot_off, 0);
+ if (errno != 0)
+ {
+ sprintf (mess, "\nreading user struct at offset 0x%x", udot_off);
+ perror_with_name (mess);
+ }
+ /* Avoid using nonportable (?) "*" in print specs */
+ printf_filtered (sizeof (int) == 4 ? " 0x%08x" : " 0x%16x", udot_val);
+ }
+ printf_filtered ("\n");
+
+#endif
+}
+#endif /* !defined (CHILD_XFER_MEMORY). */
+
+\f
+void
+_initialize_infptrace ()
+{
+#if !defined (CHILD_XFER_MEMORY)
+ add_info ("udot", udot_info,
+ "Print contents of kernel ``struct user'' for current child.");
+#endif
+}