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