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