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