* inf-ttrace.c: New file.
authorMark Kettenis <kettenis@gnu.org>
Tue, 23 Nov 2004 21:14:33 +0000 (21:14 +0000)
committerMark Kettenis <kettenis@gnu.org>
Tue, 23 Nov 2004 21:14:33 +0000 (21:14 +0000)
* inf-ttrace.h: New file.
* hppa-hpux-nat.c [HAVE_TTRACE]: Include <sys/ttrace>.
Include "inf-ttrace.h".
(ss_mpsfu_high): Define to ss_tlsp if necessary.
(hppa_hpux_fetch_register, hppa_hpux_store_register): Use
ptid_get_pid instead of PIDGET.  Modify to handle both ttrace and
ptrace systems.
(_initialize_hppa_hpux_nat) [HAVE_TTRACE]: Call inf_ttrace_traget
instead of inf_ptrace_target.
* config/pa/hpux.mh (NATDEPFILES): Add inf-ttrace.o.
* Makefile.in (inf_ttrace_h): New variable.
(hppa-hpux-nat.o): Update dependency.
(inf-ttrace.o): New dependency.
(ALLDEPFILES): Add inf-ptrace.c and inf-ttrace.c.

gdb/ChangeLog
gdb/Makefile.in
gdb/config/pa/hpux.mh
gdb/hppa-hpux-nat.c
gdb/inf-ttrace.c [new file with mode: 0644]
gdb/inf-ttrace.h [new file with mode: 0644]

index 83ecf1abbac0de7cf3a68c2853282a81d4faf65f..fcdbd92da264da62154f4be0446dccf4e9535f7f 100644 (file)
@@ -1,3 +1,21 @@
+2004-11-23  Mark Kettenis  <kettenis@gnu.org>
+
+       * inf-ttrace.c: New file.
+       * inf-ttrace.h: New file.
+       * hppa-hpux-nat.c [HAVE_TTRACE]: Include <sys/ttrace>.
+       Include "inf-ttrace.h".
+       (ss_mpsfu_high): Define to ss_tlsp if necessary.
+       (hppa_hpux_fetch_register, hppa_hpux_store_register): Use
+       ptid_get_pid instead of PIDGET.  Modify to handle both ttrace and
+       ptrace systems.
+       (_initialize_hppa_hpux_nat) [HAVE_TTRACE]: Call inf_ttrace_traget
+       instead of inf_ptrace_target.
+       * config/pa/hpux.mh (NATDEPFILES): Add inf-ttrace.o.
+       * Makefile.in (inf_ttrace_h): New variable.
+       (hppa-hpux-nat.o): Update dependency.
+       (inf-ttrace.o): New dependency.
+       (ALLDEPFILES): Add inf-ptrace.c and inf-ttrace.c.
+
 2004-11-23  Randolph Chung  <tausq@debian.org>
 
        * arch-utils.c (generic_instruction_nullified): New.
index 5173f06bd47ac874e9d8772c6802cd39e9fb68d8..ddac59950d5cb98275671251de1ad9a0cd255a80 100644 (file)
@@ -712,6 +712,7 @@ inf_loop_h = inf-loop.h
 inflow_h = inflow.h $(terminal_h)
 inf_ptrace_h = inf-ptrace.h
 infttrace_h = infttrace.h
+inf_ttrace_h = inf-ttrace.h
 interps_h = interps.h
 jv_lang_h = jv-lang.h
 kod_h = kod.h
@@ -1383,6 +1384,7 @@ ALLDEPFILES = \
        i386-sol2-nat.c i386-sol2-tdep.c \
        i386gnu-nat.c i386gnu-tdep.c \
        ia64-linux-nat.c ia64-linux-tdep.c ia64-tdep.c \
+       inf-ptrace.c inf-ttrace.c \
        infptrace.c inftarg.c irix4-nat.c irix5-nat.c \
        libunwind-frame.c \
        lynx-nat.c m3-nat.c \
@@ -1970,7 +1972,8 @@ hppah-nat.o: hppah-nat.c $(defs_h) $(inferior_h) $(target_h) $(gdbcore_h) \
        $(gdb_wait_h) $(regcache_h) $(gdb_string_h) $(infttrace_h) \
        $(hppa_tdep_h)
 hppa-hpux-nat.o: hppa-hpux-nat.c $(defs_h) $(inferior_h) $(regcache_h) \
