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