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