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