aboutsummaryrefslogtreecommitdiff
path: root/gdb
diff options
context:
space:
mode:
Diffstat (limited to 'gdb')
-rw-r--r--gdb/ChangeLog18
-rw-r--r--gdb/Makefile.in8
-rw-r--r--gdb/config/pa/hpux.mh2
-rw-r--r--gdb/hppa-hpux-nat.c103
-rw-r--r--gdb/inf-ttrace.c413
-rw-r--r--gdb/inf-ttrace.h30
6 files changed, 547 insertions, 27 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 83ecf1a..fcdbd92 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -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.
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 5173f06..ddac599 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -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)
diff --git a/gdb/config/pa/hpux.mh b/gdb/config/pa/hpux.mh
index 0a0d2f8..30d349e 100644
--- a/gdb/config/pa/hpux.mh
+++ b/gdb/config/pa/hpux.mh
@@ -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
diff --git a/gdb/hppa-hpux-nat.c b/gdb/hppa-hpux-nat.c
index df925d0..11fc993 100644
--- a/gdb/hppa-hpux-nat.c
+++ b/gdb/hppa-hpux-nat.c
@@ -28,8 +28,20 @@
#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
index 0000000..da15380
--- /dev/null
+++ b/gdb/inf-ttrace.c
@@ -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));
+}
+
+
+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
index 0000000..cc38cbf
--- /dev/null
+++ b/gdb/inf-ttrace.h
@@ -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