This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[COMMIT] Add "traditional" ptrace support to inf-ptrace.c


When Andrew introduced inf-ptrace.c, he didn't add
PT_READ_U/PT_WRITE_U register support, because that was a huge mess of
macro's and weird functions.  The patch below adds back a much more
cleaner implementation.  In a few minutes I'll commit some code to
make vax-dec-ultrix use this, but it is also necessary for
ia64-unknown-linux-gnu, and might benefit other targets too.

Mark


Index: ChangeLog
from  Mark Kettenis  <kettenis@gnu.org>

	* inf-ptrace.h: Update copyright year.  Sync comment with
	inf-ptrace.c.
	(inf_ptrace_trad_target): New prototype.
	* inf-ptrace.c: Update copyright year.  Include "regcache.h" and
	"gdb_assert.h"
	(inf_ptrace_target): Add comment.
	(inf_ptrace+register_u_offset): New variable.
	(inf_ptrace_fetch_register, inf_ptrace_fetch_registers)
	(inf_ptrace_store_register, inf_ptrace_store_registers)
	(inf_ptrace_trad_target): New functions.
	* Makefile.in (inf-ptrace.o): Update dependencies.

Index: Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.683
diff -u -p -r1.683 Makefile.in
--- Makefile.in 5 Jan 2005 22:51:46 -0000 1.683
+++ Makefile.in 10 Jan 2005 20:32:59 -0000
@@ -2079,8 +2079,8 @@ inflow.o: inflow.c $(defs_h) $(frame_h) 
 	$(serial_h) $(terminal_h) $(target_h) $(gdbthread_h) $(gdb_string_h) \
 	$(inflow_h)
 inf-ptrace.o: inf-ptrace.c $(defs_h) $(command_h) $(inferior_h) $(inflow_h) \
-	$(gdbcore_h) $(observer_h) $(gdb_string_h) $(gdb_ptrace_h) \
-	$(gdb_wait_h) $(inf_child_h)
+	$(gdbcore_h) $(observer_h) $(regcache_h) $(gdb_assert_h) \
+	$(gdb_string_h) $(gdb_ptrace_h) $(gdb_wait_h) $(inf_child_h)
 inf-ttrace.o: inf-ttrace.c $(defs_h) $(command_h) $(gdbcore_h) \
 	$(gdbthread_h) $(inferior_h) $(observer_h) $(target_h) \
 	$(gdb_assert_h) $(gdb_string_h) $(inf_child_h) $(inf_ttrace_h)
