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