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. */
25 * Helsinki University of Technology
28 * Thanks to my friends who helped with ideas and testing:
30 * Johannes Helander, Antti Louko, Tero Mononen,
33 * Tero Kivinen and Eamonn McManus
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>
60 #include <servers/machid_lib.h>
62 #define MACH_TYPE_TASK 1
63 #define MACH_TYPE_THREAD 2
66 /* Included only for signal names and NSIG
68 * note: There are many problems in signal handling with
69 * gdb in Mach 3.0 in general.
72 #define SIG_UNKNOWN 0 /* Exception that has no matching unix signal */
76 /* This is what a cproc looks like. This is here partly because
77 cthread_internals.h is not a header we can just #include, partly with
78 an eye towards perhaps getting this to work with cross-debugging
79 someday. Best solution is if CMU publishes a real interface to this
81 #define CPROC_NEXT_OFFSET 0
82 #define CPROC_NEXT_SIZE (TARGET_PTR_BIT / HOST_CHAR_BIT)
83 #define CPROC_INCARNATION_OFFSET (CPROC_NEXT_OFFSET + CPROC_NEXT_SIZE)
84 #define CPROC_INCARNATION_SIZE (sizeof (cthread_t))
85 #define CPROC_LIST_OFFSET (CPROC_INCARNATION_OFFSET + CPROC_INCARNATION_SIZE)
86 #define CPROC_LIST_SIZE (TARGET_PTR_BIT / HOST_CHAR_BIT)
87 #define CPROC_WAIT_OFFSET (CPROC_LIST_OFFSET + CPROC_LIST_SIZE)
88 #define CPROC_WAIT_SIZE (TARGET_PTR_BIT / HOST_CHAR_BIT)
89 #define CPROC_REPLY_OFFSET (CPROC_WAIT_OFFSET + CPROC_WAIT_SIZE)
90 #define CPROC_REPLY_SIZE (sizeof (mach_port_t))
91 #define CPROC_CONTEXT_OFFSET (CPROC_REPLY_OFFSET + CPROC_REPLY_SIZE)
92 #define CPROC_CONTEXT_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT)
93 #define CPROC_LOCK_OFFSET (CPROC_CONTEXT_OFFSET + CPROC_CONTEXT_SIZE)
94 #define CPROC_LOCK_SIZE (sizeof (spin_lock_t))
95 #define CPROC_STATE_OFFSET (CPROC_LOCK_OFFSET + CPROC_LOCK_SIZE)
96 #define CPROC_STATE_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT)
97 #define CPROC_WIRED_OFFSET (CPROC_STATE_OFFSET + CPROC_STATE_SIZE)
98 #define CPROC_WIRED_SIZE (sizeof (mach_port_t))
99 #define CPROC_BUSY_OFFSET (CPROC_WIRED_OFFSET + CPROC_WIRED_SIZE)
100 #define CPROC_BUSY_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT)
101 #define CPROC_MSG_OFFSET (CPROC_BUSY_OFFSET + CPROC_BUSY_SIZE)
102 #define CPROC_MSG_SIZE (sizeof (mach_msg_header_t))
103 #define CPROC_BASE_OFFSET (CPROC_MSG_OFFSET + CPROC_MSG_SIZE)
104 #define CPROC_BASE_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT)
105 #define CPROC_SIZE_OFFSET (CPROC_BASE_OFFSET + CPROC_BASE_SIZE)
106 #define CPROC_SIZE_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT)
107 #define CPROC_SIZE (CPROC_SIZE_OFFSET + CPROC_SIZE_SIZE)
109 /* Values for the state field in the cproc. */
110 #define CPROC_RUNNING 0
111 #define CPROC_SWITCHING 1
112 #define CPROC_BLOCKED 2
113 #define CPROC_CONDWAIT 4
115 /* For cproc and kernel thread mapping */
116 typedef struct gdb_thread {
121 boolean_t in_emulator;
124 /* This is for the mthreads list. It points to the cproc list.
125 Perhaps the two lists should be merged (or perhaps it was a mistake
126 to make them both use a struct gdb_thread). */
127 struct gdb_thread *cproc;
129 /* These are for the cproc list, which is linked through the next field
130 of the struct gdb_thread. */
131 char raw_cproc[CPROC_SIZE];
132 /* The cthread which is pointed to by the incarnation field from the
133 cproc. This points to the copy we've read into GDB. */
135 /* Point back to the mthreads list. */
137 struct gdb_thread *next;
141 * Actions for Mach exceptions.
143 * sigmap field maps the exception to corresponding Unix signal.
145 * I do not know how to map the exception to unix signal
146 * if SIG_UNKNOWN is specified.
149 struct exception_list {
154 } exception_map[] = {
155 {"not_mach3_exception", FALSE, TRUE, SIG_UNKNOWN},
156 {"EXC_BAD_ACCESS", FALSE, TRUE, SIGSEGV},
157 {"EXC_BAD_INSTRUCTION", FALSE, TRUE, SIGILL},
158 {"EXC_ARITHMETIC", FALSE, TRUE, SIGFPE},
159 {"EXC_EMULATION", FALSE, TRUE, SIGEMT}, /* ??? */
160 {"EXC_SOFTWARE", FALSE, TRUE, SIG_UNKNOWN},
161 {"EXC_BREAKPOINT", FALSE, FALSE, SIGTRAP}
164 /* Mach exception table size */
165 int max_exception = sizeof(exception_map)/sizeof(struct exception_list) - 1;
167 #define MAX_EXCEPTION max_exception
169 WAITTYPE wait_status;
171 /* If you define this, intercepted bsd server calls will be
172 * dumped while waiting the inferior to EXEC the correct
175 /* #define DUMP_SYSCALL /* debugging interceptor */
177 /* xx_debug() outputs messages if this is nonzero.
178 * If > 1, DUMP_SYSCALL will dump message contents.
182 /* "Temporary" debug stuff */
184 xx_debug (fmt, a,b,c)
189 warning (fmt, a, b, c);
192 /* This is in libmach.a */
193 extern mach_port_t name_server_port;
195 /* Set in catch_exception_raise */
196 int stop_exception, stop_code, stop_subcode;
197 int stopped_in_exception;
199 /* Thread that was the active thread when we stopped */
200 thread_t stop_thread = MACH_PORT_NULL;
204 /* Set when task is attached or created */
205 boolean_t emulator_present = FALSE;
207 task_t inferior_task;
208 thread_t current_thread;
210 /* Exception ports for inferior task */
211 mach_port_t inferior_exception_port = MACH_PORT_NULL;
212 mach_port_t inferior_old_exception_port = MACH_PORT_NULL;
214 /* task exceptions and notifications */
215 mach_port_t inferior_wait_port_set = MACH_PORT_NULL;
216 mach_port_t our_notify_port = MACH_PORT_NULL;
218 /* This is "inferior_wait_port_set" when not single stepping, and
219 * "singlestepped_thread_port" when we are single stepping.
221 * This is protected by a cleanup function: discard_single_step()
223 mach_port_t currently_waiting_for = MACH_PORT_NULL;
225 /* A port for external messages to gdb.
226 * External in the meaning that they do not come
227 * from the inferior_task, but rather from external
230 * As a debugging feature:
231 * A debugger debugging another debugger can stop the
232 * inferior debugger by the following command sequence
233 * (without running external programs)
235 * (top-gdb) set stop_inferior_gdb ()
238 mach_port_t our_message_port = MACH_PORT_NULL;
240 /* For single stepping */
241 mach_port_t thread_exception_port = MACH_PORT_NULL;
242 mach_port_t thread_saved_exception_port = MACH_PORT_NULL;
243 mach_port_t singlestepped_thread_port = MACH_PORT_NULL;
245 /* For machid calls */
246 mach_port_t mid_server = MACH_PORT_NULL;
247 mach_port_t mid_auth = MACH_PORT_NULL;
249 /* If gdb thinks the inferior task is not suspended, it
250 * must take suspend/abort the threads when it reads the state.
252 int must_suspend_thread = 0;
254 /* When single stepping, we switch the port that mach_really_wait() listens to.
255 * This cleanup is a guard to prevent the port set from being left to
256 * the singlestepped_thread_port when error() is called.
257 * This is nonzero only when we are single stepping.
259 #define NULL_CLEANUP (struct cleanup *)0
260 struct cleanup *cleanup_step = NULL_CLEANUP;
263 extern struct target_ops m3_ops;
264 static void m3_kill_inferior ();
267 #define MACH_TYPE_EXCEPTION_PORT -1
270 /* Chain of ports to remember requested notifications. */
273 struct port_chain *next;
276 int mid; /* Now only valid with MACH_TYPE_THREAD and */
277 /* MACH_TYPE_THREAD */
279 typedef struct port_chain *port_chain_t;
281 /* Room for chain nodes comes from pchain_obstack */
282 struct obstack pchain_obstack;
283 struct obstack *port_chain_obstack = &pchain_obstack;
285 /* For thread handling */
286 struct obstack Cproc_obstack;
287 struct obstack *cproc_obstack = &Cproc_obstack;
289 /* the list of notified ports */
290 port_chain_t notify_chain = (port_chain_t) NULL;
293 port_chain_insert (list, name, type)
302 if (! MACH_PORT_VALID (name))
305 if (type == MACH_TYPE_TASK || type == MACH_TYPE_THREAD)
307 if (! MACH_PORT_VALID (mid_server))
309 warning ("Machid server port invalid, can not map port 0x%x to MID",
315 ret = machid_mach_register (mid_server, mid_auth, name, type, &mid);
317 if (ret != KERN_SUCCESS)
319 warning ("Can not map name (0x%x) to MID with machid", name);
327 new = (port_chain_t) obstack_alloc (port_chain_obstack,
328 sizeof (struct port_chain));
338 port_chain_delete (list, elem)
343 if (list->port == elem)
348 if (list->next->port == elem)
349 list->next = list->next->next; /* GCd with obstack_free() */
357 port_chain_destroy (ostack)
358 struct obstack *ostack;
360 obstack_free (ostack, 0);
361 obstack_init (ostack);
365 port_chain_member (list, elem)
371 if (list->port == elem)
375 return (port_chain_t) NULL;
379 map_port_name_to_mid (name, type)
385 if (!MACH_PORT_VALID (name))
388 elem = port_chain_member (notify_chain, name);
390 if (elem && (elem->type == type))
396 if (! MACH_PORT_VALID (mid_server))
398 warning ("Machid server port invalid, can not map port 0x%x to mid",
407 ret = machid_mach_register (mid_server, mid_auth, name, type, &mid);
409 if (ret != KERN_SUCCESS)
411 warning ("Can not map name (0x%x) to mid with machid", name);
418 /* Guard for currently_waiting_for and singlestepped_thread_port */
420 discard_single_step (thread)
423 currently_waiting_for = inferior_wait_port_set;
425 cleanup_step = NULL_CLEANUP;
426 if (MACH_PORT_VALID (thread) && MACH_PORT_VALID (singlestepped_thread_port))
427 setup_single_step (thread, FALSE);
430 setup_single_step (thread, start_step)
432 boolean_t start_step;
436 if (! MACH_PORT_VALID (thread))
437 error ("Invalid thread supplied to setup_single_step");
442 /* Get the current thread exception port */
443 ret = thread_get_exception_port (thread, &teport);
444 CHK ("Getting thread's exception port", ret);
448 if (MACH_PORT_VALID (singlestepped_thread_port))
450 warning ("Singlestepped_thread_port (0x%x) is still valid?",
451 singlestepped_thread_port);
452 singlestepped_thread_port = MACH_PORT_NULL;
455 /* If we are already stepping this thread */
456 if (MACH_PORT_VALID (teport) && teport == thread_exception_port)
458 ret = mach_port_deallocate (mach_task_self (), teport);
459 CHK ("Could not deallocate thread exception port", ret);
463 ret = thread_set_exception_port (thread, thread_exception_port);
464 CHK ("Setting exception port for thread", ret);
466 /* Insert thread exception port to wait port set */
467 ret = mach_port_move_member (mach_task_self(),
468 thread_exception_port,
469 inferior_wait_port_set);
470 CHK ("Moving thread exception port to inferior_wait_port_set",
473 thread_saved_exception_port = teport;
476 thread_trace (thread, TRUE);
478 singlestepped_thread_port = thread_exception_port;
479 currently_waiting_for = singlestepped_thread_port;
480 cleanup_step = make_cleanup (discard_single_step, thread);
484 if (! MACH_PORT_VALID (teport))
485 error ("Single stepped thread had an invalid exception port?");
487 if (teport != thread_exception_port)
488 error ("Single stepped thread had an unknown exception port?");
490 ret = mach_port_deallocate (mach_task_self (), teport);
491 CHK ("Couldn't deallocate thread exception port", ret);
493 /* Remove thread exception port from wait port set */
494 ret = mach_port_move_member (mach_task_self(),
495 thread_exception_port,
497 CHK ("Removing thread exception port from inferior_wait_port_set",
500 /* Restore thread's old exception port */
501 ret = thread_set_exception_port (thread,
502 thread_saved_exception_port);
503 CHK ("Restoring stepped thread's exception port", ret);
505 if (MACH_PORT_VALID (thread_saved_exception_port))
506 (void) mach_port_deallocate (mach_task_self (),
507 thread_saved_exception_port);
509 thread_trace (thread, FALSE);
511 singlestepped_thread_port = MACH_PORT_NULL;
512 currently_waiting_for = inferior_wait_port_set;
514 discard_cleanups (cleanup_step);
520 request_notify (name, variant, type)
522 mach_msg_id_t variant;
526 mach_port_t previous_port_dummy = MACH_PORT_NULL;
528 if (! MACH_PORT_VALID (name))
531 if (port_chain_member (notify_chain, name))
534 ret = mach_port_request_notification (mach_task_self(),
539 MACH_MSG_TYPE_MAKE_SEND_ONCE,
540 &previous_port_dummy);
541 CHK ("Serious: request_notify failed", ret);
543 (void) mach_port_deallocate (mach_task_self (),
544 previous_port_dummy);
546 notify_chain = port_chain_insert (notify_chain, name, type);
549 reverse_msg_bits(msgp, type)
550 mach_msg_header_t *msgp;
554 rbits = MACH_MSGH_BITS_REMOTE(msgp->msgh_bits);
557 (msgp->msgh_bits & ~MACH_MSGH_BITS_PORTS_MASK) |
558 MACH_MSGH_BITS(lbits,rbits);
561 /* On the third day He said:
564 and then it was global.
566 When creating the inferior fork, the
567 child code in inflow.c sets the name of the
568 bootstrap_port in its address space to this
571 The name is transferred to our address space
572 with mach3_read_inferior().
574 Thou shalt not do this with
575 task_get_bootstrap_port() in this task, since
576 the name in the inferior task is different than
579 For blessed are the meek, as they shall inherit
582 mach_port_t original_server_port_name = MACH_PORT_NULL;
585 /* Called from inferior after FORK but before EXEC */
591 /* Get the NAME of the bootstrap port in this task
592 so that GDB can read it */
593 ret = task_get_bootstrap_port (mach_task_self (),
594 &original_server_port_name);
595 if (ret != KERN_SUCCESS)
597 ret = mach_port_deallocate (mach_task_self (),
598 original_server_port_name);
599 if (ret != KERN_SUCCESS)
602 /* Suspend this task to let the parent change my ports.
603 Resumed by the debugger */
604 ret = task_suspend (mach_task_self ());
605 if (ret != KERN_SUCCESS)
610 * Intercept system calls to Unix server.
611 * After EXEC_COUNTER calls to exec(), return.
613 * Pre-assertion: Child is suspended. (Not verified)
614 * Post-condition: Child is suspended after EXEC_COUNTER exec() calls.
618 intercept_exec_calls (exec_counter)
621 int terminal_initted = 0;
623 struct syscall_msg_t {
624 mach_msg_header_t header;
625 mach_msg_type_t type;
626 char room[ 2000 ]; /* Enuff space */
629 struct syscall_msg_t syscall_in, syscall_out;
631 mach_port_t fake_server;
632 mach_port_t original_server_send;
633 mach_port_t original_exec_reply;
634 mach_port_t exec_reply;
635 mach_port_t exec_reply_send;
636 mach_msg_type_name_t acquired;
637 mach_port_t emulator_server_port_name;
638 struct task_basic_info info;
639 mach_msg_type_number_t info_count;
643 if (exec_counter <= 0)
644 return; /* We are already set up in the correct program */
646 ret = mach_port_allocate(mach_task_self(),
647 MACH_PORT_RIGHT_RECEIVE,
649 CHK("create inferior_fake_server port failed", ret);
651 /* Wait for inferior_task to suspend itself */
654 info_count = sizeof (info);
655 ret = task_info (inferior_task,
659 CHK ("Task info", ret);
661 if (info.suspend_count)
664 /* Note that the definition of the parameter was undefined
665 * at the time of this writing, so I just use an `ad hoc' value.
667 (void) swtch_pri (42); /* Universal Priority Value */
670 /* Read the inferior's bootstrap port name */
671 if (!mach3_read_inferior (&original_server_port_name,
672 &original_server_port_name,
673 sizeof (original_server_port_name)))
674 error ("Can't read inferior task bootstrap port name");
676 /* @@ BUG: If more than 1 send right GDB will FAIL!!! */
677 /* Should get refs, and set them back when restoring */
678 /* Steal the original bsd server send right from inferior */
679 ret = mach_port_extract_right (inferior_task,
680 original_server_port_name,
681 MACH_MSG_TYPE_MOVE_SEND,
682 &original_server_send,
684 CHK("mach_port_extract_right (bsd server send)",ret);
686 if (acquired != MACH_MSG_TYPE_PORT_SEND)
687 error("Incorrect right extracted, send right to bsd server excpected");
689 ret = mach_port_insert_right (inferior_task,
690 original_server_port_name,
692 MACH_MSG_TYPE_MAKE_SEND);
693 CHK("mach_port_insert_right (fake server send)",ret);
695 xx_debug ("inferior task bsd server ports set up \nfs %x, ospn %x, oss %x\n",
697 original_server_port_name, original_server_send);
699 /* A receive right to the reply generated by unix server exec() request */
700 ret = mach_port_allocate(mach_task_self(),
701 MACH_PORT_RIGHT_RECEIVE,
703 CHK("create intercepted_reply_port port failed", ret);
705 /* Pass this send right to Unix server so it replies to us after exec() */
706 ret = mach_port_extract_right (mach_task_self (),
708 MACH_MSG_TYPE_MAKE_SEND_ONCE,
711 CHK("mach_port_extract_right (exec_reply)",ret);
713 if (acquired != MACH_MSG_TYPE_PORT_SEND_ONCE)
714 error("Incorrect right extracted, send once excpected for exec reply");
716 ret = mach_port_move_member(mach_task_self(),
718 inferior_wait_port_set);
719 CHK ("Moving fake syscall port to inferior_wait_port_set", ret);
721 xx_debug ("syscall fake server set up, resuming inferior\n");
723 ret = task_resume (inferior_task);
724 CHK("task_resume (startup)", ret);
726 /* Read requests from the inferior.
727 Pass directly through everything else except exec() calls.
729 while(exec_counter > 0)
731 ret = mach_msg (&syscall_in.header, /* header */
732 MACH_RCV_MSG, /* options */
734 sizeof (struct syscall_msg_t), /* receive size */
735 inferior_wait_port_set, /* receive_name */
736 MACH_MSG_TIMEOUT_NONE,
738 CHK("mach_msg (intercepted sycall)", ret);
741 print_msg (&syscall_in.header);
744 /* ASSERT : msgh_local_port == fake_server */
746 if (notify_server (&syscall_in.header, &syscall_out.header))
747 error ("received a notify while intercepting syscalls");
749 if (syscall_in.header.msgh_id == MIG_EXEC_SYSCALL_ID)
751 xx_debug ("Received EXEC SYSCALL, counter = %d\n", exec_counter);
752 if (exec_counter == 1)
754 original_exec_reply = syscall_in.header.msgh_remote_port;
755 syscall_in.header.msgh_remote_port = exec_reply_send;
758 if (!terminal_initted)
760 /* Now that the child has exec'd we know it has already set its
761 process group. On POSIX systems, tcsetpgrp will fail with
762 EPERM if we try it before the child's setpgid. */
764 /* Set up the "saved terminal modes" of the inferior
765 based on what modes we are starting it with. */
766 target_terminal_init ();
768 /* Install inferior's terminal modes. */
769 target_terminal_inferior ();
771 terminal_initted = 1;
777 syscall_in.header.msgh_local_port = syscall_in.header.msgh_remote_port;
778 syscall_in.header.msgh_remote_port = original_server_send;
780 reverse_msg_bits(&syscall_in.header, MACH_MSG_TYPE_COPY_SEND);
782 ret = mach_msg_send (&syscall_in.header);
783 CHK ("Forwarded syscall", ret);
786 ret = mach_port_move_member(mach_task_self(),
789 CHK ("Moving fake syscall out of inferior_wait_port_set", ret);
791 ret = mach_port_move_member(mach_task_self(),
793 inferior_wait_port_set);
794 CHK ("Moving exec_reply to inferior_wait_port_set", ret);
796 ret = mach_msg (&syscall_in.header, /* header */
797 MACH_RCV_MSG, /* options */
799 sizeof (struct syscall_msg_t), /* receive size */
800 inferior_wait_port_set, /* receive_name */
801 MACH_MSG_TIMEOUT_NONE,
803 CHK("mach_msg (exec reply)", ret);
805 ret = task_suspend (inferior_task);
806 CHK ("Suspending inferior after last exec", ret);
808 must_suspend_thread = 0;
810 xx_debug ("Received exec reply from bsd server, suspended inferior task\n");
813 print_msg (&syscall_in.header);
816 /* Message should appear as if it came from the unix server */
817 syscall_in.header.msgh_local_port = MACH_PORT_NULL;
819 /* and go to the inferior task original reply port */
820 syscall_in.header.msgh_remote_port = original_exec_reply;
822 reverse_msg_bits(&syscall_in.header, MACH_MSG_TYPE_MOVE_SEND_ONCE);
824 ret = mach_msg_send (&syscall_in.header);
825 CHK ("Forwarding exec reply to inferior", ret);
827 /* Garbage collect */
828 ret = mach_port_deallocate (inferior_task,
829 original_server_port_name);
830 CHK ("deallocating fake server send right", ret);
832 ret = mach_port_insert_right (inferior_task,
833 original_server_port_name,
834 original_server_send,
835 MACH_MSG_TYPE_MOVE_SEND);
836 CHK ("Restoring the original bsd server send right", ret);
838 ret = mach_port_destroy (mach_task_self (),
840 fake_server = MACH_PORT_DEAD;
841 CHK("mach_port_destroy (fake_server)", ret);
843 ret = mach_port_destroy (mach_task_self (),
845 exec_reply = MACH_PORT_DEAD;
846 CHK("mach_port_destroy (exec_reply)", ret);
848 xx_debug ("Done with exec call interception\n");
852 consume_send_rights (thread_list, thread_count)
853 thread_array_t thread_list;
861 for (index = 0; index < thread_count; index++)
863 /* Since thread kill command kills threads, don't check ret */
864 (void) mach_port_deallocate (mach_task_self (),
865 thread_list [ index ]);
869 /* suspend/abort/resume a thread. */
870 setup_thread (thread, what)
878 ret = thread_suspend (thread);
879 CHK ("setup_thread thread_suspend", ret);
881 ret = thread_abort (thread);
882 CHK ("setup_thread thread_abort", ret);
886 ret = thread_resume (thread);
887 CHK ("setup_thread thread_resume", ret);
892 map_slot_to_mid (slot, threads, thread_count)
894 thread_array_t threads;
905 ret = task_threads (inferior_task, &threads, &thread_count);
906 CHK ("Can not select a thread from a dead task", ret);
909 if (slot < 0 || slot >= thread_count)
913 consume_send_rights (threads, thread_count);
914 (void) vm_deallocate (mach_task_self(), (vm_address_t)threads,
915 (thread_count * sizeof(mach_port_t)));
918 error ("invalid slot number");
923 mid = map_port_name_to_mid (threads [slot], MACH_TYPE_THREAD);
927 consume_send_rights (threads, thread_count);
928 (void) vm_deallocate (mach_task_self(), (vm_address_t)threads,
929 (thread_count * sizeof(mach_port_t)));
936 parse_thread_id (arg, thread_count, slots)
949 while (*arg && (*arg == ' ' || *arg == '\t'))
955 /* Currently parse MID and @SLOTNUMBER */
960 error ("valid thread mid expected");
968 error ("invalid slot number");
970 /* If you want slot numbers to remain slot numbers, set slots.
972 * Well, since 0 is reserved, return the ordinal number
973 * of the thread rather than the slot number. Awk, this
974 * counts as a kludge.
979 if (thread_count && slot >= thread_count)
982 mid = map_slot_to_mid (slot);
987 /* THREAD_ID 0 is special; it selects the first kernel
988 * thread from the list (i.e. SLOTNUMBER 0)
989 * This is used when starting the program with 'run' or when attaching.
991 * If FLAG is 0 the context is not changed, and the registers, frame, etc
992 * will continue to describe the old thread.
994 * If FLAG is nonzero, really select the thread.
995 * If FLAG is 2, the THREAD_ID is a slotnumber instead of a mid.
999 select_thread (task, thread_id, flag)
1004 thread_array_t thread_list;
1008 thread_t new_thread = MACH_PORT_NULL;
1011 error ("Can't select cprocs without kernel thread");
1013 ret = task_threads (task, &thread_list, &thread_count);
1014 if (ret != KERN_SUCCESS)
1016 warning ("Can not select a thread from a dead task");
1017 m3_kill_inferior ();
1018 return KERN_FAILURE;
1021 if (thread_count == 0)
1023 /* The task can not do anything anymore, but it still
1024 * exists as a container for memory and ports.
1026 registers_changed ();
1027 warning ("Task %d has no threads",
1028 map_port_name_to_mid (task, MACH_TYPE_TASK));
1029 current_thread = MACH_PORT_NULL;
1030 (void) vm_deallocate(mach_task_self(),
1031 (vm_address_t) thread_list,
1032 (thread_count * sizeof(mach_port_t)));
1033 return KERN_FAILURE;
1036 if (! thread_id || flag == 2)
1038 /* First thread or a slotnumber */
1040 new_thread = thread_list[0];
1043 if (thread_id < thread_count)
1044 new_thread = thread_list[ thread_id ];
1047 (void) vm_deallocate(mach_task_self(),
1048 (vm_address_t) thread_list,
1049 (thread_count * sizeof(mach_port_t)));
1050 error ("No such thread slot number : %d", thread_id);
1056 for (index = 0; index < thread_count; index++)
1057 if (thread_id == map_port_name_to_mid (thread_list [index],
1060 new_thread = thread_list [index];
1066 error ("No thread with mid %d", thread_id);
1069 /* Notify when the selected thread dies */
1070 request_notify (new_thread, MACH_NOTIFY_DEAD_NAME, MACH_TYPE_THREAD);
1072 ret = vm_deallocate(mach_task_self(),
1073 (vm_address_t) thread_list,
1074 (thread_count * sizeof(mach_port_t)));
1075 CHK ("vm_deallocate", ret);
1078 current_thread = new_thread;
1082 if (MACH_PORT_VALID (current_thread))
1084 /* Store the gdb's view of the thread we are deselecting
1086 * @@ I think gdb updates registers immediately when they are
1087 * changed, so don't do this.
1089 ret = thread_abort (current_thread);
1090 CHK ("Could not abort system calls when saving state of old thread",
1092 target_prepare_to_store ();
1093 target_store_registers (-1);
1097 registers_changed ();
1099 current_thread = new_thread;
1101 ret = thread_abort (current_thread);
1102 CHK ("Could not abort system calls when selecting a thread", ret);
1104 stop_pc = read_pc();
1105 set_current_frame (create_new_frame (read_register (FP_REGNUM),
1108 select_frame (get_current_frame (), 0);
1110 stop_frame_address = FRAME_FP (get_current_frame ());
1113 return KERN_SUCCESS;
1117 * Switch to use thread named NEW_THREAD.
1121 switch_to_thread (new_thread)
1122 thread_t new_thread;
1124 thread_t saved_thread = current_thread;
1127 mid = map_port_name_to_mid (new_thread,
1130 warning ("Can't map thread name 0x%x to mid", new_thread);
1131 else if (select_thread (inferior_task, mid, 1) != KERN_SUCCESS)
1134 current_thread = saved_thread;
1135 error ("Could not select thread %d", mid);
1141 /* Do this in gdb after doing FORK but before STARTUP_INFERIOR.
1142 * Note that the registers are not yet valid in the inferior task.
1150 push_target (&m3_ops);
1152 inferior_task = task_by_pid (pid);
1154 if (! MACH_PORT_VALID (inferior_task))
1155 error ("Can not map Unix pid %d to Mach task", pid);
1157 /* Clean up previous notifications and create new ones */
1158 setup_notify_port (1);
1160 /* When notification appears, the inferior task has died */
1161 request_notify (inferior_task, MACH_NOTIFY_DEAD_NAME, MACH_TYPE_TASK);
1163 emulator_present = have_emulator_p (inferior_task);
1165 /* By default, select the first thread,
1166 * If task has no threads, gives a warning
1167 * Does not fetch registers, since they are not yet valid.
1169 select_thread (inferior_task, 0, 0);
1171 inferior_exception_port = MACH_PORT_NULL;
1173 setup_exception_port ();
1175 xx_debug ("Now the debugged task is created\n");
1177 /* One trap to exec the shell, one to exec the program being debugged. */
1178 intercept_exec_calls (2);
1181 setup_exception_port ()
1185 ret = mach_port_allocate (mach_task_self(),
1186 MACH_PORT_RIGHT_RECEIVE,
1187 &inferior_exception_port);
1188 CHK("mach_port_allocate",ret);
1190 /* add send right */
1191 ret = mach_port_insert_right (mach_task_self (),
1192 inferior_exception_port,
1193 inferior_exception_port,
1194 MACH_MSG_TYPE_MAKE_SEND);
1195 CHK("mach_port_insert_right",ret);
1197 ret = mach_port_move_member (mach_task_self(),
1198 inferior_exception_port,
1199 inferior_wait_port_set);
1200 CHK("mach_port_move_member",ret);
1202 ret = task_get_special_port (inferior_task,
1203 TASK_EXCEPTION_PORT,
1204 &inferior_old_exception_port);
1205 CHK ("task_get_special_port(old exc)",ret);
1207 ret = task_set_special_port (inferior_task,
1208 TASK_EXCEPTION_PORT,
1209 inferior_exception_port);
1210 CHK("task_set_special_port",ret);
1212 ret = mach_port_deallocate (mach_task_self (),
1213 inferior_exception_port);
1214 CHK("mack_port_deallocate",ret);
1217 /* When notify appears, the inferior_task's exception
1218 * port has been destroyed.
1220 * Not used, since the dead_name_notification already
1221 * appears when task dies.
1224 request_notify (inferior_exception_port,
1225 MACH_NOTIFY_NO_SENDERS,
1226 MACH_TYPE_EXCEPTION_PORT);
1230 /* Nonzero if gdb is waiting for a message */
1231 int mach_really_waiting;
1233 /* Wait for the inferior to stop for some reason.
1234 - Loop on notifications until inferior_task dies.
1235 - Loop on exceptions until stopped_in_exception comes true.
1236 (e.g. we receive a single step trace trap)
1237 - a message arrives to gdb's message port
1239 There is no other way to exit this loop.
1241 Returns the inferior_pid for rest of gdb.
1242 Side effects: Set *OURSTATUS. */
1244 mach_really_wait (pid, ourstatus)
1246 struct target_waitstatus *ourstatus;
1252 mach_msg_header_t header;
1253 mach_msg_type_t foo;
1257 /* Either notify (death), exception or message can stop the inferior */
1258 stopped_in_exception = FALSE;
1264 stop_exception = stop_code = stop_subcode = -1;
1265 stop_thread = MACH_PORT_NULL;
1267 mach_really_waiting = 1;
1268 ret = mach_msg (&in_msg.header, /* header */
1269 MACH_RCV_MSG, /* options */
1271 sizeof (struct msg), /* receive size */
1272 currently_waiting_for, /* receive name */
1273 MACH_MSG_TIMEOUT_NONE,
1275 mach_really_waiting = 0;
1276 CHK("mach_msg (receive)", ret);
1278 /* Check if we received a notify of the childs' death */
1279 if (notify_server (&in_msg.header, &out_msg.header))
1281 /* If inferior_task is null then the inferior has
1282 gone away and we want to return to command level.
1283 Otherwise it was just an informative message and we
1284 need to look to see if there are any more. */
1285 if (inferior_task != MACH_PORT_NULL)
1289 /* Collect Unix exit status for gdb */
1291 wait3(&w, WNOHANG, 0);
1293 /* This mess is here to check that the rest of
1294 * gdb knows that the inferior died. It also
1295 * tries to hack around the fact that Mach 3.0 (mk69)
1296 * unix server (ux28) does not always know what
1297 * has happened to it's children when mach-magic
1298 * is applied on them.
1300 if ((!WIFEXITED(w) && WIFSTOPPED(w)) ||
1301 (WIFEXITED(w) && WEXITSTATUS(w) > 0377))
1304 warning ("Using exit value 0 for terminated task");
1306 else if (!WIFEXITED(w))
1308 int sig = WTERMSIG(w);
1310 /* Signals cause problems. Warn the user. */
1311 if (sig != SIGKILL) /* Bad luck if garbage matches this */
1312 warning ("The terminating signal stuff may be nonsense");
1313 else if (sig > NSIG)
1316 warning ("Using exit value 0 for terminated task");
1319 store_waitstatus (ourstatus, w);
1320 return inferior_pid;
1324 /* Hmm. Check for exception, as it was not a notification.
1325 exc_server() does an upcall to catch_exception_raise()
1326 if this rpc is an exception. Further actions are decided
1329 if (! exc_server (&in_msg.header, &out_msg.header))
1332 /* Not an exception, check for message.
1334 * Messages don't come from the inferior, or if they
1335 * do they better be asynchronous or it will hang.
1337 if (gdb_message_server (&in_msg.header))
1340 error ("Unrecognized message received in mach_really_wait");
1343 /* Send the reply of the exception rpc to the suspended task */
1344 ret = mach_msg_send (&out_msg.header);
1345 CHK ("mach_msg_send (exc reply)", ret);
1347 if (stopped_in_exception)
1349 /* Get unix state. May be changed in mach3_exception_actions() */
1350 wait3(&w, WNOHANG, 0);
1352 mach3_exception_actions (&w, FALSE, "Task");
1354 store_waitstatus (ourstatus, w);
1355 return inferior_pid;
1360 /* Called by macro DO_QUIT() in utils.c(quit).
1361 * This is called just before calling error() to return to command level
1369 if (mach_really_waiting)
1371 ret = task_suspend (inferior_task);
1373 if (ret != KERN_SUCCESS)
1375 warning ("Could not suspend task for interrupt: %s",
1376 mach_error_string (ret));
1377 mach_really_waiting = 0;
1382 must_suspend_thread = 0;
1383 mach_really_waiting = 0;
1385 mid = map_port_name_to_mid (current_thread, MACH_TYPE_THREAD);
1388 warning ("Selecting first existing kernel thread");
1392 current_thread = MACH_PORT_NULL; /* Force setup */
1393 select_thread (inferior_task, mid, 1);
1399 /* bogus bogus bogus. It is NOT OK to quit out of target_wait. */
1401 /* If ^C is typed when we are waiting for a message
1402 * and your Unix server is able to notice that we
1405 * Called by REQUEST_QUIT() from utils.c(request_quit)
1408 mach3_request_quit ()
1410 if (mach_really_waiting)
1416 * Gdb message server.
1417 * Currently implemented is the STOP message, that causes
1418 * gdb to return to the command level like ^C had been typed from terminal.
1421 gdb_message_server (InP)
1422 mach_msg_header_t *InP;
1427 if (InP->msgh_local_port == our_message_port)
1429 /* A message coming to our_message_port. Check validity */
1430 switch (InP->msgh_id) {
1432 case GDB_MESSAGE_ID_STOP:
1433 ret = task_suspend (inferior_task);
1434 if (ret != KERN_SUCCESS)
1435 warning ("Could not suspend task for stop message: %s",
1436 mach_error_string (ret));
1438 /* QUIT in mach_really_wait() loop. */
1443 warning ("Invalid message id %d received, ignored.",
1451 /* Message not handled by this server */
1455 /* NOTE: This is not an RPC call. It is a simpleroutine.
1457 * This is not called from this gdb code.
1459 * It may be called by another debugger to cause this
1460 * debugger to enter command level:
1462 * (gdb) set stop_inferior_gdb ()
1465 * External program "stop-gdb" implements this also.
1468 stop_inferior_gdb ()
1472 /* Code generated by mig, with minor cleanups :-)
1474 * simpleroutine stop_inferior_gdb (our_message_port : mach_port_t);
1478 mach_msg_header_t Head;
1483 register Request *InP = &Mess;
1485 InP->Head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
1487 /* msgh_size passed as argument */
1488 InP->Head.msgh_remote_port = our_message_port;
1489 InP->Head.msgh_local_port = MACH_PORT_NULL;
1490 InP->Head.msgh_seqno = 0;
1491 InP->Head.msgh_id = GDB_MESSAGE_ID_STOP;
1493 ret = mach_msg (&InP->Head,
1494 MACH_SEND_MSG|MACH_MSG_OPTION_NONE,
1498 MACH_MSG_TIMEOUT_NONE,
1502 #ifdef THREAD_ALLOWED_TO_BREAK
1504 * Return 1 if the MID specifies the thread that caused the
1506 * Since catch_exception_raise() selects the thread causing
1507 * the last exception to current_thread, we just check that
1508 * it is selected and the last exception was a breakpoint.
1511 mach_thread_for_breakpoint (mid)
1514 int cmid = map_port_name_to_mid (current_thread, MACH_TYPE_THREAD);
1518 mid = map_slot_to_mid (-(mid+1), 0, 0);
1520 return 0; /* Don't stop, no such slot */
1523 if (! mid || cmid == -1)
1524 return 1; /* stop */
1526 return cmid == mid && stop_exception == EXC_BREAKPOINT;
1528 #endif /* THREAD_ALLOWED_TO_BREAK */
1530 #ifdef THREAD_PARSE_ID
1532 * Map a thread id string (MID or a @SLOTNUMBER)
1535 * 0 matches all threads.
1536 * Otherwise the meaning is defined only in this file.
1537 * (mach_thread_for_breakpoint uses it)
1539 * @@ This allows non-existent MIDs to be specified.
1540 * It now also allows non-existent slots to be
1541 * specified. (Slot numbers stored are negative,
1542 * and the magnitude is one greater than the actual
1543 * slot index. (Since 0 is reserved))
1546 mach_thread_parse_id (arg)
1551 error ("thread id excpected");
1552 mid = parse_thread_id (arg, 0, 1);
1556 #endif /* THREAD_PARSE_ID */
1558 #ifdef THREAD_OUTPUT_ID
1560 mach_thread_output_id (mid)
1563 static char foobar [20];
1566 sprintf (foobar, "mid %d", mid);
1568 sprintf (foobar, "@%d", -(mid+1));
1570 sprintf (foobar, "*any thread*");
1574 #endif /* THREAD_OUTPUT_ID */
1576 /* Called with hook PREPARE_TO_PROCEED() from infrun.c.
1578 * If we have switched threads and stopped at breakpoint return 1 otherwise 0.
1580 * if SELECT_IT is nonzero, reselect the thread that was active when
1581 * we stopped at a breakpoint.
1585 mach3_prepare_to_proceed (select_it)
1589 stop_thread != current_thread &&
1590 stop_exception == EXC_BREAKPOINT)
1597 mid = switch_to_thread (stop_thread);
1605 /* this stuff here is an upcall via libmach/excServer.c
1606 and mach_really_wait which does the actual upcall.
1608 The code will pass the exception to the inferior if:
1610 - The task that signaled is not the inferior task
1611 (e.g. when debugging another debugger)
1613 - The user has explicitely requested to pass on the exceptions.
1614 (e.g to the default unix exception handler, which maps
1615 exceptions to signals, or the user has her own exception handler)
1617 - If the thread that signaled is being single-stepped and it
1618 has set it's own exception port and the exception is not
1619 EXC_BREAKPOINT. (Maybe this is not desirable?)
1623 catch_exception_raise (port, thread, task, exception, code, subcode)
1627 int exception, code, subcode;
1630 boolean_t signal_thread;
1631 int mid = map_port_name_to_mid (thread, MACH_TYPE_THREAD);
1633 if (! MACH_PORT_VALID (thread))
1635 /* If the exception was sent and thread dies before we
1636 receive it, THREAD will be MACH_PORT_DEAD
1639 current_thread = thread = MACH_PORT_NULL;
1640 error ("Received exception from nonexistent thread");
1643 /* Check if the task died in transit.
1644 * @@ Isn't the thread also invalid in such case?
1646 if (! MACH_PORT_VALID (task))
1648 current_thread = thread = MACH_PORT_NULL;
1649 error ("Received exception from nonexistent task");
1652 if (exception < 0 || exception > MAX_EXCEPTION)
1653 fatal ("catch_exception_raise: unknown exception code %d thread %d",
1657 if (! MACH_PORT_VALID (inferior_task))
1658 error ("got an exception, but inferior_task is null or dead");
1660 stop_exception = exception;
1662 stop_subcode = subcode;
1663 stop_thread = thread;
1665 signal_thread = exception != EXC_BREAKPOINT &&
1666 port == singlestepped_thread_port &&
1667 MACH_PORT_VALID (thread_saved_exception_port);
1669 /* If it was not our inferior or if we want to forward
1670 * the exception to the inferior's handler, do it here
1672 * Note: If you have forwarded EXC_BREAKPOINT I trust you know why.
1674 if (task != inferior_task ||
1676 exception_map [exception].forward)
1678 mach_port_t eport = inferior_old_exception_port;
1683 GDB now forwards the exeption to thread's original handler,
1684 since the user propably knows what he is doing.
1685 Give a message, though.
1688 mach3_exception_actions ((WAITTYPE *)NULL, TRUE, "Thread");
1689 eport = thread_saved_exception_port;
1692 /* Send the exception to the original handler */
1693 ret = exception_raise (eport,
1700 (void) mach_port_deallocate (mach_task_self (), task);
1701 (void) mach_port_deallocate (mach_task_self (), thread);
1703 /* If we come here, we don't want to trace any more, since we
1704 * will never stop for tracing anyway.
1706 discard_single_step (thread);
1708 /* Do not stop the inferior */
1712 /* Now gdb handles the exception */
1713 stopped_in_exception = TRUE;
1715 ret = task_suspend (task);
1716 CHK ("Error suspending inferior after exception", ret);
1718 must_suspend_thread = 0;
1720 if (current_thread != thread)
1722 if (MACH_PORT_VALID (singlestepped_thread_port))
1723 /* Cleanup discards single stepping */
1724 error ("Exception from thread %d while singlestepping thread %d",
1726 map_port_name_to_mid (current_thread, MACH_TYPE_THREAD));
1728 /* Then select the thread that caused the exception */
1729 if (select_thread (inferior_task, mid, 0) != KERN_SUCCESS)
1730 error ("Could not select thread %d causing exception", mid);
1732 warning ("Gdb selected thread %d", mid);
1735 /* If we receive an exception that is not breakpoint
1736 * exception, we interrupt the single step and return to
1737 * debugger. Trace condition is cleared.
1739 if (MACH_PORT_VALID (singlestepped_thread_port))
1741 if (stop_exception != EXC_BREAKPOINT)
1742 warning ("Single step interrupted by exception");
1743 else if (port == singlestepped_thread_port)
1745 /* Single step exception occurred, remove trace bit
1746 * and return to gdb.
1748 if (! MACH_PORT_VALID (current_thread))
1749 error ("Single stepped thread is not valid");
1751 /* Resume threads, but leave the task suspended */
1752 resume_all_threads (0);
1755 warning ("Breakpoint while single stepping?");
1757 discard_single_step (current_thread);
1760 (void) mach_port_deallocate (mach_task_self (), task);
1761 (void) mach_port_deallocate (mach_task_self (), thread);
1763 return KERN_SUCCESS;
1767 port_valid (port, mask)
1772 mach_port_type_t type;
1774 ret = mach_port_type (mach_task_self (),
1777 if (ret != KERN_SUCCESS || (type & mask) != mask)
1782 /* @@ No vm read cache implemented yet */
1783 boolean_t vm_read_cache_valid = FALSE;
1786 * Read inferior task's LEN bytes from ADDR and copy it to MYADDR
1787 * in gdb's address space.
1789 * Return 0 on failure; number of bytes read otherwise.
1792 mach3_read_inferior (addr, myaddr, length)
1798 vm_address_t low_address = (vm_address_t) trunc_page (addr);
1799 vm_size_t aligned_length =
1800 (vm_size_t) round_page (addr+length) - low_address;
1801 pointer_t copied_memory;
1804 /* Get memory from inferior with page aligned addresses */
1805 ret = vm_read (inferior_task,
1810 if (ret != KERN_SUCCESS)
1812 /* the problem is that the inferior might be killed for whatever reason
1813 * before we go to mach_really_wait. This is one place that ought to
1814 * catch many of those errors.
1815 * @@ A better fix would be to make all external events to GDB
1816 * to arrive via a SINGLE port set. (Including user input!)
1819 if (! port_valid (inferior_task, MACH_PORT_TYPE_SEND))
1821 m3_kill_inferior ();
1822 error ("Inferior killed (task port invalid)");
1828 /* valprint.c gives nicer format if this does not
1829 screw it. Eamonn seems to like this, so I enable
1830 it if OSF is defined...
1832 warning ("[read inferior %x failed: %s]",
1833 addr, mach_error_string (ret));
1840 memcpy (myaddr, (char *)addr - low_address + copied_memory, length);
1842 ret = vm_deallocate (mach_task_self (),
1845 CHK("mach3_read_inferior vm_deallocate failed", ret);
1851 #define CHK_GOTO_OUT(str,ret) \
1852 do if (ret != KERN_SUCCESS) { errstr = #str; goto out; } while(0)
1854 #define CHK_GOTO_OUT(str,ret) \
1855 do if (ret != KERN_SUCCESS) { errstr = str; goto out; } while(0)
1858 struct vm_region_list {
1859 struct vm_region_list *next;
1860 vm_prot_t protection;
1865 struct obstack region_obstack;
1868 * Write inferior task's LEN bytes from ADDR and copy it to MYADDR
1869 * in gdb's address space.
1872 mach3_write_inferior (addr, myaddr, length)
1878 vm_address_t low_address = (vm_address_t) trunc_page (addr);
1879 vm_size_t aligned_length =
1880 (vm_size_t) round_page (addr+length) - low_address;
1881 pointer_t copied_memory;
1885 char *errstr = "Bug in mach3_write_inferior";
1887 struct vm_region_list *region_element;
1888 struct vm_region_list *region_head = (struct vm_region_list *)NULL;
1890 /* Get memory from inferior with page aligned addresses */
1891 ret = vm_read (inferior_task,
1896 CHK_GOTO_OUT ("mach3_write_inferior vm_read failed", ret);
1900 memcpy ((char *)addr - low_address + copied_memory, myaddr, length);
1902 obstack_init (®ion_obstack);
1904 /* Do writes atomically.
1905 * First check for holes and unwritable memory.
1908 vm_size_t remaining_length = aligned_length;
1909 vm_address_t region_address = low_address;
1911 struct vm_region_list *scan;
1913 while(region_address < low_address + aligned_length)
1915 vm_prot_t protection;
1916 vm_prot_t max_protection;
1917 vm_inherit_t inheritance;
1919 mach_port_t object_name;
1921 vm_size_t region_length = remaining_length;
1922 vm_address_t old_address = region_address;
1924 ret = vm_region (inferior_task,
1933 CHK_GOTO_OUT ("vm_region failed", ret);
1935 /* Check for holes in memory */
1936 if (old_address != region_address)
1938 warning ("No memory at 0x%x. Nothing written",
1945 if (!(max_protection & VM_PROT_WRITE))
1947 warning ("Memory at address 0x%x is unwritable. Nothing written",
1954 /* Chain the regions for later use */
1956 (struct vm_region_list *)
1957 obstack_alloc (®ion_obstack, sizeof (struct vm_region_list));
1959 region_element->protection = protection;
1960 region_element->start = region_address;
1961 region_element->length = region_length;
1963 /* Chain the regions along with protections */
1964 region_element->next = region_head;
1965 region_head = region_element;
1967 region_address += region_length;
1968 remaining_length = remaining_length - region_length;
1971 /* If things fail after this, we give up.
1972 * Somebody is messing up inferior_task's mappings.
1975 /* Enable writes to the chained vm regions */
1976 for (scan = region_head; scan; scan = scan->next)
1978 boolean_t protection_changed = FALSE;
1980 if (!(scan->protection & VM_PROT_WRITE))
1982 ret = vm_protect (inferior_task,
1986 scan->protection | VM_PROT_WRITE);
1987 CHK_GOTO_OUT ("vm_protect: enable write failed", ret);
1991 ret = vm_write (inferior_task,
1995 CHK_GOTO_OUT ("vm_write failed", ret);
1997 /* Set up the original region protections, if they were changed */
1998 for (scan = region_head; scan; scan = scan->next)
2000 boolean_t protection_changed = FALSE;
2002 if (!(scan->protection & VM_PROT_WRITE))
2004 ret = vm_protect (inferior_task,
2009 CHK_GOTO_OUT ("vm_protect: enable write failed", ret);
2017 obstack_free (®ion_obstack, 0);
2019 (void) vm_deallocate (mach_task_self (),
2024 if (ret != KERN_SUCCESS)
2026 warning ("%s %s", errstr, mach_error_string (ret));
2033 /* Return 0 on failure, number of bytes handled otherwise. */
2035 m3_xfer_memory (memaddr, myaddr, len, write, target)
2040 struct target_ops *target; /* IGNORED */
2045 result = mach3_write_inferior (memaddr, myaddr, len);
2047 result = mach3_read_inferior (memaddr, myaddr, len);
2054 translate_state(state)
2058 case TH_STATE_RUNNING: return("R");
2059 case TH_STATE_STOPPED: return("S");
2060 case TH_STATE_WAITING: return("W");
2061 case TH_STATE_UNINTERRUPTIBLE: return("U");
2062 case TH_STATE_HALTED: return("H");
2063 default: return("?");
2068 translate_cstate (state)
2073 case CPROC_RUNNING: return "R";
2074 case CPROC_SWITCHING: return "S";
2075 case CPROC_BLOCKED: return "B";
2076 case CPROC_CONDWAIT: return "C";
2077 case CPROC_CONDWAIT|CPROC_SWITCHING: return "CS";
2078 default: return "?";
2082 /* type == MACH_MSG_TYPE_COPY_SEND || type == MACH_MSG_TYPE_MAKE_SEND */
2084 mach_port_t /* no mach_port_name_t found in include files. */
2085 map_inferior_port_name (inferior_name, type)
2086 mach_port_t inferior_name;
2087 mach_msg_type_name_t type;
2090 mach_msg_type_name_t acquired;
2093 ret = mach_port_extract_right (inferior_task,
2098 CHK("mach_port_extract_right (map_inferior_port_name)", ret);
2100 if (acquired != MACH_MSG_TYPE_PORT_SEND)
2101 error("Incorrect right extracted, (map_inferior_port_name)");
2103 ret = mach_port_deallocate (mach_task_self (),
2105 CHK ("Deallocating mapped port (map_inferior_port_name)", ret);
2111 * Naming convention:
2112 * Always return user defined name if found.
2113 * _K == A kernel thread with no matching CPROC
2114 * _C == A cproc with no current cthread
2115 * _t == A cthread with no user defined name
2117 * The digits that follow the _names are the SLOT number of the
2118 * kernel thread if there is such a thing, otherwise just a negation
2119 * of the sequential number of such cprocs.
2125 get_thread_name (one_cproc, id)
2126 gdb_thread_t one_cproc;
2130 if (one_cproc->cthread == NULL)
2132 /* cproc not mapped to any cthread */
2133 sprintf(buf, "_C%d", id);
2135 else if (! one_cproc->cthread->name)
2137 /* cproc and cthread, but no name */
2138 sprintf(buf, "_t%d", id);
2141 return (char *)(one_cproc->cthread->name);
2145 warning ("Inconsistency in thread name id %d", id);
2147 /* Kernel thread without cproc */
2148 sprintf(buf, "_K%d", id);
2155 fetch_thread_info (task, mthreads_out)
2157 gdb_thread_t *mthreads_out; /* out */
2160 thread_array_t th_table;
2162 gdb_thread_t mthreads = NULL;
2165 ret = task_threads (task, &th_table, &th_count);
2166 if (ret != KERN_SUCCESS)
2168 warning ("Error getting inferior's thread list:%s",
2169 mach_error_string(ret));
2170 m3_kill_inferior ();
2174 mthreads = (gdb_thread_t)
2177 th_count * sizeof (struct gdb_thread));
2179 for (index = 0; index < th_count; index++)
2181 thread_t saved_thread = MACH_PORT_NULL;
2184 if (must_suspend_thread)
2185 setup_thread (th_table[ index ], 1);
2187 if (th_table[index] != current_thread)
2189 saved_thread = current_thread;
2191 mid = switch_to_thread (th_table[ index ]);
2194 mthreads[index].name = th_table[index];
2195 mthreads[index].cproc = NULL; /* map_cprocs_to_kernel_threads() */
2196 mthreads[index].in_emulator = FALSE;
2197 mthreads[index].slotid = index;
2199 mthreads[index].sp = read_register (SP_REGNUM);
2200 mthreads[index].fp = read_register (FP_REGNUM);
2201 mthreads[index].pc = read_pc ();
2203 if (MACH_PORT_VALID (saved_thread))
2204 mid = switch_to_thread (saved_thread);
2206 if (must_suspend_thread)
2207 setup_thread (th_table[ index ], 0);
2210 consume_send_rights (th_table, th_count);
2211 ret = vm_deallocate (mach_task_self(), (vm_address_t)th_table,
2212 (th_count * sizeof(mach_port_t)));
2213 if (ret != KERN_SUCCESS)
2215 warning ("Error trying to deallocate thread list : %s",
2216 mach_error_string (ret));
2219 *mthreads_out = mthreads;
2226 * Current emulator always saves the USP on top of
2227 * emulator stack below struct emul_stack_top stuff.
2230 fetch_usp_from_emulator_stack (sp)
2233 CORE_ADDR stack_pointer;
2235 sp = (sp & ~(EMULATOR_STACK_SIZE-1)) +
2236 EMULATOR_STACK_SIZE - sizeof (struct emul_stack_top);
2238 if (mach3_read_inferior (sp,
2240 sizeof (CORE_ADDR)) != sizeof (CORE_ADDR))
2242 warning ("Can't read user sp from emulator stack address 0x%x", sp);
2246 return stack_pointer;
2251 /* get_emulation_vector() interface was changed after mk67 */
2252 #define EMUL_VECTOR_COUNT 400 /* Value does not matter too much */
2256 /* Check if the emulator exists at task's address space.
2259 have_emulator_p (task)
2263 #ifndef EMUL_VECTOR_COUNT
2264 vm_offset_t *emulation_vector;
2267 vm_offset_t emulation_vector[ EMUL_VECTOR_COUNT ];
2268 int n = EMUL_VECTOR_COUNT;
2273 ret = task_get_emulation_vector (task,
2275 #ifndef EMUL_VECTOR_COUNT
2281 CHK("task_get_emulation_vector", ret);
2282 xx_debug ("%d vectors from %d at 0x%08x\n",
2283 n, vector_start, emulation_vector);
2285 for(i = 0; i < n; i++)
2287 vm_offset_t entry = emulation_vector [i];
2289 if (EMULATOR_BASE <= entry && entry <= EMULATOR_END)
2293 static boolean_t informed = FALSE;
2296 warning("Emulation vector address 0x08%x outside emulator space",
2305 /* Map cprocs to kernel threads and vice versa. */
2308 map_cprocs_to_kernel_threads (cprocs, mthreads, thread_count)
2309 gdb_thread_t cprocs;
2310 gdb_thread_t mthreads;
2315 boolean_t all_mapped = TRUE;
2319 for (scan = cprocs; scan; scan = scan->next)
2321 /* Default to: no kernel thread for this cproc */
2322 scan->reverse_map = -1;
2324 /* Check if the cproc is found by its stack */
2325 for (index = 0; index < thread_count; index++)
2328 extract_signed_integer (scan->raw_cproc + CPROC_BASE_OFFSET,
2331 extract_signed_integer (scan->raw_cproc + CPROC_SIZE_OFFSET,
2333 if ((mthreads + index)->sp > stack_base &&
2334 (mthreads + index)->sp <= stack_base + stack_size)
2336 (mthreads + index)->cproc = scan;
2337 scan->reverse_map = index;
2341 all_mapped &= (scan->reverse_map != -1);
2344 /* Check for threads that are currently in the emulator.
2345 * If so, they have a different stack, and the still unmapped
2346 * cprocs may well get mapped to these threads.
2349 * - cproc stack does not match any kernel thread stack pointer
2350 * - there is at least one extra kernel thread
2351 * that has no cproc mapped above.
2352 * - some kernel thread stack pointer points to emulator space
2353 * then we find the user stack pointer saved in the emulator
2354 * stack, and try to map that to the cprocs.
2356 * Also set in_emulator for kernel threads.
2359 if (emulator_present)
2361 for (index = 0; index < thread_count; index++)
2366 gdb_thread_t mthread = (mthreads+index);
2367 emul_sp = mthread->sp;
2369 if (mthread->cproc == NULL &&
2370 EMULATOR_BASE <= emul_sp && emul_sp <= EMULATOR_END)
2372 mthread->in_emulator = emulator_present;
2374 if (!all_mapped && cprocs)
2376 usp = fetch_usp_from_emulator_stack (emul_sp);
2378 /* @@ Could be more accurate */
2380 error ("Zero stack pointer read from emulator?");
2382 /* Try to match this stack pointer to the cprocs that
2383 * don't yet have a kernel thread.
2385 for (scan = cprocs; scan; scan = scan->next)
2388 /* Check is this unmapped CPROC stack contains
2389 * the user stack pointer saved in the
2392 if (scan->reverse_map == -1)
2395 extract_signed_integer
2396 (scan->raw_cproc + CPROC_BASE_OFFSET,
2399 extract_signed_integer
2400 (scan->raw_cproc + CPROC_SIZE_OFFSET,
2402 if (usp > stack_base &&
2403 usp <= stack_base + stack_size)
2405 mthread->cproc = scan;
2406 scan->reverse_map = index;
2418 * Format of the thread_list command
2420 * slot mid sel name emul ks susp cstate wired address
2422 #define TL_FORMAT "%-2.2s %5d%c %-10.10s %1.1s%s%-5.5s %-2.2s %-5.5s "
2424 #define TL_HEADER "\n@ MID Name KState CState Where\n"
2427 print_tl_address (stream, pc)
2431 if (! lookup_minimal_symbol_by_pc (pc))
2432 fprintf_filtered (stream, local_hex_format(), pc);
2435 extern int addressprint;
2436 extern int asm_demangle;
2438 int store = addressprint;
2440 print_address_symbolic (pc, stream, asm_demangle, "");
2441 addressprint = store;
2445 /* For thread names, but also for gdb_message_port external name */
2446 #define MAX_NAME_LEN 50
2448 /* Returns the address of variable NAME or 0 if not found */
2450 lookup_address_of_variable (name)
2454 CORE_ADDR symaddr = 0;
2455 struct minimal_symbol *msymbol;
2457 sym = lookup_symbol (name,
2458 (struct block *)NULL,
2461 (struct symtab **)NULL);
2464 symaddr = SYMBOL_VALUE (sym);
2468 msymbol = lookup_minimal_symbol (name, (struct objfile *) NULL);
2470 if (msymbol && msymbol->type == mst_data)
2471 symaddr = SYMBOL_VALUE_ADDRESS (msymbol);
2480 gdb_thread_t cproc_head;
2481 gdb_thread_t cproc_copy;
2482 CORE_ADDR their_cprocs;
2483 char *buf[TARGET_PTR_BIT / HOST_CHAR_BIT];
2488 symaddr = lookup_address_of_variable ("cproc_list");
2492 /* cproc_list is not in a file compiled with debugging
2493 symbols, but don't give up yet */
2495 symaddr = lookup_address_of_variable ("cprocs");
2499 static int informed = 0;
2503 warning ("Your program is loaded with an old threads library.");
2504 warning ("GDB does not know the old form of threads");
2505 warning ("so things may not work.");
2510 /* Stripped or no -lthreads loaded or "cproc_list" is in wrong segment. */
2514 /* Get the address of the first cproc in the task */
2515 if (!mach3_read_inferior (symaddr,
2517 TARGET_PTR_BIT / HOST_CHAR_BIT))
2518 error ("Can't read cproc master list at address (0x%x).", symaddr);
2519 their_cprocs = extract_address (buf, TARGET_PTR_BIT / HOST_CHAR_BIT);
2521 /* Scan the CPROCs in the task.
2522 CPROCs are chained with LIST field, not NEXT field, which
2523 chains mutexes, condition variables and queues */
2527 while (their_cprocs != (CORE_ADDR)0)
2529 CORE_ADDR cproc_copy_incarnation;
2530 cproc_copy = (gdb_thread_t) obstack_alloc (cproc_obstack,
2531 sizeof (struct gdb_thread));
2533 if (!mach3_read_inferior (their_cprocs,
2534 &cproc_copy->raw_cproc[0],
2536 error("Can't read next cproc at 0x%x.", their_cprocs);
2539 extract_address (cproc_copy->raw_cproc + CPROC_LIST_OFFSET,
2541 cproc_copy_incarnation =
2542 extract_address (cproc_copy->raw_cproc + CPROC_INCARNATION_OFFSET,
2543 CPROC_INCARNATION_SIZE);
2545 if (cproc_copy_incarnation == (CORE_ADDR)0)
2546 cproc_copy->cthread = NULL;
2549 /* This CPROC has an attached CTHREAD. Get its name */
2550 cthread = (cthread_t)obstack_alloc (cproc_obstack,
2551 sizeof(struct cthread));
2553 if (!mach3_read_inferior (cproc_copy_incarnation,
2555 sizeof(struct cthread)))
2556 error("Can't read next thread at 0x%x.",
2557 cproc_copy_incarnation);
2559 cproc_copy->cthread = cthread;
2563 name = (char *) obstack_alloc (cproc_obstack, MAX_NAME_LEN);
2565 if (!mach3_read_inferior(cthread->name, name, MAX_NAME_LEN))
2566 error("Can't read next thread's name at 0x%x.", cthread->name);
2568 cthread->name = name;
2572 /* insert in front */
2573 cproc_copy->next = cproc_head;
2574 cproc_head = cproc_copy;
2579 #ifndef FETCH_CPROC_STATE
2581 * Check if your machine does not grok the way this routine
2582 * fetches the FP,PC and SP of a cproc that is not
2583 * currently attached to any kernel thread (e.g. its cproc.context
2584 * field points to the place in stack where the context
2587 * If it doesn't, define your own routine.
2589 #define FETCH_CPROC_STATE(mth) mach3_cproc_state (mth)
2592 mach3_cproc_state (mthread)
2593 gdb_thread_t mthread;
2597 if (! mthread || !mthread->cproc)
2600 context = extract_signed_integer
2601 (mthread->cproc->raw_cproc + CPROC_CONTEXT_OFFSET,
2602 CPROC_CONTEXT_SIZE);
2606 mthread->sp = context + MACHINE_CPROC_SP_OFFSET;
2608 if (mach3_read_inferior (context + MACHINE_CPROC_PC_OFFSET,
2610 sizeof (CORE_ADDR)) != sizeof (CORE_ADDR))
2612 warning ("Can't read cproc pc from inferior");
2616 if (mach3_read_inferior (context + MACHINE_CPROC_FP_OFFSET,
2618 sizeof (CORE_ADDR)) != sizeof (CORE_ADDR))
2620 warning ("Can't read cproc fp from inferior");
2626 #endif /* FETCH_CPROC_STATE */
2630 thread_list_command()
2632 thread_basic_info_data_t ths;
2634 gdb_thread_t cprocs;
2642 mach_port_t mid_or_port;
2643 gdb_thread_t their_threads;
2644 gdb_thread_t kthread;
2648 char *fmt = "There are %d kernel threads in task %d.\n";
2650 int tmid = map_port_name_to_mid (inferior_task, MACH_TYPE_TASK);
2652 MACH_ERROR_NO_INFERIOR;
2654 thread_count = fetch_thread_info (inferior_task,
2656 if (thread_count == -1)
2659 if (thread_count == 1)
2660 fmt = "There is %d kernel thread in task %d.\n";
2662 printf_filtered (fmt, thread_count, tmid);
2664 puts_filtered (TL_HEADER);
2666 cprocs = get_cprocs();
2668 map_cprocs_to_kernel_threads (cprocs, their_threads, thread_count);
2670 for (scan = cprocs; scan; scan = scan->next)
2676 extract_signed_integer
2677 (scan->raw_cproc + CPROC_STATE_OFFSET, CPROC_STATE_SIZE);
2681 /* a wired cproc? */
2682 wired = (extract_address (scan->raw_cproc + CPROC_WIRED_OFFSET,
2686 if (scan->reverse_map != -1)
2687 kthread = (their_threads + scan->reverse_map);
2693 /* These cprocs have a kernel thread */
2695 mid = map_port_name_to_mid (kthread->name, MACH_TYPE_THREAD);
2697 infoCnt = THREAD_BASIC_INFO_COUNT;
2699 ret = thread_info (kthread->name,
2701 (thread_info_t)&ths,
2704 if (ret != KERN_SUCCESS)
2706 warning ("Unable to get basic info on thread %d : %s",
2708 mach_error_string (ret));
2712 /* Who is the first to have more than 100 threads */
2713 sprintf (slot, "%d", kthread->slotid%100);
2715 if (kthread->name == current_thread)
2718 if (ths.suspend_count)
2719 sprintf (buf, "%d", ths.suspend_count);
2724 if (ths.flags & TH_FLAGS_SWAPPED)
2728 if (ths.flags & TH_FLAGS_IDLE)
2731 /* FIXME: May run afloul of arbitrary limit in printf_filtered. */
2732 printf_filtered (TL_FORMAT,
2736 get_thread_name (scan, kthread->slotid),
2737 kthread->in_emulator ? "E" : "",
2738 translate_state (ths.run_state),
2740 translate_cstate (cproc_state),
2742 print_tl_address (gdb_stdout, kthread->pc);
2746 /* These cprocs don't have a kernel thread.
2747 * find out the calling frame with
2748 * FETCH_CPROC_STATE.
2751 struct gdb_thread state;
2754 /* jtv -> emcmanus: why do you want this here? */
2755 if (scan->incarnation == NULL)
2756 continue; /* EMcM */
2759 /* FIXME: May run afloul of arbitrary limit in printf_filtered. */
2760 printf_filtered (TL_FORMAT,
2762 -neworder, /* Pseudo MID */
2764 get_thread_name (scan, -neworder),
2766 "-", /* kernel state */
2768 translate_cstate (cproc_state),
2772 if (FETCH_CPROC_STATE (&state) == -1)
2773 puts_filtered ("???");
2775 print_tl_address (gdb_stdout, state.pc);
2779 puts_filtered ("\n");
2782 /* Scan for kernel threads without cprocs */
2783 for (index = 0; index < thread_count; index++)
2785 if (! their_threads[index].cproc)
2792 mach_port_t name = their_threads[index].name;
2794 mid = map_port_name_to_mid (name, MACH_TYPE_THREAD);
2796 infoCnt = THREAD_BASIC_INFO_COUNT;
2798 ret = thread_info(name,
2800 (thread_info_t)&ths,
2803 if (ret != KERN_SUCCESS)
2805 warning ("Unable to get basic info on thread %d : %s",
2807 mach_error_string (ret));
2811 sprintf (slot, "%d", index%100);
2813 if (name == current_thread)
2818 if (ths.suspend_count)
2819 sprintf (buf, "%d", ths.suspend_count);
2824 if (ths.flags & TH_FLAGS_SWAPPED)
2828 if (ths.flags & TH_FLAGS_IDLE)
2831 /* FIXME: May run afloul of arbitrary limit in printf_filtered. */
2832 printf_filtered (TL_FORMAT,
2836 get_thread_name (NULL, index),
2837 their_threads[index].in_emulator ? "E" : "",
2838 translate_state (ths.run_state),
2840 "", /* No cproc state */
2841 ""); /* Can't be wired */
2842 print_tl_address (gdb_stdout, their_threads[index].pc);
2843 puts_filtered ("\n");
2847 obstack_free (cproc_obstack, 0);
2848 obstack_init (cproc_obstack);
2852 thread_select_command(args, from_tty)
2857 thread_array_t thread_list;
2862 MACH_ERROR_NO_INFERIOR;
2865 error_no_arg ("MID or @SLOTNUMBER to specify a thread to select");
2867 while (*args == ' ' || *args == '\t')
2879 if (!is_slot || *args != '0') /* Rudimentary checks */
2880 error ("You must select threads by MID or @SLOTNUMBER");
2882 if (select_thread (inferior_task, mid, is_slot?2:1) != KERN_SUCCESS)
2886 printf_filtered ("Thread %d selected\n",
2887 is_slot ? map_port_name_to_mid (current_thread,
2888 MACH_TYPE_THREAD) : mid);
2891 thread_trace (thread, set)
2895 int flavor = TRACE_FLAVOR;
2896 unsigned int stateCnt = TRACE_FLAVOR_SIZE;
2898 thread_state_data_t state;
2900 if (! MACH_PORT_VALID (thread))
2902 warning ("thread_trace: invalid thread");
2906 if (must_suspend_thread)
2907 setup_thread (thread, 1);
2909 ret = thread_get_state(thread, flavor, state, &stateCnt);
2910 CHK ("thread_trace: error reading thread state", ret);
2914 TRACE_SET (thread, state);
2918 if (! TRACE_CLEAR (thread, state))
2920 if (must_suspend_thread)
2921 setup_thread (thread, 0);
2926 ret = thread_set_state(thread, flavor, state, stateCnt);
2927 CHK ("thread_trace: error writing thread state", ret);
2928 if (must_suspend_thread)
2929 setup_thread (thread, 0);
2932 #ifdef FLUSH_INFERIOR_CACHE
2934 /* When over-writing code on some machines the I-Cache must be flushed
2935 explicitly, because it is not kept coherent by the lazy hardware.
2936 This definitely includes breakpoints, for instance, or else we
2937 end up looping in mysterious Bpt traps */
2939 flush_inferior_icache(pc, amount)
2942 vm_machine_attribute_val_t flush = MATTR_VAL_ICACHE_FLUSH;
2945 ret = vm_machine_attribute (inferior_task,
2950 if (ret != KERN_SUCCESS)
2951 warning ("Error flushing inferior's cache : %s",
2952 mach_error_string (ret));
2954 #endif FLUSH_INFERIOR_CACHE
2958 suspend_all_threads (from_tty)
2962 thread_array_t thread_list;
2963 int thread_count, index;
2965 thread_basic_info_data_t th_info;
2968 ret = task_threads (inferior_task, &thread_list, &thread_count);
2969 if (ret != KERN_SUCCESS)
2971 warning ("Could not suspend inferior threads.");
2972 m3_kill_inferior ();
2973 return_to_top_level (RETURN_ERROR);
2976 for (index = 0; index < thread_count; index++)
2980 mid = map_port_name_to_mid (thread_list[ index ],
2983 ret = thread_suspend(thread_list[ index ]);
2985 if (ret != KERN_SUCCESS)
2986 warning ("Error trying to suspend thread %d : %s",
2987 mid, mach_error_string (ret));
2991 infoCnt = THREAD_BASIC_INFO_COUNT;
2992 ret = thread_info (thread_list[ index ],
2994 (thread_info_t) &th_info,
2996 CHK ("suspend can't get thread info", ret);
2998 warning ("Thread %d suspend count is %d",
2999 mid, th_info.suspend_count);
3003 consume_send_rights (thread_list, thread_count);
3004 ret = vm_deallocate(mach_task_self(),
3005 (vm_address_t)thread_list,
3006 (thread_count * sizeof(int)));
3007 CHK ("Error trying to deallocate thread list", ret);
3011 thread_suspend_command (args, from_tty)
3017 mach_port_t saved_thread;
3019 thread_basic_info_data_t th_info;
3021 MACH_ERROR_NO_INFERIOR;
3023 if (!strcasecmp (args, "all")) {
3024 suspend_all_threads (from_tty);
3028 saved_thread = current_thread;
3030 mid = parse_thread_id (args, 0, 0);
3033 error ("You can suspend only existing kernel threads with MID or @SLOTNUMBER");
3036 mid = map_port_name_to_mid (current_thread, MACH_TYPE_THREAD);
3038 if (select_thread (inferior_task, mid, 0) != KERN_SUCCESS)
3041 current_thread = saved_thread;
3042 error ("Could not select thread %d", mid);
3045 ret = thread_suspend (current_thread);
3046 if (ret != KERN_SUCCESS)
3047 warning ("thread_suspend failed : %s",
3048 mach_error_string (ret));
3050 infoCnt = THREAD_BASIC_INFO_COUNT;
3051 ret = thread_info (current_thread,
3053 (thread_info_t) &th_info,
3055 CHK ("suspend can't get thread info", ret);
3057 warning ("Thread %d suspend count is %d", mid, th_info.suspend_count);
3059 current_thread = saved_thread;
3062 resume_all_threads (from_tty)
3066 thread_array_t thread_list;
3067 int thread_count, index;
3070 thread_basic_info_data_t th_info;
3072 ret = task_threads (inferior_task, &thread_list, &thread_count);
3073 if (ret != KERN_SUCCESS)
3075 m3_kill_inferior ();
3076 error("task_threads", mach_error_string( ret));
3079 for (index = 0; index < thread_count; index++)
3081 infoCnt = THREAD_BASIC_INFO_COUNT;
3082 ret = thread_info (thread_list [ index ],
3084 (thread_info_t) &th_info,
3086 CHK ("resume_all can't get thread info", ret);
3088 mid = map_port_name_to_mid (thread_list[ index ],
3091 if (! th_info.suspend_count)
3093 if (mid != -1 && from_tty)
3094 warning ("Thread %d is not suspended", mid);
3098 ret = thread_resume (thread_list[ index ]);
3100 if (ret != KERN_SUCCESS)
3101 warning ("Error trying to resume thread %d : %s",
3102 mid, mach_error_string (ret));
3103 else if (mid != -1 && from_tty)
3104 warning ("Thread %d suspend count is %d",
3105 mid, --th_info.suspend_count);
3108 consume_send_rights (thread_list, thread_count);
3109 ret = vm_deallocate(mach_task_self(),
3110 (vm_address_t)thread_list,
3111 (thread_count * sizeof(int)));
3112 CHK("Error trying to deallocate thread list", ret);
3116 thread_resume_command (args, from_tty)
3121 mach_port_t saved_thread;
3123 thread_basic_info_data_t th_info;
3124 int infoCnt = THREAD_BASIC_INFO_COUNT;
3126 MACH_ERROR_NO_INFERIOR;
3128 if (!strcasecmp (args, "all")) {
3129 resume_all_threads (from_tty);
3133 saved_thread = current_thread;
3135 mid = parse_thread_id (args, 0, 0);
3138 error ("You can resume only existing kernel threads with MID or @SLOTNUMBER");
3141 mid = map_port_name_to_mid (current_thread, MACH_TYPE_THREAD);
3143 if (select_thread (inferior_task, mid, 0) != KERN_SUCCESS)
3146 current_thread = saved_thread;
3147 return_to_top_level (RETURN_ERROR);
3150 ret = thread_info (current_thread,
3152 (thread_info_t) &th_info,
3154 CHK ("resume can't get thread info", ret);
3156 if (! th_info.suspend_count)
3158 warning ("Thread %d is not suspended", mid);
3162 ret = thread_resume (current_thread);
3163 if (ret != KERN_SUCCESS)
3164 warning ("thread_resume failed : %s",
3165 mach_error_string (ret));
3168 th_info.suspend_count--;
3169 warning ("Thread %d suspend count is %d", mid, th_info.suspend_count);
3173 current_thread = saved_thread;
3177 thread_kill_command (args, from_tty)
3184 thread_array_t thread_table;
3186 mach_port_t thread_to_kill = MACH_PORT_NULL;
3189 MACH_ERROR_NO_INFERIOR;
3192 error_no_arg ("thread mid to kill from the inferior task");
3194 mid = parse_thread_id (args, 0, 0);
3197 error ("You can kill only existing kernel threads with MID or @SLOTNUMBER");
3201 ret = machid_mach_port (mid_server, mid_auth, mid, &thread_to_kill);
3202 CHK ("thread_kill_command: machid_mach_port map failed", ret);
3205 mid = map_port_name_to_mid (current_thread, MACH_TYPE_THREAD);
3207 /* Don't allow gdb to kill *any* thread in the system. Use mkill program for that */
3208 ret = task_threads (inferior_task, &thread_table, &thread_count);
3209 CHK ("Error getting inferior's thread list", ret);
3211 if (thread_to_kill == current_thread)
3213 ret = thread_terminate (thread_to_kill);
3214 CHK ("Thread could not be terminated", ret);
3216 if (select_thread (inferior_task, 0, 1) != KERN_SUCCESS)
3217 warning ("Last thread was killed, use \"kill\" command to kill task");
3220 for (index = 0; index < thread_count; index++)
3221 if (thread_table [ index ] == thread_to_kill)
3223 ret = thread_terminate (thread_to_kill);
3224 CHK ("Thread could not be terminated", ret);
3227 if (thread_count > 1)
3228 consume_send_rights (thread_table, thread_count);
3230 ret = vm_deallocate (mach_task_self(), (vm_address_t)thread_table,
3231 (thread_count * sizeof(mach_port_t)));
3232 CHK ("Error trying to deallocate thread list", ret);
3234 warning ("Thread %d killed", mid);
3238 /* Task specific commands; add more if you like */
3241 task_resume_command (args, from_tty)
3246 task_basic_info_data_t ta_info;
3247 int infoCnt = TASK_BASIC_INFO_COUNT;
3248 int mid = map_port_name_to_mid (inferior_task, MACH_TYPE_TASK);
3250 MACH_ERROR_NO_INFERIOR;
3252 /* Would be trivial to change, but is it desirable? */
3254 error ("Currently gdb can resume only it's inferior task");
3256 ret = task_info (inferior_task,
3258 (task_info_t) &ta_info,
3260 CHK ("task_resume_command: task_info failed", ret);
3262 if (ta_info.suspend_count == 0)
3263 error ("Inferior task %d is not suspended", mid);
3264 else if (ta_info.suspend_count == 1 &&
3266 !query ("Suspend count is now 1. Do you know what you are doing? "))
3267 error ("Task not resumed");
3269 ret = task_resume (inferior_task);
3270 CHK ("task_resume_command: task_resume", ret);
3272 if (ta_info.suspend_count == 1)
3274 warning ("Inferior task %d is no longer suspended", mid);
3275 must_suspend_thread = 1;
3276 /* @@ This is not complete: Registers change all the time when not
3278 registers_changed ();
3281 warning ("Inferior task %d suspend count is now %d",
3282 mid, ta_info.suspend_count-1);
3287 task_suspend_command (args, from_tty)
3292 task_basic_info_data_t ta_info;
3293 int infoCnt = TASK_BASIC_INFO_COUNT;
3294 int mid = map_port_name_to_mid (inferior_task, MACH_TYPE_TASK);
3296 MACH_ERROR_NO_INFERIOR;
3298 /* Would be trivial to change, but is it desirable? */
3300 error ("Currently gdb can suspend only it's inferior task");
3302 ret = task_suspend (inferior_task);
3303 CHK ("task_suspend_command: task_suspend", ret);
3305 must_suspend_thread = 0;
3307 ret = task_info (inferior_task,
3309 (task_info_t) &ta_info,
3311 CHK ("task_suspend_command: task_info failed", ret);
3313 warning ("Inferior task %d suspend count is now %d",
3314 mid, ta_info.suspend_count);
3321 static char size [ 30 ];
3322 int zz = bytes/1024;
3325 sprintf (size, "%-2.1f M", ((float)bytes)/(1024.0*1024.0));
3327 sprintf (size, "%d K", zz);
3332 /* Does this require the target task to be suspended?? I don't think so. */
3334 task_info_command (args, from_tty)
3341 task_basic_info_data_t ta_info;
3342 int infoCnt = TASK_BASIC_INFO_COUNT;
3343 int page_size = round_page(1);
3344 int thread_count = 0;
3346 if (MACH_PORT_VALID (inferior_task))
3347 mid = map_port_name_to_mid (inferior_task,
3350 task = inferior_task;
3354 int tmid = atoi (args);
3357 error ("Invalid mid %d for task info", tmid);
3362 ret = machid_mach_port (mid_server, mid_auth, tmid, &task);
3363 CHK ("task_info_command: machid_mach_port map failed", ret);
3368 error ("You have to give the task MID as an argument");
3370 ret = task_info (task,
3372 (task_info_t) &ta_info,
3374 CHK ("task_info_command: task_info failed", ret);
3376 printf_filtered ("\nTask info for task %d:\n\n", mid);
3377 printf_filtered (" Suspend count : %d\n", ta_info.suspend_count);
3378 printf_filtered (" Base priority : %d\n", ta_info.base_priority);
3379 printf_filtered (" Virtual size : %s\n", get_size (ta_info.virtual_size));
3380 printf_filtered (" Resident size : %s\n", get_size (ta_info.resident_size));
3383 thread_array_t thread_list;
3385 ret = task_threads (task, &thread_list, &thread_count);
3386 CHK ("task_info_command: task_threads", ret);
3388 printf_filtered (" Thread count : %d\n", thread_count);
3390 consume_send_rights (thread_list, thread_count);
3391 ret = vm_deallocate(mach_task_self(),
3392 (vm_address_t)thread_list,
3393 (thread_count * sizeof(int)));
3394 CHK("Error trying to deallocate thread list", ret);
3396 if (have_emulator_p (task))
3397 printf_filtered (" Emulator at : 0x%x..0x%x\n",
3398 EMULATOR_BASE, EMULATOR_END);
3400 printf_filtered (" No emulator.\n");
3402 if (thread_count && task == inferior_task)
3403 printf_filtered ("\nUse the \"thread list\" command to see the threads\n");
3406 /* You may either FORWARD the exception to the inferior, or KEEP
3407 * it and return to GDB command level.
3409 * exception mid [ forward | keep ]
3413 exception_command (args, from_tty)
3422 error_no_arg ("exception number action");
3424 while (*scan == ' ' || *scan == '\t') scan++;
3426 if ('0' <= *scan && *scan <= '9')
3427 while ('0' <= *scan && *scan <= '9')
3430 error ("exception number action");
3432 exception = atoi (args);
3433 if (exception <= 0 || exception > MAX_EXCEPTION)
3434 error ("Allowed exception numbers are in range 1..%d",
3437 if (*scan != ' ' && *scan != '\t')
3438 error ("exception number must be followed by a space");
3440 while (*scan == ' ' || *scan == '\t') scan++;
3451 error("exception number action");
3453 if (!strncasecmp (args, "forward", len))
3454 exception_map[ exception ].forward = TRUE;
3455 else if (!strncasecmp (args, "keep", len))
3456 exception_map[ exception ].forward = FALSE;
3458 error ("exception action is either \"keep\" or \"forward\"");
3462 print_exception_info (exception)
3465 boolean_t forward = exception_map[ exception ].forward;
3467 printf_filtered ("%s\t(%d): ", exception_map[ exception ].name,
3470 if (exception_map[ exception ].sigmap != SIG_UNKNOWN)
3471 printf_filtered ("keep and handle as signal %d\n",
3472 exception_map[ exception ].sigmap);
3474 printf_filtered ("keep and handle as unknown signal %d\n",
3475 exception_map[ exception ].sigmap);
3477 printf_filtered ("forward exception to inferior\n");
3481 exception_info (args, from_tty)
3488 for (exception = 1; exception <= MAX_EXCEPTION; exception++)
3489 print_exception_info (exception);
3492 exception = atoi (args);
3494 if (exception <= 0 || exception > MAX_EXCEPTION)
3495 error ("Invalid exception number, values from 1 to %d allowed",
3497 print_exception_info (exception);
3501 /* Check for actions for mach exceptions.
3503 mach3_exception_actions (w, force_print_only, who)
3505 boolean_t force_print_only;
3508 boolean_t force_print = FALSE;
3511 if (force_print_only ||
3512 exception_map[stop_exception].sigmap == SIG_UNKNOWN)
3515 WSETSTOP (*w, exception_map[stop_exception].sigmap);
3517 if (exception_map[stop_exception].print || force_print)
3519 target_terminal_ours ();
3521 printf_filtered ("\n%s received %s exception : ",
3523 exception_map[stop_exception].name);
3527 switch(stop_exception) {
3528 case EXC_BAD_ACCESS:
3529 printf_filtered ("referencing address 0x%x : %s\n",
3531 mach_error_string (stop_code));
3533 case EXC_BAD_INSTRUCTION:
3535 ("illegal or undefined instruction. code %d subcode %d\n",
3536 stop_code, stop_subcode);
3538 case EXC_ARITHMETIC:
3539 printf_filtered ("code %d\n", stop_code);
3542 printf_filtered ("code %d subcode %d\n", stop_code, stop_subcode);
3545 printf_filtered ("%s specific, code 0x%x\n",
3546 stop_code < 0xffff ? "hardware" : "os emulation",
3549 case EXC_BREAKPOINT:
3550 printf_filtered ("type %d (machine dependent)\n",
3554 fatal ("Unknown exception");
3559 setup_notify_port (create_new)
3564 if (MACH_PORT_VALID (our_notify_port))
3566 ret = mach_port_destroy (mach_task_self (), our_notify_port);
3567 CHK ("Could not destroy our_notify_port", ret);
3570 our_notify_port = MACH_PORT_NULL;
3571 notify_chain = (port_chain_t) NULL;
3572 port_chain_destroy (port_chain_obstack);
3576 ret = mach_port_allocate (mach_task_self(),
3577 MACH_PORT_RIGHT_RECEIVE,
3579 if (ret != KERN_SUCCESS)
3580 fatal("Creating notify port %s", mach_error_string(ret));
3582 ret = mach_port_move_member(mach_task_self(),
3584 inferior_wait_port_set);
3585 if (ret != KERN_SUCCESS)
3586 fatal("initial move member %s",mach_error_string(ret));
3591 * Register our message port to the net name server
3593 * Currently used only by the external stop-gdb program
3594 * since ^C does not work if you would like to enter
3595 * gdb command level while debugging your program.
3597 * NOTE: If the message port is sometimes used for other
3598 * purposes also, the NAME must not be a guessable one.
3599 * Then, there should be a way to change it.
3602 char registered_name[ MAX_NAME_LEN ];
3605 message_port_info (args, from_tty)
3609 if (registered_name[0])
3610 printf_filtered ("gdb's message port name: '%s'\n",
3613 printf_filtered ("gdb's message port is not currently registered\n");
3617 gdb_register_port (name, port)
3622 static int already_signed = 0;
3625 if (! MACH_PORT_VALID (port) || !name || !*name)
3627 warning ("Invalid registration request");
3631 if (! already_signed)
3633 ret = mach_port_insert_right (mach_task_self (),
3636 MACH_MSG_TYPE_MAKE_SEND);
3637 CHK ("Failed to create a signature to our_message_port", ret);
3640 else if (already_signed > 1)
3642 ret = netname_check_out (name_server_port,
3645 CHK ("Failed to check out gdb's message port", ret);
3646 registered_name[0] = '\000';
3650 ret = netname_check_in (name_server_port, /* Name server port */
3651 name, /* Name of service */
3652 our_message_port, /* Signature */
3653 port); /* Creates a new send right */
3654 CHK("Failed to check in the port", ret);
3657 while(len < MAX_NAME_LEN && *(name+len))
3659 registered_name[len] = *(name+len);
3662 registered_name[len] = '\000';
3666 struct cmd_list_element *cmd_thread_list;
3667 struct cmd_list_element *cmd_task_list;
3671 thread_command (arg, from_tty)
3675 printf_unfiltered ("\"thread\" must be followed by the name of a thread command.\n");
3676 help_list (cmd_thread_list, "thread ", -1, gdb_stdout);
3681 task_command (arg, from_tty)
3685 printf_unfiltered ("\"task\" must be followed by the name of a task command.\n");
3686 help_list (cmd_task_list, "task ", -1, gdb_stdout);
3689 add_mach_specific_commands ()
3691 /* Thread handling commands */
3693 /* FIXME: Move our thread support into the generic thread.c stuff so we
3694 can share that code. */
3695 add_prefix_cmd ("mthread", class_stack, thread_command,
3696 "Generic command for handling Mach threads in the debugged task.",
3697 &cmd_thread_list, "thread ", 0, &cmdlist);
3699 add_com_alias ("th", "mthread", class_stack, 1);
3701 add_cmd ("select", class_stack, thread_select_command,
3702 "Select and print MID of the selected thread",
3704 add_cmd ("list", class_stack, thread_list_command,
3705 "List info of task's threads. Selected thread is marked with '*'",
3707 add_cmd ("suspend", class_run, thread_suspend_command,
3708 "Suspend one or all of the threads in the selected task.",
3710 add_cmd ("resume", class_run, thread_resume_command,
3711 "Resume one or all of the threads in the selected task.",
3713 add_cmd ("kill", class_run, thread_kill_command,
3714 "Kill the specified thread MID from inferior task.",
3717 /* The rest of this support (condition_thread) was not merged. It probably
3718 should not be merged in this form, but instead added to the generic GDB
3720 add_cmd ("break", class_breakpoint, condition_thread,
3721 "Breakpoint N will only be effective for thread MID or @SLOT\n\
3722 If MID/@SLOT is omitted allow all threads to break at breakpoint",
3725 /* Thread command shorthands (for backward compatibility) */
3726 add_alias_cmd ("ts", "mthread select", 0, 0, &cmdlist);
3727 add_alias_cmd ("tl", "mthread list", 0, 0, &cmdlist);
3729 /* task handling commands */
3731 add_prefix_cmd ("task", class_stack, task_command,
3732 "Generic command for handling debugged task.",
3733 &cmd_task_list, "task ", 0, &cmdlist);
3735 add_com_alias ("ta", "task", class_stack, 1);
3737 add_cmd ("suspend", class_run, task_suspend_command,
3738 "Suspend the inferior task.",
3740 add_cmd ("resume", class_run, task_resume_command,
3741 "Resume the inferior task.",
3743 add_cmd ("info", no_class, task_info_command,
3744 "Print information about the specified task.",
3747 /* Print my message port name */
3749 add_info ("message-port", message_port_info,
3750 "Returns the name of gdb's message port in the netnameserver");
3752 /* Exception commands */
3754 add_info ("exceptions", exception_info,
3755 "What debugger does when program gets various exceptions.\n\
3756 Specify an exception number as argument to print info on that\n\
3759 add_com ("exception", class_run, exception_command,
3760 "Specify how to handle an exception.\n\
3761 Args are exception number followed by \"forward\" or \"keep\".\n\
3762 `Forward' means forward the exception to the program's normal exception\n\
3764 `Keep' means reenter debugger if this exception happens, and GDB maps\n\
3765 the exception to some signal (see info exception)\n\
3766 Normally \"keep\" is used to return to GDB on exception.");
3770 do_mach_notify_dead_name (notify, name)
3774 kern_return_t kr = KERN_SUCCESS;
3776 /* Find the thing that notified */
3777 port_chain_t element = port_chain_member (notify_chain, name);
3779 /* Take name of from unreceived dead name notification list */
3780 notify_chain = port_chain_delete (notify_chain, name);
3783 error ("Received a dead name notify from unchained port (0x%x)", name);
3785 switch (element->type) {
3787 case MACH_TYPE_THREAD:
3788 target_terminal_ours_for_output ();
3789 if (name == current_thread)
3791 printf_filtered ("\nCurrent thread %d died", element->mid);
3792 current_thread = MACH_PORT_NULL;
3795 printf_filtered ("\nThread %d died", element->mid);
3799 case MACH_TYPE_TASK:
3800 target_terminal_ours_for_output ();
3801 if (name != inferior_task)
3802 printf_filtered ("Task %d died, but it was not the selected task",
3806 printf_filtered ("Current task %d died", element->mid);
3808 mach_port_destroy (mach_task_self(), name);
3809 inferior_task = MACH_PORT_NULL;
3812 warning ("There were still unreceived dead_name_notifications???");
3814 /* Destroy the old notifications */
3815 setup_notify_port (0);
3821 error ("Unregistered dead_name 0x%x notification received. Type is %d, mid is 0x%x",
3822 name, element->type, element->mid);
3826 return KERN_SUCCESS;
3830 do_mach_notify_msg_accepted (notify, name)
3834 warning ("do_mach_notify_msg_accepted : notify %x, name %x",
3836 return KERN_SUCCESS;
3840 do_mach_notify_no_senders (notify, mscount)
3842 mach_port_mscount_t mscount;
3844 warning ("do_mach_notify_no_senders : notify %x, mscount %x",
3846 return KERN_SUCCESS;
3850 do_mach_notify_port_deleted (notify, name)
3854 warning ("do_mach_notify_port_deleted : notify %x, name %x",
3856 return KERN_SUCCESS;
3860 do_mach_notify_port_destroyed (notify, rights)
3864 warning ("do_mach_notify_port_destroyed : notify %x, rights %x",
3866 return KERN_SUCCESS;
3870 do_mach_notify_send_once (notify)
3874 /* MANY of these are generated. */
3875 warning ("do_mach_notify_send_once : notify %x",
3878 return KERN_SUCCESS;
3881 /* Kills the inferior. It's gone when you call this */
3883 kill_inferior_fast ()
3887 if (inferior_pid == 0 || inferior_pid == 1)
3890 /* kill() it, since the Unix server does not otherwise notice when
3891 * killed with task_terminate().
3893 if (inferior_pid > 0)
3894 kill (inferior_pid, SIGKILL);
3896 /* It's propably terminate already */
3897 (void) task_terminate (inferior_task);
3899 inferior_task = MACH_PORT_NULL;
3900 current_thread = MACH_PORT_NULL;
3902 wait3 (&w, WNOHANG, 0);
3904 setup_notify_port (0);
3910 kill_inferior_fast ();
3911 target_mourn_inferior ();
3914 /* Clean up after the inferior dies. */
3917 m3_mourn_inferior ()
3919 unpush_target (&m3_ops);
3920 generic_mourn_inferior ();
3924 /* Fork an inferior process, and start debugging it. */
3927 m3_create_inferior (exec_file, allargs, env)
3932 fork_inferior (exec_file, allargs, env, m3_trace_me, m3_trace_him, NULL);
3933 /* We are at the first instruction we care about. */
3934 /* Pedal to the metal... */
3935 proceed ((CORE_ADDR) -1, 0, 0);
3938 /* Mark our target-struct as eligible for stray "run" and "attach"
3946 /* Mach 3.0 does not need ptrace for anything
3947 * Make sure nobody uses it on mach.
3952 error ("Lose, Lose! Somebody called ptrace\n");
3955 /* Resume execution of the inferior process.
3956 If STEP is nonzero, single-step it.
3957 If SIGNAL is nonzero, give it that signal. */
3960 m3_resume (pid, step, signal)
3963 enum target_signal signal;
3969 thread_basic_info_data_t th_info;
3970 unsigned int infoCnt = THREAD_BASIC_INFO_COUNT;
3972 /* There is no point in single stepping when current_thread
3975 if (! MACH_PORT_VALID (current_thread))
3976 error ("No thread selected; can not single step");
3978 /* If current_thread is suspended, tracing it would never return.
3980 ret = thread_info (current_thread,
3982 (thread_info_t) &th_info,
3984 CHK ("child_resume: can't get thread info", ret);
3986 if (th_info.suspend_count)
3987 error ("Can't trace a suspended thread. Use \"thread resume\" command to resume it");
3990 vm_read_cache_valid = FALSE;
3992 if (signal && inferior_pid > 0) /* Do not signal, if attached by MID */
3993 kill (inferior_pid, target_signal_to_host (signal));
3997 suspend_all_threads (0);
3999 setup_single_step (current_thread, TRUE);
4001 ret = thread_resume (current_thread);
4002 CHK ("thread_resume", ret);
4005 ret = task_resume (inferior_task);
4006 if (ret == KERN_FAILURE)
4007 warning ("Task was not suspended");
4009 CHK ("Resuming task", ret);
4011 /* HACK HACK This is needed by the multiserver system HACK HACK */
4012 while ((ret = task_resume(inferior_task)) == KERN_SUCCESS)
4013 /* make sure it really runs */;
4014 /* HACK HACK This is needed by the multiserver system HACK HACK */
4017 #ifdef ATTACH_DETACH
4019 /* Start debugging the process with the given task */
4025 inferior_task = tid;
4027 ret = task_suspend (inferior_task);
4028 CHK("task_attach: task_suspend", ret);
4030 must_suspend_thread = 0;
4032 setup_notify_port (1);
4034 request_notify (inferior_task, MACH_NOTIFY_DEAD_NAME, MACH_TYPE_TASK);
4036 setup_exception_port ();
4038 emulator_present = have_emulator_p (inferior_task);
4043 /* Well, we can call error also here and leave the
4044 * target stack inconsistent. Sigh.
4045 * Fix this sometime (the only way to fail here is that
4046 * the task has no threads at all, which is rare, but
4047 * possible; or if the target task has died, which is also
4048 * possible, but unlikely, since it has been suspended.
4049 * (Someone must have killed it))
4054 if (select_thread (inferior_task, 0, 1) != KERN_SUCCESS)
4055 error ("Could not select any threads to attach to");
4063 ret = machid_mach_port (mid_server, mid_auth, mid, &inferior_task);
4064 CHK("mid_attach: machid_mach_port", ret);
4066 task_attach (inferior_task);
4072 * Start debugging the process whose unix process-id is PID.
4073 * A negative "pid" value is legal and signifies a mach_id not a unix pid.
4075 * Prevent (possible unwanted) dangerous operations by enabled users
4076 * like "atta 0" or "atta foo" (equal to the previous :-) and
4077 * "atta pidself". Anyway, the latter is allowed by specifying a MID.
4086 error("MID=0, Debugging the master unix server does not compute");
4088 /* Foo. This assumes gdb has a unix pid */
4089 if (pid == getpid())
4090 error ("I will debug myself only by mid. (Gdb would suspend itself!)");
4094 mid_attach (-(pid));
4096 /* inferior_pid will be NEGATIVE! */
4099 return inferior_pid;
4102 inferior_task = task_by_pid (pid);
4103 if (! MACH_PORT_VALID (inferior_task))
4104 error("Cannot map Unix pid %d to Mach task port", pid);
4106 task_attach (inferior_task);
4110 return inferior_pid;
4113 /* Attach to process PID, then initialize for debugging it
4114 and wait for the trace-trap that results from attaching. */
4117 m3_attach (args, from_tty)
4125 error_no_arg ("process-id to attach");
4129 if (pid == getpid()) /* Trying to masturbate? */
4130 error ("I refuse to debug myself!");
4134 exec_file = (char *) get_exec_file (0);
4137 printf_unfiltered ("Attaching to program `%s', %s\n", exec_file, target_pid_to_str (pid));
4139 printf_unfiltered ("Attaching to %s\n", target_pid_to_str (pid));
4141 gdb_flush (gdb_stdout);
4146 push_target (&m3_ops);
4150 deallocate_inferior_ports ()
4153 thread_array_t thread_list;
4154 int thread_count, index;
4156 if (!MACH_PORT_VALID (inferior_task))
4159 ret = task_threads (inferior_task, &thread_list, &thread_count);
4160 if (ret != KERN_SUCCESS)
4162 warning ("deallocate_inferior_ports: task_threads",
4163 mach_error_string(ret));
4167 /* Get rid of send rights to task threads */
4168 for (index = 0; index < thread_count; index++)
4171 ret = mach_port_get_refs (mach_task_self (),
4173 MACH_PORT_RIGHT_SEND,
4175 CHK("deallocate_inferior_ports: get refs", ret);
4179 ret = mach_port_mod_refs (mach_task_self (),
4181 MACH_PORT_RIGHT_SEND,
4183 CHK("deallocate_inferior_ports: mod refs", ret);
4187 ret = mach_port_mod_refs (mach_task_self (),
4188 inferior_exception_port,
4189 MACH_PORT_RIGHT_RECEIVE,
4191 CHK ("deallocate_inferior_ports: cannot get rid of exception port", ret);
4193 ret = mach_port_deallocate (mach_task_self (),
4195 CHK ("deallocate_task_port: deallocating inferior_task", ret);
4197 current_thread = MACH_PORT_NULL;
4198 inferior_task = MACH_PORT_NULL;
4201 /* Stop debugging the process whose number is PID
4202 and continue it with signal number SIGNAL.
4203 SIGNAL = 0 means just continue it. */
4206 m3_do_detach (signal)
4211 MACH_ERROR_NO_INFERIOR;
4213 if (current_thread != MACH_PORT_NULL)
4215 /* Store the gdb's view of the thread we are deselecting
4217 * @@ I am really not sure if this is ever needeed.
4219 target_prepare_to_store ();
4220 target_store_registers (-1);
4223 ret = task_set_special_port (inferior_task,
4224 TASK_EXCEPTION_PORT,
4225 inferior_old_exception_port);
4226 CHK ("task_set_special_port", ret);
4228 /* Discard all requested notifications */
4229 setup_notify_port (0);
4231 if (remove_breakpoints ())
4232 warning ("Could not remove breakpoints when detaching");
4234 if (signal && inferior_pid > 0)
4235 kill (inferior_pid, signal);
4237 /* the task might be dead by now */
4238 (void) task_resume (inferior_task);
4240 deallocate_inferior_ports ();
4245 /* Take a program previously attached to and detaches it.
4246 The program resumes execution and will no longer stop
4247 on signals, etc. We'd better not have left any breakpoints
4248 in the program or it'll die when it hits one. For this
4249 to work, it may be necessary for the process to have been
4250 previously attached. It *might* work if the program was
4251 started via fork. */
4254 m3_detach (args, from_tty)
4262 char *exec_file = get_exec_file (0);
4265 printf_unfiltered ("Detaching from program: %s %s\n",
4266 exec_file, target_pid_to_str (inferior_pid));
4267 gdb_flush (gdb_stdout);
4270 siggnal = atoi (args);
4272 m3_do_detach (siggnal);
4274 unpush_target (&m3_ops); /* Pop out of handling an inferior */
4276 #endif /* ATTACH_DETACH */
4278 /* Get ready to modify the registers array. On machines which store
4279 individual registers, this doesn't need to do anything. On machines
4280 which store all the registers in one fell swoop, this makes sure
4281 that registers contains all the registers from the program being
4285 m3_prepare_to_store ()
4287 #ifdef CHILD_PREPARE_TO_STORE
4288 CHILD_PREPARE_TO_STORE ();
4292 /* Print status information about what we're accessing. */
4295 m3_files_info (ignore)
4296 struct target_ops *ignore;
4298 /* FIXME: should print MID and all that crap. */
4299 printf_unfiltered ("\tUsing the running image of %s %s.\n",
4300 attach_flag? "attached": "child", target_pid_to_str (inferior_pid));
4304 m3_open (arg, from_tty)
4308 error ("Use the \"run\" command to start a Unix child process.");
4318 char *bsd1_names[] = {
4386 int bsd1_nnames = sizeof(bsd1_names)/sizeof(bsd1_names[0]);
4396 case MACH_MSG_TYPE_BOOLEAN:
4398 case MACH_MSG_TYPE_INTEGER_16:
4400 case MACH_MSG_TYPE_INTEGER_32:
4402 case MACH_MSG_TYPE_CHAR:
4404 case MACH_MSG_TYPE_BYTE:
4406 case MACH_MSG_TYPE_REAL:
4408 case MACH_MSG_TYPE_STRING:
4411 sprintf(buf,"%d",name);
4424 if (id >= 101000 && id < 101000+bsd1_nnames) {
4425 if (p = bsd1_names[id-101000])
4429 return "psignal_retry";
4432 sprintf(buf,"%d",id);
4437 mach_msg_header_t *mp;
4439 char *fmt_x = "%20s : 0x%08x\n";
4440 char *fmt_d = "%20s : %10d\n";
4441 char *fmt_s = "%20s : %s\n";
4444 puts_filtered ("\n");
4445 #define pr(fmt,h,x) printf_filtered(fmt,STR(x),(h).x)
4446 pr(fmt_x,(*mp),msgh_bits);
4447 pr(fmt_d,(*mp),msgh_size);
4448 pr(fmt_x,(*mp),msgh_remote_port);
4449 pr(fmt_x,(*mp),msgh_local_port);
4450 pr(fmt_d,(*mp),msgh_kind);
4451 printf_filtered(fmt_s,STR(msgh_id),id_str(mp->msgh_id,buf));
4453 if (debug_level > 1)
4458 ep = p+mp->msgh_size;
4460 for(; p < ep; p += plen) {
4461 mach_msg_type_t *tp;
4462 mach_msg_type_long_t *tlp;
4463 int name,size,number;
4464 tp = (mach_msg_type_t*)p;
4465 if (tp->msgt_longform) {
4466 tlp = (mach_msg_type_long_t*)tp;
4467 name = tlp->msgtl_name;
4468 size = tlp->msgtl_size;
4469 number = tlp->msgtl_number;
4470 plen = sizeof(*tlp);
4472 name = tp->msgt_name;
4473 size = tp->msgt_size;
4474 number = tp->msgt_number;
4477 printf_filtered("name=%-16s size=%2d number=%7d inline=%d long=%d deal=%d\n",
4478 name_str(name,buf),size,number,tp->msgt_inline,
4479 tp->msgt_longform, tp->msgt_deallocate);
4481 if (tp->msgt_inline) {
4484 l = (l+sizeof(long)-1)&~((sizeof(long))-1);
4486 print_data(dp,size,number);
4488 plen += sizeof(int*);
4490 printf_filtered("plen=%d\n",plen);
4495 print_data(p,size,number)
4506 for(i = 0; i < number; i++) {
4507 printf_filtered(" %02x",p[i]);
4512 for(i = 0; i < number; i++) {
4513 printf_filtered(" %04x",sp[i]);
4518 for(i = 0; i < number; i++) {
4519 printf_filtered(" %08x",ip[i]);
4523 puts_filtered("\n");
4527 struct target_ops m3_ops = {
4528 "mach", /* to_shortname */
4529 "Mach child process", /* to_longname */
4530 "Mach child process (started by the \"run\" command).", /* to_doc */
4531 m3_open, /* to_open */
4533 m3_attach, /* to_attach */
4534 m3_detach, /* to_detach */
4535 m3_resume, /* to_resume */
4536 mach_really_wait, /* to_wait */
4537 fetch_inferior_registers, /* to_fetch_registers */
4538 store_inferior_registers, /* to_store_registers */
4539 m3_prepare_to_store, /* to_prepare_to_store */
4540 m3_xfer_memory, /* to_xfer_memory */
4541 m3_files_info, /* to_files_info */
4542 memory_insert_breakpoint, /* to_insert_breakpoint */
4543 memory_remove_breakpoint, /* to_remove_breakpoint */
4544 terminal_init_inferior, /* to_terminal_init */
4545 terminal_inferior, /* to_terminal_inferior */
4546 terminal_ours_for_output, /* to_terminal_ours_for_output */
4547 terminal_ours, /* to_terminal_ours */
4548 child_terminal_info, /* to_terminal_info */
4549 m3_kill_inferior, /* to_kill */
4551 0, /* to_lookup_symbol */
4553 m3_create_inferior, /* to_create_inferior */
4554 m3_mourn_inferior, /* to_mourn_inferior */
4555 m3_can_run, /* to_can_run */
4556 0, /* to_notice_signals */
4557 process_stratum, /* to_stratum */
4559 1, /* to_has_all_memory */
4560 1, /* to_has_memory */
4561 1, /* to_has_stack */
4562 1, /* to_has_registers */
4563 1, /* to_has_execution */
4565 0, /* sections_end */
4566 OPS_MAGIC /* to_magic */
4570 _initialize_m3_nat ()
4574 add_target (&m3_ops);
4576 ret = mach_port_allocate(mach_task_self(),
4577 MACH_PORT_RIGHT_PORT_SET,
4578 &inferior_wait_port_set);
4579 if (ret != KERN_SUCCESS)
4580 fatal("initial port set %s",mach_error_string(ret));
4582 /* mach_really_wait now waits for this */
4583 currently_waiting_for = inferior_wait_port_set;
4585 ret = netname_look_up(name_server_port, hostname, "MachID", &mid_server);
4586 if (ret != KERN_SUCCESS)
4588 mid_server = MACH_PORT_NULL;
4590 warning ("initialize machid: netname_lookup_up(MachID) : %s",
4591 mach_error_string(ret));
4592 warning ("Some (most?) features disabled...");
4595 mid_auth = mach_privileged_host_port();
4596 if (mid_auth == MACH_PORT_NULL)
4597 mid_auth = mach_task_self();
4599 obstack_init (port_chain_obstack);
4601 ret = mach_port_allocate (mach_task_self (),
4602 MACH_PORT_RIGHT_RECEIVE,
4603 &thread_exception_port);
4604 CHK ("Creating thread_exception_port for single stepping", ret);
4606 ret = mach_port_insert_right (mach_task_self (),
4607 thread_exception_port,
4608 thread_exception_port,
4609 MACH_MSG_TYPE_MAKE_SEND);
4610 CHK ("Inserting send right to thread_exception_port", ret);
4612 /* Allocate message port */
4613 ret = mach_port_allocate (mach_task_self (),
4614 MACH_PORT_RIGHT_RECEIVE,
4616 if (ret != KERN_SUCCESS)
4617 warning ("Creating message port %s", mach_error_string (ret));
4620 char buf[ MAX_NAME_LEN ];
4621 ret = mach_port_move_member(mach_task_self (),
4623 inferior_wait_port_set);
4624 if (ret != KERN_SUCCESS)
4625 warning ("message move member %s", mach_error_string (ret));
4628 /* @@@@ No way to change message port name currently */
4629 /* Foo. This assumes gdb has a unix pid */
4630 sprintf (buf, "gdb-%d", getpid ());
4631 gdb_register_port (buf, our_message_port);
4634 /* Heap for thread commands */
4635 obstack_init (cproc_obstack);
4637 add_mach_specific_commands ();