1 /* Interface GDB to Mach 3.0 operating systems.
2 (Most) Mach 3.0 related routines live in this file.
4 Copyright (C) 1992 Free Software Foundation, Inc.
6 This file is part of GDB.
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
23 * Author: Jukka Virtanen <jtv@hut.fi>
25 * Helsinki University of Technology
28 * Thanks to my friends who helped with ideas and testing:
30 * Johannes Helander, Antti Louko, Tero Mononen,
31 * jvh@cs.hut.fi alo@hut.fi tmo@cs.hut.fi
33 * Tero Kivinen and Eamonn McManus
34 * kivinen@cs.hut.fi emcmanus@gr.osf.org
41 #include <servers/netname.h>
42 #include <servers/machid.h>
43 #include <mach/message.h>
44 #include <mach/notify.h>
45 #include <mach_error.h>
46 #include <mach/exception.h>
47 #include <mach/vm_attributes.h>
58 #include <servers/machid_lib.h>
60 /* Included only for signal names and NSIG
62 * note: There are many problems in signal handling with
63 * gdb in Mach 3.0 in general.
66 #define SIG_UNKNOWN 0 /* Exception that has no matching unix signal */
70 /* This is what a cproc looks like. This is here partly because
71 cthread_internals.h is not a header we can just #include, partly with
72 an eye towards perhaps getting this to work with cross-debugging
73 someday. Best solution is if CMU publishes a real interface to this
75 #define CPROC_NEXT_OFFSET 0
76 #define CPROC_NEXT_SIZE (TARGET_PTR_BIT / HOST_CHAR_BIT)
77 #define CPROC_INCARNATION_OFFSET (CPROC_NEXT_OFFSET + CPROC_NEXT_SIZE)
78 #define CPROC_INCARNATION_SIZE (sizeof (cthread_t))
79 #define CPROC_LIST_OFFSET (CPROC_INCARNATION_OFFSET + CPROC_INCARNATION_SIZE)
80 #define CPROC_LIST_SIZE (TARGET_PTR_BIT / HOST_CHAR_BIT)
81 #define CPROC_WAIT_OFFSET (CPROC_LIST_OFFSET + CPROC_LIST_SIZE)
82 #define CPROC_WAIT_SIZE (TARGET_PTR_BIT / HOST_CHAR_BIT)
83 #define CPROC_REPLY_OFFSET (CPROC_WAIT_OFFSET + CPROC_WAIT_SIZE)
84 #define CPROC_REPLY_SIZE (sizeof (mach_port_t))
85 #define CPROC_CONTEXT_OFFSET (CPROC_REPLY_OFFSET + CPROC_REPLY_SIZE)
86 #define CPROC_CONTEXT_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT)
87 #define CPROC_LOCK_OFFSET (CPROC_CONTEXT_OFFSET + CPROC_CONTEXT_SIZE)
88 #define CPROC_LOCK_SIZE (sizeof (spin_lock_t))
89 #define CPROC_STATE_OFFSET (CPROC_LOCK_OFFSET + CPROC_LOCK_SIZE)
90 #define CPROC_STATE_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT)
91 #define CPROC_WIRED_OFFSET (CPROC_STATE_OFFSET + CPROC_STATE_SIZE)
92 #define CPROC_WIRED_SIZE (sizeof (mach_port_t))
93 #define CPROC_BUSY_OFFSET (CPROC_WIRED_OFFSET + CPROC_WIRED_SIZE)
94 #define CPROC_BUSY_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT)
95 #define CPROC_MSG_OFFSET (CPROC_BUSY_OFFSET + CPROC_BUSY_SIZE)
96 #define CPROC_MSG_SIZE (sizeof (mach_msg_header_t))
97 #define CPROC_BASE_OFFSET (CPROC_MSG_OFFSET + CPROC_MSG_SIZE)
98 #define CPROC_BASE_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT)
99 #define CPROC_SIZE_OFFSET (CPROC_BASE_OFFSET + CPROC_BASE_SIZE)
100 #define CPROC_SIZE_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT)
101 #define CPROC_SIZE (CPROC_SIZE_OFFSET + CPROC_SIZE_SIZE)
103 /* Values for the state field in the cproc. */
104 #define CPROC_RUNNING 0
105 #define CPROC_SWITCHING 1
106 #define CPROC_BLOCKED 2
107 #define CPROC_CONDWAIT 4
109 /* For cproc and kernel thread mapping */
110 typedef struct gdb_thread {
115 boolean_t in_emulator;
118 /* This is for the mthreads list. It points to the cproc list.
119 Perhaps the two lists should be merged (or perhaps it was a mistake
120 to make them both use a struct gdb_thread). */
121 struct gdb_thread *cproc;
123 /* These are for the cproc list, which is linked through the next field
124 of the struct gdb_thread. */
125 char raw_cproc[CPROC_SIZE];
126 /* The cthread which is pointed to by the incarnation field from the
127 cproc. This points to the copy we've read into GDB. */
129 /* Point back to the mthreads list. */
131 struct gdb_thread *next;
135 * Actions for Mach exceptions.
137 * sigmap field maps the exception to corresponding Unix signal.
139 * I do not know how to map the exception to unix signal
140 * if SIG_UNKNOWN is specified.
143 struct exception_list {
148 } exception_map[] = {
149 {"not_mach3_exception", FALSE, TRUE, SIG_UNKNOWN},
150 {"EXC_BAD_ACCESS", FALSE, TRUE, SIGSEGV},
151 {"EXC_BAD_INSTRUCTION", FALSE, TRUE, SIGILL},
152 {"EXC_ARITHMETIC", FALSE, TRUE, SIGFPE},
153 {"EXC_EMULATION", FALSE, TRUE, SIGEMT}, /* ??? */
154 {"EXC_SOFTWARE", FALSE, TRUE, SIG_UNKNOWN},
155 {"EXC_BREAKPOINT", FALSE, FALSE, SIGTRAP}
158 /* Mach exception table size */
159 int max_exception = sizeof(exception_map)/sizeof(struct exception_list) - 1;
161 #define MAX_EXCEPTION max_exception
163 WAITTYPE wait_status;
165 /* If you define this, intercepted bsd server calls will be
166 * dumped while waiting the inferior to EXEC the correct
169 /* #define DUMP_SYSCALL /* debugging interceptor */
171 /* xx_debug() outputs messages if this is nonzero.
172 * If > 1, DUMP_SYSCALL will dump message contents.
176 /* "Temporary" debug stuff */
178 xx_debug (fmt, a,b,c)
183 warning (fmt, a, b, c);
186 /* This is in libmach.a */
187 extern mach_port_t name_server_port;
189 /* Set in catch_exception_raise */
190 int stop_exception, stop_code, stop_subcode;
191 int stopped_in_exception;
193 /* Thread that was the active thread when we stopped */
194 thread_t stop_thread = MACH_PORT_NULL;
198 /* Set when task is attached or created */
199 boolean_t emulator_present = FALSE;
201 task_t inferior_task;
202 thread_t current_thread;
204 /* Exception ports for inferior task */
205 mach_port_t inferior_exception_port = MACH_PORT_NULL;
206 mach_port_t inferior_old_exception_port = MACH_PORT_NULL;
208 /* task exceptions and notifications */
209 mach_port_t inferior_wait_port_set = MACH_PORT_NULL;
210 mach_port_t our_notify_port = MACH_PORT_NULL;
212 /* This is "inferior_wait_port_set" when not single stepping, and
213 * "singlestepped_thread_port" when we are single stepping.
215 * This is protected by a cleanup function: discard_single_step()
217 mach_port_t currently_waiting_for = MACH_PORT_NULL;
219 /* A port for external messages to gdb.
220 * External in the meaning that they do not come
221 * from the inferior_task, but rather from external
224 * As a debugging feature:
225 * A debugger debugging another debugger can stop the
226 * inferior debugger by the following command sequence
227 * (without running external programs)
229 * (top-gdb) set stop_inferior_gdb ()
232 mach_port_t our_message_port = MACH_PORT_NULL;
234 /* For single stepping */
235 mach_port_t thread_exception_port = MACH_PORT_NULL;
236 mach_port_t thread_saved_exception_port = MACH_PORT_NULL;
237 mach_port_t singlestepped_thread_port = MACH_PORT_NULL;
239 /* For machid calls */
240 mach_port_t mid_server = MACH_PORT_NULL;
241 mach_port_t mid_auth = MACH_PORT_NULL;
243 /* If gdb thinks the inferior task is not suspended, it
244 * must take suspend/abort the threads when it reads the state.
246 int must_suspend_thread = 0;
248 /* When single stepping, we switch the port that mach_really_wait() listens to.
249 * This cleanup is a guard to prevent the port set from being left to
250 * the singlestepped_thread_port when error() is called.
251 * This is nonzero only when we are single stepping.
253 #define NULL_CLEANUP (struct cleanup *)0
254 struct cleanup *cleanup_step = NULL_CLEANUP;
258 #define MACH_TYPE_EXCEPTION_PORT -1
261 /* Chain of ports to remember requested notifications. */
264 struct port_chain *next;
267 int mid; /* Now only valid with MACH_TYPE_THREAD and */
268 /* MACH_TYPE_THREAD */
270 typedef struct port_chain *port_chain_t;
272 /* Room for chain nodes comes from pchain_obstack */
273 struct obstack pchain_obstack;
274 struct obstack *port_chain_obstack = &pchain_obstack;
276 /* For thread handling */
277 struct obstack Cproc_obstack;
278 struct obstack *cproc_obstack = &Cproc_obstack;
280 /* the list of notified ports */
281 port_chain_t notify_chain = (port_chain_t) NULL;
284 port_chain_insert (list, name, type)
293 if (! MACH_PORT_VALID (name))
296 if (type == MACH_TYPE_TASK || type == MACH_TYPE_THREAD)
298 if (! MACH_PORT_VALID (mid_server))
300 warning ("Machid server port invalid, can not map port 0x%x to MID",
306 ret = machid_mach_register (mid_server, mid_auth, name, type, &mid);
308 if (ret != KERN_SUCCESS)
310 warning ("Can not map name (0x%x) to MID with machid", name);
316 mid = 3735928559; /* 0x? :-) */
318 new = (port_chain_t) obstack_alloc (port_chain_obstack,
319 sizeof (struct port_chain));
329 port_chain_delete (list, elem)
334 if (list->port == elem)
339 if (list->next->port == elem)
340 list->next = list->next->next; /* GCd with obstack_free() */
348 port_chain_destroy (ostack)
349 struct obstack *ostack;
351 obstack_free (ostack, 0);
352 obstack_init (ostack);
356 port_chain_member (list, elem)
362 if (list->port == elem)
366 return (port_chain_t) NULL;
370 map_port_name_to_mid (name, type)
376 if (!MACH_PORT_VALID (name))
379 elem = port_chain_member (notify_chain, name);
381 if (elem && (elem->type == type))
387 if (! MACH_PORT_VALID (mid_server))
389 warning ("Machid server port invalid, can not map port 0x%x to mid",
398 ret = machid_mach_register (mid_server, mid_auth, name, type, &mid);
400 if (ret != KERN_SUCCESS)
402 warning ("Can not map name (0x%x) to mid with machid", name);
409 /* Guard for currently_waiting_for and singlestepped_thread_port */
411 discard_single_step (thread)
414 currently_waiting_for = inferior_wait_port_set;
416 cleanup_step = NULL_CLEANUP;
417 if (MACH_PORT_VALID (thread) && MACH_PORT_VALID (singlestepped_thread_port))
418 setup_single_step (thread, FALSE);
421 setup_single_step (thread, start_step)
423 boolean_t start_step;
427 if (! MACH_PORT_VALID (thread))
428 error ("Invalid thread supplied to setup_single_step");
433 /* Get the current thread exception port */
434 ret = thread_get_exception_port (thread, &teport);
435 CHK ("Getting thread's exception port", ret);
439 if (MACH_PORT_VALID (singlestepped_thread_port))
441 warning ("Singlestepped_thread_port (0x%x) is still valid?",
442 singlestepped_thread_port);
443 singlestepped_thread_port = MACH_PORT_NULL;
446 /* If we are already stepping this thread */
447 if (MACH_PORT_VALID (teport) && teport == thread_exception_port)
449 ret = mach_port_deallocate (mach_task_self (), teport);
450 CHK ("Could not deallocate thread exception port", ret);
454 ret = thread_set_exception_port (thread, thread_exception_port);
455 CHK ("Setting exception port for thread", ret);
457 /* Insert thread exception port to wait port set */
458 ret = mach_port_move_member (mach_task_self(),
459 thread_exception_port,
460 inferior_wait_port_set);
461 CHK ("Moving thread exception port to inferior_wait_port_set",
464 thread_saved_exception_port = teport;
467 thread_trace (thread, TRUE);
469 singlestepped_thread_port = thread_exception_port;
470 currently_waiting_for = singlestepped_thread_port;
471 cleanup_step = make_cleanup (discard_single_step, thread);
475 if (! MACH_PORT_VALID (teport))
476 error ("Single stepped thread had an invalid exception port?");
478 if (teport != thread_exception_port)
479 error ("Single stepped thread had an unknown exception port?");
481 ret = mach_port_deallocate (mach_task_self (), teport);
482 CHK ("Couldn't deallocate thread exception port", ret);
484 /* Remove thread exception port from wait port set */
485 ret = mach_port_move_member (mach_task_self(),
486 thread_exception_port,
488 CHK ("Removing thread exception port from inferior_wait_port_set",
491 /* Restore thread's old exception port */
492 ret = thread_set_exception_port (thread,
493 thread_saved_exception_port);
494 CHK ("Restoring stepped thread's exception port", ret);
496 if (MACH_PORT_VALID (thread_saved_exception_port))
497 (void) mach_port_deallocate (mach_task_self (),
498 thread_saved_exception_port);
500 thread_trace (thread, FALSE);
502 singlestepped_thread_port = MACH_PORT_NULL;
503 currently_waiting_for = inferior_wait_port_set;
505 discard_cleanups (cleanup_step);
511 request_notify (name, variant, type)
513 mach_msg_id_t variant;
517 mach_port_t previous_port_dummy = MACH_PORT_NULL;
519 if (! MACH_PORT_VALID (name))
522 if (port_chain_member (notify_chain, name))
525 ret = mach_port_request_notification (mach_task_self(),
530 MACH_MSG_TYPE_MAKE_SEND_ONCE,
531 &previous_port_dummy);
532 CHK ("Serious: request_notify failed", ret);
534 (void) mach_port_deallocate (mach_task_self (),
535 previous_port_dummy);
537 notify_chain = port_chain_insert (notify_chain, name, type);
540 reverse_msg_bits(msgp, type)
541 mach_msg_header_t *msgp;
545 rbits = MACH_MSGH_BITS_REMOTE(msgp->msgh_bits);
548 (msgp->msgh_bits & ~MACH_MSGH_BITS_PORTS_MASK) |
549 MACH_MSGH_BITS(lbits,rbits);
552 /* On the third day He said:
555 and then it was global.
557 When creating the inferior fork, the
558 child code in inflow.c sets the name of the
559 bootstrap_port in its address space to this
562 The name is transferred to our address space
563 with mach3_read_inferior().
565 Thou shalt not do this with
566 task_get_bootstrap_port() in this task, since
567 the name in the inferior task is different than
570 For blessed are the meek, as they shall inherit
573 mach_port_t original_server_port_name = MACH_PORT_NULL;
576 /* Called from inferior after FORK but before EXEC */
582 /* Get the NAME of the bootstrap port in this task
583 so that GDB can read it */
584 ret = task_get_bootstrap_port (mach_task_self (),
585 &original_server_port_name);
586 if (ret != KERN_SUCCESS)
588 ret = mach_port_deallocate (mach_task_self (),
589 original_server_port_name);
590 if (ret != KERN_SUCCESS)
593 /* Suspend this task to let the parent change my ports.
594 Resumed by the debugger */
595 ret = task_suspend (mach_task_self ());
596 if (ret != KERN_SUCCESS)
601 * Intercept system calls to Unix server.
602 * After EXEC_COUNTER calls to exec(), return.
604 * Pre-assertion: Child is suspended. (Not verified)
605 * Post-condition: Child is suspended after EXEC_COUNTER exec() calls.
609 intercept_exec_calls (exec_counter)
612 struct syscall_msg_t {
613 mach_msg_header_t header;
614 mach_msg_type_t type;
615 char room[ 2000 ]; /* Enuff space */
618 struct syscall_msg_t syscall_in, syscall_out;
620 mach_port_t fake_server;
621 mach_port_t original_server_send;
622 mach_port_t original_exec_reply;
623 mach_port_t exec_reply;
624 mach_port_t exec_reply_send;
625 mach_msg_type_name_t acquired;
626 mach_port_t emulator_server_port_name;
627 struct task_basic_info info;
628 mach_msg_type_number_t info_count;
632 if (exec_counter <= 0)
633 return; /* We are already set up in the correct program */
635 ret = mach_port_allocate(mach_task_self(),
636 MACH_PORT_RIGHT_RECEIVE,
638 CHK("create inferior_fake_server port failed", ret);
640 /* Wait for inferior_task to suspend itself */
643 info_count = sizeof (info);
644 ret = task_info (inferior_task,
648 CHK ("Task info", ret);
650 if (info.suspend_count)
653 /* Note that the definition of the parameter was undefined
654 * at the time of this writing, so I just use an `ad hoc' value.
656 (void) swtch_pri (42); /* Universal Priority Value */
659 /* Read the inferior's bootstrap port name */
660 if (!mach3_read_inferior (&original_server_port_name,
661 &original_server_port_name,
662 sizeof (original_server_port_name)))
663 error ("Can't read inferior task bootstrap port name");
665 /* @@ BUG: If more than 1 send right GDB will FAIL!!! */
666 /* Should get refs, and set them back when restoring */
667 /* Steal the original bsd server send right from inferior */
668 ret = mach_port_extract_right (inferior_task,
669 original_server_port_name,
670 MACH_MSG_TYPE_MOVE_SEND,
671 &original_server_send,
673 CHK("mach_port_extract_right (bsd server send)",ret);
675 if (acquired != MACH_MSG_TYPE_PORT_SEND)
676 error("Incorrect right extracted, send right to bsd server excpected");
678 ret = mach_port_insert_right (inferior_task,
679 original_server_port_name,
681 MACH_MSG_TYPE_MAKE_SEND);
682 CHK("mach_port_insert_right (fake server send)",ret);
684 xx_debug ("inferior task bsd server ports set up \nfs %x, ospn %x, oss %x\n",
686 original_server_port_name, original_server_send);
688 /* A receive right to the reply generated by unix server exec() request */
689 ret = mach_port_allocate(mach_task_self(),
690 MACH_PORT_RIGHT_RECEIVE,
692 CHK("create intercepted_reply_port port failed", ret);
694 /* Pass this send right to Unix server so it replies to us after exec() */
695 ret = mach_port_extract_right (mach_task_self (),
697 MACH_MSG_TYPE_MAKE_SEND_ONCE,
700 CHK("mach_port_extract_right (exec_reply)",ret);
702 if (acquired != MACH_MSG_TYPE_PORT_SEND_ONCE)
703 error("Incorrect right extracted, send once excpected for exec reply");
705 ret = mach_port_move_member(mach_task_self(),
707 inferior_wait_port_set);
708 CHK ("Moving fake syscall port to inferior_wait_port_set", ret);
710 xx_debug ("syscall fake server set up, resuming inferior\n");
712 ret = task_resume (inferior_task);
713 CHK("task_resume (startup)", ret);
715 /* Read requests from the inferior.
716 Pass directly through everything else except exec() calls.
718 while(exec_counter > 0)
720 ret = mach_msg (&syscall_in.header, /* header */
721 MACH_RCV_MSG, /* options */
723 sizeof (struct syscall_msg_t), /* receive size */
724 inferior_wait_port_set, /* receive_name */
725 MACH_MSG_TIMEOUT_NONE,
727 CHK("mach_msg (intercepted sycall)", ret);
730 print_msg (&syscall_in.header);
733 /* ASSERT : msgh_local_port == fake_server */
735 if (notify_server (&syscall_in.header, &syscall_out.header))
736 error ("received a notify while intercepting syscalls");
738 if (syscall_in.header.msgh_id == MIG_EXEC_SYSCALL_ID)
740 xx_debug ("Received EXEC SYSCALL, counter = %d\n", exec_counter);
741 if (exec_counter == 1)
743 original_exec_reply = syscall_in.header.msgh_remote_port;
744 syscall_in.header.msgh_remote_port = exec_reply_send;
749 syscall_in.header.msgh_local_port = syscall_in.header.msgh_remote_port;
750 syscall_in.header.msgh_remote_port = original_server_send;
752 reverse_msg_bits(&syscall_in.header, MACH_MSG_TYPE_COPY_SEND);
754 ret = mach_msg_send (&syscall_in.header);
755 CHK ("Forwarded syscall", ret);
758 ret = mach_port_move_member(mach_task_self(),
761 CHK ("Moving fake syscall out of inferior_wait_port_set", ret);
763 ret = mach_port_move_member(mach_task_self(),
765 inferior_wait_port_set);
766 CHK ("Moving exec_reply to inferior_wait_port_set", ret);
768 ret = mach_msg (&syscall_in.header, /* header */
769 MACH_RCV_MSG, /* options */
771 sizeof (struct syscall_msg_t), /* receive size */
772 inferior_wait_port_set, /* receive_name */
773 MACH_MSG_TIMEOUT_NONE,
775 CHK("mach_msg (exec reply)", ret);
777 ret = task_suspend (inferior_task);
778 CHK ("Suspending inferior after last exec", ret);
780 must_suspend_thread = 0;
782 xx_debug ("Received exec reply from bsd server, suspended inferior task\n");
785 print_msg (&syscall_in.header);
788 /* Message should appear as if it came from the unix server */
789 syscall_in.header.msgh_local_port = MACH_PORT_NULL;
791 /* and go to the inferior task original reply port */
792 syscall_in.header.msgh_remote_port = original_exec_reply;
794 reverse_msg_bits(&syscall_in.header, MACH_MSG_TYPE_MOVE_SEND_ONCE);
796 ret = mach_msg_send (&syscall_in.header);
797 CHK ("Forwarding exec reply to inferior", ret);
799 /* Garbage collect */
800 ret = mach_port_deallocate (inferior_task,
801 original_server_port_name);
802 CHK ("deallocating fake server send right", ret);
804 ret = mach_port_insert_right (inferior_task,
805 original_server_port_name,
806 original_server_send,
807 MACH_MSG_TYPE_MOVE_SEND);
808 CHK ("Restoring the original bsd server send right", ret);
810 ret = mach_port_destroy (mach_task_self (),
812 fake_server = MACH_PORT_DEAD;
813 CHK("mach_port_destroy (fake_server)", ret);
815 ret = mach_port_destroy (mach_task_self (),
817 exec_reply = MACH_PORT_DEAD;
818 CHK("mach_port_destroy (exec_reply)", ret);
820 xx_debug ("Done with exec call interception\n");
824 consume_send_rights (thread_list, thread_count)
825 thread_array_t thread_list;
833 for (index = 0; index < thread_count; index++)
835 /* Since thread kill command kills threads, don't check ret */
836 (void) mach_port_deallocate (mach_task_self (),
837 thread_list [ index ]);
841 /* suspend/abort/resume a thread. */
842 setup_thread (thread, what)
850 ret = thread_suspend (thread);
851 CHK ("setup_thread thread_suspend", ret);
853 ret = thread_abort (thread);
854 CHK ("setup_thread thread_abort", ret);
858 ret = thread_resume (thread);
859 CHK ("setup_thread thread_resume", ret);
864 map_slot_to_mid (slot, threads, thread_count)
866 thread_array_t threads;
877 ret = task_threads (inferior_task, &threads, &thread_count);
878 CHK ("Can not select a thread from a dead task", ret);
881 if (slot < 0 || slot >= thread_count)
885 consume_send_rights (threads, thread_count);
886 (void) vm_deallocate (mach_task_self(), (vm_address_t)threads,
887 (thread_count * sizeof(mach_port_t)));
890 error ("invalid slot number");
895 mid = map_port_name_to_mid (threads [slot], MACH_TYPE_THREAD);
899 consume_send_rights (threads, thread_count);
900 (void) vm_deallocate (mach_task_self(), (vm_address_t)threads,
901 (thread_count * sizeof(mach_port_t)));
908 parse_thread_id (arg, thread_count, slots)
921 while (*arg && (*arg == ' ' || *arg == '\t'))
927 /* Currently parse MID and @SLOTNUMBER */
932 error ("valid thread mid expected");
940 error ("invalid slot number");
942 /* If you want slot numbers to remain slot numbers, set slots.
944 * Well, since 0 is reserved, return the ordinal number
945 * of the thread rather than the slot number. Awk, this
946 * counts as a kludge.
951 if (thread_count && slot >= thread_count)
954 mid = map_slot_to_mid (slot);
959 /* THREAD_ID 0 is special; it selects the first kernel
960 * thread from the list (i.e. SLOTNUMBER 0)
961 * This is used when starting the program with 'run' or when attaching.
963 * If FLAG is 0 the context is not changed, and the registers, frame, etc
964 * will continue to describe the old thread.
966 * If FLAG is nonzero, really select the thread.
967 * If FLAG is 2, the THREAD_ID is a slotnumber instead of a mid.
971 select_thread (task, thread_id, flag)
976 thread_array_t thread_list;
980 thread_t new_thread = MACH_PORT_NULL;
983 error ("Can't select cprocs without kernel thread");
985 ret = task_threads (task, &thread_list, &thread_count);
986 if (ret != KERN_SUCCESS)
988 warning ("Can not select a thread from a dead task");
993 if (thread_count == 0)
995 /* The task can not do anything anymore, but it still
996 * exists as a container for memory and ports.
998 registers_changed ();
999 warning ("Task %d has no threads",
1000 map_port_name_to_mid (task, MACH_TYPE_TASK));
1001 current_thread = MACH_PORT_NULL;
1002 (void) vm_deallocate(mach_task_self(),
1003 (vm_address_t) thread_list,
1004 (thread_count * sizeof(mach_port_t)));
1005 return KERN_FAILURE;
1008 if (! thread_id || flag == 2)
1010 /* First thread or a slotnumber */
1012 new_thread = thread_list[0];
1015 if (thread_id < thread_count)
1016 new_thread = thread_list[ thread_id ];
1019 (void) vm_deallocate(mach_task_self(),
1020 (vm_address_t) thread_list,
1021 (thread_count * sizeof(mach_port_t)));
1022 error ("No such thread slot number : %d", thread_id);
1028 for (index = 0; index < thread_count; index++)
1029 if (thread_id == map_port_name_to_mid (thread_list [index],
1032 new_thread = thread_list [index];
1038 error ("No thread with mid %d", thread_id);
1041 /* Notify when the selected thread dies */
1042 request_notify (new_thread, MACH_NOTIFY_DEAD_NAME, MACH_TYPE_THREAD);
1044 ret = vm_deallocate(mach_task_self(),
1045 (vm_address_t) thread_list,
1046 (thread_count * sizeof(mach_port_t)));
1047 CHK ("vm_deallocate", ret);
1050 current_thread = new_thread;
1054 if (MACH_PORT_VALID (current_thread))
1056 /* Store the gdb's view of the thread we are deselecting
1058 * @@ I think gdb updates registers immediately when they are
1059 * changed, so don't do this.
1061 ret = thread_abort (current_thread);
1062 CHK ("Could not abort system calls when saving state of old thread",
1064 target_prepare_to_store ();
1065 target_store_registers (-1);
1069 registers_changed ();
1071 current_thread = new_thread;
1073 ret = thread_abort (current_thread);
1074 CHK ("Could not abort system calls when selecting a thread", ret);
1076 stop_pc = read_pc();
1077 set_current_frame (create_new_frame (read_register (FP_REGNUM),
1080 select_frame (get_current_frame (), 0);
1082 stop_frame_address = FRAME_FP (get_current_frame ());
1085 return KERN_SUCCESS;
1089 * Switch to use thread named NEW_THREAD.
1093 switch_to_thread (new_thread)
1094 thread_t new_thread;
1096 thread_t saved_thread = current_thread;
1099 mid = map_port_name_to_mid (new_thread,
1102 warning ("Can't map thread name 0x%x to mid", new_thread);
1103 else if (select_thread (inferior_task, mid, 1) != KERN_SUCCESS)
1106 current_thread = saved_thread;
1107 error ("Could not select thread %d", mid);
1113 /* Do this in gdb after doing FORK but before STARTUP_INFERIOR.
1114 * Note that the registers are not yet valid in the inferior task.
1122 inferior_task = task_by_pid (pid);
1124 if (! MACH_PORT_VALID (inferior_task))
1125 error ("Can not map Unix pid %d to Mach task", pid);
1127 /* Clean up previous notifications and create new ones */
1128 setup_notify_port (1);
1130 /* When notification appears, the inferior task has died */
1131 request_notify (inferior_task, MACH_NOTIFY_DEAD_NAME, MACH_TYPE_TASK);
1133 emulator_present = have_emulator_p (inferior_task);
1135 /* By default, select the first thread,
1136 * If task has no threads, gives a warning
1137 * Does not fetch registers, since they are not yet valid.
1139 select_thread (inferior_task, 0, 0);
1141 inferior_exception_port = MACH_PORT_NULL;
1143 setup_exception_port ();
1145 xx_debug ("Now the debugged task is created\n");
1148 setup_exception_port ()
1152 ret = mach_port_allocate (mach_task_self(),
1153 MACH_PORT_RIGHT_RECEIVE,
1154 &inferior_exception_port);
1155 CHK("mach_port_allocate",ret);
1157 /* add send right */
1158 ret = mach_port_insert_right (mach_task_self (),
1159 inferior_exception_port,
1160 inferior_exception_port,
1161 MACH_MSG_TYPE_MAKE_SEND);
1162 CHK("mach_port_insert_right",ret);
1164 ret = mach_port_move_member (mach_task_self(),
1165 inferior_exception_port,
1166 inferior_wait_port_set);
1167 CHK("mach_port_move_member",ret);
1169 ret = task_get_special_port (inferior_task,
1170 TASK_EXCEPTION_PORT,
1171 &inferior_old_exception_port);
1172 CHK ("task_get_special_port(old exc)",ret);
1174 ret = task_set_special_port (inferior_task,
1175 TASK_EXCEPTION_PORT,
1176 inferior_exception_port);
1177 CHK("task_set_special_port",ret);
1179 ret = mach_port_deallocate (mach_task_self (),
1180 inferior_exception_port);
1181 CHK("mack_port_deallocate",ret);
1184 /* When notify appears, the inferior_task's exception
1185 * port has been destroyed.
1187 * Not used, since the dead_name_notification already
1188 * appears when task dies.
1191 request_notify (inferior_exception_port,
1192 MACH_NOTIFY_NO_SENDERS,
1193 MACH_TYPE_EXCEPTION_PORT);
1197 /* Nonzero if gdb is waiting for a message */
1198 int mach_really_waiting;
1200 /* Wait for the inferior to stop for some reason.
1201 - Loop on notifications until inferior_task dies.
1202 - Loop on exceptions until stopped_in_exception comes true.
1203 (e.g. we receive a single step trace trap)
1204 - a message arrives to gdb's message port
1206 There is no other way to exit this loop.
1208 Returns the inferior_pid for rest of gdb.
1209 Side effects: Set unix exit value to *w.
1212 mach_really_wait (w)
1219 mach_msg_header_t header;
1220 mach_msg_type_t foo;
1224 /* Either notify (death), exception or message can stop the inferior */
1225 stopped_in_exception = FALSE;
1231 stop_exception = stop_code = stop_subcode = -1;
1232 stop_thread = MACH_PORT_NULL;
1234 mach_really_waiting = 1;
1235 ret = mach_msg (&in_msg.header, /* header */
1236 MACH_RCV_MSG, /* options */
1238 sizeof (struct msg), /* receive size */
1239 currently_waiting_for, /* receive name */
1240 MACH_MSG_TIMEOUT_NONE,
1242 mach_really_waiting = 0;
1243 CHK("mach_msg (receive)", ret);
1245 /* Check if we received a notify of the childs' death */
1246 if (notify_server (&in_msg.header, &out_msg.header))
1248 /* If inferior_task is null then the inferior has
1249 gone away and we want to return to command level.
1250 Otherwise it was just an informative message and we
1251 need to look to see if there are any more. */
1252 if (inferior_task != MACH_PORT_NULL)
1256 /* Collect Unix exit status for gdb */
1258 wait3(w, WNOHANG, 0);
1260 /* This mess is here to check that the rest of
1261 * gdb knows that the inferior died. It also
1262 * tries to hack around the fact that Mach 3.0 (mk69)
1263 * unix server (ux28) does not always know what
1264 * has happened to it's children when mach-magic
1265 * is applied on them.
1267 if ((!WIFEXITED(*w) && WIFSTOPPED(*w)) ||
1268 (WIFEXITED(*w) && WEXITSTATUS(*w) > 0377))
1271 warning ("Using exit value 0 for terminated task");
1273 else if (!WIFEXITED(*w))
1275 int sig = WTERMSIG(*w);
1277 /* Signals cause problems. Warn the user. */
1278 if (sig != SIGKILL) /* Bad luck if garbage matches this */
1279 warning ("The terminating signal stuff may be nonsense");
1280 else if (sig > NSIG)
1283 warning ("Using exit value 0 for terminated task");
1286 return inferior_pid;
1290 /* Hmm. Check for exception, as it was not a notification.
1291 exc_server() does an upcall to catch_exception_raise()
1292 if this rpc is an exception. Further actions are decided
1295 if (! exc_server (&in_msg.header, &out_msg.header))
1298 /* Not an exception, check for message.
1300 * Messages don't come from the inferior, or if they
1301 * do they better be asynchronous or it will hang.
1303 if (gdb_message_server (&in_msg.header))
1306 error ("Unrecognized message received in mach_really_wait");
1309 /* Send the reply of the exception rpc to the suspended task */
1310 ret = mach_msg_send (&out_msg.header);
1311 CHK ("mach_msg_send (exc reply)", ret);
1313 if (stopped_in_exception)
1315 /* Get unix state. May be changed in mach3_exception_actions() */
1316 wait3(w, WNOHANG, 0);
1318 mach3_exception_actions (w, FALSE, "Task");
1320 return inferior_pid;
1325 /* Called by macro DO_QUIT() in utils.c(quit).
1326 * This is called just before calling error() to return to command level
1334 if (mach_really_waiting)
1336 ret = task_suspend (inferior_task);
1338 if (ret != KERN_SUCCESS)
1340 warning ("Could not suspend task for interrupt: %s",
1341 mach_error_string (ret));
1342 mach_really_waiting = 0;
1347 must_suspend_thread = 0;
1348 mach_really_waiting = 0;
1350 mid = map_port_name_to_mid (current_thread, MACH_TYPE_THREAD);
1353 warning ("Selecting first existing kernel thread");
1357 current_thread = MACH_PORT_NULL; /* Force setup */
1358 select_thread (inferior_task, mid, 1);
1363 /* If ^C is typed when we are waiting for a message
1364 * and your Unix server is able to notice that we
1367 * Called by REQUEST_QUIT() from utils.c(request_quit)
1370 mach3_request_quit ()
1372 if (mach_really_waiting)
1377 * Gdb message server.
1378 * Currently implemented is the STOP message, that causes
1379 * gdb to return to the command level like ^C had been typed from terminal.
1382 gdb_message_server (InP)
1383 mach_msg_header_t *InP;
1388 if (InP->msgh_local_port == our_message_port)
1390 /* A message coming to our_message_port. Check validity */
1391 switch (InP->msgh_id) {
1393 case GDB_MESSAGE_ID_STOP:
1394 ret = task_suspend (inferior_task);
1395 if (ret != KERN_SUCCESS)
1396 warning ("Could not suspend task for stop message: %s",
1397 mach_error_string (ret));
1399 /* QUIT in mach_really_wait() loop. */
1404 warning ("Invalid message id %d received, ignored.",
1412 /* Message not handled by this server */
1416 /* NOTE: This is not an RPC call. It is a simpleroutine.
1418 * This is not called from this gdb code.
1420 * It may be called by another debugger to cause this
1421 * debugger to enter command level:
1423 * (gdb) set stop_inferior_gdb ()
1426 * External program "stop-gdb" implements this also.
1429 stop_inferior_gdb ()
1433 /* Code generated by mig, with minor cleanups :-)
1435 * simpleroutine stop_inferior_gdb (our_message_port : mach_port_t);
1439 mach_msg_header_t Head;
1444 register Request *InP = &Mess;
1446 InP->Head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
1448 /* msgh_size passed as argument */
1449 InP->Head.msgh_remote_port = our_message_port;
1450 InP->Head.msgh_local_port = MACH_PORT_NULL;
1451 InP->Head.msgh_seqno = 0;
1452 InP->Head.msgh_id = GDB_MESSAGE_ID_STOP;
1454 ret = mach_msg (&InP->Head,
1455 MACH_SEND_MSG|MACH_MSG_OPTION_NONE,
1459 MACH_MSG_TIMEOUT_NONE,
1463 #ifdef THREAD_ALLOWED_TO_BREAK
1465 * Return 1 if the MID specifies the thread that caused the
1467 * Since catch_exception_raise() selects the thread causing
1468 * the last exception to current_thread, we just check that
1469 * it is selected and the last exception was a breakpoint.
1472 mach_thread_for_breakpoint (mid)
1475 int cmid = map_port_name_to_mid (current_thread, MACH_TYPE_THREAD);
1479 mid = map_slot_to_mid (-(mid+1), 0, 0);
1481 return 0; /* Don't stop, no such slot */
1484 if (! mid || cmid == -1)
1485 return 1; /* stop */
1487 return cmid == mid && stop_exception == EXC_BREAKPOINT;
1489 #endif /* THREAD_ALLOWED_TO_BREAK */
1491 #ifdef THREAD_PARSE_ID
1493 * Map a thread id string (MID or a @SLOTNUMBER)
1496 * 0 matches all threads.
1497 * Otherwise the meaning is defined only in this file.
1498 * (mach_thread_for_breakpoint uses it)
1500 * @@ This allows non-existent MIDs to be specified.
1501 * It now also allows non-existent slots to be
1502 * specified. (Slot numbers stored are negative,
1503 * and the magnitude is one greater than the actual
1504 * slot index. (Since 0 is reserved))
1507 mach_thread_parse_id (arg)
1512 error ("thread id excpected");
1513 mid = parse_thread_id (arg, 0, 1);
1517 #endif /* THREAD_PARSE_ID */
1519 #ifdef THREAD_OUTPUT_ID
1521 mach_thread_output_id (mid)
1524 static char foobar [20];
1527 sprintf (foobar, "mid %d", mid);
1529 sprintf (foobar, "@%d", -(mid+1));
1531 sprintf (foobar, "*any thread*");
1535 #endif /* THREAD_OUTPUT_ID */
1537 /* Called with hook PREPARE_TO_PROCEED() from infrun.c.
1539 * If we have switched threads and stopped at breakpoint return 1 otherwise 0.
1541 * if SELECT_IT is nonzero, reselect the thread that was active when
1542 * we stopped at a breakpoint.
1546 mach3_prepare_to_proceed (select_it)
1550 stop_thread != current_thread &&
1551 stop_exception == EXC_BREAKPOINT)
1558 mid = switch_to_thread (stop_thread);
1566 /* this stuff here is an upcall via libmach/excServer.c
1567 and mach_really_wait which does the actual upcall.
1569 The code will pass the exception to the inferior if:
1571 - The task that signaled is not the inferior task
1572 (e.g. when debugging another debugger)
1574 - The user has explicitely requested to pass on the exceptions.
1575 (e.g to the default unix exception handler, which maps
1576 exceptions to signals, or the user has her own exception handler)
1578 - If the thread that signaled is being single-stepped and it
1579 has set it's own exception port and the exception is not
1580 EXC_BREAKPOINT. (Maybe this is not desirable?)
1584 catch_exception_raise (port, thread, task, exception, code, subcode)
1588 int exception, code, subcode;
1591 boolean_t signal_thread;
1592 int mid = map_port_name_to_mid (thread, MACH_TYPE_THREAD);
1594 if (! MACH_PORT_VALID (thread))
1596 /* If the exception was sent and thread dies before we
1597 receive it, THREAD will be MACH_PORT_DEAD
1600 current_thread = thread = MACH_PORT_NULL;
1601 error ("Received exception from nonexistent thread");
1604 /* Check if the task died in transit.
1605 * @@ Isn't the thread also invalid in such case?
1607 if (! MACH_PORT_VALID (task))
1609 current_thread = thread = MACH_PORT_NULL;
1610 error ("Received exception from nonexistent task");
1613 if (exception < 0 || exception > MAX_EXCEPTION)
1614 fatal ("catch_exception_raise: unknown exception code %d thread %d",
1618 if (! MACH_PORT_VALID (inferior_task))
1619 error ("got an exception, but inferior_task is null or dead");
1621 stop_exception = exception;
1623 stop_subcode = subcode;
1624 stop_thread = thread;
1626 signal_thread = exception != EXC_BREAKPOINT &&
1627 port == singlestepped_thread_port &&
1628 MACH_PORT_VALID (thread_saved_exception_port);
1630 /* If it was not our inferior or if we want to forward
1631 * the exception to the inferior's handler, do it here
1633 * Note: If you have forwarded EXC_BREAKPOINT I trust you know why.
1635 if (task != inferior_task ||
1637 exception_map [exception].forward)
1639 mach_port_t eport = inferior_old_exception_port;
1644 GDB now forwards the exeption to thread's original handler,
1645 since the user propably knows what he is doing.
1646 Give a message, though.
1649 mach3_exception_actions ((WAITTYPE *)NULL, TRUE, "Thread");
1650 eport = thread_saved_exception_port;
1653 /* Send the exception to the original handler */
1654 ret = exception_raise (eport,
1661 (void) mach_port_deallocate (mach_task_self (), task);
1662 (void) mach_port_deallocate (mach_task_self (), thread);
1664 /* If we come here, we don't want to trace any more, since we
1665 * will never stop for tracing anyway.
1667 discard_single_step (thread);
1669 /* Do not stop the inferior */
1673 /* Now gdb handles the exception */
1674 stopped_in_exception = TRUE;
1676 ret = task_suspend (task);
1677 CHK ("Error suspending inferior after exception", ret);
1679 must_suspend_thread = 0;
1681 if (current_thread != thread)
1683 if (MACH_PORT_VALID (singlestepped_thread_port))
1684 /* Cleanup discards single stepping */
1685 error ("Exception from thread %d while singlestepping thread %d",
1687 map_port_name_to_mid (current_thread, MACH_TYPE_THREAD));
1689 /* Then select the thread that caused the exception */
1690 if (select_thread (inferior_task, mid, 0) != KERN_SUCCESS)
1691 error ("Could not select thread %d causing exception", mid);
1693 warning ("Gdb selected thread %d", mid);
1696 /* If we receive an exception that is not breakpoint
1697 * exception, we interrupt the single step and return to
1698 * debugger. Trace condition is cleared.
1700 if (MACH_PORT_VALID (singlestepped_thread_port))
1702 if (stop_exception != EXC_BREAKPOINT)
1703 warning ("Single step interrupted by exception");
1704 else if (port == singlestepped_thread_port)
1706 /* Single step exception occurred, remove trace bit
1707 * and return to gdb.
1709 if (! MACH_PORT_VALID (current_thread))
1710 error ("Single stepped thread is not valid");
1712 /* Resume threads, but leave the task suspended */
1713 resume_all_threads (0);
1716 warning ("Breakpoint while single stepping?");
1718 discard_single_step (current_thread);
1721 (void) mach_port_deallocate (mach_task_self (), task);
1722 (void) mach_port_deallocate (mach_task_self (), thread);
1724 return KERN_SUCCESS;
1728 port_valid (port, mask)
1733 mach_port_type_t type;
1735 ret = mach_port_type (mach_task_self (),
1738 if (ret != KERN_SUCCESS || (type & mask) != mask)
1743 /* @@ No vm read cache implemented yet */
1744 boolean_t vm_read_cache_valid = FALSE;
1747 * Read inferior task's LEN bytes from ADDR and copy it to MYADDR
1748 * in gdb's address space.
1750 * Return 0 on failure; number of bytes read otherwise.
1753 mach3_read_inferior (addr, myaddr, length)
1759 vm_address_t low_address = (vm_address_t) trunc_page (addr);
1760 vm_size_t aligned_length =
1761 (vm_size_t) round_page (addr+length) - low_address;
1762 pointer_t copied_memory;
1765 /* Get memory from inferior with page aligned addresses */
1766 ret = vm_read (inferior_task,
1771 if (ret != KERN_SUCCESS)
1773 /* the problem is that the inferior might be killed for whatever reason
1774 * before we go to mach_really_wait. This is one place that ought to
1775 * catch many of those errors.
1776 * @@ A better fix would be to make all external events to GDB
1777 * to arrive via a SINGLE port set. (Including user input!)
1780 if (! port_valid (inferior_task, MACH_PORT_TYPE_SEND))
1783 error ("Inferior killed (task port invalid)");
1789 /* valprint.c gives nicer format if this does not
1790 screw it. Eamonn seems to like this, so I enable
1791 it if OSF is defined...
1793 warning ("[read inferior %x failed: %s]",
1794 addr, mach_error_string (ret));
1801 memcpy (myaddr, (char *)addr - low_address + copied_memory, length);
1803 ret = vm_deallocate (mach_task_self (),
1806 CHK("mach3_read_inferior vm_deallocate failed", ret);
1812 #define CHK_GOTO_OUT(str,ret) \
1813 do if (ret != KERN_SUCCESS) { errstr = #str; goto out; } while(0)
1815 #define CHK_GOTO_OUT(str,ret) \
1816 do if (ret != KERN_SUCCESS) { errstr = str; goto out; } while(0)
1819 struct vm_region_list {
1820 struct vm_region_list *next;
1821 vm_prot_t protection;
1826 struct obstack region_obstack;
1829 * Write inferior task's LEN bytes from ADDR and copy it to MYADDR
1830 * in gdb's address space.
1833 mach3_write_inferior (addr, myaddr, length)
1839 vm_address_t low_address = (vm_address_t) trunc_page (addr);
1840 vm_size_t aligned_length =
1841 (vm_size_t) round_page (addr+length) - low_address;
1842 pointer_t copied_memory;
1846 char *errstr = "Bug in mach3_write_inferior";
1848 struct vm_region_list *region_element;
1849 struct vm_region_list *region_head = (struct vm_region_list *)NULL;
1851 /* Get memory from inferior with page aligned addresses */
1852 ret = vm_read (inferior_task,
1857 CHK_GOTO_OUT ("mach3_write_inferior vm_read failed", ret);
1861 memcpy ((char *)addr - low_address + copied_memory, myaddr, length);
1863 obstack_init (®ion_obstack);
1865 /* Do writes atomically.
1866 * First check for holes and unwritable memory.
1869 vm_size_t remaining_length = aligned_length;
1870 vm_address_t region_address = low_address;
1872 struct vm_region_list *scan;
1874 while(region_address < low_address + aligned_length)
1876 vm_prot_t protection;
1877 vm_prot_t max_protection;
1878 vm_inherit_t inheritance;
1880 mach_port_t object_name;
1882 vm_size_t region_length = remaining_length;
1883 vm_address_t old_address = region_address;
1885 ret = vm_region (inferior_task,
1894 CHK_GOTO_OUT ("vm_region failed", ret);
1896 /* Check for holes in memory */
1897 if (old_address != region_address)
1899 warning ("No memory at 0x%x. Nothing written",
1906 if (!(max_protection & VM_PROT_WRITE))
1908 warning ("Memory at address 0x%x is unwritable. Nothing written",
1915 /* Chain the regions for later use */
1917 (struct vm_region_list *)
1918 obstack_alloc (®ion_obstack, sizeof (struct vm_region_list));
1920 region_element->protection = protection;
1921 region_element->start = region_address;
1922 region_element->length = region_length;
1924 /* Chain the regions along with protections */
1925 region_element->next = region_head;
1926 region_head = region_element;
1928 region_address += region_length;
1929 remaining_length = remaining_length - region_length;
1932 /* If things fail after this, we give up.
1933 * Somebody is messing up inferior_task's mappings.
1936 /* Enable writes to the chained vm regions */
1937 for (scan = region_head; scan; scan = scan->next)
1939 boolean_t protection_changed = FALSE;
1941 if (!(scan->protection & VM_PROT_WRITE))
1943 ret = vm_protect (inferior_task,
1947 scan->protection | VM_PROT_WRITE);
1948 CHK_GOTO_OUT ("vm_protect: enable write failed", ret);
1952 ret = vm_write (inferior_task,
1956 CHK_GOTO_OUT ("vm_write failed", ret);
1958 /* Set up the original region protections, if they were changed */
1959 for (scan = region_head; scan; scan = scan->next)
1961 boolean_t protection_changed = FALSE;
1963 if (!(scan->protection & VM_PROT_WRITE))
1965 ret = vm_protect (inferior_task,
1970 CHK_GOTO_OUT ("vm_protect: enable write failed", ret);
1978 obstack_free (®ion_obstack, 0);
1980 (void) vm_deallocate (mach_task_self (),
1985 if (ret != KERN_SUCCESS)
1987 warning ("%s %s", errstr, mach_error_string (ret));
1994 /* Return 0 on failure, number of bytes handled otherwise. */
1996 m3_xfer_memory (memaddr, myaddr, len, write, target)
2001 struct target_ops *target; /* IGNORED */
2006 result = mach3_write_inferior (memaddr, myaddr, len);
2008 result = mach3_read_inferior (memaddr, myaddr, len);
2015 translate_state(state)
2019 case TH_STATE_RUNNING: return("R");
2020 case TH_STATE_STOPPED: return("S");
2021 case TH_STATE_WAITING: return("W");
2022 case TH_STATE_UNINTERRUPTIBLE: return("U");
2023 case TH_STATE_HALTED: return("H");
2024 default: return("?");
2029 translate_cstate (state)
2034 case CPROC_RUNNING: return "R";
2035 case CPROC_SWITCHING: return "S";
2036 case CPROC_BLOCKED: return "B";
2037 case CPROC_CONDWAIT: return "C";
2038 case CPROC_CONDWAIT|CPROC_SWITCHING: return "CS";
2039 default: return "?";
2043 /* type == MACH_MSG_TYPE_COPY_SEND || type == MACH_MSG_TYPE_MAKE_SEND */
2045 mach_port_t /* no mach_port_name_t found in include files. */
2046 map_inferior_port_name (inferior_name, type)
2047 mach_port_t inferior_name;
2048 mach_msg_type_name_t type;
2051 mach_msg_type_name_t acquired;
2054 ret = mach_port_extract_right (inferior_task,
2059 CHK("mach_port_extract_right (map_inferior_port_name)", ret);
2061 if (acquired != MACH_MSG_TYPE_PORT_SEND)
2062 error("Incorrect right extracted, (map_inferior_port_name)");
2064 ret = mach_port_deallocate (mach_task_self (),
2066 CHK ("Deallocating mapped port (map_inferior_port_name)", ret);
2072 * Naming convention:
2073 * Always return user defined name if found.
2074 * _K == A kernel thread with no matching CPROC
2075 * _C == A cproc with no current cthread
2076 * _t == A cthread with no user defined name
2078 * The digits that follow the _names are the SLOT number of the
2079 * kernel thread if there is such a thing, otherwise just a negation
2080 * of the sequential number of such cprocs.
2086 get_thread_name (one_cproc, id)
2087 gdb_thread_t one_cproc;
2091 if (one_cproc->cthread == NULL)
2093 /* cproc not mapped to any cthread */
2094 sprintf(buf, "_C%d", id);
2096 else if (! one_cproc->cthread->name)
2098 /* cproc and cthread, but no name */
2099 sprintf(buf, "_t%d", id);
2102 return (one_cproc->cthread->name);
2106 warning ("Inconsistency in thread name id %d", id);
2108 /* Kernel thread without cproc */
2109 sprintf(buf, "_K%d", id);
2116 fetch_thread_info (task, mthreads_out)
2118 gdb_thread_t *mthreads_out; /* out */
2121 thread_array_t th_table;
2123 gdb_thread_t mthreads = NULL;
2126 ret = task_threads (task, &th_table, &th_count);
2127 if (ret != KERN_SUCCESS)
2129 warning ("Error getting inferior's thread list:%s",
2130 mach_error_string(ret));
2135 mthreads = (gdb_thread_t)
2138 th_count * sizeof (struct gdb_thread));
2140 for (index = 0; index < th_count; index++)
2142 thread_t saved_thread = MACH_PORT_NULL;
2145 if (must_suspend_thread)
2146 setup_thread (th_table[ index ], 1);
2148 if (th_table[index] != current_thread)
2150 saved_thread = current_thread;
2152 mid = switch_to_thread (th_table[ index ]);
2155 mthreads[index].name = th_table[index];
2156 mthreads[index].cproc = NULL; /* map_cprocs_to_kernel_threads() */
2157 mthreads[index].in_emulator = FALSE;
2158 mthreads[index].slotid = index;
2160 mthreads[index].sp = read_register (SP_REGNUM);
2161 mthreads[index].fp = read_register (FP_REGNUM);
2162 mthreads[index].pc = read_pc ();
2164 if (MACH_PORT_VALID (saved_thread))
2165 mid = switch_to_thread (saved_thread);
2167 if (must_suspend_thread)
2168 setup_thread (th_table[ index ], 0);
2171 consume_send_rights (th_table, th_count);
2172 ret = vm_deallocate (mach_task_self(), (vm_address_t)th_table,
2173 (th_count * sizeof(mach_port_t)));
2174 if (ret != KERN_SUCCESS)
2176 warning ("Error trying to deallocate thread list : %s",
2177 mach_error_string (ret));
2180 *mthreads_out = mthreads;
2187 * Current emulator always saves the USP on top of
2188 * emulator stack below struct emul_stack_top stuff.
2191 fetch_usp_from_emulator_stack (sp)
2194 CORE_ADDR stack_pointer;
2196 sp = (sp & ~(EMULATOR_STACK_SIZE-1)) +
2197 EMULATOR_STACK_SIZE - sizeof (struct emul_stack_top);
2199 if (mach3_read_inferior (sp,
2201 sizeof (CORE_ADDR)) != sizeof (CORE_ADDR))
2203 warning ("Can't read user sp from emulator stack address 0x%x", sp);
2207 return stack_pointer;
2212 /* get_emulation_vector() interface was changed after mk67 */
2213 #define EMUL_VECTOR_COUNT 400 /* Value does not matter too much */
2217 /* Check if the emulator exists at task's address space.
2220 have_emulator_p (task)
2224 #ifndef EMUL_VECTOR_COUNT
2225 vm_offset_t *emulation_vector;
2228 vm_offset_t emulation_vector[ EMUL_VECTOR_COUNT ];
2229 int n = EMUL_VECTOR_COUNT;
2234 ret = task_get_emulation_vector (task,
2236 #ifndef EMUL_VECTOR_COUNT
2242 CHK("task_get_emulation_vector", ret);
2243 xx_debug ("%d vectors from %d at 0x%08x\n",
2244 n, vector_start, emulation_vector);
2246 for(i = 0; i < n; i++)
2248 vm_offset_t entry = emulation_vector [i];
2250 if (EMULATOR_BASE <= entry && entry <= EMULATOR_END)
2254 static boolean_t informed = FALSE;
2257 warning("Emulation vector address 0x08%x outside emulator space",
2266 /* Map cprocs to kernel threads and vice versa. */
2269 map_cprocs_to_kernel_threads (cprocs, mthreads, thread_count)
2270 gdb_thread_t cprocs;
2271 gdb_thread_t mthreads;
2276 boolean_t all_mapped = TRUE;
2278 for (scan = cprocs; scan; scan = scan->next)
2280 /* Default to: no kernel thread for this cproc */
2281 scan->reverse_map = -1;
2283 /* Check if the cproc is found by its stack */
2284 for (index = 0; index < thread_count; index++)
2286 LONGEST stack_base =
2287 extract_signed_integer (scan.raw_cproc + CPROC_BASE_OFFSET,
2289 LONGEST stack_size =
2290 extract_signed_integer (scan.raw_cproc + CPROC_SIZE_OFFSET,
2292 if ((mthreads + index)->sp > stack_base &&
2293 (mthreads + index)->sp <= stack_base + stack_size)
2295 (mthreads + index)->cproc = scan;
2296 scan->reverse_map = index;
2300 all_mapped &= (scan->reverse_map != -1);
2303 /* Check for threads that are currently in the emulator.
2304 * If so, they have a different stack, and the still unmapped
2305 * cprocs may well get mapped to these threads.
2308 * - cproc stack does not match any kernel thread stack pointer
2309 * - there is at least one extra kernel thread
2310 * that has no cproc mapped above.
2311 * - some kernel thread stack pointer points to emulator space
2312 * then we find the user stack pointer saved in the emulator
2313 * stack, and try to map that to the cprocs.
2315 * Also set in_emulator for kernel threads.
2318 if (emulator_present)
2320 for (index = 0; index < thread_count; index++)
2325 gdb_thread_t mthread = (mthreads+index);
2326 emul_sp = mthread->sp;
2328 if (mthread->cproc == NULL &&
2329 EMULATOR_BASE <= emul_sp && emul_sp <= EMULATOR_END)
2331 mthread->in_emulator = emulator_present;
2333 if (!all_mapped && cprocs)
2335 usp = fetch_usp_from_emulator_stack (emul_sp);
2337 /* @@ Could be more accurate */
2339 error ("Zero stack pointer read from emulator?");
2341 /* Try to match this stack pointer to the cprocs that
2342 * don't yet have a kernel thread.
2344 for (scan = cprocs; scan; scan = scan->next)
2347 /* Check is this unmapped CPROC stack contains
2348 * the user stack pointer saved in the
2351 if (scan->reverse_map == -1 &&
2352 usp > scan->stack_base &&
2353 usp <= scan->stack_base + scan->stack_size)
2355 mthread->cproc = scan;
2356 scan->reverse_map = index;
2367 * Format of the thread_list command
2369 * slot mid sel name emul ks susp cstate wired address
2371 #define TL_FORMAT "%-2.2s %5d%c %-10.10s %1.1s%s%-5.5s %-2.2s %-5.5s "
2373 #define TL_HEADER "\n@ MID Name KState CState Where\n"
2376 print_tl_address (stream, pc)
2380 if (! lookup_minimal_symbol_by_pc (pc))
2381 fprintf_filtered (stream, local_hex_format(), pc);
2384 extern int addressprint;
2385 extern int asm_demangle;
2387 int store = addressprint;
2389 print_address_symbolic (pc, stream, asm_demangle, "");
2390 addressprint = store;
2394 /* For thread names, but also for gdb_message_port external name */
2395 #define MAX_NAME_LEN 50
2397 /* Returns the address of variable NAME or 0 if not found */
2399 lookup_address_of_variable (name)
2403 CORE_ADDR symaddr = 0;
2404 struct minimal_symbol *msymbol;
2406 sym = lookup_symbol (name,
2407 (struct block *)NULL,
2410 (struct symtab **)NULL);
2413 symaddr = SYMBOL_VALUE (sym);
2417 msymbol = lookup_minimal_symbol (name, (struct objfile *) NULL);
2419 if (msymbol && msymbol->type == mst_data)
2420 symaddr = msymbol->address;
2429 gdb_thread_t cproc_head;
2430 gdb_thread_t cproc_copy;
2431 CORE_ADDR their_cprocs;
2432 char *buf[TARGET_PTR_BIT / HOST_CHAR_BIT];
2437 symaddr = lookup_address_of_variable ("cproc_list");
2441 /* cproc_list is not in a file compiled with debugging
2442 symbols, but don't give up yet */
2444 symaddr = lookup_address_of_variable ("cprocs");
2448 static int informed = 0;
2452 warning ("Your program is loaded with an old threads library.");
2453 warning ("GDB does not know the old form of threads");
2454 warning ("so things may not work.");
2459 /* Stripped or no -lthreads loaded or "cproc_list" is in wrong segment. */
2463 /* Get the address of the first cproc in the task */
2464 if (!mach3_read_inferior (symaddr,
2466 TARGET_PTR_BIT / HOST_CHAR_BIT))
2467 error ("Can't read cproc master list at address (0x%x).", symaddr);
2468 their_cprocs = extract_address (buf, TARGET_PTR_BIT / HOST_CHAR_BIT);
2470 /* Scan the CPROCs in the task.
2471 CPROCs are chained with LIST field, not NEXT field, which
2472 chains mutexes, condition variables and queues */
2476 while (their_cprocs != (CORE_ADDR)0)
2478 CORE_ADDR cproc_copy_incarnation;
2479 cproc_copy = (gdb_thread_t) obstack_alloc (cproc_obstack,
2480 sizeof (struct gdb_thread));
2482 if (!mach3_read_inferior (their_cprocs,
2483 &cproc_copy.raw_cproc[0],
2485 error("Can't read next cproc at 0x%x.", their_cprocs);
2486 cproc_copy = extract_address (buf, TARGET_PTR_BIT / HOST_CHAR_BIT);
2489 extract_address (cproc_copy.raw_cproc + CPROC_LIST_OFFSET,
2491 cproc_copy_incarnation =
2492 extract_address (cproc_copy.raw_cproc + CPROC_INCARNATION_OFFSET,
2493 CPROC_INCARNATION_SIZE);
2495 if (cproc_copy_incarnation == (CORE_ADDR)0)
2496 cproc_copy->cthread = NULL;
2499 /* This CPROC has an attached CTHREAD. Get its name */
2500 cthread = (cthread_t)obstack_alloc (cproc_obstack,
2501 sizeof(struct cthread));
2503 if (!mach3_read_inferior (cproc_copy_incarnation,
2505 sizeof(struct cthread)))
2506 error("Can't read next thread at 0x%x.",
2507 cproc_copy_incarnation);
2509 cproc_copy->cthread = cthread;
2513 name = (char *) obstack_alloc (cproc_obstack, MAX_NAME_LEN);
2515 if (!mach3_read_inferior(cthread->name, name, MAX_NAME_LEN))
2516 error("Can't read next thread's name at 0x%x.", cthread->name);
2518 cthread->name = name;
2522 /* insert in front */
2523 cproc_copy->next = cproc_head;
2524 cproc_head = cproc_copy;
2529 #ifndef FETCH_CPROC_STATE
2531 * Check if your machine does not grok the way this routine
2532 * fetches the FP,PC and SP of a cproc that is not
2533 * currently attached to any kernel thread (e.g. its cproc.context
2534 * field points to the place in stack where the context
2537 * If it doesn't, define your own routine.
2539 #define FETCH_CPROC_STATE(mth) mach3_cproc_state (mth)
2542 mach3_cproc_state (mthread)
2543 gdb_thread_t mthread;
2547 if (! mthread || !mthread->cproc || !mthread->cproc->context)
2550 context = extract_signed_integer
2551 (mthread->cproc->raw_cproc + CPROC_CONTEXT_OFFSET,
2552 CPROC_CONTEXT_SIZE);
2554 mthread->sp = context + MACHINE_CPROC_SP_OFFSET;
2556 if (mach3_read_inferior (context + MACHINE_CPROC_PC_OFFSET,
2558 sizeof (CORE_ADDR)) != sizeof (CORE_ADDR))
2560 warning ("Can't read cproc pc from inferior");
2564 if (mach3_read_inferior (context + MACHINE_CPROC_FP_OFFSET,
2566 sizeof (CORE_ADDR)) != sizeof (CORE_ADDR))
2568 warning ("Can't read cproc fp from inferior");
2574 #endif /* FETCH_CPROC_STATE */
2578 thread_list_command()
2580 thread_basic_info_data_t ths;
2582 gdb_thread_t cprocs;
2590 mach_port_t mid_or_port;
2591 gdb_thread_t their_threads;
2592 gdb_thread_t kthread;
2596 char *fmt = "There are %d kernel threads in task %d.\n";
2598 int tmid = map_port_name_to_mid (inferior_task, MACH_TYPE_TASK);
2600 MACH_ERROR_NO_INFERIOR;
2602 thread_count = fetch_thread_info (inferior_task,
2604 if (thread_count == -1)
2607 if (thread_count == 1)
2608 fmt = "There is %d kernel thread in task %d.\n";
2610 printf_filtered (fmt, thread_count, tmid);
2612 puts_filtered (TL_HEADER);
2614 cprocs = get_cprocs();
2616 map_cprocs_to_kernel_threads (cprocs, their_threads, thread_count);
2618 for (scan = cprocs; scan; scan = scan->next)
2626 /* a wired cproc? */
2627 wired = (extract_address (scan->raw_cproc + CPROC_WIRED_OFFSET,
2631 if (scan->reverse_map != -1)
2632 kthread = (their_threads + scan->reverse_map);
2638 /* These cprocs have a kernel thread */
2640 mid = map_port_name_to_mid (kthread->name, MACH_TYPE_THREAD);
2642 infoCnt = THREAD_BASIC_INFO_COUNT;
2644 ret = thread_info (kthread->name,
2646 (thread_info_t)&ths,
2649 if (ret != KERN_SUCCESS)
2651 warning ("Unable to get basic info on thread %d : %s",
2653 mach_error_string (ret));
2657 /* Who is the first to have more than 100 threads */
2658 sprintf (slot, "%d", kthread->slotid%100);
2660 if (kthread->name == current_thread)
2663 if (ths.suspend_count)
2664 sprintf (buf, "%d", ths.suspend_count);
2669 if (ths.flags & TH_FLAGS_SWAPPED)
2673 if (ths.flags & TH_FLAGS_IDLE)
2676 /* FIXME: May run afloul of arbitrary limit in printf_filtered. */
2677 printf_filtered (TL_FORMAT,
2681 get_thread_name (scan, kthread->slotid),
2682 kthread->in_emulator ? "E" : "",
2683 translate_state (ths.run_state),
2685 translate_cstate (scan->state),
2687 print_tl_address (stdout, kthread->pc);
2691 /* These cprocs don't have a kernel thread.
2692 * find out the calling frame with
2693 * FETCH_CPROC_STATE.
2696 struct gdb_thread state;
2699 /* jtv -> emcmanus: why do you want this here? */
2700 if (scan->incarnation == NULL)
2701 continue; /* EMcM */
2704 /* FIXME: May run afloul of arbitrary limit in printf_filtered. */
2705 printf_filtered (TL_FORMAT,
2707 -neworder, /* Pseudo MID */
2709 get_thread_name (scan, -neworder),
2711 "-", /* kernel state */
2713 translate_cstate (scan->state),
2717 if (FETCH_CPROC_STATE (&state) == -1)
2718 puts_filtered ("???");
2720 print_tl_address (stdout, state.pc);
2724 puts_filtered ("\n");
2727 /* Scan for kernel threads without cprocs */
2728 for (index = 0; index < thread_count; index++)
2730 if (! their_threads[index].cproc)
2737 mach_port_t name = their_threads[index].name;
2739 mid = map_port_name_to_mid (name, MACH_TYPE_THREAD);
2741 infoCnt = THREAD_BASIC_INFO_COUNT;
2743 ret = thread_info(name,
2745 (thread_info_t)&ths,
2748 if (ret != KERN_SUCCESS)
2750 warning ("Unable to get basic info on thread %d : %s",
2752 mach_error_string (ret));
2756 sprintf (slot, "%d", index%100);
2758 if (name == current_thread)
2763 if (ths.suspend_count)
2764 sprintf (buf, "%d", ths.suspend_count);
2769 if (ths.flags & TH_FLAGS_SWAPPED)
2773 if (ths.flags & TH_FLAGS_IDLE)
2776 /* FIXME: May run afloul of arbitrary limit in printf_filtered. */
2777 printf_filtered (TL_FORMAT,
2781 get_thread_name (NULL, index),
2782 their_threads[index].in_emulator ? "E" : "",
2783 translate_state (ths.run_state),
2785 "", /* No cproc state */
2786 ""); /* Can't be wired */
2787 print_tl_address (stdout, their_threads[index].pc);
2788 puts_filtered ("\n");
2792 obstack_free (cproc_obstack, 0);
2793 obstack_init (cproc_obstack);
2797 thread_select_command(args, from_tty)
2802 thread_array_t thread_list;
2807 MACH_ERROR_NO_INFERIOR;
2810 error_no_arg ("MID or @SLOTNUMBER to specify a thread to select");
2812 while (*args == ' ' || *args == '\t')
2824 if (!is_slot || *args != '0') /* Rudimentary checks */
2825 error ("You must select threads by MID or @SLOTNUMBER");
2827 if (select_thread (inferior_task, mid, is_slot?2:1) != KERN_SUCCESS)
2831 printf_filtered ("Thread %d selected\n",
2832 is_slot ? map_port_name_to_mid (current_thread,
2833 MACH_TYPE_THREAD) : mid);
2836 thread_trace (thread, set)
2840 int flavor = TRACE_FLAVOR;
2841 unsigned int stateCnt = TRACE_FLAVOR_SIZE;
2843 thread_state_data_t state;
2845 if (! MACH_PORT_VALID (thread))
2847 warning ("thread_trace: invalid thread");
2851 if (must_suspend_thread)
2852 setup_thread (thread, 1);
2854 ret = thread_get_state(thread, flavor, state, &stateCnt);
2855 CHK ("thread_trace: error reading thread state", ret);
2859 TRACE_SET (thread, state);
2863 if (! TRACE_CLEAR (thread, state))
2865 if (must_suspend_thread)
2866 setup_thread (thread, 0);
2871 ret = thread_set_state(thread, flavor, state, stateCnt);
2872 CHK ("thread_trace: error writing thread state", ret);
2873 if (must_suspend_thread)
2874 setup_thread (thread, 0);
2877 #ifdef FLUSH_INFERIOR_CACHE
2879 /* When over-writing code on some machines the I-Cache must be flushed
2880 explicitly, because it is not kept coherent by the lazy hardware.
2881 This definitely includes breakpoints, for instance, or else we
2882 end up looping in mysterious Bpt traps */
2884 flush_inferior_icache(pc, amount)
2887 vm_machine_attribute_val_t flush = MATTR_VAL_ICACHE_FLUSH;
2890 ret = vm_machine_attribute (inferior_task,
2895 if (ret != KERN_SUCCESS)
2896 warning ("Error flushing inferior's cache : %s",
2897 mach_error_string (ret));
2899 #endif FLUSH_INFERIOR_CACHE
2903 suspend_all_threads (from_tty)
2907 thread_array_t thread_list;
2908 int thread_count, index;
2910 thread_basic_info_data_t th_info;
2913 ret = task_threads (inferior_task, &thread_list, &thread_count);
2914 if (ret != KERN_SUCCESS)
2916 warning ("Could not suspend inferior threads.");
2918 return_to_top_level ();
2921 for (index = 0; index < thread_count; index++)
2925 mid = map_port_name_to_mid (thread_list[ index ],
2928 ret = thread_suspend(thread_list[ index ]);
2930 if (ret != KERN_SUCCESS)
2931 warning ("Error trying to suspend thread %d : %s",
2932 mid, mach_error_string (ret));
2936 infoCnt = THREAD_BASIC_INFO_COUNT;
2937 ret = thread_info (thread_list[ index ],
2939 (thread_info_t) &th_info,
2941 CHK ("suspend can't get thread info", ret);
2943 warning ("Thread %d suspend count is %d",
2944 mid, th_info.suspend_count);
2948 consume_send_rights (thread_list, thread_count);
2949 ret = vm_deallocate(mach_task_self(),
2950 (vm_address_t)thread_list,
2951 (thread_count * sizeof(int)));
2952 CHK ("Error trying to deallocate thread list", ret);
2956 thread_suspend_command (args, from_tty)
2962 mach_port_t saved_thread;
2964 thread_basic_info_data_t th_info;
2966 MACH_ERROR_NO_INFERIOR;
2968 if (!strcasecmp (args, "all")) {
2969 suspend_all_threads (from_tty);
2973 saved_thread = current_thread;
2975 mid = parse_thread_id (args, 0, 0);
2978 error ("You can suspend only existing kernel threads with MID or @SLOTNUMBER");
2981 mid = map_port_name_to_mid (current_thread, MACH_TYPE_THREAD);
2983 if (select_thread (inferior_task, mid, 0) != KERN_SUCCESS)
2986 current_thread = saved_thread;
2987 error ("Could not select thread %d", mid);
2990 ret = thread_suspend (current_thread);
2991 if (ret != KERN_SUCCESS)
2992 warning ("thread_suspend failed : %s",
2993 mach_error_string (ret));
2995 infoCnt = THREAD_BASIC_INFO_COUNT;
2996 ret = thread_info (current_thread,
2998 (thread_info_t) &th_info,
3000 CHK ("suspend can't get thread info", ret);
3002 warning ("Thread %d suspend count is %d", mid, th_info.suspend_count);
3004 current_thread = saved_thread;
3007 resume_all_threads (from_tty)
3011 thread_array_t thread_list;
3012 int thread_count, index;
3015 thread_basic_info_data_t th_info;
3017 ret = task_threads (inferior_task, &thread_list, &thread_count);
3018 if (ret != KERN_SUCCESS)
3021 error("task_threads", mach_error_string( ret));
3024 for (index = 0; index < thread_count; index++)
3026 infoCnt = THREAD_BASIC_INFO_COUNT;
3027 ret = thread_info (thread_list [ index ],
3029 (thread_info_t) &th_info,
3031 CHK ("resume_all can't get thread info", ret);
3033 mid = map_port_name_to_mid (thread_list[ index ],
3036 if (! th_info.suspend_count)
3038 if (mid != -1 && from_tty)
3039 warning ("Thread %d is not suspended", mid);
3043 ret = thread_resume (thread_list[ index ]);
3045 if (ret != KERN_SUCCESS)
3046 warning ("Error trying to resume thread %d : %s",
3047 mid, mach_error_string (ret));
3048 else if (mid != -1 && from_tty)
3049 warning ("Thread %d suspend count is %d",
3050 mid, --th_info.suspend_count);
3053 consume_send_rights (thread_list, thread_count);
3054 ret = vm_deallocate(mach_task_self(),
3055 (vm_address_t)thread_list,
3056 (thread_count * sizeof(int)));
3057 CHK("Error trying to deallocate thread list", ret);
3061 thread_resume_command (args, from_tty)
3066 mach_port_t saved_thread;
3068 thread_basic_info_data_t th_info;
3069 int infoCnt = THREAD_BASIC_INFO_COUNT;
3071 MACH_ERROR_NO_INFERIOR;
3073 if (!strcasecmp (args, "all")) {
3074 resume_all_threads (from_tty);
3078 saved_thread = current_thread;
3080 mid = parse_thread_id (args, 0, 0);
3083 error ("You can resume only existing kernel threads with MID or @SLOTNUMBER");
3086 mid = map_port_name_to_mid (current_thread, MACH_TYPE_THREAD);
3088 if (select_thread (inferior_task, mid, 0) != KERN_SUCCESS)
3091 current_thread = saved_thread;
3092 return_to_top_level ();
3095 ret = thread_info (current_thread,
3097 (thread_info_t) &th_info,
3099 CHK ("resume can't get thread info", ret);
3101 if (! th_info.suspend_count)
3103 warning ("Thread %d is not suspended", mid);
3107 ret = thread_resume (current_thread);
3108 if (ret != KERN_SUCCESS)
3109 warning ("thread_resume failed : %s",
3110 mach_error_string (ret));
3113 th_info.suspend_count--;
3114 warning ("Thread %d suspend count is %d", mid, th_info.suspend_count);
3118 current_thread = saved_thread;
3122 thread_kill_command (args, from_tty)
3129 thread_array_t thread_table;
3131 mach_port_t thread_to_kill = MACH_PORT_NULL;
3134 MACH_ERROR_NO_INFERIOR;
3137 error_no_arg ("thread mid to kill from the inferior task");
3139 mid = parse_thread_id (args, 0, 0);
3142 error ("You can kill only existing kernel threads with MID or @SLOTNUMBER");
3146 ret = machid_mach_port (mid_server, mid_auth, mid, &thread_to_kill);
3147 CHK ("thread_kill_command: machid_mach_port map failed", ret);
3150 mid = map_port_name_to_mid (current_thread, MACH_TYPE_THREAD);
3152 /* Don't allow gdb to kill *any* thread in the system. Use mkill program for that */
3153 ret = task_threads (inferior_task, &thread_table, &thread_count);
3154 CHK ("Error getting inferior's thread list", ret);
3156 if (thread_to_kill == current_thread)
3158 ret = thread_terminate (thread_to_kill);
3159 CHK ("Thread could not be terminated", ret);
3161 if (select_thread (inferior_task, 0, 1) != KERN_SUCCESS)
3162 warning ("Last thread was killed, use \"kill\" command to kill task");
3165 for (index = 0; index < thread_count; index++)
3166 if (thread_table [ index ] == thread_to_kill)
3168 ret = thread_terminate (thread_to_kill);
3169 CHK ("Thread could not be terminated", ret);
3172 if (thread_count > 1)
3173 consume_send_rights (thread_table, thread_count);
3175 ret = vm_deallocate (mach_task_self(), (vm_address_t)thread_table,
3176 (thread_count * sizeof(mach_port_t)));
3177 CHK ("Error trying to deallocate thread list", ret);
3179 warning ("Thread %d killed", mid);
3183 /* Task specific commands; add more if you like */
3186 task_resume_command (args, from_tty)
3191 task_basic_info_data_t ta_info;
3192 int infoCnt = TASK_BASIC_INFO_COUNT;
3193 int mid = map_port_name_to_mid (inferior_task, MACH_TYPE_TASK);
3195 MACH_ERROR_NO_INFERIOR;
3197 /* Would be trivial to change, but is it desirable? */
3199 error ("Currently gdb can resume only it's inferior task");
3201 ret = task_info (inferior_task,
3203 (task_info_t) &ta_info,
3205 CHK ("task_resume_command: task_info failed", ret);
3207 if (ta_info.suspend_count == 0)
3208 error ("Inferior task %d is not suspended", mid);
3209 else if (ta_info.suspend_count == 1 &&
3211 !query ("Suspend count is now 1. Do you know what you are doing? "))
3212 error ("Task not resumed");
3214 ret = task_resume (inferior_task);
3215 CHK ("task_resume_command: task_resume", ret);
3217 if (ta_info.suspend_count == 1)
3219 warning ("Inferior task %d is no longer suspended", mid);
3220 must_suspend_thread = 1;
3221 /* @@ This is not complete: Registers change all the time when not
3223 registers_changed ();
3226 warning ("Inferior task %d suspend count is now %d",
3227 mid, ta_info.suspend_count-1);
3232 task_suspend_command (args, from_tty)
3237 task_basic_info_data_t ta_info;
3238 int infoCnt = TASK_BASIC_INFO_COUNT;
3239 int mid = map_port_name_to_mid (inferior_task, MACH_TYPE_TASK);
3241 MACH_ERROR_NO_INFERIOR;
3243 /* Would be trivial to change, but is it desirable? */
3245 error ("Currently gdb can suspend only it's inferior task");
3247 ret = task_suspend (inferior_task);
3248 CHK ("task_suspend_command: task_suspend", ret);
3250 must_suspend_thread = 0;
3252 ret = task_info (inferior_task,
3254 (task_info_t) &ta_info,
3256 CHK ("task_suspend_command: task_info failed", ret);
3258 warning ("Inferior task %d suspend count is now %d",
3259 mid, ta_info.suspend_count);
3266 static char size [ 30 ];
3267 int zz = bytes/1024;
3270 sprintf (size, "%-2.1f M", ((float)bytes)/(1024.0*1024.0));
3272 sprintf (size, "%d K", zz);
3277 /* Does this require the target task to be suspended?? I don't think so. */
3279 task_info_command (args, from_tty)
3286 task_basic_info_data_t ta_info;
3287 int infoCnt = TASK_BASIC_INFO_COUNT;
3288 int page_size = round_page(1);
3289 int thread_count = 0;
3291 if (MACH_PORT_VALID (inferior_task))
3292 mid = map_port_name_to_mid (inferior_task,
3295 task = inferior_task;
3299 int tmid = atoi (args);
3302 error ("Invalid mid %d for task info", tmid);
3307 ret = machid_mach_port (mid_server, mid_auth, tmid, &task);
3308 CHK ("task_info_command: machid_mach_port map failed", ret);
3313 error ("You have to give the task MID as an argument");
3315 ret = task_info (task,
3317 (task_info_t) &ta_info,
3319 CHK ("task_info_command: task_info failed", ret);
3321 printf_filtered ("\nTask info for task %d:\n\n", mid);
3322 printf_filtered (" Suspend count : %d\n", ta_info.suspend_count);
3323 printf_filtered (" Base priority : %d\n", ta_info.base_priority);
3324 printf_filtered (" Virtual size : %s\n", get_size (ta_info.virtual_size));
3325 printf_filtered (" Resident size : %s\n", get_size (ta_info.resident_size));
3328 thread_array_t thread_list;
3330 ret = task_threads (task, &thread_list, &thread_count);
3331 CHK ("task_info_command: task_threads", ret);
3333 printf_filtered (" Thread count : %d\n", thread_count);
3335 consume_send_rights (thread_list, thread_count);
3336 ret = vm_deallocate(mach_task_self(),
3337 (vm_address_t)thread_list,
3338 (thread_count * sizeof(int)));
3339 CHK("Error trying to deallocate thread list", ret);
3341 if (have_emulator_p (task))
3342 printf_filtered (" Emulator at : 0x%x..0x%x\n",
3343 EMULATOR_BASE, EMULATOR_END);
3345 printf_filtered (" No emulator.\n");
3347 if (thread_count && task == inferior_task)
3348 printf_filtered ("\nUse the \"thread list\" command to see the threads\n");
3351 /* You may either FORWARD the exception to the inferior, or KEEP
3352 * it and return to GDB command level.
3354 * exception mid [ forward | keep ]
3358 exception_command (args, from_tty)
3367 error_no_arg ("exception number action");
3369 while (*scan == ' ' || *scan == '\t') scan++;
3371 if ('0' <= *scan && *scan <= '9')
3372 while ('0' <= *scan && *scan <= '9')
3375 error ("exception number action");
3377 exception = atoi (args);
3378 if (exception <= 0 || exception > MAX_EXCEPTION)
3379 error ("Allowed exception numbers are in range 1..%d",
3382 if (*scan != ' ' && *scan != '\t')
3383 error ("exception number must be followed by a space");
3385 while (*scan == ' ' || *scan == '\t') scan++;
3396 error("exception number action");
3398 if (!strncasecmp (args, "forward", len))
3399 exception_map[ exception ].forward = TRUE;
3400 else if (!strncasecmp (args, "keep", len))
3401 exception_map[ exception ].forward = FALSE;
3403 error ("exception action is either \"keep\" or \"forward\"");
3407 print_exception_info (exception)
3410 boolean_t forward = exception_map[ exception ].forward;
3412 printf_filtered ("%s\t(%d): ", exception_map[ exception ].name,
3415 if (exception_map[ exception ].sigmap != SIG_UNKNOWN)
3416 printf_filtered ("keep and handle as signal %d\n",
3417 exception_map[ exception ].sigmap);
3419 printf_filtered ("keep and handle as unknown signal %d\n",
3420 exception_map[ exception ].sigmap);
3422 printf_filtered ("forward exception to inferior\n");
3426 exception_info (args, from_tty)
3433 for (exception = 1; exception <= MAX_EXCEPTION; exception++)
3434 print_exception_info (exception);
3437 exception = atoi (args);
3439 if (exception <= 0 || exception > MAX_EXCEPTION)
3440 error ("Invalid exception number, values from 1 to %d allowed",
3442 print_exception_info (exception);
3446 /* Check for actions for mach exceptions.
3448 mach3_exception_actions (w, force_print_only, who)
3450 boolean_t force_print_only;
3453 boolean_t force_print = FALSE;
3456 if (force_print_only ||
3457 exception_map[stop_exception].sigmap == SIG_UNKNOWN)
3460 WSETSTOP (*w, exception_map[stop_exception].sigmap);
3462 if (exception_map[stop_exception].print || force_print)
3464 int giveback = grab_terminal ();
3466 printf_filtered ("\n%s received %s exception : ",
3468 exception_map[stop_exception].name);
3472 switch(stop_exception) {
3473 case EXC_BAD_ACCESS:
3474 printf_filtered ("referencing address 0x%x : %s\n",
3476 mach_error_string (stop_code));
3478 case EXC_BAD_INSTRUCTION:
3480 ("illegal or undefined instruction. code %d subcode %d\n",
3481 stop_code, stop_subcode);
3483 case EXC_ARITHMETIC:
3484 printf_filtered ("code %d\n", stop_code);
3487 printf_filtered ("code %d subcode %d\n", stop_code, stop_subcode);
3490 printf_filtered ("%s specific, code 0x%x\n",
3491 stop_code < 0xffff ? "hardware" : "os emulation",
3494 case EXC_BREAKPOINT:
3495 printf_filtered ("type %d (machine dependent)\n",
3499 fatal ("Unknown exception");
3503 terminal_inferior ();
3507 setup_notify_port (create_new)
3512 if (MACH_PORT_VALID (our_notify_port))
3514 ret = mach_port_destroy (mach_task_self (), our_notify_port);
3515 CHK ("Could not destroy our_notify_port", ret);
3518 our_notify_port = MACH_PORT_NULL;
3519 notify_chain = (port_chain_t) NULL;
3520 port_chain_destroy (port_chain_obstack);
3524 ret = mach_port_allocate (mach_task_self(),
3525 MACH_PORT_RIGHT_RECEIVE,
3527 if (ret != KERN_SUCCESS)
3528 fatal("Creating notify port %s", mach_error_string(ret));
3530 ret = mach_port_move_member(mach_task_self(),
3532 inferior_wait_port_set);
3533 if (ret != KERN_SUCCESS)
3534 fatal("initial move member %s",mach_error_string(ret));
3539 * Register our message port to the net name server
3541 * Currently used only by the external stop-gdb program
3542 * since ^C does not work if you would like to enter
3543 * gdb command level while debugging your program.
3545 * NOTE: If the message port is sometimes used for other
3546 * purposes also, the NAME must not be a guessable one.
3547 * Then, there should be a way to change it.
3550 char registered_name[ MAX_NAME_LEN ];
3553 message_port_info (args, from_tty)
3557 if (registered_name[0])
3558 printf_filtered ("gdb's message port name: '%s'\n",
3561 printf_filtered ("gdb's message port is not currently registered\n");
3565 gdb_register_port (name, port)
3570 static int already_signed = 0;
3573 if (! MACH_PORT_VALID (port) || !name || !*name)
3575 warning ("Invalid registration request");
3579 if (! already_signed)
3581 ret = mach_port_insert_right (mach_task_self (),
3584 MACH_MSG_TYPE_MAKE_SEND);
3585 CHK ("Failed to create a signature to our_message_port", ret);
3588 else if (already_signed > 1)
3590 ret = netname_check_out (name_server_port,
3593 CHK ("Failed to check out gdb's message port", ret);
3594 registered_name[0] = '\000';
3598 ret = netname_check_in (name_server_port, /* Name server port */
3599 name, /* Name of service */
3600 our_message_port, /* Signature */
3601 port); /* Creates a new send right */
3602 CHK("Failed to check in the port", ret);
3605 while(len < MAX_NAME_LEN && *(name+len))
3607 registered_name[len] = *(name+len);
3610 registered_name[len] = '\000';
3614 struct cmd_list_element *cmd_thread_list;
3615 struct cmd_list_element *cmd_task_list;
3619 thread_command (arg, from_tty)
3623 printf ("\"thread\" must be followed by the name of a thread command.\n");
3624 help_list (cmd_thread_list, "thread ", -1, stdout);
3629 task_command (arg, from_tty)
3633 printf ("\"task\" must be followed by the name of a task command.\n");
3634 help_list (cmd_task_list, "task ", -1, stdout);
3637 add_mach_specific_commands ()
3639 extern void condition_thread ();
3641 /* Thread handling commands */
3643 /* FIXME: Move our thread support into the generic thread.c stuff so we
3644 can share that code. */
3645 add_prefix_cmd ("mthread", class_stack, thread_command,
3646 "Generic command for handling Mach threads in the debugged task.",
3647 &cmd_thread_list, "thread ", 0, &cmdlist);
3649 add_com_alias ("th", "mthread", class_stack, 1);
3651 add_cmd ("select", class_stack, thread_select_command,
3652 "Select and print MID of the selected thread",
3654 add_cmd ("list", class_stack, thread_list_command,
3655 "List info of task's threads. Selected thread is marked with '*'",
3657 add_cmd ("suspend", class_run, thread_suspend_command,
3658 "Suspend one or all of the threads in the selected task.",
3660 add_cmd ("resume", class_run, thread_resume_command,
3661 "Resume one or all of the threads in the selected task.",
3663 add_cmd ("kill", class_run, thread_kill_command,
3664 "Kill the specified thread MID from inferior task.",
3666 add_cmd ("break", class_breakpoint, condition_thread,
3667 "Breakpoint N will only be effective for thread MID or @SLOT\n\
3668 If MID/@SLOT is omitted allow all threads to break at breakpoint",
3670 /* Thread command shorthands (for backward compatibility) */
3671 add_alias_cmd ("ts", "mthread select", 0, 0, &cmdlist);
3672 add_alias_cmd ("tl", "mthread list", 0, 0, &cmdlist);
3674 /* task handling commands */
3676 add_prefix_cmd ("task", class_stack, task_command,
3677 "Generic command for handling debugged task.",
3678 &cmd_task_list, "task ", 0, &cmdlist);
3680 add_com_alias ("ta", "task", class_stack, 1);
3682 add_cmd ("suspend", class_run, task_suspend_command,
3683 "Suspend the inferior task.",
3685 add_cmd ("resume", class_run, task_resume_command,
3686 "Resume the inferior task.",
3688 add_cmd ("info", no_class, task_info_command,
3689 "Print information about the specified task.",
3692 /* Print my message port name */
3694 add_info ("message-port", message_port_info,
3695 "Returns the name of gdb's message port in the netnameserver");
3697 /* Exception commands */
3699 add_info ("exceptions", exception_info,
3700 "What debugger does when program gets various exceptions.\n\
3701 Specify an exception number as argument to print info on that\n\
3704 add_com ("exception", class_run, exception_command,
3705 "Specify how to handle an exception.\n\
3706 Args are exception number followed by \"forward\" or \"keep\".\n\
3707 `Forward' means forward the exception to the program's normal exception\n\
3709 `Keep' means reenter debugger if this exception happens, and GDB maps\n\
3710 the exception to some signal (see info exception)\n\
3711 Normally \"keep\" is used to return to GDB on exception.");
3715 do_mach_notify_dead_name (notify, name)
3719 kern_return_t kr = KERN_SUCCESS;
3721 /* Find the thing that notified */
3722 port_chain_t element = port_chain_member (notify_chain, name);
3724 /* Take name of from unreceived dead name notification list */
3725 notify_chain = port_chain_delete (notify_chain, name);
3728 error ("Received a dead name notify from unchained port (0x%x)", name);
3730 switch (element->type) {
3732 case MACH_TYPE_THREAD:
3733 target_terminal_ours_for_output ();
3734 if (name == current_thread)
3736 printf_filtered ("\nCurrent thread %d died", element->mid);
3737 current_thread = MACH_PORT_NULL;
3740 printf_filtered ("\nThread %d died", element->mid);
3744 case MACH_TYPE_TASK:
3745 target_terminal_ours_for_output ();
3746 if (name != inferior_task)
3747 printf_filtered ("Task %d died, but it was not the selected task",
3751 printf_filtered ("Current task %d died", element->mid);
3753 mach_port_destroy (mach_task_self(), name);
3754 inferior_task = MACH_PORT_NULL;
3757 warning ("There were still unreceived dead_name_notifications???");
3759 /* Destroy the old notifications */
3760 setup_notify_port (0);
3766 error ("Unregistered dead_name 0x%x notification received. Type is %d, mid is 0x%x",
3767 name, element->type, element->mid);
3771 return KERN_SUCCESS;
3775 do_mach_notify_msg_accepted (notify, name)
3779 warning ("do_mach_notify_msg_accepted : notify %x, name %x",
3781 return KERN_SUCCESS;
3785 do_mach_notify_no_senders (notify, mscount)
3787 mach_port_mscount_t mscount;
3789 warning ("do_mach_notify_no_senders : notify %x, mscount %x",
3791 return KERN_SUCCESS;
3795 do_mach_notify_port_deleted (notify, name)
3799 warning ("do_mach_notify_port_deleted : notify %x, name %x",
3801 return KERN_SUCCESS;
3805 do_mach_notify_port_destroyed (notify, rights)
3809 warning ("do_mach_notify_port_destroyed : notify %x, rights %x",
3811 return KERN_SUCCESS;
3815 do_mach_notify_send_once (notify)
3819 /* MANY of these are generated. */
3820 warning ("do_mach_notify_send_once : notify %x",
3823 return KERN_SUCCESS;
3826 /* Kills the inferior. It's gone when you call this */
3828 kill_inferior_fast ()
3832 if (inferior_pid == 0 || inferior_pid == 1)
3835 /* kill() it, since the Unix server does not otherwise notice when
3836 * killed with task_terminate().
3838 if (inferior_pid > 0)
3839 kill (inferior_pid, SIGKILL);
3841 /* It's propably terminate already */
3842 (void) task_terminate (inferior_task);
3844 inferior_task = MACH_PORT_NULL;
3845 current_thread = MACH_PORT_NULL;
3847 wait3 (&w, WNOHANG, 0);
3849 setup_notify_port (0);
3855 kill_inferior_fast ();
3856 target_mourn_inferior ();
3859 /* Clean up after the inferior dies. */
3862 m3_mourn_inferior ()
3864 unpush_target (&m3_ops);
3865 generic_mourn_inferior ();
3869 /* Fork an inferior process, and start debugging it. */
3872 m3_create_inferior (exec_file, allargs, env)
3877 fork_inferior (exec_file, allargs, env, m3_trace_m3, m3_trace_him);
3878 /* We are at the first instruction we care about. */
3879 /* Pedal to the metal... */
3880 proceed ((CORE_ADDR) -1, 0, 0);
3883 /* Mark our target-struct as eligible for stray "run" and "attach"
3891 /* Mach 3.0 does not need ptrace for anything
3892 * Make sure nobody uses it on mach.
3897 error ("Lose, Lose! Somebody called ptrace\n");
3900 /* Resume execution of the inferior process.
3901 If STEP is nonzero, single-step it.
3902 If SIGNAL is nonzero, give it that signal. */
3905 m3_resume (pid, step, signal)
3914 thread_basic_info_data_t th_info;
3915 unsigned int infoCnt = THREAD_BASIC_INFO_COUNT;
3917 /* There is no point in single stepping when current_thread
3920 if (! MACH_PORT_VALID (current_thread))
3921 error ("No thread selected; can not single step");
3923 /* If current_thread is suspended, tracing it would never return.
3925 ret = thread_info (current_thread,
3927 (thread_info_t) &th_info,
3929 CHK ("child_resume: can't get thread info", ret);
3931 if (th_info.suspend_count)
3932 error ("Can't trace a suspended thread. Use \"thread resume\" command to resume it");
3935 vm_read_cache_valid = FALSE;
3937 if (signal && inferior_pid > 0) /* Do not signal, if attached by MID */
3938 kill (inferior_pid, signal);
3942 suspend_all_threads (0);
3944 setup_single_step (current_thread, TRUE);
3946 ret = thread_resume (current_thread);
3947 CHK ("thread_resume", ret);
3950 ret = task_resume (inferior_task);
3951 if (ret == KERN_FAILURE)
3952 warning ("Task was not suspended");
3954 CHK ("Resuming task", ret);
3956 /* HACK HACK This is needed by the multiserver system HACK HACK */
3957 while ((ret = task_resume(inferior_task)) == KERN_SUCCESS)
3958 /* make sure it really runs */;
3959 /* HACK HACK This is needed by the multiserver system HACK HACK */
3962 #ifdef ATTACH_DETACH
3964 /* Start debugging the process with the given task */
3970 inferior_task = tid;
3972 ret = task_suspend (inferior_task);
3973 CHK("task_attach: task_suspend", ret);
3975 must_suspend_thread = 0;
3977 setup_notify_port (1);
3979 request_notify (inferior_task, MACH_NOTIFY_DEAD_NAME, MACH_TYPE_TASK);
3981 setup_exception_port ();
3983 emulator_present = have_emulator_p (inferior_task);
3988 /* Well, we can call error also here and leave the
3989 * target stack inconsistent. Sigh.
3990 * Fix this sometime (the only way to fail here is that
3991 * the task has no threads at all, which is rare, but
3992 * possible; or if the target task has died, which is also
3993 * possible, but unlikely, since it has been suspended.
3994 * (Someone must have killed it))
3999 if (select_thread (inferior_task, 0, 1) != KERN_SUCCESS)
4000 error ("Could not select any threads to attach to");
4008 ret = machid_mach_port (mid_server, mid_auth, mid, &inferior_task);
4009 CHK("mid_attach: machid_mach_port", ret);
4011 task_attach (inferior_task);
4017 * Start debugging the process whose unix process-id is PID.
4018 * A negative "pid" value is legal and signifies a mach_id not a unix pid.
4020 * Prevent (possible unwanted) dangerous operations by enabled users
4021 * like "atta 0" or "atta foo" (equal to the previous :-) and
4022 * "atta pidself". Anyway, the latter is allowed by specifying a MID.
4031 error("MID=0, Debugging the master unix server does not compute");
4033 /* Foo. This assumes gdb has a unix pid */
4034 if (pid == getpid())
4035 error ("I will debug myself only by mid. (Gdb would suspend itself!)");
4039 mid_attach (-(pid));
4041 /* inferior_pid will be NEGATIVE! */
4044 return inferior_pid;
4047 inferior_task = task_by_pid (pid);
4048 if (! MACH_PORT_VALID (inferior_task))
4049 error("Cannot map Unix pid %d to Mach task port", pid);
4051 task_attach (inferior_task);
4055 return inferior_pid;
4058 /* Attach to process PID, then initialize for debugging it
4059 and wait for the trace-trap that results from attaching. */
4062 m3_attach (args, from_tty)
4070 error_no_arg ("process-id to attach");
4074 if (pid == getpid()) /* Trying to masturbate? */
4075 error ("I refuse to debug myself!");
4079 exec_file = (char *) get_exec_file (0);
4082 printf ("Attaching to program `%s', %s\n", exec_file, target_pid_to_str (pid));
4084 printf ("Attaching to %s\n", target_pid_to_str (pid));
4091 push_target (&procfs_ops);
4095 deallocate_inferior_ports ()
4098 thread_array_t thread_list;
4099 int thread_count, index;
4101 if (!MACH_PORT_VALID (inferior_task))
4104 ret = task_threads (inferior_task, &thread_list, &thread_count);
4105 if (ret != KERN_SUCCESS)
4107 warning ("deallocate_inferior_ports: task_threads",
4108 mach_error_string(ret));
4112 /* Get rid of send rights to task threads */
4113 for (index = 0; index < thread_count; index++)
4116 ret = mach_port_get_refs (mach_task_self (),
4118 MACH_PORT_RIGHT_SEND,
4120 CHK("deallocate_inferior_ports: get refs", ret);
4124 ret = mach_port_mod_refs (mach_task_self (),
4126 MACH_PORT_RIGHT_SEND,
4128 CHK("deallocate_inferior_ports: mod refs", ret);
4132 ret = mach_port_mod_refs (mach_task_self (),
4133 inferior_exception_port,
4134 MACH_PORT_RIGHT_RECEIVE,
4136 CHK ("deallocate_inferior_ports: cannot get rid of exception port", ret);
4138 ret = mach_port_deallocate (mach_task_self (),
4140 CHK ("deallocate_task_port: deallocating inferior_task", ret);
4142 current_thread = MACH_PORT_NULL;
4143 inferior_task = MACH_PORT_NULL;
4146 /* Stop debugging the process whose number is PID
4147 and continue it with signal number SIGNAL.
4148 SIGNAL = 0 means just continue it. */
4151 m3_do_detach (signal)
4156 MACH_ERROR_NO_INFERIOR;
4158 if (current_thread != MACH_PORT_NULL)
4160 /* Store the gdb's view of the thread we are deselecting
4162 * @@ I am really not sure if this is ever needeed.
4164 target_prepare_to_store ();
4165 target_store_registers (-1);
4168 ret = task_set_special_port (inferior_task,
4169 TASK_EXCEPTION_PORT,
4170 inferior_old_exception_port);
4171 CHK ("task_set_special_port", ret);
4173 /* Discard all requested notifications */
4174 setup_notify_port (0);
4176 if (remove_breakpoints ())
4177 warning ("Could not remove breakpoints when detaching");
4179 if (signal && inferior_pid > 0)
4180 kill (inferior_pid, signal);
4182 /* the task might be dead by now */
4183 (void) task_resume (inferior_task);
4185 deallocate_inferior_ports ();
4190 /* Take a program previously attached to and detaches it.
4191 The program resumes execution and will no longer stop
4192 on signals, etc. We'd better not have left any breakpoints
4193 in the program or it'll die when it hits one. For this
4194 to work, it may be necessary for the process to have been
4195 previously attached. It *might* work if the program was
4196 started via fork. */
4199 m3_detach (args, from_tty)
4207 char *exec_file = get_exec_file (0);
4210 printf ("Detaching from program: %s %s\n",
4211 exec_file, target_pid_to_str (inferior_pid));
4215 siggnal = atoi (args);
4217 m3_do_detach (siggnal);
4219 unpush_target (&m3_ops); /* Pop out of handling an inferior */
4221 #endif /* ATTACH_DETACH */
4230 char *bsd1_names[] = {
4298 int bsd1_nnames = sizeof(bsd1_names)/sizeof(bsd1_names[0]);
4308 case MACH_MSG_TYPE_BOOLEAN:
4310 case MACH_MSG_TYPE_INTEGER_16:
4312 case MACH_MSG_TYPE_INTEGER_32:
4314 case MACH_MSG_TYPE_CHAR:
4316 case MACH_MSG_TYPE_BYTE:
4318 case MACH_MSG_TYPE_REAL:
4320 case MACH_MSG_TYPE_STRING:
4323 sprintf(buf,"%d",name);
4336 if (id >= 101000 && id < 101000+bsd1_nnames) {
4337 if (p = bsd1_names[id-101000])
4341 return "psignal_retry";
4344 sprintf(buf,"%d",id);
4349 mach_msg_header_t *mp;
4351 char *fmt_x = "%20s : 0x%08x\n";
4352 char *fmt_d = "%20s : %10d\n";
4353 char *fmt_s = "%20s : %s\n";
4356 puts_filtered ("\n");
4357 #define pr(fmt,h,x) printf_filtered(fmt,STR(x),(h).x)
4358 pr(fmt_x,(*mp),msgh_bits);
4359 pr(fmt_d,(*mp),msgh_size);
4360 pr(fmt_x,(*mp),msgh_remote_port);
4361 pr(fmt_x,(*mp),msgh_local_port);
4362 pr(fmt_d,(*mp),msgh_kind);
4363 printf_filtered(fmt_s,STR(msgh_id),id_str(mp->msgh_id,buf));
4365 if (debug_level > 1)
4370 ep = p+mp->msgh_size;
4372 for(; p < ep; p += plen) {
4373 mach_msg_type_t *tp;
4374 mach_msg_type_long_t *tlp;
4375 int name,size,number;
4376 tp = (mach_msg_type_t*)p;
4377 if (tp->msgt_longform) {
4378 tlp = (mach_msg_type_long_t*)tp;
4379 name = tlp->msgtl_name;
4380 size = tlp->msgtl_size;
4381 number = tlp->msgtl_number;
4382 plen = sizeof(*tlp);
4384 name = tp->msgt_name;
4385 size = tp->msgt_size;
4386 number = tp->msgt_number;
4389 printf_filtered("name=%-16s size=%2d number=%7d inline=%d long=%d deal=%d\n",
4390 name_str(name,buf),size,number,tp->msgt_inline,
4391 tp->msgt_longform, tp->msgt_deallocate);
4393 if (tp->msgt_inline) {
4396 l = (l+sizeof(long)-1)&~((sizeof(long))-1);
4398 print_data(dp,size,number);
4400 plen += sizeof(int*);
4402 printf_filtered("plen=%d\n",plen);
4407 print_data(p,size,number)
4418 for(i = 0; i < number; i++) {
4419 printf_filtered(" %02x",p[i]);
4424 for(i = 0; i < number; i++) {
4425 printf_filtered(" %04x",sp[i]);
4430 for(i = 0; i < number; i++) {
4431 printf_filtered(" %08x",ip[i]);
4435 puts_filtered("\n");
4439 struct target_ops m3_ops = {
4440 "mach", /* to_shortname */
4441 "Mach child process", /* to_longname */
4442 "Mach child process (started by the \"run\" command).", /* to_doc */
4443 ??_open, /* to_open */
4445 m3_attach, /* to_attach */
4446 m3_detach, /* to_detach */
4447 m3_resume, /* to_resume */
4448 mach_really_wait, /* to_wait */
4449 fetch_inferior_registers, /* to_fetch_registers */
4450 store_inferior_registers, /* to_store_registers */
4451 child_prepare_to_store, /* to_prepare_to_store */
4452 m3_xfer_memory, /* to_xfer_memory */
4454 /* FIXME: Should print MID and all that crap. */
4455 child_files_info, /* to_files_info */
4457 memory_insert_breakpoint, /* to_insert_breakpoint */
4458 memory_remove_breakpoint, /* to_remove_breakpoint */
4459 terminal_init_inferior, /* to_terminal_init */
4460 terminal_inferior, /* to_terminal_inferior */
4461 terminal_ours_for_output, /* to_terminal_ours_for_output */
4462 terminal_ours, /* to_terminal_ours */
4463 child_terminal_info, /* to_terminal_info */
4464 m3_kill_inferior, /* to_kill */
4466 0, /* to_lookup_symbol */
4468 m3_create_inferior, /* to_create_inferior */
4469 m3_mourn_inferior, /* to_mourn_inferior */
4470 m3_can_run, /* to_can_run */
4471 0, /* to_notice_signals */
4472 process_stratum, /* to_stratum */
4474 1, /* to_has_all_memory */
4475 1, /* to_has_memory */
4476 1, /* to_has_stack */
4477 1, /* to_has_registers */
4478 1, /* to_has_execution */
4480 0, /* sections_end */
4481 OPS_MAGIC /* to_magic */
4485 _initialize_m3_nat ()
4489 add_target (&m3_ops);
4491 ret = mach_port_allocate(mach_task_self(),
4492 MACH_PORT_RIGHT_PORT_SET,
4493 &inferior_wait_port_set);
4494 if (ret != KERN_SUCCESS)
4495 fatal("initial port set %s",mach_error_string(ret));
4497 /* mach_really_wait now waits for this */
4498 currently_waiting_for = inferior_wait_port_set;
4500 ret = netname_look_up(name_server_port, hostname, "MachID", &mid_server);
4501 if (ret != KERN_SUCCESS)
4503 mid_server = MACH_PORT_NULL;
4505 warning ("initialize machid: netname_lookup_up(MachID) : %s",
4506 mach_error_string(ret));
4507 warning ("Some (most?) features disabled...");
4510 mid_auth = mach_privileged_host_port();
4511 if (mid_auth == MACH_PORT_NULL)
4512 mid_auth = mach_task_self();
4514 obstack_init (port_chain_obstack);
4516 ret = mach_port_allocate (mach_task_self (),
4517 MACH_PORT_RIGHT_RECEIVE,
4518 &thread_exception_port);
4519 CHK ("Creating thread_exception_port for single stepping", ret);
4521 ret = mach_port_insert_right (mach_task_self (),
4522 thread_exception_port,
4523 thread_exception_port,
4524 MACH_MSG_TYPE_MAKE_SEND);
4525 CHK ("Inserting send right to thread_exception_port", ret);
4527 /* Allocate message port */
4528 ret = mach_port_allocate (mach_task_self (),
4529 MACH_PORT_RIGHT_RECEIVE,
4531 if (ret != KERN_SUCCESS)
4532 warning ("Creating message port %s", mach_error_string (ret));
4535 char buf[ MAX_NAME_LEN ];
4536 ret = mach_port_move_member(mach_task_self (),
4538 inferior_wait_port_set);
4539 if (ret != KERN_SUCCESS)
4540 warning ("message move member %s", mach_error_string (ret));
4543 /* @@@@ No way to change message port name currently */
4544 /* Foo. This assumes gdb has a unix pid */
4545 sprintf (buf, "gdb-%d", getpid ());
4546 gdb_register_port (buf, our_message_port);
4549 /* Heap for thread commands */
4550 obstack_init (cproc_obstack);
4552 add_mach_specific_commands ();