* hppa-hpux-tdep.c (hppa_hpux_push_dummy_code): Use ULONGEST as
[deliverable/binutils-gdb.git] / gdb / inf-ttrace.c
CommitLineData
eee22bf8
MK
1/* Low-level child interface to ttrace.
2
3 Copyright 2004 Free Software Foundation, Inc.
4
5 This file is part of GDB.
6
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.
11
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.
16
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. */
21
22#include "defs.h"
23
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. */
26#ifdef HAVE_TTRACE
27
28#include "command.h"
29#include "gdbcore.h"
30#include "inferior.h"
31#include "observer.h"
32#include "target.h"
33
34#include "gdb_assert.h"
35#include "gdb_string.h"
36#include <sys/ttrace.h>
37
38#include "inf-child.h"
39#include "inf-ttrace.h"
40
41/* HACK: Save the ttrace ops returned by inf_ttrace_target. */
42static struct target_ops *ttrace_ops_hack;
43
44/* File descriptors for pipes used as semaphores during initial
45 startup of an inferior. */
46static int inf_ttrace_pfd1[2];
47static int inf_ttrace_pfd2[2];
48
49static void
50do_cleanup_pfds (void *dummy)
51{
52 close (inf_ttrace_pfd1[0]);
53 close (inf_ttrace_pfd1[1]);
54 close (inf_ttrace_pfd2[0]);
55 close (inf_ttrace_pfd2[1]);
56}
57
58static void
59inf_ttrace_prepare (void)
60{
61 if (pipe (inf_ttrace_pfd1) == -1)
62 perror_with_name ("pipe");
63
64 if (pipe (inf_ttrace_pfd2) == -1)
65 {
66 close (inf_ttrace_pfd1[0]);
67 close (inf_ttrace_pfd2[0]);
68 perror_with_name ("pipe");
69 }
70}
71
72/* Prepare to be traced. */
73
74static void
75inf_ttrace_me (void)
76{
77 struct cleanup *old_chain = make_cleanup (do_cleanup_pfds, 0);
78 char c;
79
80 /* "Trace me, Dr. Memory!" */
81 if (ttrace (TT_PROC_SETTRC, 0, 0, 0, TT_VERSION, 0) == -1)
82 perror_with_name ("ttrace");
83
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");
87
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");
91
92 do_cleanups (old_chain);
93}
94
95/* Start tracing PID. */
96
97static void
98inf_ttrace_him (int pid)
99{
100 struct cleanup *old_chain = make_cleanup (do_cleanup_pfds, 0);
101 ttevent_t tte;
102 ttstate_t tts;
103 char c;
104
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");
108
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");
116
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");
120
121 do_cleanups (old_chain);
122
123 push_target (ttrace_ops_hack);
124
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. */
129
130 target_acknowledge_created_inferior (pid);
131
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
134 shell. */
135 startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
136
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));
140}
141
142static void
143inf_ttrace_create_inferior (char *exec_file, char *allargs, char **env,
144 int from_tty)
145{
146 fork_inferior (exec_file, allargs, env, inf_ttrace_me, inf_ttrace_him,
147 inf_ttrace_prepare, NULL);
148
149 /* We are at the first instruction we care about. */
150 observer_notify_inferior_created (&current_target, from_tty);
151
152 /* Pedal to the metal... */
153 proceed ((CORE_ADDR) -1, TARGET_SIGNAL_0, 0);
154}
155
156static void
157inf_ttrace_kill_inferior (void)
158{
159 pid_t pid = ptid_get_pid (inferior_ptid);
160
161 if (pid == 0)
162 return;
163
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 ();
168}
169
170static void
171inf_ttrace_mourn_inferior (void)
172{
173 unpush_target (ttrace_ops_hack);
174 generic_mourn_inferior ();
175}
176
177static void
178inf_ttrace_attach (char *args, int from_tty)
179{
180 char *exec_file;
181 pid_t pid;
182 char *dummy;
183
184 if (!args)
185 error_no_arg ("process-id to attach");
186
187 dummy = args;
188 pid = strtol (args, &dummy, 0);
189 if (pid == 0 && args == dummy)
190 error ("Illegal process-id: %s\n", args);
191
192 if (pid == getpid ()) /* Trying to masturbate? */
193 error ("I refuse to debug myself!");
194
195 if (from_tty)
196 {
197 exec_file = (char *) get_exec_file (0);
198
199 if (exec_file)
200 printf_unfiltered ("Attaching to program: %s, %s\n", exec_file,
201 target_pid_to_str (pid_to_ptid (pid)));
202 else
203 printf_unfiltered ("Attaching to %s\n",
204 target_pid_to_str (pid_to_ptid (pid)));
205
206 gdb_flush (gdb_stdout);
207 }
208
209 if (ttrace (TT_PROC_ATTACH, pid, 0, TT_KILL_ON_EXIT, TT_VERSION, 0) == -1)
210 perror_with_name ("ttrace");
211 attach_flag = 1;
212
213 inferior_ptid = pid_to_ptid (pid);
214 push_target (ttrace_ops_hack);
215
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 (&current_target, from_tty);
219}
220
221static void
222inf_ttrace_detach (char *args, int from_tty)
223{
224 int sig = 0;
225 pid_t pid = ptid_get_pid (inferior_ptid);
226
227 if (from_tty)
228 {
229 char *exec_file = get_exec_file (0);
230 if (exec_file == 0)
231 exec_file = "";
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);
235 }
236 if (args)
237 sig = atoi (args);
238
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");
243
244 inferior_ptid = null_ptid;
245 unpush_target (ttrace_ops_hack);
246}
247
248static void
249inf_ttrace_resume (ptid_t ptid, int step, enum target_signal signal)
250{
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);
255
256 if (pid == -1)
257 {
258 pid = ptid_get_pid (inferior_ptid);
259 lwpid = ptid_get_lwp (inferior_ptid);
260 }
261
262 if (ttrace (request, pid, lwpid, TT_NOPC, sig, 0) == -1)
263 perror_with_name ("ttrace");
264
265 if (ptid_equal (ptid, minus_one_ptid))
266 {
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");
270 }
271}
272
273static ptid_t
274inf_ttrace_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
275{
276 pid_t pid = ptid_get_pid (ptid);
277 lwpid_t lwpid = ptid_get_lwp (ptid);
278 ttstate_t tts;
279
280 ourstatus->kind = TARGET_WAITKIND_IGNORE;
281
282 if (pid == -1)
283 pid = 0;
284
285 gdb_assert (lwpid == 0 || pid != 0);
286
287 do
288 {
289 set_sigint_trap ();
290 set_sigio_trap ();
291
292 if (ttrace_wait (pid, lwpid, TTRACE_WAITOK, &tts, sizeof tts) == -1)
293 perror_with_name ("ttrace_wait");
294
295 clear_sigio_trap ();
296 clear_sigint_trap ();
297 }
298 while (tts.tts_event == TTEVT_NONE);
299
300 switch (tts.tts_event)
301 {
302 case TTEVT_EXEC:
303 /* Make it look like a breakpoint. */
304 ourstatus->kind = TARGET_WAITKIND_STOPPED;
305 ourstatus->value.sig = TARGET_SIGNAL_TRAP;
306 break;
307 case TTEVT_EXIT:
308 store_waitstatus (ourstatus, tts.tts_u.tts_exit.tts_exitcode);
309 break;
310 case TTEVT_SIGNAL:
311 ourstatus->kind = TARGET_WAITKIND_STOPPED;
312 ourstatus->value.sig =
313 target_signal_from_host (tts.tts_u.tts_signal.tts_signo);
314 break;
315 }
316
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");
320
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);
325
326 return ptid_build (tts.tts_pid, tts.tts_lwpid, tts.tts_user_tid);
327}
328
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). */
334
335static LONGEST
336inf_ttrace_xfer_memory (CORE_ADDR addr, ULONGEST len,
337 void *readbuf, const void *writebuf)
338{
339 pid_t pid = ptid_get_pid (inferior_ptid);
340
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. */
345
346 if (readbuf
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)
349 return 0;
350
351 if (writebuf
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)
354 return 0;
355
356 return len;
357}
358
359static LONGEST
360inf_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)
363{
364 switch (object)
365 {
366 case TARGET_OBJECT_MEMORY:
367 return inf_ttrace_xfer_memory (offset, len, readbuf, writebuf);
368
369 case TARGET_OBJECT_UNWIND_TABLE:
370 return -1;
371
372 case TARGET_OBJECT_AUXV:
373 return -1;
374
375 case TARGET_OBJECT_WCOOKIE:
376 return -1;
377
378 default:
379 return -1;
380 }
381}
382
383/* Print status information about what we're accessing. */
384
385static void
386inf_ttrace_files_info (struct target_ops *ignore)
387{
388 printf_unfiltered ("\tUsing the running image of %s %s.\n",
389 attach_flag ? "attached" : "child",
390 target_pid_to_str (inferior_ptid));
391}
392\f
393
394struct target_ops *
395inf_ttrace_target (void)
396{
397 struct target_ops *t = inf_child_target ();
398
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;
408
409 ttrace_ops_hack = t;
410 return t;
411}
412
413#endif
This page took 0.046806 seconds and 4 git commands to generate.