-       $(target_h) $(gdb_assert_h) $(hppa_tdep_h) $(inf_ptrace_h)
+       $(target_h) $(gdb_assert_h) $(hppa_tdep_h) $(inf_ptrace_h) \
+       $(inf_ttrace_h)
 hppa-hpux-tdep.o: hppa-hpux-tdep.c $(defs_h) $(arch_utils_h) $(gdbcore_h) \
        $(osabi_h) $(gdb_string_h) $(frame_h) $(frame_unwind_h) \
        $(trad_frame_h) $(symtab_h) $(objfiles_h) $(inferior_h) $(infcall_h) \
@@ -2085,6 +2088,9 @@ inflow.o: inflow.c $(defs_h) $(frame_h) $(inferior_h) $(command_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)
+inf-ttrace.o: inf-ttrace.c $(defs_h) $(command_h) $(inferior_h) \
+       $(observer_h) $(target_h) $(gdb_assert_h) $(gdb_string_h) \
+       $(inf_child_h) $(inf_ttrace_h)
 infptrace.o: infptrace.c $(defs_h) $(command_h) $(frame_h) $(gdbcore_h) \
        $(inferior_h) $(regcache_h) $(target_h) $(gdb_assert_h) \
        $(gdb_wait_h) $(gdb_string_h) $(gdb_dirent_h) $(gdb_ptrace_h)
index 0a0d2f8b4f868a3e292976d91d8f59149a3961be..30d349e9ce07b77dba141c8c44dace02aa1fd241 100644 (file)
@@ -1,3 +1,3 @@
 # Host: PA-RISC HP-UX
-NATDEPFILES= fork-child.o inf-ptrace.o \
+NATDEPFILES= fork-child.o inf-ptrace.o inf-ttrace.o \
        hppa-hpux-nat.o hpread.o somread.o somsolib.o
index df925d052abb40ad30bbc1c1773553b702ce25d1..11fc993690ccc9655ec77c29f31a959909609023 100644 (file)
 #include <sys/ptrace.h>
 #include <machine/save_state.h>
 
+#ifdef HAVE_TTRACE
+#include <sys/ttrace.h>
+#endif
+
 #include "hppa-tdep.h"
 #include "inf-ptrace.h"
+#include "inf-ttrace.h"
+
+/* HP-UX 10.20 has a different name than HP-UX 11.00 and later.
+   Apparently, the intended usage changed.  Unfortunately HP didn't
+   care about backwards compatibility.  */
+#ifdef ss_tlsp
+#define ss_mpsfu_high ss_tlsp
+#endif
 
 int child_suppress_run = 0;     /* Non-zero if we should pretend not to be
                                   a runnable target.  */
@@ -179,6 +191,12 @@ hppa_hpux_cannot_store_register (int regnum)
   return hppa_hpux_cannot_fetch_register (regnum);
 }
 
+/* Just in case a future version of PA-RISC HP-UX won't have ptrace(2)
+   at all.  */
+#ifndef PTRACE_TYPE_RET
+#define PTRACE_TYPE_RET void
+#endif
+
 static void
 hppa_hpux_fetch_register (int regnum)
 {
@@ -194,26 +212,41 @@ hppa_hpux_fetch_register (int regnum)
       return;
     }
 
-  pid = PIDGET (inferior_ptid);
+  pid = ptid_get_pid (inferior_ptid);
 
   /* This isn't really an address.  But ptrace thinks of it as one.  */
   addr = hppa_hpux_save_state_offset[regnum];
   size = register_size (current_gdbarch, regnum);
 
-  gdb_assert ((size % sizeof (PTRACE_TYPE_RET)) == 0);
+  gdb_assert (size == 4 || size == 8);
   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_RUREGS, pid, (PTRACE_TYPE_ARG3) addr, 0, 0);
