OSDN Git Service

Updated copyright notices for most files.
[pf3gnuchains/pf3gnuchains3x.git] / gdb / inf-ttrace.c
1 /* Low-level child interface to ttrace.
2
3    Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009
4    Free Software Foundation, Inc.
5
6    This file is part of GDB.
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
20
21 #include "defs.h"
22
23 /* The ttrace(2) system call didn't exist before HP-UX 10.30.  Don't
24    try to compile this code unless we have it.  */
25 #ifdef HAVE_TTRACE
26
27 #include "command.h"
28 #include "gdbcore.h"
29 #include "gdbthread.h"
30 #include "inferior.h"
31 #include "target.h"
32
33 #include "gdb_assert.h"
34 #include "gdb_string.h"
35 #include <sys/mman.h>
36 #include <sys/ttrace.h>
37 #include <signal.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 struct inf_ttrace_private_thread_info
82 {
83   int dying;
84 };
85
86 /* Number of lwps that are currently in a system call.  */
87 static int inf_ttrace_num_lwps_in_syscall;
88
89 /* Flag to indicate whether we should re-enable page protections after
90    the next wait.  */
91 static int inf_ttrace_reenable_page_protections;
92
93 /* Enable system call events for process PID.  */
94
95 static void
96 inf_ttrace_enable_syscall_events (pid_t pid)
97 {
98   ttevent_t tte;
99   ttstate_t tts;
100
101   gdb_assert (inf_ttrace_num_lwps_in_syscall == 0);
102
103   if (ttrace (TT_PROC_GET_EVENT_MASK, pid, 0,
104               (uintptr_t)&tte, sizeof tte, 0) == -1)
105     perror_with_name (("ttrace"));
106
107   tte.tte_events |= (TTEVT_SYSCALL_ENTRY | TTEVT_SYSCALL_RETURN);
108
109   if (ttrace (TT_PROC_SET_EVENT_MASK, pid, 0,
110               (uintptr_t)&tte, sizeof tte, 0) == -1)
111     perror_with_name (("ttrace"));
112
113   if (ttrace (TT_PROC_GET_FIRST_LWP_STATE, pid, 0,
114               (uintptr_t)&tts, sizeof tts, 0) == -1)
115     perror_with_name (("ttrace"));
116
117   if (tts.tts_flags & TTS_INSYSCALL)
118     inf_ttrace_num_lwps_in_syscall++;
119
120   /* FIXME: Handle multiple threads.  */
121 }
122
123 /* Disable system call events for process PID.  */
124
125 static void
126 inf_ttrace_disable_syscall_events (pid_t pid)
127 {
128   ttevent_t tte;
129
130   gdb_assert (inf_ttrace_page_dict.count == 0);
131
132   if (ttrace (TT_PROC_GET_EVENT_MASK, pid, 0,
133               (uintptr_t)&tte, sizeof tte, 0) == -1)
134     perror_with_name (("ttrace"));
135
136   tte.tte_events &= ~(TTEVT_SYSCALL_ENTRY | TTEVT_SYSCALL_RETURN);
137
138   if (ttrace (TT_PROC_SET_EVENT_MASK, pid, 0,
139               (uintptr_t)&tte, sizeof tte, 0) == -1)
140     perror_with_name (("ttrace"));
141
142   inf_ttrace_num_lwps_in_syscall = 0;
143 }
144
145 /* Get information about the page at address ADDR for process PID from
146    the dictionary.  */
147
148 static struct inf_ttrace_page *
149 inf_ttrace_get_page (pid_t pid, CORE_ADDR addr)
150 {
151   const int num_buckets = ARRAY_SIZE (inf_ttrace_page_dict.buckets);
152   const int pagesize = inf_ttrace_page_dict.pagesize;
153   int bucket;
154   struct inf_ttrace_page *page;
155
156   bucket = (addr / pagesize) % num_buckets;
157   page = &inf_ttrace_page_dict.buckets[bucket];
158   while (page)
159     {
160       if (page->addr == addr)
161         break;
162
163       page = page->next;
164     }
165
166   return page;
167 }
168
169 /* Add the page at address ADDR for process PID to the dictionary.  */
170
171 static struct inf_ttrace_page *
172 inf_ttrace_add_page (pid_t pid, CORE_ADDR addr)
173 {
174   const int num_buckets = ARRAY_SIZE (inf_ttrace_page_dict.buckets);
175   const int pagesize = inf_ttrace_page_dict.pagesize;
176   int bucket;
177   struct inf_ttrace_page *page;
178   struct inf_ttrace_page *prev = NULL;
179
180   bucket = (addr / pagesize) % num_buckets;
181   page = &inf_ttrace_page_dict.buckets[bucket];
182   while (page)
183     {
184       if (page->addr == addr)
185         break;
186
187       prev = page;
188       page = page->next;
189     }
190   
191   if (!page)
192     {
193       int prot;
194
195       if (ttrace (TT_PROC_GET_MPROTECT, pid, 0,
196                   addr, 0, (uintptr_t)&prot) == -1)
197         perror_with_name (("ttrace"));
198       
199       page = XMALLOC (struct inf_ttrace_page);
200       page->addr = addr;
201       page->prot = prot;
202       page->refcount = 0;
203       page->next = NULL;
204
205       page->prev = prev;
206       prev->next = page;
207
208       inf_ttrace_page_dict.count++;
209       if (inf_ttrace_page_dict.count == 1)
210         inf_ttrace_enable_syscall_events (pid);
211
212       if (inf_ttrace_num_lwps_in_syscall == 0)
213         {
214           if (ttrace (TT_PROC_SET_MPROTECT, pid, 0,
215                       addr, pagesize, prot & ~PROT_WRITE) == -1)
216             perror_with_name (("ttrace"));
217         }
218     }
219
220   return page;
221 }
222
223 /* Insert the page at address ADDR of process PID to the dictionary.  */
224
225 static void
226 inf_ttrace_insert_page (pid_t pid, CORE_ADDR addr)
227 {
228   struct inf_ttrace_page *page;
229
230   page = inf_ttrace_get_page (pid, addr);
231   if (!page)
232     page = inf_ttrace_add_page (pid, addr);
233
234   page->refcount++;
235 }
236
237 /* Remove the page at address ADDR of process PID from the dictionary.  */
238
239 static void
240 inf_ttrace_remove_page (pid_t pid, CORE_ADDR addr)
241 {
242   const int pagesize = inf_ttrace_page_dict.pagesize;
243   struct inf_ttrace_page *page;
244
245   page = inf_ttrace_get_page (pid, addr);
246   page->refcount--;
247
248   gdb_assert (page->refcount >= 0);
249
250   if (page->refcount == 0)
251     {
252       if (inf_ttrace_num_lwps_in_syscall == 0)
253         {
254           if (ttrace (TT_PROC_SET_MPROTECT, pid, 0,
255                       addr, pagesize, page->prot) == -1)
256             perror_with_name (("ttrace"));
257         }
258
259       inf_ttrace_page_dict.count--;
260       if (inf_ttrace_page_dict.count == 0)
261         inf_ttrace_disable_syscall_events (pid);
262
263       page->prev->next = page->next;
264       if (page->next)
265         page->next->prev = page->prev;
266
267       xfree (page);
268     }
269 }
270
271 /* Mask the bits in PROT from the page protections that are currently
272    in the dictionary for process PID.  */
273
274 static void
275 inf_ttrace_mask_page_protections (pid_t pid, int prot)
276 {
277   const int num_buckets = ARRAY_SIZE (inf_ttrace_page_dict.buckets);
278   const int pagesize = inf_ttrace_page_dict.pagesize;
279   int bucket;
280
281   for (bucket = 0; bucket < num_buckets; bucket++)
282     {
283       struct inf_ttrace_page *page;
284
285       page = inf_ttrace_page_dict.buckets[bucket].next;
286       while (page)
287         {
288           if (ttrace (TT_PROC_SET_MPROTECT, pid, 0,
289                       page->addr, pagesize, page->prot & ~prot) == -1)
290             perror_with_name (("ttrace"));
291
292           page = page->next;
293         }
294     }
295 }
296
297 /* Write-protect the pages in the dictionary for process PID.  */
298
299 static void
300 inf_ttrace_enable_page_protections (pid_t pid)
301 {
302   inf_ttrace_mask_page_protections (pid, PROT_WRITE);
303 }
304
305 /* Restore the protection of the pages in the dictionary for process
306    PID.  */
307
308 static void
309 inf_ttrace_disable_page_protections (pid_t pid)
310 {
311   inf_ttrace_mask_page_protections (pid, 0);
312 }
313
314 /* Insert a "hardware" watchpoint for LEN bytes at address ADDR of
315    type TYPE.  */
316
317 static int
318 inf_ttrace_insert_watchpoint (CORE_ADDR addr, int len, int type)
319 {
320   const int pagesize = inf_ttrace_page_dict.pagesize;
321   pid_t pid = ptid_get_pid (inferior_ptid);
322   CORE_ADDR page_addr;
323   int num_pages;
324   int page;
325
326   gdb_assert (type == hw_write);
327
328   page_addr = (addr / pagesize) * pagesize;
329   num_pages = (len + pagesize - 1) / pagesize;
330
331   for (page = 0; page < num_pages; page++, page_addr += pagesize)
332     inf_ttrace_insert_page (pid, page_addr);
333
334   return 1;
335 }
336
337 /* Remove a "hardware" watchpoint for LEN bytes at address ADDR of
338    type TYPE.  */
339
340 static int
341 inf_ttrace_remove_watchpoint (CORE_ADDR addr, int len, int type)
342 {
343   const int pagesize = inf_ttrace_page_dict.pagesize;
344   pid_t pid = ptid_get_pid (inferior_ptid);
345   CORE_ADDR page_addr;
346   int num_pages;
347   int page;
348
349   gdb_assert (type == hw_write);
350
351   page_addr = (addr / pagesize) * pagesize;
352   num_pages = (len + pagesize - 1) / pagesize;
353
354   for (page = 0; page < num_pages; page++, page_addr += pagesize)
355     inf_ttrace_remove_page (pid, page_addr);
356
357   return 1;
358 }
359
360 static int
361 inf_ttrace_can_use_hw_breakpoint (int type, int len, int ot)
362 {
363   return (type == bp_hardware_watchpoint);
364 }
365
366 static int
367 inf_ttrace_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
368 {
369   return 1;
370 }
371
372 /* Return non-zero if the current inferior was (potentially) stopped
373    by hitting a "hardware" watchpoint.  */
374
375 static int
376 inf_ttrace_stopped_by_watchpoint (void)
377 {
378   pid_t pid = ptid_get_pid (inferior_ptid);
379   lwpid_t lwpid = ptid_get_lwp (inferior_ptid);
380   ttstate_t tts;
381
382   if (inf_ttrace_page_dict.count > 0)
383     {
384       if (ttrace (TT_LWP_GET_STATE, pid, lwpid,
385                   (uintptr_t)&tts, sizeof tts, 0) == -1)
386         perror_with_name (("ttrace"));
387
388       if (tts.tts_event == TTEVT_SIGNAL
389           && tts.tts_u.tts_signal.tts_signo == SIGBUS)
390         {
391           const int pagesize = inf_ttrace_page_dict.pagesize;
392           void *addr = tts.tts_u.tts_signal.tts_siginfo.si_addr;
393           CORE_ADDR page_addr = ((uintptr_t)addr / pagesize) * pagesize;
394
395           if (inf_ttrace_get_page (pid, page_addr))
396             return 1;
397         }
398     }
399
400   return 0;
401 }
402 \f
403
404 /* When tracking a vfork(2), we cannot detach from the parent until
405    after the child has called exec(3) or has exited.  If we are still
406    attached to the parent, this variable will be set to the process ID
407    of the parent.  Otherwise it will be set to zero.  */
408 static pid_t inf_ttrace_vfork_ppid = -1;
409
410 static int
411 inf_ttrace_follow_fork (struct target_ops *ops, int follow_child)
412 {
413   pid_t pid, fpid;
414   lwpid_t lwpid, flwpid;
415   ttstate_t tts;
416   struct thread_info *last_tp = NULL;
417   struct breakpoint *step_resume_breakpoint = NULL;
418   CORE_ADDR step_range_start = 0, step_range_end = 0;
419   struct frame_id step_frame_id = null_frame_id;
420
421   /* FIXME: kettenis/20050720: This stuff should really be passed as
422      an argument by our caller.  */
423   {
424     ptid_t ptid;
425     struct target_waitstatus status;
426
427     get_last_target_status (&ptid, &status);
428     gdb_assert (status.kind == TARGET_WAITKIND_FORKED
429                 || status.kind == TARGET_WAITKIND_VFORKED);
430
431     pid = ptid_get_pid (ptid);
432     lwpid = ptid_get_lwp (ptid);
433     last_tp = find_thread_pid (ptid);
434   }
435
436   /* Get all important details that core GDB doesn't (and shouldn't)
437      know about.  */
438   if (ttrace (TT_LWP_GET_STATE, pid, lwpid,
439               (uintptr_t)&tts, sizeof tts, 0) == -1)
440     perror_with_name (("ttrace"));
441
442   gdb_assert (tts.tts_event == TTEVT_FORK || tts.tts_event == TTEVT_VFORK);
443
444   if (tts.tts_u.tts_fork.tts_isparent)
445     {
446       pid = tts.tts_pid;
447       lwpid = tts.tts_lwpid;
448       fpid = tts.tts_u.tts_fork.tts_fpid;
449       flwpid = tts.tts_u.tts_fork.tts_flwpid;
450     }
451   else
452     {
453       pid = tts.tts_u.tts_fork.tts_fpid;
454       lwpid = tts.tts_u.tts_fork.tts_flwpid;
455       fpid = tts.tts_pid;
456       flwpid = tts.tts_lwpid;
457     }
458
459   if (follow_child)
460     {
461       /* Copy user stepping state to the new inferior thread.  */
462       step_resume_breakpoint = last_tp->step_resume_breakpoint;
463       step_range_start = last_tp->step_range_start;
464       step_range_end = last_tp->step_range_end;
465       step_frame_id = last_tp->step_frame_id;
466
467       /* Otherwise, deleting the parent would get rid of this
468          breakpoint.  */
469       last_tp->step_resume_breakpoint = NULL;
470
471       inferior_ptid = ptid_build (fpid, flwpid, 0);
472       add_inferior (fpid);
473       detach_breakpoints (pid);
474
475       target_terminal_ours ();
476       fprintf_unfiltered (gdb_stdlog, _("\
477 Attaching after fork to child process %ld.\n"), (long)fpid);
478     }
479   else
480     {
481       inferior_ptid = ptid_build (pid, lwpid, 0);
482       detach_breakpoints (fpid);
483
484       target_terminal_ours ();
485       fprintf_unfiltered (gdb_stdlog, _("\
486 Detaching after fork from child process %ld.\n"), (long)fpid);
487     }
488
489   if (tts.tts_event == TTEVT_VFORK)
490     {
491       gdb_assert (!tts.tts_u.tts_fork.tts_isparent);
492
493       if (follow_child)
494         {
495           /* We can't detach from the parent yet.  */
496           inf_ttrace_vfork_ppid = pid;
497
498           reattach_breakpoints (fpid);
499         }
500       else
501         {
502           if (ttrace (TT_PROC_DETACH, fpid, 0, 0, 0, 0) == -1)
503             perror_with_name (("ttrace"));
504
505           /* Wait till we get the TTEVT_VFORK event in the parent.
506              This indicates that the child has called exec(3) or has
507              exited and that the parent is ready to be traced again.  */
508           if (ttrace_wait (pid, lwpid, TTRACE_WAITOK, &tts, sizeof tts) == -1)
509             perror_with_name (("ttrace_wait"));
510           gdb_assert (tts.tts_event == TTEVT_VFORK);
511           gdb_assert (tts.tts_u.tts_fork.tts_isparent);
512
513           reattach_breakpoints (pid);
514         }
515     }
516   else
517     {
518       gdb_assert (tts.tts_u.tts_fork.tts_isparent);
519
520       if (follow_child)
521         {
522           if (ttrace (TT_PROC_DETACH, pid, 0, 0, 0, 0) == -1)
523             perror_with_name (("ttrace"));
524         }
525       else
526         {
527           if (ttrace (TT_PROC_DETACH, fpid, 0, 0, 0, 0) == -1)
528             perror_with_name (("ttrace"));
529         }
530     }
531
532   if (follow_child)
533     {
534       struct thread_info *ti;
535
536       /* The child will start out single-threaded.  */
537       inf_ttrace_num_lwps = 1;
538       inf_ttrace_num_lwps_in_syscall = 0;
539
540       /* Delete parent.  */
541       delete_thread_silent (ptid_build (pid, lwpid, 0));
542       detach_inferior (pid);
543
544       /* Add child thread.  inferior_ptid was already set above.  */
545       ti = add_thread_silent (inferior_ptid);
546       ti->private =
547         xmalloc (sizeof (struct inf_ttrace_private_thread_info));
548       memset (ti->private, 0,
549               sizeof (struct inf_ttrace_private_thread_info));
550
551       ti->step_resume_breakpoint = step_resume_breakpoint;
552       ti->step_range_start = step_range_start;
553       ti->step_range_end = step_range_end;
554       ti->step_frame_id = step_frame_id;
555
556       /* Reset breakpoints in the child as appropriate.  */
557       follow_inferior_reset_breakpoints ();
558     }
559
560   return 0;
561 }
562 \f
563
564 /* File descriptors for pipes used as semaphores during initial
565    startup of an inferior.  */
566 static int inf_ttrace_pfd1[2];
567 static int inf_ttrace_pfd2[2];
568
569 static void
570 do_cleanup_pfds (void *dummy)
571 {
572   close (inf_ttrace_pfd1[0]);
573   close (inf_ttrace_pfd1[1]);
574   close (inf_ttrace_pfd2[0]);
575   close (inf_ttrace_pfd2[1]);
576 }
577
578 static void
579 inf_ttrace_prepare (void)
580 {
581   if (pipe (inf_ttrace_pfd1) == -1)
582     perror_with_name (("pipe"));
583
584   if (pipe (inf_ttrace_pfd2) == -1)
585     {
586       close (inf_ttrace_pfd1[0]);
587       close (inf_ttrace_pfd2[0]);
588       perror_with_name (("pipe"));
589     }
590 }
591
592 /* Prepare to be traced.  */
593
594 static void
595 inf_ttrace_me (void)
596 {
597   struct cleanup *old_chain = make_cleanup (do_cleanup_pfds, 0);
598   char c;
599
600   /* "Trace me, Dr. Memory!"  */
601   if (ttrace (TT_PROC_SETTRC, 0, 0, 0, TT_VERSION, 0) == -1)
602     perror_with_name (("ttrace"));
603
604   /* Tell our parent that we are ready to be traced.  */
605   if (write (inf_ttrace_pfd1[1], &c, sizeof c) != sizeof c)
606     perror_with_name (("write"));
607
608   /* Wait until our parent has set the initial event mask.  */
609   if (read (inf_ttrace_pfd2[0], &c, sizeof c) != sizeof c)
610     perror_with_name (("read"));
611
612   do_cleanups (old_chain);
613 }
614
615 /* Start tracing PID.  */
616
617 static void
618 inf_ttrace_him (int pid)
619 {
620   struct cleanup *old_chain = make_cleanup (do_cleanup_pfds, 0);
621   ttevent_t tte;
622   char c;
623
624   /* Wait until our child is ready to be traced.  */
625   if (read (inf_ttrace_pfd1[0], &c, sizeof c) != sizeof c)
626     perror_with_name (("read"));
627
628   /* Set the initial event mask.  */
629   memset (&tte, 0, sizeof (tte));
630   tte.tte_events |= TTEVT_EXEC | TTEVT_EXIT | TTEVT_FORK | TTEVT_VFORK;
631   tte.tte_events |= TTEVT_LWP_CREATE | TTEVT_LWP_EXIT | TTEVT_LWP_TERMINATE;
632 #ifdef TTEVT_BPT_SSTEP
633   tte.tte_events |= TTEVT_BPT_SSTEP;
634 #endif
635   tte.tte_opts |= TTEO_PROC_INHERIT;
636   if (ttrace (TT_PROC_SET_EVENT_MASK, pid, 0,
637               (uintptr_t)&tte, sizeof tte, 0) == -1)
638     perror_with_name (("ttrace"));
639
640   /* Tell our child that we have set the initial event mask.  */
641   if (write (inf_ttrace_pfd2[1], &c, sizeof c) != sizeof c)
642     perror_with_name (("write"));
643
644   do_cleanups (old_chain);
645
646   push_target (ttrace_ops_hack);
647
648   /* On some targets, there must be some explicit synchronization
649      between the parent and child processes after the debugger forks,
650      and before the child execs the debuggee program.  This call
651      basically gives permission for the child to exec.  */
652
653   target_acknowledge_created_inferior (pid);
654
655   /* START_INFERIOR_TRAPS_EXPECTED is defined in inferior.h, and will
656      be 1 or 2 depending on whether we're starting without or with a
657      shell.  */
658   startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
659
660   /* On some targets, there must be some explicit actions taken after
661      the inferior has been started up.  */
662   target_post_startup_inferior (pid_to_ptid (pid));
663 }
664
665 static void
666 inf_ttrace_create_inferior (struct target_ops *ops, char *exec_file, 
667                             char *allargs, char **env, int from_tty)
668 {
669   gdb_assert (inf_ttrace_num_lwps == 0);
670   gdb_assert (inf_ttrace_num_lwps_in_syscall == 0);
671   gdb_assert (inf_ttrace_page_dict.count == 0);
672   gdb_assert (inf_ttrace_reenable_page_protections == 0);
673   gdb_assert (inf_ttrace_vfork_ppid == -1);
674
675   fork_inferior (exec_file, allargs, env, inf_ttrace_me, inf_ttrace_him,
676                  inf_ttrace_prepare, NULL);
677 }
678
679 static void
680 inf_ttrace_mourn_inferior (struct target_ops *ops)
681 {
682   const int num_buckets = ARRAY_SIZE (inf_ttrace_page_dict.buckets);
683   int bucket;
684
685   inf_ttrace_num_lwps = 0;
686   inf_ttrace_num_lwps_in_syscall = 0;
687
688   for (bucket = 0; bucket < num_buckets; bucket++)
689     {
690       struct inf_ttrace_page *page;
691       struct inf_ttrace_page *next;
692
693       page = inf_ttrace_page_dict.buckets[bucket].next;
694       while (page)
695         {
696           next = page->next;
697           xfree (page);
698           page = next;
699         }
700     }
701   inf_ttrace_page_dict.count = 0;
702
703   unpush_target (ttrace_ops_hack);
704   generic_mourn_inferior ();
705 }
706
707 static void
708 inf_ttrace_attach (struct target_ops *ops, char *args, int from_tty)
709 {
710   char *exec_file;
711   pid_t pid;
712   char *dummy;
713   ttevent_t tte;
714   struct inferior *inf;
715
716   if (!args)
717     error_no_arg (_("process-id to attach"));
718
719   dummy = args;
720   pid = strtol (args, &dummy, 0);
721   if (pid == 0 && args == dummy)
722     error (_("Illegal process-id: %s."), args);
723
724   if (pid == getpid ())         /* Trying to masturbate?  */
725     error (_("I refuse to debug myself!"));
726
727   if (from_tty)
728     {
729       exec_file = get_exec_file (0);
730
731       if (exec_file)
732         printf_unfiltered (_("Attaching to program: %s, %s\n"), exec_file,
733                            target_pid_to_str (pid_to_ptid (pid)));
734       else
735         printf_unfiltered (_("Attaching to %s\n"),
736                            target_pid_to_str (pid_to_ptid (pid)));
737
738       gdb_flush (gdb_stdout);
739     }
740
741   gdb_assert (inf_ttrace_num_lwps == 0);
742   gdb_assert (inf_ttrace_num_lwps_in_syscall == 0);
743   gdb_assert (inf_ttrace_vfork_ppid == -1);
744
745   if (ttrace (TT_PROC_ATTACH, pid, 0, TT_KILL_ON_EXIT, TT_VERSION, 0) == -1)
746     perror_with_name (("ttrace"));
747
748   inf = add_inferior (pid);
749   inf->attach_flag = 1;
750
751   /* Set the initial event mask.  */
752   memset (&tte, 0, sizeof (tte));
753   tte.tte_events |= TTEVT_EXEC | TTEVT_EXIT | TTEVT_FORK | TTEVT_VFORK;
754   tte.tte_events |= TTEVT_LWP_CREATE | TTEVT_LWP_EXIT | TTEVT_LWP_TERMINATE;
755 #ifdef TTEVT_BPT_SSTEP
756   tte.tte_events |= TTEVT_BPT_SSTEP;
757 #endif
758   tte.tte_opts |= TTEO_PROC_INHERIT;
759   if (ttrace (TT_PROC_SET_EVENT_MASK, pid, 0,
760               (uintptr_t)&tte, sizeof tte, 0) == -1)
761     perror_with_name (("ttrace"));
762
763   push_target (ttrace_ops_hack);
764
765   /* We'll bump inf_ttrace_num_lwps up and add the private data to the
766      thread as soon as we get to inf_ttrace_wait.  At this point, we
767      don't have lwpid info yet.  */
768   inferior_ptid = pid_to_ptid (pid);
769   add_thread_silent (inferior_ptid);
770 }
771
772 static void
773 inf_ttrace_detach (struct target_ops *ops, char *args, int from_tty)
774 {
775   pid_t pid = ptid_get_pid (inferior_ptid);
776   int sig = 0;
777
778   if (from_tty)
779     {
780       char *exec_file = get_exec_file (0);
781       if (exec_file == 0)
782         exec_file = "";
783       printf_unfiltered (_("Detaching from program: %s, %s\n"), exec_file,
784                          target_pid_to_str (pid_to_ptid (pid)));
785       gdb_flush (gdb_stdout);
786     }
787   if (args)
788     sig = atoi (args);
789
790   /* ??? The HP-UX 11.0 ttrace(2) manual page doesn't mention that we
791      can pass a signal number here.  Does this really work?  */
792   if (ttrace (TT_PROC_DETACH, pid, 0, 0, sig, 0) == -1)
793     perror_with_name (("ttrace"));
794
795   if (inf_ttrace_vfork_ppid != -1)
796     {
797       if (ttrace (TT_PROC_DETACH, inf_ttrace_vfork_ppid, 0, 0, 0, 0) == -1)
798         perror_with_name (("ttrace"));
799       inf_ttrace_vfork_ppid = -1;
800     }
801
802   inf_ttrace_num_lwps = 0;
803   inf_ttrace_num_lwps_in_syscall = 0;
804
805   inferior_ptid = null_ptid;
806   detach_inferior (pid);
807
808   unpush_target (ttrace_ops_hack);
809 }
810
811 static void
812 inf_ttrace_kill (void)
813 {
814   pid_t pid = ptid_get_pid (inferior_ptid);
815
816   if (pid == 0)
817     return;
818
819   if (ttrace (TT_PROC_EXIT, pid, 0, 0, 0, 0) == -1)
820     perror_with_name (("ttrace"));
821   /* ??? Is it necessary to call ttrace_wait() here?  */
822
823   if (inf_ttrace_vfork_ppid != -1)
824     {
825       if (ttrace (TT_PROC_DETACH, inf_ttrace_vfork_ppid, 0, 0, 0, 0) == -1)
826         perror_with_name (("ttrace"));
827       inf_ttrace_vfork_ppid = -1;
828     }
829
830   target_mourn_inferior ();
831 }
832
833 /* Check is a dying thread is dead by now, and delete it from GDBs
834    thread list if so.  */
835 static int
836 inf_ttrace_delete_dead_threads_callback (struct thread_info *info, void *arg)
837 {
838   lwpid_t lwpid;
839   struct inf_ttrace_private_thread_info *p;
840
841   if (is_exited (info->ptid))
842     return 0;
843
844   lwpid = ptid_get_lwp (info->ptid);
845   p = (struct inf_ttrace_private_thread_info *) info->private;
846
847   /* Check if an lwp that was dying is still there or not.  */
848   if (p->dying && (kill (lwpid, 0) == -1))
849     /* It's gone now.  */
850     delete_thread (info->ptid);
851
852   return 0;
853 }
854
855 /* Resume the lwp pointed to by INFO, with REQUEST, and pass it signal
856    SIG.  */
857
858 static void
859 inf_ttrace_resume_lwp (struct thread_info *info, ttreq_t request, int sig)
860 {
861   pid_t pid = ptid_get_pid (info->ptid);
862   lwpid_t lwpid = ptid_get_lwp (info->ptid);
863
864   if (ttrace (request, pid, lwpid, TT_NOPC, sig, 0) == -1)
865     {
866       struct inf_ttrace_private_thread_info *p
867         = (struct inf_ttrace_private_thread_info *) info->private;
868       if (p->dying && errno == EPROTO)
869         /* This is expected, it means the dying lwp is really gone
870            by now.  If ttrace had an event to inform the debugger
871            the lwp is really gone, this wouldn't be needed.  */
872         delete_thread (info->ptid);
873       else
874         /* This was really unexpected.  */
875         perror_with_name (("ttrace"));
876     }
877 }
878
879 /* Callback for iterate_over_threads.  */
880
881 static int
882 inf_ttrace_resume_callback (struct thread_info *info, void *arg)
883 {
884   if (!ptid_equal (info->ptid, inferior_ptid) && !is_exited (info->ptid))
885     inf_ttrace_resume_lwp (info, TT_LWP_CONTINUE, 0);
886
887   return 0;
888 }
889
890 static void
891 inf_ttrace_resume (ptid_t ptid, int step, enum target_signal signal)
892 {
893   int resume_all;
894   ttreq_t request = step ? TT_LWP_SINGLE : TT_LWP_CONTINUE;
895   int sig = target_signal_to_host (signal);
896   struct thread_info *info;
897
898   /* A specific PTID means `step only this process id'.  */
899   resume_all = (ptid_equal (ptid, minus_one_ptid));
900
901   /* If resuming all threads, it's the current thread that should be
902      handled specially.  */
903   if (resume_all)
904     ptid = inferior_ptid;
905
906   info = find_thread_pid (ptid);
907   inf_ttrace_resume_lwp (info, request, sig);
908
909   if (resume_all)
910     /* Let all the other threads run too.  */
911     iterate_over_threads (inf_ttrace_resume_callback, NULL);
912 }
913
914 static ptid_t
915 inf_ttrace_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
916 {
917   pid_t pid = ptid_get_pid (ptid);
918   lwpid_t lwpid = ptid_get_lwp (ptid);
919   ttstate_t tts;
920   struct thread_info *ti;
921   ptid_t related_ptid;
922
923   /* Until proven otherwise.  */
924   ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
925
926   if (pid == -1)
927     pid = lwpid = 0;
928
929   gdb_assert (pid != 0 || lwpid == 0);
930
931   do
932     {
933       set_sigint_trap ();
934
935       if (ttrace_wait (pid, lwpid, TTRACE_WAITOK, &tts, sizeof tts) == -1)
936         perror_with_name (("ttrace_wait"));
937
938       if (tts.tts_event == TTEVT_VFORK && tts.tts_u.tts_fork.tts_isparent)
939         {
940           if (inf_ttrace_vfork_ppid != -1)
941             {
942               gdb_assert (inf_ttrace_vfork_ppid == tts.tts_pid);
943
944               if (ttrace (TT_PROC_DETACH, tts.tts_pid, 0, 0, 0, 0) == -1)
945                 perror_with_name (("ttrace"));
946               inf_ttrace_vfork_ppid = -1;
947             }
948
949           tts.tts_event = TTEVT_NONE;
950         }
951
952       clear_sigint_trap ();
953     }
954   while (tts.tts_event == TTEVT_NONE);
955
956   /* Now that we've waited, we can re-enable the page protections.  */
957   if (inf_ttrace_reenable_page_protections)
958     {
959       gdb_assert (inf_ttrace_num_lwps_in_syscall == 0);
960       inf_ttrace_enable_page_protections (tts.tts_pid);
961       inf_ttrace_reenable_page_protections = 0;
962     }
963
964   ptid = ptid_build (tts.tts_pid, tts.tts_lwpid, 0);
965
966   if (inf_ttrace_num_lwps == 0)
967     {
968       struct thread_info *ti;
969
970       inf_ttrace_num_lwps = 1;
971
972       /* This is the earliest we hear about the lwp member of
973          INFERIOR_PTID, after an attach or fork_inferior.  */
974       gdb_assert (ptid_get_lwp (inferior_ptid) == 0);
975
976       /* We haven't set the private member on the main thread yet.  Do
977          it now.  */
978       ti = find_thread_pid (inferior_ptid);
979       gdb_assert (ti != NULL && ti->private == NULL);
980       ti->private =
981         xmalloc (sizeof (struct inf_ttrace_private_thread_info));
982       memset (ti->private, 0,
983               sizeof (struct inf_ttrace_private_thread_info));
984
985       /* Notify the core that this ptid changed.  This changes
986          inferior_ptid as well.  */
987       thread_change_ptid (inferior_ptid, ptid);
988     }
989
990   switch (tts.tts_event)
991     {
992 #ifdef TTEVT_BPT_SSTEP
993     case TTEVT_BPT_SSTEP:
994       /* Make it look like a breakpoint.  */
995       ourstatus->kind = TARGET_WAITKIND_STOPPED;
996       ourstatus->value.sig = TARGET_SIGNAL_TRAP;
997       break;
998 #endif
999
1000     case TTEVT_EXEC:
1001       ourstatus->kind = TARGET_WAITKIND_EXECD;
1002       ourstatus->value.execd_pathname =
1003         xmalloc (tts.tts_u.tts_exec.tts_pathlen + 1);
1004       if (ttrace (TT_PROC_GET_PATHNAME, tts.tts_pid, 0,
1005                   (uintptr_t)ourstatus->value.execd_pathname,
1006                   tts.tts_u.tts_exec.tts_pathlen, 0) == -1)
1007         perror_with_name (("ttrace"));
1008       ourstatus->value.execd_pathname[tts.tts_u.tts_exec.tts_pathlen] = 0;
1009
1010       /* At this point, all inserted breakpoints are gone.  Doing this
1011          as soon as we detect an exec prevents the badness of deleting
1012          a breakpoint writing the current "shadow contents" to lift
1013          the bp.  That shadow is NOT valid after an exec.  */
1014       mark_breakpoints_out ();
1015       break;
1016
1017     case TTEVT_EXIT:
1018       store_waitstatus (ourstatus, tts.tts_u.tts_exit.tts_exitcode);
1019       inf_ttrace_num_lwps = 0;
1020       break;
1021
1022     case TTEVT_FORK:
1023       related_ptid = ptid_build (tts.tts_u.tts_fork.tts_fpid,
1024                                  tts.tts_u.tts_fork.tts_flwpid, 0);
1025
1026       ourstatus->kind = TARGET_WAITKIND_FORKED;
1027       ourstatus->value.related_pid = related_ptid;
1028
1029       /* Make sure the other end of the fork is stopped too.  */
1030       if (ttrace_wait (tts.tts_u.tts_fork.tts_fpid,
1031                        tts.tts_u.tts_fork.tts_flwpid,
1032                        TTRACE_WAITOK, &tts, sizeof tts) == -1)
1033         perror_with_name (("ttrace_wait"));
1034
1035       gdb_assert (tts.tts_event == TTEVT_FORK);
1036       if (tts.tts_u.tts_fork.tts_isparent)
1037         {
1038           related_ptid = ptid_build (tts.tts_u.tts_fork.tts_fpid,
1039                                      tts.tts_u.tts_fork.tts_flwpid, 0);
1040           ptid = ptid_build (tts.tts_pid, tts.tts_lwpid, 0);
1041           ourstatus->value.related_pid = related_ptid;
1042         }
1043       break;
1044
1045     case TTEVT_VFORK:
1046       gdb_assert (!tts.tts_u.tts_fork.tts_isparent);
1047
1048       related_ptid = ptid_build (tts.tts_u.tts_fork.tts_fpid,
1049                                  tts.tts_u.tts_fork.tts_flwpid, 0);
1050
1051       ourstatus->kind = TARGET_WAITKIND_VFORKED;
1052       ourstatus->value.related_pid = related_ptid;
1053
1054       /* HACK: To avoid touching the parent during the vfork, switch
1055          away from it.  */
1056       inferior_ptid = ptid;
1057       break;
1058
1059     case TTEVT_LWP_CREATE:
1060       lwpid = tts.tts_u.tts_thread.tts_target_lwpid;
1061       ptid = ptid_build (tts.tts_pid, lwpid, 0);
1062       ti = add_thread (ptid);
1063       ti->private =
1064         xmalloc (sizeof (struct inf_ttrace_private_thread_info));
1065       memset (ti->private, 0,
1066               sizeof (struct inf_ttrace_private_thread_info));
1067       inf_ttrace_num_lwps++;
1068       ptid = ptid_build (tts.tts_pid, tts.tts_lwpid, 0);
1069       /* Let the lwp_create-caller thread continue.  */
1070       ttrace (TT_LWP_CONTINUE, ptid_get_pid (ptid),
1071               ptid_get_lwp (ptid), TT_NOPC, 0, 0);
1072       /* Return without stopping the whole process.  */
1073       ourstatus->kind = TARGET_WAITKIND_IGNORE;
1074       return ptid;
1075
1076     case TTEVT_LWP_EXIT:
1077       if (print_thread_events)
1078         printf_unfiltered (_("[%s exited]\n"), target_pid_to_str (ptid));
1079       ti = find_thread_pid (ptid);
1080       gdb_assert (ti != NULL);
1081       ((struct inf_ttrace_private_thread_info *)ti->private)->dying = 1;
1082       inf_ttrace_num_lwps--;
1083       /* Let the thread really exit.  */
1084       ttrace (TT_LWP_CONTINUE, ptid_get_pid (ptid),
1085               ptid_get_lwp (ptid), TT_NOPC, 0, 0);
1086       /* Return without stopping the whole process.  */
1087       ourstatus->kind = TARGET_WAITKIND_IGNORE;
1088       return ptid;
1089
1090     case TTEVT_LWP_TERMINATE:
1091       lwpid = tts.tts_u.tts_thread.tts_target_lwpid;
1092       ptid = ptid_build (tts.tts_pid, lwpid, 0);
1093       if (print_thread_events)
1094         printf_unfiltered(_("[%s has been terminated]\n"),
1095                           target_pid_to_str (ptid));
1096       ti = find_thread_pid (ptid);
1097       gdb_assert (ti != NULL);
1098       ((struct inf_ttrace_private_thread_info *)ti->private)->dying = 1;
1099       inf_ttrace_num_lwps--;
1100
1101       /* Resume the lwp_terminate-caller thread.  */
1102       ptid = ptid_build (tts.tts_pid, tts.tts_lwpid, 0);
1103       ttrace (TT_LWP_CONTINUE, ptid_get_pid (ptid),
1104               ptid_get_lwp (ptid), TT_NOPC, 0, 0);
1105       /* Return without stopping the whole process.  */
1106       ourstatus->kind = TARGET_WAITKIND_IGNORE;
1107       return ptid;
1108
1109     case TTEVT_SIGNAL:
1110       ourstatus->kind = TARGET_WAITKIND_STOPPED;
1111       ourstatus->value.sig =
1112         target_signal_from_host (tts.tts_u.tts_signal.tts_signo);
1113       break;
1114
1115     case TTEVT_SYSCALL_ENTRY:
1116       gdb_assert (inf_ttrace_reenable_page_protections == 0);
1117       inf_ttrace_num_lwps_in_syscall++;
1118       if (inf_ttrace_num_lwps_in_syscall == 1)
1119         {
1120           /* A thread has just entered a system call.  Disable any
1121              page protections as the kernel can't deal with them.  */
1122           inf_ttrace_disable_page_protections (tts.tts_pid);
1123         }
1124       ourstatus->kind = TARGET_WAITKIND_SYSCALL_ENTRY;
1125       ourstatus->value.syscall_id = tts.tts_scno;
1126       break;
1127
1128     case TTEVT_SYSCALL_RETURN:
1129       if (inf_ttrace_num_lwps_in_syscall > 0)
1130         {
1131           /* If the last thread has just left the system call, this
1132              would be a logical place to re-enable the page
1133              protections, but that doesn't work.  We can't re-enable
1134              them until we've done another wait.  */
1135           inf_ttrace_reenable_page_protections = 
1136             (inf_ttrace_num_lwps_in_syscall == 1);
1137           inf_ttrace_num_lwps_in_syscall--;
1138         }
1139       ourstatus->kind = TARGET_WAITKIND_SYSCALL_RETURN;
1140       ourstatus->value.syscall_id = tts.tts_scno;
1141       break;
1142
1143     default:
1144       gdb_assert (!"Unexpected ttrace event");
1145       break;
1146     }
1147
1148   /* Make sure all threads within the process are stopped.  */
1149   if (ttrace (TT_PROC_STOP, tts.tts_pid, 0, 0, 0, 0) == -1)
1150     perror_with_name (("ttrace"));
1151
1152   /* Now that the whole process is stopped, check if any dying thread
1153      is really dead by now.  If a dying thread is still alive, it will
1154      be stopped too, and will still show up in `info threads', tagged
1155      with "(Exiting)".  We could make `info threads' prune dead
1156      threads instead via inf_ttrace_thread_alive, but doing this here
1157      has the advantage that a frontend is notificed sooner of thread
1158      exits.  Note that a dying lwp is still alive, it still has to be
1159      resumed, like any other lwp.  */
1160   iterate_over_threads (inf_ttrace_delete_dead_threads_callback, NULL);
1161
1162   return ptid;
1163 }
1164
1165 /* Transfer LEN bytes from ADDR in the inferior's memory into READBUF,
1166    and transfer LEN bytes from WRITEBUF into the inferior's memory at
1167    ADDR.  Either READBUF or WRITEBUF may be null, in which case the
1168    corresponding transfer doesn't happen.  Return the number of bytes
1169    actually transferred (which may be zero if an error occurs).  */
1170
1171 static LONGEST
1172 inf_ttrace_xfer_memory (CORE_ADDR addr, ULONGEST len,
1173                         void *readbuf, const void *writebuf)
1174 {
1175   pid_t pid = ptid_get_pid (inferior_ptid);
1176
1177   /* HP-UX treats text space and data space differently.  GDB however,
1178      doesn't really know the difference.  Therefore we try both.  Try
1179      text space before data space though because when we're writing
1180      into text space the instruction cache might need to be flushed.  */
1181
1182   if (readbuf
1183       && ttrace (TT_PROC_RDTEXT, pid, 0, addr, len, (uintptr_t)readbuf) == -1
1184       && ttrace (TT_PROC_RDDATA, pid, 0, addr, len, (uintptr_t)readbuf) == -1)
1185     return 0;
1186
1187   if (writebuf
1188       && ttrace (TT_PROC_WRTEXT, pid, 0, addr, len, (uintptr_t)writebuf) == -1
1189       && ttrace (TT_PROC_WRDATA, pid, 0, addr, len, (uintptr_t)writebuf) == -1)
1190     return 0;
1191
1192   return len;
1193 }
1194
1195 static LONGEST
1196 inf_ttrace_xfer_partial (struct target_ops *ops, enum target_object object,
1197                          const char *annex, gdb_byte *readbuf,
1198                          const gdb_byte *writebuf, ULONGEST offset, LONGEST len)
1199 {
1200   switch (object)
1201     {
1202     case TARGET_OBJECT_MEMORY:
1203       return inf_ttrace_xfer_memory (offset, len, readbuf, writebuf);
1204
1205     case TARGET_OBJECT_UNWIND_TABLE:
1206       return -1;
1207
1208     case TARGET_OBJECT_AUXV:
1209       return -1;
1210
1211     case TARGET_OBJECT_WCOOKIE:
1212       return -1;
1213
1214     default:
1215       return -1;
1216     }
1217 }
1218
1219 /* Print status information about what we're accessing.  */
1220
1221 static void
1222 inf_ttrace_files_info (struct target_ops *ignore)
1223 {
1224   struct inferior *inf = current_inferior ();
1225   printf_filtered (_("\tUsing the running image of %s %s.\n"),
1226                    inf->attach_flag ? "attached" : "child",
1227                    target_pid_to_str (inferior_ptid));
1228 }
1229
1230 static int
1231 inf_ttrace_thread_alive (ptid_t ptid)
1232 {
1233   return 1;
1234 }
1235
1236 /* Return a string describing the state of the thread specified by
1237    INFO.  */
1238
1239 static char *
1240 inf_ttrace_extra_thread_info (struct thread_info *info)
1241 {
1242   struct inf_ttrace_private_thread_info* private =
1243     (struct inf_ttrace_private_thread_info *) info->private;
1244
1245   if (private != NULL && private->dying)
1246     return "Exiting";
1247
1248   return NULL;
1249 }
1250
1251 static char *
1252 inf_ttrace_pid_to_str (ptid_t ptid)
1253 {
1254   pid_t pid = ptid_get_pid (ptid);
1255   lwpid_t lwpid = ptid_get_lwp (ptid);
1256   static char buf[128];
1257
1258   if (lwpid == 0)
1259     xsnprintf (buf, sizeof buf, "process %ld",
1260                (long) pid);
1261   else
1262     xsnprintf (buf, sizeof buf, "process %ld, lwp %ld",
1263                (long) pid, (long) lwpid);
1264   return buf;
1265 }
1266 \f
1267
1268 struct target_ops *
1269 inf_ttrace_target (void)
1270 {
1271   struct target_ops *t = inf_child_target ();
1272
1273   t->to_attach = inf_ttrace_attach;
1274   t->to_detach = inf_ttrace_detach;
1275   t->to_resume = inf_ttrace_resume;
1276   t->to_wait = inf_ttrace_wait;
1277   t->to_files_info = inf_ttrace_files_info;
1278   t->to_can_use_hw_breakpoint = inf_ttrace_can_use_hw_breakpoint;
1279   t->to_insert_watchpoint = inf_ttrace_insert_watchpoint;
1280   t->to_remove_watchpoint = inf_ttrace_remove_watchpoint;
1281   t->to_stopped_by_watchpoint = inf_ttrace_stopped_by_watchpoint;
1282   t->to_region_ok_for_hw_watchpoint =
1283     inf_ttrace_region_ok_for_hw_watchpoint;
1284   t->to_kill = inf_ttrace_kill;
1285   t->to_create_inferior = inf_ttrace_create_inferior;
1286   t->to_follow_fork = inf_ttrace_follow_fork;
1287   t->to_mourn_inferior = inf_ttrace_mourn_inferior;
1288   t->to_thread_alive = inf_ttrace_thread_alive;
1289   t->to_extra_thread_info = inf_ttrace_extra_thread_info;
1290   t->to_pid_to_str = inf_ttrace_pid_to_str;
1291   t->to_xfer_partial = inf_ttrace_xfer_partial;
1292
1293   ttrace_ops_hack = t;
1294   return t;
1295 }
1296 #endif
1297 \f
1298
1299 /* Prevent warning from -Wmissing-prototypes.  */
1300 void _initialize_hppa_hpux_nat (void);
1301
1302 void
1303 _initialize_inf_ttrace (void)
1304 {
1305 #ifdef HAVE_TTRACE
1306   inf_ttrace_page_dict.pagesize = getpagesize();
1307 #endif
1308 }