]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/inf-ttrace.c
Copyright updates for 2007.
[thirdparty/binutils-gdb.git] / gdb / inf-ttrace.c
CommitLineData
eee22bf8
MK
1/* Low-level child interface to ttrace.
2
6aba47ca 3 Copyright (C) 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
eee22bf8
MK
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
197e01b6
EZ
19 Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA. */
eee22bf8
MK
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"
a7be7fa8 30#include "gdbthread.h"
eee22bf8 31#include "inferior.h"
eee22bf8
MK
32#include "target.h"
33
34#include "gdb_assert.h"
35#include "gdb_string.h"
932936f0 36#include <sys/mman.h>
eee22bf8
MK
37#include <sys/ttrace.h>
38
39#include "inf-child.h"
40#include "inf-ttrace.h"
41
42/* HACK: Save the ttrace ops returned by inf_ttrace_target. */
43static struct target_ops *ttrace_ops_hack;
932936f0
MK
44\f
45
a7be7fa8
MK
46/* HP-UX uses a threading model where each user-space thread
47 corresponds to a kernel thread. These kernel threads are called
48 lwps. The ttrace(2) interface gives us almost full control over
49 the threads, which makes it very easy to support them in GDB. We
50 identify the threads by process ID and lwp ID. The ttrace(2) also
51 provides us with a thread's user ID (in the `tts_user_tid' member
52 of `ttstate_t') but we don't use that (yet) as it isn't necessary
53 to uniquely label the thread. */
54
55/* Number of active lwps. */
56static int inf_ttrace_num_lwps;
57\f
58
932936f0
MK
59/* On HP-UX versions that have the ttrace(2) system call, we can
60 implement "hardware" watchpoints by fiddling with the protection of
61 pages in the address space that contain the variable being watched.
62 In order to implement this, we keep a dictionary of pages for which
63 we have changed the protection. */
64
65struct inf_ttrace_page
66{
67 CORE_ADDR addr; /* Page address. */
68 int prot; /* Protection. */
69 int refcount; /* Reference count. */
70 struct inf_ttrace_page *next;
71 struct inf_ttrace_page *prev;
72};
73
74struct inf_ttrace_page_dict
75{
76 struct inf_ttrace_page buckets[128];
77 int pagesize; /* Page size. */
78 int count; /* Number of pages in this dictionary. */
79} inf_ttrace_page_dict;
80
a7be7fa8
MK
81/* Number of lwps that are currently in a system call. */
82static int inf_ttrace_num_lwps_in_syscall;
932936f0
MK
83
84/* Flag to indicate whether we should re-enable page protections after
85 the next wait. */
86static int inf_ttrace_reenable_page_protections;
87
88/* Enable system call events for process PID. */
89
90static void
91inf_ttrace_enable_syscall_events (pid_t pid)
92{
93 ttevent_t tte;
94 ttstate_t tts;
95
a7be7fa8 96 gdb_assert (inf_ttrace_num_lwps_in_syscall == 0);
932936f0
MK
97
98 if (ttrace (TT_PROC_GET_EVENT_MASK, pid, 0,
99 (uintptr_t)&tte, sizeof tte, 0) == -1)
e2e0b3e5 100 perror_with_name (("ttrace"));
932936f0
MK
101
102 tte.tte_events |= (TTEVT_SYSCALL_ENTRY | TTEVT_SYSCALL_RETURN);
103
104 if (ttrace (TT_PROC_SET_EVENT_MASK, pid, 0,
105 (uintptr_t)&tte, sizeof tte, 0) == -1)
e2e0b3e5 106 perror_with_name (("ttrace"));
932936f0
MK
107
108 if (ttrace (TT_PROC_GET_FIRST_LWP_STATE, pid, 0,
109 (uintptr_t)&tts, sizeof tts, 0) == -1)
e2e0b3e5 110 perror_with_name (("ttrace"));
932936f0
MK
111
112 if (tts.tts_flags & TTS_INSYSCALL)
a7be7fa8 113 inf_ttrace_num_lwps_in_syscall++;
932936f0
MK
114
115 /* FIXME: Handle multiple threads. */
116}
117
118/* Disable system call events for process PID. */
119
120static void
121inf_ttrace_disable_syscall_events (pid_t pid)
122{
123 ttevent_t tte;
124
125 gdb_assert (inf_ttrace_page_dict.count == 0);
126
127 if (ttrace (TT_PROC_GET_EVENT_MASK, pid, 0,
128 (uintptr_t)&tte, sizeof tte, 0) == -1)
e2e0b3e5 129 perror_with_name (("ttrace"));
932936f0
MK
130
131 tte.tte_events &= ~(TTEVT_SYSCALL_ENTRY | TTEVT_SYSCALL_RETURN);
132
133 if (ttrace (TT_PROC_SET_EVENT_MASK, pid, 0,
134 (uintptr_t)&tte, sizeof tte, 0) == -1)
e2e0b3e5 135 perror_with_name (("ttrace"));
932936f0 136
a7be7fa8 137 inf_ttrace_num_lwps_in_syscall = 0;
932936f0
MK
138}
139
140/* Get information about the page at address ADDR for process PID from
141 the dictionary. */
142
143static struct inf_ttrace_page *
144inf_ttrace_get_page (pid_t pid, CORE_ADDR addr)
145{
146 const int num_buckets = ARRAY_SIZE (inf_ttrace_page_dict.buckets);
147 const int pagesize = inf_ttrace_page_dict.pagesize;
148 int bucket;
149 struct inf_ttrace_page *page;
150
151 bucket = (addr / pagesize) % num_buckets;
152 page = &inf_ttrace_page_dict.buckets[bucket];
153 while (page)
154 {
155 if (page->addr == addr)
156 break;
157
158 page = page->next;
159 }
160
161 return page;
162}
163
164/* Add the page at address ADDR for process PID to the dictionary. */
165
166static struct inf_ttrace_page *
167inf_ttrace_add_page (pid_t pid, CORE_ADDR addr)
168{
169 const int num_buckets = ARRAY_SIZE (inf_ttrace_page_dict.buckets);
170 const int pagesize = inf_ttrace_page_dict.pagesize;
171 int bucket;
172 struct inf_ttrace_page *page;
173 struct inf_ttrace_page *prev = NULL;
174
175 bucket = (addr / pagesize) % num_buckets;
176 page = &inf_ttrace_page_dict.buckets[bucket];
177 while (page)
178 {
179 if (page->addr == addr)
180 break;
181
182 prev = page;
183 page = page->next;
184 }
185
186 if (!page)
187 {
188 int prot;
189
190 if (ttrace (TT_PROC_GET_MPROTECT, pid, 0,
191 addr, 0, (uintptr_t)&prot) == -1)
e2e0b3e5 192 perror_with_name (("ttrace"));
932936f0
MK
193
194 page = XMALLOC (struct inf_ttrace_page);
195 page->addr = addr;
196 page->prot = prot;
197 page->refcount = 0;
198 page->next = NULL;
199
200 page->prev = prev;
201 prev->next = page;
202
203 inf_ttrace_page_dict.count++;
204 if (inf_ttrace_page_dict.count == 1)
205 inf_ttrace_enable_syscall_events (pid);
206
a7be7fa8 207 if (inf_ttrace_num_lwps_in_syscall == 0)
932936f0
MK
208 {
209 if (ttrace (TT_PROC_SET_MPROTECT, pid, 0,
210 addr, pagesize, prot & ~PROT_WRITE) == -1)
e2e0b3e5 211 perror_with_name (("ttrace"));
932936f0
MK
212 }
213 }
214
215 return page;
216}
217
218/* Insert the page at address ADDR of process PID to the dictionary. */
219
220static void
221inf_ttrace_insert_page (pid_t pid, CORE_ADDR addr)
222{
223 struct inf_ttrace_page *page;
224
225 page = inf_ttrace_get_page (pid, addr);
226 if (!page)
227 page = inf_ttrace_add_page (pid, addr);
228
229 page->refcount++;
230}
231
232/* Remove the page at address ADDR of process PID from the dictionary. */
233
234static void
235inf_ttrace_remove_page (pid_t pid, CORE_ADDR addr)
236{
237 const int pagesize = inf_ttrace_page_dict.pagesize;
238 struct inf_ttrace_page *page;
239
240 page = inf_ttrace_get_page (pid, addr);
241 page->refcount--;
242
243 gdb_assert (page->refcount >= 0);
244
245 if (page->refcount == 0)
246 {
a7be7fa8 247 if (inf_ttrace_num_lwps_in_syscall == 0)
932936f0
MK
248 {
249 if (ttrace (TT_PROC_SET_MPROTECT, pid, 0,
250 addr, pagesize, page->prot) == -1)
e2e0b3e5 251 perror_with_name (("ttrace"));
932936f0
MK
252 }
253
254 inf_ttrace_page_dict.count--;
255 if (inf_ttrace_page_dict.count == 0)
256 inf_ttrace_disable_syscall_events (pid);
257
258 page->prev->next = page->next;
259 if (page->next)
260 page->next->prev = page->prev;
261
262 xfree (page);
263 }
264}
265
266/* Mask the bits in PROT from the page protections that are currently
267 in the dictionary for process PID. */
268
269static void
270inf_ttrace_mask_page_protections (pid_t pid, int prot)
271{
272 const int num_buckets = ARRAY_SIZE (inf_ttrace_page_dict.buckets);
273 const int pagesize = inf_ttrace_page_dict.pagesize;
274 int bucket;
275
276 for (bucket = 0; bucket < num_buckets; bucket++)
277 {
278 struct inf_ttrace_page *page;
279
280 page = inf_ttrace_page_dict.buckets[bucket].next;
281 while (page)
282 {
283 if (ttrace (TT_PROC_SET_MPROTECT, pid, 0,
284 page->addr, pagesize, page->prot & ~prot) == -1)
e2e0b3e5 285 perror_with_name (("ttrace"));
932936f0
MK
286
287 page = page->next;
288 }
289 }
290}
291
292/* Write-protect the pages in the dictionary for process PID. */
293
294static void
295inf_ttrace_enable_page_protections (pid_t pid)
296{
297 inf_ttrace_mask_page_protections (pid, PROT_WRITE);
298}
299
300/* Restore the protection of the pages in the dictionary for process
301 PID. */
302
303static void
304inf_ttrace_disable_page_protections (pid_t pid)
305{
306 inf_ttrace_mask_page_protections (pid, 0);
307}
308
309/* Insert a "hardware" watchpoint for LEN bytes at address ADDR of
310 type TYPE. */
311
312static int
313inf_ttrace_insert_watchpoint (CORE_ADDR addr, int len, int type)
314{
315 const int pagesize = inf_ttrace_page_dict.pagesize;
316 pid_t pid = ptid_get_pid (inferior_ptid);
317 CORE_ADDR page_addr;
318 int num_pages;
319 int page;
320
321 gdb_assert (type == hw_write);
322
323 page_addr = (addr / pagesize) * pagesize;
324 num_pages = (len + pagesize - 1) / pagesize;
325
326 for (page = 0; page < num_pages; page++, page_addr += pagesize)
327 inf_ttrace_insert_page (pid, page_addr);
328
329 return 1;
330}
331
332/* Remove a "hardware" watchpoint for LEN bytes at address ADDR of
333 type TYPE. */
334
335static int
336inf_ttrace_remove_watchpoint (CORE_ADDR addr, int len, int type)
337{
338 const int pagesize = inf_ttrace_page_dict.pagesize;
339 pid_t pid = ptid_get_pid (inferior_ptid);
340 CORE_ADDR page_addr;
341 int num_pages;
342 int page;
343
344 gdb_assert (type == hw_write);
345
346 page_addr = (addr / pagesize) * pagesize;
347 num_pages = (len + pagesize - 1) / pagesize;
348
349 for (page = 0; page < num_pages; page++, page_addr += pagesize)
350 inf_ttrace_remove_page (pid, page_addr);
351
352 return 1;
353}
354
355static int
356inf_ttrace_can_use_hw_breakpoint (int type, int len, int ot)
357{
358 return (type == bp_hardware_watchpoint);
359}
360
361static int
2a3cdf79 362inf_ttrace_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
932936f0
MK
363{
364 return 1;
365}
366
367/* Return non-zero if the current inferior was (potentially) stopped
368 by hitting a "hardware" watchpoint. */
369
370static int
371inf_ttrace_stopped_by_watchpoint (void)
372{
373 pid_t pid = ptid_get_pid (inferior_ptid);
374 lwpid_t lwpid = ptid_get_lwp (inferior_ptid);
375 ttstate_t tts;
376
377 if (inf_ttrace_page_dict.count > 0)
378 {
379 if (ttrace (TT_LWP_GET_STATE, pid, lwpid,
380 (uintptr_t)&tts, sizeof tts, 0) == -1)
e2e0b3e5 381 perror_with_name (("ttrace"));
932936f0
MK
382
383 if (tts.tts_event == TTEVT_SIGNAL
384 && tts.tts_u.tts_signal.tts_signo == SIGBUS)
385 {
386 const int pagesize = inf_ttrace_page_dict.pagesize;
387 void *addr = tts.tts_u.tts_signal.tts_siginfo.si_addr;
388 CORE_ADDR page_addr = ((uintptr_t)addr / pagesize) * pagesize;
389
390 if (inf_ttrace_get_page (pid, page_addr))
391 return 1;
392 }
393 }
394
395 return 0;
396}
397\f
eee22bf8 398
b2a4db28
MK
399/* When tracking a vfork(2), we cannot detach from the parent until
400 after the child has called exec(3) or has exited. If we are still
401 attached to the parent, this variable will be set to the process ID
402 of the parent. Otherwise it will be set to zero. */
403static pid_t inf_ttrace_vfork_ppid = -1;
404
405static int
ee057212 406inf_ttrace_follow_fork (struct target_ops *ops, int follow_child)
b2a4db28
MK
407{
408 pid_t pid, fpid;
409 lwpid_t lwpid, flwpid;
410 ttstate_t tts;
411
412 /* FIXME: kettenis/20050720: This stuff should really be passed as
413 an argument by our caller. */
414 {
415 ptid_t ptid;
416 struct target_waitstatus status;
417
418 get_last_target_status (&ptid, &status);
419 gdb_assert (status.kind == TARGET_WAITKIND_FORKED
420 || status.kind == TARGET_WAITKIND_VFORKED);
421
422 pid = ptid_get_pid (ptid);
423 lwpid = ptid_get_lwp (ptid);
424 }
425
426 /* Get all important details that core GDB doesn't (and shouldn't)
427 know about. */
428 if (ttrace (TT_LWP_GET_STATE, pid, lwpid,
429 (uintptr_t)&tts, sizeof tts, 0) == -1)
430 perror_with_name (("ttrace"));
431
432 gdb_assert (tts.tts_event == TTEVT_FORK || tts.tts_event == TTEVT_VFORK);
433
434 if (tts.tts_u.tts_fork.tts_isparent)
435 {
436 pid = tts.tts_pid;
437 lwpid = tts.tts_lwpid;
438 fpid = tts.tts_u.tts_fork.tts_fpid;
439 flwpid = tts.tts_u.tts_fork.tts_flwpid;
440 }
441 else
442 {
443 pid = tts.tts_u.tts_fork.tts_fpid;
444 lwpid = tts.tts_u.tts_fork.tts_flwpid;
445 fpid = tts.tts_pid;
446 flwpid = tts.tts_lwpid;
447 }
448
449 if (follow_child)
450 {
451 inferior_ptid = ptid_build (fpid, flwpid, 0);
452 detach_breakpoints (pid);
453
454 target_terminal_ours ();
455 fprintf_unfiltered (gdb_stdlog, _("\
456Attaching after fork to child process %ld.\n"), (long)fpid);
457 }
458 else
459 {
460 inferior_ptid = ptid_build (pid, lwpid, 0);
461 detach_breakpoints (fpid);
462
463 target_terminal_ours ();
464 fprintf_unfiltered (gdb_stdlog, _("\
465Detaching after fork from child process %ld.\n"), (long)fpid);
466 }
467
468 if (tts.tts_event == TTEVT_VFORK)
469 {
470 gdb_assert (!tts.tts_u.tts_fork.tts_isparent);
471
472 if (follow_child)
473 {
474 /* We can't detach from the parent yet. */
475 inf_ttrace_vfork_ppid = pid;
476
477 reattach_breakpoints (fpid);
478 }
479 else
480 {
481 if (ttrace (TT_PROC_DETACH, fpid, 0, 0, 0, 0) == -1)
482 perror_with_name (("ttrace"));
483
484 /* Wait till we get the TTEVT_VFORK event in the parent.
485 This indicates that the child has called exec(3) or has
486 exited and that the parent is ready to be traced again. */
487 if (ttrace_wait (pid, lwpid, TTRACE_WAITOK, &tts, sizeof tts) == -1)
488 perror_with_name (("ttrace_wait"));
489 gdb_assert (tts.tts_event == TTEVT_VFORK);
490 gdb_assert (tts.tts_u.tts_fork.tts_isparent);
491
492 reattach_breakpoints (pid);
493 }
494 }
495 else
496 {
497 gdb_assert (tts.tts_u.tts_fork.tts_isparent);
498
499 if (follow_child)
500 {
501 if (ttrace (TT_PROC_DETACH, pid, 0, 0, 0, 0) == -1)
502 perror_with_name (("ttrace"));
503 }
504 else
505 {
506 if (ttrace (TT_PROC_DETACH, fpid, 0, 0, 0, 0) == -1)
507 perror_with_name (("ttrace"));
508 }
509 }
510
511 if (follow_child)
512 {
513 /* The child will start out single-threaded. */
514 inf_ttrace_num_lwps = 0;
515 inf_ttrace_num_lwps_in_syscall = 0;
516
517 /* Reset breakpoints in the child as appropriate. */
518 follow_inferior_reset_breakpoints ();
519 }
520
521 return 0;
522}
523\f
524
eee22bf8
MK
525/* File descriptors for pipes used as semaphores during initial
526 startup of an inferior. */
527static int inf_ttrace_pfd1[2];
528static int inf_ttrace_pfd2[2];
529
530static void
531do_cleanup_pfds (void *dummy)
532{
533 close (inf_ttrace_pfd1[0]);
534 close (inf_ttrace_pfd1[1]);
535 close (inf_ttrace_pfd2[0]);
536 close (inf_ttrace_pfd2[1]);
537}
538
539static void
540inf_ttrace_prepare (void)
541{
542 if (pipe (inf_ttrace_pfd1) == -1)
a3f17187 543 perror_with_name (("pipe"));
eee22bf8
MK
544
545 if (pipe (inf_ttrace_pfd2) == -1)
546 {
547 close (inf_ttrace_pfd1[0]);
548 close (inf_ttrace_pfd2[0]);
a3f17187 549 perror_with_name (("pipe"));
eee22bf8
MK
550 }
551}
552
553/* Prepare to be traced. */
554
555static void
556inf_ttrace_me (void)
557{
558 struct cleanup *old_chain = make_cleanup (do_cleanup_pfds, 0);
559 char c;
560
561 /* "Trace me, Dr. Memory!" */
562 if (ttrace (TT_PROC_SETTRC, 0, 0, 0, TT_VERSION, 0) == -1)
e2e0b3e5 563 perror_with_name (("ttrace"));
eee22bf8
MK
564
565 /* Tell our parent that we are ready to be traced. */
566 if (write (inf_ttrace_pfd1[1], &c, sizeof c) != sizeof c)
e2e0b3e5 567 perror_with_name (("write"));
eee22bf8
MK
568
569 /* Wait until our parent has set the initial event mask. */
570 if (read (inf_ttrace_pfd2[0], &c, sizeof c) != sizeof c)
e2e0b3e5 571 perror_with_name (("read"));
eee22bf8
MK
572
573 do_cleanups (old_chain);
574}
575
576/* Start tracing PID. */
577
578static void
579inf_ttrace_him (int pid)
580{
581 struct cleanup *old_chain = make_cleanup (do_cleanup_pfds, 0);
582 ttevent_t tte;
eee22bf8
MK
583 char c;
584
585 /* Wait until our child is ready to be traced. */
586 if (read (inf_ttrace_pfd1[0], &c, sizeof c) != sizeof c)
e2e0b3e5 587 perror_with_name (("read"));
eee22bf8
MK
588
589 /* Set the initial event mask. */
590 memset (&tte, 0, sizeof (tte));
b2a4db28 591 tte.tte_events |= TTEVT_EXEC | TTEVT_EXIT | TTEVT_FORK | TTEVT_VFORK;
a7be7fa8 592 tte.tte_events |= TTEVT_LWP_CREATE | TTEVT_LWP_EXIT | TTEVT_LWP_TERMINATE;
7ba0e0c2
MK
593#ifdef TTEVT_BPT_SSTEP
594 tte.tte_events |= TTEVT_BPT_SSTEP;
595#endif
b2a4db28 596 tte.tte_opts |= TTEO_PROC_INHERIT;
eee22bf8
MK
597 if (ttrace (TT_PROC_SET_EVENT_MASK, pid, 0,
598 (uintptr_t)&tte, sizeof tte, 0) == -1)
e2e0b3e5 599 perror_with_name (("ttrace"));
eee22bf8
MK
600
601 /* Tell our child that we have set the initial event mask. */
602 if (write (inf_ttrace_pfd2[1], &c, sizeof c) != sizeof c)
e2e0b3e5 603 perror_with_name (("write"));
eee22bf8
MK
604
605 do_cleanups (old_chain);
606
607 push_target (ttrace_ops_hack);
608
609 /* On some targets, there must be some explicit synchronization
610 between the parent and child processes after the debugger forks,
611 and before the child execs the debuggee program. This call
612 basically gives permission for the child to exec. */
613
614 target_acknowledge_created_inferior (pid);
615
616 /* START_INFERIOR_TRAPS_EXPECTED is defined in inferior.h, and will
617 be 1 or 2 depending on whether we're starting without or with a
618 shell. */
619 startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
620
621 /* On some targets, there must be some explicit actions taken after
622 the inferior has been started up. */
623 target_post_startup_inferior (pid_to_ptid (pid));
624}
625
626static void
627inf_ttrace_create_inferior (char *exec_file, char *allargs, char **env,
628 int from_tty)
629{
a7be7fa8
MK
630 gdb_assert (inf_ttrace_num_lwps == 0);
631 gdb_assert (inf_ttrace_num_lwps_in_syscall == 0);
932936f0 632 gdb_assert (inf_ttrace_page_dict.count == 0);
932936f0 633 gdb_assert (inf_ttrace_reenable_page_protections == 0);
b2a4db28 634 gdb_assert (inf_ttrace_vfork_ppid == -1);
932936f0 635
eee22bf8
MK
636 fork_inferior (exec_file, allargs, env, inf_ttrace_me, inf_ttrace_him,
637 inf_ttrace_prepare, NULL);
eee22bf8
MK
638}
639
eee22bf8
MK
640static void
641inf_ttrace_mourn_inferior (void)
642{
932936f0
MK
643 const int num_buckets = ARRAY_SIZE (inf_ttrace_page_dict.buckets);
644 int bucket;
645
a7be7fa8
MK
646 inf_ttrace_num_lwps = 0;
647 inf_ttrace_num_lwps_in_syscall = 0;
932936f0
MK
648
649 for (bucket = 0; bucket < num_buckets; bucket++)
650 {
651 struct inf_ttrace_page *page;
652 struct inf_ttrace_page *next;
653
654 page = inf_ttrace_page_dict.buckets[bucket].next;
655 while (page)
656 {
657 next = page->next;
658 xfree (page);
659 page = next;
660 }
661 }
662 inf_ttrace_page_dict.count = 0;
663
eee22bf8
MK
664 unpush_target (ttrace_ops_hack);
665 generic_mourn_inferior ();
666}
667
668static void
669inf_ttrace_attach (char *args, int from_tty)
670{
671 char *exec_file;
672 pid_t pid;
673 char *dummy;
932936f0 674 ttevent_t tte;
eee22bf8
MK
675
676 if (!args)
a3f17187 677 error_no_arg (_("process-id to attach"));
eee22bf8
MK
678
679 dummy = args;
680 pid = strtol (args, &dummy, 0);
681 if (pid == 0 && args == dummy)
8a3fe4f8 682 error (_("Illegal process-id: %s."), args);
eee22bf8
MK
683
684 if (pid == getpid ()) /* Trying to masturbate? */
8a3fe4f8 685 error (_("I refuse to debug myself!"));
eee22bf8
MK
686
687 if (from_tty)
688 {
346e281c 689 exec_file = get_exec_file (0);
eee22bf8
MK
690
691 if (exec_file)
a3f17187 692 printf_unfiltered (_("Attaching to program: %s, %s\n"), exec_file,
eee22bf8
MK
693 target_pid_to_str (pid_to_ptid (pid)));
694 else
a3f17187 695 printf_unfiltered (_("Attaching to %s\n"),
eee22bf8
MK
696 target_pid_to_str (pid_to_ptid (pid)));
697
698 gdb_flush (gdb_stdout);
699 }
700
a7be7fa8
MK
701 gdb_assert (inf_ttrace_num_lwps == 0);
702 gdb_assert (inf_ttrace_num_lwps_in_syscall == 0);
b2a4db28 703 gdb_assert (inf_ttrace_vfork_ppid == -1);
a7be7fa8 704
eee22bf8 705 if (ttrace (TT_PROC_ATTACH, pid, 0, TT_KILL_ON_EXIT, TT_VERSION, 0) == -1)
e2e0b3e5 706 perror_with_name (("ttrace"));
eee22bf8
MK
707 attach_flag = 1;
708
932936f0 709 /* Set the initial event mask. */
932936f0 710 memset (&tte, 0, sizeof (tte));
b2a4db28 711 tte.tte_events |= TTEVT_EXEC | TTEVT_EXIT | TTEVT_FORK | TTEVT_VFORK;
a7be7fa8 712 tte.tte_events |= TTEVT_LWP_CREATE | TTEVT_LWP_EXIT | TTEVT_LWP_TERMINATE;
7ba0e0c2
MK
713#ifdef TTEVT_BPT_SSTEP
714 tte.tte_events |= TTEVT_BPT_SSTEP;
715#endif
b2a4db28 716 tte.tte_opts |= TTEO_PROC_INHERIT;
932936f0
MK
717 if (ttrace (TT_PROC_SET_EVENT_MASK, pid, 0,
718 (uintptr_t)&tte, sizeof tte, 0) == -1)
e2e0b3e5 719 perror_with_name (("ttrace"));
932936f0 720
eee22bf8
MK
721 inferior_ptid = pid_to_ptid (pid);
722 push_target (ttrace_ops_hack);
eee22bf8
MK
723}
724
725static void
726inf_ttrace_detach (char *args, int from_tty)
727{
eee22bf8 728 pid_t pid = ptid_get_pid (inferior_ptid);
5d426ff1 729 int sig = 0;
eee22bf8
MK
730
731 if (from_tty)
732 {
733 char *exec_file = get_exec_file (0);
734 if (exec_file == 0)
735 exec_file = "";
a3f17187 736 printf_unfiltered (_("Detaching from program: %s, %s\n"), exec_file,
eee22bf8
MK
737 target_pid_to_str (pid_to_ptid (pid)));
738 gdb_flush (gdb_stdout);
739 }
740 if (args)
741 sig = atoi (args);
742
743 /* ??? The HP-UX 11.0 ttrace(2) manual page doesn't mention that we
744 can pass a signal number here. Does this really work? */
745 if (ttrace (TT_PROC_DETACH, pid, 0, 0, sig, 0) == -1)
e2e0b3e5 746 perror_with_name (("ttrace"));
eee22bf8 747
b2a4db28
MK
748 if (inf_ttrace_vfork_ppid != -1)
749 {
750 if (ttrace (TT_PROC_DETACH, inf_ttrace_vfork_ppid, 0, 0, 0, 0) == -1)
751 perror_with_name (("ttrace"));
752 inf_ttrace_vfork_ppid = -1;
753 }
754
a7be7fa8
MK
755 inf_ttrace_num_lwps = 0;
756 inf_ttrace_num_lwps_in_syscall = 0;
932936f0 757
eee22bf8 758 unpush_target (ttrace_ops_hack);
932936f0 759 inferior_ptid = null_ptid;
eee22bf8
MK
760}
761
346e281c
MK
762static void
763inf_ttrace_kill (void)
764{
765 pid_t pid = ptid_get_pid (inferior_ptid);
766
767 if (pid == 0)
768 return;
769
770 if (ttrace (TT_PROC_EXIT, pid, 0, 0, 0, 0) == -1)
771 perror_with_name (("ttrace"));
772 /* ??? Is it necessary to call ttrace_wait() here? */
773
774 if (inf_ttrace_vfork_ppid != -1)
775 {
776 if (ttrace (TT_PROC_DETACH, inf_ttrace_vfork_ppid, 0, 0, 0, 0) == -1)
777 perror_with_name (("ttrace"));
778 inf_ttrace_vfork_ppid = -1;
779 }
780
781 target_mourn_inferior ();
782}
783
7ba0e0c2
MK
784static int
785inf_ttrace_resume_callback (struct thread_info *info, void *arg)
786{
787 if (!ptid_equal (info->ptid, inferior_ptid))
788 {
789 pid_t pid = ptid_get_pid (info->ptid);
790 lwpid_t lwpid = ptid_get_lwp (info->ptid);
791
792 if (ttrace (TT_LWP_CONTINUE, pid, lwpid, TT_NOPC, 0, 0) == -1)
e2e0b3e5 793 perror_with_name (("ttrace"));
7ba0e0c2
MK
794 }
795
796 return 0;
797}
798
eee22bf8
MK
799static void
800inf_ttrace_resume (ptid_t ptid, int step, enum target_signal signal)
801{
802 pid_t pid = ptid_get_pid (ptid);
803 lwpid_t lwpid = ptid_get_lwp (ptid);
804 ttreq_t request = step ? TT_LWP_SINGLE : TT_LWP_CONTINUE;
805 int sig = target_signal_to_host (signal);
806
807 if (pid == -1)
808 {
809 pid = ptid_get_pid (inferior_ptid);
810 lwpid = ptid_get_lwp (inferior_ptid);
811 }
812
813 if (ttrace (request, pid, lwpid, TT_NOPC, sig, 0) == -1)
e2e0b3e5 814 perror_with_name (("ttrace"));
eee22bf8 815
7ba0e0c2 816 if (ptid_equal (ptid, minus_one_ptid) && inf_ttrace_num_lwps > 0)
eee22bf8
MK
817 {
818 /* Let all the other threads run too. */
7ba0e0c2 819 iterate_over_threads (inf_ttrace_resume_callback, NULL);
eee22bf8
MK
820 }
821}
822
823static ptid_t
824inf_ttrace_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
825{
826 pid_t pid = ptid_get_pid (ptid);
827 lwpid_t lwpid = ptid_get_lwp (ptid);
828 ttstate_t tts;
829
932936f0 830 /* Until proven otherwise. */
a7be7fa8 831 ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
eee22bf8
MK
832
833 if (pid == -1)
b2a4db28 834 pid = lwpid = 0;
eee22bf8 835
b2a4db28 836 gdb_assert (pid != 0 || lwpid == 0);
eee22bf8
MK
837
838 do
839 {
840 set_sigint_trap ();
841 set_sigio_trap ();
842
843 if (ttrace_wait (pid, lwpid, TTRACE_WAITOK, &tts, sizeof tts) == -1)
a3f17187 844 perror_with_name (("ttrace_wait"));
eee22bf8 845
b2a4db28
MK
846 if (tts.tts_event == TTEVT_VFORK && tts.tts_u.tts_fork.tts_isparent)
847 {
848 if (inf_ttrace_vfork_ppid != -1)
849 {
850 gdb_assert (inf_ttrace_vfork_ppid == tts.tts_pid);
851
852 if (ttrace (TT_PROC_DETACH, tts.tts_pid, 0, 0, 0, 0) == -1)
853 perror_with_name (("ttrace"));
854 inf_ttrace_vfork_ppid = -1;
855 }
856
857 tts.tts_event = TTEVT_NONE;
858 }
859
eee22bf8
MK
860 clear_sigio_trap ();
861 clear_sigint_trap ();
862 }
863 while (tts.tts_event == TTEVT_NONE);
864
932936f0
MK
865 /* Now that we've waited, we can re-enable the page protections. */
866 if (inf_ttrace_reenable_page_protections)
867 {
a7be7fa8 868 gdb_assert (inf_ttrace_num_lwps_in_syscall == 0);
932936f0
MK
869 inf_ttrace_enable_page_protections (tts.tts_pid);
870 inf_ttrace_reenable_page_protections = 0;
871 }
872
a7be7fa8
MK
873 ptid = ptid_build (tts.tts_pid, tts.tts_lwpid, 0);
874
eee22bf8
MK
875 switch (tts.tts_event)
876 {
7ba0e0c2
MK
877#ifdef TTEVT_BPT_SSTEP
878 case TTEVT_BPT_SSTEP:
879 /* Make it look like a breakpoint. */
880 ourstatus->kind = TARGET_WAITKIND_STOPPED;
881 ourstatus->value.sig = TARGET_SIGNAL_TRAP;
882 break;
883#endif
884
eee22bf8 885 case TTEVT_EXEC:
7c35e3f3
MK
886 /* FIXME: kettenis/20051029: GDB doesn't really know how to deal
887 with TARGET_WAITKIND_EXECD events yet. So we make it look
888 like a SIGTRAP instead. */
889#if 0
5d426ff1
MK
890 ourstatus->kind = TARGET_WAITKIND_EXECD;
891 ourstatus->value.execd_pathname =
892 xmalloc (tts.tts_u.tts_exec.tts_pathlen + 1);
893 if (ttrace (TT_PROC_GET_PATHNAME, tts.tts_pid, 0,
894 (uintptr_t)ourstatus->value.execd_pathname,
895 tts.tts_u.tts_exec.tts_pathlen, 0) == -1)
896 perror_with_name (("ttrace"));
897 ourstatus->value.execd_pathname[tts.tts_u.tts_exec.tts_pathlen] = 0;
7c35e3f3
MK
898#else
899 ourstatus->kind = TARGET_WAITKIND_STOPPED;
900 ourstatus->value.sig = TARGET_SIGNAL_TRAP;
901#endif
eee22bf8 902 break;
932936f0 903
eee22bf8
MK
904 case TTEVT_EXIT:
905 store_waitstatus (ourstatus, tts.tts_u.tts_exit.tts_exitcode);
a7be7fa8
MK
906 inf_ttrace_num_lwps = 0;
907 break;
908
b2a4db28
MK
909 case TTEVT_FORK:
910 ourstatus->kind = TARGET_WAITKIND_FORKED;
911 ourstatus->value.related_pid = tts.tts_u.tts_fork.tts_fpid;
912
913 /* Make sure the other end of the fork is stopped too. */
914 if (ttrace_wait (tts.tts_u.tts_fork.tts_fpid,
915 tts.tts_u.tts_fork.tts_flwpid,
916 TTRACE_WAITOK, &tts, sizeof tts) == -1)
917 perror_with_name (("ttrace_wait"));
918
919 gdb_assert (tts.tts_event == TTEVT_FORK);
920 if (tts.tts_u.tts_fork.tts_isparent)
921 {
922 ptid = ptid_build (tts.tts_pid, tts.tts_lwpid, 0);
923 ourstatus->value.related_pid = tts.tts_u.tts_fork.tts_fpid;
924 }
925 break;
926
927 case TTEVT_VFORK:
928 gdb_assert (!tts.tts_u.tts_fork.tts_isparent);
929
930 ourstatus->kind = TARGET_WAITKIND_VFORKED;
931 ourstatus->value.related_pid = tts.tts_u.tts_fork.tts_fpid;
932
933 /* HACK: To avoid touching the parent during the vfork, switch
934 away from it. */
935 inferior_ptid = ptid;
936 break;
937
a7be7fa8
MK
938 case TTEVT_LWP_CREATE:
939 lwpid = tts.tts_u.tts_thread.tts_target_lwpid;
940 ptid = ptid_build (tts.tts_pid, lwpid, 0);
941 if (inf_ttrace_num_lwps == 0)
942 {
943 /* Now that we're going to be multi-threaded, add the
3d450bdd 944 original thread to the list first. */
a7be7fa8
MK
945 add_thread (ptid_build (tts.tts_pid, tts.tts_lwpid, 0));
946 inf_ttrace_num_lwps++;
947 }
a3f17187 948 printf_filtered (_("[New %s]\n"), target_pid_to_str (ptid));
a7be7fa8
MK
949 add_thread (ptid);
950 inf_ttrace_num_lwps++;
951 ptid = ptid_build (tts.tts_pid, tts.tts_lwpid, 0);
952 break;
953
954 case TTEVT_LWP_EXIT:
a3f17187 955 printf_filtered(_("[%s exited]\n"), target_pid_to_str (ptid));
a7be7fa8
MK
956 delete_thread (ptid);
957 inf_ttrace_num_lwps--;
958 /* If we don't return -1 here, core GDB will re-add the thread. */
959 ptid = minus_one_ptid;
960 break;
961
962 case TTEVT_LWP_TERMINATE:
963 lwpid = tts.tts_u.tts_thread.tts_target_lwpid;
964 ptid = ptid_build (tts.tts_pid, lwpid, 0);
a3f17187 965 printf_filtered(_("[%s has been terminated]\n"), target_pid_to_str (ptid));
a7be7fa8
MK
966 delete_thread (ptid);
967 inf_ttrace_num_lwps--;
968 ptid = ptid_build (tts.tts_pid, tts.tts_lwpid, 0);
eee22bf8 969 break;
932936f0 970
eee22bf8
MK
971 case TTEVT_SIGNAL:
972 ourstatus->kind = TARGET_WAITKIND_STOPPED;
973 ourstatus->value.sig =
974 target_signal_from_host (tts.tts_u.tts_signal.tts_signo);
975 break;
932936f0
MK
976
977 case TTEVT_SYSCALL_ENTRY:
978 gdb_assert (inf_ttrace_reenable_page_protections == 0);
a7be7fa8
MK
979 inf_ttrace_num_lwps_in_syscall++;
980 if (inf_ttrace_num_lwps_in_syscall == 1)
932936f0
MK
981 {
982 /* A thread has just entered a system call. Disable any
983 page protections as the kernel can't deal with them. */
984 inf_ttrace_disable_page_protections (tts.tts_pid);
985 }
986 ourstatus->kind = TARGET_WAITKIND_SYSCALL_ENTRY;
987 ourstatus->value.syscall_id = tts.tts_scno;
988 break;
989
990 case TTEVT_SYSCALL_RETURN:
a7be7fa8 991 if (inf_ttrace_num_lwps_in_syscall > 0)
932936f0
MK
992 {
993 /* If the last thread has just left the system call, this
994 would be a logical place to re-enable the page
995 protections, but that doesn't work. We can't re-enable
996 them until we've done another wait. */
997 inf_ttrace_reenable_page_protections =
a7be7fa8
MK
998 (inf_ttrace_num_lwps_in_syscall == 1);
999 inf_ttrace_num_lwps_in_syscall--;
932936f0
MK
1000 }
1001 ourstatus->kind = TARGET_WAITKIND_SYSCALL_RETURN;
1002 ourstatus->value.syscall_id = tts.tts_scno;
1003 break;
a7be7fa8
MK
1004
1005 default:
1006 gdb_assert (!"Unexpected ttrace event");
1007 break;
eee22bf8
MK
1008 }
1009
1010 /* Make sure all threads within the process are stopped. */
1011 if (ttrace (TT_PROC_STOP, tts.tts_pid, 0, 0, 0, 0) == -1)
e2e0b3e5 1012 perror_with_name (("ttrace"));
eee22bf8
MK
1013
1014 /* HACK: Twiddle INFERIOR_PTID such that the initial thread of a
1015 process isn't recognized as a new thread. */
1016 if (ptid_get_lwp (inferior_ptid) == 0)
a7be7fa8 1017 inferior_ptid = ptid;
eee22bf8 1018
a7be7fa8 1019 return ptid;
eee22bf8
MK
1020}
1021
1022/* Transfer LEN bytes from ADDR in the inferior's memory into READBUF,
1023 and transfer LEN bytes from WRITEBUF into the inferior's memory at
1024 ADDR. Either READBUF or WRITEBUF may be null, in which case the
1025 corresponding transfer doesn't happen. Return the number of bytes
1026 actually transferred (which may be zero if an error occurs). */
1027
1028static LONGEST
1029inf_ttrace_xfer_memory (CORE_ADDR addr, ULONGEST len,
1030 void *readbuf, const void *writebuf)
1031{
1032 pid_t pid = ptid_get_pid (inferior_ptid);
1033
1034 /* HP-UX treats text space and data space differently. GDB however,
1035 doesn't really know the difference. Therefore we try both. Try
1036 text space before data space though because when we're writing
1037 into text space the instruction cache might need to be flushed. */
1038
1039 if (readbuf
1040 && ttrace (TT_PROC_RDTEXT, pid, 0, addr, len, (uintptr_t)readbuf) == -1
1041 && ttrace (TT_PROC_RDDATA, pid, 0, addr, len, (uintptr_t)readbuf) == -1)
1042 return 0;
1043
1044 if (writebuf
1045 && ttrace (TT_PROC_WRTEXT, pid, 0, addr, len, (uintptr_t)writebuf) == -1
1046 && ttrace (TT_PROC_WRDATA, pid, 0, addr, len, (uintptr_t)writebuf) == -1)
1047 return 0;
1048
1049 return len;
1050}
1051
1052static LONGEST
1053inf_ttrace_xfer_partial (struct target_ops *ops, enum target_object object,
7a4609f7
MK
1054 const char *annex, gdb_byte *readbuf,
1055 const gdb_byte *writebuf, ULONGEST offset, LONGEST len)
eee22bf8
MK
1056{
1057 switch (object)
1058 {
1059 case TARGET_OBJECT_MEMORY:
1060 return inf_ttrace_xfer_memory (offset, len, readbuf, writebuf);
1061
1062 case TARGET_OBJECT_UNWIND_TABLE:
1063 return -1;
1064
1065 case TARGET_OBJECT_AUXV:
1066 return -1;
1067
1068 case TARGET_OBJECT_WCOOKIE:
1069 return -1;
1070
1071 default:
1072 return -1;
1073 }
1074}
1075
1076/* Print status information about what we're accessing. */
1077
1078static void
1079inf_ttrace_files_info (struct target_ops *ignore)
1080{
346e281c
MK
1081 printf_filtered (_("\tUsing the running image of %s %s.\n"),
1082 attach_flag ? "attached" : "child",
1083 target_pid_to_str (inferior_ptid));
eee22bf8 1084}
a7be7fa8
MK
1085
1086static int
1087inf_ttrace_thread_alive (ptid_t ptid)
1088{
1089 return 1;
1090}
1091
1092static char *
1093inf_ttrace_pid_to_str (ptid_t ptid)
1094{
1095 if (inf_ttrace_num_lwps > 0)
1096 {
1097 pid_t pid = ptid_get_pid (ptid);
1098 lwpid_t lwpid = ptid_get_lwp (ptid);
fd0a2a6f 1099 static char buf[128];
a7be7fa8 1100
5fff8fc0
MK
1101 xsnprintf (buf, sizeof buf, "process %ld, lwp %ld",
1102 (long)pid, (long)lwpid);
a7be7fa8
MK
1103 return buf;
1104 }
1105
1106 return normal_pid_to_str (ptid);
1107}
eee22bf8
MK
1108\f
1109
1110struct target_ops *
1111inf_ttrace_target (void)
1112{
1113 struct target_ops *t = inf_child_target ();
1114
eee22bf8
MK
1115 t->to_attach = inf_ttrace_attach;
1116 t->to_detach = inf_ttrace_detach;
1117 t->to_resume = inf_ttrace_resume;
1118 t->to_wait = inf_ttrace_wait;
eee22bf8 1119 t->to_files_info = inf_ttrace_files_info;
932936f0 1120 t->to_can_use_hw_breakpoint = inf_ttrace_can_use_hw_breakpoint;
932936f0
MK
1121 t->to_insert_watchpoint = inf_ttrace_insert_watchpoint;
1122 t->to_remove_watchpoint = inf_ttrace_remove_watchpoint;
1123 t->to_stopped_by_watchpoint = inf_ttrace_stopped_by_watchpoint;
2a3cdf79
WZ
1124 t->to_region_ok_for_hw_watchpoint =
1125 inf_ttrace_region_ok_for_hw_watchpoint;
346e281c
MK
1126 t->to_kill = inf_ttrace_kill;
1127 t->to_create_inferior = inf_ttrace_create_inferior;
1128 t->to_follow_fork = inf_ttrace_follow_fork;
1129 t->to_mourn_inferior = inf_ttrace_mourn_inferior;
1130 t->to_thread_alive = inf_ttrace_thread_alive;
1131 t->to_pid_to_str = inf_ttrace_pid_to_str;
1132 t->to_xfer_partial = inf_ttrace_xfer_partial;
eee22bf8
MK
1133
1134 ttrace_ops_hack = t;
1135 return t;
1136}
d3322e8a 1137#endif
932936f0
MK
1138\f
1139
1140/* Prevent warning from -Wmissing-prototypes. */
1141void _initialize_hppa_hpux_nat (void);
eee22bf8 1142
932936f0
MK
1143void
1144_initialize_inf_ttrace (void)
1145{
d3322e8a 1146#ifdef HAVE_TTRACE
932936f0 1147 inf_ttrace_page_dict.pagesize = getpagesize();
eee22bf8 1148#endif
d3322e8a 1149}