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