* hppa-hpux-tdep.c: Update copyright notice and year.
[deliverable/binutils-gdb.git] / gdb / inf-ttrace.c
CommitLineData
eee22bf8
MK
1/* Low-level child interface to ttrace.
2
3 Copyright 2004 Free Software Foundation, Inc.
4
5 This file is part of GDB.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
21
22#include "defs.h"
23
24/* The ttrace(2) system call didn't exist before HP-UX 10.30. Don't
25 try to compile this code unless we have it. */
26#ifdef HAVE_TTRACE
27
28#include "command.h"
29#include "gdbcore.h"
30#include "inferior.h"
31#include "observer.h"
32#include "target.h"
33
34#include "gdb_assert.h"
35#include "gdb_string.h"
932936f0 36#include <sys/mman.h>
eee22bf8
MK
37#include <sys/ttrace.h>
38
39#include "inf-child.h"
40#include "inf-ttrace.h"
41
42/* HACK: Save the ttrace ops returned by inf_ttrace_target. */
43static struct target_ops *ttrace_ops_hack;
932936f0
MK
44\f
45
46/* On HP-UX versions that have the ttrace(2) system call, we can
47 implement "hardware" watchpoints by fiddling with the protection of
48 pages in the address space that contain the variable being watched.
49 In order to implement this, we keep a dictionary of pages for which
50 we have changed the protection. */
51
52struct inf_ttrace_page
53{
54 CORE_ADDR addr; /* Page address. */
55 int prot; /* Protection. */
56 int refcount; /* Reference count. */
57 struct inf_ttrace_page *next;
58 struct inf_ttrace_page *prev;
59};
60
61struct inf_ttrace_page_dict
62{
63 struct inf_ttrace_page buckets[128];
64 int pagesize; /* Page size. */
65 int count; /* Number of pages in this dictionary. */
66} inf_ttrace_page_dict;
67
68/* Number of threads that are currently in a system call. */
69static int inf_ttrace_num_threads_in_syscall;
70
71/* Flag to indicate whether we should re-enable page protections after
72 the next wait. */
73static int inf_ttrace_reenable_page_protections;
74
75/* Enable system call events for process PID. */
76
77static void
78inf_ttrace_enable_syscall_events (pid_t pid)
79{
80 ttevent_t tte;
81 ttstate_t tts;
82
83 gdb_assert (inf_ttrace_num_threads_in_syscall == 0);
84
85 if (ttrace (TT_PROC_GET_EVENT_MASK, pid, 0,
86 (uintptr_t)&tte, sizeof tte, 0) == -1)
87 perror_with_name ("ttrace");
88
89 tte.tte_events |= (TTEVT_SYSCALL_ENTRY | TTEVT_SYSCALL_RETURN);
90
91 if (ttrace (TT_PROC_SET_EVENT_MASK, pid, 0,
92 (uintptr_t)&tte, sizeof tte, 0) == -1)
93 perror_with_name ("ttrace");
94
95 if (ttrace (TT_PROC_GET_FIRST_LWP_STATE, pid, 0,
96 (uintptr_t)&tts, sizeof tts, 0) == -1)
97 perror_with_name ("ttrace");
98
99 if (tts.tts_flags & TTS_INSYSCALL)
100 inf_ttrace_num_threads_in_syscall++;
101
102 /* FIXME: Handle multiple threads. */
103}
104
105/* Disable system call events for process PID. */
106
107static void
108inf_ttrace_disable_syscall_events (pid_t pid)
109{
110 ttevent_t tte;
111
112 gdb_assert (inf_ttrace_page_dict.count == 0);
113
114 if (ttrace (TT_PROC_GET_EVENT_MASK, pid, 0,
115 (uintptr_t)&tte, sizeof tte, 0) == -1)
116 perror_with_name ("ttrace");
117
118 tte.tte_events &= ~(TTEVT_SYSCALL_ENTRY | TTEVT_SYSCALL_RETURN);
119
120 if (ttrace (TT_PROC_SET_EVENT_MASK, pid, 0,
121 (uintptr_t)&tte, sizeof tte, 0) == -1)
122 perror_with_name ("ttrace");
123
124 inf_ttrace_num_threads_in_syscall = 0;
125}
126
127/* Get information about the page at address ADDR for process PID from
128 the dictionary. */
129
130static struct inf_ttrace_page *
131inf_ttrace_get_page (pid_t pid, CORE_ADDR addr)
132{
133 const int num_buckets = ARRAY_SIZE (inf_ttrace_page_dict.buckets);
134 const int pagesize = inf_ttrace_page_dict.pagesize;
135 int bucket;
136 struct inf_ttrace_page *page;
137
138 bucket = (addr / pagesize) % num_buckets;
139 page = &inf_ttrace_page_dict.buckets[bucket];
140 while (page)
141 {
142 if (page->addr == addr)
143 break;
144
145 page = page->next;
146 }
147
148 return page;
149}
150
151/* Add the page at address ADDR for process PID to the dictionary. */
152
153static struct inf_ttrace_page *
154inf_ttrace_add_page (pid_t pid, CORE_ADDR addr)
155{
156 const int num_buckets = ARRAY_SIZE (inf_ttrace_page_dict.buckets);
157 const int pagesize = inf_ttrace_page_dict.pagesize;
158 int bucket;
159 struct inf_ttrace_page *page;
160 struct inf_ttrace_page *prev = NULL;
161
162 bucket = (addr / pagesize) % num_buckets;
163 page = &inf_ttrace_page_dict.buckets[bucket];
164 while (page)
165 {
166 if (page->addr == addr)
167 break;
168
169 prev = page;
170 page = page->next;
171 }
172
173 if (!page)
174 {
175 int prot;
176
177 if (ttrace (TT_PROC_GET_MPROTECT, pid, 0,
178 addr, 0, (uintptr_t)&prot) == -1)
179 perror_with_name ("ttrace");
180
181 page = XMALLOC (struct inf_ttrace_page);
182 page->addr = addr;
183 page->prot = prot;
184 page->refcount = 0;
185 page->next = NULL;
186
187 page->prev = prev;
188 prev->next = page;
189
190 inf_ttrace_page_dict.count++;
191 if (inf_ttrace_page_dict.count == 1)
192 inf_ttrace_enable_syscall_events (pid);
193
194 if (inf_ttrace_num_threads_in_syscall == 0)
195 {
196 if (ttrace (TT_PROC_SET_MPROTECT, pid, 0,
197 addr, pagesize, prot & ~PROT_WRITE) == -1)
198 perror_with_name ("ttrace");
199 }
200 }
201
202 return page;
203}
204
205/* Insert the page at address ADDR of process PID to the dictionary. */
206
207static void
208inf_ttrace_insert_page (pid_t pid, CORE_ADDR addr)
209{
210 struct inf_ttrace_page *page;
211
212 page = inf_ttrace_get_page (pid, addr);
213 if (!page)
214 page = inf_ttrace_add_page (pid, addr);
215
216 page->refcount++;
217}
218
219/* Remove the page at address ADDR of process PID from the dictionary. */
220
221static void
222inf_ttrace_remove_page (pid_t pid, CORE_ADDR addr)
223{
224 const int pagesize = inf_ttrace_page_dict.pagesize;
225 struct inf_ttrace_page *page;
226
227 page = inf_ttrace_get_page (pid, addr);
228 page->refcount--;
229
230 gdb_assert (page->refcount >= 0);
231
232 if (page->refcount == 0)
233 {
234 if (inf_ttrace_num_threads_in_syscall == 0)
235 {
236 if (ttrace (TT_PROC_SET_MPROTECT, pid, 0,
237 addr, pagesize, page->prot) == -1)
238 perror_with_name ("ttrace");
239 }
240
241 inf_ttrace_page_dict.count--;
242 if (inf_ttrace_page_dict.count == 0)
243 inf_ttrace_disable_syscall_events (pid);
244
245 page->prev->next = page->next;
246 if (page->next)
247 page->next->prev = page->prev;
248
249 xfree (page);
250 }
251}
252
253/* Mask the bits in PROT from the page protections that are currently
254 in the dictionary for process PID. */
255
256static void
257inf_ttrace_mask_page_protections (pid_t pid, int prot)
258{
259 const int num_buckets = ARRAY_SIZE (inf_ttrace_page_dict.buckets);
260 const int pagesize = inf_ttrace_page_dict.pagesize;
261 int bucket;
262
263 for (bucket = 0; bucket < num_buckets; bucket++)
264 {
265 struct inf_ttrace_page *page;
266
267 page = inf_ttrace_page_dict.buckets[bucket].next;
268 while (page)
269 {
270 if (ttrace (TT_PROC_SET_MPROTECT, pid, 0,
271 page->addr, pagesize, page->prot & ~prot) == -1)
272 perror_with_name ("ttrace");
273
274 page = page->next;
275 }
276 }
277}
278
279/* Write-protect the pages in the dictionary for process PID. */
280
281static void
282inf_ttrace_enable_page_protections (pid_t pid)
283{
284 inf_ttrace_mask_page_protections (pid, PROT_WRITE);
285}
286
287/* Restore the protection of the pages in the dictionary for process
288 PID. */
289
290static void
291inf_ttrace_disable_page_protections (pid_t pid)
292{
293 inf_ttrace_mask_page_protections (pid, 0);
294}
295
296/* Insert a "hardware" watchpoint for LEN bytes at address ADDR of
297 type TYPE. */
298
299static int
300inf_ttrace_insert_watchpoint (CORE_ADDR addr, int len, int type)
301{
302 const int pagesize = inf_ttrace_page_dict.pagesize;
303 pid_t pid = ptid_get_pid (inferior_ptid);
304 CORE_ADDR page_addr;
305 int num_pages;
306 int page;
307
308 gdb_assert (type == hw_write);
309
310 page_addr = (addr / pagesize) * pagesize;
311 num_pages = (len + pagesize - 1) / pagesize;
312
313 for (page = 0; page < num_pages; page++, page_addr += pagesize)
314 inf_ttrace_insert_page (pid, page_addr);
315
316 return 1;
317}
318
319/* Remove a "hardware" watchpoint for LEN bytes at address ADDR of
320 type TYPE. */
321
322static int
323inf_ttrace_remove_watchpoint (CORE_ADDR addr, int len, int type)
324{
325 const int pagesize = inf_ttrace_page_dict.pagesize;
326 pid_t pid = ptid_get_pid (inferior_ptid);
327 CORE_ADDR page_addr;
328 int num_pages;
329 int page;
330
331 gdb_assert (type == hw_write);
332
333 page_addr = (addr / pagesize) * pagesize;
334 num_pages = (len + pagesize - 1) / pagesize;
335
336 for (page = 0; page < num_pages; page++, page_addr += pagesize)
337 inf_ttrace_remove_page (pid, page_addr);
338
339 return 1;
340}
341
342static int
343inf_ttrace_can_use_hw_breakpoint (int type, int len, int ot)
344{
345 return (type == bp_hardware_watchpoint);
346}
347
348static int
349inf_ttrace_region_size_ok_for_hw_watchpoint (int len)
350{
351 return 1;
352}
353
354/* Return non-zero if the current inferior was (potentially) stopped
355 by hitting a "hardware" watchpoint. */
356
357static int
358inf_ttrace_stopped_by_watchpoint (void)
359{
360 pid_t pid = ptid_get_pid (inferior_ptid);
361 lwpid_t lwpid = ptid_get_lwp (inferior_ptid);
362 ttstate_t tts;
363
364 if (inf_ttrace_page_dict.count > 0)
365 {
366 if (ttrace (TT_LWP_GET_STATE, pid, lwpid,
367 (uintptr_t)&tts, sizeof tts, 0) == -1)
368 perror_with_name ("ttrace");
369
370 if (tts.tts_event == TTEVT_SIGNAL
371 && tts.tts_u.tts_signal.tts_signo == SIGBUS)
372 {
373 const int pagesize = inf_ttrace_page_dict.pagesize;
374 void *addr = tts.tts_u.tts_signal.tts_siginfo.si_addr;
375 CORE_ADDR page_addr = ((uintptr_t)addr / pagesize) * pagesize;
376
377 if (inf_ttrace_get_page (pid, page_addr))
378 return 1;
379 }
380 }
381
382 return 0;
383}
384\f
eee22bf8
MK
385
386/* File descriptors for pipes used as semaphores during initial
387 startup of an inferior. */
388static int inf_ttrace_pfd1[2];
389static int inf_ttrace_pfd2[2];
390
391static void
392do_cleanup_pfds (void *dummy)
393{
394 close (inf_ttrace_pfd1[0]);
395 close (inf_ttrace_pfd1[1]);
396 close (inf_ttrace_pfd2[0]);
397 close (inf_ttrace_pfd2[1]);
398}
399
400static void
401inf_ttrace_prepare (void)
402{
403 if (pipe (inf_ttrace_pfd1) == -1)
404 perror_with_name ("pipe");
405
406 if (pipe (inf_ttrace_pfd2) == -1)
407 {
408 close (inf_ttrace_pfd1[0]);
409 close (inf_ttrace_pfd2[0]);
410 perror_with_name ("pipe");
411 }
412}
413
414/* Prepare to be traced. */
415
416static void
417inf_ttrace_me (void)
418{
419 struct cleanup *old_chain = make_cleanup (do_cleanup_pfds, 0);
420 char c;
421
422 /* "Trace me, Dr. Memory!" */
423 if (ttrace (TT_PROC_SETTRC, 0, 0, 0, TT_VERSION, 0) == -1)
424 perror_with_name ("ttrace");
425
426 /* Tell our parent that we are ready to be traced. */
427 if (write (inf_ttrace_pfd1[1], &c, sizeof c) != sizeof c)
428 perror_with_name ("write");
429
430 /* Wait until our parent has set the initial event mask. */
431 if (read (inf_ttrace_pfd2[0], &c, sizeof c) != sizeof c)
432 perror_with_name ("read");
433
434 do_cleanups (old_chain);
435}
436
437/* Start tracing PID. */
438
439static void
440inf_ttrace_him (int pid)
441{
442 struct cleanup *old_chain = make_cleanup (do_cleanup_pfds, 0);
443 ttevent_t tte;
eee22bf8
MK
444 char c;
445
446 /* Wait until our child is ready to be traced. */
447 if (read (inf_ttrace_pfd1[0], &c, sizeof c) != sizeof c)
448 perror_with_name ("read");
449
450 /* Set the initial event mask. */
451 memset (&tte, 0, sizeof (tte));
452 tte.tte_events = TTEVT_EXEC | TTEVT_EXIT;
453 tte.tte_opts = TTEO_NOSTRCCHLD;
454 if (ttrace (TT_PROC_SET_EVENT_MASK, pid, 0,
455 (uintptr_t)&tte, sizeof tte, 0) == -1)
456 perror_with_name ("ttrace");
457
458 /* Tell our child that we have set the initial event mask. */
459 if (write (inf_ttrace_pfd2[1], &c, sizeof c) != sizeof c)
460 perror_with_name ("write");
461
462 do_cleanups (old_chain);
463
464 push_target (ttrace_ops_hack);
465
466 /* On some targets, there must be some explicit synchronization
467 between the parent and child processes after the debugger forks,
468 and before the child execs the debuggee program. This call
469 basically gives permission for the child to exec. */
470
471 target_acknowledge_created_inferior (pid);
472
473 /* START_INFERIOR_TRAPS_EXPECTED is defined in inferior.h, and will
474 be 1 or 2 depending on whether we're starting without or with a
475 shell. */
476 startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
477
478 /* On some targets, there must be some explicit actions taken after
479 the inferior has been started up. */
480 target_post_startup_inferior (pid_to_ptid (pid));
481}
482
483static void
484inf_ttrace_create_inferior (char *exec_file, char *allargs, char **env,
485 int from_tty)
486{
932936f0
MK
487 gdb_assert (inf_ttrace_page_dict.count == 0);
488 gdb_assert (inf_ttrace_num_threads_in_syscall == 0);
489 gdb_assert (inf_ttrace_reenable_page_protections == 0);
490
eee22bf8
MK
491 fork_inferior (exec_file, allargs, env, inf_ttrace_me, inf_ttrace_him,
492 inf_ttrace_prepare, NULL);
493
494 /* We are at the first instruction we care about. */
495 observer_notify_inferior_created (&current_target, from_tty);
496
497 /* Pedal to the metal... */
498 proceed ((CORE_ADDR) -1, TARGET_SIGNAL_0, 0);
499}
500
501static void
502inf_ttrace_kill_inferior (void)
503{
504 pid_t pid = ptid_get_pid (inferior_ptid);
505
506 if (pid == 0)
507 return;
508
509 if (ttrace (TT_PROC_EXIT, pid, 0, 0, 0, 0) == -1)
510 perror_with_name ("ttrace");
511 /* ??? Is it necessary to call ttrace_wait() here? */
512 target_mourn_inferior ();
513}
514
515static void
516inf_ttrace_mourn_inferior (void)
517{
932936f0
MK
518 const int num_buckets = ARRAY_SIZE (inf_ttrace_page_dict.buckets);
519 int bucket;
520
521 inf_ttrace_num_threads_in_syscall = 0;
522
523 for (bucket = 0; bucket < num_buckets; bucket++)
524 {
525 struct inf_ttrace_page *page;
526 struct inf_ttrace_page *next;
527
528 page = inf_ttrace_page_dict.buckets[bucket].next;
529 while (page)
530 {
531 next = page->next;
532 xfree (page);
533 page = next;
534 }
535 }
536 inf_ttrace_page_dict.count = 0;
537
eee22bf8
MK
538 unpush_target (ttrace_ops_hack);
539 generic_mourn_inferior ();
540}
541
542static void
543inf_ttrace_attach (char *args, int from_tty)
544{
545 char *exec_file;
546 pid_t pid;
547 char *dummy;
932936f0 548 ttevent_t tte;
eee22bf8
MK
549
550 if (!args)
551 error_no_arg ("process-id to attach");
552
553 dummy = args;
554 pid = strtol (args, &dummy, 0);
555 if (pid == 0 && args == dummy)
556 error ("Illegal process-id: %s\n", args);
557
558 if (pid == getpid ()) /* Trying to masturbate? */
559 error ("I refuse to debug myself!");
560
561 if (from_tty)
562 {
563 exec_file = (char *) get_exec_file (0);
564
565 if (exec_file)
566 printf_unfiltered ("Attaching to program: %s, %s\n", exec_file,
567 target_pid_to_str (pid_to_ptid (pid)));
568 else
569 printf_unfiltered ("Attaching to %s\n",
570 target_pid_to_str (pid_to_ptid (pid)));
571
572 gdb_flush (gdb_stdout);
573 }
574
575 if (ttrace (TT_PROC_ATTACH, pid, 0, TT_KILL_ON_EXIT, TT_VERSION, 0) == -1)
576 perror_with_name ("ttrace");
577 attach_flag = 1;
578
932936f0
MK
579 /* Set the initial event mask. */
580 gdb_assert (inf_ttrace_num_threads_in_syscall == 0);
581 memset (&tte, 0, sizeof (tte));
582 tte.tte_events = TTEVT_EXEC | TTEVT_EXIT;
583 tte.tte_opts = TTEO_NOSTRCCHLD;
584 if (ttrace (TT_PROC_SET_EVENT_MASK, pid, 0,
585 (uintptr_t)&tte, sizeof tte, 0) == -1)
586 perror_with_name ("ttrace");
587
eee22bf8
MK
588 inferior_ptid = pid_to_ptid (pid);
589 push_target (ttrace_ops_hack);
590
591 /* Do this first, before anything has had a chance to query the
592 inferior's symbol table or similar. */
593 observer_notify_inferior_created (&current_target, from_tty);
594}
595
596static void
597inf_ttrace_detach (char *args, int from_tty)
598{
599 int sig = 0;
600 pid_t pid = ptid_get_pid (inferior_ptid);
601
602 if (from_tty)
603 {
604 char *exec_file = get_exec_file (0);
605 if (exec_file == 0)
606 exec_file = "";
607 printf_unfiltered ("Detaching from program: %s, %s\n", exec_file,
608 target_pid_to_str (pid_to_ptid (pid)));
609 gdb_flush (gdb_stdout);
610 }
611 if (args)
612 sig = atoi (args);
613
614 /* ??? The HP-UX 11.0 ttrace(2) manual page doesn't mention that we
615 can pass a signal number here. Does this really work? */
616 if (ttrace (TT_PROC_DETACH, pid, 0, 0, sig, 0) == -1)
617 perror_with_name ("ttrace");
618
932936f0
MK
619 inf_ttrace_num_threads_in_syscall = 0;
620
eee22bf8 621 unpush_target (ttrace_ops_hack);
932936f0 622 inferior_ptid = null_ptid;
eee22bf8
MK
623}
624
625static void
626inf_ttrace_resume (ptid_t ptid, int step, enum target_signal signal)
627{
628 pid_t pid = ptid_get_pid (ptid);
629 lwpid_t lwpid = ptid_get_lwp (ptid);
630 ttreq_t request = step ? TT_LWP_SINGLE : TT_LWP_CONTINUE;
631 int sig = target_signal_to_host (signal);
632
633 if (pid == -1)
634 {
635 pid = ptid_get_pid (inferior_ptid);
636 lwpid = ptid_get_lwp (inferior_ptid);
637 }
638
639 if (ttrace (request, pid, lwpid, TT_NOPC, sig, 0) == -1)
640 perror_with_name ("ttrace");
641
642 if (ptid_equal (ptid, minus_one_ptid))
643 {
644 /* Let all the other threads run too. */
645 if (ttrace (TT_PROC_CONTINUE, pid, 0, 0, 0, 0) == -1)
646 perror_with_name ("ttrace");
647 }
648}
649
650static ptid_t
651inf_ttrace_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
652{
653 pid_t pid = ptid_get_pid (ptid);
654 lwpid_t lwpid = ptid_get_lwp (ptid);
655 ttstate_t tts;
656
932936f0 657 /* Until proven otherwise. */
eee22bf8
MK
658 ourstatus->kind = TARGET_WAITKIND_IGNORE;
659
660 if (pid == -1)
661 pid = 0;
662
663 gdb_assert (lwpid == 0 || pid != 0);
664
665 do
666 {
667 set_sigint_trap ();
668 set_sigio_trap ();
669
670 if (ttrace_wait (pid, lwpid, TTRACE_WAITOK, &tts, sizeof tts) == -1)
671 perror_with_name ("ttrace_wait");
672
673 clear_sigio_trap ();
674 clear_sigint_trap ();
675 }
676 while (tts.tts_event == TTEVT_NONE);
677
932936f0
MK
678 /* Now that we've waited, we can re-enable the page protections. */
679 if (inf_ttrace_reenable_page_protections)
680 {
681 gdb_assert (inf_ttrace_num_threads_in_syscall == 0);
682 inf_ttrace_enable_page_protections (tts.tts_pid);
683 inf_ttrace_reenable_page_protections = 0;
684 }
685
eee22bf8
MK
686 switch (tts.tts_event)
687 {
688 case TTEVT_EXEC:
689 /* Make it look like a breakpoint. */
690 ourstatus->kind = TARGET_WAITKIND_STOPPED;
691 ourstatus->value.sig = TARGET_SIGNAL_TRAP;
692 break;
932936f0 693
eee22bf8
MK
694 case TTEVT_EXIT:
695 store_waitstatus (ourstatus, tts.tts_u.tts_exit.tts_exitcode);
696 break;
932936f0 697
eee22bf8
MK
698 case TTEVT_SIGNAL:
699 ourstatus->kind = TARGET_WAITKIND_STOPPED;
700 ourstatus->value.sig =
701 target_signal_from_host (tts.tts_u.tts_signal.tts_signo);
702 break;
932936f0
MK
703
704 case TTEVT_SYSCALL_ENTRY:
705 gdb_assert (inf_ttrace_reenable_page_protections == 0);
706 inf_ttrace_num_threads_in_syscall++;
707 if (inf_ttrace_num_threads_in_syscall == 1)
708 {
709 /* A thread has just entered a system call. Disable any
710 page protections as the kernel can't deal with them. */
711 inf_ttrace_disable_page_protections (tts.tts_pid);
712 }
713 ourstatus->kind = TARGET_WAITKIND_SYSCALL_ENTRY;
714 ourstatus->value.syscall_id = tts.tts_scno;
715 break;
716
717 case TTEVT_SYSCALL_RETURN:
718 if (inf_ttrace_num_threads_in_syscall > 0)
719 {
720 /* If the last thread has just left the system call, this
721 would be a logical place to re-enable the page
722 protections, but that doesn't work. We can't re-enable
723 them until we've done another wait. */
724 inf_ttrace_reenable_page_protections =
725 (inf_ttrace_num_threads_in_syscall == 1);
726 inf_ttrace_num_threads_in_syscall--;
727 }
728 ourstatus->kind = TARGET_WAITKIND_SYSCALL_RETURN;
729 ourstatus->value.syscall_id = tts.tts_scno;
730 break;
eee22bf8
MK
731 }
732
733 /* Make sure all threads within the process are stopped. */
734 if (ttrace (TT_PROC_STOP, tts.tts_pid, 0, 0, 0, 0) == -1)
735 perror_with_name ("ttrace");
736
737 /* HACK: Twiddle INFERIOR_PTID such that the initial thread of a
738 process isn't recognized as a new thread. */
739 if (ptid_get_lwp (inferior_ptid) == 0)
740 inferior_ptid = ptid_build (tts.tts_pid, tts.tts_lwpid, tts.tts_user_tid);
741
742 return ptid_build (tts.tts_pid, tts.tts_lwpid, tts.tts_user_tid);
743}
744
745/* Transfer LEN bytes from ADDR in the inferior's memory into READBUF,
746 and transfer LEN bytes from WRITEBUF into the inferior's memory at
747 ADDR. Either READBUF or WRITEBUF may be null, in which case the
748 corresponding transfer doesn't happen. Return the number of bytes
749 actually transferred (which may be zero if an error occurs). */
750
751static LONGEST
752inf_ttrace_xfer_memory (CORE_ADDR addr, ULONGEST len,
753 void *readbuf, const void *writebuf)
754{
755 pid_t pid = ptid_get_pid (inferior_ptid);
756
757 /* HP-UX treats text space and data space differently. GDB however,
758 doesn't really know the difference. Therefore we try both. Try
759 text space before data space though because when we're writing
760 into text space the instruction cache might need to be flushed. */
761
762 if (readbuf
763 && ttrace (TT_PROC_RDTEXT, pid, 0, addr, len, (uintptr_t)readbuf) == -1
764 && ttrace (TT_PROC_RDDATA, pid, 0, addr, len, (uintptr_t)readbuf) == -1)
765 return 0;
766
767 if (writebuf
768 && ttrace (TT_PROC_WRTEXT, pid, 0, addr, len, (uintptr_t)writebuf) == -1
769 && ttrace (TT_PROC_WRDATA, pid, 0, addr, len, (uintptr_t)writebuf) == -1)
770 return 0;
771
772 return len;
773}
774
775static LONGEST
776inf_ttrace_xfer_partial (struct target_ops *ops, enum target_object object,
777 const char *annex, void *readbuf,
778 const void *writebuf, ULONGEST offset, LONGEST len)
779{
780 switch (object)
781 {
782 case TARGET_OBJECT_MEMORY:
783 return inf_ttrace_xfer_memory (offset, len, readbuf, writebuf);
784
785 case TARGET_OBJECT_UNWIND_TABLE:
786 return -1;
787
788 case TARGET_OBJECT_AUXV:
789 return -1;
790
791 case TARGET_OBJECT_WCOOKIE:
792 return -1;
793
794 default:
795 return -1;
796 }
797}
798
799/* Print status information about what we're accessing. */
800
801static void
802inf_ttrace_files_info (struct target_ops *ignore)
803{
804 printf_unfiltered ("\tUsing the running image of %s %s.\n",
805 attach_flag ? "attached" : "child",
806 target_pid_to_str (inferior_ptid));
807}
808\f
809
810struct target_ops *
811inf_ttrace_target (void)
812{
813 struct target_ops *t = inf_child_target ();
814
815 t->to_create_inferior = inf_ttrace_create_inferior;
816 t->to_kill = inf_ttrace_kill_inferior;
817 t->to_mourn_inferior = inf_ttrace_mourn_inferior;
818 t->to_attach = inf_ttrace_attach;
819 t->to_detach = inf_ttrace_detach;
820 t->to_resume = inf_ttrace_resume;
821 t->to_wait = inf_ttrace_wait;
822 t->to_xfer_partial = inf_ttrace_xfer_partial;
823 t->to_files_info = inf_ttrace_files_info;
932936f0
MK
824 t->to_can_use_hw_breakpoint = inf_ttrace_can_use_hw_breakpoint;
825 t->to_region_size_ok_for_hw_watchpoint =
826 inf_ttrace_region_size_ok_for_hw_watchpoint;
827 t->to_insert_watchpoint = inf_ttrace_insert_watchpoint;
828 t->to_remove_watchpoint = inf_ttrace_remove_watchpoint;
829 t->to_stopped_by_watchpoint = inf_ttrace_stopped_by_watchpoint;
eee22bf8
MK
830
831 ttrace_ops_hack = t;
832 return t;
833}
932936f0
MK
834\f
835
836/* Prevent warning from -Wmissing-prototypes. */
837void _initialize_hppa_hpux_nat (void);
eee22bf8 838
932936f0
MK
839void
840_initialize_inf_ttrace (void)
841{
842 inf_ttrace_page_dict.pagesize = getpagesize();
843}
eee22bf8 844#endif
This page took 0.053932 seconds and 4 git commands to generate.