-      if (errno != 0)
-       error ("Couldn't read register %s (#%d): %s.", REGISTER_NAME (regnum),
-              regnum, safe_strerror (errno));
+#ifdef HAVE_TTRACE
+  {
+    lwpid_t lwp = ptid_get_lwp (inferior_ptid);
+
+    if (ttrace (TT_LWP_RUREGS, pid, lwp, addr, size, (uintptr_t)buf) == -1)
+      error ("Couldn't read register %s (#%d): %s",
+            REGISTER_NAME (regnum), regnum, safe_strerror (errno));
+  }
+#else
+  {
+    int i;
+
+    /* 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_RUREGS, pid, (PTRACE_TYPE_ARG3) addr, 0, 0);
+       if (errno != 0)
+         error ("Couldn't read register %s (#%d): %s",
+                REGISTER_NAME (regnum), regnum, safe_strerror (errno));
+
+       addr += sizeof (PTRACE_TYPE_RET);
+      }
+  }
+#endif
 
-      addr += sizeof (PTRACE_TYPE_RET);
-    }
   regcache_raw_supply (current_regcache, regnum, buf);
 }
 
@@ -236,32 +269,46 @@ hppa_hpux_store_register (int regnum)
   size_t size;
   PTRACE_TYPE_RET *buf;
   pid_t pid;
-  int i;
 
   if (hppa_hpux_cannot_store_register (regnum))
     return;
 
-  pid = PIDGET (inferior_ptid);
+  pid = ptid_get_pid (inferior_ptid);
 
   /* This isn't really an address.  But ptrace thinks of it as one.  */
   addr = hppa_hpux_save_state_offset[regnum];
   size = register_size (current_gdbarch, regnum);
 
-  gdb_assert ((size % sizeof (PTRACE_TYPE_RET)) == 0);
+  gdb_assert (size == 4 || size == 8);
   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_WUREGS, pid, (PTRACE_TYPE_ARG3) addr, buf[i], 0);
-      if (errno != 0)
-       error ("Couldn't write register %s (#%d): %s.", REGISTER_NAME (regnum),
-              regnum, safe_strerror (errno));
 
