1 /* Low-level child interface to ttrace.
3 Copyright 2004 Free Software Foundation, Inc.
5 This file is part of GDB.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
24 /* The ttrace(2) system call didn't exist before HP-UX 10.30. Don't
25 try to compile this code unless we have it. */
34 #include "gdb_assert.h"
35 #include "gdb_string.h"
36 #include <sys/ttrace.h>
38 #include "inf-child.h"
39 #include "inf-ttrace.h"
41 /* HACK: Save the ttrace ops returned by inf_ttrace_target. */
42 static struct target_ops
*ttrace_ops_hack
;
44 /* File descriptors for pipes used as semaphores during initial
45 startup of an inferior. */
46 static int inf_ttrace_pfd1
[2];
47 static int inf_ttrace_pfd2
[2];
50 do_cleanup_pfds (void *dummy
)
52 close (inf_ttrace_pfd1
[0]);
53 close (inf_ttrace_pfd1
[1]);
54 close (inf_ttrace_pfd2
[0]);
55 close (inf_ttrace_pfd2
[1]);
59 inf_ttrace_prepare (void)
61 if (pipe (inf_ttrace_pfd1
) == -1)
62 perror_with_name ("pipe");
64 if (pipe (inf_ttrace_pfd2
) == -1)
66 close (inf_ttrace_pfd1
[0]);
67 close (inf_ttrace_pfd2
[0]);
68 perror_with_name ("pipe");
72 /* Prepare to be traced. */
77 struct cleanup
*old_chain
= make_cleanup (do_cleanup_pfds
, 0);
80 /* "Trace me, Dr. Memory!" */
81 if (ttrace (TT_PROC_SETTRC
, 0, 0, 0, TT_VERSION
, 0) == -1)
82 perror_with_name ("ttrace");
84 /* Tell our parent that we are ready to be traced. */
85 if (write (inf_ttrace_pfd1
[1], &c
, sizeof c
) != sizeof c
)
86 perror_with_name ("write");
88 /* Wait until our parent has set the initial event mask. */
89 if (read (inf_ttrace_pfd2
[0], &c
, sizeof c
) != sizeof c
)
90 perror_with_name ("read");
92 do_cleanups (old_chain
);
95 /* Start tracing PID. */
98 inf_ttrace_him (int pid
)
100 struct cleanup
*old_chain
= make_cleanup (do_cleanup_pfds
, 0);
105 /* Wait until our child is ready to be traced. */
106 if (read (inf_ttrace_pfd1
[0], &c
, sizeof c
) != sizeof c
)
107 perror_with_name ("read");
109 /* Set the initial event mask. */
110 memset (&tte
, 0, sizeof (tte
));
111 tte
.tte_events
= TTEVT_EXEC
| TTEVT_EXIT
;
112 tte
.tte_opts
= TTEO_NOSTRCCHLD
;
113 if (ttrace (TT_PROC_SET_EVENT_MASK
, pid
, 0,
114 (uintptr_t)&tte
, sizeof tte
, 0) == -1)
115 perror_with_name ("ttrace");
117 /* Tell our child that we have set the initial event mask. */
118 if (write (inf_ttrace_pfd2
[1], &c
, sizeof c
) != sizeof c
)
119 perror_with_name ("write");
121 do_cleanups (old_chain
);
123 push_target (ttrace_ops_hack
);
125 /* On some targets, there must be some explicit synchronization
126 between the parent and child processes after the debugger forks,
127 and before the child execs the debuggee program. This call
128 basically gives permission for the child to exec. */
130 target_acknowledge_created_inferior (pid
);
132 /* START_INFERIOR_TRAPS_EXPECTED is defined in inferior.h, and will
133 be 1 or 2 depending on whether we're starting without or with a
135 startup_inferior (START_INFERIOR_TRAPS_EXPECTED
);
137 /* On some targets, there must be some explicit actions taken after
138 the inferior has been started up. */
139 target_post_startup_inferior (pid_to_ptid (pid
));
143 inf_ttrace_create_inferior (char *exec_file
, char *allargs
, char **env
,
146 fork_inferior (exec_file
, allargs
, env
, inf_ttrace_me
, inf_ttrace_him
,
147 inf_ttrace_prepare
, NULL
);
149 /* We are at the first instruction we care about. */
150 observer_notify_inferior_created (¤t_target
, from_tty
);
152 /* Pedal to the metal... */
153 proceed ((CORE_ADDR
) -1, TARGET_SIGNAL_0
, 0);
157 inf_ttrace_kill_inferior (void)
159 pid_t pid
= ptid_get_pid (inferior_ptid
);
164 if (ttrace (TT_PROC_EXIT
, pid
, 0, 0, 0, 0) == -1)
165 perror_with_name ("ttrace");
166 /* ??? Is it necessary to call ttrace_wait() here? */
167 target_mourn_inferior ();
171 inf_ttrace_mourn_inferior (void)
173 unpush_target (ttrace_ops_hack
);
174 generic_mourn_inferior ();
178 inf_ttrace_attach (char *args
, int from_tty
)
185 error_no_arg ("process-id to attach");
188 pid
= strtol (args
, &dummy
, 0);
189 if (pid
== 0 && args
== dummy
)
190 error ("Illegal process-id: %s\n", args
);
192 if (pid
== getpid ()) /* Trying to masturbate? */
193 error ("I refuse to debug myself!");
197 exec_file
= (char *) get_exec_file (0);
200 printf_unfiltered ("Attaching to program: %s, %s\n", exec_file
,
201 target_pid_to_str (pid_to_ptid (pid
)));
203 printf_unfiltered ("Attaching to %s\n",
204 target_pid_to_str (pid_to_ptid (pid
)));
206 gdb_flush (gdb_stdout
);
209 if (ttrace (TT_PROC_ATTACH
, pid
, 0, TT_KILL_ON_EXIT
, TT_VERSION
, 0) == -1)
210 perror_with_name ("ttrace");
213 inferior_ptid
= pid_to_ptid (pid
);
214 push_target (ttrace_ops_hack
);
216 /* Do this first, before anything has had a chance to query the
217 inferior's symbol table or similar. */
218 observer_notify_inferior_created (¤t_target
, from_tty
);
222 inf_ttrace_detach (char *args
, int from_tty
)
225 pid_t pid
= ptid_get_pid (inferior_ptid
);
229 char *exec_file
= get_exec_file (0);
232 printf_unfiltered ("Detaching from program: %s, %s\n", exec_file
,
233 target_pid_to_str (pid_to_ptid (pid
)));
234 gdb_flush (gdb_stdout
);
239 /* ??? The HP-UX 11.0 ttrace(2) manual page doesn't mention that we
240 can pass a signal number here. Does this really work? */
241 if (ttrace (TT_PROC_DETACH
, pid
, 0, 0, sig
, 0) == -1)
242 perror_with_name ("ttrace");
244 inferior_ptid
= null_ptid
;
245 unpush_target (ttrace_ops_hack
);
249 inf_ttrace_resume (ptid_t ptid
, int step
, enum target_signal signal
)
251 pid_t pid
= ptid_get_pid (ptid
);
252 lwpid_t lwpid
= ptid_get_lwp (ptid
);
253 ttreq_t request
= step
? TT_LWP_SINGLE
: TT_LWP_CONTINUE
;
254 int sig
= target_signal_to_host (signal
);
258 pid
= ptid_get_pid (inferior_ptid
);
259 lwpid
= ptid_get_lwp (inferior_ptid
);
262 if (ttrace (request
, pid
, lwpid
, TT_NOPC
, sig
, 0) == -1)
263 perror_with_name ("ttrace");
265 if (ptid_equal (ptid
, minus_one_ptid
))
267 /* Let all the other threads run too. */
268 if (ttrace (TT_PROC_CONTINUE
, pid
, 0, 0, 0, 0) == -1)
269 perror_with_name ("ttrace");
274 inf_ttrace_wait (ptid_t ptid
, struct target_waitstatus
*ourstatus
)
276 pid_t pid
= ptid_get_pid (ptid
);
277 lwpid_t lwpid
= ptid_get_lwp (ptid
);
280 ourstatus
->kind
= TARGET_WAITKIND_IGNORE
;
285 gdb_assert (lwpid
== 0 || pid
!= 0);
292 if (ttrace_wait (pid
, lwpid
, TTRACE_WAITOK
, &tts
, sizeof tts
) == -1)
293 perror_with_name ("ttrace_wait");
296 clear_sigint_trap ();
298 while (tts
.tts_event
== TTEVT_NONE
);
300 switch (tts
.tts_event
)
303 /* Make it look like a breakpoint. */
304 ourstatus
->kind
= TARGET_WAITKIND_STOPPED
;
305 ourstatus
->value
.sig
= TARGET_SIGNAL_TRAP
;
308 store_waitstatus (ourstatus
, tts
.tts_u
.tts_exit
.tts_exitcode
);
311 ourstatus
->kind
= TARGET_WAITKIND_STOPPED
;
312 ourstatus
->value
.sig
=
313 target_signal_from_host (tts
.tts_u
.tts_signal
.tts_signo
);
317 /* Make sure all threads within the process are stopped. */
318 if (ttrace (TT_PROC_STOP
, tts
.tts_pid
, 0, 0, 0, 0) == -1)
319 perror_with_name ("ttrace");
321 /* HACK: Twiddle INFERIOR_PTID such that the initial thread of a
322 process isn't recognized as a new thread. */
323 if (ptid_get_lwp (inferior_ptid
) == 0)
324 inferior_ptid
= ptid_build (tts
.tts_pid
, tts
.tts_lwpid
, tts
.tts_user_tid
);
326 return ptid_build (tts
.tts_pid
, tts
.tts_lwpid
, tts
.tts_user_tid
);
329 /* Transfer LEN bytes from ADDR in the inferior's memory into READBUF,
330 and transfer LEN bytes from WRITEBUF into the inferior's memory at
331 ADDR. Either READBUF or WRITEBUF may be null, in which case the
332 corresponding transfer doesn't happen. Return the number of bytes
333 actually transferred (which may be zero if an error occurs). */
336 inf_ttrace_xfer_memory (CORE_ADDR addr
, ULONGEST len
,
337 void *readbuf
, const void *writebuf
)
339 pid_t pid
= ptid_get_pid (inferior_ptid
);
341 /* HP-UX treats text space and data space differently. GDB however,
342 doesn't really know the difference. Therefore we try both. Try
343 text space before data space though because when we're writing
344 into text space the instruction cache might need to be flushed. */
347 && ttrace (TT_PROC_RDTEXT
, pid
, 0, addr
, len
, (uintptr_t)readbuf
) == -1
348 && ttrace (TT_PROC_RDDATA
, pid
, 0, addr
, len
, (uintptr_t)readbuf
) == -1)
352 && ttrace (TT_PROC_WRTEXT
, pid
, 0, addr
, len
, (uintptr_t)writebuf
) == -1
353 && ttrace (TT_PROC_WRDATA
, pid
, 0, addr
, len
, (uintptr_t)writebuf
) == -1)
360 inf_ttrace_xfer_partial (struct target_ops
*ops
, enum target_object object
,
361 const char *annex
, void *readbuf
,
362 const void *writebuf
, ULONGEST offset
, LONGEST len
)
366 case TARGET_OBJECT_MEMORY
:
367 return inf_ttrace_xfer_memory (offset
, len
, readbuf
, writebuf
);
369 case TARGET_OBJECT_UNWIND_TABLE
:
372 case TARGET_OBJECT_AUXV
:
375 case TARGET_OBJECT_WCOOKIE
:
383 /* Print status information about what we're accessing. */
386 inf_ttrace_files_info (struct target_ops
*ignore
)
388 printf_unfiltered ("\tUsing the running image of %s %s.\n",
389 attach_flag
? "attached" : "child",
390 target_pid_to_str (inferior_ptid
));
395 inf_ttrace_target (void)
397 struct target_ops
*t
= inf_child_target ();
399 t
->to_create_inferior
= inf_ttrace_create_inferior
;
400 t
->to_kill
= inf_ttrace_kill_inferior
;
401 t
->to_mourn_inferior
= inf_ttrace_mourn_inferior
;
402 t
->to_attach
= inf_ttrace_attach
;
403 t
->to_detach
= inf_ttrace_detach
;
404 t
->to_resume
= inf_ttrace_resume
;
405 t
->to_wait
= inf_ttrace_wait
;
406 t
->to_xfer_partial
= inf_ttrace_xfer_partial
;
407 t
->to_files_info
= inf_ttrace_files_info
;