* 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.
This commit is contained in:
parent
3ca6495449
commit
eee22bf873
@ -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.
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
413
gdb/inf-ttrace.c
Normal file
413
gdb/inf-ttrace.c
Normal file
@ -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 (¤t_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 (¤t_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
|
30
gdb/inf-ttrace.h
Normal file
30
gdb/inf-ttrace.h
Normal file
@ -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
|
Loading…
x
Reference in New Issue
Block a user