-      addr += sizeof (PTRACE_TYPE_RET);
-    }
+#ifdef HAVE_TTRACE
+  {
+    lwpid_t lwp = ptid_get_lwp (inferior_ptid);
+
+    if (ttrace (TT_LWP_WUREGS, pid, lwp, addr, size, (uintptr_t)buf) == -1)
+      error ("Couldn't write register %s (#%d): %s",
+            REGISTER_NAME (regnum), regnum, safe_strerror (errno));
+  }
+#else
+  {
+    int i;
+
+    /* Write the register contents into the inferior a chunk at the time.  */
+    for (i = 0; i < size / sizeof (PTRACE_TYPE_RET); i++)
+      {
+       errno = 0;
+       ptrace (PT_WUREGS, pid, (PTRACE_TYPE_ARG3) addr, buf[i], 0);
+       if (errno != 0)
+         error ("Couldn't write register %s (#%d): %s",
+                REGISTER_NAME (regnum), regnum, safe_strerror (errno));
+
+       addr += sizeof (PTRACE_TYPE_RET);
+      }
+  }
+#endif
 }
 
 /* Store register REGNUM back into the inferior.  If REGNUM is -1, do
@@ -296,9 +343,15 @@ _initialize_hppa_hpux_nat (void)
 {
   struct target_ops *t;
 
+#ifdef HAVE_TTRACE
+  t = inf_ttrace_target ();
+#else
   t = inf_ptrace_target ();
+#endif
+
   t->to_fetch_registers = hppa_hpux_fetch_inferior_registers;
   t->to_store_registers = hppa_hpux_store_inferior_registers;
   t->to_can_run = hppa_hpux_child_can_run;
+
   add_target (t);
 }
diff --git a/gdb/inf-ttrace.c b/gdb/inf-ttrace.c
new file mode 100644 (file)
index 0000000..da15380
--- /dev/null
@@ -0,0 +1,413 @@
+/* Low-level child interface to ttrace.
+
+   Copyright 2004 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 2 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, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+
+/* The ttrace(2) system call didn't exist before HP-UX 10.30.  Don't
+   try to compile this code unless we have it.  */
+#ifdef HAVE_TTRACE
+
+#include "command.h"
+#include "gdbcore.h"
+#include "inferior.h"
+#include "observer.h"
+#include "target.h"
+
+#include "gdb_assert.h"
+#include "gdb_string.h"
+#include <sys/ttrace.h>
+
+#include "inf-child.h"
+#include "inf-ttrace.h"
+
+/* HACK: Save the ttrace ops returned by inf_ttrace_target.  */
+static struct target_ops *ttrace_ops_hack;
+
+/* File descriptors for pipes used as semaphores during initial
+   startup of an inferior.  */
+static int inf_ttrace_pfd1[2];
+static int inf_ttrace_pfd2[2];
+
+static void
+do_cleanup_pfds (void *dummy)
+{
+  close (inf_ttrace_pfd1[0]);
+  close (inf_ttrace_pfd1[1]);
+  close (inf_ttrace_pfd2[0]);
+  close (inf_ttrace_pfd2[1]);
+}
+
+static void
+inf_ttrace_prepare (void)
+{
+  if (pipe (inf_ttrace_pfd1) == -1)
+    perror_with_name ("pipe");
+
+  if (pipe (inf_ttrace_pfd2) == -1)
+    {
+      close (inf_ttrace_pfd1[0]);
+      close (inf_ttrace_pfd2[0]);
+      perror_with_name ("pipe");
+    }
+}
+
+/* Prepare to be traced.  */
+
+static void
+inf_ttrace_me (void)
+{
+  struct cleanup *old_chain = make_cleanup (do_cleanup_pfds, 0);
+  char c;
+
+  /* "Trace me, Dr. Memory!"  */
+  if (ttrace (TT_PROC_SETTRC, 0, 0, 0, TT_VERSION, 0) == -1)
+    perror_with_name ("ttrace");
+
+  /* Tell our parent that we are ready to be traced.  */
+  if (write (inf_ttrace_pfd1[1], &c, sizeof c) != sizeof c)
+    perror_with_name ("write");
+
+  /* Wait until our parent has set the initial event mask.  */
+  if (read (inf_ttrace_pfd2[0], &c, sizeof c) != sizeof c)
+    perror_with_name ("read");
+
+  do_cleanups (old_chain);
+}
+
+/* Start tracing PID.  */
+
+static void
+inf_ttrace_him (int pid)
+{
+  struct cleanup *old_chain = make_cleanup (do_cleanup_pfds, 0);
+  ttevent_t tte;
+  ttstate_t tts;
+  char c;
+
+  /* Wait until our child is ready to be traced.  */
+  if (read (inf_ttrace_pfd1[0], &c, sizeof c) != sizeof c)
+    perror_with_name ("read");
+
+  /* Set the initial event mask.  */
+  memset (&tte, 0, sizeof (tte));
+  tte.tte_events = TTEVT_EXEC | TTEVT_EXIT;
+  tte.tte_opts = TTEO_NOSTRCCHLD;
+  if (ttrace (TT_PROC_SET_EVENT_MASK, pid, 0,
+             (uintptr_t)&tte, sizeof tte, 0) == -1)
+    perror_with_name ("ttrace");
+
+  /* Tell our child that we have set the initial event mask.  */
+  if (write (inf_ttrace_pfd2[1], &c, sizeof c) != sizeof c)
+    perror_with_name ("write");
+
+  do_cleanups (old_chain);
+
+  push_target (ttrace_ops_hack);
+
+  /* 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));
+}
+
+static void
+inf_ttrace_create_inferior (char *exec_file, char *allargs, char **env,
+                           int from_tty)
+{
+  fork_inferior (exec_file, allargs, env, inf_ttrace_me, inf_ttrace_him,
+                inf_ttrace_prepare, NULL);
+
+  /* We are at the first instruction we care about.  */
+  observer_notify_inferior_created (&current_target, from_tty);
+
+  /* Pedal to the metal...  */
+  proceed ((CORE_ADDR) -1, TARGET_SIGNAL_0, 0);
+}
+
+static void
+inf_ttrace_kill_inferior (void)
+{
+  pid_t pid = ptid_get_pid (inferior_ptid);
+
+  if (pid == 0)
+    return;
+
+  if (ttrace (TT_PROC_EXIT, pid, 0, 0, 0, 0) == -1)
+    perror_with_name ("ttrace");
+  /* ??? Is it necessary to call ttrace_wait() here?  */
+  target_mourn_inferior ();
+}
+
+static void
+inf_ttrace_mourn_inferior (void)
+{
+  unpush_target (ttrace_ops_hack);
+  generic_mourn_inferior ();
+}
+
+static void
+inf_ttrace_attach (char *args, int from_tty)
+{
+  char *exec_file;
+  pid_t pid;
+  char *dummy;
+
+  if (!args)
+    error_no_arg ("process-id to attach");
+
+  dummy = args;
+  pid = strtol (args, &dummy, 0);
+  if (pid == 0 && args == dummy)
+    error ("Illegal process-id: %s\n", 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);
+    }
+
+  if (ttrace (TT_PROC_ATTACH, pid, 0, TT_KILL_ON_EXIT, TT_VERSION, 0) == -1)
+    perror_with_name ("ttrace");
+  attach_flag = 1;
+
+  inferior_ptid = pid_to_ptid (pid);
+  push_target (ttrace_ops_hack);
+
+  /* Do this first, before anything has had a chance to query the
+     inferior's symbol table or similar.  */
+  observer_notify_inferior_created (&current_target, from_tty);
+}
+
+static void
+inf_ttrace_detach (char *args, int from_tty)
+{
+  int sig = 0;
+  pid_t pid = ptid_get_pid (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)
+    sig = atoi (args);
+
+  /* ??? The HP-UX 11.0 ttrace(2) manual page doesn't mention that we
+     can pass a signal number here.  Does this really work?  */
+  if (ttrace (TT_PROC_DETACH, pid, 0, 0, sig, 0) == -1)
+    perror_with_name ("ttrace");
+
+  inferior_ptid = null_ptid;
+  unpush_target (ttrace_ops_hack);
+}
+
+static void
+inf_ttrace_resume (ptid_t ptid, int step, enum target_signal signal)
+{
+  pid_t pid = ptid_get_pid (ptid);
+  lwpid_t lwpid = ptid_get_lwp (ptid);
+  ttreq_t request = step ? TT_LWP_SINGLE : TT_LWP_CONTINUE;
+  int sig = target_signal_to_host (signal);
+
+  if (pid == -1)
+    {
+      pid = ptid_get_pid (inferior_ptid);
+      lwpid = ptid_get_lwp (inferior_ptid);
+    }
+
+  if (ttrace (request, pid, lwpid, TT_NOPC, sig, 0) == -1)
+    perror_with_name ("ttrace");
+
+  if (ptid_equal (ptid, minus_one_ptid))
+    {
+      /* Let all the other threads run too.  */
+      if (ttrace (TT_PROC_CONTINUE, pid, 0, 0, 0, 0) == -1)
+       perror_with_name ("ttrace");
+    }
+}
+
+static ptid_t
+inf_ttrace_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
+{
+  pid_t pid = ptid_get_pid (ptid);
+  lwpid_t lwpid = ptid_get_lwp (ptid);
+  ttstate_t tts;
+
+  ourstatus->kind = TARGET_WAITKIND_IGNORE;
+
+  if (pid == -1)
+    pid = 0;
+
+  gdb_assert (lwpid == 0 || pid != 0);
+
+  do
+    {
+      set_sigint_trap ();
+      set_sigio_trap ();
+
+      if (ttrace_wait (pid, lwpid, TTRACE_WAITOK, &tts, sizeof tts) == -1)
+       perror_with_name ("ttrace_wait");
+
+      clear_sigio_trap ();
+      clear_sigint_trap ();
+    }
+  while (tts.tts_event == TTEVT_NONE);
+
+  switch (tts.tts_event)
+    {
+    case TTEVT_EXEC:
+      /* Make it look like a breakpoint.  */
+      ourstatus->kind = TARGET_WAITKIND_STOPPED;
+      ourstatus->value.sig = TARGET_SIGNAL_TRAP;
+      break;
+    case TTEVT_EXIT:
+      store_waitstatus (ourstatus, tts.tts_u.tts_exit.tts_exitcode);
+      break;
+    case TTEVT_SIGNAL:
+      ourstatus->kind = TARGET_WAITKIND_STOPPED;
+      ourstatus->value.sig =
+       target_signal_from_host (tts.tts_u.tts_signal.tts_signo);
+      break;
+    }
+
+  /* Make sure all threads within the process are stopped.  */
+  if (ttrace (TT_PROC_STOP, tts.tts_pid, 0, 0, 0, 0) == -1)
+    perror_with_name ("ttrace");
+
+  /* HACK: Twiddle INFERIOR_PTID such that the initial thread of a
+     process isn't recognized as a new thread.  */
+  if (ptid_get_lwp (inferior_ptid) == 0)
+    inferior_ptid = ptid_build (tts.tts_pid, tts.tts_lwpid, tts.tts_user_tid);
+
+  return ptid_build (tts.tts_pid, tts.tts_lwpid, tts.tts_user_tid);
+}
+
+/* Transfer LEN bytes from ADDR in the inferior's memory into READBUF,
+   and transfer LEN bytes from WRITEBUF into the inferior's memory at
+   ADDR.  Either READBUF or WRITEBUF may be null, in which case the
+   corresponding transfer doesn't happen.  Return the number of bytes
+   actually transferred (which may be zero if an error occurs).  */
+
+static LONGEST
+inf_ttrace_xfer_memory (CORE_ADDR addr, ULONGEST len,
+                       void *readbuf, const void *writebuf)
+{
+  pid_t pid = ptid_get_pid (inferior_ptid);
+
+  /* HP-UX treats text space and data space differently.  GDB however,
+     doesn't really know the difference.  Therefore we try both.  Try
+     text space before data space though because when we're writing
+     into text space the instruction cache might need to be flushed.  */
+
+  if (readbuf
+      && ttrace (TT_PROC_RDTEXT, pid, 0, addr, len, (uintptr_t)readbuf) == -1
+      && ttrace (TT_PROC_RDDATA, pid, 0, addr, len, (uintptr_t)readbuf) == -1)
+    return 0;
+
+  if (writebuf
+      && ttrace (TT_PROC_WRTEXT, pid, 0, addr, len, (uintptr_t)writebuf) == -1
+      && ttrace (TT_PROC_WRDATA, pid, 0, addr, len, (uintptr_t)writebuf) == -1)
+    return 0;
+
+  return len;
+}
+
+static LONGEST
+inf_ttrace_xfer_partial (struct target_ops *ops, enum target_object object,
+                        const char *annex, void *readbuf,
+                        const void *writebuf, ULONGEST offset, LONGEST len)
+{
+  switch (object)
+    {
+    case TARGET_OBJECT_MEMORY:
+      return inf_ttrace_xfer_memory (offset, len, readbuf, writebuf);
+
+    case TARGET_OBJECT_UNWIND_TABLE:
+      return -1;
+
+    case TARGET_OBJECT_AUXV:
+      return -1;
+
+    case TARGET_OBJECT_WCOOKIE:
+      return -1;
+
+    default:
+      return -1;
+    }
+}
+
+/* Print status information about what we're accessing.  */
+
+static void
+inf_ttrace_files_info (struct target_ops *ignore)
+{
+  printf_unfiltered ("\tUsing the running image of %s %s.\n",
+                    attach_flag ? "attached" : "child",
+                    target_pid_to_str (inferior_ptid));
+}
+\f
+
+struct target_ops *
+inf_ttrace_target (void)
+{
+  struct target_ops *t = inf_child_target ();
+
+  t->to_create_inferior = inf_ttrace_create_inferior;
+  t->to_kill = inf_ttrace_kill_inferior;
+  t->to_mourn_inferior = inf_ttrace_mourn_inferior;
+  t->to_attach = inf_ttrace_attach;
+  t->to_detach = inf_ttrace_detach;
+  t->to_resume = inf_ttrace_resume;
+  t->to_wait = inf_ttrace_wait;
+  t->to_xfer_partial = inf_ttrace_xfer_partial;
+  t->to_files_info = inf_ttrace_files_info;
+
+  ttrace_ops_hack = t;
+  return t;
+}
+
+#endif
diff --git a/gdb/inf-ttrace.h b/gdb/inf-ttrace.h
new file mode 100644 (file)
index 0000000..cc38cbf
--- /dev/null
@@ -0,0 +1,30 @@
+/* Low-level child interface to ttrace.
+
+   Copyright 2004 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 2 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, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef INF_TTRACE_H
+#define INF_TTRACE_H
+
+/* Create a prototype ttrace target.  The client can override it with
+   local methods.  */
+
+extern struct target_ops *inf_ttrace_target (void);
+
+#endif