Index: inf-ptrace.c
===================================================================
RCS file: /cvs/src/src/gdb/inf-ptrace.c,v
retrieving revision 1.14
diff -u -p -r1.14 inf-ptrace.c
--- inf-ptrace.c 21 Nov 2004 13:51:53 -0000 1.14
+++ inf-ptrace.c 10 Jan 2005 20:33:00 -0000
@@ -1,7 +1,8 @@
 /* Low-level child interface to ptrace.
 
    Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
-   1998, 1999, 2000, 2001, 2002, 2004 Free Software Foundation, Inc.
+   1998, 1999, 2000, 2001, 2002, 2004, 2005
+   Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -26,7 +27,9 @@
 #include "inflow.h"
 #include "gdbcore.h"
 #include "observer.h"
+#include "regcache.h"
 
+#include "gdb_assert.h"
 #include "gdb_string.h"
 #include "gdb_ptrace.h"
 #include "gdb_wait.h"
@@ -592,10 +595,14 @@ inf_ptrace_pid_to_str (ptid_t ptid)
   return normal_pid_to_str (ptid);
 }
 
+/* Create a prototype ptrace target.  The client can override it with
+   local methods.  */
+
 struct target_ops *
 inf_ptrace_target (void)
 {
   struct target_ops *t = inf_child_target ();
+
   t->to_open = inf_ptrace_open;
   t->to_attach = inf_ptrace_attach;
   t->to_post_attach = inf_ptrace_post_attach;
@@ -633,5 +640,128 @@ inf_ptrace_target (void)
   t->to_has_execution = 1;
   t->to_magic = OPS_MAGIC;
   ptrace_ops_hack = t;
+
+  return t;
+}
+
+
+/* Pointer to a function that returns the oggset within the user area
+   where a particular register is stored.  */
+static CORE_ADDR (*inf_ptrace_register_u_offset)(int);
+
+/* Fetch register REGNUM from the inferior.  */
+
+static void
+inf_ptrace_fetch_register (int regnum)
+{
+  CORE_ADDR addr;
+  size_t size;
+  PTRACE_TYPE_RET *buf;
+  int pid, i;
+
+  /* Cater for systems like GNU/Linux, that implement threads as
+     seperate processes.  */
+  pid = ptid_get_lwp (inferior_ptid);
+  if (pid == 0)
+    pid = ptid_get_pid (inferior_ptid);
+
+  /* This isn't really an address, but ptrace thinks of it as one.  */
+  addr = inf_ptrace_register_u_offset (regnum);
+  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, pid, (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
+inf_ptrace_fetch_registers (int regnum)
+{
+  if (regnum == -1)
+    for (regnum = 0; regnum < NUM_REGS; regnum++)
+      inf_ptrace_fetch_register (regnum);
+  else
+    inf_ptrace_fetch_register (regnum);
+}
+
+/* Store register REGNUM into the inferior.  */
+
+static void
+inf_ptrace_store_register (int regnum)
+{
+  CORE_ADDR addr;
+  size_t size;
+  PTRACE_TYPE_RET *buf;
+  int pid, i;
+
+  /* Cater for systems like GNU/Linux, that implement threads as
+     seperate processes.  */
+  pid = ptid_get_lwp (inferior_ptid);
+  if (pid == 0)
+    pid = ptid_get_pid (inferior_ptid);
+
+  /* This isn't really an address, but ptrace thinks of it as one.  */
+  addr = inf_ptrace_register_u_offset (regnum);
+  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, pid, (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.  */
+
+void
+inf_ptrace_store_registers (int regnum)
+{
+  if (regnum == -1)
+    for (regnum = 0; regnum < NUM_REGS; regnum++)
+      inf_ptrace_store_register (regnum);
+  else
+    inf_ptrace_store_register (regnum);
+}
+
+/* Create a "traditional" ptrace target.  REGISTER_U_OFFSET should be
+   a function returning the offset within the user area where a
+   particular register is stored.  */
+
+struct target_ops *
+inf_ptrace_trad_target (CORE_ADDR (*register_u_offset)(int))
+{
+  struct target_ops *t = inf_ptrace_target();
+
+  gdb_assert (register_u_offset);
+  inf_ptrace_register_u_offset = register_u_offset;
+  t->to_fetch_registers = inf_ptrace_fetch_registers;
+  t->to_store_registers = inf_ptrace_store_registers;
+
   return t;
 }
Index: inf-ptrace.h
===================================================================
RCS file: /cvs/src/src/gdb/inf-ptrace.h,v
retrieving revision 1.1
diff -u -p -r1.1 inf-ptrace.h
--- inf-ptrace.h 12 Sep 2004 13:04:40 -0000 1.1
+++ inf-ptrace.h 10 Jan 2005 20:33:00 -0000
@@ -1,7 +1,6 @@
-/* Low level Unix child interface to ptrace, for GDB when running
-   under Unix.
+/* Low level child interface to ptrace.
 
-   Copyright 2004 Free Software Foundation, Inc.
+   Copyright 2004, 2005 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -28,4 +27,11 @@
 
 extern struct target_ops *inf_ptrace_target (void);
 
+/* Create a "traditional" ptrace target.  REGISTER_U_OFFSET should be
+   a function returning the offset within the user area where a
+   particular register is stored.  */
+
+extern struct target_ops *
+  inf_ptrace_trad_target (CORE_ADDR (*register_u_offset)(int));
+
 #endif


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]