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