]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/inf-ttrace.c
Copyright updates for 2007.
[thirdparty/binutils-gdb.git] / gdb / inf-ttrace.c
1 /* Low-level child interface to ttrace.
2
3 Copyright (C) 2004, 2005, 2006, 2007 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., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, 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 "gdbthread.h"
31 #include "inferior.h"
32 #include "target.h"
33
34 #include "gdb_assert.h"
35 #include "gdb_string.h"
36 #include <sys/mman.h>
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. */
43 static struct target_ops *ttrace_ops_hack;
44 \f
45
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. */
56 static int inf_ttrace_num_lwps;
57 \f
58
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
65 struct 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
74 struct 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
81 /* Number of lwps that are currently in a system call. */
82 static int inf_ttrace_num_lwps_in_syscall;
83
84 /* Flag to indicate whether we should re-enable page protections after
85 the next wait. */
86 static int inf_ttrace_reenable_page_protections;
87
88 /* Enable system call events for process PID. */
89
90 static void
91 inf_ttrace_enable_syscall_events (pid_t pid)
92 {
93 ttevent_t tte;
94 ttstate_t tts;
95
96 gdb_assert (inf_ttrace_num_lwps_in_syscall == 0);
97
98 if (ttrace (TT_PROC_GET_EVENT_MASK, pid, 0,
99 (uintptr_t)&tte, sizeof tte, 0) == -1)
100 perror_with_name (("ttrace"));
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)
106 perror_with_name (("ttrace"));
107
108 if (ttrace (TT_PROC_GET_FIRST_LWP_STATE, pid, 0,
109 (uintptr_t)&tts, sizeof tts, 0) == -1)
110 perror_with_name (("ttrace"));
111
112 if (tts.tts_flags & TTS_INSYSCALL)
113 inf_ttrace_num_lwps_in_syscall++;
114
115 /* FIXME: Handle multiple threads. */
116 }
117
118 /* Disable system call events for process PID. */
119
120 static void
121 inf_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)
129 perror_with_name (("ttrace"));
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)
135 perror_with_name (("ttrace"));
136
137 inf_ttrace_num_lwps_in_syscall = 0;
138 }
139
140 /* Get information about the page at address ADDR for process PID from
141 the dictionary. */
142
143 static struct inf_ttrace_page *
144 inf_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
166 static struct inf_ttrace_page *
167 inf_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)
192 perror_with_name (("ttrace"));
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
207 if (inf_ttrace_num_lwps_in_syscall == 0)
208 {
209 if (ttrace (TT_PROC_SET_MPROTECT, pid, 0,
210 addr, pagesize, prot & ~PROT_WRITE) == -1)
211 perror_with_name (("ttrace"));
212 }
213 }
214
215 return page;
216 }
217
218 /* Insert the page at address ADDR of process PID to the dictionary. */
219
220 static void
221 inf_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
234 static void
235 inf_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 {
247 if (inf_ttrace_num_lwps_in_syscall == 0)
248 {
249 if (ttrace (TT_PROC_SET_MPROTECT, pid, 0,
250 addr, pagesize, page->prot) == -1)
251 perror_with_name (("ttrace"));
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
269 static void
270 inf_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)
285 perror_with_name (("ttrace"));
286
287 page = page->next;
288 }
289 }
290 }
291
292 /* Write-protect the pages in the dictionary for process PID. */
293
294 static void
295 inf_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
303 static void
304 inf_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
312 static int
313 inf_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
335 static int
336 inf_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
355 static int
356 inf_ttrace_can_use_hw_breakpoint (int type, int len, int ot)
357 {
358 return (type == bp_hardware_watchpoint);
359 }
360
361 static int
362 inf_ttrace_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
363 {
364 return 1;
365 }
366
367 /* Return non-zero if the current inferior was (potentially) stopped
368 by hitting a "hardware" watchpoint. */
369
370 static int
371 inf_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)
381 perror_with_name (("ttrace"));
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
398
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. */
403 static pid_t inf_ttrace_vfork_ppid = -1;
404
405 static int
406 inf_ttrace_follow_fork (struct target_ops *ops, int follow_child)
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, _("\
456 Attaching 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, _("\
465 Detaching 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
525 /* File descriptors for pipes used as semaphores during initial
526 startup of an inferior. */
527 static int inf_ttrace_pfd1[2];
528 static int inf_ttrace_pfd2[2];
529
530 static void
531 do_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
539 static void
540 inf_ttrace_prepare (void)
541 {
542 if (pipe (inf_ttrace_pfd1) == -1)
543 perror_with_name (("pipe"));
544
545 if (pipe (inf_ttrace_pfd2) == -1)
546 {
547 close (inf_ttrace_pfd1[0]);
548 close (inf_ttrace_pfd2[0]);
549 perror_with_name (("pipe"));
550 }
551 }
552
553 /* Prepare to be traced. */
554
555 static void
556 inf_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)
563 perror_with_name (("ttrace"));
564
565 /* Tell our parent that we are ready to be traced. */
566 if (write (inf_ttrace_pfd1[1], &c, sizeof c) != sizeof c)
567 perror_with_name (("write"));
568
569 /* Wait until our parent has set the initial event mask. */
570 if (read (inf_ttrace_pfd2[0], &c, sizeof c) != sizeof c)
571 perror_with_name (("read"));
572
573 do_cleanups (old_chain);
574 }
575
576 /* Start tracing PID. */
577
578 static void
579 inf_ttrace_him (int pid)
580 {
581 struct cleanup *old_chain = make_cleanup (do_cleanup_pfds, 0);
582 ttevent_t tte;
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)
587 perror_with_name (("read"));
588
589 /* Set the initial event mask. */
590 memset (&tte, 0, sizeof (tte));
591 tte.tte_events |= TTEVT_EXEC | TTEVT_EXIT | TTEVT_FORK | TTEVT_VFORK;
592 tte.tte_events |= TTEVT_LWP_CREATE | TTEVT_LWP_EXIT | TTEVT_LWP_TERMINATE;
593 #ifdef TTEVT_BPT_SSTEP
594 tte.tte_events |= TTEVT_BPT_SSTEP;
595 #endif
596 tte.tte_opts |= TTEO_PROC_INHERIT;
597 if (ttrace (TT_PROC_SET_EVENT_MASK, pid, 0,
598 (uintptr_t)&tte, sizeof tte, 0) == -1)
599 perror_with_name (("ttrace"));
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)
603 perror_with_name (("write"));
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
626 static void
627 inf_ttrace_create_inferior (char *exec_file, char *allargs, char **env,
628 int from_tty)
629 {
630 gdb_assert (inf_ttrace_num_lwps == 0);
631 gdb_assert (inf_ttrace_num_lwps_in_syscall == 0);
632 gdb_assert (inf_ttrace_page_dict.count == 0);
633 gdb_assert (inf_ttrace_reenable_page_protections == 0);
634 gdb_assert (inf_ttrace_vfork_ppid == -1);
635
636 fork_inferior (exec_file, allargs, env, inf_ttrace_me, inf_ttrace_him,
637 inf_ttrace_prepare, NULL);
638 }
639
640 static void
641 inf_ttrace_mourn_inferior (void)
642 {
643 const int num_buckets = ARRAY_SIZE (inf_ttrace_page_dict.buckets);
644 int bucket;
645
646 inf_ttrace_num_lwps = 0;
647 inf_ttrace_num_lwps_in_syscall = 0;
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
664 unpush_target (ttrace_ops_hack);
665 generic_mourn_inferior ();
666 }
667
668 static void
669 inf_ttrace_attach (char *args, int from_tty)
670 {
671 char *exec_file;
672 pid_t pid;
673 char *dummy;
674 ttevent_t tte;
675
676 if (!args)
677 error_no_arg (_("process-id to attach"));
678
679 dummy = args;
680 pid = strtol (args, &dummy, 0);
681 if (pid == 0 && args == dummy)
682 error (_("Illegal process-id: %s."), args);
683
684 if (pid == getpid ()) /* Trying to masturbate? */
685 error (_("I refuse to debug myself!"));
686
687 if (from_tty)
688 {
689 exec_file = get_exec_file (0);
690
691 if (exec_file)
692 printf_unfiltered (_("Attaching to program: %s, %s\n"), exec_file,
693 target_pid_to_str (pid_to_ptid (pid)));
694 else
695 printf_unfiltered (_("Attaching to %s\n"),
696 target_pid_to_str (pid_to_ptid (pid)));
697
698 gdb_flush (gdb_stdout);
699 }
700
701 gdb_assert (inf_ttrace_num_lwps == 0);
702 gdb_assert (inf_ttrace_num_lwps_in_syscall == 0);
703 gdb_assert (inf_ttrace_vfork_ppid == -1);
704
705 if (ttrace (TT_PROC_ATTACH, pid, 0, TT_KILL_ON_EXIT, TT_VERSION, 0) == -1)
706 perror_with_name (("ttrace"));
707 attach_flag = 1;
708
709 /* Set the initial event mask. */
710 memset (&tte, 0, sizeof (tte));
711 tte.tte_events |= TTEVT_EXEC | TTEVT_EXIT | TTEVT_FORK | TTEVT_VFORK;
712 tte.tte_events |= TTEVT_LWP_CREATE | TTEVT_LWP_EXIT | TTEVT_LWP_TERMINATE;
713 #ifdef TTEVT_BPT_SSTEP
714 tte.tte_events |= TTEVT_BPT_SSTEP;
715 #endif
716 tte.tte_opts |= TTEO_PROC_INHERIT;
717 if (ttrace (TT_PROC_SET_EVENT_MASK, pid, 0,
718 (uintptr_t)&tte, sizeof tte, 0) == -1)
719 perror_with_name (("ttrace"));
720
721 inferior_ptid = pid_to_ptid (pid);
722 push_target (ttrace_ops_hack);
723 }
724
725 static void
726 inf_ttrace_detach (char *args, int from_tty)
727 {
728 pid_t pid = ptid_get_pid (inferior_ptid);
729 int sig = 0;
730
731 if (from_tty)
732 {
733 char *exec_file = get_exec_file (0);
734 if (exec_file == 0)
735 exec_file = "";
736 printf_unfiltered (_("Detaching from program: %s, %s\n"), exec_file,
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)
746 perror_with_name (("ttrace"));
747
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
755 inf_ttrace_num_lwps = 0;
756 inf_ttrace_num_lwps_in_syscall = 0;
757
758 unpush_target (ttrace_ops_hack);
759 inferior_ptid = null_ptid;
760 }
761
762 static void
763 inf_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
784 static int
785 inf_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)
793 perror_with_name (("ttrace"));
794 }
795
796 return 0;
797 }
798
799 static void
800 inf_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)
814 perror_with_name (("ttrace"));
815
816 if (ptid_equal (ptid, minus_one_ptid) && inf_ttrace_num_lwps > 0)
817 {
818 /* Let all the other threads run too. */
819 iterate_over_threads (inf_ttrace_resume_callback, NULL);
820 }
821 }
822
823 static ptid_t
824 inf_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
830 /* Until proven otherwise. */
831 ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
832
833 if (pid == -1)
834 pid = lwpid = 0;
835
836 gdb_assert (pid != 0 || lwpid == 0);
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)
844 perror_with_name (("ttrace_wait"));
845
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
860 clear_sigio_trap ();
861 clear_sigint_trap ();
862 }
863 while (tts.tts_event == TTEVT_NONE);
864
865 /* Now that we've waited, we can re-enable the page protections. */
866 if (inf_ttrace_reenable_page_protections)
867 {
868 gdb_assert (inf_ttrace_num_lwps_in_syscall == 0);
869 inf_ttrace_enable_page_protections (tts.tts_pid);
870 inf_ttrace_reenable_page_protections = 0;
871 }
872
873 ptid = ptid_build (tts.tts_pid, tts.tts_lwpid, 0);
874
875 switch (tts.tts_event)
876 {
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
885 case TTEVT_EXEC:
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
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;
898 #else
899 ourstatus->kind = TARGET_WAITKIND_STOPPED;
900 ourstatus->value.sig = TARGET_SIGNAL_TRAP;
901 #endif
902 break;
903
904 case TTEVT_EXIT:
905 store_waitstatus (ourstatus, tts.tts_u.tts_exit.tts_exitcode);
906 inf_ttrace_num_lwps = 0;
907 break;
908
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
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
944 original thread to the list first. */
945 add_thread (ptid_build (tts.tts_pid, tts.tts_lwpid, 0));
946 inf_ttrace_num_lwps++;
947 }
948 printf_filtered (_("[New %s]\n"), target_pid_to_str (ptid));
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:
955 printf_filtered(_("[%s exited]\n"), target_pid_to_str (ptid));
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);
965 printf_filtered(_("[%s has been terminated]\n"), target_pid_to_str (ptid));
966 delete_thread (ptid);
967 inf_ttrace_num_lwps--;
968 ptid = ptid_build (tts.tts_pid, tts.tts_lwpid, 0);
969 break;
970
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;
976
977 case TTEVT_SYSCALL_ENTRY:
978 gdb_assert (inf_ttrace_reenable_page_protections == 0);
979 inf_ttrace_num_lwps_in_syscall++;
980 if (inf_ttrace_num_lwps_in_syscall == 1)
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:
991 if (inf_ttrace_num_lwps_in_syscall > 0)
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 =
998 (inf_ttrace_num_lwps_in_syscall == 1);
999 inf_ttrace_num_lwps_in_syscall--;
1000 }
1001 ourstatus->kind = TARGET_WAITKIND_SYSCALL_RETURN;
1002 ourstatus->value.syscall_id = tts.tts_scno;
1003 break;
1004
1005 default:
1006 gdb_assert (!"Unexpected ttrace event");
1007 break;
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)
1012 perror_with_name (("ttrace"));
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)
1017 inferior_ptid = ptid;
1018
1019 return ptid;
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
1028 static LONGEST
1029 inf_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
1052 static LONGEST
1053 inf_ttrace_xfer_partial (struct target_ops *ops, enum target_object object,
1054 const char *annex, gdb_byte *readbuf,
1055 const gdb_byte *writebuf, ULONGEST offset, LONGEST len)
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
1078 static void
1079 inf_ttrace_files_info (struct target_ops *ignore)
1080 {
1081 printf_filtered (_("\tUsing the running image of %s %s.\n"),
1082 attach_flag ? "attached" : "child",
1083 target_pid_to_str (inferior_ptid));
1084 }
1085
1086 static int
1087 inf_ttrace_thread_alive (ptid_t ptid)
1088 {
1089 return 1;
1090 }
1091
1092 static char *
1093 inf_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);
1099 static char buf[128];
1100
1101 xsnprintf (buf, sizeof buf, "process %ld, lwp %ld",
1102 (long)pid, (long)lwpid);
1103 return buf;
1104 }
1105
1106 return normal_pid_to_str (ptid);
1107 }
1108 \f
1109
1110 struct target_ops *
1111 inf_ttrace_target (void)
1112 {
1113 struct target_ops *t = inf_child_target ();
1114
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;
1119 t->to_files_info = inf_ttrace_files_info;
1120 t->to_can_use_hw_breakpoint = inf_ttrace_can_use_hw_breakpoint;
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;
1124 t->to_region_ok_for_hw_watchpoint =
1125 inf_ttrace_region_ok_for_hw_watchpoint;
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;
1133
1134 ttrace_ops_hack = t;
1135 return t;
1136 }
1137 #endif
1138 \f
1139
1140 /* Prevent warning from -Wmissing-prototypes. */
1141 void _initialize_hppa_hpux_nat (void);
1142
1143 void
1144 _initialize_inf_ttrace (void)
1145 {
1146 #ifdef HAVE_TTRACE
1147 inf_ttrace_page_dict.pagesize = getpagesize();
1148 #endif
1149 }