* m3-nat.c, i386m3-nat.c, config/i386/i386m3.mh: Many minor
[binutils-gdb.git] / gdb / m3-nat.c
1 /* Interface GDB to Mach 3.0 operating systems.
2 (Most) Mach 3.0 related routines live in this file.
3
4 Copyright (C) 1992 Free Software Foundation, Inc.
5
6 This file is part of GDB.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
21
22 /*
23 * Author: Jukka Virtanen <jtv@hut.fi>
24 * Computing Centre
25 * Helsinki University of Technology
26 * Finland
27 *
28 * Thanks to my friends who helped with ideas and testing:
29 *
30 * Johannes Helander, Antti Louko, Tero Mononen,
31 * jvh@cs.hut.fi alo@hut.fi tmo@cs.hut.fi
32 *
33 * Tero Kivinen and Eamonn McManus
34 * kivinen@cs.hut.fi emcmanus@gr.osf.org
35 *
36 */
37
38 #include <stdio.h>
39
40 #include <mach.h>
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>
48
49 #include "defs.h"
50 #include "inferior.h"
51 #include "symtab.h"
52 #include "value.h"
53 #include "language.h"
54 #include "target.h"
55 #include "wait.h"
56 #include "gdbcmd.h"
57 #include "gdbcore.h"
58
59 #if 0
60 #include <servers/machid_lib.h>
61 #else
62 #define MACH_TYPE_TASK 1
63 #define MACH_TYPE_THREAD 2
64 #endif
65
66 /* Included only for signal names and NSIG
67 *
68 * note: There are many problems in signal handling with
69 * gdb in Mach 3.0 in general.
70 */
71 #include <signal.h>
72 #define SIG_UNKNOWN 0 /* Exception that has no matching unix signal */
73
74 #include <cthreads.h>
75
76 /* This is what a cproc looks like. This is here partly because
77 cthread_internals.h is not a header we can just #include, partly with
78 an eye towards perhaps getting this to work with cross-debugging
79 someday. Best solution is if CMU publishes a real interface to this
80 stuff. */
81 #define CPROC_NEXT_OFFSET 0
82 #define CPROC_NEXT_SIZE (TARGET_PTR_BIT / HOST_CHAR_BIT)
83 #define CPROC_INCARNATION_OFFSET (CPROC_NEXT_OFFSET + CPROC_NEXT_SIZE)
84 #define CPROC_INCARNATION_SIZE (sizeof (cthread_t))
85 #define CPROC_LIST_OFFSET (CPROC_INCARNATION_OFFSET + CPROC_INCARNATION_SIZE)
86 #define CPROC_LIST_SIZE (TARGET_PTR_BIT / HOST_CHAR_BIT)
87 #define CPROC_WAIT_OFFSET (CPROC_LIST_OFFSET + CPROC_LIST_SIZE)
88 #define CPROC_WAIT_SIZE (TARGET_PTR_BIT / HOST_CHAR_BIT)
89 #define CPROC_REPLY_OFFSET (CPROC_WAIT_OFFSET + CPROC_WAIT_SIZE)
90 #define CPROC_REPLY_SIZE (sizeof (mach_port_t))
91 #define CPROC_CONTEXT_OFFSET (CPROC_REPLY_OFFSET + CPROC_REPLY_SIZE)
92 #define CPROC_CONTEXT_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT)
93 #define CPROC_LOCK_OFFSET (CPROC_CONTEXT_OFFSET + CPROC_CONTEXT_SIZE)
94 #define CPROC_LOCK_SIZE (sizeof (spin_lock_t))
95 #define CPROC_STATE_OFFSET (CPROC_LOCK_OFFSET + CPROC_LOCK_SIZE)
96 #define CPROC_STATE_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT)
97 #define CPROC_WIRED_OFFSET (CPROC_STATE_OFFSET + CPROC_STATE_SIZE)
98 #define CPROC_WIRED_SIZE (sizeof (mach_port_t))
99 #define CPROC_BUSY_OFFSET (CPROC_WIRED_OFFSET + CPROC_WIRED_SIZE)
100 #define CPROC_BUSY_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT)
101 #define CPROC_MSG_OFFSET (CPROC_BUSY_OFFSET + CPROC_BUSY_SIZE)
102 #define CPROC_MSG_SIZE (sizeof (mach_msg_header_t))
103 #define CPROC_BASE_OFFSET (CPROC_MSG_OFFSET + CPROC_MSG_SIZE)
104 #define CPROC_BASE_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT)
105 #define CPROC_SIZE_OFFSET (CPROC_BASE_OFFSET + CPROC_BASE_SIZE)
106 #define CPROC_SIZE_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT)
107 #define CPROC_SIZE (CPROC_SIZE_OFFSET + CPROC_SIZE_SIZE)
108
109 /* Values for the state field in the cproc. */
110 #define CPROC_RUNNING 0
111 #define CPROC_SWITCHING 1
112 #define CPROC_BLOCKED 2
113 #define CPROC_CONDWAIT 4
114
115 /* For cproc and kernel thread mapping */
116 typedef struct gdb_thread {
117 mach_port_t name;
118 CORE_ADDR sp;
119 CORE_ADDR pc;
120 CORE_ADDR fp;
121 boolean_t in_emulator;
122 int slotid;
123
124 /* This is for the mthreads list. It points to the cproc list.
125 Perhaps the two lists should be merged (or perhaps it was a mistake
126 to make them both use a struct gdb_thread). */
127 struct gdb_thread *cproc;
128
129 /* These are for the cproc list, which is linked through the next field
130 of the struct gdb_thread. */
131 char raw_cproc[CPROC_SIZE];
132 /* The cthread which is pointed to by the incarnation field from the
133 cproc. This points to the copy we've read into GDB. */
134 cthread_t cthread;
135 /* Point back to the mthreads list. */
136 int reverse_map;
137 struct gdb_thread *next;
138 } *gdb_thread_t;
139
140 /*
141 * Actions for Mach exceptions.
142 *
143 * sigmap field maps the exception to corresponding Unix signal.
144 *
145 * I do not know how to map the exception to unix signal
146 * if SIG_UNKNOWN is specified.
147 */
148
149 struct exception_list {
150 char *name;
151 boolean_t forward;
152 boolean_t print;
153 int sigmap;
154 } exception_map[] = {
155 {"not_mach3_exception", FALSE, TRUE, SIG_UNKNOWN},
156 {"EXC_BAD_ACCESS", FALSE, TRUE, SIGSEGV},
157 {"EXC_BAD_INSTRUCTION", FALSE, TRUE, SIGILL},
158 {"EXC_ARITHMETIC", FALSE, TRUE, SIGFPE},
159 {"EXC_EMULATION", FALSE, TRUE, SIGEMT}, /* ??? */
160 {"EXC_SOFTWARE", FALSE, TRUE, SIG_UNKNOWN},
161 {"EXC_BREAKPOINT", FALSE, FALSE, SIGTRAP}
162 };
163
164 /* Mach exception table size */
165 int max_exception = sizeof(exception_map)/sizeof(struct exception_list) - 1;
166
167 #define MAX_EXCEPTION max_exception
168
169 WAITTYPE wait_status;
170
171 /* If you define this, intercepted bsd server calls will be
172 * dumped while waiting the inferior to EXEC the correct
173 * program
174 */
175 /* #define DUMP_SYSCALL /* debugging interceptor */
176
177 /* xx_debug() outputs messages if this is nonzero.
178 * If > 1, DUMP_SYSCALL will dump message contents.
179 */
180 int debug_level = 0;
181
182 /* "Temporary" debug stuff */
183 void
184 xx_debug (fmt, a,b,c)
185 char *fmt;
186 int a,b,c;
187 {
188 if (debug_level)
189 warning (fmt, a, b, c);
190 }
191
192 /* This is in libmach.a */
193 extern mach_port_t name_server_port;
194
195 /* Set in catch_exception_raise */
196 int stop_exception, stop_code, stop_subcode;
197 int stopped_in_exception;
198
199 /* Thread that was the active thread when we stopped */
200 thread_t stop_thread = MACH_PORT_NULL;
201
202 char *hostname = "";
203
204 /* Set when task is attached or created */
205 boolean_t emulator_present = FALSE;
206
207 task_t inferior_task;
208 thread_t current_thread;
209
210 /* Exception ports for inferior task */
211 mach_port_t inferior_exception_port = MACH_PORT_NULL;
212 mach_port_t inferior_old_exception_port = MACH_PORT_NULL;
213
214 /* task exceptions and notifications */
215 mach_port_t inferior_wait_port_set = MACH_PORT_NULL;
216 mach_port_t our_notify_port = MACH_PORT_NULL;
217
218 /* This is "inferior_wait_port_set" when not single stepping, and
219 * "singlestepped_thread_port" when we are single stepping.
220 *
221 * This is protected by a cleanup function: discard_single_step()
222 */
223 mach_port_t currently_waiting_for = MACH_PORT_NULL;
224
225 /* A port for external messages to gdb.
226 * External in the meaning that they do not come
227 * from the inferior_task, but rather from external
228 * tasks.
229 *
230 * As a debugging feature:
231 * A debugger debugging another debugger can stop the
232 * inferior debugger by the following command sequence
233 * (without running external programs)
234 *
235 * (top-gdb) set stop_inferior_gdb ()
236 * (top-gdb) continue
237 */
238 mach_port_t our_message_port = MACH_PORT_NULL;
239
240 /* For single stepping */
241 mach_port_t thread_exception_port = MACH_PORT_NULL;
242 mach_port_t thread_saved_exception_port = MACH_PORT_NULL;
243 mach_port_t singlestepped_thread_port = MACH_PORT_NULL;
244
245 /* For machid calls */
246 mach_port_t mid_server = MACH_PORT_NULL;
247 mach_port_t mid_auth = MACH_PORT_NULL;
248
249 /* If gdb thinks the inferior task is not suspended, it
250 * must take suspend/abort the threads when it reads the state.
251 */
252 int must_suspend_thread = 0;
253
254 /* When single stepping, we switch the port that mach_really_wait() listens to.
255 * This cleanup is a guard to prevent the port set from being left to
256 * the singlestepped_thread_port when error() is called.
257 * This is nonzero only when we are single stepping.
258 */
259 #define NULL_CLEANUP (struct cleanup *)0
260 struct cleanup *cleanup_step = NULL_CLEANUP;
261
262 \f
263 extern struct target_ops m3_ops;
264 \f
265 #if 0
266 #define MACH_TYPE_EXCEPTION_PORT -1
267 #endif
268
269 /* Chain of ports to remember requested notifications. */
270
271 struct port_chain {
272 struct port_chain *next;
273 mach_port_t port;
274 int type;
275 int mid; /* Now only valid with MACH_TYPE_THREAD and */
276 /* MACH_TYPE_THREAD */
277 };
278 typedef struct port_chain *port_chain_t;
279
280 /* Room for chain nodes comes from pchain_obstack */
281 struct obstack pchain_obstack;
282 struct obstack *port_chain_obstack = &pchain_obstack;
283
284 /* For thread handling */
285 struct obstack Cproc_obstack;
286 struct obstack *cproc_obstack = &Cproc_obstack;
287
288 /* the list of notified ports */
289 port_chain_t notify_chain = (port_chain_t) NULL;
290
291 port_chain_t
292 port_chain_insert (list, name, type)
293 port_chain_t list;
294 mach_port_t name;
295 int type;
296 {
297 kern_return_t ret;
298 port_chain_t new;
299 int mid;
300
301 if (! MACH_PORT_VALID (name))
302 return list;
303
304 if (type == MACH_TYPE_TASK || type == MACH_TYPE_THREAD)
305 {
306 if (! MACH_PORT_VALID (mid_server))
307 {
308 warning ("Machid server port invalid, can not map port 0x%x to MID",
309 name);
310 mid = name;
311 }
312 else
313 {
314 ret = machid_mach_register (mid_server, mid_auth, name, type, &mid);
315
316 if (ret != KERN_SUCCESS)
317 {
318 warning ("Can not map name (0x%x) to MID with machid", name);
319 mid = name;
320 }
321 }
322 }
323 else
324 mid = 3735928559; /* 0x? :-) */
325
326 new = (port_chain_t) obstack_alloc (port_chain_obstack,
327 sizeof (struct port_chain));
328 new->next = list;
329 new->port = name;
330 new->type = type;
331 new->mid = mid;
332
333 return new;
334 }
335
336 port_chain_t
337 port_chain_delete (list, elem)
338 port_chain_t list;
339 mach_port_t elem;
340 {
341 if (list)
342 if (list->port == elem)
343 list = list->next;
344 else
345 while (list->next)
346 {
347 if (list->next->port == elem)
348 list->next = list->next->next; /* GCd with obstack_free() */
349 else
350 list = list->next;
351 }
352 return list;
353 }
354
355 void
356 port_chain_destroy (ostack)
357 struct obstack *ostack;
358 {
359 obstack_free (ostack, 0);
360 obstack_init (ostack);
361 }
362
363 port_chain_t
364 port_chain_member (list, elem)
365 port_chain_t list;
366 mach_port_t elem;
367 {
368 while (list)
369 {
370 if (list->port == elem)
371 return list;
372 list = list->next;
373 }
374 return (port_chain_t) NULL;
375 }
376 \f
377 int
378 map_port_name_to_mid (name, type)
379 mach_port_t name;
380 int type;
381 {
382 port_chain_t elem;
383
384 if (!MACH_PORT_VALID (name))
385 return -1;
386
387 elem = port_chain_member (notify_chain, name);
388
389 if (elem && (elem->type == type))
390 return elem->mid;
391
392 if (elem)
393 return -1;
394
395 if (! MACH_PORT_VALID (mid_server))
396 {
397 warning ("Machid server port invalid, can not map port 0x%x to mid",
398 name);
399 return -1;
400 }
401 else
402 {
403 int mid;
404 kern_return_t ret;
405
406 ret = machid_mach_register (mid_server, mid_auth, name, type, &mid);
407
408 if (ret != KERN_SUCCESS)
409 {
410 warning ("Can not map name (0x%x) to mid with machid", name);
411 return -1;
412 }
413 return mid;
414 }
415 }
416 \f
417 /* Guard for currently_waiting_for and singlestepped_thread_port */
418 static void
419 discard_single_step (thread)
420 thread_t thread;
421 {
422 currently_waiting_for = inferior_wait_port_set;
423
424 cleanup_step = NULL_CLEANUP;
425 if (MACH_PORT_VALID (thread) && MACH_PORT_VALID (singlestepped_thread_port))
426 setup_single_step (thread, FALSE);
427 }
428
429 setup_single_step (thread, start_step)
430 thread_t thread;
431 boolean_t start_step;
432 {
433 kern_return_t ret;
434
435 if (! MACH_PORT_VALID (thread))
436 error ("Invalid thread supplied to setup_single_step");
437 else
438 {
439 mach_port_t teport;
440
441 /* Get the current thread exception port */
442 ret = thread_get_exception_port (thread, &teport);
443 CHK ("Getting thread's exception port", ret);
444
445 if (start_step)
446 {
447 if (MACH_PORT_VALID (singlestepped_thread_port))
448 {
449 warning ("Singlestepped_thread_port (0x%x) is still valid?",
450 singlestepped_thread_port);
451 singlestepped_thread_port = MACH_PORT_NULL;
452 }
453
454 /* If we are already stepping this thread */
455 if (MACH_PORT_VALID (teport) && teport == thread_exception_port)
456 {
457 ret = mach_port_deallocate (mach_task_self (), teport);
458 CHK ("Could not deallocate thread exception port", ret);
459 }
460 else
461 {
462 ret = thread_set_exception_port (thread, thread_exception_port);
463 CHK ("Setting exception port for thread", ret);
464 #if 0
465 /* Insert thread exception port to wait port set */
466 ret = mach_port_move_member (mach_task_self(),
467 thread_exception_port,
468 inferior_wait_port_set);
469 CHK ("Moving thread exception port to inferior_wait_port_set",
470 ret);
471 #endif
472 thread_saved_exception_port = teport;
473 }
474
475 thread_trace (thread, TRUE);
476
477 singlestepped_thread_port = thread_exception_port;
478 currently_waiting_for = singlestepped_thread_port;
479 cleanup_step = make_cleanup (discard_single_step, thread);
480 }
481 else
482 {
483 if (! MACH_PORT_VALID (teport))
484 error ("Single stepped thread had an invalid exception port?");
485
486 if (teport != thread_exception_port)
487 error ("Single stepped thread had an unknown exception port?");
488
489 ret = mach_port_deallocate (mach_task_self (), teport);
490 CHK ("Couldn't deallocate thread exception port", ret);
491 #if 0
492 /* Remove thread exception port from wait port set */
493 ret = mach_port_move_member (mach_task_self(),
494 thread_exception_port,
495 MACH_PORT_NULL);
496 CHK ("Removing thread exception port from inferior_wait_port_set",
497 ret);
498 #endif
499 /* Restore thread's old exception port */
500 ret = thread_set_exception_port (thread,
501 thread_saved_exception_port);
502 CHK ("Restoring stepped thread's exception port", ret);
503
504 if (MACH_PORT_VALID (thread_saved_exception_port))
505 (void) mach_port_deallocate (mach_task_self (),
506 thread_saved_exception_port);
507
508 thread_trace (thread, FALSE);
509
510 singlestepped_thread_port = MACH_PORT_NULL;
511 currently_waiting_for = inferior_wait_port_set;
512 if (cleanup_step)
513 discard_cleanups (cleanup_step);
514 }
515 }
516 }
517 \f
518 static
519 request_notify (name, variant, type)
520 mach_port_t name;
521 mach_msg_id_t variant;
522 int type;
523 {
524 kern_return_t ret;
525 mach_port_t previous_port_dummy = MACH_PORT_NULL;
526
527 if (! MACH_PORT_VALID (name))
528 return;
529
530 if (port_chain_member (notify_chain, name))
531 return;
532
533 ret = mach_port_request_notification (mach_task_self(),
534 name,
535 variant,
536 1,
537 our_notify_port,
538 MACH_MSG_TYPE_MAKE_SEND_ONCE,
539 &previous_port_dummy);
540 CHK ("Serious: request_notify failed", ret);
541
542 (void) mach_port_deallocate (mach_task_self (),
543 previous_port_dummy);
544
545 notify_chain = port_chain_insert (notify_chain, name, type);
546 }
547
548 reverse_msg_bits(msgp, type)
549 mach_msg_header_t *msgp;
550 int type;
551 {
552 int rbits,lbits;
553 rbits = MACH_MSGH_BITS_REMOTE(msgp->msgh_bits);
554 lbits = type;
555 msgp->msgh_bits =
556 (msgp->msgh_bits & ~MACH_MSGH_BITS_PORTS_MASK) |
557 MACH_MSGH_BITS(lbits,rbits);
558 }
559 \f
560 /* On the third day He said:
561
562 Let this be global
563 and then it was global.
564
565 When creating the inferior fork, the
566 child code in inflow.c sets the name of the
567 bootstrap_port in its address space to this
568 variable.
569
570 The name is transferred to our address space
571 with mach3_read_inferior().
572
573 Thou shalt not do this with
574 task_get_bootstrap_port() in this task, since
575 the name in the inferior task is different than
576 the one we get.
577
578 For blessed are the meek, as they shall inherit
579 the address space.
580 */
581 mach_port_t original_server_port_name = MACH_PORT_NULL;
582
583
584 /* Called from inferior after FORK but before EXEC */
585 static void
586 m3_trace_me ()
587 {
588 kern_return_t ret;
589
590 /* Get the NAME of the bootstrap port in this task
591 so that GDB can read it */
592 ret = task_get_bootstrap_port (mach_task_self (),
593 &original_server_port_name);
594 if (ret != KERN_SUCCESS)
595 abort ();
596 ret = mach_port_deallocate (mach_task_self (),
597 original_server_port_name);
598 if (ret != KERN_SUCCESS)
599 abort ();
600
601 /* Suspend this task to let the parent change my ports.
602 Resumed by the debugger */
603 ret = task_suspend (mach_task_self ());
604 if (ret != KERN_SUCCESS)
605 abort ();
606 }
607 \f
608 /*
609 * Intercept system calls to Unix server.
610 * After EXEC_COUNTER calls to exec(), return.
611 *
612 * Pre-assertion: Child is suspended. (Not verified)
613 * Post-condition: Child is suspended after EXEC_COUNTER exec() calls.
614 */
615
616 void
617 intercept_exec_calls (exec_counter)
618 int exec_counter;
619 {
620 struct syscall_msg_t {
621 mach_msg_header_t header;
622 mach_msg_type_t type;
623 char room[ 2000 ]; /* Enuff space */
624 };
625
626 struct syscall_msg_t syscall_in, syscall_out;
627
628 mach_port_t fake_server;
629 mach_port_t original_server_send;
630 mach_port_t original_exec_reply;
631 mach_port_t exec_reply;
632 mach_port_t exec_reply_send;
633 mach_msg_type_name_t acquired;
634 mach_port_t emulator_server_port_name;
635 struct task_basic_info info;
636 mach_msg_type_number_t info_count;
637
638 kern_return_t ret;
639
640 if (exec_counter <= 0)
641 return; /* We are already set up in the correct program */
642
643 ret = mach_port_allocate(mach_task_self(),
644 MACH_PORT_RIGHT_RECEIVE,
645 &fake_server);
646 CHK("create inferior_fake_server port failed", ret);
647
648 /* Wait for inferior_task to suspend itself */
649 while(1)
650 {
651 info_count = sizeof (info);
652 ret = task_info (inferior_task,
653 TASK_BASIC_INFO,
654 (task_info_t)&info,
655 &info_count);
656 CHK ("Task info", ret);
657
658 if (info.suspend_count)
659 break;
660
661 /* Note that the definition of the parameter was undefined
662 * at the time of this writing, so I just use an `ad hoc' value.
663 */
664 (void) swtch_pri (42); /* Universal Priority Value */
665 }
666
667 /* Read the inferior's bootstrap port name */
668 if (!mach3_read_inferior (&original_server_port_name,
669 &original_server_port_name,
670 sizeof (original_server_port_name)))
671 error ("Can't read inferior task bootstrap port name");
672
673 /* @@ BUG: If more than 1 send right GDB will FAIL!!! */
674 /* Should get refs, and set them back when restoring */
675 /* Steal the original bsd server send right from inferior */
676 ret = mach_port_extract_right (inferior_task,
677 original_server_port_name,
678 MACH_MSG_TYPE_MOVE_SEND,
679 &original_server_send,
680 &acquired);
681 CHK("mach_port_extract_right (bsd server send)",ret);
682
683 if (acquired != MACH_MSG_TYPE_PORT_SEND)
684 error("Incorrect right extracted, send right to bsd server excpected");
685
686 ret = mach_port_insert_right (inferior_task,
687 original_server_port_name,
688 fake_server,
689 MACH_MSG_TYPE_MAKE_SEND);
690 CHK("mach_port_insert_right (fake server send)",ret);
691
692 xx_debug ("inferior task bsd server ports set up \nfs %x, ospn %x, oss %x\n",
693 fake_server,
694 original_server_port_name, original_server_send);
695
696 /* A receive right to the reply generated by unix server exec() request */
697 ret = mach_port_allocate(mach_task_self(),
698 MACH_PORT_RIGHT_RECEIVE,
699 &exec_reply);
700 CHK("create intercepted_reply_port port failed", ret);
701
702 /* Pass this send right to Unix server so it replies to us after exec() */
703 ret = mach_port_extract_right (mach_task_self (),
704 exec_reply,
705 MACH_MSG_TYPE_MAKE_SEND_ONCE,
706 &exec_reply_send,
707 &acquired);
708 CHK("mach_port_extract_right (exec_reply)",ret);
709
710 if (acquired != MACH_MSG_TYPE_PORT_SEND_ONCE)
711 error("Incorrect right extracted, send once excpected for exec reply");
712
713 ret = mach_port_move_member(mach_task_self(),
714 fake_server,
715 inferior_wait_port_set);
716 CHK ("Moving fake syscall port to inferior_wait_port_set", ret);
717
718 xx_debug ("syscall fake server set up, resuming inferior\n");
719
720 ret = task_resume (inferior_task);
721 CHK("task_resume (startup)", ret);
722
723 /* Read requests from the inferior.
724 Pass directly through everything else except exec() calls.
725 */
726 while(exec_counter > 0)
727 {
728 ret = mach_msg (&syscall_in.header, /* header */
729 MACH_RCV_MSG, /* options */
730 0, /* send size */
731 sizeof (struct syscall_msg_t), /* receive size */
732 inferior_wait_port_set, /* receive_name */
733 MACH_MSG_TIMEOUT_NONE,
734 MACH_PORT_NULL);
735 CHK("mach_msg (intercepted sycall)", ret);
736
737 #ifdef DUMP_SYSCALL
738 print_msg (&syscall_in.header);
739 #endif
740
741 /* ASSERT : msgh_local_port == fake_server */
742
743 if (notify_server (&syscall_in.header, &syscall_out.header))
744 error ("received a notify while intercepting syscalls");
745
746 if (syscall_in.header.msgh_id == MIG_EXEC_SYSCALL_ID)
747 {
748 xx_debug ("Received EXEC SYSCALL, counter = %d\n", exec_counter);
749 if (exec_counter == 1)
750 {
751 original_exec_reply = syscall_in.header.msgh_remote_port;
752 syscall_in.header.msgh_remote_port = exec_reply_send;
753 }
754 exec_counter--;
755 }
756
757 syscall_in.header.msgh_local_port = syscall_in.header.msgh_remote_port;
758 syscall_in.header.msgh_remote_port = original_server_send;
759
760 reverse_msg_bits(&syscall_in.header, MACH_MSG_TYPE_COPY_SEND);
761
762 ret = mach_msg_send (&syscall_in.header);
763 CHK ("Forwarded syscall", ret);
764 }
765
766 ret = mach_port_move_member(mach_task_self(),
767 fake_server,
768 MACH_PORT_NULL);
769 CHK ("Moving fake syscall out of inferior_wait_port_set", ret);
770
771 ret = mach_port_move_member(mach_task_self(),
772 exec_reply,
773 inferior_wait_port_set);
774 CHK ("Moving exec_reply to inferior_wait_port_set", ret);
775
776 ret = mach_msg (&syscall_in.header, /* header */
777 MACH_RCV_MSG, /* options */
778 0, /* send size */
779 sizeof (struct syscall_msg_t), /* receive size */
780 inferior_wait_port_set, /* receive_name */
781 MACH_MSG_TIMEOUT_NONE,
782 MACH_PORT_NULL);
783 CHK("mach_msg (exec reply)", ret);
784
785 ret = task_suspend (inferior_task);
786 CHK ("Suspending inferior after last exec", ret);
787
788 must_suspend_thread = 0;
789
790 xx_debug ("Received exec reply from bsd server, suspended inferior task\n");
791
792 #ifdef DUMP_SYSCALL
793 print_msg (&syscall_in.header);
794 #endif
795
796 /* Message should appear as if it came from the unix server */
797 syscall_in.header.msgh_local_port = MACH_PORT_NULL;
798
799 /* and go to the inferior task original reply port */
800 syscall_in.header.msgh_remote_port = original_exec_reply;
801
802 reverse_msg_bits(&syscall_in.header, MACH_MSG_TYPE_MOVE_SEND_ONCE);
803
804 ret = mach_msg_send (&syscall_in.header);
805 CHK ("Forwarding exec reply to inferior", ret);
806
807 /* Garbage collect */
808 ret = mach_port_deallocate (inferior_task,
809 original_server_port_name);
810 CHK ("deallocating fake server send right", ret);
811
812 ret = mach_port_insert_right (inferior_task,
813 original_server_port_name,
814 original_server_send,
815 MACH_MSG_TYPE_MOVE_SEND);
816 CHK ("Restoring the original bsd server send right", ret);
817
818 ret = mach_port_destroy (mach_task_self (),
819 fake_server);
820 fake_server = MACH_PORT_DEAD;
821 CHK("mach_port_destroy (fake_server)", ret);
822
823 ret = mach_port_destroy (mach_task_self (),
824 exec_reply);
825 exec_reply = MACH_PORT_DEAD;
826 CHK("mach_port_destroy (exec_reply)", ret);
827
828 xx_debug ("Done with exec call interception\n");
829 }
830
831 void
832 consume_send_rights (thread_list, thread_count)
833 thread_array_t thread_list;
834 int thread_count;
835 {
836 int index;
837
838 if (!thread_count)
839 return;
840
841 for (index = 0; index < thread_count; index++)
842 {
843 /* Since thread kill command kills threads, don't check ret */
844 (void) mach_port_deallocate (mach_task_self (),
845 thread_list [ index ]);
846 }
847 }
848
849 /* suspend/abort/resume a thread. */
850 setup_thread (thread, what)
851 mach_port_t thread;
852 int what;
853 {
854 kern_return_t ret;
855
856 if (what)
857 {
858 ret = thread_suspend (thread);
859 CHK ("setup_thread thread_suspend", ret);
860
861 ret = thread_abort (thread);
862 CHK ("setup_thread thread_abort", ret);
863 }
864 else
865 {
866 ret = thread_resume (thread);
867 CHK ("setup_thread thread_resume", ret);
868 }
869 }
870
871 int
872 map_slot_to_mid (slot, threads, thread_count)
873 int slot;
874 thread_array_t threads;
875 int thread_count;
876 {
877 kern_return_t ret;
878 int deallocate = 0;
879 int index;
880 int mid;
881
882 if (! threads)
883 {
884 deallocate++;
885 ret = task_threads (inferior_task, &threads, &thread_count);
886 CHK ("Can not select a thread from a dead task", ret);
887 }
888
889 if (slot < 0 || slot >= thread_count)
890 {
891 if (deallocate)
892 {
893 consume_send_rights (threads, thread_count);
894 (void) vm_deallocate (mach_task_self(), (vm_address_t)threads,
895 (thread_count * sizeof(mach_port_t)));
896 }
897 if (slot < 0)
898 error ("invalid slot number");
899 else
900 return -(slot+1);
901 }
902
903 mid = map_port_name_to_mid (threads [slot], MACH_TYPE_THREAD);
904
905 if (deallocate)
906 {
907 consume_send_rights (threads, thread_count);
908 (void) vm_deallocate (mach_task_self(), (vm_address_t)threads,
909 (thread_count * sizeof(mach_port_t)));
910 }
911
912 return mid;
913 }
914
915 static int
916 parse_thread_id (arg, thread_count, slots)
917 char *arg;
918 int thread_count;
919 int slots;
920 {
921 kern_return_t ret;
922 int mid;
923 int slot;
924 int index;
925
926 if (arg == 0)
927 return 0;
928
929 while (*arg && (*arg == ' ' || *arg == '\t'))
930 arg++;
931
932 if (! *arg)
933 return 0;
934
935 /* Currently parse MID and @SLOTNUMBER */
936 if (*arg != '@')
937 {
938 mid = atoi (arg);
939 if (mid <= 0)
940 error ("valid thread mid expected");
941 return mid;
942 }
943
944 arg++;
945 slot = atoi (arg);
946
947 if (slot < 0)
948 error ("invalid slot number");
949
950 /* If you want slot numbers to remain slot numbers, set slots.
951 *
952 * Well, since 0 is reserved, return the ordinal number
953 * of the thread rather than the slot number. Awk, this
954 * counts as a kludge.
955 */
956 if (slots)
957 return -(slot+1);
958
959 if (thread_count && slot >= thread_count)
960 return -(slot+1);
961
962 mid = map_slot_to_mid (slot);
963
964 return mid;
965 }
966
967 /* THREAD_ID 0 is special; it selects the first kernel
968 * thread from the list (i.e. SLOTNUMBER 0)
969 * This is used when starting the program with 'run' or when attaching.
970 *
971 * If FLAG is 0 the context is not changed, and the registers, frame, etc
972 * will continue to describe the old thread.
973 *
974 * If FLAG is nonzero, really select the thread.
975 * If FLAG is 2, the THREAD_ID is a slotnumber instead of a mid.
976 *
977 */
978 kern_return_t
979 select_thread (task, thread_id, flag)
980 mach_port_t task;
981 int thread_id;
982 int flag;
983 {
984 thread_array_t thread_list;
985 int thread_count;
986 kern_return_t ret;
987 int index;
988 thread_t new_thread = MACH_PORT_NULL;
989
990 if (thread_id < 0)
991 error ("Can't select cprocs without kernel thread");
992
993 ret = task_threads (task, &thread_list, &thread_count);
994 if (ret != KERN_SUCCESS)
995 {
996 warning ("Can not select a thread from a dead task");
997 m3_kill_inferior ();
998 return KERN_FAILURE;
999 }
1000
1001 if (thread_count == 0)
1002 {
1003 /* The task can not do anything anymore, but it still
1004 * exists as a container for memory and ports.
1005 */
1006 registers_changed ();
1007 warning ("Task %d has no threads",
1008 map_port_name_to_mid (task, MACH_TYPE_TASK));
1009 current_thread = MACH_PORT_NULL;
1010 (void) vm_deallocate(mach_task_self(),
1011 (vm_address_t) thread_list,
1012 (thread_count * sizeof(mach_port_t)));
1013 return KERN_FAILURE;
1014 }
1015
1016 if (! thread_id || flag == 2)
1017 {
1018 /* First thread or a slotnumber */
1019 if (! thread_id)
1020 new_thread = thread_list[0];
1021 else
1022 {
1023 if (thread_id < thread_count)
1024 new_thread = thread_list[ thread_id ];
1025 else
1026 {
1027 (void) vm_deallocate(mach_task_self(),
1028 (vm_address_t) thread_list,
1029 (thread_count * sizeof(mach_port_t)));
1030 error ("No such thread slot number : %d", thread_id);
1031 }
1032 }
1033 }
1034 else
1035 {
1036 for (index = 0; index < thread_count; index++)
1037 if (thread_id == map_port_name_to_mid (thread_list [index],
1038 MACH_TYPE_THREAD))
1039 {
1040 new_thread = thread_list [index];
1041 index = -1;
1042 break;
1043 }
1044
1045 if (index != -1)
1046 error ("No thread with mid %d", thread_id);
1047 }
1048
1049 /* Notify when the selected thread dies */
1050 request_notify (new_thread, MACH_NOTIFY_DEAD_NAME, MACH_TYPE_THREAD);
1051
1052 ret = vm_deallocate(mach_task_self(),
1053 (vm_address_t) thread_list,
1054 (thread_count * sizeof(mach_port_t)));
1055 CHK ("vm_deallocate", ret);
1056
1057 if (! flag)
1058 current_thread = new_thread;
1059 else
1060 {
1061 #if 0
1062 if (MACH_PORT_VALID (current_thread))
1063 {
1064 /* Store the gdb's view of the thread we are deselecting
1065 *
1066 * @@ I think gdb updates registers immediately when they are
1067 * changed, so don't do this.
1068 */
1069 ret = thread_abort (current_thread);
1070 CHK ("Could not abort system calls when saving state of old thread",
1071 ret);
1072 target_prepare_to_store ();
1073 target_store_registers (-1);
1074 }
1075 #endif
1076
1077 registers_changed ();
1078
1079 current_thread = new_thread;
1080
1081 ret = thread_abort (current_thread);
1082 CHK ("Could not abort system calls when selecting a thread", ret);
1083
1084 stop_pc = read_pc();
1085 set_current_frame (create_new_frame (read_register (FP_REGNUM),
1086 stop_pc));
1087
1088 select_frame (get_current_frame (), 0);
1089
1090 stop_frame_address = FRAME_FP (get_current_frame ());
1091 }
1092
1093 return KERN_SUCCESS;
1094 }
1095
1096 /*
1097 * Switch to use thread named NEW_THREAD.
1098 * Return it's MID
1099 */
1100 int
1101 switch_to_thread (new_thread)
1102 thread_t new_thread;
1103 {
1104 thread_t saved_thread = current_thread;
1105 int mid;
1106
1107 mid = map_port_name_to_mid (new_thread,
1108 MACH_TYPE_THREAD);
1109 if (mid == -1)
1110 warning ("Can't map thread name 0x%x to mid", new_thread);
1111 else if (select_thread (inferior_task, mid, 1) != KERN_SUCCESS)
1112 {
1113 if (current_thread)
1114 current_thread = saved_thread;
1115 error ("Could not select thread %d", mid);
1116 }
1117
1118 return mid;
1119 }
1120
1121 /* Do this in gdb after doing FORK but before STARTUP_INFERIOR.
1122 * Note that the registers are not yet valid in the inferior task.
1123 */
1124 static void
1125 m3_trace_him (pid)
1126 int pid;
1127 {
1128 kern_return_t ret;
1129
1130 inferior_task = task_by_pid (pid);
1131
1132 if (! MACH_PORT_VALID (inferior_task))
1133 error ("Can not map Unix pid %d to Mach task", pid);
1134
1135 /* Clean up previous notifications and create new ones */
1136 setup_notify_port (1);
1137
1138 /* When notification appears, the inferior task has died */
1139 request_notify (inferior_task, MACH_NOTIFY_DEAD_NAME, MACH_TYPE_TASK);
1140
1141 emulator_present = have_emulator_p (inferior_task);
1142
1143 /* By default, select the first thread,
1144 * If task has no threads, gives a warning
1145 * Does not fetch registers, since they are not yet valid.
1146 */
1147 select_thread (inferior_task, 0, 0);
1148
1149 inferior_exception_port = MACH_PORT_NULL;
1150
1151 setup_exception_port ();
1152
1153 xx_debug ("Now the debugged task is created\n");
1154
1155 /* One trap to exec the shell, one to exec the program being debugged. */
1156 intercept_exec_calls (2);
1157 }
1158
1159 setup_exception_port ()
1160 {
1161 kern_return_t ret;
1162
1163 ret = mach_port_allocate (mach_task_self(),
1164 MACH_PORT_RIGHT_RECEIVE,
1165 &inferior_exception_port);
1166 CHK("mach_port_allocate",ret);
1167
1168 /* add send right */
1169 ret = mach_port_insert_right (mach_task_self (),
1170 inferior_exception_port,
1171 inferior_exception_port,
1172 MACH_MSG_TYPE_MAKE_SEND);
1173 CHK("mach_port_insert_right",ret);
1174
1175 ret = mach_port_move_member (mach_task_self(),
1176 inferior_exception_port,
1177 inferior_wait_port_set);
1178 CHK("mach_port_move_member",ret);
1179
1180 ret = task_get_special_port (inferior_task,
1181 TASK_EXCEPTION_PORT,
1182 &inferior_old_exception_port);
1183 CHK ("task_get_special_port(old exc)",ret);
1184
1185 ret = task_set_special_port (inferior_task,
1186 TASK_EXCEPTION_PORT,
1187 inferior_exception_port);
1188 CHK("task_set_special_port",ret);
1189
1190 ret = mach_port_deallocate (mach_task_self (),
1191 inferior_exception_port);
1192 CHK("mack_port_deallocate",ret);
1193
1194 #if 0
1195 /* When notify appears, the inferior_task's exception
1196 * port has been destroyed.
1197 *
1198 * Not used, since the dead_name_notification already
1199 * appears when task dies.
1200 *
1201 */
1202 request_notify (inferior_exception_port,
1203 MACH_NOTIFY_NO_SENDERS,
1204 MACH_TYPE_EXCEPTION_PORT);
1205 #endif
1206 }
1207
1208 /* Nonzero if gdb is waiting for a message */
1209 int mach_really_waiting;
1210
1211 /* Wait for the inferior to stop for some reason.
1212 - Loop on notifications until inferior_task dies.
1213 - Loop on exceptions until stopped_in_exception comes true.
1214 (e.g. we receive a single step trace trap)
1215 - a message arrives to gdb's message port
1216
1217 There is no other way to exit this loop.
1218
1219 Returns the inferior_pid for rest of gdb.
1220 Side effects: Set *OURSTATUS. */
1221 int
1222 mach_really_wait (ourstatus)
1223 struct target_waitstatus *ourstatus;
1224 {
1225 int pid;
1226 kern_return_t ret;
1227 int w;
1228
1229 struct msg {
1230 mach_msg_header_t header;
1231 mach_msg_type_t foo;
1232 int data[8000];
1233 } in_msg, out_msg;
1234
1235 /* Either notify (death), exception or message can stop the inferior */
1236 stopped_in_exception = FALSE;
1237
1238 while (1)
1239 {
1240 QUIT;
1241
1242 stop_exception = stop_code = stop_subcode = -1;
1243 stop_thread = MACH_PORT_NULL;
1244
1245 mach_really_waiting = 1;
1246 ret = mach_msg (&in_msg.header, /* header */
1247 MACH_RCV_MSG, /* options */
1248 0, /* send size */
1249 sizeof (struct msg), /* receive size */
1250 currently_waiting_for, /* receive name */
1251 MACH_MSG_TIMEOUT_NONE,
1252 MACH_PORT_NULL);
1253 mach_really_waiting = 0;
1254 CHK("mach_msg (receive)", ret);
1255
1256 /* Check if we received a notify of the childs' death */
1257 if (notify_server (&in_msg.header, &out_msg.header))
1258 {
1259 /* If inferior_task is null then the inferior has
1260 gone away and we want to return to command level.
1261 Otherwise it was just an informative message and we
1262 need to look to see if there are any more. */
1263 if (inferior_task != MACH_PORT_NULL)
1264 continue;
1265 else
1266 {
1267 /* Collect Unix exit status for gdb */
1268
1269 wait3(&w, WNOHANG, 0);
1270
1271 /* This mess is here to check that the rest of
1272 * gdb knows that the inferior died. It also
1273 * tries to hack around the fact that Mach 3.0 (mk69)
1274 * unix server (ux28) does not always know what
1275 * has happened to it's children when mach-magic
1276 * is applied on them.
1277 */
1278 if ((!WIFEXITED(w) && WIFSTOPPED(w)) ||
1279 (WIFEXITED(w) && WEXITSTATUS(w) > 0377))
1280 {
1281 WSETEXIT(w, 0);
1282 warning ("Using exit value 0 for terminated task");
1283 }
1284 else if (!WIFEXITED(w))
1285 {
1286 int sig = WTERMSIG(w);
1287
1288 /* Signals cause problems. Warn the user. */
1289 if (sig != SIGKILL) /* Bad luck if garbage matches this */
1290 warning ("The terminating signal stuff may be nonsense");
1291 else if (sig > NSIG)
1292 {
1293 WSETEXIT(w, 0);
1294 warning ("Using exit value 0 for terminated task");
1295 }
1296 }
1297 store_waitstatus (ourstatus, w);
1298 return inferior_pid;
1299 }
1300 }
1301
1302 /* Hmm. Check for exception, as it was not a notification.
1303 exc_server() does an upcall to catch_exception_raise()
1304 if this rpc is an exception. Further actions are decided
1305 there.
1306 */
1307 if (! exc_server (&in_msg.header, &out_msg.header))
1308 {
1309
1310 /* Not an exception, check for message.
1311 *
1312 * Messages don't come from the inferior, or if they
1313 * do they better be asynchronous or it will hang.
1314 */
1315 if (gdb_message_server (&in_msg.header))
1316 continue;
1317
1318 error ("Unrecognized message received in mach_really_wait");
1319 }
1320
1321 /* Send the reply of the exception rpc to the suspended task */
1322 ret = mach_msg_send (&out_msg.header);
1323 CHK ("mach_msg_send (exc reply)", ret);
1324
1325 if (stopped_in_exception)
1326 {
1327 /* Get unix state. May be changed in mach3_exception_actions() */
1328 wait3(&w, WNOHANG, 0);
1329
1330 mach3_exception_actions (&w, FALSE, "Task");
1331
1332 store_waitstatus (ourstatus, w);
1333 return inferior_pid;
1334 }
1335 }
1336 }
1337
1338 /* Called by macro DO_QUIT() in utils.c(quit).
1339 * This is called just before calling error() to return to command level
1340 */
1341 void
1342 mach3_quit ()
1343 {
1344 int mid;
1345 kern_return_t ret;
1346
1347 if (mach_really_waiting)
1348 {
1349 ret = task_suspend (inferior_task);
1350
1351 if (ret != KERN_SUCCESS)
1352 {
1353 warning ("Could not suspend task for interrupt: %s",
1354 mach_error_string (ret));
1355 mach_really_waiting = 0;
1356 return;
1357 }
1358 }
1359
1360 must_suspend_thread = 0;
1361 mach_really_waiting = 0;
1362
1363 mid = map_port_name_to_mid (current_thread, MACH_TYPE_THREAD);
1364 if (mid == -1)
1365 {
1366 warning ("Selecting first existing kernel thread");
1367 mid = 0;
1368 }
1369
1370 current_thread = MACH_PORT_NULL; /* Force setup */
1371 select_thread (inferior_task, mid, 1);
1372
1373 return;
1374 }
1375
1376 /* If ^C is typed when we are waiting for a message
1377 * and your Unix server is able to notice that we
1378 * should quit now.
1379 *
1380 * Called by REQUEST_QUIT() from utils.c(request_quit)
1381 */
1382 void
1383 mach3_request_quit ()
1384 {
1385 if (mach_really_waiting)
1386 immediate_quit = 1;
1387 }
1388
1389 /*
1390 * Gdb message server.
1391 * Currently implemented is the STOP message, that causes
1392 * gdb to return to the command level like ^C had been typed from terminal.
1393 */
1394 int
1395 gdb_message_server (InP)
1396 mach_msg_header_t *InP;
1397 {
1398 kern_return_t ret;
1399 int mid;
1400
1401 if (InP->msgh_local_port == our_message_port)
1402 {
1403 /* A message coming to our_message_port. Check validity */
1404 switch (InP->msgh_id) {
1405
1406 case GDB_MESSAGE_ID_STOP:
1407 ret = task_suspend (inferior_task);
1408 if (ret != KERN_SUCCESS)
1409 warning ("Could not suspend task for stop message: %s",
1410 mach_error_string (ret));
1411
1412 /* QUIT in mach_really_wait() loop. */
1413 request_quit (0);
1414 break;
1415
1416 default:
1417 warning ("Invalid message id %d received, ignored.",
1418 InP->msgh_id);
1419 break;
1420 }
1421
1422 return 1;
1423 }
1424
1425 /* Message not handled by this server */
1426 return 0;
1427 }
1428
1429 /* NOTE: This is not an RPC call. It is a simpleroutine.
1430 *
1431 * This is not called from this gdb code.
1432 *
1433 * It may be called by another debugger to cause this
1434 * debugger to enter command level:
1435 *
1436 * (gdb) set stop_inferior_gdb ()
1437 * (gdb) continue
1438 *
1439 * External program "stop-gdb" implements this also.
1440 */
1441 void
1442 stop_inferior_gdb ()
1443 {
1444 kern_return_t ret;
1445
1446 /* Code generated by mig, with minor cleanups :-)
1447 *
1448 * simpleroutine stop_inferior_gdb (our_message_port : mach_port_t);
1449 */
1450
1451 typedef struct {
1452 mach_msg_header_t Head;
1453 } Request;
1454
1455 Request Mess;
1456
1457 register Request *InP = &Mess;
1458
1459 InP->Head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
1460
1461 /* msgh_size passed as argument */
1462 InP->Head.msgh_remote_port = our_message_port;
1463 InP->Head.msgh_local_port = MACH_PORT_NULL;
1464 InP->Head.msgh_seqno = 0;
1465 InP->Head.msgh_id = GDB_MESSAGE_ID_STOP;
1466
1467 ret = mach_msg (&InP->Head,
1468 MACH_SEND_MSG|MACH_MSG_OPTION_NONE,
1469 sizeof(Request),
1470 0,
1471 MACH_PORT_NULL,
1472 MACH_MSG_TIMEOUT_NONE,
1473 MACH_PORT_NULL);
1474 }
1475
1476 #ifdef THREAD_ALLOWED_TO_BREAK
1477 /*
1478 * Return 1 if the MID specifies the thread that caused the
1479 * last exception.
1480 * Since catch_exception_raise() selects the thread causing
1481 * the last exception to current_thread, we just check that
1482 * it is selected and the last exception was a breakpoint.
1483 */
1484 int
1485 mach_thread_for_breakpoint (mid)
1486 int mid;
1487 {
1488 int cmid = map_port_name_to_mid (current_thread, MACH_TYPE_THREAD);
1489
1490 if (mid < 0)
1491 {
1492 mid = map_slot_to_mid (-(mid+1), 0, 0);
1493 if (mid < 0)
1494 return 0; /* Don't stop, no such slot */
1495 }
1496
1497 if (! mid || cmid == -1)
1498 return 1; /* stop */
1499
1500 return cmid == mid && stop_exception == EXC_BREAKPOINT;
1501 }
1502 #endif /* THREAD_ALLOWED_TO_BREAK */
1503
1504 #ifdef THREAD_PARSE_ID
1505 /*
1506 * Map a thread id string (MID or a @SLOTNUMBER)
1507 * to a thread-id.
1508 *
1509 * 0 matches all threads.
1510 * Otherwise the meaning is defined only in this file.
1511 * (mach_thread_for_breakpoint uses it)
1512 *
1513 * @@ This allows non-existent MIDs to be specified.
1514 * It now also allows non-existent slots to be
1515 * specified. (Slot numbers stored are negative,
1516 * and the magnitude is one greater than the actual
1517 * slot index. (Since 0 is reserved))
1518 */
1519 int
1520 mach_thread_parse_id (arg)
1521 char *arg;
1522 {
1523 int mid;
1524 if (arg == 0)
1525 error ("thread id excpected");
1526 mid = parse_thread_id (arg, 0, 1);
1527
1528 return mid;
1529 }
1530 #endif /* THREAD_PARSE_ID */
1531
1532 #ifdef THREAD_OUTPUT_ID
1533 char *
1534 mach_thread_output_id (mid)
1535 int mid;
1536 {
1537 static char foobar [20];
1538
1539 if (mid > 0)
1540 sprintf (foobar, "mid %d", mid);
1541 else if (mid < 0)
1542 sprintf (foobar, "@%d", -(mid+1));
1543 else
1544 sprintf (foobar, "*any thread*");
1545
1546 return foobar;
1547 }
1548 #endif /* THREAD_OUTPUT_ID */
1549
1550 /* Called with hook PREPARE_TO_PROCEED() from infrun.c.
1551 *
1552 * If we have switched threads and stopped at breakpoint return 1 otherwise 0.
1553 *
1554 * if SELECT_IT is nonzero, reselect the thread that was active when
1555 * we stopped at a breakpoint.
1556 *
1557 */
1558
1559 mach3_prepare_to_proceed (select_it)
1560 int select_it;
1561 {
1562 if (stop_thread &&
1563 stop_thread != current_thread &&
1564 stop_exception == EXC_BREAKPOINT)
1565 {
1566 int mid;
1567
1568 if (! select_it)
1569 return 1;
1570
1571 mid = switch_to_thread (stop_thread);
1572
1573 return 1;
1574 }
1575
1576 return 0;
1577 }
1578
1579 /* this stuff here is an upcall via libmach/excServer.c
1580 and mach_really_wait which does the actual upcall.
1581
1582 The code will pass the exception to the inferior if:
1583
1584 - The task that signaled is not the inferior task
1585 (e.g. when debugging another debugger)
1586
1587 - The user has explicitely requested to pass on the exceptions.
1588 (e.g to the default unix exception handler, which maps
1589 exceptions to signals, or the user has her own exception handler)
1590
1591 - If the thread that signaled is being single-stepped and it
1592 has set it's own exception port and the exception is not
1593 EXC_BREAKPOINT. (Maybe this is not desirable?)
1594 */
1595
1596 kern_return_t
1597 catch_exception_raise (port, thread, task, exception, code, subcode)
1598 mach_port_t port;
1599 thread_t thread;
1600 task_t task;
1601 int exception, code, subcode;
1602 {
1603 kern_return_t ret;
1604 boolean_t signal_thread;
1605 int mid = map_port_name_to_mid (thread, MACH_TYPE_THREAD);
1606
1607 if (! MACH_PORT_VALID (thread))
1608 {
1609 /* If the exception was sent and thread dies before we
1610 receive it, THREAD will be MACH_PORT_DEAD
1611 */
1612
1613 current_thread = thread = MACH_PORT_NULL;
1614 error ("Received exception from nonexistent thread");
1615 }
1616
1617 /* Check if the task died in transit.
1618 * @@ Isn't the thread also invalid in such case?
1619 */
1620 if (! MACH_PORT_VALID (task))
1621 {
1622 current_thread = thread = MACH_PORT_NULL;
1623 error ("Received exception from nonexistent task");
1624 }
1625
1626 if (exception < 0 || exception > MAX_EXCEPTION)
1627 fatal ("catch_exception_raise: unknown exception code %d thread %d",
1628 exception,
1629 mid);
1630
1631 if (! MACH_PORT_VALID (inferior_task))
1632 error ("got an exception, but inferior_task is null or dead");
1633
1634 stop_exception = exception;
1635 stop_code = code;
1636 stop_subcode = subcode;
1637 stop_thread = thread;
1638
1639 signal_thread = exception != EXC_BREAKPOINT &&
1640 port == singlestepped_thread_port &&
1641 MACH_PORT_VALID (thread_saved_exception_port);
1642
1643 /* If it was not our inferior or if we want to forward
1644 * the exception to the inferior's handler, do it here
1645 *
1646 * Note: If you have forwarded EXC_BREAKPOINT I trust you know why.
1647 */
1648 if (task != inferior_task ||
1649 signal_thread ||
1650 exception_map [exception].forward)
1651 {
1652 mach_port_t eport = inferior_old_exception_port;
1653
1654 if (signal_thread)
1655 {
1656 /*
1657 GDB now forwards the exeption to thread's original handler,
1658 since the user propably knows what he is doing.
1659 Give a message, though.
1660 */
1661
1662 mach3_exception_actions ((WAITTYPE *)NULL, TRUE, "Thread");
1663 eport = thread_saved_exception_port;
1664 }
1665
1666 /* Send the exception to the original handler */
1667 ret = exception_raise (eport,
1668 thread,
1669 task,
1670 exception,
1671 code,
1672 subcode);
1673
1674 (void) mach_port_deallocate (mach_task_self (), task);
1675 (void) mach_port_deallocate (mach_task_self (), thread);
1676
1677 /* If we come here, we don't want to trace any more, since we
1678 * will never stop for tracing anyway.
1679 */
1680 discard_single_step (thread);
1681
1682 /* Do not stop the inferior */
1683 return ret;
1684 }
1685
1686 /* Now gdb handles the exception */
1687 stopped_in_exception = TRUE;
1688
1689 ret = task_suspend (task);
1690 CHK ("Error suspending inferior after exception", ret);
1691
1692 must_suspend_thread = 0;
1693
1694 if (current_thread != thread)
1695 {
1696 if (MACH_PORT_VALID (singlestepped_thread_port))
1697 /* Cleanup discards single stepping */
1698 error ("Exception from thread %d while singlestepping thread %d",
1699 mid,
1700 map_port_name_to_mid (current_thread, MACH_TYPE_THREAD));
1701
1702 /* Then select the thread that caused the exception */
1703 if (select_thread (inferior_task, mid, 0) != KERN_SUCCESS)
1704 error ("Could not select thread %d causing exception", mid);
1705 else
1706 warning ("Gdb selected thread %d", mid);
1707 }
1708
1709 /* If we receive an exception that is not breakpoint
1710 * exception, we interrupt the single step and return to
1711 * debugger. Trace condition is cleared.
1712 */
1713 if (MACH_PORT_VALID (singlestepped_thread_port))
1714 {
1715 if (stop_exception != EXC_BREAKPOINT)
1716 warning ("Single step interrupted by exception");
1717 else if (port == singlestepped_thread_port)
1718 {
1719 /* Single step exception occurred, remove trace bit
1720 * and return to gdb.
1721 */
1722 if (! MACH_PORT_VALID (current_thread))
1723 error ("Single stepped thread is not valid");
1724
1725 /* Resume threads, but leave the task suspended */
1726 resume_all_threads (0);
1727 }
1728 else
1729 warning ("Breakpoint while single stepping?");
1730
1731 discard_single_step (current_thread);
1732 }
1733
1734 (void) mach_port_deallocate (mach_task_self (), task);
1735 (void) mach_port_deallocate (mach_task_self (), thread);
1736
1737 return KERN_SUCCESS;
1738 }
1739 \f
1740 int
1741 port_valid (port, mask)
1742 mach_port_t port;
1743 int mask;
1744 {
1745 kern_return_t ret;
1746 mach_port_type_t type;
1747
1748 ret = mach_port_type (mach_task_self (),
1749 port,
1750 &type);
1751 if (ret != KERN_SUCCESS || (type & mask) != mask)
1752 return 0;
1753 return 1;
1754 }
1755 \f
1756 /* @@ No vm read cache implemented yet */
1757 boolean_t vm_read_cache_valid = FALSE;
1758
1759 /*
1760 * Read inferior task's LEN bytes from ADDR and copy it to MYADDR
1761 * in gdb's address space.
1762 *
1763 * Return 0 on failure; number of bytes read otherwise.
1764 */
1765 int
1766 mach3_read_inferior (addr, myaddr, length)
1767 CORE_ADDR addr;
1768 char *myaddr;
1769 int length;
1770 {
1771 kern_return_t ret;
1772 vm_address_t low_address = (vm_address_t) trunc_page (addr);
1773 vm_size_t aligned_length =
1774 (vm_size_t) round_page (addr+length) - low_address;
1775 pointer_t copied_memory;
1776 int copy_count;
1777
1778 /* Get memory from inferior with page aligned addresses */
1779 ret = vm_read (inferior_task,
1780 low_address,
1781 aligned_length,
1782 &copied_memory,
1783 &copy_count);
1784 if (ret != KERN_SUCCESS)
1785 {
1786 /* the problem is that the inferior might be killed for whatever reason
1787 * before we go to mach_really_wait. This is one place that ought to
1788 * catch many of those errors.
1789 * @@ A better fix would be to make all external events to GDB
1790 * to arrive via a SINGLE port set. (Including user input!)
1791 */
1792
1793 if (! port_valid (inferior_task, MACH_PORT_TYPE_SEND))
1794 {
1795 m3_kill_inferior ();
1796 error ("Inferior killed (task port invalid)");
1797 }
1798 else
1799 {
1800 #ifdef OSF
1801 extern int errno;
1802 /* valprint.c gives nicer format if this does not
1803 screw it. Eamonn seems to like this, so I enable
1804 it if OSF is defined...
1805 */
1806 warning ("[read inferior %x failed: %s]",
1807 addr, mach_error_string (ret));
1808 errno = 0;
1809 #endif
1810 return 0;
1811 }
1812 }
1813
1814 memcpy (myaddr, (char *)addr - low_address + copied_memory, length);
1815
1816 ret = vm_deallocate (mach_task_self (),
1817 copied_memory,
1818 copy_count);
1819 CHK("mach3_read_inferior vm_deallocate failed", ret);
1820
1821 return length;
1822 }
1823
1824 #ifdef __STDC__
1825 #define CHK_GOTO_OUT(str,ret) \
1826 do if (ret != KERN_SUCCESS) { errstr = #str; goto out; } while(0)
1827 #else
1828 #define CHK_GOTO_OUT(str,ret) \
1829 do if (ret != KERN_SUCCESS) { errstr = str; goto out; } while(0)
1830 #endif
1831
1832 struct vm_region_list {
1833 struct vm_region_list *next;
1834 vm_prot_t protection;
1835 vm_address_t start;
1836 vm_size_t length;
1837 };
1838
1839 struct obstack region_obstack;
1840
1841 /*
1842 * Write inferior task's LEN bytes from ADDR and copy it to MYADDR
1843 * in gdb's address space.
1844 */
1845 int
1846 mach3_write_inferior (addr, myaddr, length)
1847 CORE_ADDR addr;
1848 char *myaddr;
1849 int length;
1850 {
1851 kern_return_t ret;
1852 vm_address_t low_address = (vm_address_t) trunc_page (addr);
1853 vm_size_t aligned_length =
1854 (vm_size_t) round_page (addr+length) - low_address;
1855 pointer_t copied_memory;
1856 int copy_count;
1857 int deallocate = 0;
1858
1859 char *errstr = "Bug in mach3_write_inferior";
1860
1861 struct vm_region_list *region_element;
1862 struct vm_region_list *region_head = (struct vm_region_list *)NULL;
1863
1864 /* Get memory from inferior with page aligned addresses */
1865 ret = vm_read (inferior_task,
1866 low_address,
1867 aligned_length,
1868 &copied_memory,
1869 &copy_count);
1870 CHK_GOTO_OUT ("mach3_write_inferior vm_read failed", ret);
1871
1872 deallocate++;
1873
1874 memcpy ((char *)addr - low_address + copied_memory, myaddr, length);
1875
1876 obstack_init (&region_obstack);
1877
1878 /* Do writes atomically.
1879 * First check for holes and unwritable memory.
1880 */
1881 {
1882 vm_size_t remaining_length = aligned_length;
1883 vm_address_t region_address = low_address;
1884
1885 struct vm_region_list *scan;
1886
1887 while(region_address < low_address + aligned_length)
1888 {
1889 vm_prot_t protection;
1890 vm_prot_t max_protection;
1891 vm_inherit_t inheritance;
1892 boolean_t shared;
1893 mach_port_t object_name;
1894 vm_offset_t offset;
1895 vm_size_t region_length = remaining_length;
1896 vm_address_t old_address = region_address;
1897
1898 ret = vm_region (inferior_task,
1899 &region_address,
1900 &region_length,
1901 &protection,
1902 &max_protection,
1903 &inheritance,
1904 &shared,
1905 &object_name,
1906 &offset);
1907 CHK_GOTO_OUT ("vm_region failed", ret);
1908
1909 /* Check for holes in memory */
1910 if (old_address != region_address)
1911 {
1912 warning ("No memory at 0x%x. Nothing written",
1913 old_address);
1914 ret = KERN_SUCCESS;
1915 length = 0;
1916 goto out;
1917 }
1918
1919 if (!(max_protection & VM_PROT_WRITE))
1920 {
1921 warning ("Memory at address 0x%x is unwritable. Nothing written",
1922 old_address);
1923 ret = KERN_SUCCESS;
1924 length = 0;
1925 goto out;
1926 }
1927
1928 /* Chain the regions for later use */
1929 region_element =
1930 (struct vm_region_list *)
1931 obstack_alloc (&region_obstack, sizeof (struct vm_region_list));
1932
1933 region_element->protection = protection;
1934 region_element->start = region_address;
1935 region_element->length = region_length;
1936
1937 /* Chain the regions along with protections */
1938 region_element->next = region_head;
1939 region_head = region_element;
1940
1941 region_address += region_length;
1942 remaining_length = remaining_length - region_length;
1943 }
1944
1945 /* If things fail after this, we give up.
1946 * Somebody is messing up inferior_task's mappings.
1947 */
1948
1949 /* Enable writes to the chained vm regions */
1950 for (scan = region_head; scan; scan = scan->next)
1951 {
1952 boolean_t protection_changed = FALSE;
1953
1954 if (!(scan->protection & VM_PROT_WRITE))
1955 {
1956 ret = vm_protect (inferior_task,
1957 scan->start,
1958 scan->length,
1959 FALSE,
1960 scan->protection | VM_PROT_WRITE);
1961 CHK_GOTO_OUT ("vm_protect: enable write failed", ret);
1962 }
1963 }
1964
1965 ret = vm_write (inferior_task,
1966 low_address,
1967 copied_memory,
1968 aligned_length);
1969 CHK_GOTO_OUT ("vm_write failed", ret);
1970
1971 /* Set up the original region protections, if they were changed */
1972 for (scan = region_head; scan; scan = scan->next)
1973 {
1974 boolean_t protection_changed = FALSE;
1975
1976 if (!(scan->protection & VM_PROT_WRITE))
1977 {
1978 ret = vm_protect (inferior_task,
1979 scan->start,
1980 scan->length,
1981 FALSE,
1982 scan->protection);
1983 CHK_GOTO_OUT ("vm_protect: enable write failed", ret);
1984 }
1985 }
1986 }
1987
1988 out:
1989 if (deallocate)
1990 {
1991 obstack_free (&region_obstack, 0);
1992
1993 (void) vm_deallocate (mach_task_self (),
1994 copied_memory,
1995 copy_count);
1996 }
1997
1998 if (ret != KERN_SUCCESS)
1999 {
2000 warning ("%s %s", errstr, mach_error_string (ret));
2001 return 0;
2002 }
2003
2004 return length;
2005 }
2006
2007 /* Return 0 on failure, number of bytes handled otherwise. */
2008 static int
2009 m3_xfer_memory (memaddr, myaddr, len, write, target)
2010 CORE_ADDR memaddr;
2011 char *myaddr;
2012 int len;
2013 int write;
2014 struct target_ops *target; /* IGNORED */
2015 {
2016 int result;
2017
2018 if (write)
2019 result = mach3_write_inferior (memaddr, myaddr, len);
2020 else
2021 result = mach3_read_inferior (memaddr, myaddr, len);
2022
2023 return result;
2024 }
2025
2026 \f
2027 static char *
2028 translate_state(state)
2029 int state;
2030 {
2031 switch (state) {
2032 case TH_STATE_RUNNING: return("R");
2033 case TH_STATE_STOPPED: return("S");
2034 case TH_STATE_WAITING: return("W");
2035 case TH_STATE_UNINTERRUPTIBLE: return("U");
2036 case TH_STATE_HALTED: return("H");
2037 default: return("?");
2038 }
2039 }
2040
2041 static char *
2042 translate_cstate (state)
2043 int state;
2044 {
2045 switch (state)
2046 {
2047 case CPROC_RUNNING: return "R";
2048 case CPROC_SWITCHING: return "S";
2049 case CPROC_BLOCKED: return "B";
2050 case CPROC_CONDWAIT: return "C";
2051 case CPROC_CONDWAIT|CPROC_SWITCHING: return "CS";
2052 default: return "?";
2053 }
2054 }
2055
2056 /* type == MACH_MSG_TYPE_COPY_SEND || type == MACH_MSG_TYPE_MAKE_SEND */
2057
2058 mach_port_t /* no mach_port_name_t found in include files. */
2059 map_inferior_port_name (inferior_name, type)
2060 mach_port_t inferior_name;
2061 mach_msg_type_name_t type;
2062 {
2063 kern_return_t ret;
2064 mach_msg_type_name_t acquired;
2065 mach_port_t iport;
2066
2067 ret = mach_port_extract_right (inferior_task,
2068 inferior_name,
2069 type,
2070 &iport,
2071 &acquired);
2072 CHK("mach_port_extract_right (map_inferior_port_name)", ret);
2073
2074 if (acquired != MACH_MSG_TYPE_PORT_SEND)
2075 error("Incorrect right extracted, (map_inferior_port_name)");
2076
2077 ret = mach_port_deallocate (mach_task_self (),
2078 iport);
2079 CHK ("Deallocating mapped port (map_inferior_port_name)", ret);
2080
2081 return iport;
2082 }
2083
2084 /*
2085 * Naming convention:
2086 * Always return user defined name if found.
2087 * _K == A kernel thread with no matching CPROC
2088 * _C == A cproc with no current cthread
2089 * _t == A cthread with no user defined name
2090 *
2091 * The digits that follow the _names are the SLOT number of the
2092 * kernel thread if there is such a thing, otherwise just a negation
2093 * of the sequential number of such cprocs.
2094 */
2095
2096 static char buf[7];
2097
2098 static char *
2099 get_thread_name (one_cproc, id)
2100 gdb_thread_t one_cproc;
2101 int id;
2102 {
2103 if (one_cproc)
2104 if (one_cproc->cthread == NULL)
2105 {
2106 /* cproc not mapped to any cthread */
2107 sprintf(buf, "_C%d", id);
2108 }
2109 else if (! one_cproc->cthread->name)
2110 {
2111 /* cproc and cthread, but no name */
2112 sprintf(buf, "_t%d", id);
2113 }
2114 else
2115 return (one_cproc->cthread->name);
2116 else
2117 {
2118 if (id < 0)
2119 warning ("Inconsistency in thread name id %d", id);
2120
2121 /* Kernel thread without cproc */
2122 sprintf(buf, "_K%d", id);
2123 }
2124
2125 return buf;
2126 }
2127
2128 int
2129 fetch_thread_info (task, mthreads_out)
2130 mach_port_t task;
2131 gdb_thread_t *mthreads_out; /* out */
2132 {
2133 kern_return_t ret;
2134 thread_array_t th_table;
2135 int th_count;
2136 gdb_thread_t mthreads = NULL;
2137 int index;
2138
2139 ret = task_threads (task, &th_table, &th_count);
2140 if (ret != KERN_SUCCESS)
2141 {
2142 warning ("Error getting inferior's thread list:%s",
2143 mach_error_string(ret));
2144 m3_kill_inferior ();
2145 return -1;
2146 }
2147
2148 mthreads = (gdb_thread_t)
2149 obstack_alloc
2150 (cproc_obstack,
2151 th_count * sizeof (struct gdb_thread));
2152
2153 for (index = 0; index < th_count; index++)
2154 {
2155 thread_t saved_thread = MACH_PORT_NULL;
2156 int mid;
2157
2158 if (must_suspend_thread)
2159 setup_thread (th_table[ index ], 1);
2160
2161 if (th_table[index] != current_thread)
2162 {
2163 saved_thread = current_thread;
2164
2165 mid = switch_to_thread (th_table[ index ]);
2166 }
2167
2168 mthreads[index].name = th_table[index];
2169 mthreads[index].cproc = NULL; /* map_cprocs_to_kernel_threads() */
2170 mthreads[index].in_emulator = FALSE;
2171 mthreads[index].slotid = index;
2172
2173 mthreads[index].sp = read_register (SP_REGNUM);
2174 mthreads[index].fp = read_register (FP_REGNUM);
2175 mthreads[index].pc = read_pc ();
2176
2177 if (MACH_PORT_VALID (saved_thread))
2178 mid = switch_to_thread (saved_thread);
2179
2180 if (must_suspend_thread)
2181 setup_thread (th_table[ index ], 0);
2182 }
2183
2184 consume_send_rights (th_table, th_count);
2185 ret = vm_deallocate (mach_task_self(), (vm_address_t)th_table,
2186 (th_count * sizeof(mach_port_t)));
2187 if (ret != KERN_SUCCESS)
2188 {
2189 warning ("Error trying to deallocate thread list : %s",
2190 mach_error_string (ret));
2191 }
2192
2193 *mthreads_out = mthreads;
2194
2195 return th_count;
2196 }
2197
2198
2199 /*
2200 * Current emulator always saves the USP on top of
2201 * emulator stack below struct emul_stack_top stuff.
2202 */
2203 CORE_ADDR
2204 fetch_usp_from_emulator_stack (sp)
2205 CORE_ADDR sp;
2206 {
2207 CORE_ADDR stack_pointer;
2208
2209 sp = (sp & ~(EMULATOR_STACK_SIZE-1)) +
2210 EMULATOR_STACK_SIZE - sizeof (struct emul_stack_top);
2211
2212 if (mach3_read_inferior (sp,
2213 &stack_pointer,
2214 sizeof (CORE_ADDR)) != sizeof (CORE_ADDR))
2215 {
2216 warning ("Can't read user sp from emulator stack address 0x%x", sp);
2217 return 0;
2218 }
2219
2220 return stack_pointer;
2221 }
2222
2223 #ifdef MK67
2224
2225 /* get_emulation_vector() interface was changed after mk67 */
2226 #define EMUL_VECTOR_COUNT 400 /* Value does not matter too much */
2227
2228 #endif /* MK67 */
2229
2230 /* Check if the emulator exists at task's address space.
2231 */
2232 boolean_t
2233 have_emulator_p (task)
2234 task_t task;
2235 {
2236 kern_return_t ret;
2237 #ifndef EMUL_VECTOR_COUNT
2238 vm_offset_t *emulation_vector;
2239 int n;
2240 #else
2241 vm_offset_t emulation_vector[ EMUL_VECTOR_COUNT ];
2242 int n = EMUL_VECTOR_COUNT;
2243 #endif
2244 int i;
2245 int vector_start;
2246
2247 ret = task_get_emulation_vector (task,
2248 &vector_start,
2249 #ifndef EMUL_VECTOR_COUNT
2250 &emulation_vector,
2251 #else
2252 emulation_vector,
2253 #endif
2254 &n);
2255 CHK("task_get_emulation_vector", ret);
2256 xx_debug ("%d vectors from %d at 0x%08x\n",
2257 n, vector_start, emulation_vector);
2258
2259 for(i = 0; i < n; i++)
2260 {
2261 vm_offset_t entry = emulation_vector [i];
2262
2263 if (EMULATOR_BASE <= entry && entry <= EMULATOR_END)
2264 return TRUE;
2265 else if (entry)
2266 {
2267 static boolean_t informed = FALSE;
2268 if (!informed)
2269 {
2270 warning("Emulation vector address 0x08%x outside emulator space",
2271 entry);
2272 informed = TRUE;
2273 }
2274 }
2275 }
2276 return FALSE;
2277 }
2278
2279 /* Map cprocs to kernel threads and vice versa. */
2280
2281 void
2282 map_cprocs_to_kernel_threads (cprocs, mthreads, thread_count)
2283 gdb_thread_t cprocs;
2284 gdb_thread_t mthreads;
2285 int thread_count;
2286 {
2287 int index;
2288 gdb_thread_t scan;
2289 boolean_t all_mapped = TRUE;
2290 LONGEST stack_base;
2291 LONGEST stack_size;
2292
2293 for (scan = cprocs; scan; scan = scan->next)
2294 {
2295 /* Default to: no kernel thread for this cproc */
2296 scan->reverse_map = -1;
2297
2298 /* Check if the cproc is found by its stack */
2299 for (index = 0; index < thread_count; index++)
2300 {
2301 stack_base =
2302 extract_signed_integer (scan->raw_cproc + CPROC_BASE_OFFSET,
2303 CPROC_BASE_SIZE);
2304 stack_size =
2305 extract_signed_integer (scan->raw_cproc + CPROC_SIZE_OFFSET,
2306 CPROC_SIZE_SIZE);
2307 if ((mthreads + index)->sp > stack_base &&
2308 (mthreads + index)->sp <= stack_base + stack_size)
2309 {
2310 (mthreads + index)->cproc = scan;
2311 scan->reverse_map = index;
2312 break;
2313 }
2314 }
2315 all_mapped &= (scan->reverse_map != -1);
2316 }
2317
2318 /* Check for threads that are currently in the emulator.
2319 * If so, they have a different stack, and the still unmapped
2320 * cprocs may well get mapped to these threads.
2321 *
2322 * If:
2323 * - cproc stack does not match any kernel thread stack pointer
2324 * - there is at least one extra kernel thread
2325 * that has no cproc mapped above.
2326 * - some kernel thread stack pointer points to emulator space
2327 * then we find the user stack pointer saved in the emulator
2328 * stack, and try to map that to the cprocs.
2329 *
2330 * Also set in_emulator for kernel threads.
2331 */
2332
2333 if (emulator_present)
2334 {
2335 for (index = 0; index < thread_count; index++)
2336 {
2337 CORE_ADDR emul_sp;
2338 CORE_ADDR usp;
2339
2340 gdb_thread_t mthread = (mthreads+index);
2341 emul_sp = mthread->sp;
2342
2343 if (mthread->cproc == NULL &&
2344 EMULATOR_BASE <= emul_sp && emul_sp <= EMULATOR_END)
2345 {
2346 mthread->in_emulator = emulator_present;
2347
2348 if (!all_mapped && cprocs)
2349 {
2350 usp = fetch_usp_from_emulator_stack (emul_sp);
2351
2352 /* @@ Could be more accurate */
2353 if (! usp)
2354 error ("Zero stack pointer read from emulator?");
2355
2356 /* Try to match this stack pointer to the cprocs that
2357 * don't yet have a kernel thread.
2358 */
2359 for (scan = cprocs; scan; scan = scan->next)
2360 {
2361
2362 /* Check is this unmapped CPROC stack contains
2363 * the user stack pointer saved in the
2364 * emulator.
2365 */
2366 if (scan->reverse_map == -1)
2367 {
2368 stack_base =
2369 extract_signed_integer
2370 (scan->raw_cproc + CPROC_BASE_OFFSET,
2371 CPROC_BASE_SIZE);
2372 stack_size =
2373 extract_signed_integer
2374 (scan->raw_cproc + CPROC_SIZE_OFFSET,
2375 CPROC_SIZE_SIZE);
2376 if (usp > stack_base &&
2377 usp <= stack_base + stack_size)
2378 {
2379 mthread->cproc = scan;
2380 scan->reverse_map = index;
2381 break;
2382 }
2383 }
2384 }
2385 }
2386 }
2387 }
2388 }
2389 }
2390 \f
2391 /*
2392 * Format of the thread_list command
2393 *
2394 * slot mid sel name emul ks susp cstate wired address
2395 */
2396 #define TL_FORMAT "%-2.2s %5d%c %-10.10s %1.1s%s%-5.5s %-2.2s %-5.5s "
2397
2398 #define TL_HEADER "\n@ MID Name KState CState Where\n"
2399
2400 void
2401 print_tl_address (stream, pc)
2402 GDB_FILE *stream;
2403 CORE_ADDR pc;
2404 {
2405 if (! lookup_minimal_symbol_by_pc (pc))
2406 fprintf_filtered (stream, local_hex_format(), pc);
2407 else
2408 {
2409 extern int addressprint;
2410 extern int asm_demangle;
2411
2412 int store = addressprint;
2413 addressprint = 0;
2414 print_address_symbolic (pc, stream, asm_demangle, "");
2415 addressprint = store;
2416 }
2417 }
2418 \f
2419 /* For thread names, but also for gdb_message_port external name */
2420 #define MAX_NAME_LEN 50
2421
2422 /* Returns the address of variable NAME or 0 if not found */
2423 CORE_ADDR
2424 lookup_address_of_variable (name)
2425 char *name;
2426 {
2427 struct symbol *sym;
2428 CORE_ADDR symaddr = 0;
2429 struct minimal_symbol *msymbol;
2430
2431 sym = lookup_symbol (name,
2432 (struct block *)NULL,
2433 VAR_NAMESPACE,
2434 (int *)NULL,
2435 (struct symtab **)NULL);
2436
2437 if (sym)
2438 symaddr = SYMBOL_VALUE (sym);
2439
2440 if (! symaddr)
2441 {
2442 msymbol = lookup_minimal_symbol (name, (struct objfile *) NULL);
2443
2444 if (msymbol && msymbol->type == mst_data)
2445 symaddr = SYMBOL_VALUE_ADDRESS (msymbol);
2446 }
2447
2448 return symaddr;
2449 }
2450
2451 static gdb_thread_t
2452 get_cprocs()
2453 {
2454 gdb_thread_t cproc_head;
2455 gdb_thread_t cproc_copy;
2456 CORE_ADDR their_cprocs;
2457 char *buf[TARGET_PTR_BIT / HOST_CHAR_BIT];
2458 char *name;
2459 cthread_t cthread;
2460 CORE_ADDR symaddr;
2461
2462 symaddr = lookup_address_of_variable ("cproc_list");
2463
2464 if (! symaddr)
2465 {
2466 /* cproc_list is not in a file compiled with debugging
2467 symbols, but don't give up yet */
2468
2469 symaddr = lookup_address_of_variable ("cprocs");
2470
2471 if (symaddr)
2472 {
2473 static int informed = 0;
2474 if (!informed)
2475 {
2476 informed++;
2477 warning ("Your program is loaded with an old threads library.");
2478 warning ("GDB does not know the old form of threads");
2479 warning ("so things may not work.");
2480 }
2481 }
2482 }
2483
2484 /* Stripped or no -lthreads loaded or "cproc_list" is in wrong segment. */
2485 if (! symaddr)
2486 return NULL;
2487
2488 /* Get the address of the first cproc in the task */
2489 if (!mach3_read_inferior (symaddr,
2490 buf,
2491 TARGET_PTR_BIT / HOST_CHAR_BIT))
2492 error ("Can't read cproc master list at address (0x%x).", symaddr);
2493 their_cprocs = extract_address (buf, TARGET_PTR_BIT / HOST_CHAR_BIT);
2494
2495 /* Scan the CPROCs in the task.
2496 CPROCs are chained with LIST field, not NEXT field, which
2497 chains mutexes, condition variables and queues */
2498
2499 cproc_head = NULL;
2500
2501 while (their_cprocs != (CORE_ADDR)0)
2502 {
2503 CORE_ADDR cproc_copy_incarnation;
2504 cproc_copy = (gdb_thread_t) obstack_alloc (cproc_obstack,
2505 sizeof (struct gdb_thread));
2506
2507 if (!mach3_read_inferior (their_cprocs,
2508 &cproc_copy->raw_cproc[0],
2509 CPROC_SIZE))
2510 error("Can't read next cproc at 0x%x.", their_cprocs);
2511
2512 their_cprocs =
2513 extract_address (cproc_copy->raw_cproc + CPROC_LIST_OFFSET,
2514 CPROC_LIST_SIZE);
2515 cproc_copy_incarnation =
2516 extract_address (cproc_copy->raw_cproc + CPROC_INCARNATION_OFFSET,
2517 CPROC_INCARNATION_SIZE);
2518
2519 if (cproc_copy_incarnation == (CORE_ADDR)0)
2520 cproc_copy->cthread = NULL;
2521 else
2522 {
2523 /* This CPROC has an attached CTHREAD. Get its name */
2524 cthread = (cthread_t)obstack_alloc (cproc_obstack,
2525 sizeof(struct cthread));
2526
2527 if (!mach3_read_inferior (cproc_copy_incarnation,
2528 cthread,
2529 sizeof(struct cthread)))
2530 error("Can't read next thread at 0x%x.",
2531 cproc_copy_incarnation);
2532
2533 cproc_copy->cthread = cthread;
2534
2535 if (cthread->name)
2536 {
2537 name = (char *) obstack_alloc (cproc_obstack, MAX_NAME_LEN);
2538
2539 if (!mach3_read_inferior(cthread->name, name, MAX_NAME_LEN))
2540 error("Can't read next thread's name at 0x%x.", cthread->name);
2541
2542 cthread->name = name;
2543 }
2544 }
2545
2546 /* insert in front */
2547 cproc_copy->next = cproc_head;
2548 cproc_head = cproc_copy;
2549 }
2550 return cproc_head;
2551 }
2552
2553 #ifndef FETCH_CPROC_STATE
2554 /*
2555 * Check if your machine does not grok the way this routine
2556 * fetches the FP,PC and SP of a cproc that is not
2557 * currently attached to any kernel thread (e.g. its cproc.context
2558 * field points to the place in stack where the context
2559 * is saved).
2560 *
2561 * If it doesn't, define your own routine.
2562 */
2563 #define FETCH_CPROC_STATE(mth) mach3_cproc_state (mth)
2564
2565 int
2566 mach3_cproc_state (mthread)
2567 gdb_thread_t mthread;
2568 {
2569 int context;
2570
2571 if (! mthread || !mthread->cproc)
2572 return -1;
2573
2574 context = extract_signed_integer
2575 (mthread->cproc->raw_cproc + CPROC_CONTEXT_OFFSET,
2576 CPROC_CONTEXT_SIZE);
2577 if (context == 0)
2578 return -1;
2579
2580 mthread->sp = context + MACHINE_CPROC_SP_OFFSET;
2581
2582 if (mach3_read_inferior (context + MACHINE_CPROC_PC_OFFSET,
2583 &mthread->pc,
2584 sizeof (CORE_ADDR)) != sizeof (CORE_ADDR))
2585 {
2586 warning ("Can't read cproc pc from inferior");
2587 return -1;
2588 }
2589
2590 if (mach3_read_inferior (context + MACHINE_CPROC_FP_OFFSET,
2591 &mthread->fp,
2592 sizeof (CORE_ADDR)) != sizeof (CORE_ADDR))
2593 {
2594 warning ("Can't read cproc fp from inferior");
2595 return -1;
2596 }
2597
2598 return 0;
2599 }
2600 #endif /* FETCH_CPROC_STATE */
2601
2602 \f
2603 void
2604 thread_list_command()
2605 {
2606 thread_basic_info_data_t ths;
2607 int thread_count;
2608 gdb_thread_t cprocs;
2609 gdb_thread_t scan;
2610 int index;
2611 char *name;
2612 char selected;
2613 char *wired;
2614 int infoCnt;
2615 kern_return_t ret;
2616 mach_port_t mid_or_port;
2617 gdb_thread_t their_threads;
2618 gdb_thread_t kthread;
2619
2620 int neworder = 1;
2621
2622 char *fmt = "There are %d kernel threads in task %d.\n";
2623
2624 int tmid = map_port_name_to_mid (inferior_task, MACH_TYPE_TASK);
2625
2626 MACH_ERROR_NO_INFERIOR;
2627
2628 thread_count = fetch_thread_info (inferior_task,
2629 &their_threads);
2630 if (thread_count == -1)
2631 return;
2632
2633 if (thread_count == 1)
2634 fmt = "There is %d kernel thread in task %d.\n";
2635
2636 printf_filtered (fmt, thread_count, tmid);
2637
2638 puts_filtered (TL_HEADER);
2639
2640 cprocs = get_cprocs();
2641
2642 map_cprocs_to_kernel_threads (cprocs, their_threads, thread_count);
2643
2644 for (scan = cprocs; scan; scan = scan->next)
2645 {
2646 int mid;
2647 char buf[10];
2648 char slot[3];
2649 int cproc_state =
2650 extract_signed_integer
2651 (scan->raw_cproc + CPROC_STATE_OFFSET, CPROC_STATE_SIZE);
2652
2653 selected = ' ';
2654
2655 /* a wired cproc? */
2656 wired = (extract_address (scan->raw_cproc + CPROC_WIRED_OFFSET,
2657 CPROC_WIRED_SIZE)
2658 ? "wired" : "");
2659
2660 if (scan->reverse_map != -1)
2661 kthread = (their_threads + scan->reverse_map);
2662 else
2663 kthread = NULL;
2664
2665 if (kthread)
2666 {
2667 /* These cprocs have a kernel thread */
2668
2669 mid = map_port_name_to_mid (kthread->name, MACH_TYPE_THREAD);
2670
2671 infoCnt = THREAD_BASIC_INFO_COUNT;
2672
2673 ret = thread_info (kthread->name,
2674 THREAD_BASIC_INFO,
2675 (thread_info_t)&ths,
2676 &infoCnt);
2677
2678 if (ret != KERN_SUCCESS)
2679 {
2680 warning ("Unable to get basic info on thread %d : %s",
2681 mid,
2682 mach_error_string (ret));
2683 continue;
2684 }
2685
2686 /* Who is the first to have more than 100 threads */
2687 sprintf (slot, "%d", kthread->slotid%100);
2688
2689 if (kthread->name == current_thread)
2690 selected = '*';
2691
2692 if (ths.suspend_count)
2693 sprintf (buf, "%d", ths.suspend_count);
2694 else
2695 buf[0] = '\000';
2696
2697 #if 0
2698 if (ths.flags & TH_FLAGS_SWAPPED)
2699 strcat (buf, "S");
2700 #endif
2701
2702 if (ths.flags & TH_FLAGS_IDLE)
2703 strcat (buf, "I");
2704
2705 /* FIXME: May run afloul of arbitrary limit in printf_filtered. */
2706 printf_filtered (TL_FORMAT,
2707 slot,
2708 mid,
2709 selected,
2710 get_thread_name (scan, kthread->slotid),
2711 kthread->in_emulator ? "E" : "",
2712 translate_state (ths.run_state),
2713 buf,
2714 translate_cstate (cproc_state),
2715 wired);
2716 print_tl_address (gdb_stdout, kthread->pc);
2717 }
2718 else
2719 {
2720 /* These cprocs don't have a kernel thread.
2721 * find out the calling frame with
2722 * FETCH_CPROC_STATE.
2723 */
2724
2725 struct gdb_thread state;
2726
2727 #if 0
2728 /* jtv -> emcmanus: why do you want this here? */
2729 if (scan->incarnation == NULL)
2730 continue; /* EMcM */
2731 #endif
2732
2733 /* FIXME: May run afloul of arbitrary limit in printf_filtered. */
2734 printf_filtered (TL_FORMAT,
2735 "-",
2736 -neworder, /* Pseudo MID */
2737 selected,
2738 get_thread_name (scan, -neworder),
2739 "",
2740 "-", /* kernel state */
2741 "",
2742 translate_cstate (cproc_state),
2743 "");
2744 state.cproc = scan;
2745
2746 if (FETCH_CPROC_STATE (&state) == -1)
2747 puts_filtered ("???");
2748 else
2749 print_tl_address (gdb_stdout, state.pc);
2750
2751 neworder++;
2752 }
2753 puts_filtered ("\n");
2754 }
2755
2756 /* Scan for kernel threads without cprocs */
2757 for (index = 0; index < thread_count; index++)
2758 {
2759 if (! their_threads[index].cproc)
2760 {
2761 int mid;
2762
2763 char buf[10];
2764 char slot[3];
2765
2766 mach_port_t name = their_threads[index].name;
2767
2768 mid = map_port_name_to_mid (name, MACH_TYPE_THREAD);
2769
2770 infoCnt = THREAD_BASIC_INFO_COUNT;
2771
2772 ret = thread_info(name,
2773 THREAD_BASIC_INFO,
2774 (thread_info_t)&ths,
2775 &infoCnt);
2776
2777 if (ret != KERN_SUCCESS)
2778 {
2779 warning ("Unable to get basic info on thread %d : %s",
2780 mid,
2781 mach_error_string (ret));
2782 continue;
2783 }
2784
2785 sprintf (slot, "%d", index%100);
2786
2787 if (name == current_thread)
2788 selected = '*';
2789 else
2790 selected = ' ';
2791
2792 if (ths.suspend_count)
2793 sprintf (buf, "%d", ths.suspend_count);
2794 else
2795 buf[0] = '\000';
2796
2797 #if 0
2798 if (ths.flags & TH_FLAGS_SWAPPED)
2799 strcat (buf, "S");
2800 #endif
2801
2802 if (ths.flags & TH_FLAGS_IDLE)
2803 strcat (buf, "I");
2804
2805 /* FIXME: May run afloul of arbitrary limit in printf_filtered. */
2806 printf_filtered (TL_FORMAT,
2807 slot,
2808 mid,
2809 selected,
2810 get_thread_name (NULL, index),
2811 their_threads[index].in_emulator ? "E" : "",
2812 translate_state (ths.run_state),
2813 buf,
2814 "", /* No cproc state */
2815 ""); /* Can't be wired */
2816 print_tl_address (gdb_stdout, their_threads[index].pc);
2817 puts_filtered ("\n");
2818 }
2819 }
2820
2821 obstack_free (cproc_obstack, 0);
2822 obstack_init (cproc_obstack);
2823 }
2824 \f
2825 void
2826 thread_select_command(args, from_tty)
2827 char *args;
2828 int from_tty;
2829 {
2830 int mid;
2831 thread_array_t thread_list;
2832 int thread_count;
2833 kern_return_t ret;
2834 int is_slot = 0;
2835
2836 MACH_ERROR_NO_INFERIOR;
2837
2838 if (!args)
2839 error_no_arg ("MID or @SLOTNUMBER to specify a thread to select");
2840
2841 while (*args == ' ' || *args == '\t')
2842 args++;
2843
2844 if (*args == '@')
2845 {
2846 is_slot++;
2847 args++;
2848 }
2849
2850 mid = atoi(args);
2851
2852 if (mid == 0)
2853 if (!is_slot || *args != '0') /* Rudimentary checks */
2854 error ("You must select threads by MID or @SLOTNUMBER");
2855
2856 if (select_thread (inferior_task, mid, is_slot?2:1) != KERN_SUCCESS)
2857 return;
2858
2859 if (from_tty)
2860 printf_filtered ("Thread %d selected\n",
2861 is_slot ? map_port_name_to_mid (current_thread,
2862 MACH_TYPE_THREAD) : mid);
2863 }
2864 \f
2865 thread_trace (thread, set)
2866 mach_port_t thread;
2867 boolean_t set;
2868 {
2869 int flavor = TRACE_FLAVOR;
2870 unsigned int stateCnt = TRACE_FLAVOR_SIZE;
2871 kern_return_t ret;
2872 thread_state_data_t state;
2873
2874 if (! MACH_PORT_VALID (thread))
2875 {
2876 warning ("thread_trace: invalid thread");
2877 return;
2878 }
2879
2880 if (must_suspend_thread)
2881 setup_thread (thread, 1);
2882
2883 ret = thread_get_state(thread, flavor, state, &stateCnt);
2884 CHK ("thread_trace: error reading thread state", ret);
2885
2886 if (set)
2887 {
2888 TRACE_SET (thread, state);
2889 }
2890 else
2891 {
2892 if (! TRACE_CLEAR (thread, state))
2893 {
2894 if (must_suspend_thread)
2895 setup_thread (thread, 0);
2896 return;
2897 }
2898 }
2899
2900 ret = thread_set_state(thread, flavor, state, stateCnt);
2901 CHK ("thread_trace: error writing thread state", ret);
2902 if (must_suspend_thread)
2903 setup_thread (thread, 0);
2904 }
2905
2906 #ifdef FLUSH_INFERIOR_CACHE
2907
2908 /* When over-writing code on some machines the I-Cache must be flushed
2909 explicitly, because it is not kept coherent by the lazy hardware.
2910 This definitely includes breakpoints, for instance, or else we
2911 end up looping in mysterious Bpt traps */
2912
2913 flush_inferior_icache(pc, amount)
2914 CORE_ADDR pc;
2915 {
2916 vm_machine_attribute_val_t flush = MATTR_VAL_ICACHE_FLUSH;
2917 kern_return_t ret;
2918
2919 ret = vm_machine_attribute (inferior_task,
2920 pc,
2921 amount,
2922 MATTR_CACHE,
2923 &flush);
2924 if (ret != KERN_SUCCESS)
2925 warning ("Error flushing inferior's cache : %s",
2926 mach_error_string (ret));
2927 }
2928 #endif FLUSH_INFERIOR_CACHE
2929
2930 \f
2931 static
2932 suspend_all_threads (from_tty)
2933 int from_tty;
2934 {
2935 kern_return_t ret;
2936 thread_array_t thread_list;
2937 int thread_count, index;
2938 int infoCnt;
2939 thread_basic_info_data_t th_info;
2940
2941
2942 ret = task_threads (inferior_task, &thread_list, &thread_count);
2943 if (ret != KERN_SUCCESS)
2944 {
2945 warning ("Could not suspend inferior threads.");
2946 m3_kill_inferior ();
2947 return_to_top_level ();
2948 }
2949
2950 for (index = 0; index < thread_count; index++)
2951 {
2952 int mid;
2953
2954 mid = map_port_name_to_mid (thread_list[ index ],
2955 MACH_TYPE_THREAD);
2956
2957 ret = thread_suspend(thread_list[ index ]);
2958
2959 if (ret != KERN_SUCCESS)
2960 warning ("Error trying to suspend thread %d : %s",
2961 mid, mach_error_string (ret));
2962
2963 if (from_tty)
2964 {
2965 infoCnt = THREAD_BASIC_INFO_COUNT;
2966 ret = thread_info (thread_list[ index ],
2967 THREAD_BASIC_INFO,
2968 (thread_info_t) &th_info,
2969 &infoCnt);
2970 CHK ("suspend can't get thread info", ret);
2971
2972 warning ("Thread %d suspend count is %d",
2973 mid, th_info.suspend_count);
2974 }
2975 }
2976
2977 consume_send_rights (thread_list, thread_count);
2978 ret = vm_deallocate(mach_task_self(),
2979 (vm_address_t)thread_list,
2980 (thread_count * sizeof(int)));
2981 CHK ("Error trying to deallocate thread list", ret);
2982 }
2983
2984 void
2985 thread_suspend_command (args, from_tty)
2986 char *args;
2987 int from_tty;
2988 {
2989 kern_return_t ret;
2990 int mid;
2991 mach_port_t saved_thread;
2992 int infoCnt;
2993 thread_basic_info_data_t th_info;
2994
2995 MACH_ERROR_NO_INFERIOR;
2996
2997 if (!strcasecmp (args, "all")) {
2998 suspend_all_threads (from_tty);
2999 return;
3000 }
3001
3002 saved_thread = current_thread;
3003
3004 mid = parse_thread_id (args, 0, 0);
3005
3006 if (mid < 0)
3007 error ("You can suspend only existing kernel threads with MID or @SLOTNUMBER");
3008
3009 if (mid == 0)
3010 mid = map_port_name_to_mid (current_thread, MACH_TYPE_THREAD);
3011 else
3012 if (select_thread (inferior_task, mid, 0) != KERN_SUCCESS)
3013 {
3014 if (current_thread)
3015 current_thread = saved_thread;
3016 error ("Could not select thread %d", mid);
3017 }
3018
3019 ret = thread_suspend (current_thread);
3020 if (ret != KERN_SUCCESS)
3021 warning ("thread_suspend failed : %s",
3022 mach_error_string (ret));
3023
3024 infoCnt = THREAD_BASIC_INFO_COUNT;
3025 ret = thread_info (current_thread,
3026 THREAD_BASIC_INFO,
3027 (thread_info_t) &th_info,
3028 &infoCnt);
3029 CHK ("suspend can't get thread info", ret);
3030
3031 warning ("Thread %d suspend count is %d", mid, th_info.suspend_count);
3032
3033 current_thread = saved_thread;
3034 }
3035
3036 resume_all_threads (from_tty)
3037 int from_tty;
3038 {
3039 kern_return_t ret;
3040 thread_array_t thread_list;
3041 int thread_count, index;
3042 int mid;
3043 int infoCnt;
3044 thread_basic_info_data_t th_info;
3045
3046 ret = task_threads (inferior_task, &thread_list, &thread_count);
3047 if (ret != KERN_SUCCESS)
3048 {
3049 m3_kill_inferior ();
3050 error("task_threads", mach_error_string( ret));
3051 }
3052
3053 for (index = 0; index < thread_count; index++)
3054 {
3055 infoCnt = THREAD_BASIC_INFO_COUNT;
3056 ret = thread_info (thread_list [ index ],
3057 THREAD_BASIC_INFO,
3058 (thread_info_t) &th_info,
3059 &infoCnt);
3060 CHK ("resume_all can't get thread info", ret);
3061
3062 mid = map_port_name_to_mid (thread_list[ index ],
3063 MACH_TYPE_THREAD);
3064
3065 if (! th_info.suspend_count)
3066 {
3067 if (mid != -1 && from_tty)
3068 warning ("Thread %d is not suspended", mid);
3069 continue;
3070 }
3071
3072 ret = thread_resume (thread_list[ index ]);
3073
3074 if (ret != KERN_SUCCESS)
3075 warning ("Error trying to resume thread %d : %s",
3076 mid, mach_error_string (ret));
3077 else if (mid != -1 && from_tty)
3078 warning ("Thread %d suspend count is %d",
3079 mid, --th_info.suspend_count);
3080 }
3081
3082 consume_send_rights (thread_list, thread_count);
3083 ret = vm_deallocate(mach_task_self(),
3084 (vm_address_t)thread_list,
3085 (thread_count * sizeof(int)));
3086 CHK("Error trying to deallocate thread list", ret);
3087 }
3088
3089 void
3090 thread_resume_command (args, from_tty)
3091 char *args;
3092 int from_tty;
3093 {
3094 int mid;
3095 mach_port_t saved_thread;
3096 kern_return_t ret;
3097 thread_basic_info_data_t th_info;
3098 int infoCnt = THREAD_BASIC_INFO_COUNT;
3099
3100 MACH_ERROR_NO_INFERIOR;
3101
3102 if (!strcasecmp (args, "all")) {
3103 resume_all_threads (from_tty);
3104 return;
3105 }
3106
3107 saved_thread = current_thread;
3108
3109 mid = parse_thread_id (args, 0, 0);
3110
3111 if (mid < 0)
3112 error ("You can resume only existing kernel threads with MID or @SLOTNUMBER");
3113
3114 if (mid == 0)
3115 mid = map_port_name_to_mid (current_thread, MACH_TYPE_THREAD);
3116 else
3117 if (select_thread (inferior_task, mid, 0) != KERN_SUCCESS)
3118 {
3119 if (current_thread)
3120 current_thread = saved_thread;
3121 return_to_top_level ();
3122 }
3123
3124 ret = thread_info (current_thread,
3125 THREAD_BASIC_INFO,
3126 (thread_info_t) &th_info,
3127 &infoCnt);
3128 CHK ("resume can't get thread info", ret);
3129
3130 if (! th_info.suspend_count)
3131 {
3132 warning ("Thread %d is not suspended", mid);
3133 goto out;
3134 }
3135
3136 ret = thread_resume (current_thread);
3137 if (ret != KERN_SUCCESS)
3138 warning ("thread_resume failed : %s",
3139 mach_error_string (ret));
3140 else
3141 {
3142 th_info.suspend_count--;
3143 warning ("Thread %d suspend count is %d", mid, th_info.suspend_count);
3144 }
3145
3146 out:
3147 current_thread = saved_thread;
3148 }
3149
3150 void
3151 thread_kill_command (args, from_tty)
3152 char *args;
3153 int from_tty;
3154 {
3155 int mid;
3156 kern_return_t ret;
3157 int thread_count;
3158 thread_array_t thread_table;
3159 int index;
3160 mach_port_t thread_to_kill = MACH_PORT_NULL;
3161
3162
3163 MACH_ERROR_NO_INFERIOR;
3164
3165 if (!args)
3166 error_no_arg ("thread mid to kill from the inferior task");
3167
3168 mid = parse_thread_id (args, 0, 0);
3169
3170 if (mid < 0)
3171 error ("You can kill only existing kernel threads with MID or @SLOTNUMBER");
3172
3173 if (mid)
3174 {
3175 ret = machid_mach_port (mid_server, mid_auth, mid, &thread_to_kill);
3176 CHK ("thread_kill_command: machid_mach_port map failed", ret);
3177 }
3178 else
3179 mid = map_port_name_to_mid (current_thread, MACH_TYPE_THREAD);
3180
3181 /* Don't allow gdb to kill *any* thread in the system. Use mkill program for that */
3182 ret = task_threads (inferior_task, &thread_table, &thread_count);
3183 CHK ("Error getting inferior's thread list", ret);
3184
3185 if (thread_to_kill == current_thread)
3186 {
3187 ret = thread_terminate (thread_to_kill);
3188 CHK ("Thread could not be terminated", ret);
3189
3190 if (select_thread (inferior_task, 0, 1) != KERN_SUCCESS)
3191 warning ("Last thread was killed, use \"kill\" command to kill task");
3192 }
3193 else
3194 for (index = 0; index < thread_count; index++)
3195 if (thread_table [ index ] == thread_to_kill)
3196 {
3197 ret = thread_terminate (thread_to_kill);
3198 CHK ("Thread could not be terminated", ret);
3199 }
3200
3201 if (thread_count > 1)
3202 consume_send_rights (thread_table, thread_count);
3203
3204 ret = vm_deallocate (mach_task_self(), (vm_address_t)thread_table,
3205 (thread_count * sizeof(mach_port_t)));
3206 CHK ("Error trying to deallocate thread list", ret);
3207
3208 warning ("Thread %d killed", mid);
3209 }
3210
3211 \f
3212 /* Task specific commands; add more if you like */
3213
3214 void
3215 task_resume_command (args, from_tty)
3216 char *args;
3217 int from_tty;
3218 {
3219 kern_return_t ret;
3220 task_basic_info_data_t ta_info;
3221 int infoCnt = TASK_BASIC_INFO_COUNT;
3222 int mid = map_port_name_to_mid (inferior_task, MACH_TYPE_TASK);
3223
3224 MACH_ERROR_NO_INFERIOR;
3225
3226 /* Would be trivial to change, but is it desirable? */
3227 if (args)
3228 error ("Currently gdb can resume only it's inferior task");
3229
3230 ret = task_info (inferior_task,
3231 TASK_BASIC_INFO,
3232 (task_info_t) &ta_info,
3233 &infoCnt);
3234 CHK ("task_resume_command: task_info failed", ret);
3235
3236 if (ta_info.suspend_count == 0)
3237 error ("Inferior task %d is not suspended", mid);
3238 else if (ta_info.suspend_count == 1 &&
3239 from_tty &&
3240 !query ("Suspend count is now 1. Do you know what you are doing? "))
3241 error ("Task not resumed");
3242
3243 ret = task_resume (inferior_task);
3244 CHK ("task_resume_command: task_resume", ret);
3245
3246 if (ta_info.suspend_count == 1)
3247 {
3248 warning ("Inferior task %d is no longer suspended", mid);
3249 must_suspend_thread = 1;
3250 /* @@ This is not complete: Registers change all the time when not
3251 suspended! */
3252 registers_changed ();
3253 }
3254 else
3255 warning ("Inferior task %d suspend count is now %d",
3256 mid, ta_info.suspend_count-1);
3257 }
3258
3259
3260 void
3261 task_suspend_command (args, from_tty)
3262 char *args;
3263 int from_tty;
3264 {
3265 kern_return_t ret;
3266 task_basic_info_data_t ta_info;
3267 int infoCnt = TASK_BASIC_INFO_COUNT;
3268 int mid = map_port_name_to_mid (inferior_task, MACH_TYPE_TASK);
3269
3270 MACH_ERROR_NO_INFERIOR;
3271
3272 /* Would be trivial to change, but is it desirable? */
3273 if (args)
3274 error ("Currently gdb can suspend only it's inferior task");
3275
3276 ret = task_suspend (inferior_task);
3277 CHK ("task_suspend_command: task_suspend", ret);
3278
3279 must_suspend_thread = 0;
3280
3281 ret = task_info (inferior_task,
3282 TASK_BASIC_INFO,
3283 (task_info_t) &ta_info,
3284 &infoCnt);
3285 CHK ("task_suspend_command: task_info failed", ret);
3286
3287 warning ("Inferior task %d suspend count is now %d",
3288 mid, ta_info.suspend_count);
3289 }
3290
3291 static char *
3292 get_size (bytes)
3293 int bytes;
3294 {
3295 static char size [ 30 ];
3296 int zz = bytes/1024;
3297
3298 if (zz / 1024)
3299 sprintf (size, "%-2.1f M", ((float)bytes)/(1024.0*1024.0));
3300 else
3301 sprintf (size, "%d K", zz);
3302
3303 return size;
3304 }
3305
3306 /* Does this require the target task to be suspended?? I don't think so. */
3307 void
3308 task_info_command (args, from_tty)
3309 char *args;
3310 int from_tty;
3311 {
3312 int mid = -5;
3313 mach_port_t task;
3314 kern_return_t ret;
3315 task_basic_info_data_t ta_info;
3316 int infoCnt = TASK_BASIC_INFO_COUNT;
3317 int page_size = round_page(1);
3318 int thread_count = 0;
3319
3320 if (MACH_PORT_VALID (inferior_task))
3321 mid = map_port_name_to_mid (inferior_task,
3322 MACH_TYPE_TASK);
3323
3324 task = inferior_task;
3325
3326 if (args)
3327 {
3328 int tmid = atoi (args);
3329
3330 if (tmid <= 0)
3331 error ("Invalid mid %d for task info", tmid);
3332
3333 if (tmid != mid)
3334 {
3335 mid = tmid;
3336 ret = machid_mach_port (mid_server, mid_auth, tmid, &task);
3337 CHK ("task_info_command: machid_mach_port map failed", ret);
3338 }
3339 }
3340
3341 if (mid < 0)
3342 error ("You have to give the task MID as an argument");
3343
3344 ret = task_info (task,
3345 TASK_BASIC_INFO,
3346 (task_info_t) &ta_info,
3347 &infoCnt);
3348 CHK ("task_info_command: task_info failed", ret);
3349
3350 printf_filtered ("\nTask info for task %d:\n\n", mid);
3351 printf_filtered (" Suspend count : %d\n", ta_info.suspend_count);
3352 printf_filtered (" Base priority : %d\n", ta_info.base_priority);
3353 printf_filtered (" Virtual size : %s\n", get_size (ta_info.virtual_size));
3354 printf_filtered (" Resident size : %s\n", get_size (ta_info.resident_size));
3355
3356 {
3357 thread_array_t thread_list;
3358
3359 ret = task_threads (task, &thread_list, &thread_count);
3360 CHK ("task_info_command: task_threads", ret);
3361
3362 printf_filtered (" Thread count : %d\n", thread_count);
3363
3364 consume_send_rights (thread_list, thread_count);
3365 ret = vm_deallocate(mach_task_self(),
3366 (vm_address_t)thread_list,
3367 (thread_count * sizeof(int)));
3368 CHK("Error trying to deallocate thread list", ret);
3369 }
3370 if (have_emulator_p (task))
3371 printf_filtered (" Emulator at : 0x%x..0x%x\n",
3372 EMULATOR_BASE, EMULATOR_END);
3373 else
3374 printf_filtered (" No emulator.\n");
3375
3376 if (thread_count && task == inferior_task)
3377 printf_filtered ("\nUse the \"thread list\" command to see the threads\n");
3378 }
3379 \f
3380 /* You may either FORWARD the exception to the inferior, or KEEP
3381 * it and return to GDB command level.
3382 *
3383 * exception mid [ forward | keep ]
3384 */
3385
3386 static void
3387 exception_command (args, from_tty)
3388 char *args;
3389 int from_tty;
3390 {
3391 char *scan = args;
3392 int exception;
3393 int len;
3394
3395 if (!args)
3396 error_no_arg ("exception number action");
3397
3398 while (*scan == ' ' || *scan == '\t') scan++;
3399
3400 if ('0' <= *scan && *scan <= '9')
3401 while ('0' <= *scan && *scan <= '9')
3402 scan++;
3403 else
3404 error ("exception number action");
3405
3406 exception = atoi (args);
3407 if (exception <= 0 || exception > MAX_EXCEPTION)
3408 error ("Allowed exception numbers are in range 1..%d",
3409 MAX_EXCEPTION);
3410
3411 if (*scan != ' ' && *scan != '\t')
3412 error ("exception number must be followed by a space");
3413 else
3414 while (*scan == ' ' || *scan == '\t') scan++;
3415
3416 args = scan;
3417 len = 0;
3418 while (*scan)
3419 {
3420 len++;
3421 scan++;
3422 }
3423
3424 if (!len)
3425 error("exception number action");
3426
3427 if (!strncasecmp (args, "forward", len))
3428 exception_map[ exception ].forward = TRUE;
3429 else if (!strncasecmp (args, "keep", len))
3430 exception_map[ exception ].forward = FALSE;
3431 else
3432 error ("exception action is either \"keep\" or \"forward\"");
3433 }
3434
3435 static void
3436 print_exception_info (exception)
3437 int exception;
3438 {
3439 boolean_t forward = exception_map[ exception ].forward;
3440
3441 printf_filtered ("%s\t(%d): ", exception_map[ exception ].name,
3442 exception);
3443 if (!forward)
3444 if (exception_map[ exception ].sigmap != SIG_UNKNOWN)
3445 printf_filtered ("keep and handle as signal %d\n",
3446 exception_map[ exception ].sigmap);
3447 else
3448 printf_filtered ("keep and handle as unknown signal %d\n",
3449 exception_map[ exception ].sigmap);
3450 else
3451 printf_filtered ("forward exception to inferior\n");
3452 }
3453
3454 void
3455 exception_info (args, from_tty)
3456 char *args;
3457 int from_tty;
3458 {
3459 int exception;
3460
3461 if (!args)
3462 for (exception = 1; exception <= MAX_EXCEPTION; exception++)
3463 print_exception_info (exception);
3464 else
3465 {
3466 exception = atoi (args);
3467
3468 if (exception <= 0 || exception > MAX_EXCEPTION)
3469 error ("Invalid exception number, values from 1 to %d allowed",
3470 MAX_EXCEPTION);
3471 print_exception_info (exception);
3472 }
3473 }
3474 \f
3475 /* Check for actions for mach exceptions.
3476 */
3477 mach3_exception_actions (w, force_print_only, who)
3478 WAITTYPE *w;
3479 boolean_t force_print_only;
3480 char *who;
3481 {
3482 boolean_t force_print = FALSE;
3483
3484
3485 if (force_print_only ||
3486 exception_map[stop_exception].sigmap == SIG_UNKNOWN)
3487 force_print = TRUE;
3488 else
3489 WSETSTOP (*w, exception_map[stop_exception].sigmap);
3490
3491 if (exception_map[stop_exception].print || force_print)
3492 {
3493 target_terminal_ours ();
3494
3495 printf_filtered ("\n%s received %s exception : ",
3496 who,
3497 exception_map[stop_exception].name);
3498
3499 wrap_here (" ");
3500
3501 switch(stop_exception) {
3502 case EXC_BAD_ACCESS:
3503 printf_filtered ("referencing address 0x%x : %s\n",
3504 stop_subcode,
3505 mach_error_string (stop_code));
3506 break;
3507 case EXC_BAD_INSTRUCTION:
3508 printf_filtered
3509 ("illegal or undefined instruction. code %d subcode %d\n",
3510 stop_code, stop_subcode);
3511 break;
3512 case EXC_ARITHMETIC:
3513 printf_filtered ("code %d\n", stop_code);
3514 break;
3515 case EXC_EMULATION:
3516 printf_filtered ("code %d subcode %d\n", stop_code, stop_subcode);
3517 break;
3518 case EXC_SOFTWARE:
3519 printf_filtered ("%s specific, code 0x%x\n",
3520 stop_code < 0xffff ? "hardware" : "os emulation",
3521 stop_code);
3522 break;
3523 case EXC_BREAKPOINT:
3524 printf_filtered ("type %d (machine dependent)\n",
3525 stop_code);
3526 break;
3527 default:
3528 fatal ("Unknown exception");
3529 }
3530 }
3531 }
3532 \f
3533 setup_notify_port (create_new)
3534 int create_new;
3535 {
3536 kern_return_t ret;
3537
3538 if (MACH_PORT_VALID (our_notify_port))
3539 {
3540 ret = mach_port_destroy (mach_task_self (), our_notify_port);
3541 CHK ("Could not destroy our_notify_port", ret);
3542 }
3543
3544 our_notify_port = MACH_PORT_NULL;
3545 notify_chain = (port_chain_t) NULL;
3546 port_chain_destroy (port_chain_obstack);
3547
3548 if (create_new)
3549 {
3550 ret = mach_port_allocate (mach_task_self(),
3551 MACH_PORT_RIGHT_RECEIVE,
3552 &our_notify_port);
3553 if (ret != KERN_SUCCESS)
3554 fatal("Creating notify port %s", mach_error_string(ret));
3555
3556 ret = mach_port_move_member(mach_task_self(),
3557 our_notify_port,
3558 inferior_wait_port_set);
3559 if (ret != KERN_SUCCESS)
3560 fatal("initial move member %s",mach_error_string(ret));
3561 }
3562 }
3563
3564 /*
3565 * Register our message port to the net name server
3566 *
3567 * Currently used only by the external stop-gdb program
3568 * since ^C does not work if you would like to enter
3569 * gdb command level while debugging your program.
3570 *
3571 * NOTE: If the message port is sometimes used for other
3572 * purposes also, the NAME must not be a guessable one.
3573 * Then, there should be a way to change it.
3574 */
3575
3576 char registered_name[ MAX_NAME_LEN ];
3577
3578 void
3579 message_port_info (args, from_tty)
3580 char *args;
3581 int from_tty;
3582 {
3583 if (registered_name[0])
3584 printf_filtered ("gdb's message port name: '%s'\n",
3585 registered_name);
3586 else
3587 printf_filtered ("gdb's message port is not currently registered\n");
3588 }
3589
3590 void
3591 gdb_register_port (name, port)
3592 char *name;
3593 mach_port_t port;
3594 {
3595 kern_return_t ret;
3596 static int already_signed = 0;
3597 int len;
3598
3599 if (! MACH_PORT_VALID (port) || !name || !*name)
3600 {
3601 warning ("Invalid registration request");
3602 return;
3603 }
3604
3605 if (! already_signed)
3606 {
3607 ret = mach_port_insert_right (mach_task_self (),
3608 our_message_port,
3609 our_message_port,
3610 MACH_MSG_TYPE_MAKE_SEND);
3611 CHK ("Failed to create a signature to our_message_port", ret);
3612 already_signed = 1;
3613 }
3614 else if (already_signed > 1)
3615 {
3616 ret = netname_check_out (name_server_port,
3617 registered_name,
3618 our_message_port);
3619 CHK ("Failed to check out gdb's message port", ret);
3620 registered_name[0] = '\000';
3621 already_signed = 1;
3622 }
3623
3624 ret = netname_check_in (name_server_port, /* Name server port */
3625 name, /* Name of service */
3626 our_message_port, /* Signature */
3627 port); /* Creates a new send right */
3628 CHK("Failed to check in the port", ret);
3629
3630 len = 0;
3631 while(len < MAX_NAME_LEN && *(name+len))
3632 {
3633 registered_name[len] = *(name+len);
3634 len++;
3635 }
3636 registered_name[len] = '\000';
3637 already_signed = 2;
3638 }
3639
3640 struct cmd_list_element *cmd_thread_list;
3641 struct cmd_list_element *cmd_task_list;
3642
3643 /*ARGSUSED*/
3644 static void
3645 thread_command (arg, from_tty)
3646 char *arg;
3647 int from_tty;
3648 {
3649 printf_unfiltered ("\"thread\" must be followed by the name of a thread command.\n");
3650 help_list (cmd_thread_list, "thread ", -1, gdb_stdout);
3651 }
3652
3653 /*ARGSUSED*/
3654 static void
3655 task_command (arg, from_tty)
3656 char *arg;
3657 int from_tty;
3658 {
3659 printf_unfiltered ("\"task\" must be followed by the name of a task command.\n");
3660 help_list (cmd_task_list, "task ", -1, gdb_stdout);
3661 }
3662
3663 add_mach_specific_commands ()
3664 {
3665 extern void condition_thread ();
3666
3667 /* Thread handling commands */
3668
3669 /* FIXME: Move our thread support into the generic thread.c stuff so we
3670 can share that code. */
3671 add_prefix_cmd ("mthread", class_stack, thread_command,
3672 "Generic command for handling Mach threads in the debugged task.",
3673 &cmd_thread_list, "thread ", 0, &cmdlist);
3674
3675 add_com_alias ("th", "mthread", class_stack, 1);
3676
3677 add_cmd ("select", class_stack, thread_select_command,
3678 "Select and print MID of the selected thread",
3679 &cmd_thread_list);
3680 add_cmd ("list", class_stack, thread_list_command,
3681 "List info of task's threads. Selected thread is marked with '*'",
3682 &cmd_thread_list);
3683 add_cmd ("suspend", class_run, thread_suspend_command,
3684 "Suspend one or all of the threads in the selected task.",
3685 &cmd_thread_list);
3686 add_cmd ("resume", class_run, thread_resume_command,
3687 "Resume one or all of the threads in the selected task.",
3688 &cmd_thread_list);
3689 add_cmd ("kill", class_run, thread_kill_command,
3690 "Kill the specified thread MID from inferior task.",
3691 &cmd_thread_list);
3692 add_cmd ("break", class_breakpoint, condition_thread,
3693 "Breakpoint N will only be effective for thread MID or @SLOT\n\
3694 If MID/@SLOT is omitted allow all threads to break at breakpoint",
3695 &cmd_thread_list);
3696 /* Thread command shorthands (for backward compatibility) */
3697 add_alias_cmd ("ts", "mthread select", 0, 0, &cmdlist);
3698 add_alias_cmd ("tl", "mthread list", 0, 0, &cmdlist);
3699
3700 /* task handling commands */
3701
3702 add_prefix_cmd ("task", class_stack, task_command,
3703 "Generic command for handling debugged task.",
3704 &cmd_task_list, "task ", 0, &cmdlist);
3705
3706 add_com_alias ("ta", "task", class_stack, 1);
3707
3708 add_cmd ("suspend", class_run, task_suspend_command,
3709 "Suspend the inferior task.",
3710 &cmd_task_list);
3711 add_cmd ("resume", class_run, task_resume_command,
3712 "Resume the inferior task.",
3713 &cmd_task_list);
3714 add_cmd ("info", no_class, task_info_command,
3715 "Print information about the specified task.",
3716 &cmd_task_list);
3717
3718 /* Print my message port name */
3719
3720 add_info ("message-port", message_port_info,
3721 "Returns the name of gdb's message port in the netnameserver");
3722
3723 /* Exception commands */
3724
3725 add_info ("exceptions", exception_info,
3726 "What debugger does when program gets various exceptions.\n\
3727 Specify an exception number as argument to print info on that\n\
3728 exception only.");
3729
3730 add_com ("exception", class_run, exception_command,
3731 "Specify how to handle an exception.\n\
3732 Args are exception number followed by \"forward\" or \"keep\".\n\
3733 `Forward' means forward the exception to the program's normal exception\n\
3734 handler.\n\
3735 `Keep' means reenter debugger if this exception happens, and GDB maps\n\
3736 the exception to some signal (see info exception)\n\
3737 Normally \"keep\" is used to return to GDB on exception.");
3738 }
3739
3740 kern_return_t
3741 do_mach_notify_dead_name (notify, name)
3742 mach_port_t notify;
3743 mach_port_t name;
3744 {
3745 kern_return_t kr = KERN_SUCCESS;
3746
3747 /* Find the thing that notified */
3748 port_chain_t element = port_chain_member (notify_chain, name);
3749
3750 /* Take name of from unreceived dead name notification list */
3751 notify_chain = port_chain_delete (notify_chain, name);
3752
3753 if (! element)
3754 error ("Received a dead name notify from unchained port (0x%x)", name);
3755
3756 switch (element->type) {
3757
3758 case MACH_TYPE_THREAD:
3759 target_terminal_ours_for_output ();
3760 if (name == current_thread)
3761 {
3762 printf_filtered ("\nCurrent thread %d died", element->mid);
3763 current_thread = MACH_PORT_NULL;
3764 }
3765 else
3766 printf_filtered ("\nThread %d died", element->mid);
3767
3768 break;
3769
3770 case MACH_TYPE_TASK:
3771 target_terminal_ours_for_output ();
3772 if (name != inferior_task)
3773 printf_filtered ("Task %d died, but it was not the selected task",
3774 element->mid);
3775 else
3776 {
3777 printf_filtered ("Current task %d died", element->mid);
3778
3779 mach_port_destroy (mach_task_self(), name);
3780 inferior_task = MACH_PORT_NULL;
3781
3782 if (notify_chain)
3783 warning ("There were still unreceived dead_name_notifications???");
3784
3785 /* Destroy the old notifications */
3786 setup_notify_port (0);
3787
3788 }
3789 break;
3790
3791 default:
3792 error ("Unregistered dead_name 0x%x notification received. Type is %d, mid is 0x%x",
3793 name, element->type, element->mid);
3794 break;
3795 }
3796
3797 return KERN_SUCCESS;
3798 }
3799
3800 kern_return_t
3801 do_mach_notify_msg_accepted (notify, name)
3802 mach_port_t notify;
3803 mach_port_t name;
3804 {
3805 warning ("do_mach_notify_msg_accepted : notify %x, name %x",
3806 notify, name);
3807 return KERN_SUCCESS;
3808 }
3809
3810 kern_return_t
3811 do_mach_notify_no_senders (notify, mscount)
3812 mach_port_t notify;
3813 mach_port_mscount_t mscount;
3814 {
3815 warning ("do_mach_notify_no_senders : notify %x, mscount %x",
3816 notify, mscount);
3817 return KERN_SUCCESS;
3818 }
3819
3820 kern_return_t
3821 do_mach_notify_port_deleted (notify, name)
3822 mach_port_t notify;
3823 mach_port_t name;
3824 {
3825 warning ("do_mach_notify_port_deleted : notify %x, name %x",
3826 notify, name);
3827 return KERN_SUCCESS;
3828 }
3829
3830 kern_return_t
3831 do_mach_notify_port_destroyed (notify, rights)
3832 mach_port_t notify;
3833 mach_port_t rights;
3834 {
3835 warning ("do_mach_notify_port_destroyed : notify %x, rights %x",
3836 notify, rights);
3837 return KERN_SUCCESS;
3838 }
3839
3840 kern_return_t
3841 do_mach_notify_send_once (notify)
3842 mach_port_t notify;
3843 {
3844 #ifdef DUMP_SYSCALL
3845 /* MANY of these are generated. */
3846 warning ("do_mach_notify_send_once : notify %x",
3847 notify);
3848 #endif
3849 return KERN_SUCCESS;
3850 }
3851
3852 /* Kills the inferior. It's gone when you call this */
3853 static void
3854 kill_inferior_fast ()
3855 {
3856 WAITTYPE w;
3857
3858 if (inferior_pid == 0 || inferior_pid == 1)
3859 return;
3860
3861 /* kill() it, since the Unix server does not otherwise notice when
3862 * killed with task_terminate().
3863 */
3864 if (inferior_pid > 0)
3865 kill (inferior_pid, SIGKILL);
3866
3867 /* It's propably terminate already */
3868 (void) task_terminate (inferior_task);
3869
3870 inferior_task = MACH_PORT_NULL;
3871 current_thread = MACH_PORT_NULL;
3872
3873 wait3 (&w, WNOHANG, 0);
3874
3875 setup_notify_port (0);
3876 }
3877
3878 static void
3879 m3_kill_inferior ()
3880 {
3881 kill_inferior_fast ();
3882 target_mourn_inferior ();
3883 }
3884
3885 /* Clean up after the inferior dies. */
3886
3887 static void
3888 m3_mourn_inferior ()
3889 {
3890 unpush_target (&m3_ops);
3891 generic_mourn_inferior ();
3892 }
3893
3894 \f
3895 /* Fork an inferior process, and start debugging it. */
3896
3897 static void
3898 m3_create_inferior (exec_file, allargs, env)
3899 char *exec_file;
3900 char *allargs;
3901 char **env;
3902 {
3903 fork_inferior (exec_file, allargs, env, m3_trace_me, m3_trace_him, NULL);
3904 /* We are at the first instruction we care about. */
3905 /* Pedal to the metal... */
3906 proceed ((CORE_ADDR) -1, 0, 0);
3907 }
3908
3909 /* Mark our target-struct as eligible for stray "run" and "attach"
3910 commands. */
3911 static int
3912 m3_can_run ()
3913 {
3914 return 1;
3915 }
3916 \f
3917 /* Mach 3.0 does not need ptrace for anything
3918 * Make sure nobody uses it on mach.
3919 */
3920 ptrace (a,b,c,d)
3921 int a,b,c,d;
3922 {
3923 error ("Lose, Lose! Somebody called ptrace\n");
3924 }
3925
3926 /* Resume execution of the inferior process.
3927 If STEP is nonzero, single-step it.
3928 If SIGNAL is nonzero, give it that signal. */
3929
3930 void
3931 m3_resume (pid, step, signal)
3932 int pid;
3933 int step;
3934 enum target_signal signal;
3935 {
3936 kern_return_t ret;
3937
3938 if (step)
3939 {
3940 thread_basic_info_data_t th_info;
3941 unsigned int infoCnt = THREAD_BASIC_INFO_COUNT;
3942
3943 /* There is no point in single stepping when current_thread
3944 * is dead.
3945 */
3946 if (! MACH_PORT_VALID (current_thread))
3947 error ("No thread selected; can not single step");
3948
3949 /* If current_thread is suspended, tracing it would never return.
3950 */
3951 ret = thread_info (current_thread,
3952 THREAD_BASIC_INFO,
3953 (thread_info_t) &th_info,
3954 &infoCnt);
3955 CHK ("child_resume: can't get thread info", ret);
3956
3957 if (th_info.suspend_count)
3958 error ("Can't trace a suspended thread. Use \"thread resume\" command to resume it");
3959 }
3960
3961 vm_read_cache_valid = FALSE;
3962
3963 if (signal && inferior_pid > 0) /* Do not signal, if attached by MID */
3964 kill (inferior_pid, target_signal_to_host (signal));
3965
3966 if (step)
3967 {
3968 suspend_all_threads (0);
3969
3970 setup_single_step (current_thread, TRUE);
3971
3972 ret = thread_resume (current_thread);
3973 CHK ("thread_resume", ret);
3974 }
3975
3976 ret = task_resume (inferior_task);
3977 if (ret == KERN_FAILURE)
3978 warning ("Task was not suspended");
3979 else
3980 CHK ("Resuming task", ret);
3981
3982 /* HACK HACK This is needed by the multiserver system HACK HACK */
3983 while ((ret = task_resume(inferior_task)) == KERN_SUCCESS)
3984 /* make sure it really runs */;
3985 /* HACK HACK This is needed by the multiserver system HACK HACK */
3986 }
3987 \f
3988 #ifdef ATTACH_DETACH
3989
3990 /* Start debugging the process with the given task */
3991 void
3992 task_attach (tid)
3993 task_t tid;
3994 {
3995 kern_return_t ret;
3996 inferior_task = tid;
3997
3998 ret = task_suspend (inferior_task);
3999 CHK("task_attach: task_suspend", ret);
4000
4001 must_suspend_thread = 0;
4002
4003 setup_notify_port (1);
4004
4005 request_notify (inferior_task, MACH_NOTIFY_DEAD_NAME, MACH_TYPE_TASK);
4006
4007 setup_exception_port ();
4008
4009 emulator_present = have_emulator_p (inferior_task);
4010
4011 attach_flag = 1;
4012 }
4013
4014 /* Well, we can call error also here and leave the
4015 * target stack inconsistent. Sigh.
4016 * Fix this sometime (the only way to fail here is that
4017 * the task has no threads at all, which is rare, but
4018 * possible; or if the target task has died, which is also
4019 * possible, but unlikely, since it has been suspended.
4020 * (Someone must have killed it))
4021 */
4022 void
4023 attach_to_thread ()
4024 {
4025 if (select_thread (inferior_task, 0, 1) != KERN_SUCCESS)
4026 error ("Could not select any threads to attach to");
4027 }
4028
4029 mid_attach (mid)
4030 int mid;
4031 {
4032 kern_return_t ret;
4033
4034 ret = machid_mach_port (mid_server, mid_auth, mid, &inferior_task);
4035 CHK("mid_attach: machid_mach_port", ret);
4036
4037 task_attach (inferior_task);
4038
4039 return mid;
4040 }
4041
4042 /*
4043 * Start debugging the process whose unix process-id is PID.
4044 * A negative "pid" value is legal and signifies a mach_id not a unix pid.
4045 *
4046 * Prevent (possible unwanted) dangerous operations by enabled users
4047 * like "atta 0" or "atta foo" (equal to the previous :-) and
4048 * "atta pidself". Anyway, the latter is allowed by specifying a MID.
4049 */
4050 static int
4051 m3_do_attach (pid)
4052 int pid;
4053 {
4054 kern_return_t ret;
4055
4056 if (pid == 0)
4057 error("MID=0, Debugging the master unix server does not compute");
4058
4059 /* Foo. This assumes gdb has a unix pid */
4060 if (pid == getpid())
4061 error ("I will debug myself only by mid. (Gdb would suspend itself!)");
4062
4063 if (pid < 0)
4064 {
4065 mid_attach (-(pid));
4066
4067 /* inferior_pid will be NEGATIVE! */
4068 inferior_pid = pid;
4069
4070 return inferior_pid;
4071 }
4072
4073 inferior_task = task_by_pid (pid);
4074 if (! MACH_PORT_VALID (inferior_task))
4075 error("Cannot map Unix pid %d to Mach task port", pid);
4076
4077 task_attach (inferior_task);
4078
4079 inferior_pid = pid;
4080
4081 return inferior_pid;
4082 }
4083
4084 /* Attach to process PID, then initialize for debugging it
4085 and wait for the trace-trap that results from attaching. */
4086
4087 static void
4088 m3_attach (args, from_tty)
4089 char *args;
4090 int from_tty;
4091 {
4092 char *exec_file;
4093 int pid;
4094
4095 if (!args)
4096 error_no_arg ("process-id to attach");
4097
4098 pid = atoi (args);
4099
4100 if (pid == getpid()) /* Trying to masturbate? */
4101 error ("I refuse to debug myself!");
4102
4103 if (from_tty)
4104 {
4105 exec_file = (char *) get_exec_file (0);
4106
4107 if (exec_file)
4108 printf_unfiltered ("Attaching to program `%s', %s\n", exec_file, target_pid_to_str (pid));
4109 else
4110 printf_unfiltered ("Attaching to %s\n", target_pid_to_str (pid));
4111
4112 gdb_flush (gdb_stdout);
4113 }
4114
4115 m3_do_attach (pid);
4116 inferior_pid = pid;
4117 push_target (&m3_ops);
4118 }
4119 \f
4120 void
4121 deallocate_inferior_ports ()
4122 {
4123 kern_return_t ret;
4124 thread_array_t thread_list;
4125 int thread_count, index;
4126
4127 if (!MACH_PORT_VALID (inferior_task))
4128 return;
4129
4130 ret = task_threads (inferior_task, &thread_list, &thread_count);
4131 if (ret != KERN_SUCCESS)
4132 {
4133 warning ("deallocate_inferior_ports: task_threads",
4134 mach_error_string(ret));
4135 return;
4136 }
4137
4138 /* Get rid of send rights to task threads */
4139 for (index = 0; index < thread_count; index++)
4140 {
4141 int rights;
4142 ret = mach_port_get_refs (mach_task_self (),
4143 thread_list[index],
4144 MACH_PORT_RIGHT_SEND,
4145 &rights);
4146 CHK("deallocate_inferior_ports: get refs", ret);
4147
4148 if (rights > 0)
4149 {
4150 ret = mach_port_mod_refs (mach_task_self (),
4151 thread_list[index],
4152 MACH_PORT_RIGHT_SEND,
4153 -rights);
4154 CHK("deallocate_inferior_ports: mod refs", ret);
4155 }
4156 }
4157
4158 ret = mach_port_mod_refs (mach_task_self (),
4159 inferior_exception_port,
4160 MACH_PORT_RIGHT_RECEIVE,
4161 -1);
4162 CHK ("deallocate_inferior_ports: cannot get rid of exception port", ret);
4163
4164 ret = mach_port_deallocate (mach_task_self (),
4165 inferior_task);
4166 CHK ("deallocate_task_port: deallocating inferior_task", ret);
4167
4168 current_thread = MACH_PORT_NULL;
4169 inferior_task = MACH_PORT_NULL;
4170 }
4171
4172 /* Stop debugging the process whose number is PID
4173 and continue it with signal number SIGNAL.
4174 SIGNAL = 0 means just continue it. */
4175
4176 static void
4177 m3_do_detach (signal)
4178 int signal;
4179 {
4180 kern_return_t ret;
4181
4182 MACH_ERROR_NO_INFERIOR;
4183
4184 if (current_thread != MACH_PORT_NULL)
4185 {
4186 /* Store the gdb's view of the thread we are deselecting
4187 * before we detach.
4188 * @@ I am really not sure if this is ever needeed.
4189 */
4190 target_prepare_to_store ();
4191 target_store_registers (-1);
4192 }
4193
4194 ret = task_set_special_port (inferior_task,
4195 TASK_EXCEPTION_PORT,
4196 inferior_old_exception_port);
4197 CHK ("task_set_special_port", ret);
4198
4199 /* Discard all requested notifications */
4200 setup_notify_port (0);
4201
4202 if (remove_breakpoints ())
4203 warning ("Could not remove breakpoints when detaching");
4204
4205 if (signal && inferior_pid > 0)
4206 kill (inferior_pid, signal);
4207
4208 /* the task might be dead by now */
4209 (void) task_resume (inferior_task);
4210
4211 deallocate_inferior_ports ();
4212
4213 attach_flag = 0;
4214 }
4215
4216 /* Take a program previously attached to and detaches it.
4217 The program resumes execution and will no longer stop
4218 on signals, etc. We'd better not have left any breakpoints
4219 in the program or it'll die when it hits one. For this
4220 to work, it may be necessary for the process to have been
4221 previously attached. It *might* work if the program was
4222 started via fork. */
4223
4224 static void
4225 m3_detach (args, from_tty)
4226 char *args;
4227 int from_tty;
4228 {
4229 int siggnal = 0;
4230
4231 if (from_tty)
4232 {
4233 char *exec_file = get_exec_file (0);
4234 if (exec_file == 0)
4235 exec_file = "";
4236 printf_unfiltered ("Detaching from program: %s %s\n",
4237 exec_file, target_pid_to_str (inferior_pid));
4238 gdb_flush (gdb_stdout);
4239 }
4240 if (args)
4241 siggnal = atoi (args);
4242
4243 m3_do_detach (siggnal);
4244 inferior_pid = 0;
4245 unpush_target (&m3_ops); /* Pop out of handling an inferior */
4246 }
4247 #endif /* ATTACH_DETACH */
4248
4249 /* Get ready to modify the registers array. On machines which store
4250 individual registers, this doesn't need to do anything. On machines
4251 which store all the registers in one fell swoop, this makes sure
4252 that registers contains all the registers from the program being
4253 debugged. */
4254
4255 static void
4256 m3_prepare_to_store ()
4257 {
4258 #ifdef CHILD_PREPARE_TO_STORE
4259 CHILD_PREPARE_TO_STORE ();
4260 #endif
4261 }
4262
4263 /* Print status information about what we're accessing. */
4264
4265 static void
4266 m3_files_info (ignore)
4267 struct target_ops *ignore;
4268 {
4269 /* FIXME: should print MID and all that crap. */
4270 printf_unfiltered ("\tUsing the running image of %s %s.\n",
4271 attach_flag? "attached": "child", target_pid_to_str (inferior_pid));
4272 }
4273
4274 static void
4275 m3_open (arg, from_tty)
4276 char *arg;
4277 int from_tty;
4278 {
4279 error ("Use the \"run\" command to start a Unix child process.");
4280 }
4281
4282 #ifdef DUMP_SYSCALL
4283 #ifdef __STDC__
4284 #define STR(x) #x
4285 #else
4286 #define STR(x) "x"
4287 #endif
4288
4289 char *bsd1_names[] = {
4290 "execve",
4291 "fork",
4292 "take_signal",
4293 "sigreturn",
4294 "getrusage",
4295 "chdir",
4296 "chroot",
4297 "open",
4298 "creat",
4299 "mknod",
4300 "link",
4301 "symlink",
4302 "unlink",
4303 "access",
4304 "stat",
4305 "readlink",
4306 "chmod",
4307 "chown",
4308 "utimes",
4309 "truncate",
4310 "rename",
4311 "mkdir",
4312 "rmdir",
4313 "xutimes",
4314 "mount",
4315 "umount",
4316 "acct",
4317 "setquota",
4318 "write_short",
4319 "write_long",
4320 "send_short",
4321 "send_long",
4322 "sendto_short",
4323 "sendto_long",
4324 "select",
4325 "task_by_pid",
4326 "recvfrom_short",
4327 "recvfrom_long",
4328 "setgroups",
4329 "setrlimit",
4330 "sigvec",
4331 "sigstack",
4332 "settimeofday",
4333 "adjtime",
4334 "setitimer",
4335 "sethostname",
4336 "bind",
4337 "accept",
4338 "connect",
4339 "setsockopt",
4340 "getsockopt",
4341 "getsockname",
4342 "getpeername",
4343 "init_process",
4344 "table_set",
4345 "table_get",
4346 "pioctl",
4347 "emulator_error",
4348 "readwrite",
4349 "share_wakeup",
4350 0,
4351 "maprw_request_it",
4352 "maprw_release_it",
4353 "maprw_remap",
4354 "pid_by_task",
4355 };
4356
4357 int bsd1_nnames = sizeof(bsd1_names)/sizeof(bsd1_names[0]);
4358
4359 char*
4360 name_str(name,buf)
4361
4362 int name;
4363 char *buf;
4364
4365 {
4366 switch (name) {
4367 case MACH_MSG_TYPE_BOOLEAN:
4368 return "boolean";
4369 case MACH_MSG_TYPE_INTEGER_16:
4370 return "short";
4371 case MACH_MSG_TYPE_INTEGER_32:
4372 return "long";
4373 case MACH_MSG_TYPE_CHAR:
4374 return "char";
4375 case MACH_MSG_TYPE_BYTE:
4376 return "byte";
4377 case MACH_MSG_TYPE_REAL:
4378 return "real";
4379 case MACH_MSG_TYPE_STRING:
4380 return "string";
4381 default:
4382 sprintf(buf,"%d",name);
4383 return buf;
4384 }
4385 }
4386
4387 char *
4388 id_str(id,buf)
4389
4390 int id;
4391 char *buf;
4392
4393 {
4394 char *p;
4395 if (id >= 101000 && id < 101000+bsd1_nnames) {
4396 if (p = bsd1_names[id-101000])
4397 return p;
4398 }
4399 if (id == 102000)
4400 return "psignal_retry";
4401 if (id == 100000)
4402 return "syscall";
4403 sprintf(buf,"%d",id);
4404 return buf;
4405 }
4406
4407 print_msg(mp)
4408 mach_msg_header_t *mp;
4409 {
4410 char *fmt_x = "%20s : 0x%08x\n";
4411 char *fmt_d = "%20s : %10d\n";
4412 char *fmt_s = "%20s : %s\n";
4413 char buf[100];
4414
4415 puts_filtered ("\n");
4416 #define pr(fmt,h,x) printf_filtered(fmt,STR(x),(h).x)
4417 pr(fmt_x,(*mp),msgh_bits);
4418 pr(fmt_d,(*mp),msgh_size);
4419 pr(fmt_x,(*mp),msgh_remote_port);
4420 pr(fmt_x,(*mp),msgh_local_port);
4421 pr(fmt_d,(*mp),msgh_kind);
4422 printf_filtered(fmt_s,STR(msgh_id),id_str(mp->msgh_id,buf));
4423
4424 if (debug_level > 1)
4425 {
4426 char *p,*ep,*dp;
4427 int plen;
4428 p = (char*)mp;
4429 ep = p+mp->msgh_size;
4430 p += sizeof(*mp);
4431 for(; p < ep; p += plen) {
4432 mach_msg_type_t *tp;
4433 mach_msg_type_long_t *tlp;
4434 int name,size,number;
4435 tp = (mach_msg_type_t*)p;
4436 if (tp->msgt_longform) {
4437 tlp = (mach_msg_type_long_t*)tp;
4438 name = tlp->msgtl_name;
4439 size = tlp->msgtl_size;
4440 number = tlp->msgtl_number;
4441 plen = sizeof(*tlp);
4442 } else {
4443 name = tp->msgt_name;
4444 size = tp->msgt_size;
4445 number = tp->msgt_number;
4446 plen = sizeof(*tp);
4447 }
4448 printf_filtered("name=%-16s size=%2d number=%7d inline=%d long=%d deal=%d\n",
4449 name_str(name,buf),size,number,tp->msgt_inline,
4450 tp->msgt_longform, tp->msgt_deallocate);
4451 dp = p+plen;
4452 if (tp->msgt_inline) {
4453 int l;
4454 l = size*number/8;
4455 l = (l+sizeof(long)-1)&~((sizeof(long))-1);
4456 plen += l;
4457 print_data(dp,size,number);
4458 } else {
4459 plen += sizeof(int*);
4460 }
4461 printf_filtered("plen=%d\n",plen);
4462 }
4463 }
4464 }
4465
4466 print_data(p,size,number)
4467
4468 char *p;
4469
4470 {
4471 int *ip;
4472 short *sp;
4473 int i;
4474
4475 switch (size) {
4476 case 8:
4477 for(i = 0; i < number; i++) {
4478 printf_filtered(" %02x",p[i]);
4479 }
4480 break;
4481 case 16:
4482 sp = (short*)p;
4483 for(i = 0; i < number; i++) {
4484 printf_filtered(" %04x",sp[i]);
4485 }
4486 break;
4487 case 32:
4488 ip = (int*)p;
4489 for(i = 0; i < number; i++) {
4490 printf_filtered(" %08x",ip[i]);
4491 }
4492 break;
4493 }
4494 puts_filtered("\n");
4495 }
4496 #endif DUMP_SYSCALL
4497
4498 struct target_ops m3_ops = {
4499 "mach", /* to_shortname */
4500 "Mach child process", /* to_longname */
4501 "Mach child process (started by the \"run\" command).", /* to_doc */
4502 m3_open, /* to_open */
4503 0, /* to_close */
4504 m3_attach, /* to_attach */
4505 m3_detach, /* to_detach */
4506 m3_resume, /* to_resume */
4507 mach_really_wait, /* to_wait */
4508 fetch_inferior_registers, /* to_fetch_registers */
4509 store_inferior_registers, /* to_store_registers */
4510 m3_prepare_to_store, /* to_prepare_to_store */
4511 m3_xfer_memory, /* to_xfer_memory */
4512 m3_files_info, /* to_files_info */
4513 memory_insert_breakpoint, /* to_insert_breakpoint */
4514 memory_remove_breakpoint, /* to_remove_breakpoint */
4515 terminal_init_inferior, /* to_terminal_init */
4516 terminal_inferior, /* to_terminal_inferior */
4517 terminal_ours_for_output, /* to_terminal_ours_for_output */
4518 terminal_ours, /* to_terminal_ours */
4519 child_terminal_info, /* to_terminal_info */
4520 m3_kill_inferior, /* to_kill */
4521 0, /* to_load */
4522 0, /* to_lookup_symbol */
4523
4524 m3_create_inferior, /* to_create_inferior */
4525 m3_mourn_inferior, /* to_mourn_inferior */
4526 m3_can_run, /* to_can_run */
4527 0, /* to_notice_signals */
4528 process_stratum, /* to_stratum */
4529 0, /* to_next */
4530 1, /* to_has_all_memory */
4531 1, /* to_has_memory */
4532 1, /* to_has_stack */
4533 1, /* to_has_registers */
4534 1, /* to_has_execution */
4535 0, /* sections */
4536 0, /* sections_end */
4537 OPS_MAGIC /* to_magic */
4538 };
4539
4540 void
4541 _initialize_m3_nat ()
4542 {
4543 kern_return_t ret;
4544
4545 add_target (&m3_ops);
4546
4547 ret = mach_port_allocate(mach_task_self(),
4548 MACH_PORT_RIGHT_PORT_SET,
4549 &inferior_wait_port_set);
4550 if (ret != KERN_SUCCESS)
4551 fatal("initial port set %s",mach_error_string(ret));
4552
4553 /* mach_really_wait now waits for this */
4554 currently_waiting_for = inferior_wait_port_set;
4555
4556 ret = netname_look_up(name_server_port, hostname, "MachID", &mid_server);
4557 if (ret != KERN_SUCCESS)
4558 {
4559 mid_server = MACH_PORT_NULL;
4560
4561 warning ("initialize machid: netname_lookup_up(MachID) : %s",
4562 mach_error_string(ret));
4563 warning ("Some (most?) features disabled...");
4564 }
4565
4566 mid_auth = mach_privileged_host_port();
4567 if (mid_auth == MACH_PORT_NULL)
4568 mid_auth = mach_task_self();
4569
4570 obstack_init (port_chain_obstack);
4571
4572 ret = mach_port_allocate (mach_task_self (),
4573 MACH_PORT_RIGHT_RECEIVE,
4574 &thread_exception_port);
4575 CHK ("Creating thread_exception_port for single stepping", ret);
4576
4577 ret = mach_port_insert_right (mach_task_self (),
4578 thread_exception_port,
4579 thread_exception_port,
4580 MACH_MSG_TYPE_MAKE_SEND);
4581 CHK ("Inserting send right to thread_exception_port", ret);
4582
4583 /* Allocate message port */
4584 ret = mach_port_allocate (mach_task_self (),
4585 MACH_PORT_RIGHT_RECEIVE,
4586 &our_message_port);
4587 if (ret != KERN_SUCCESS)
4588 warning ("Creating message port %s", mach_error_string (ret));
4589 else
4590 {
4591 char buf[ MAX_NAME_LEN ];
4592 ret = mach_port_move_member(mach_task_self (),
4593 our_message_port,
4594 inferior_wait_port_set);
4595 if (ret != KERN_SUCCESS)
4596 warning ("message move member %s", mach_error_string (ret));
4597
4598
4599 /* @@@@ No way to change message port name currently */
4600 /* Foo. This assumes gdb has a unix pid */
4601 sprintf (buf, "gdb-%d", getpid ());
4602 gdb_register_port (buf, our_message_port);
4603 }
4604
4605 /* Heap for thread commands */
4606 obstack_init (cproc_obstack);
4607
4608 add_mach_specific_commands ();
4609 }