1 /* Interface GDB to Mach 3.0 operating systems.
2 (Most) Mach 3.0 related routines live in this file.
4 Copyright (C) 1992 Free Software Foundation, Inc.
6 This file is part of GDB.
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 2 of the License, or
11 (at your option) any later version.
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.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
23 * Author: Jukka Virtanen <jtv@hut.fi>
25 * Helsinki University of Technology
28 * Thanks to my friends who helped with ideas and testing:
30 * Johannes Helander, Antti Louko, Tero Mononen,
31 * jvh@cs.hut.fi alo@hut.fi tmo@cs.hut.fi
33 * Tero Kivinen and Eamonn McManus
34 * kivinen@cs.hut.fi emcmanus@gr.osf.org
41 #include <servers/netname.h>
42 #include <servers/machid.h>
43 #include <mach/message.h>
44 #include <mach/notify.h>
45 #include <mach_error.h>
46 #include <mach/exception.h>
47 #include <mach/vm_attributes.h>
58 #include <servers/machid_lib.h>
60 /* Included only for signal names and NSIG
62 * note: There are many problems in signal handling with
63 * gdb in Mach 3.0 in general.
66 #define SIG_UNKNOWN 0 /* Exception that has no matching unix signal */
71 * Mis-use the struct cproc busy field in the copy of
72 * the cproc in gdb's address space.
74 * This *can* be done otherwise, but I'm too lazy.
75 * (Don't tell anyone :-)
77 #define CPROC_REVERSE_MAP(x) ((x)->busy)
79 /* For cproc and kernel thread mapping */
80 typedef struct gdb_thread
{
86 boolean_t in_emulator
;
91 * Actions for Mach exceptions.
93 * sigmap field maps the exception to corresponding Unix signal.
95 * I do not know how to map the exception to unix signal
96 * if SIG_UNKNOWN is specified.
99 struct exception_list
{
104 } exception_map
[] = {
105 {"not_mach3_exception", FALSE
, TRUE
, SIG_UNKNOWN
},
106 {"EXC_BAD_ACCESS", FALSE
, TRUE
, SIGSEGV
},
107 {"EXC_BAD_INSTRUCTION", FALSE
, TRUE
, SIGILL
},
108 {"EXC_ARITHMETIC", FALSE
, TRUE
, SIGFPE
},
109 {"EXC_EMULATION", FALSE
, TRUE
, SIGEMT
}, /* ??? */
110 {"EXC_SOFTWARE", FALSE
, TRUE
, SIG_UNKNOWN
},
111 {"EXC_BREAKPOINT", FALSE
, FALSE
, SIGTRAP
}
114 /* Mach exception table size */
115 int max_exception
= sizeof(exception_map
)/sizeof(struct exception_list
) - 1;
117 #define MAX_EXCEPTION max_exception
119 WAITTYPE wait_status
;
121 /* If you define this, intercepted bsd server calls will be
122 * dumped while waiting the inferior to EXEC the correct
125 /* #define DUMP_SYSCALL /* debugging interceptor */
127 /* xx_debug() outputs messages if this is nonzero.
128 * If > 1, DUMP_SYSCALL will dump message contents.
132 /* "Temporary" debug stuff */
134 xx_debug (fmt
, a
,b
,c
)
139 message (fmt
, a
, b
, c
);
142 /* This is in libmach.a */
143 extern mach_port_t name_server_port
;
145 /* Set in catch_exception_raise */
146 int stop_exception
, stop_code
, stop_subcode
;
147 int stopped_in_exception
;
149 /* Thread that was the active thread when we stopped */
150 thread_t stop_thread
= MACH_PORT_NULL
;
154 /* Set when task is attached or created */
155 boolean_t emulator_present
= FALSE
;
157 task_t inferior_task
;
158 thread_t current_thread
;
160 /* Exception ports for inferior task */
161 mach_port_t inferior_exception_port
= MACH_PORT_NULL
;
162 mach_port_t inferior_old_exception_port
= MACH_PORT_NULL
;
164 /* task exceptions and notifications */
165 mach_port_t inferior_wait_port_set
= MACH_PORT_NULL
;
166 mach_port_t our_notify_port
= MACH_PORT_NULL
;
168 /* This is "inferior_wait_port_set" when not single stepping, and
169 * "singlestepped_thread_port" when we are single stepping.
171 * This is protected by a cleanup function: discard_single_step()
173 mach_port_t currently_waiting_for
= MACH_PORT_NULL
;
175 /* A port for external messages to gdb.
176 * External in the meaning that they do not come
177 * from the inferior_task, but rather from external
180 * As a debugging feature:
181 * A debugger debugging another debugger can stop the
182 * inferior debugger by the following command sequence
183 * (without running external programs)
185 * (top-gdb) set stop_inferior_gdb ()
188 mach_port_t our_message_port
= MACH_PORT_NULL
;
190 /* For single stepping */
191 mach_port_t thread_exception_port
= MACH_PORT_NULL
;
192 mach_port_t thread_saved_exception_port
= MACH_PORT_NULL
;
193 mach_port_t singlestepped_thread_port
= MACH_PORT_NULL
;
195 /* For machid calls */
196 mach_port_t mid_server
= MACH_PORT_NULL
;
197 mach_port_t mid_auth
= MACH_PORT_NULL
;
199 /* If gdb thinks the inferior task is not suspended, it
200 * must take suspend/abort the threads when it reads the state.
202 int must_suspend_thread
= 0;
204 /* When single stepping, we switch the port that mach_really_wait() listens to.
205 * This cleanup is a guard to prevent the port set from being left to
206 * the singlestepped_thread_port when error() is called.
207 * This is nonzero only when we are single stepping.
209 #define NULL_CLEANUP (struct cleanup *)0
210 struct cleanup
*cleanup_step
= NULL_CLEANUP
;
214 #define MACH_TYPE_EXCEPTION_PORT -1
217 /* Chain of ports to remember requested notifications. */
220 struct port_chain
*next
;
223 int mid
; /* Now only valid with MACH_TYPE_THREAD and */
224 /* MACH_TYPE_THREAD */
226 typedef struct port_chain
*port_chain_t
;
228 /* Room for chain nodes comes from pchain_obstack */
229 struct obstack pchain_obstack
;
230 struct obstack
*port_chain_obstack
= &pchain_obstack
;
232 /* For thread handling */
233 struct obstack Cproc_obstack
;
234 struct obstack
*cproc_obstack
= &Cproc_obstack
;
236 /* the list of notified ports */
237 port_chain_t notify_chain
= (port_chain_t
) NULL
;
240 port_chain_insert (list
, name
, type
)
249 if (! MACH_PORT_VALID (name
))
252 if (type
== MACH_TYPE_TASK
|| type
== MACH_TYPE_THREAD
)
254 if (! MACH_PORT_VALID (mid_server
))
256 message ("Machid server port invalid, can not map port 0x%x to MID",
262 ret
= machid_mach_register (mid_server
, mid_auth
, name
, type
, &mid
);
264 if (ret
!= KERN_SUCCESS
)
266 message ("Can not map name (0x%x) to MID with machid", name
);
272 mid
= 3735928559; /* 0x? :-) */
274 new = (port_chain_t
) obstack_alloc (port_chain_obstack
,
275 sizeof (struct port_chain
));
285 port_chain_delete (list
, elem
)
290 if (list
->port
== elem
)
295 if (list
->next
->port
== elem
)
296 list
->next
= list
->next
->next
; /* GCd with obstack_free() */
304 port_chain_destroy (ostack
)
305 struct obstack
*ostack
;
307 obstack_free (ostack
, 0);
308 obstack_init (ostack
);
312 port_chain_member (list
, elem
)
318 if (list
->port
== elem
)
322 return (port_chain_t
) NULL
;
326 map_port_name_to_mid (name
, type
)
332 if (!MACH_PORT_VALID (name
))
335 elem
= port_chain_member (notify_chain
, name
);
337 if (elem
&& (elem
->type
== type
))
343 if (! MACH_PORT_VALID (mid_server
))
345 message ("Machid server port invalid, can not map port 0x%x to mid",
354 ret
= machid_mach_register (mid_server
, mid_auth
, name
, type
, &mid
);
356 if (ret
!= KERN_SUCCESS
)
358 message ("Can not map name (0x%x) to mid with machid", name
);
365 /* Guard for currently_waiting_for and singlestepped_thread_port */
367 discard_single_step (thread
)
370 currently_waiting_for
= inferior_wait_port_set
;
372 cleanup_step
= NULL_CLEANUP
;
373 if (MACH_PORT_VALID (thread
) && MACH_PORT_VALID (singlestepped_thread_port
))
374 setup_single_step (thread
, FALSE
);
377 setup_single_step (thread
, start_step
)
379 boolean_t start_step
;
383 if (! MACH_PORT_VALID (thread
))
384 error ("Invalid thread supplied to setup_single_step");
389 /* Get the current thread exception port */
390 ret
= thread_get_exception_port (thread
, &teport
);
391 CHK ("Getting thread's exception port", ret
);
395 if (MACH_PORT_VALID (singlestepped_thread_port
))
397 message ("Singlestepped_thread_port (0x%x) is still valid?",
398 singlestepped_thread_port
);
399 singlestepped_thread_port
= MACH_PORT_NULL
;
402 /* If we are already stepping this thread */
403 if (MACH_PORT_VALID (teport
) && teport
== thread_exception_port
)
405 ret
= mach_port_deallocate (mach_task_self (), teport
);
406 CHK ("Could not deallocate thread exception port", ret
);
410 ret
= thread_set_exception_port (thread
, thread_exception_port
);
411 CHK ("Setting exception port for thread", ret
);
413 /* Insert thread exception port to wait port set */
414 ret
= mach_port_move_member (mach_task_self(),
415 thread_exception_port
,
416 inferior_wait_port_set
);
417 CHK ("Moving thread exception port to inferior_wait_port_set",
420 thread_saved_exception_port
= teport
;
423 thread_trace (thread
, TRUE
);
425 singlestepped_thread_port
= thread_exception_port
;
426 currently_waiting_for
= singlestepped_thread_port
;
427 cleanup_step
= make_cleanup (discard_single_step
, thread
);
431 if (! MACH_PORT_VALID (teport
))
432 error ("Single stepped thread had an invalid exception port?");
434 if (teport
!= thread_exception_port
)
435 error ("Single stepped thread had an unknown exception port?");
437 ret
= mach_port_deallocate (mach_task_self (), teport
);
438 CHK ("Couldn't deallocate thread exception port", ret
);
440 /* Remove thread exception port from wait port set */
441 ret
= mach_port_move_member (mach_task_self(),
442 thread_exception_port
,
444 CHK ("Removing thread exception port from inferior_wait_port_set",
447 /* Restore thread's old exception port */
448 ret
= thread_set_exception_port (thread
,
449 thread_saved_exception_port
);
450 CHK ("Restoring stepped thread's exception port", ret
);
452 if (MACH_PORT_VALID (thread_saved_exception_port
))
453 (void) mach_port_deallocate (mach_task_self (),
454 thread_saved_exception_port
);
456 thread_trace (thread
, FALSE
);
458 singlestepped_thread_port
= MACH_PORT_NULL
;
459 currently_waiting_for
= inferior_wait_port_set
;
461 discard_cleanups (cleanup_step
);
467 request_notify (name
, variant
, type
)
469 mach_msg_id_t variant
;
473 mach_port_t previous_port_dummy
= MACH_PORT_NULL
;
475 if (! MACH_PORT_VALID (name
))
478 if (port_chain_member (notify_chain
, name
))
481 ret
= mach_port_request_notification (mach_task_self(),
486 MACH_MSG_TYPE_MAKE_SEND_ONCE
,
487 &previous_port_dummy
);
488 CHK ("Serious: request_notify failed", ret
);
490 (void) mach_port_deallocate (mach_task_self (),
491 previous_port_dummy
);
493 notify_chain
= port_chain_insert (notify_chain
, name
, type
);
496 reverse_msg_bits(msgp
, type
)
497 mach_msg_header_t
*msgp
;
501 rbits
= MACH_MSGH_BITS_REMOTE(msgp
->msgh_bits
);
504 (msgp
->msgh_bits
& ~MACH_MSGH_BITS_PORTS_MASK
) |
505 MACH_MSGH_BITS(lbits
,rbits
);
508 /* On the third day He said:
511 and then it was global.
513 When creating the inferior fork, the
514 child code in inflow.c sets the name of the
515 bootstrap_port in its address space to this
518 The name is transferred to our address space
519 with mach3_read_inferior().
521 Thou shalt not do this with
522 task_get_bootstrap_port() in this task, since
523 the name in the inferior task is different than
526 For blessed are the meek, as they shall inherit
529 mach_port_t original_server_port_name
= MACH_PORT_NULL
;
532 /* Called from inferior after FORK but before EXEC */
538 /* Get the NAME of the bootstrap port in this task
539 so that GDB can read it */
540 ret
= task_get_bootstrap_port (mach_task_self (),
541 &original_server_port_name
);
542 if (ret
!= KERN_SUCCESS
)
544 ret
= mach_port_deallocate (mach_task_self (),
545 original_server_port_name
);
546 if (ret
!= KERN_SUCCESS
)
549 /* Suspend this task to let the parent change my ports.
550 Resumed by the debugger */
551 ret
= task_suspend (mach_task_self ());
552 if (ret
!= KERN_SUCCESS
)
557 * Intercept system calls to Unix server.
558 * After EXEC_COUNTER calls to exec(), return.
560 * Pre-assertion: Child is suspended. (Not verified)
561 * Post-condition: Child is suspended after EXEC_COUNTER exec() calls.
565 intercept_exec_calls (exec_counter
)
568 struct syscall_msg_t
{
569 mach_msg_header_t header
;
570 mach_msg_type_t type
;
571 char room
[ 2000 ]; /* Enuff space */
574 struct syscall_msg_t syscall_in
, syscall_out
;
576 mach_port_t fake_server
;
577 mach_port_t original_server_send
;
578 mach_port_t original_exec_reply
;
579 mach_port_t exec_reply
;
580 mach_port_t exec_reply_send
;
581 mach_msg_type_name_t acquired
;
582 mach_port_t emulator_server_port_name
;
583 struct task_basic_info info
;
584 mach_msg_type_number_t info_count
;
588 if (exec_counter
<= 0)
589 return; /* We are already set up in the correct program */
591 ret
= mach_port_allocate(mach_task_self(),
592 MACH_PORT_RIGHT_RECEIVE
,
594 CHK("create inferior_fake_server port failed", ret
);
596 /* Wait for inferior_task to suspend itself */
599 info_count
= sizeof (info
);
600 ret
= task_info (inferior_task
,
604 CHK ("Task info", ret
);
606 if (info
.suspend_count
)
609 /* Note that the definition of the parameter was undefined
610 * at the time of this writing, so I just use an `ad hoc' value.
612 (void) swtch_pri (42); /* Universal Priority Value */
615 /* Read the inferior's bootstrap port name */
616 if (!mach3_read_inferior (&original_server_port_name
,
617 &original_server_port_name
,
618 sizeof (original_server_port_name
)))
619 error ("Can't read inferior task bootstrap port name");
621 /* @@ BUG: If more than 1 send right GDB will FAIL!!! */
622 /* Should get refs, and set them back when restoring */
623 /* Steal the original bsd server send right from inferior */
624 ret
= mach_port_extract_right (inferior_task
,
625 original_server_port_name
,
626 MACH_MSG_TYPE_MOVE_SEND
,
627 &original_server_send
,
629 CHK("mach_port_extract_right (bsd server send)",ret
);
631 if (acquired
!= MACH_MSG_TYPE_PORT_SEND
)
632 error("Incorrect right extracted, send right to bsd server excpected");
634 ret
= mach_port_insert_right (inferior_task
,
635 original_server_port_name
,
637 MACH_MSG_TYPE_MAKE_SEND
);
638 CHK("mach_port_insert_right (fake server send)",ret
);
640 xx_debug ("inferior task bsd server ports set up \nfs %x, ospn %x, oss %x\n",
642 original_server_port_name
, original_server_send
);
644 /* A receive right to the reply generated by unix server exec() request */
645 ret
= mach_port_allocate(mach_task_self(),
646 MACH_PORT_RIGHT_RECEIVE
,
648 CHK("create intercepted_reply_port port failed", ret
);
650 /* Pass this send right to Unix server so it replies to us after exec() */
651 ret
= mach_port_extract_right (mach_task_self (),
653 MACH_MSG_TYPE_MAKE_SEND_ONCE
,
656 CHK("mach_port_extract_right (exec_reply)",ret
);
658 if (acquired
!= MACH_MSG_TYPE_PORT_SEND_ONCE
)
659 error("Incorrect right extracted, send once excpected for exec reply");
661 ret
= mach_port_move_member(mach_task_self(),
663 inferior_wait_port_set
);
664 CHK ("Moving fake syscall port to inferior_wait_port_set", ret
);
666 xx_debug ("syscall fake server set up, resuming inferior\n");
668 ret
= task_resume (inferior_task
);
669 CHK("task_resume (startup)", ret
);
671 /* Read requests from the inferior.
672 Pass directly through everything else except exec() calls.
674 while(exec_counter
> 0)
676 ret
= mach_msg (&syscall_in
.header
, /* header */
677 MACH_RCV_MSG
, /* options */
679 sizeof (struct syscall_msg_t
), /* receive size */
680 inferior_wait_port_set
, /* receive_name */
681 MACH_MSG_TIMEOUT_NONE
,
683 CHK("mach_msg (intercepted sycall)", ret
);
686 print_msg (&syscall_in
.header
);
689 /* ASSERT : msgh_local_port == fake_server */
691 if (notify_server (&syscall_in
.header
, &syscall_out
.header
))
692 error ("received a notify while intercepting syscalls");
694 if (syscall_in
.header
.msgh_id
== MIG_EXEC_SYSCALL_ID
)
696 xx_debug ("Received EXEC SYSCALL, counter = %d\n", exec_counter
);
697 if (exec_counter
== 1)
699 original_exec_reply
= syscall_in
.header
.msgh_remote_port
;
700 syscall_in
.header
.msgh_remote_port
= exec_reply_send
;
705 syscall_in
.header
.msgh_local_port
= syscall_in
.header
.msgh_remote_port
;
706 syscall_in
.header
.msgh_remote_port
= original_server_send
;
708 reverse_msg_bits(&syscall_in
.header
, MACH_MSG_TYPE_COPY_SEND
);
710 ret
= mach_msg_send (&syscall_in
.header
);
711 CHK ("Forwarded syscall", ret
);
714 ret
= mach_port_move_member(mach_task_self(),
717 CHK ("Moving fake syscall out of inferior_wait_port_set", ret
);
719 ret
= mach_port_move_member(mach_task_self(),
721 inferior_wait_port_set
);
722 CHK ("Moving exec_reply to inferior_wait_port_set", ret
);
724 ret
= mach_msg (&syscall_in
.header
, /* header */
725 MACH_RCV_MSG
, /* options */
727 sizeof (struct syscall_msg_t
), /* receive size */
728 inferior_wait_port_set
, /* receive_name */
729 MACH_MSG_TIMEOUT_NONE
,
731 CHK("mach_msg (exec reply)", ret
);
733 ret
= task_suspend (inferior_task
);
734 CHK ("Suspending inferior after last exec", ret
);
736 must_suspend_thread
= 0;
738 xx_debug ("Received exec reply from bsd server, suspended inferior task\n");
741 print_msg (&syscall_in
.header
);
744 /* Message should appear as if it came from the unix server */
745 syscall_in
.header
.msgh_local_port
= MACH_PORT_NULL
;
747 /* and go to the inferior task original reply port */
748 syscall_in
.header
.msgh_remote_port
= original_exec_reply
;
750 reverse_msg_bits(&syscall_in
.header
, MACH_MSG_TYPE_MOVE_SEND_ONCE
);
752 ret
= mach_msg_send (&syscall_in
.header
);
753 CHK ("Forwarding exec reply to inferior", ret
);
755 /* Garbage collect */
756 ret
= mach_port_deallocate (inferior_task
,
757 original_server_port_name
);
758 CHK ("deallocating fake server send right", ret
);
760 ret
= mach_port_insert_right (inferior_task
,
761 original_server_port_name
,
762 original_server_send
,
763 MACH_MSG_TYPE_MOVE_SEND
);
764 CHK ("Restoring the original bsd server send right", ret
);
766 ret
= mach_port_destroy (mach_task_self (),
768 fake_server
= MACH_PORT_DEAD
;
769 CHK("mach_port_destroy (fake_server)", ret
);
771 ret
= mach_port_destroy (mach_task_self (),
773 exec_reply
= MACH_PORT_DEAD
;
774 CHK("mach_port_destroy (exec_reply)", ret
);
776 xx_debug ("Done with exec call interception\n");
780 consume_send_rights (thread_list
, thread_count
)
781 thread_array_t thread_list
;
789 for (index
= 0; index
< thread_count
; index
++)
791 /* Since thread kill command kills threads, don't check ret */
792 (void) mach_port_deallocate (mach_task_self (),
793 thread_list
[ index
]);
797 /* suspend/abort/resume a thread. */
798 setup_thread (thread
, what
)
806 ret
= thread_suspend (thread
);
807 CHK ("setup_thread thread_suspend", ret
);
809 ret
= thread_abort (thread
);
810 CHK ("setup_thread thread_abort", ret
);
814 ret
= thread_resume (thread
);
815 CHK ("setup_thread thread_resume", ret
);
820 map_slot_to_mid (slot
, threads
, thread_count
)
822 thread_array_t threads
;
833 ret
= task_threads (inferior_task
, &threads
, &thread_count
);
834 CHK ("Can not select a thread from a dead task", ret
);
837 if (slot
< 0 || slot
>= thread_count
)
841 consume_send_rights (threads
, thread_count
);
842 (void) vm_deallocate (mach_task_self(), (vm_address_t
)threads
,
843 (thread_count
* sizeof(mach_port_t
)));
846 error ("invalid slot number");
851 mid
= map_port_name_to_mid (threads
[slot
], MACH_TYPE_THREAD
);
855 consume_send_rights (threads
, thread_count
);
856 (void) vm_deallocate (mach_task_self(), (vm_address_t
)threads
,
857 (thread_count
* sizeof(mach_port_t
)));
864 parse_thread_id (arg
, thread_count
, slots
)
877 while (*arg
&& (*arg
== ' ' || *arg
== '\t'))
883 /* Currently parse MID and @SLOTNUMBER */
888 error ("valid thread mid expected");
896 error ("invalid slot number");
898 /* If you want slot numbers to remain slot numbers, set slots.
900 * Well, since 0 is reserved, return the ordinal number
901 * of the thread rather than the slot number. Awk, this
902 * counts as a kludge.
907 if (thread_count
&& slot
>= thread_count
)
910 mid
= map_slot_to_mid (slot
);
915 /* THREAD_ID 0 is special; it selects the first kernel
916 * thread from the list (i.e. SLOTNUMBER 0)
917 * This is used when starting the program with 'run' or when attaching.
919 * If FLAG is 0 the context is not changed, and the registers, frame, etc
920 * will continue to describe the old thread.
922 * If FLAG is nonzero, really select the thread.
923 * If FLAG is 2, the THREAD_ID is a slotnumber instead of a mid.
927 select_thread (task
, thread_id
, flag
)
932 thread_array_t thread_list
;
936 thread_t new_thread
= MACH_PORT_NULL
;
939 error ("Can't select cprocs without kernel thread");
941 ret
= task_threads (task
, &thread_list
, &thread_count
);
942 if (ret
!= KERN_SUCCESS
)
944 message ("Can not select a thread from a dead task");
949 if (thread_count
== 0)
951 /* The task can not do anything anymore, but it still
952 * exists as a container for memory and ports.
954 registers_changed ();
955 message ("Task %d has no threads",
956 map_port_name_to_mid (task
, MACH_TYPE_TASK
));
957 current_thread
= MACH_PORT_NULL
;
958 (void) vm_deallocate(mach_task_self(),
959 (vm_address_t
) thread_list
,
960 (thread_count
* sizeof(mach_port_t
)));
964 if (! thread_id
|| flag
== 2)
966 /* First thread or a slotnumber */
968 new_thread
= thread_list
[0];
971 if (thread_id
< thread_count
)
972 new_thread
= thread_list
[ thread_id
];
975 (void) vm_deallocate(mach_task_self(),
976 (vm_address_t
) thread_list
,
977 (thread_count
* sizeof(mach_port_t
)));
978 error ("No such thread slot number : %d", thread_id
);
984 for (index
= 0; index
< thread_count
; index
++)
985 if (thread_id
== map_port_name_to_mid (thread_list
[index
],
988 new_thread
= thread_list
[index
];
994 error ("No thread with mid %d", thread_id
);
997 /* Notify when the selected thread dies */
998 request_notify (new_thread
, MACH_NOTIFY_DEAD_NAME
, MACH_TYPE_THREAD
);
1000 ret
= vm_deallocate(mach_task_self(),
1001 (vm_address_t
) thread_list
,
1002 (thread_count
* sizeof(mach_port_t
)));
1003 CHK ("vm_deallocate", ret
);
1006 current_thread
= new_thread
;
1010 if (MACH_PORT_VALID (current_thread
))
1012 /* Store the gdb's view of the thread we are deselecting
1014 * @@ I think gdb updates registers immediately when they are
1015 * changed, so don't do this.
1017 ret
= thread_abort (current_thread
);
1018 CHK ("Could not abort system calls when saving state of old thread",
1020 target_prepare_to_store ();
1021 target_store_registers (-1);
1025 registers_changed ();
1027 current_thread
= new_thread
;
1029 ret
= thread_abort (current_thread
);
1030 CHK ("Could not abort system calls when selecting a thread", ret
);
1032 stop_pc
= read_pc();
1033 set_current_frame (create_new_frame (read_register (FP_REGNUM
),
1036 select_frame (get_current_frame (), 0);
1038 stop_frame_address
= FRAME_FP (get_current_frame ());
1041 return KERN_SUCCESS
;
1045 * Switch to use thread named NEW_THREAD.
1049 switch_to_thread (new_thread
)
1050 thread_t new_thread
;
1052 thread_t saved_thread
= current_thread
;
1055 mid
= map_port_name_to_mid (new_thread
,
1058 message ("Can't map thread name 0x%x to mid", new_thread
);
1059 else if (select_thread (inferior_task
, mid
, 1) != KERN_SUCCESS
)
1062 current_thread
= saved_thread
;
1063 error ("Could not select thread %d", mid
);
1069 /* Do this in gdb after doing FORK but before STARTUP_INFERIOR.
1070 * Note that the registers are not yet valid in the inferior task.
1078 inferior_task
= task_by_pid (pid
);
1080 if (! MACH_PORT_VALID (inferior_task
))
1081 error ("Can not map Unix pid %d to Mach task", pid
);
1083 /* Clean up previous notifications and create new ones */
1084 setup_notify_port (1);
1086 /* When notification appears, the inferior task has died */
1087 request_notify (inferior_task
, MACH_NOTIFY_DEAD_NAME
, MACH_TYPE_TASK
);
1089 emulator_present
= have_emulator_p (inferior_task
);
1091 /* By default, select the first thread,
1092 * If task has no threads, gives a warning
1093 * Does not fetch registers, since they are not yet valid.
1095 select_thread (inferior_task
, 0, 0);
1097 inferior_exception_port
= MACH_PORT_NULL
;
1099 setup_exception_port ();
1101 xx_debug ("Now the debugged task is created\n");
1104 setup_exception_port ()
1108 ret
= mach_port_allocate (mach_task_self(),
1109 MACH_PORT_RIGHT_RECEIVE
,
1110 &inferior_exception_port
);
1111 CHK("mach_port_allocate",ret
);
1113 /* add send right */
1114 ret
= mach_port_insert_right (mach_task_self (),
1115 inferior_exception_port
,
1116 inferior_exception_port
,
1117 MACH_MSG_TYPE_MAKE_SEND
);
1118 CHK("mach_port_insert_right",ret
);
1120 ret
= mach_port_move_member (mach_task_self(),
1121 inferior_exception_port
,
1122 inferior_wait_port_set
);
1123 CHK("mach_port_move_member",ret
);
1125 ret
= task_get_special_port (inferior_task
,
1126 TASK_EXCEPTION_PORT
,
1127 &inferior_old_exception_port
);
1128 CHK ("task_get_special_port(old exc)",ret
);
1130 ret
= task_set_special_port (inferior_task
,
1131 TASK_EXCEPTION_PORT
,
1132 inferior_exception_port
);
1133 CHK("task_set_special_port",ret
);
1135 ret
= mach_port_deallocate (mach_task_self (),
1136 inferior_exception_port
);
1137 CHK("mack_port_deallocate",ret
);
1140 /* When notify appears, the inferior_task's exception
1141 * port has been destroyed.
1143 * Not used, since the dead_name_notification already
1144 * appears when task dies.
1147 request_notify (inferior_exception_port
,
1148 MACH_NOTIFY_NO_SENDERS
,
1149 MACH_TYPE_EXCEPTION_PORT
);
1153 /* Nonzero if gdb is waiting for a message */
1154 int mach_really_waiting
;
1156 /* Wait for the inferior to stop for some reason.
1157 - Loop on notifications until inferior_task dies.
1158 - Loop on exceptions until stopped_in_exception comes true.
1159 (e.g. we receive a single step trace trap)
1160 - a message arrives to gdb's message port
1162 There is no other way to exit this loop.
1164 Returns the inferior_pid for rest of gdb.
1165 Side effects: Set unix exit value to *w.
1168 mach_really_wait (w
)
1175 mach_msg_header_t header
;
1176 mach_msg_type_t foo
;
1180 /* Either notify (death), exception or message can stop the inferior */
1181 stopped_in_exception
= FALSE
;
1187 stop_exception
= stop_code
= stop_subcode
= -1;
1188 stop_thread
= MACH_PORT_NULL
;
1190 mach_really_waiting
= 1;
1191 ret
= mach_msg (&in_msg
.header
, /* header */
1192 MACH_RCV_MSG
, /* options */
1194 sizeof (struct msg
), /* receive size */
1195 currently_waiting_for
, /* receive name */
1196 MACH_MSG_TIMEOUT_NONE
,
1198 mach_really_waiting
= 0;
1199 CHK("mach_msg (receive)", ret
);
1201 /* Check if we received a notify of the childs' death */
1202 if (notify_server (&in_msg
.header
, &out_msg
.header
))
1204 /* If inferior_task is null then the inferior has
1205 gone away and we want to return to command level.
1206 Otherwise it was just an informative message and we
1207 need to look to see if there are any more. */
1208 if (inferior_task
!= MACH_PORT_NULL
)
1212 /* Collect Unix exit status for gdb */
1214 wait3(w
, WNOHANG
, 0);
1216 /* This mess is here to check that the rest of
1217 * gdb knows that the inferior died. It also
1218 * tries to hack around the fact that Mach 3.0 (mk69)
1219 * unix server (ux28) does not always know what
1220 * has happened to it's children when mach-magic
1221 * is applied on them.
1223 if ((!WIFEXITED(*w
) && WIFSTOPPED(*w
)) ||
1224 (WIFEXITED(*w
) && WEXITSTATUS(*w
) > 0377))
1227 message ("Using exit value 0 for terminated task");
1229 else if (!WIFEXITED(*w
))
1231 int sig
= WTERMSIG(*w
);
1233 /* Signals cause problems. Warn the user. */
1234 if (sig
!= SIGKILL
) /* Bad luck if garbage matches this */
1235 message ("The terminating signal stuff may be nonsense");
1236 else if (sig
> NSIG
)
1239 message ("Using exit value 0 for terminated task");
1242 return inferior_pid
;
1246 /* Hmm. Check for exception, as it was not a notification.
1247 exc_server() does an upcall to catch_exception_raise()
1248 if this rpc is an exception. Further actions are decided
1251 if (! exc_server (&in_msg
.header
, &out_msg
.header
))
1254 /* Not an exception, check for message.
1256 * Messages don't come from the inferior, or if they
1257 * do they better be asynchronous or it will hang.
1259 if (gdb_message_server (&in_msg
.header
))
1262 error ("Unrecognized message received in mach_really_wait");
1265 /* Send the reply of the exception rpc to the suspended task */
1266 ret
= mach_msg_send (&out_msg
.header
);
1267 CHK ("mach_msg_send (exc reply)", ret
);
1269 if (stopped_in_exception
)
1271 /* Get unix state. May be changed in mach3_exception_actions() */
1272 wait3(w
, WNOHANG
, 0);
1274 mach3_exception_actions (w
, FALSE
, "Task");
1276 return inferior_pid
;
1281 /* Called by macro DO_QUIT() in utils.c(quit).
1282 * This is called just before calling error() to return to command level
1290 if (mach_really_waiting
)
1292 ret
= task_suspend (inferior_task
);
1294 if (ret
!= KERN_SUCCESS
)
1296 message ("Could not suspend task for interrupt: %s",
1297 mach_error_string (ret
));
1298 mach_really_waiting
= 0;
1303 must_suspend_thread
= 0;
1304 mach_really_waiting
= 0;
1306 mid
= map_port_name_to_mid (current_thread
, MACH_TYPE_THREAD
);
1309 message ("Selecting first existing kernel thread");
1313 current_thread
= MACH_PORT_NULL
; /* Force setup */
1314 select_thread (inferior_task
, mid
, 1);
1319 /* If ^C is typed when we are waiting for a message
1320 * and your Unix server is able to notice that we
1323 * Called by REQUEST_QUIT() from utils.c(request_quit)
1326 mach3_request_quit ()
1328 if (mach_really_waiting
)
1333 * Gdb message server.
1334 * Currently implemented is the STOP message, that causes
1335 * gdb to return to the command level like ^C had been typed from terminal.
1338 gdb_message_server (InP
)
1339 mach_msg_header_t
*InP
;
1344 if (InP
->msgh_local_port
== our_message_port
)
1346 /* A message coming to our_message_port. Check validity */
1347 switch (InP
->msgh_id
) {
1349 case GDB_MESSAGE_ID_STOP
:
1350 ret
= task_suspend (inferior_task
);
1351 if (ret
!= KERN_SUCCESS
)
1352 message ("Could not suspend task for stop message: %s",
1353 mach_error_string (ret
));
1355 /* QUIT in mach_really_wait() loop. */
1360 message ("Invalid message id %d received, ignored.",
1368 /* Message not handled by this server */
1372 /* NOTE: This is not an RPC call. It is a simpleroutine.
1374 * This is not called from this gdb code.
1376 * It may be called by another debugger to cause this
1377 * debugger to enter command level:
1379 * (gdb) set stop_inferior_gdb ()
1382 * External program "stop-gdb" implements this also.
1385 stop_inferior_gdb ()
1389 /* Code generated by mig, with minor cleanups :-)
1391 * simpleroutine stop_inferior_gdb (our_message_port : mach_port_t);
1395 mach_msg_header_t Head
;
1400 register Request
*InP
= &Mess
;
1402 InP
->Head
.msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND
, 0);
1404 /* msgh_size passed as argument */
1405 InP
->Head
.msgh_remote_port
= our_message_port
;
1406 InP
->Head
.msgh_local_port
= MACH_PORT_NULL
;
1407 InP
->Head
.msgh_seqno
= 0;
1408 InP
->Head
.msgh_id
= GDB_MESSAGE_ID_STOP
;
1410 ret
= mach_msg (&InP
->Head
,
1411 MACH_SEND_MSG
|MACH_MSG_OPTION_NONE
,
1415 MACH_MSG_TIMEOUT_NONE
,
1419 #ifdef THREAD_ALLOWED_TO_BREAK
1421 * Return 1 if the MID specifies the thread that caused the
1423 * Since catch_exception_raise() selects the thread causing
1424 * the last exception to current_thread, we just check that
1425 * it is selected and the last exception was a breakpoint.
1428 mach_thread_for_breakpoint (mid
)
1431 int cmid
= map_port_name_to_mid (current_thread
, MACH_TYPE_THREAD
);
1435 mid
= map_slot_to_mid (-(mid
+1), 0, 0);
1437 return 0; /* Don't stop, no such slot */
1440 if (! mid
|| cmid
== -1)
1441 return 1; /* stop */
1443 return cmid
== mid
&& stop_exception
== EXC_BREAKPOINT
;
1445 #endif /* THREAD_ALLOWED_TO_BREAK */
1447 #ifdef THREAD_PARSE_ID
1449 * Map a thread id string (MID or a @SLOTNUMBER)
1452 * 0 matches all threads.
1453 * Otherwise the meaning is defined only in this file.
1454 * (mach_thread_for_breakpoint uses it)
1456 * @@ This allows non-existent MIDs to be specified.
1457 * It now also allows non-existent slots to be
1458 * specified. (Slot numbers stored are negative,
1459 * and the magnitude is one greater than the actual
1460 * slot index. (Since 0 is reserved))
1463 mach_thread_parse_id (arg
)
1468 error ("thread id excpected");
1469 mid
= parse_thread_id (arg
, 0, 1);
1473 #endif /* THREAD_PARSE_ID */
1475 #ifdef THREAD_OUTPUT_ID
1477 mach_thread_output_id (mid
)
1480 static char foobar
[20];
1483 sprintf (foobar
, "mid %d", mid
);
1485 sprintf (foobar
, "@%d", -(mid
+1));
1487 sprintf (foobar
, "*any thread*");
1491 #endif /* THREAD_OUTPUT_ID */
1493 /* Called with hook PREPARE_TO_PROCEED() from infrun.c.
1495 * If we have switched threads and stopped at breakpoint return 1 otherwise 0.
1497 * if SELECT_IT is nonzero, reselect the thread that was active when
1498 * we stopped at a breakpoint.
1502 mach3_prepare_to_proceed (select_it
)
1506 stop_thread
!= current_thread
&&
1507 stop_exception
== EXC_BREAKPOINT
)
1514 mid
= switch_to_thread (stop_thread
);
1522 /* this stuff here is an upcall via libmach/excServer.c
1523 and mach_really_wait which does the actual upcall.
1525 The code will pass the exception to the inferior if:
1527 - The task that signaled is not the inferior task
1528 (e.g. when debugging another debugger)
1530 - The user has explicitely requested to pass on the exceptions.
1531 (e.g to the default unix exception handler, which maps
1532 exceptions to signals, or the user has her own exception handler)
1534 - If the thread that signaled is being single-stepped and it
1535 has set it's own exception port and the exception is not
1536 EXC_BREAKPOINT. (Maybe this is not desirable?)
1540 catch_exception_raise (port
, thread
, task
, exception
, code
, subcode
)
1544 int exception
, code
, subcode
;
1547 boolean_t signal_thread
;
1548 int mid
= map_port_name_to_mid (thread
, MACH_TYPE_THREAD
);
1550 if (! MACH_PORT_VALID (thread
))
1552 /* If the exception was sent and thread dies before we
1553 receive it, THREAD will be MACH_PORT_DEAD
1556 current_thread
= thread
= MACH_PORT_NULL
;
1557 error ("Received exception from nonexistent thread");
1560 /* Check if the task died in transit.
1561 * @@ Isn't the thread also invalid in such case?
1563 if (! MACH_PORT_VALID (task
))
1565 current_thread
= thread
= MACH_PORT_NULL
;
1566 error ("Received exception from nonexistent task");
1569 if (exception
< 0 || exception
> MAX_EXCEPTION
)
1570 fatal ("catch_exception_raise: unknown exception code %d thread %d",
1574 if (! MACH_PORT_VALID (inferior_task
))
1575 error ("got an exception, but inferior_task is null or dead");
1577 stop_exception
= exception
;
1579 stop_subcode
= subcode
;
1580 stop_thread
= thread
;
1582 signal_thread
= exception
!= EXC_BREAKPOINT
&&
1583 port
== singlestepped_thread_port
&&
1584 MACH_PORT_VALID (thread_saved_exception_port
);
1586 /* If it was not our inferior or if we want to forward
1587 * the exception to the inferior's handler, do it here
1589 * Note: If you have forwarded EXC_BREAKPOINT I trust you know why.
1591 if (task
!= inferior_task
||
1593 exception_map
[exception
].forward
)
1595 mach_port_t eport
= inferior_old_exception_port
;
1600 GDB now forwards the exeption to thread's original handler,
1601 since the user propably knows what he is doing.
1602 Give a message, though.
1605 mach3_exception_actions ((WAITTYPE
*)NULL
, TRUE
, "Thread");
1606 eport
= thread_saved_exception_port
;
1609 /* Send the exception to the original handler */
1610 ret
= exception_raise (eport
,
1617 (void) mach_port_deallocate (mach_task_self (), task
);
1618 (void) mach_port_deallocate (mach_task_self (), thread
);
1620 /* If we come here, we don't want to trace any more, since we
1621 * will never stop for tracing anyway.
1623 discard_single_step (thread
);
1625 /* Do not stop the inferior */
1629 /* Now gdb handles the exception */
1630 stopped_in_exception
= TRUE
;
1632 ret
= task_suspend (task
);
1633 CHK ("Error suspending inferior after exception", ret
);
1635 must_suspend_thread
= 0;
1637 if (current_thread
!= thread
)
1639 if (MACH_PORT_VALID (singlestepped_thread_port
))
1640 /* Cleanup discards single stepping */
1641 error ("Exception from thread %d while singlestepping thread %d",
1643 map_port_name_to_mid (current_thread
, MACH_TYPE_THREAD
));
1645 /* Then select the thread that caused the exception */
1646 if (select_thread (inferior_task
, mid
, 0) != KERN_SUCCESS
)
1647 error ("Could not select thread %d causing exception", mid
);
1649 message ("Gdb selected thread %d", mid
);
1652 /* If we receive an exception that is not breakpoint
1653 * exception, we interrupt the single step and return to
1654 * debugger. Trace condition is cleared.
1656 if (MACH_PORT_VALID (singlestepped_thread_port
))
1658 if (stop_exception
!= EXC_BREAKPOINT
)
1659 message ("Single step interrupted by exception");
1660 else if (port
== singlestepped_thread_port
)
1662 /* Single step exception occurred, remove trace bit
1663 * and return to gdb.
1665 if (! MACH_PORT_VALID (current_thread
))
1666 error ("Single stepped thread is not valid");
1668 /* Resume threads, but leave the task suspended */
1669 resume_all_threads (0);
1672 message ("Breakpoint while single stepping?");
1674 discard_single_step (current_thread
);
1677 (void) mach_port_deallocate (mach_task_self (), task
);
1678 (void) mach_port_deallocate (mach_task_self (), thread
);
1680 return KERN_SUCCESS
;
1684 port_valid (port
, mask
)
1689 mach_port_type_t type
;
1691 ret
= mach_port_type (mach_task_self (),
1694 if (ret
!= KERN_SUCCESS
|| (type
& mask
) != mask
)
1699 /* @@ No vm read cache implemented yet */
1700 boolean_t vm_read_cache_valid
= FALSE
;
1703 * Read inferior task's LEN bytes from ADDR and copy it to MYADDR
1704 * in gdb's address space.
1706 * Return 0 on failure; number of bytes read otherwise.
1709 mach3_read_inferior (addr
, myaddr
, length
)
1715 vm_address_t low_address
= (vm_address_t
) trunc_page (addr
);
1716 vm_size_t aligned_length
=
1717 (vm_size_t
) round_page (addr
+length
) - low_address
;
1718 pointer_t copied_memory
;
1721 /* Get memory from inferior with page aligned addresses */
1722 ret
= vm_read (inferior_task
,
1727 if (ret
!= KERN_SUCCESS
)
1729 /* the problem is that the inferior might be killed for whatever reason
1730 * before we go to mach_really_wait. This is one place that ought to
1731 * catch many of those errors.
1732 * @@ A better fix would be to make all external events to GDB
1733 * to arrive via a SINGLE port set. (Including user input!)
1736 if (! port_valid (inferior_task
, MACH_PORT_TYPE_SEND
))
1739 error ("Inferior killed (task port invalid)");
1745 /* valprint.c gives nicer format if this does not
1746 screw it. Eamonn seems to like this, so I enable
1747 it if OSF is defined...
1749 message ("[read inferior %x failed: %s]",
1750 addr
, mach_error_string (ret
));
1757 bcopy ((char *)addr
- low_address
+ copied_memory
, myaddr
, length
);
1759 ret
= vm_deallocate (mach_task_self (),
1762 CHK("mach3_read_inferior vm_deallocate failed", ret
);
1768 #define CHK_GOTO_OUT(str,ret) \
1769 do if (ret != KERN_SUCCESS) { errstr = #str; goto out; } while(0)
1771 #define CHK_GOTO_OUT(str,ret) \
1772 do if (ret != KERN_SUCCESS) { errstr = str; goto out; } while(0)
1775 struct vm_region_list
{
1776 struct vm_region_list
*next
;
1777 vm_prot_t protection
;
1782 struct obstack region_obstack
;
1785 * Write inferior task's LEN bytes from ADDR and copy it to MYADDR
1786 * in gdb's address space.
1789 mach3_write_inferior (addr
, myaddr
, length
)
1795 vm_address_t low_address
= (vm_address_t
) trunc_page (addr
);
1796 vm_size_t aligned_length
=
1797 (vm_size_t
) round_page (addr
+length
) - low_address
;
1798 pointer_t copied_memory
;
1802 char *errstr
= "Bug in mach3_write_inferior";
1804 struct vm_region_list
*region_element
;
1805 struct vm_region_list
*region_head
= (struct vm_region_list
*)NULL
;
1807 /* Get memory from inferior with page aligned addresses */
1808 ret
= vm_read (inferior_task
,
1813 CHK_GOTO_OUT ("mach3_write_inferior vm_read failed", ret
);
1817 bcopy (myaddr
, (char *)addr
- low_address
+ copied_memory
, length
);
1819 obstack_init (®ion_obstack
);
1821 /* Do writes atomically.
1822 * First check for holes and unwritable memory.
1825 vm_size_t remaining_length
= aligned_length
;
1826 vm_address_t region_address
= low_address
;
1828 struct vm_region_list
*scan
;
1830 while(region_address
< low_address
+ aligned_length
)
1832 vm_prot_t protection
;
1833 vm_prot_t max_protection
;
1834 vm_inherit_t inheritance
;
1836 mach_port_t object_name
;
1838 vm_size_t region_length
= remaining_length
;
1839 vm_address_t old_address
= region_address
;
1841 ret
= vm_region (inferior_task
,
1850 CHK_GOTO_OUT ("vm_region failed", ret
);
1852 /* Check for holes in memory */
1853 if (old_address
!= region_address
)
1855 message ("No memory at 0x%x. Nothing written",
1862 if (!(max_protection
& VM_PROT_WRITE
))
1864 message ("Memory at address 0x%x is unwritable. Nothing written",
1871 /* Chain the regions for later use */
1873 (struct vm_region_list
*)
1874 obstack_alloc (®ion_obstack
, sizeof (struct vm_region_list
));
1876 region_element
->protection
= protection
;
1877 region_element
->start
= region_address
;
1878 region_element
->length
= region_length
;
1880 /* Chain the regions along with protections */
1881 region_element
->next
= region_head
;
1882 region_head
= region_element
;
1884 region_address
+= region_length
;
1885 remaining_length
= remaining_length
- region_length
;
1888 /* If things fail after this, we give up.
1889 * Somebody is messing up inferior_task's mappings.
1892 /* Enable writes to the chained vm regions */
1893 for (scan
= region_head
; scan
; scan
= scan
->next
)
1895 boolean_t protection_changed
= FALSE
;
1897 if (!(scan
->protection
& VM_PROT_WRITE
))
1899 ret
= vm_protect (inferior_task
,
1903 scan
->protection
| VM_PROT_WRITE
);
1904 CHK_GOTO_OUT ("vm_protect: enable write failed", ret
);
1908 ret
= vm_write (inferior_task
,
1912 CHK_GOTO_OUT ("vm_write failed", ret
);
1914 /* Set up the original region protections, if they were changed */
1915 for (scan
= region_head
; scan
; scan
= scan
->next
)
1917 boolean_t protection_changed
= FALSE
;
1919 if (!(scan
->protection
& VM_PROT_WRITE
))
1921 ret
= vm_protect (inferior_task
,
1926 CHK_GOTO_OUT ("vm_protect: enable write failed", ret
);
1934 obstack_free (®ion_obstack
, 0);
1936 (void) vm_deallocate (mach_task_self (),
1941 if (ret
!= KERN_SUCCESS
)
1943 message ("%s %s", errstr
, mach_error_string (ret
));
1950 /* Return 0 on failure, number of bytes handled otherwise. */
1952 m3_xfer_memory (memaddr
, myaddr
, len
, write
, target
)
1957 struct target_ops
*target
; /* IGNORED */
1962 result
= mach3_write_inferior (memaddr
, myaddr
, len
);
1964 result
= mach3_read_inferior (memaddr
, myaddr
, len
);
1971 translate_state(state
)
1975 case TH_STATE_RUNNING
: return("R");
1976 case TH_STATE_STOPPED
: return("S");
1977 case TH_STATE_WAITING
: return("W");
1978 case TH_STATE_UNINTERRUPTIBLE
: return("U");
1979 case TH_STATE_HALTED
: return("H");
1980 default: return("?");
1985 translate_cstate(state
)
1989 case CPROC_RUNNING
: return "R";
1990 case CPROC_SWITCHING
: return "S";
1991 case CPROC_BLOCKED
: return "B";
1992 case CPROC_CONDWAIT
: return "C";
1993 case CPROC_CONDWAIT
|CPROC_SWITCHING
:
1995 default: return "?";
1999 /* type == MACH_MSG_TYPE_COPY_SEND || type == MACH_MSG_TYPE_MAKE_SEND
2002 mach_port_t
/* no mach_port_name_t found in include files. */
2003 map_inferior_port_name (inferior_name
, type
)
2004 mach_port_t inferior_name
;
2005 mach_msg_type_name_t type
;
2008 mach_msg_type_name_t acquired
;
2011 ret
= mach_port_extract_right (inferior_task
,
2016 CHK("mach_port_extract_right (map_inferior_port_name)", ret
);
2018 if (acquired
!= MACH_MSG_TYPE_PORT_SEND
)
2019 error("Incorrect right extracted, (map_inferior_port_name)");
2021 ret
= mach_port_deallocate (mach_task_self (),
2023 CHK ("Deallocating mapped port (map_inferior_port_name)", ret
);
2029 * Naming convention:
2030 * Always return user defined name if found.
2031 * _K == A kernel thread with no matching CPROC
2032 * _C == A cproc with no current cthread
2033 * _t == A cthread with no user defined name
2035 * The digits that follow the _names are the SLOT number of the
2036 * kernel thread if there is such a thing, otherwise just a negation
2037 * of the sequential number of such cprocs.
2043 get_thread_name (one_cproc
, id
)
2048 if (one_cproc
->incarnation
== NULL
)
2050 /* cproc not mapped to any cthread */
2051 sprintf(buf
, "_C%d", id
);
2053 else if (! one_cproc
->incarnation
->name
)
2055 /* cproc and cthread, but no name */
2056 sprintf(buf
, "_t%d", id
);
2059 return (one_cproc
->incarnation
->name
);
2063 message ("Inconsistency in thread name id %d", id
);
2065 /* Kernel thread without cproc */
2066 sprintf(buf
, "_K%d", id
);
2073 fetch_thread_info (task
, mthreads_out
)
2075 gdb_thread_t
*mthreads_out
; /* out */
2078 thread_array_t th_table
;
2080 gdb_thread_t mthreads
= NULL
;
2083 ret
= task_threads (task
, &th_table
, &th_count
);
2084 if (ret
!= KERN_SUCCESS
)
2086 message ("Error getting inferior's thread list:%s",
2087 mach_error_string(ret
));
2092 mthreads
= (gdb_thread_t
)
2095 th_count
* sizeof (struct gdb_thread
));
2097 for (index
= 0; index
< th_count
; index
++)
2099 thread_t saved_thread
= MACH_PORT_NULL
;
2102 if (must_suspend_thread
)
2103 setup_thread (th_table
[ index
], 1);
2105 if (th_table
[index
] != current_thread
)
2107 saved_thread
= current_thread
;
2109 mid
= switch_to_thread (th_table
[ index
]);
2112 mthreads
[index
].name
= th_table
[index
];
2113 mthreads
[index
].cproc
= NULL
; /* map_cprocs_to_kernel_threads() */
2114 mthreads
[index
].in_emulator
= FALSE
;
2115 mthreads
[index
].slotid
= index
;
2117 mthreads
[index
].sp
= read_register (SP_REGNUM
);
2118 mthreads
[index
].fp
= read_register (FP_REGNUM
);
2119 mthreads
[index
].pc
= read_pc ();
2121 if (MACH_PORT_VALID (saved_thread
))
2122 mid
= switch_to_thread (saved_thread
);
2124 if (must_suspend_thread
)
2125 setup_thread (th_table
[ index
], 0);
2128 consume_send_rights (th_table
, th_count
);
2129 ret
= vm_deallocate (mach_task_self(), (vm_address_t
)th_table
,
2130 (th_count
* sizeof(mach_port_t
)));
2131 if (ret
!= KERN_SUCCESS
)
2133 message ("Error trying to deallocate thread list : %s",
2134 mach_error_string (ret
));
2137 *mthreads_out
= mthreads
;
2144 * Current emulator always saves the USP on top of
2145 * emulator stack below struct emul_stack_top stuff.
2148 fetch_usp_from_emulator_stack (sp
)
2151 CORE_ADDR stack_pointer
;
2153 sp
= (sp
& ~(EMULATOR_STACK_SIZE
-1)) +
2154 EMULATOR_STACK_SIZE
- sizeof (struct emul_stack_top
);
2156 if (mach3_read_inferior (sp
,
2158 sizeof (CORE_ADDR
)) != sizeof (CORE_ADDR
))
2160 message ("Can't read user sp from emulator stack address 0x%x", sp
);
2164 return stack_pointer
;
2169 /* get_emulation_vector() interface was changed after mk67 */
2170 #define EMUL_VECTOR_COUNT 400 /* Value does not matter too much */
2174 /* Check if the emulator exists at task's address space.
2177 have_emulator_p (task
)
2181 #ifndef EMUL_VECTOR_COUNT
2182 vm_offset_t
*emulation_vector
;
2185 vm_offset_t emulation_vector
[ EMUL_VECTOR_COUNT
];
2186 int n
= EMUL_VECTOR_COUNT
;
2191 ret
= task_get_emulation_vector (task
,
2193 #ifndef EMUL_VECTOR_COUNT
2199 CHK("task_get_emulation_vector", ret
);
2200 xx_debug ("%d vectors from %d at 0x%08x\n",
2201 n
, vector_start
, emulation_vector
);
2203 for(i
= 0; i
< n
; i
++)
2205 vm_offset_t entry
= emulation_vector
[i
];
2207 if (EMULATOR_BASE
<= entry
&& entry
<= EMULATOR_END
)
2211 static boolean_t informed
= FALSE
;
2214 message("Emulation vector address 0x08%x outside emulator space",
2224 * Map cprocs to kernel threads and vice versa.
2226 * For reverse mapping the code mis-uses one struct cproc field,
2227 * see "os-mach3.h" and code here.
2232 map_cprocs_to_kernel_threads (cprocs
, mthreads
, thread_count
)
2234 gdb_thread_t mthreads
;
2239 boolean_t all_mapped
= TRUE
;
2241 for (scan
= cprocs
; scan
; scan
= scan
->list
)
2243 /* Default to: no kernel thread for this cproc */
2244 CPROC_REVERSE_MAP (scan
) = -1;
2246 /* Check if the cproc is found by its stack */
2247 for (index
= 0; index
< thread_count
; index
++)
2249 if ((mthreads
+ index
)->sp
> scan
->stack_base
&&
2250 (mthreads
+ index
)->sp
<= scan
->stack_base
+ scan
->stack_size
)
2252 (mthreads
+ index
)->cproc
= scan
;
2253 CPROC_REVERSE_MAP (scan
) = index
;
2257 all_mapped
&= (CPROC_REVERSE_MAP(scan
) != -1);
2260 /* Check for threads that are currently in the emulator.
2261 * If so, they have a different stack, and the still unmapped
2262 * cprocs may well get mapped to these threads.
2265 * - cproc stack does not match any kernel thread stack pointer
2266 * - there is at least one extra kernel thread
2267 * that has no cproc mapped above.
2268 * - some kernel thread stack pointer points to emulator space
2269 * then we find the user stack pointer saved in the emulator
2270 * stack, and try to map that to the cprocs.
2272 * Also set in_emulator for kernel threads.
2275 if (emulator_present
)
2277 for (index
= 0; index
< thread_count
; index
++)
2282 gdb_thread_t mthread
= (mthreads
+index
);
2283 emul_sp
= mthread
->sp
;
2285 if (! mthread
->cproc
&&
2286 EMULATOR_BASE
<= emul_sp
&& emul_sp
<= EMULATOR_END
)
2288 mthread
->in_emulator
= emulator_present
;
2290 if (!all_mapped
&& cprocs
)
2292 usp
= fetch_usp_from_emulator_stack (emul_sp
);
2294 /* @@ Could be more accurate */
2296 error ("Zero stack pointer read from emulator?");
2298 /* Try to match this stack pointer to the cprocs that
2299 * don't yet have a kernel thread.
2301 for (scan
= cprocs
; scan
; scan
= scan
->list
)
2304 /* Check is this unmapped CPROC stack contains
2305 * the user stack pointer saved in the
2308 if (CPROC_REVERSE_MAP (scan
) == -1 &&
2309 usp
> scan
->stack_base
&&
2310 usp
<= scan
->stack_base
+ scan
->stack_size
)
2312 mthread
->cproc
= scan
;
2313 CPROC_REVERSE_MAP (scan
) = index
;
2324 * Format of the thread_list command
2326 * slot mid sel name emul ks susp cstate wired address
2328 #define TL_FORMAT "%-2.2s %5d%c %-10.10s %1.1s%s%-5.5s %-2.2s %-5.5s "
2330 #define TL_HEADER "\n@ MID Name KState CState Where\n"
2333 print_tl_address (stream
, pc
)
2337 if (! lookup_minimal_symbol_by_pc (pc
))
2338 fprintf_filtered (stream
, local_hex_format(), pc
);
2341 extern int addressprint
;
2342 extern int asm_demangle
;
2344 int store
= addressprint
;
2346 print_address_symbolic (pc
, stream
, asm_demangle
, "");
2347 addressprint
= store
;
2351 /* For thread names, but also for gdb_message_port external name */
2352 #define MAX_NAME_LEN 50
2354 /* Returns the address of variable NAME or 0 if not found */
2356 lookup_address_of_variable (name
)
2360 CORE_ADDR symaddr
= 0;
2361 struct minimal_symbol
*msymbol
;
2363 sym
= lookup_symbol (name
,
2364 (struct block
*)NULL
,
2367 (struct symtab
**)NULL
);
2370 symaddr
= SYMBOL_VALUE (sym
);
2374 msymbol
= lookup_minimal_symbol (name
, (struct objfile
*) NULL
);
2376 if (msymbol
&& msymbol
->type
== mst_data
)
2377 symaddr
= msymbol
->address
;
2386 cproc_t their_cprocs
, cproc_head
, cproc_copy
;
2391 symaddr
= lookup_address_of_variable ("cproc_list");
2394 { /* cproc_list is not in a file compiled with debugging
2395 symbols, but don't give up yet */
2397 symaddr
= lookup_address_of_variable ("cprocs");
2401 static int informed
= 0;
2404 message ("Your program is loaded with an old threads library.");
2405 message ("GDB does not know the old form of threads");
2406 message ("so things may not work.");
2411 /* Stripped or no -lthreads loaded or "cproc_list" is in wrong segment. */
2415 /* Get the address of the first cproc in the task */
2416 if (!mach3_read_inferior(symaddr
,
2419 error("Can't read cproc master list at address (0x%x).", symaddr
);
2421 /* Scan the CPROCs in the task.
2422 CPROCs are chained with LIST field, not NEXT field, which
2423 chains mutexes, condition variables and queues */
2425 cproc_head
= NO_CPROC
;
2427 while (their_cprocs
!= NO_CPROC
)
2429 cproc_copy
= (cproc_t
) obstack_alloc(cproc_obstack
,
2430 sizeof(struct cproc
));
2432 if (!mach3_read_inferior(their_cprocs
,
2434 sizeof(struct cproc
)))
2435 error("Can't read next cproc at 0x%x.", their_cprocs
);
2437 their_cprocs
= cproc_copy
->list
;
2439 if (cproc_copy
->incarnation
!= NULL
)
2441 /* This CPROC has an attached CTHREAD. Get its name */
2442 cthread
= (cthread_t
)obstack_alloc (cproc_obstack
,
2443 sizeof(struct cthread
));
2445 if (!mach3_read_inferior(cproc_copy
->incarnation
,
2447 sizeof(struct cthread
)))
2448 error("Can't read next thread at 0x%x.",
2449 cproc_copy
->incarnation
);
2451 cproc_copy
->incarnation
= cthread
;
2455 name
= (char *) obstack_alloc (cproc_obstack
, MAX_NAME_LEN
);
2457 if (!mach3_read_inferior(cthread
->name
, name
, MAX_NAME_LEN
))
2458 error("Can't read next thread's name at 0x%x.", cthread
->name
);
2460 cthread
->name
= name
;
2464 /* insert in front */
2465 cproc_copy
->list
= cproc_head
;
2466 cproc_head
= cproc_copy
;
2471 #ifndef FETCH_CPROC_STATE
2473 * Check if your machine does not grok the way this routine
2474 * fetches the FP,PC and SP of a cproc that is not
2475 * currently attached to any kernel thread (e.g. its cproc.context
2476 * field points to the place in stack where the context
2479 * If it doesn't, define your own routine.
2481 #define FETCH_CPROC_STATE(mth) mach3_cproc_state (mth)
2484 mach3_cproc_state (mthread
)
2485 gdb_thread_t mthread
;
2489 if (! mthread
|| !mthread
->cproc
|| !mthread
->cproc
->context
)
2492 context
= mthread
->cproc
->context
;
2494 mthread
->sp
= context
+ MACHINE_CPROC_SP_OFFSET
;
2496 if (mach3_read_inferior (context
+ MACHINE_CPROC_PC_OFFSET
,
2498 sizeof (CORE_ADDR
)) != sizeof (CORE_ADDR
))
2500 message ("Can't read cproc pc from inferior");
2504 if (mach3_read_inferior (context
+ MACHINE_CPROC_FP_OFFSET
,
2506 sizeof (CORE_ADDR
)) != sizeof (CORE_ADDR
))
2508 message ("Can't read cproc fp from inferior");
2514 #endif /* FETCH_CPROC_STATE */
2518 thread_list_command()
2520 thread_basic_info_data_t ths
;
2530 mach_port_t mid_or_port
;
2531 gdb_thread_t their_threads
;
2532 gdb_thread_t kthread
;
2536 char *fmt
= "There are %d kernel threads in task %d.\n";
2538 int tmid
= map_port_name_to_mid (inferior_task
, MACH_TYPE_TASK
);
2540 MACH_ERROR_NO_INFERIOR
;
2542 thread_count
= fetch_thread_info (inferior_task
,
2544 if (thread_count
== -1)
2547 if (thread_count
== 1)
2548 fmt
= "There is %d kernel thread in task %d.\n";
2550 printf_filtered (fmt
, thread_count
, tmid
);
2552 puts_filtered (TL_HEADER
);
2554 cprocs
= get_cprocs();
2556 map_cprocs_to_kernel_threads (cprocs
, their_threads
, thread_count
);
2558 for (scan
= cprocs
; scan
; scan
= scan
->list
)
2566 /* a wired cproc? */
2567 wired
= scan
->wired
? "wired" : "";
2569 if (CPROC_REVERSE_MAP(scan
) != -1)
2570 kthread
= (their_threads
+ CPROC_REVERSE_MAP(scan
));
2576 /* These cprocs have a kernel thread */
2578 mid
= map_port_name_to_mid (kthread
->name
, MACH_TYPE_THREAD
);
2580 infoCnt
= THREAD_BASIC_INFO_COUNT
;
2582 ret
= thread_info (kthread
->name
,
2584 (thread_info_t
)&ths
,
2587 if (ret
!= KERN_SUCCESS
)
2589 message ("Unable to get basic info on thread %d : %s",
2591 mach_error_string (ret
));
2595 /* Who is the first to have more than 100 threads */
2596 sprintf (slot
, "%d", kthread
->slotid
%100);
2598 if (kthread
->name
== current_thread
)
2601 if (ths
.suspend_count
)
2602 sprintf (buf
, "%d", ths
.suspend_count
);
2607 if (ths
.flags
& TH_FLAGS_SWAPPED
)
2611 if (ths
.flags
& TH_FLAGS_IDLE
)
2614 printf_filtered (TL_FORMAT
,
2618 get_thread_name (scan
, kthread
->slotid
),
2619 kthread
->in_emulator
? "E" : "",
2620 translate_state (ths
.run_state
),
2622 translate_cstate (scan
->state
),
2624 print_tl_address (stdout
, kthread
->pc
);
2628 /* These cprocs don't have a kernel thread.
2629 * find out the calling frame with
2630 * FETCH_CPROC_STATE.
2633 struct gdb_thread state
;
2636 /* jtv -> emcmanus: why do you want this here? */
2637 if (scan
->incarnation
== NULL
)
2638 continue; /* EMcM */
2641 printf_filtered (TL_FORMAT
,
2643 -neworder
, /* Pseudo MID */
2645 get_thread_name (scan
, -neworder
),
2647 "-", /* kernel state */
2649 translate_cstate (scan
->state
),
2653 if (FETCH_CPROC_STATE (&state
) == -1)
2654 puts_filtered ("???");
2656 print_tl_address (stdout
, state
.pc
);
2660 puts_filtered ("\n");
2663 /* Scan for kernel threads without cprocs */
2664 for (index
= 0; index
< thread_count
; index
++)
2666 if (! their_threads
[index
].cproc
)
2673 mach_port_t name
= their_threads
[index
].name
;
2675 mid
= map_port_name_to_mid (name
, MACH_TYPE_THREAD
);
2677 infoCnt
= THREAD_BASIC_INFO_COUNT
;
2679 ret
= thread_info(name
,
2681 (thread_info_t
)&ths
,
2684 if (ret
!= KERN_SUCCESS
)
2686 message ("Unable to get basic info on thread %d : %s",
2688 mach_error_string (ret
));
2692 sprintf (slot
, "%d", index
%100);
2694 if (name
== current_thread
)
2699 if (ths
.suspend_count
)
2700 sprintf (buf
, "%d", ths
.suspend_count
);
2705 if (ths
.flags
& TH_FLAGS_SWAPPED
)
2709 if (ths
.flags
& TH_FLAGS_IDLE
)
2712 printf_filtered (TL_FORMAT
,
2716 get_thread_name (NULL
, index
),
2717 their_threads
[index
].in_emulator
? "E" : "",
2718 translate_state (ths
.run_state
),
2720 "", /* No cproc state */
2721 ""); /* Can't be wired */
2722 print_tl_address (stdout
, their_threads
[index
].pc
);
2723 puts_filtered ("\n");
2727 obstack_free (cproc_obstack
, 0);
2728 obstack_init (cproc_obstack
);
2732 thread_select_command(args
, from_tty
)
2737 thread_array_t thread_list
;
2742 MACH_ERROR_NO_INFERIOR
;
2745 error_no_arg ("MID or @SLOTNUMBER to specify a thread to select");
2747 while (*args
== ' ' || *args
== '\t')
2759 if (!is_slot
|| *args
!= '0') /* Rudimentary checks */
2760 error ("You must select threads by MID or @SLOTNUMBER");
2762 if (select_thread (inferior_task
, mid
, is_slot
?2:1) != KERN_SUCCESS
)
2766 printf_filtered ("Thread %d selected\n",
2767 is_slot
? map_port_name_to_mid (current_thread
,
2768 MACH_TYPE_THREAD
) : mid
);
2771 thread_trace (thread
, set
)
2775 int flavor
= TRACE_FLAVOR
;
2776 unsigned int stateCnt
= TRACE_FLAVOR_SIZE
;
2778 thread_state_data_t state
;
2780 if (! MACH_PORT_VALID (thread
))
2782 message ("thread_trace: invalid thread");
2786 if (must_suspend_thread
)
2787 setup_thread (thread
, 1);
2789 ret
= thread_get_state(thread
, flavor
, state
, &stateCnt
);
2790 CHK ("thread_trace: error reading thread state", ret
);
2794 TRACE_SET (thread
, state
);
2798 if (! TRACE_CLEAR (thread
, state
))
2800 if (must_suspend_thread
)
2801 setup_thread (thread
, 0);
2806 ret
= thread_set_state(thread
, flavor
, state
, stateCnt
);
2807 CHK ("thread_trace: error writing thread state", ret
);
2808 if (must_suspend_thread
)
2809 setup_thread (thread
, 0);
2812 #ifdef FLUSH_INFERIOR_CACHE
2814 /* When over-writing code on some machines the I-Cache must be flushed
2815 explicitly, because it is not kept coherent by the lazy hardware.
2816 This definitely includes breakpoints, for instance, or else we
2817 end up looping in mysterious Bpt traps */
2819 flush_inferior_icache(pc
, amount
)
2822 vm_machine_attribute_val_t flush
= MATTR_VAL_ICACHE_FLUSH
;
2825 ret
= vm_machine_attribute (inferior_task
,
2830 if (ret
!= KERN_SUCCESS
)
2831 message ("Error flushing inferior's cache : %s",
2832 mach_error_string (ret
));
2834 #endif FLUSH_INFERIOR_CACHE
2838 suspend_all_threads (from_tty
)
2842 thread_array_t thread_list
;
2843 int thread_count
, index
;
2845 thread_basic_info_data_t th_info
;
2848 ret
= task_threads (inferior_task
, &thread_list
, &thread_count
);
2849 if (ret
!= KERN_SUCCESS
)
2851 message ("Could not suspend inferior threads.");
2853 return_to_top_level ();
2856 for (index
= 0; index
< thread_count
; index
++)
2860 mid
= map_port_name_to_mid (thread_list
[ index
],
2863 ret
= thread_suspend(thread_list
[ index
]);
2865 if (ret
!= KERN_SUCCESS
)
2866 message ("Error trying to suspend thread %d : %s",
2867 mid
, mach_error_string (ret
));
2871 infoCnt
= THREAD_BASIC_INFO_COUNT
;
2872 ret
= thread_info (thread_list
[ index
],
2874 (thread_info_t
) &th_info
,
2876 CHK ("suspend can't get thread info", ret
);
2878 message ("Thread %d suspend count is %d",
2879 mid
, th_info
.suspend_count
);
2883 consume_send_rights (thread_list
, thread_count
);
2884 ret
= vm_deallocate(mach_task_self(),
2885 (vm_address_t
)thread_list
,
2886 (thread_count
* sizeof(int)));
2887 CHK ("Error trying to deallocate thread list", ret
);
2891 thread_suspend_command (args
, from_tty
)
2897 mach_port_t saved_thread
;
2899 thread_basic_info_data_t th_info
;
2901 MACH_ERROR_NO_INFERIOR
;
2903 if (!strcasecmp (args
, "all")) {
2904 suspend_all_threads (from_tty
);
2908 saved_thread
= current_thread
;
2910 mid
= parse_thread_id (args
, 0, 0);
2913 error ("You can suspend only existing kernel threads with MID or @SLOTNUMBER");
2916 mid
= map_port_name_to_mid (current_thread
, MACH_TYPE_THREAD
);
2918 if (select_thread (inferior_task
, mid
, 0) != KERN_SUCCESS
)
2921 current_thread
= saved_thread
;
2922 error ("Could not select thread %d", mid
);
2925 ret
= thread_suspend (current_thread
);
2926 if (ret
!= KERN_SUCCESS
)
2927 message ("thread_suspend failed : %s",
2928 mach_error_string (ret
));
2930 infoCnt
= THREAD_BASIC_INFO_COUNT
;
2931 ret
= thread_info (current_thread
,
2933 (thread_info_t
) &th_info
,
2935 CHK ("suspend can't get thread info", ret
);
2937 message ("Thread %d suspend count is %d", mid
, th_info
.suspend_count
);
2939 current_thread
= saved_thread
;
2942 resume_all_threads (from_tty
)
2946 thread_array_t thread_list
;
2947 int thread_count
, index
;
2950 thread_basic_info_data_t th_info
;
2952 ret
= task_threads (inferior_task
, &thread_list
, &thread_count
);
2953 if (ret
!= KERN_SUCCESS
)
2956 error("task_threads", mach_error_string( ret
));
2959 for (index
= 0; index
< thread_count
; index
++)
2961 infoCnt
= THREAD_BASIC_INFO_COUNT
;
2962 ret
= thread_info (thread_list
[ index
],
2964 (thread_info_t
) &th_info
,
2966 CHK ("resume_all can't get thread info", ret
);
2968 mid
= map_port_name_to_mid (thread_list
[ index
],
2971 if (! th_info
.suspend_count
)
2973 if (mid
!= -1 && from_tty
)
2974 message ("Thread %d is not suspended", mid
);
2978 ret
= thread_resume (thread_list
[ index
]);
2980 if (ret
!= KERN_SUCCESS
)
2981 message ("Error trying to resume thread %d : %s",
2982 mid
, mach_error_string (ret
));
2983 else if (mid
!= -1 && from_tty
)
2984 message ("Thread %d suspend count is %d",
2985 mid
, --th_info
.suspend_count
);
2988 consume_send_rights (thread_list
, thread_count
);
2989 ret
= vm_deallocate(mach_task_self(),
2990 (vm_address_t
)thread_list
,
2991 (thread_count
* sizeof(int)));
2992 CHK("Error trying to deallocate thread list", ret
);
2996 thread_resume_command (args
, from_tty
)
3001 mach_port_t saved_thread
;
3003 thread_basic_info_data_t th_info
;
3004 int infoCnt
= THREAD_BASIC_INFO_COUNT
;
3006 MACH_ERROR_NO_INFERIOR
;
3008 if (!strcasecmp (args
, "all")) {
3009 resume_all_threads (from_tty
);
3013 saved_thread
= current_thread
;
3015 mid
= parse_thread_id (args
, 0, 0);
3018 error ("You can resume only existing kernel threads with MID or @SLOTNUMBER");
3021 mid
= map_port_name_to_mid (current_thread
, MACH_TYPE_THREAD
);
3023 if (select_thread (inferior_task
, mid
, 0) != KERN_SUCCESS
)
3026 current_thread
= saved_thread
;
3027 return_to_top_level ();
3030 ret
= thread_info (current_thread
,
3032 (thread_info_t
) &th_info
,
3034 CHK ("resume can't get thread info", ret
);
3036 if (! th_info
.suspend_count
)
3038 message ("Thread %d is not suspended", mid
);
3042 ret
= thread_resume (current_thread
);
3043 if (ret
!= KERN_SUCCESS
)
3044 message ("thread_resume failed : %s",
3045 mach_error_string (ret
));
3048 th_info
.suspend_count
--;
3049 message ("Thread %d suspend count is %d", mid
, th_info
.suspend_count
);
3053 current_thread
= saved_thread
;
3057 thread_kill_command (args
, from_tty
)
3064 thread_array_t thread_table
;
3066 mach_port_t thread_to_kill
= MACH_PORT_NULL
;
3069 MACH_ERROR_NO_INFERIOR
;
3072 error_no_arg ("thread mid to kill from the inferior task");
3074 mid
= parse_thread_id (args
, 0, 0);
3077 error ("You can kill only existing kernel threads with MID or @SLOTNUMBER");
3081 ret
= machid_mach_port (mid_server
, mid_auth
, mid
, &thread_to_kill
);
3082 CHK ("thread_kill_command: machid_mach_port map failed", ret
);
3085 mid
= map_port_name_to_mid (current_thread
, MACH_TYPE_THREAD
);
3087 /* Don't allow gdb to kill *any* thread in the system. Use mkill program for that */
3088 ret
= task_threads (inferior_task
, &thread_table
, &thread_count
);
3089 CHK ("Error getting inferior's thread list", ret
);
3091 if (thread_to_kill
== current_thread
)
3093 ret
= thread_terminate (thread_to_kill
);
3094 CHK ("Thread could not be terminated", ret
);
3096 if (select_thread (inferior_task
, 0, 1) != KERN_SUCCESS
)
3097 message ("Last thread was killed, use \"kill\" command to kill task");
3100 for (index
= 0; index
< thread_count
; index
++)
3101 if (thread_table
[ index
] == thread_to_kill
)
3103 ret
= thread_terminate (thread_to_kill
);
3104 CHK ("Thread could not be terminated", ret
);
3107 if (thread_count
> 1)
3108 consume_send_rights (thread_table
, thread_count
);
3110 ret
= vm_deallocate (mach_task_self(), (vm_address_t
)thread_table
,
3111 (thread_count
* sizeof(mach_port_t
)));
3112 CHK ("Error trying to deallocate thread list", ret
);
3114 message ("Thread %d killed", mid
);
3118 /* Task specific commands; add more if you like */
3121 task_resume_command (args
, from_tty
)
3126 task_basic_info_data_t ta_info
;
3127 int infoCnt
= TASK_BASIC_INFO_COUNT
;
3128 int mid
= map_port_name_to_mid (inferior_task
, MACH_TYPE_TASK
);
3130 MACH_ERROR_NO_INFERIOR
;
3132 /* Would be trivial to change, but is it desirable? */
3134 error ("Currently gdb can resume only it's inferior task");
3136 ret
= task_info (inferior_task
,
3138 (task_info_t
) &ta_info
,
3140 CHK ("task_resume_command: task_info failed", ret
);
3142 if (ta_info
.suspend_count
== 0)
3143 error ("Inferior task %d is not suspended", mid
);
3144 else if (ta_info
.suspend_count
== 1 &&
3146 !query ("Suspend count is now 1. Do you know what you are doing? "))
3147 error ("Task not resumed");
3149 ret
= task_resume (inferior_task
);
3150 CHK ("task_resume_command: task_resume", ret
);
3152 if (ta_info
.suspend_count
== 1)
3154 message ("Inferior task %d is no longer suspended", mid
);
3155 must_suspend_thread
= 1;
3156 /* @@ This is not complete: Registers change all the time when not
3158 registers_changed ();
3161 message ("Inferior task %d suspend count is now %d",
3162 mid
, ta_info
.suspend_count
-1);
3167 task_suspend_command (args
, from_tty
)
3172 task_basic_info_data_t ta_info
;
3173 int infoCnt
= TASK_BASIC_INFO_COUNT
;
3174 int mid
= map_port_name_to_mid (inferior_task
, MACH_TYPE_TASK
);
3176 MACH_ERROR_NO_INFERIOR
;
3178 /* Would be trivial to change, but is it desirable? */
3180 error ("Currently gdb can suspend only it's inferior task");
3182 ret
= task_suspend (inferior_task
);
3183 CHK ("task_suspend_command: task_suspend", ret
);
3185 must_suspend_thread
= 0;
3187 ret
= task_info (inferior_task
,
3189 (task_info_t
) &ta_info
,
3191 CHK ("task_suspend_command: task_info failed", ret
);
3193 message ("Inferior task %d suspend count is now %d",
3194 mid
, ta_info
.suspend_count
);
3201 static char size
[ 30 ];
3202 int zz
= bytes
/1024;
3205 sprintf (size
, "%-2.1f M", ((float)bytes
)/(1024.0*1024.0));
3207 sprintf (size
, "%d K", zz
);
3212 /* Does this require the target task to be suspended?? I don't think so. */
3214 task_info_command (args
, from_tty
)
3221 task_basic_info_data_t ta_info
;
3222 int infoCnt
= TASK_BASIC_INFO_COUNT
;
3223 int page_size
= round_page(1);
3224 int thread_count
= 0;
3226 if (MACH_PORT_VALID (inferior_task
))
3227 mid
= map_port_name_to_mid (inferior_task
,
3230 task
= inferior_task
;
3234 int tmid
= atoi (args
);
3237 error ("Invalid mid %d for task info", tmid
);
3242 ret
= machid_mach_port (mid_server
, mid_auth
, tmid
, &task
);
3243 CHK ("task_info_command: machid_mach_port map failed", ret
);
3248 error ("You have to give the task MID as an argument");
3250 ret
= task_info (task
,
3252 (task_info_t
) &ta_info
,
3254 CHK ("task_info_command: task_info failed", ret
);
3256 printf_filtered ("\nTask info for task %d:\n\n", mid
);
3257 printf_filtered (" Suspend count : %d\n", ta_info
.suspend_count
);
3258 printf_filtered (" Base priority : %d\n", ta_info
.base_priority
);
3259 printf_filtered (" Virtual size : %s\n", get_size (ta_info
.virtual_size
));
3260 printf_filtered (" Resident size : %s\n", get_size (ta_info
.resident_size
));
3263 thread_array_t thread_list
;
3265 ret
= task_threads (task
, &thread_list
, &thread_count
);
3266 CHK ("task_info_command: task_threads", ret
);
3268 printf_filtered (" Thread count : %d\n", thread_count
);
3270 consume_send_rights (thread_list
, thread_count
);
3271 ret
= vm_deallocate(mach_task_self(),
3272 (vm_address_t
)thread_list
,
3273 (thread_count
* sizeof(int)));
3274 CHK("Error trying to deallocate thread list", ret
);
3276 if (have_emulator_p (task
))
3277 printf_filtered (" Emulator at : 0x%x..0x%x\n",
3278 EMULATOR_BASE
, EMULATOR_END
);
3280 printf_filtered (" No emulator.\n");
3282 if (thread_count
&& task
== inferior_task
)
3283 printf_filtered ("\nUse the \"thread list\" command to see the threads\n");
3286 /* You may either FORWARD the exception to the inferior, or KEEP
3287 * it and return to GDB command level.
3289 * exception mid [ forward | keep ]
3293 exception_command (args
, from_tty
)
3302 error_no_arg ("exception number action");
3304 while (*scan
== ' ' || *scan
== '\t') scan
++;
3306 if ('0' <= *scan
&& *scan
<= '9')
3307 while ('0' <= *scan
&& *scan
<= '9')
3310 error ("exception number action");
3312 exception
= atoi (args
);
3313 if (exception
<= 0 || exception
> MAX_EXCEPTION
)
3314 error ("Allowed exception numbers are in range 1..%d",
3317 if (*scan
!= ' ' && *scan
!= '\t')
3318 error ("exception number must be followed by a space");
3320 while (*scan
== ' ' || *scan
== '\t') scan
++;
3331 error("exception number action");
3333 if (!strncasecmp (args
, "forward", len
))
3334 exception_map
[ exception
].forward
= TRUE
;
3335 else if (!strncasecmp (args
, "keep", len
))
3336 exception_map
[ exception
].forward
= FALSE
;
3338 error ("exception action is either \"keep\" or \"forward\"");
3342 print_exception_info (exception
)
3345 boolean_t forward
= exception_map
[ exception
].forward
;
3347 printf_filtered ("%s\t(%d): ", exception_map
[ exception
].name
,
3350 if (exception_map
[ exception
].sigmap
!= SIG_UNKNOWN
)
3351 printf_filtered ("keep and handle as signal %d\n",
3352 exception_map
[ exception
].sigmap
);
3354 printf_filtered ("keep and handle as unknown signal %d\n",
3355 exception_map
[ exception
].sigmap
);
3357 printf_filtered ("forward exception to inferior\n");
3361 exception_info (args
, from_tty
)
3368 for (exception
= 1; exception
<= MAX_EXCEPTION
; exception
++)
3369 print_exception_info (exception
);
3372 exception
= atoi (args
);
3374 if (exception
<= 0 || exception
> MAX_EXCEPTION
)
3375 error ("Invalid exception number, values from 1 to %d allowed",
3377 print_exception_info (exception
);
3381 /* Check for actions for mach exceptions.
3383 mach3_exception_actions (w
, force_print_only
, who
)
3385 boolean_t force_print_only
;
3388 boolean_t force_print
= FALSE
;
3391 if (force_print_only
||
3392 exception_map
[stop_exception
].sigmap
== SIG_UNKNOWN
)
3395 WSETSTOP (*w
, exception_map
[stop_exception
].sigmap
);
3397 if (exception_map
[stop_exception
].print
|| force_print
)
3399 int giveback
= grab_terminal ();
3401 printf_filtered ("\n%s received %s exception : ",
3403 exception_map
[stop_exception
].name
);
3407 switch(stop_exception
) {
3408 case EXC_BAD_ACCESS
:
3409 printf_filtered ("referencing address 0x%x : %s\n",
3411 mach_error_string (stop_code
));
3413 case EXC_BAD_INSTRUCTION
:
3415 ("illegal or undefined instruction. code %d subcode %d\n",
3416 stop_code
, stop_subcode
);
3418 case EXC_ARITHMETIC
:
3419 printf_filtered ("code %d\n", stop_code
);
3422 printf_filtered ("code %d subcode %d\n", stop_code
, stop_subcode
);
3425 printf_filtered ("%s specific, code 0x%x\n",
3426 stop_code
< 0xffff ? "hardware" : "os emulation",
3429 case EXC_BREAKPOINT
:
3430 printf_filtered ("type %d (machine dependent)\n",
3434 fatal ("Unknown exception");
3438 terminal_inferior ();
3442 setup_notify_port (create_new
)
3447 if (MACH_PORT_VALID (our_notify_port
))
3449 ret
= mach_port_destroy (mach_task_self (), our_notify_port
);
3450 CHK ("Could not destroy our_notify_port", ret
);
3453 our_notify_port
= MACH_PORT_NULL
;
3454 notify_chain
= (port_chain_t
) NULL
;
3455 port_chain_destroy (port_chain_obstack
);
3459 ret
= mach_port_allocate (mach_task_self(),
3460 MACH_PORT_RIGHT_RECEIVE
,
3462 if (ret
!= KERN_SUCCESS
)
3463 fatal("Creating notify port %s", mach_error_string(ret
));
3465 ret
= mach_port_move_member(mach_task_self(),
3467 inferior_wait_port_set
);
3468 if (ret
!= KERN_SUCCESS
)
3469 fatal("initial move member %s",mach_error_string(ret
));
3474 * Register our message port to the net name server
3476 * Currently used only by the external stop-gdb program
3477 * since ^C does not work if you would like to enter
3478 * gdb command level while debugging your program.
3480 * NOTE: If the message port is sometimes used for other
3481 * purposes also, the NAME must not be a guessable one.
3482 * Then, there should be a way to change it.
3485 char registered_name
[ MAX_NAME_LEN
];
3488 message_port_info (args
, from_tty
)
3492 if (registered_name
[0])
3493 printf_filtered ("gdb's message port name: '%s'\n",
3496 printf_filtered ("gdb's message port is not currently registered\n");
3500 gdb_register_port (name
, port
)
3505 static int already_signed
= 0;
3508 if (! MACH_PORT_VALID (port
) || !name
|| !*name
)
3510 message ("Invalid registration request");
3514 if (! already_signed
)
3516 ret
= mach_port_insert_right (mach_task_self (),
3519 MACH_MSG_TYPE_MAKE_SEND
);
3520 CHK ("Failed to create a signature to our_message_port", ret
);
3523 else if (already_signed
> 1)
3525 ret
= netname_check_out (name_server_port
,
3528 CHK ("Failed to check out gdb's message port", ret
);
3529 registered_name
[0] = '\000';
3533 ret
= netname_check_in (name_server_port
, /* Name server port */
3534 name
, /* Name of service */
3535 our_message_port
, /* Signature */
3536 port
); /* Creates a new send right */
3537 CHK("Failed to check in the port", ret
);
3540 while(len
< MAX_NAME_LEN
&& *(name
+len
))
3542 registered_name
[len
] = *(name
+len
);
3545 registered_name
[len
] = '\000';
3549 struct cmd_list_element
*cmd_thread_list
;
3550 struct cmd_list_element
*cmd_task_list
;
3554 thread_command (arg
, from_tty
)
3558 printf ("\"thread\" must be followed by the name of a thread command.\n");
3559 help_list (cmd_thread_list
, "thread ", -1, stdout
);
3564 task_command (arg
, from_tty
)
3568 printf ("\"task\" must be followed by the name of a task command.\n");
3569 help_list (cmd_task_list
, "task ", -1, stdout
);
3572 add_mach_specific_commands ()
3574 extern void condition_thread ();
3576 /* Thread handling commands */
3578 /* FIXME: Move our thread support into the generic thread.c stuff so we
3579 can share that code. */
3580 add_prefix_cmd ("mthread", class_stack
, thread_command
,
3581 "Generic command for handling Mach threads in the debugged task.",
3582 &cmd_thread_list
, "thread ", 0, &cmdlist
);
3584 add_com_alias ("th", "mthread", class_stack
, 1);
3586 add_cmd ("select", class_stack
, thread_select_command
,
3587 "Select and print MID of the selected thread",
3589 add_cmd ("list", class_stack
, thread_list_command
,
3590 "List info of task's threads. Selected thread is marked with '*'",
3592 add_cmd ("suspend", class_run
, thread_suspend_command
,
3593 "Suspend one or all of the threads in the selected task.",
3595 add_cmd ("resume", class_run
, thread_resume_command
,
3596 "Resume one or all of the threads in the selected task.",
3598 add_cmd ("kill", class_run
, thread_kill_command
,
3599 "Kill the specified thread MID from inferior task.",
3601 add_cmd ("break", class_breakpoint
, condition_thread
,
3602 "Breakpoint N will only be effective for thread MID or @SLOT\n\
3603 If MID/@SLOT is omitted allow all threads to break at breakpoint",
3605 /* Thread command shorthands (for backward compatibility) */
3606 add_alias_cmd ("ts", "mthread select", 0, 0, &cmdlist
);
3607 add_alias_cmd ("tl", "mthread list", 0, 0, &cmdlist
);
3609 /* task handling commands */
3611 add_prefix_cmd ("task", class_stack
, task_command
,
3612 "Generic command for handling debugged task.",
3613 &cmd_task_list
, "task ", 0, &cmdlist
);
3615 add_com_alias ("ta", "task", class_stack
, 1);
3617 add_cmd ("suspend", class_run
, task_suspend_command
,
3618 "Suspend the inferior task.",
3620 add_cmd ("resume", class_run
, task_resume_command
,
3621 "Resume the inferior task.",
3623 add_cmd ("info", no_class
, task_info_command
,
3624 "Print information about the specified task.",
3627 /* Print my message port name */
3629 add_info ("message-port", message_port_info
,
3630 "Returns the name of gdb's message port in the netnameserver");
3632 /* Exception commands */
3634 add_info ("exceptions", exception_info
,
3635 "What debugger does when program gets various exceptions.\n\
3636 Specify an exception number as argument to print info on that\n\
3639 add_com ("exception", class_run
, exception_command
,
3640 "Specify how to handle an exception.\n\
3641 Args are exception number followed by \"forward\" or \"keep\".\n\
3642 `Forward' means forward the exception to the program's normal exception\n\
3644 `Keep' means reenter debugger if this exception happens, and GDB maps\n\
3645 the exception to some signal (see info exception)\n\
3646 Normally \"keep\" is used to return to GDB on exception.");
3650 do_mach_notify_dead_name (notify
, name
)
3654 kern_return_t kr
= KERN_SUCCESS
;
3656 /* Find the thing that notified */
3657 port_chain_t element
= port_chain_member (notify_chain
, name
);
3659 /* Take name of from unreceived dead name notification list */
3660 notify_chain
= port_chain_delete (notify_chain
, name
);
3663 error ("Received a dead name notify from unchained port (0x%x)", name
);
3665 switch (element
->type
) {
3667 case MACH_TYPE_THREAD
:
3668 if (name
== current_thread
)
3670 message ("\nCurrent thread %d died", element
->mid
);
3671 current_thread
= MACH_PORT_NULL
;
3674 message ("\nThread %d died", element
->mid
);
3678 case MACH_TYPE_TASK
:
3679 if (name
!= inferior_task
)
3680 message ("Task %d died, but it was not the selected task",
3684 message ("Current task %d died", element
->mid
);
3686 mach_port_destroy (mach_task_self(), name
);
3687 inferior_task
= MACH_PORT_NULL
;
3690 message("There were still unreceived dead_name_notifications???");
3692 /* Destroy the old notifications */
3693 setup_notify_port (0);
3699 error ("Unregistered dead_name 0x%x notification received. Type is %d, mid is 0x%x",
3700 name
, element
->type
, element
->mid
);
3704 return KERN_SUCCESS
;
3708 do_mach_notify_msg_accepted (notify
, name
)
3712 message ("do_mach_notify_msg_accepted : notify %x, name %x",
3714 return KERN_SUCCESS
;
3718 do_mach_notify_no_senders (notify
, mscount
)
3720 mach_port_mscount_t mscount
;
3722 message ("do_mach_notify_no_senders : notify %x, mscount %x",
3724 return KERN_SUCCESS
;
3728 do_mach_notify_port_deleted (notify
, name
)
3732 message ("do_mach_notify_port_deleted : notify %x, name %x",
3734 return KERN_SUCCESS
;
3738 do_mach_notify_port_destroyed (notify
, rights
)
3742 message ("do_mach_notify_port_destroyed : notify %x, rights %x",
3744 return KERN_SUCCESS
;
3748 do_mach_notify_send_once (notify
)
3752 /* MANY of these are generated. */
3753 message ("do_mach_notify_send_once : notify %x",
3756 return KERN_SUCCESS
;
3759 /* Kills the inferior. It's gone when you call this */
3761 kill_inferior_fast ()
3765 if (inferior_pid
== 0 || inferior_pid
== 1)
3768 /* kill() it, since the Unix server does not otherwise notice when
3769 * killed with task_terminate().
3771 if (inferior_pid
> 0)
3772 kill (inferior_pid
, SIGKILL
);
3774 /* It's propably terminate already */
3775 (void) task_terminate (inferior_task
);
3777 inferior_task
= MACH_PORT_NULL
;
3778 current_thread
= MACH_PORT_NULL
;
3780 wait3 (&w
, WNOHANG
, 0);
3782 setup_notify_port (0);
3788 kill_inferior_fast ();
3789 target_mourn_inferior ();
3792 /* Clean up after the inferior dies. */
3795 m3_mourn_inferior ()
3797 unpush_target (&m3_ops
);
3798 generic_mourn_inferior ();
3802 /* Fork an inferior process, and start debugging it. */
3805 m3_create_inferior (exec_file
, allargs
, env
)
3810 fork_inferior (exec_file
, allargs
, env
, m3_trace_m3
, m3_trace_him
);
3811 /* We are at the first instruction we care about. */
3812 /* Pedal to the metal... */
3813 proceed ((CORE_ADDR
) -1, 0, 0);
3816 /* Mark our target-struct as eligible for stray "run" and "attach"
3824 /* Mach 3.0 does not need ptrace for anything
3825 * Make sure nobody uses it on mach.
3830 error ("Lose, Lose! Somebody called ptrace\n");
3833 /* Resume execution of the inferior process.
3834 If STEP is nonzero, single-step it.
3835 If SIGNAL is nonzero, give it that signal. */
3838 m3_resume (pid
, step
, signal
)
3847 thread_basic_info_data_t th_info
;
3848 unsigned int infoCnt
= THREAD_BASIC_INFO_COUNT
;
3850 /* There is no point in single stepping when current_thread
3853 if (! MACH_PORT_VALID (current_thread
))
3854 error ("No thread selected; can not single step");
3856 /* If current_thread is suspended, tracing it would never return.
3858 ret
= thread_info (current_thread
,
3860 (thread_info_t
) &th_info
,
3862 CHK ("child_resume: can't get thread info", ret
);
3864 if (th_info
.suspend_count
)
3865 error ("Can't trace a suspended thread. Use \"thread resume\" command to resume it");
3868 vm_read_cache_valid
= FALSE
;
3870 if (signal
&& inferior_pid
> 0) /* Do not signal, if attached by MID */
3871 kill (inferior_pid
, signal
);
3875 suspend_all_threads (0);
3877 setup_single_step (current_thread
, TRUE
);
3879 ret
= thread_resume (current_thread
);
3880 CHK ("thread_resume", ret
);
3883 ret
= task_resume (inferior_task
);
3884 if (ret
== KERN_FAILURE
)
3885 message ("Task was not suspended");
3887 CHK ("Resuming task", ret
);
3889 /* HACK HACK This is needed by the multiserver system HACK HACK */
3890 while ((ret
= task_resume(inferior_task
)) == KERN_SUCCESS
)
3891 /* make sure it really runs */;
3892 /* HACK HACK This is needed by the multiserver system HACK HACK */
3895 #ifdef ATTACH_DETACH
3897 /* Start debugging the process with the given task */
3903 inferior_task
= tid
;
3905 ret
= task_suspend (inferior_task
);
3906 CHK("task_attach: task_suspend", ret
);
3908 must_suspend_thread
= 0;
3910 setup_notify_port (1);
3912 request_notify (inferior_task
, MACH_NOTIFY_DEAD_NAME
, MACH_TYPE_TASK
);
3914 setup_exception_port ();
3916 emulator_present
= have_emulator_p (inferior_task
);
3921 /* Well, we can call error also here and leave the
3922 * target stack inconsistent. Sigh.
3923 * Fix this sometime (the only way to fail here is that
3924 * the task has no threads at all, which is rare, but
3925 * possible; or if the target task has died, which is also
3926 * possible, but unlikely, since it has been suspended.
3927 * (Someone must have killed it))
3932 if (select_thread (inferior_task
, 0, 1) != KERN_SUCCESS
)
3933 error ("Could not select any threads to attach to");
3941 ret
= machid_mach_port (mid_server
, mid_auth
, mid
, &inferior_task
);
3942 CHK("mid_attach: machid_mach_port", ret
);
3944 task_attach (inferior_task
);
3950 * Start debugging the process whose unix process-id is PID.
3951 * A negative "pid" value is legal and signifies a mach_id not a unix pid.
3953 * Prevent (possible unwanted) dangerous operations by enabled users
3954 * like "atta 0" or "atta foo" (equal to the previous :-) and
3955 * "atta pidself". Anyway, the latter is allowed by specifying a MID.
3964 error("MID=0, Debugging the master unix server does not compute");
3966 /* Foo. This assumes gdb has a unix pid */
3967 if (pid
== getpid())
3968 error ("I will debug myself only by mid. (Gdb would suspend itself!)");
3972 mid_attach (-(pid
));
3974 /* inferior_pid will be NEGATIVE! */
3977 return inferior_pid
;
3980 inferior_task
= task_by_pid (pid
);
3981 if (! MACH_PORT_VALID (inferior_task
))
3982 error("Cannot map Unix pid %d to Mach task port", pid
);
3984 task_attach (inferior_task
);
3988 return inferior_pid
;
3991 /* Attach to process PID, then initialize for debugging it
3992 and wait for the trace-trap that results from attaching. */
3995 m3_attach (args
, from_tty
)
4003 error_no_arg ("process-id to attach");
4007 if (pid
== getpid()) /* Trying to masturbate? */
4008 error ("I refuse to debug myself!");
4012 exec_file
= (char *) get_exec_file (0);
4015 printf ("Attaching to program `%s', %s\n", exec_file
, target_pid_to_str (pid
));
4017 printf ("Attaching to %s\n", target_pid_to_str (pid
));
4024 push_target (&procfs_ops
);
4028 deallocate_inferior_ports ()
4031 thread_array_t thread_list
;
4032 int thread_count
, index
;
4034 if (!MACH_PORT_VALID (inferior_task
))
4037 ret
= task_threads (inferior_task
, &thread_list
, &thread_count
);
4038 if (ret
!= KERN_SUCCESS
)
4040 message ("deallocate_inferior_ports: task_threads",
4041 mach_error_string(ret
));
4045 /* Get rid of send rights to task threads */
4046 for (index
= 0; index
< thread_count
; index
++)
4049 ret
= mach_port_get_refs (mach_task_self (),
4051 MACH_PORT_RIGHT_SEND
,
4053 CHK("deallocate_inferior_ports: get refs", ret
);
4057 ret
= mach_port_mod_refs (mach_task_self (),
4059 MACH_PORT_RIGHT_SEND
,
4061 CHK("deallocate_inferior_ports: mod refs", ret
);
4065 ret
= mach_port_mod_refs (mach_task_self (),
4066 inferior_exception_port
,
4067 MACH_PORT_RIGHT_RECEIVE
,
4069 CHK ("deallocate_inferior_ports: cannot get rid of exception port", ret
);
4071 ret
= mach_port_deallocate (mach_task_self (),
4073 CHK ("deallocate_task_port: deallocating inferior_task", ret
);
4075 current_thread
= MACH_PORT_NULL
;
4076 inferior_task
= MACH_PORT_NULL
;
4079 /* Stop debugging the process whose number is PID
4080 and continue it with signal number SIGNAL.
4081 SIGNAL = 0 means just continue it. */
4084 m3_do_detach (signal
)
4089 MACH_ERROR_NO_INFERIOR
;
4091 if (current_thread
!= MACH_PORT_NULL
)
4093 /* Store the gdb's view of the thread we are deselecting
4095 * @@ I am really not sure if this is ever needeed.
4097 target_prepare_to_store ();
4098 target_store_registers (-1);
4101 ret
= task_set_special_port (inferior_task
,
4102 TASK_EXCEPTION_PORT
,
4103 inferior_old_exception_port
);
4104 CHK ("task_set_special_port", ret
);
4106 /* Discard all requested notifications */
4107 setup_notify_port (0);
4109 if (remove_breakpoints ())
4110 message ("Could not remove breakpoints when detaching");
4112 if (signal
&& inferior_pid
> 0)
4113 kill (inferior_pid
, signal
);
4115 /* the task might be dead by now */
4116 (void) task_resume (inferior_task
);
4118 deallocate_inferior_ports ();
4123 /* Take a program previously attached to and detaches it.
4124 The program resumes execution and will no longer stop
4125 on signals, etc. We'd better not have left any breakpoints
4126 in the program or it'll die when it hits one. For this
4127 to work, it may be necessary for the process to have been
4128 previously attached. It *might* work if the program was
4129 started via fork. */
4132 m3_detach (args
, from_tty
)
4140 char *exec_file
= get_exec_file (0);
4143 printf ("Detaching from program: %s %s\n",
4144 exec_file
, target_pid_to_str (inferior_pid
));
4148 siggnal
= atoi (args
);
4150 m3_do_detach (siggnal
);
4152 unpush_target (&m3_ops
); /* Pop out of handling an inferior */
4154 #endif /* ATTACH_DETACH */
4163 char *bsd1_names
[] = {
4231 int bsd1_nnames
= sizeof(bsd1_names
)/sizeof(bsd1_names
[0]);
4241 case MACH_MSG_TYPE_BOOLEAN
:
4243 case MACH_MSG_TYPE_INTEGER_16
:
4245 case MACH_MSG_TYPE_INTEGER_32
:
4247 case MACH_MSG_TYPE_CHAR
:
4249 case MACH_MSG_TYPE_BYTE
:
4251 case MACH_MSG_TYPE_REAL
:
4253 case MACH_MSG_TYPE_STRING
:
4256 sprintf(buf
,"%d",name
);
4269 if (id
>= 101000 && id
< 101000+bsd1_nnames
) {
4270 if (p
= bsd1_names
[id
-101000])
4274 return "psignal_retry";
4277 sprintf(buf
,"%d",id
);
4282 mach_msg_header_t
*mp
;
4284 char *fmt_x
= "%20s : 0x%08x\n";
4285 char *fmt_d
= "%20s : %10d\n";
4286 char *fmt_s
= "%20s : %s\n";
4289 puts_filtered ("\n");
4290 #define pr(fmt,h,x) printf_filtered(fmt,STR(x),(h).x)
4291 pr(fmt_x
,(*mp
),msgh_bits
);
4292 pr(fmt_d
,(*mp
),msgh_size
);
4293 pr(fmt_x
,(*mp
),msgh_remote_port
);
4294 pr(fmt_x
,(*mp
),msgh_local_port
);
4295 pr(fmt_d
,(*mp
),msgh_kind
);
4296 printf_filtered(fmt_s
,STR(msgh_id
),id_str(mp
->msgh_id
,buf
));
4298 if (debug_level
> 1)
4303 ep
= p
+mp
->msgh_size
;
4305 for(; p
< ep
; p
+= plen
) {
4306 mach_msg_type_t
*tp
;
4307 mach_msg_type_long_t
*tlp
;
4308 int name
,size
,number
;
4309 tp
= (mach_msg_type_t
*)p
;
4310 if (tp
->msgt_longform
) {
4311 tlp
= (mach_msg_type_long_t
*)tp
;
4312 name
= tlp
->msgtl_name
;
4313 size
= tlp
->msgtl_size
;
4314 number
= tlp
->msgtl_number
;
4315 plen
= sizeof(*tlp
);
4317 name
= tp
->msgt_name
;
4318 size
= tp
->msgt_size
;
4319 number
= tp
->msgt_number
;
4322 printf_filtered("name=%-16s size=%2d number=%7d inline=%d long=%d deal=%d\n",
4323 name_str(name
,buf
),size
,number
,tp
->msgt_inline
,
4324 tp
->msgt_longform
, tp
->msgt_deallocate
);
4326 if (tp
->msgt_inline
) {
4329 l
= (l
+sizeof(long)-1)&~((sizeof(long))-1);
4331 print_data(dp
,size
,number
);
4333 plen
+= sizeof(int*);
4335 printf_filtered("plen=%d\n",plen
);
4340 print_data(p
,size
,number
)
4351 for(i
= 0; i
< number
; i
++) {
4352 printf_filtered(" %02x",p
[i
]);
4357 for(i
= 0; i
< number
; i
++) {
4358 printf_filtered(" %04x",sp
[i
]);
4363 for(i
= 0; i
< number
; i
++) {
4364 printf_filtered(" %08x",ip
[i
]);
4368 puts_filtered("\n");
4372 struct target_ops m3_ops
= {
4373 "mach", /* to_shortname */
4374 "Mach child process", /* to_longname */
4375 "Mach child process (started by the \"run\" command).", /* to_doc */
4376 ??_open
, /* to_open */
4378 m3_attach
, /* to_attach */
4379 m3_detach
, /* to_detach */
4380 m3_resume
, /* to_resume */
4381 mach_really_wait
, /* to_wait */
4382 fetch_inferior_registers
, /* to_fetch_registers */
4383 store_inferior_registers
, /* to_store_registers */
4384 child_prepare_to_store
, /* to_prepare_to_store */
4385 m3_xfer_memory
, /* to_xfer_memory */
4387 /* FIXME: Should print MID and all that crap. */
4388 child_files_info
, /* to_files_info */
4390 memory_insert_breakpoint
, /* to_insert_breakpoint */
4391 memory_remove_breakpoint
, /* to_remove_breakpoint */
4392 terminal_init_inferior
, /* to_terminal_init */
4393 terminal_inferior
, /* to_terminal_inferior */
4394 terminal_ours_for_output
, /* to_terminal_ours_for_output */
4395 terminal_ours
, /* to_terminal_ours */
4396 child_terminal_info
, /* to_terminal_info */
4397 m3_kill_inferior
, /* to_kill */
4399 0, /* to_lookup_symbol */
4401 m3_create_inferior
, /* to_create_inferior */
4402 m3_mourn_inferior
, /* to_mourn_inferior */
4403 m3_can_run
, /* to_can_run */
4404 0, /* to_notice_signals */
4405 process_stratum
, /* to_stratum */
4407 1, /* to_has_all_memory */
4408 1, /* to_has_memory */
4409 1, /* to_has_stack */
4410 1, /* to_has_registers */
4411 1, /* to_has_execution */
4413 0, /* sections_end */
4414 OPS_MAGIC
/* to_magic */
4418 _initialize_m3_nat ()
4422 add_target (&m3_ops
);
4424 ret
= mach_port_allocate(mach_task_self(),
4425 MACH_PORT_RIGHT_PORT_SET
,
4426 &inferior_wait_port_set
);
4427 if (ret
!= KERN_SUCCESS
)
4428 fatal("initial port set %s",mach_error_string(ret
));
4430 /* mach_really_wait now waits for this */
4431 currently_waiting_for
= inferior_wait_port_set
;
4433 ret
= netname_look_up(name_server_port
, hostname
, "MachID", &mid_server
);
4434 if (ret
!= KERN_SUCCESS
)
4436 mid_server
= MACH_PORT_NULL
;
4438 message ("initialize machid: netname_lookup_up(MachID) : %s",
4439 mach_error_string(ret
));
4440 message ("Some (most?) features disabled...");
4443 mid_auth
= mach_privileged_host_port();
4444 if (mid_auth
== MACH_PORT_NULL
)
4445 mid_auth
= mach_task_self();
4447 obstack_init (port_chain_obstack
);
4449 ret
= mach_port_allocate (mach_task_self (),
4450 MACH_PORT_RIGHT_RECEIVE
,
4451 &thread_exception_port
);
4452 CHK ("Creating thread_exception_port for single stepping", ret
);
4454 ret
= mach_port_insert_right (mach_task_self (),
4455 thread_exception_port
,
4456 thread_exception_port
,
4457 MACH_MSG_TYPE_MAKE_SEND
);
4458 CHK ("Inserting send right to thread_exception_port", ret
);
4460 /* Allocate message port */
4461 ret
= mach_port_allocate (mach_task_self (),
4462 MACH_PORT_RIGHT_RECEIVE
,
4464 if (ret
!= KERN_SUCCESS
)
4465 message ("Creating message port %s", mach_error_string (ret
));
4468 char buf
[ MAX_NAME_LEN
];
4469 ret
= mach_port_move_member(mach_task_self (),
4471 inferior_wait_port_set
);
4472 if (ret
!= KERN_SUCCESS
)
4473 message ("message move member %s", mach_error_string (ret
));
4476 /* @@@@ No way to change message port name currently */
4477 /* Foo. This assumes gdb has a unix pid */
4478 sprintf (buf
, "gdb-%d", getpid ());
4479 gdb_register_port (buf
, our_message_port
);
4482 /* Heap for thread commands */
4483 obstack_init (cproc_obstack
);
4485 add_mach_specific_commands ();