Replace calls to abort() with calls to internal_error().
[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
8e65ff28
AC
4 Copyright (C) 1992, 1996, 1999, 2000, 2001
5 Free Software Foundation, Inc.
c906108c 6
c5aa993b 7 This file is part of GDB.
c906108c 8
c5aa993b
JM
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
c906108c 13
c5aa993b
JM
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
c906108c 18
c5aa993b
JM
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA. */
c906108c
SS
23
24/*
25 * Author: Jukka Virtanen <jtv@hut.fi>
c5aa993b 26 * Computing Centre
c906108c
SS
27 * Helsinki University of Technology
28 * Finland
29 *
30 * Thanks to my friends who helped with ideas and testing:
31 *
c5aa993b
JM
32 * Johannes Helander, Antti Louko, Tero Mononen,
33 * jvh@cs.hut.fi alo@hut.fi tmo@cs.hut.fi
c906108c
SS
34 *
35 * Tero Kivinen and Eamonn McManus
c5aa993b
JM
36 * kivinen@cs.hut.fi emcmanus@gr.osf.org
37 *
c906108c
SS
38 */
39
40#include <stdio.h>
41
42#include <mach.h>
43#include <servers/netname.h>
44#include <servers/machid.h>
45#include <mach/message.h>
46#include <mach/notify.h>
47#include <mach_error.h>
48#include <mach/exception.h>
49#include <mach/vm_attributes.h>
50
51#include "defs.h"
52#include "inferior.h"
53#include "symtab.h"
54#include "value.h"
55#include "language.h"
56#include "target.h"
03f2053f 57#include "gdb_wait.h"
c906108c
SS
58#include "gdbcmd.h"
59#include "gdbcore.h"
60
61#if 0
62#include <servers/machid_lib.h>
63#else
64#define MACH_TYPE_TASK 1
65#define MACH_TYPE_THREAD 2
66#endif
67
68/* Included only for signal names and NSIG
c5aa993b 69
c906108c
SS
70 * note: There are many problems in signal handling with
71 * gdb in Mach 3.0 in general.
72 */
73#include <signal.h>
c5aa993b 74#define SIG_UNKNOWN 0 /* Exception that has no matching unix signal */
c906108c
SS
75
76#include <cthreads.h>
77
78/* This is what a cproc looks like. This is here partly because
79 cthread_internals.h is not a header we can just #include, partly with
80 an eye towards perhaps getting this to work with cross-debugging
81 someday. Best solution is if CMU publishes a real interface to this
82 stuff. */
83#define CPROC_NEXT_OFFSET 0
84#define CPROC_NEXT_SIZE (TARGET_PTR_BIT / HOST_CHAR_BIT)
85#define CPROC_INCARNATION_OFFSET (CPROC_NEXT_OFFSET + CPROC_NEXT_SIZE)
86#define CPROC_INCARNATION_SIZE (sizeof (cthread_t))
87#define CPROC_LIST_OFFSET (CPROC_INCARNATION_OFFSET + CPROC_INCARNATION_SIZE)
88#define CPROC_LIST_SIZE (TARGET_PTR_BIT / HOST_CHAR_BIT)
89#define CPROC_WAIT_OFFSET (CPROC_LIST_OFFSET + CPROC_LIST_SIZE)
90#define CPROC_WAIT_SIZE (TARGET_PTR_BIT / HOST_CHAR_BIT)
91#define CPROC_REPLY_OFFSET (CPROC_WAIT_OFFSET + CPROC_WAIT_SIZE)
92#define CPROC_REPLY_SIZE (sizeof (mach_port_t))
93#define CPROC_CONTEXT_OFFSET (CPROC_REPLY_OFFSET + CPROC_REPLY_SIZE)
94#define CPROC_CONTEXT_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT)
95#define CPROC_LOCK_OFFSET (CPROC_CONTEXT_OFFSET + CPROC_CONTEXT_SIZE)
96#define CPROC_LOCK_SIZE (sizeof (spin_lock_t))
97#define CPROC_STATE_OFFSET (CPROC_LOCK_OFFSET + CPROC_LOCK_SIZE)
98#define CPROC_STATE_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT)
99#define CPROC_WIRED_OFFSET (CPROC_STATE_OFFSET + CPROC_STATE_SIZE)
100#define CPROC_WIRED_SIZE (sizeof (mach_port_t))
101#define CPROC_BUSY_OFFSET (CPROC_WIRED_OFFSET + CPROC_WIRED_SIZE)
102#define CPROC_BUSY_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT)
103#define CPROC_MSG_OFFSET (CPROC_BUSY_OFFSET + CPROC_BUSY_SIZE)
104#define CPROC_MSG_SIZE (sizeof (mach_msg_header_t))
105#define CPROC_BASE_OFFSET (CPROC_MSG_OFFSET + CPROC_MSG_SIZE)
106#define CPROC_BASE_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT)
107#define CPROC_SIZE_OFFSET (CPROC_BASE_OFFSET + CPROC_BASE_SIZE)
108#define CPROC_SIZE_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT)
109#define CPROC_SIZE (CPROC_SIZE_OFFSET + CPROC_SIZE_SIZE)
110
111/* Values for the state field in the cproc. */
112#define CPROC_RUNNING 0
113#define CPROC_SWITCHING 1
114#define CPROC_BLOCKED 2
115#define CPROC_CONDWAIT 4
116
117/* For cproc and kernel thread mapping */
c5aa993b
JM
118typedef struct gdb_thread
119 {
120 mach_port_t name;
121 CORE_ADDR sp;
122 CORE_ADDR pc;
123 CORE_ADDR fp;
124 boolean_t in_emulator;
125 int slotid;
126
127 /* This is for the mthreads list. It points to the cproc list.
128 Perhaps the two lists should be merged (or perhaps it was a mistake
129 to make them both use a struct gdb_thread). */
130 struct gdb_thread *cproc;
131
132 /* These are for the cproc list, which is linked through the next field
133 of the struct gdb_thread. */
134 char raw_cproc[CPROC_SIZE];
135 /* The cthread which is pointed to by the incarnation field from the
136 cproc. This points to the copy we've read into GDB. */
137 cthread_t cthread;
138 /* Point back to the mthreads list. */
139 int reverse_map;
140 struct gdb_thread *next;
141 }
142 *gdb_thread_t;
c906108c
SS
143
144/*
145 * Actions for Mach exceptions.
146 *
147 * sigmap field maps the exception to corresponding Unix signal.
148 *
149 * I do not know how to map the exception to unix signal
150 * if SIG_UNKNOWN is specified.
151 */
152
c5aa993b
JM
153struct exception_list
154 {
155 char *name;
156 boolean_t forward;
157 boolean_t print;
158 int sigmap;
159 }
160exception_map[] =
161{
162 {
163 "not_mach3_exception", FALSE, TRUE, SIG_UNKNOWN
164 }
165 ,
166 {
167 "EXC_BAD_ACCESS", FALSE, TRUE, SIGSEGV
168 }
169 ,
170 {
171 "EXC_BAD_INSTRUCTION", FALSE, TRUE, SIGILL
172 }
173 ,
174 {
175 "EXC_ARITHMETIC", FALSE, TRUE, SIGFPE
176 }
177 ,
178 {
179 "EXC_EMULATION", FALSE, TRUE, SIGEMT
180 }
181 , /* ??? */
182 {
183 "EXC_SOFTWARE", FALSE, TRUE, SIG_UNKNOWN
184 }
185 ,
186 {
187 "EXC_BREAKPOINT", FALSE, FALSE, SIGTRAP
188 }
c906108c
SS
189};
190
191/* Mach exception table size */
c5aa993b 192int max_exception = sizeof (exception_map) / sizeof (struct exception_list) - 1;
c906108c
SS
193
194#define MAX_EXCEPTION max_exception
195
196WAITTYPE wait_status;
197
198/* If you define this, intercepted bsd server calls will be
199 * dumped while waiting the inferior to EXEC the correct
200 * program
201 */
c5aa993b 202/* #define DUMP_SYSCALL /* debugging interceptor */
c906108c
SS
203
204/* xx_debug() outputs messages if this is nonzero.
205 * If > 1, DUMP_SYSCALL will dump message contents.
206 */
207int debug_level = 0;
208
209/* "Temporary" debug stuff */
210void
fba45db2 211xx_debug (char *fmt, int a, int b, int c)
c906108c
SS
212{
213 if (debug_level)
214 warning (fmt, a, b, c);
215}
216
217/* This is in libmach.a */
c5aa993b 218extern mach_port_t name_server_port;
c906108c
SS
219
220/* Set in catch_exception_raise */
221int stop_exception, stop_code, stop_subcode;
222int stopped_in_exception;
223
224/* Thread that was the active thread when we stopped */
225thread_t stop_thread = MACH_PORT_NULL;
226
227char *hostname = "";
228
229/* Set when task is attached or created */
230boolean_t emulator_present = FALSE;
231
c5aa993b 232task_t inferior_task;
c906108c
SS
233thread_t current_thread;
234
235/* Exception ports for inferior task */
c5aa993b 236mach_port_t inferior_exception_port = MACH_PORT_NULL;
c906108c
SS
237mach_port_t inferior_old_exception_port = MACH_PORT_NULL;
238
239/* task exceptions and notifications */
c5aa993b
JM
240mach_port_t inferior_wait_port_set = MACH_PORT_NULL;
241mach_port_t our_notify_port = MACH_PORT_NULL;
c906108c
SS
242
243/* This is "inferior_wait_port_set" when not single stepping, and
244 * "singlestepped_thread_port" when we are single stepping.
245 *
246 * This is protected by a cleanup function: discard_single_step()
247 */
c5aa993b 248mach_port_t currently_waiting_for = MACH_PORT_NULL;
c906108c
SS
249
250/* A port for external messages to gdb.
251 * External in the meaning that they do not come
252 * from the inferior_task, but rather from external
253 * tasks.
254 *
255 * As a debugging feature:
256 * A debugger debugging another debugger can stop the
257 * inferior debugger by the following command sequence
258 * (without running external programs)
259 *
260 * (top-gdb) set stop_inferior_gdb ()
261 * (top-gdb) continue
262 */
c5aa993b 263mach_port_t our_message_port = MACH_PORT_NULL;
c906108c
SS
264
265/* For single stepping */
c5aa993b 266mach_port_t thread_exception_port = MACH_PORT_NULL;
c906108c 267mach_port_t thread_saved_exception_port = MACH_PORT_NULL;
c5aa993b 268mach_port_t singlestepped_thread_port = MACH_PORT_NULL;
c906108c
SS
269
270/* For machid calls */
271mach_port_t mid_server = MACH_PORT_NULL;
c5aa993b 272mach_port_t mid_auth = MACH_PORT_NULL;
c906108c
SS
273
274/* If gdb thinks the inferior task is not suspended, it
275 * must take suspend/abort the threads when it reads the state.
276 */
277int must_suspend_thread = 0;
278
279/* When single stepping, we switch the port that mach_really_wait() listens to.
280 * This cleanup is a guard to prevent the port set from being left to
281 * the singlestepped_thread_port when error() is called.
282 * This is nonzero only when we are single stepping.
283 */
284#define NULL_CLEANUP (struct cleanup *)0
285struct cleanup *cleanup_step = NULL_CLEANUP;
c906108c 286\f
c5aa993b 287
c906108c
SS
288static struct target_ops m3_ops;
289
290static void m3_kill_inferior ();
291\f
292#if 0
293#define MACH_TYPE_EXCEPTION_PORT -1
294#endif
295
296/* Chain of ports to remember requested notifications. */
297
c5aa993b
JM
298struct port_chain
299 {
300 struct port_chain *next;
301 mach_port_t port;
302 int type;
303 int mid; /* Now only valid with MACH_TYPE_THREAD and */
304 /* MACH_TYPE_THREAD */
305 };
c906108c
SS
306typedef struct port_chain *port_chain_t;
307
308/* Room for chain nodes comes from pchain_obstack */
309struct obstack pchain_obstack;
310struct obstack *port_chain_obstack = &pchain_obstack;
311
312/* For thread handling */
313struct obstack Cproc_obstack;
314struct obstack *cproc_obstack = &Cproc_obstack;
315
316/* the list of notified ports */
317port_chain_t notify_chain = (port_chain_t) NULL;
318
319port_chain_t
fba45db2 320port_chain_insert (port_chain_t list, mach_port_t name, int type)
c906108c
SS
321{
322 kern_return_t ret;
323 port_chain_t new;
324 int mid;
325
c5aa993b 326 if (!MACH_PORT_VALID (name))
c906108c 327 return list;
c5aa993b 328
c906108c
SS
329 if (type == MACH_TYPE_TASK || type == MACH_TYPE_THREAD)
330 {
c5aa993b 331 if (!MACH_PORT_VALID (mid_server))
c906108c
SS
332 {
333 warning ("Machid server port invalid, can not map port 0x%x to MID",
334 name);
335 mid = name;
336 }
337 else
338 {
339 ret = machid_mach_register (mid_server, mid_auth, name, type, &mid);
c5aa993b 340
c906108c
SS
341 if (ret != KERN_SUCCESS)
342 {
343 warning ("Can not map name (0x%x) to MID with machid", name);
344 mid = name;
345 }
346 }
347 }
348 else
e1e9e218 349 internal_error (__FILE__, __LINE__, "failed internal consistency check");
c906108c
SS
350
351 new = (port_chain_t) obstack_alloc (port_chain_obstack,
352 sizeof (struct port_chain));
c5aa993b
JM
353 new->next = list;
354 new->port = name;
355 new->type = type;
356 new->mid = mid;
c906108c
SS
357
358 return new;
359}
360
361port_chain_t
fba45db2 362port_chain_delete (port_chain_t list, mach_port_t elem)
c906108c
SS
363{
364 if (list)
365 if (list->port == elem)
366 list = list->next;
367 else
368 while (list->next)
369 {
370 if (list->next->port == elem)
c5aa993b 371 list->next = list->next->next; /* GCd with obstack_free() */
c906108c
SS
372 else
373 list = list->next;
374 }
375 return list;
376}
377
378void
fba45db2 379port_chain_destroy (struct obstack *ostack)
c906108c
SS
380{
381 obstack_free (ostack, 0);
382 obstack_init (ostack);
383}
384
385port_chain_t
fba45db2 386port_chain_member (port_chain_t list, mach_port_t elem)
c906108c
SS
387{
388 while (list)
389 {
390 if (list->port == elem)
391 return list;
392 list = list->next;
393 }
394 return (port_chain_t) NULL;
395}
396\f
397int
fba45db2 398map_port_name_to_mid (mach_port_t name, int type)
c906108c
SS
399{
400 port_chain_t elem;
401
402 if (!MACH_PORT_VALID (name))
403 return -1;
404
405 elem = port_chain_member (notify_chain, name);
406
407 if (elem && (elem->type == type))
408 return elem->mid;
c5aa993b 409
c906108c
SS
410 if (elem)
411 return -1;
c5aa993b
JM
412
413 if (!MACH_PORT_VALID (mid_server))
c906108c
SS
414 {
415 warning ("Machid server port invalid, can not map port 0x%x to mid",
416 name);
417 return -1;
418 }
419 else
420 {
421 int mid;
422 kern_return_t ret;
423
424 ret = machid_mach_register (mid_server, mid_auth, name, type, &mid);
c5aa993b 425
c906108c
SS
426 if (ret != KERN_SUCCESS)
427 {
428 warning ("Can not map name (0x%x) to mid with machid", name);
429 return -1;
430 }
431 return mid;
432 }
433}
434\f
435/* Guard for currently_waiting_for and singlestepped_thread_port */
436static void
fba45db2 437discard_single_step (thread_t thread)
c906108c
SS
438{
439 currently_waiting_for = inferior_wait_port_set;
440
441 cleanup_step = NULL_CLEANUP;
442 if (MACH_PORT_VALID (thread) && MACH_PORT_VALID (singlestepped_thread_port))
443 setup_single_step (thread, FALSE);
444}
445
fba45db2 446setup_single_step (thread_t thread, boolean_t start_step)
c906108c
SS
447{
448 kern_return_t ret;
449
c5aa993b 450 if (!MACH_PORT_VALID (thread))
c906108c
SS
451 error ("Invalid thread supplied to setup_single_step");
452 else
453 {
454 mach_port_t teport;
455
456 /* Get the current thread exception port */
457 ret = thread_get_exception_port (thread, &teport);
458 CHK ("Getting thread's exception port", ret);
c5aa993b 459
c906108c
SS
460 if (start_step)
461 {
462 if (MACH_PORT_VALID (singlestepped_thread_port))
463 {
464 warning ("Singlestepped_thread_port (0x%x) is still valid?",
465 singlestepped_thread_port);
466 singlestepped_thread_port = MACH_PORT_NULL;
467 }
c5aa993b 468
c906108c
SS
469 /* If we are already stepping this thread */
470 if (MACH_PORT_VALID (teport) && teport == thread_exception_port)
471 {
472 ret = mach_port_deallocate (mach_task_self (), teport);
473 CHK ("Could not deallocate thread exception port", ret);
474 }
475 else
476 {
477 ret = thread_set_exception_port (thread, thread_exception_port);
478 CHK ("Setting exception port for thread", ret);
479#if 0
480 /* Insert thread exception port to wait port set */
c5aa993b 481 ret = mach_port_move_member (mach_task_self (),
c906108c
SS
482 thread_exception_port,
483 inferior_wait_port_set);
484 CHK ("Moving thread exception port to inferior_wait_port_set",
485 ret);
486#endif
487 thread_saved_exception_port = teport;
488 }
c5aa993b 489
c906108c 490 thread_trace (thread, TRUE);
c5aa993b
JM
491
492 singlestepped_thread_port = thread_exception_port;
493 currently_waiting_for = singlestepped_thread_port;
c906108c
SS
494 cleanup_step = make_cleanup (discard_single_step, thread);
495 }
496 else
497 {
c5aa993b 498 if (!MACH_PORT_VALID (teport))
c906108c
SS
499 error ("Single stepped thread had an invalid exception port?");
500
501 if (teport != thread_exception_port)
502 error ("Single stepped thread had an unknown exception port?");
c5aa993b 503
c906108c
SS
504 ret = mach_port_deallocate (mach_task_self (), teport);
505 CHK ("Couldn't deallocate thread exception port", ret);
506#if 0
507 /* Remove thread exception port from wait port set */
c5aa993b 508 ret = mach_port_move_member (mach_task_self (),
c906108c
SS
509 thread_exception_port,
510 MACH_PORT_NULL);
511 CHK ("Removing thread exception port from inferior_wait_port_set",
512 ret);
c5aa993b 513#endif
c906108c
SS
514 /* Restore thread's old exception port */
515 ret = thread_set_exception_port (thread,
516 thread_saved_exception_port);
517 CHK ("Restoring stepped thread's exception port", ret);
c5aa993b 518
c906108c
SS
519 if (MACH_PORT_VALID (thread_saved_exception_port))
520 (void) mach_port_deallocate (mach_task_self (),
521 thread_saved_exception_port);
c5aa993b 522
c906108c 523 thread_trace (thread, FALSE);
c5aa993b 524
c906108c
SS
525 singlestepped_thread_port = MACH_PORT_NULL;
526 currently_waiting_for = inferior_wait_port_set;
527 if (cleanup_step)
528 discard_cleanups (cleanup_step);
529 }
530 }
531}
532\f
533static
fba45db2 534request_notify (mach_port_t name, mach_msg_id_t variant, int type)
c906108c
SS
535{
536 kern_return_t ret;
c5aa993b
JM
537 mach_port_t previous_port_dummy = MACH_PORT_NULL;
538
539 if (!MACH_PORT_VALID (name))
c906108c 540 return;
c5aa993b 541
c906108c
SS
542 if (port_chain_member (notify_chain, name))
543 return;
544
c5aa993b 545 ret = mach_port_request_notification (mach_task_self (),
c906108c
SS
546 name,
547 variant,
548 1,
549 our_notify_port,
550 MACH_MSG_TYPE_MAKE_SEND_ONCE,
551 &previous_port_dummy);
552 CHK ("Serious: request_notify failed", ret);
553
554 (void) mach_port_deallocate (mach_task_self (),
555 previous_port_dummy);
556
557 notify_chain = port_chain_insert (notify_chain, name, type);
558}
559
fba45db2 560reverse_msg_bits (mach_msg_header_t *msgp, int type)
c906108c 561{
c5aa993b
JM
562 int rbits, lbits;
563 rbits = MACH_MSGH_BITS_REMOTE (msgp->msgh_bits);
c906108c
SS
564 lbits = type;
565 msgp->msgh_bits =
566 (msgp->msgh_bits & ~MACH_MSGH_BITS_PORTS_MASK) |
c5aa993b 567 MACH_MSGH_BITS (lbits, rbits);
c906108c
SS
568}
569\f
570/* On the third day He said:
571
c5aa993b
JM
572 Let this be global
573 and then it was global.
c906108c
SS
574
575 When creating the inferior fork, the
576 child code in inflow.c sets the name of the
577 bootstrap_port in its address space to this
578 variable.
579
580 The name is transferred to our address space
581 with mach3_read_inferior().
582
583 Thou shalt not do this with
584 task_get_bootstrap_port() in this task, since
585 the name in the inferior task is different than
586 the one we get.
587
588 For blessed are the meek, as they shall inherit
589 the address space.
590 */
591mach_port_t original_server_port_name = MACH_PORT_NULL;
592
593
594/* Called from inferior after FORK but before EXEC */
595static void
fba45db2 596m3_trace_me (void)
c906108c
SS
597{
598 kern_return_t ret;
c5aa993b 599
c906108c
SS
600 /* Get the NAME of the bootstrap port in this task
601 so that GDB can read it */
602 ret = task_get_bootstrap_port (mach_task_self (),
603 &original_server_port_name);
604 if (ret != KERN_SUCCESS)
e1e9e218 605 internal_error (__FILE__, __LINE__, "failed internal consistency check");
c906108c
SS
606 ret = mach_port_deallocate (mach_task_self (),
607 original_server_port_name);
608 if (ret != KERN_SUCCESS)
e1e9e218 609 internal_error (__FILE__, __LINE__, "failed internal consistency check");
c5aa993b 610
c906108c
SS
611 /* Suspend this task to let the parent change my ports.
612 Resumed by the debugger */
613 ret = task_suspend (mach_task_self ());
614 if (ret != KERN_SUCCESS)
e1e9e218 615 internal_error (__FILE__, __LINE__, "failed internal consistency check");
c906108c
SS
616}
617\f
618/*
619 * Intercept system calls to Unix server.
620 * After EXEC_COUNTER calls to exec(), return.
621 *
622 * Pre-assertion: Child is suspended. (Not verified)
623 * Post-condition: Child is suspended after EXEC_COUNTER exec() calls.
624 */
625
626void
fba45db2 627intercept_exec_calls (int exec_counter)
c906108c
SS
628{
629 int terminal_initted = 0;
630
c5aa993b
JM
631 struct syscall_msg_t
632 {
633 mach_msg_header_t header;
634 mach_msg_type_t type;
635 char room[2000]; /* Enuff space */
636 };
c906108c
SS
637
638 struct syscall_msg_t syscall_in, syscall_out;
639
640 mach_port_t fake_server;
641 mach_port_t original_server_send;
642 mach_port_t original_exec_reply;
643 mach_port_t exec_reply;
644 mach_port_t exec_reply_send;
645 mach_msg_type_name_t acquired;
646 mach_port_t emulator_server_port_name;
647 struct task_basic_info info;
648 mach_msg_type_number_t info_count;
649
650 kern_return_t ret;
651
652 if (exec_counter <= 0)
c5aa993b
JM
653 return; /* We are already set up in the correct program */
654
655 ret = mach_port_allocate (mach_task_self (),
656 MACH_PORT_RIGHT_RECEIVE,
657 &fake_server);
658 CHK ("create inferior_fake_server port failed", ret);
c906108c 659
c906108c 660 /* Wait for inferior_task to suspend itself */
c5aa993b 661 while (1)
c906108c
SS
662 {
663 info_count = sizeof (info);
664 ret = task_info (inferior_task,
665 TASK_BASIC_INFO,
c5aa993b 666 (task_info_t) & info,
c906108c
SS
667 &info_count);
668 CHK ("Task info", ret);
669
670 if (info.suspend_count)
671 break;
672
673 /* Note that the definition of the parameter was undefined
674 * at the time of this writing, so I just use an `ad hoc' value.
675 */
c5aa993b 676 (void) swtch_pri (42); /* Universal Priority Value */
c906108c
SS
677 }
678
679 /* Read the inferior's bootstrap port name */
680 if (!mach3_read_inferior (&original_server_port_name,
681 &original_server_port_name,
682 sizeof (original_server_port_name)))
683 error ("Can't read inferior task bootstrap port name");
684
685 /* @@ BUG: If more than 1 send right GDB will FAIL!!! */
686 /* Should get refs, and set them back when restoring */
687 /* Steal the original bsd server send right from inferior */
688 ret = mach_port_extract_right (inferior_task,
689 original_server_port_name,
690 MACH_MSG_TYPE_MOVE_SEND,
691 &original_server_send,
692 &acquired);
c5aa993b
JM
693 CHK ("mach_port_extract_right (bsd server send)", ret);
694
c906108c 695 if (acquired != MACH_MSG_TYPE_PORT_SEND)
8e1a459b 696 error ("Incorrect right extracted, send right to bsd server expected");
c906108c
SS
697
698 ret = mach_port_insert_right (inferior_task,
699 original_server_port_name,
700 fake_server,
701 MACH_MSG_TYPE_MAKE_SEND);
c5aa993b 702 CHK ("mach_port_insert_right (fake server send)", ret);
c906108c
SS
703
704 xx_debug ("inferior task bsd server ports set up \nfs %x, ospn %x, oss %x\n",
705 fake_server,
706 original_server_port_name, original_server_send);
707
708 /* A receive right to the reply generated by unix server exec() request */
c5aa993b
JM
709 ret = mach_port_allocate (mach_task_self (),
710 MACH_PORT_RIGHT_RECEIVE,
711 &exec_reply);
712 CHK ("create intercepted_reply_port port failed", ret);
713
c906108c
SS
714 /* Pass this send right to Unix server so it replies to us after exec() */
715 ret = mach_port_extract_right (mach_task_self (),
716 exec_reply,
717 MACH_MSG_TYPE_MAKE_SEND_ONCE,
718 &exec_reply_send,
719 &acquired);
c5aa993b 720 CHK ("mach_port_extract_right (exec_reply)", ret);
c906108c
SS
721
722 if (acquired != MACH_MSG_TYPE_PORT_SEND_ONCE)
8e1a459b 723 error ("Incorrect right extracted, send once expected for exec reply");
c906108c 724
c5aa993b
JM
725 ret = mach_port_move_member (mach_task_self (),
726 fake_server,
727 inferior_wait_port_set);
c906108c
SS
728 CHK ("Moving fake syscall port to inferior_wait_port_set", ret);
729
730 xx_debug ("syscall fake server set up, resuming inferior\n");
c5aa993b 731
c906108c 732 ret = task_resume (inferior_task);
c5aa993b
JM
733 CHK ("task_resume (startup)", ret);
734
c906108c
SS
735 /* Read requests from the inferior.
736 Pass directly through everything else except exec() calls.
737 */
c5aa993b 738 while (exec_counter > 0)
c906108c
SS
739 {
740 ret = mach_msg (&syscall_in.header, /* header */
c5aa993b
JM
741 MACH_RCV_MSG, /* options */
742 0, /* send size */
743 sizeof (struct syscall_msg_t), /* receive size */
744 inferior_wait_port_set, /* receive_name */
c906108c
SS
745 MACH_MSG_TIMEOUT_NONE,
746 MACH_PORT_NULL);
c5aa993b
JM
747 CHK ("mach_msg (intercepted sycall)", ret);
748
c906108c
SS
749#ifdef DUMP_SYSCALL
750 print_msg (&syscall_in.header);
751#endif
752
753 /* ASSERT : msgh_local_port == fake_server */
754
755 if (notify_server (&syscall_in.header, &syscall_out.header))
756 error ("received a notify while intercepting syscalls");
757
758 if (syscall_in.header.msgh_id == MIG_EXEC_SYSCALL_ID)
759 {
760 xx_debug ("Received EXEC SYSCALL, counter = %d\n", exec_counter);
761 if (exec_counter == 1)
762 {
763 original_exec_reply = syscall_in.header.msgh_remote_port;
764 syscall_in.header.msgh_remote_port = exec_reply_send;
765 }
766
767 if (!terminal_initted)
768 {
769 /* Now that the child has exec'd we know it has already set its
c5aa993b
JM
770 process group. On POSIX systems, tcsetpgrp will fail with
771 EPERM if we try it before the child's setpgid. */
c906108c
SS
772
773 /* Set up the "saved terminal modes" of the inferior
c5aa993b 774 based on what modes we are starting it with. */
c906108c
SS
775 target_terminal_init ();
776
777 /* Install inferior's terminal modes. */
778 target_terminal_inferior ();
779
780 terminal_initted = 1;
781 }
782
783 exec_counter--;
784 }
c5aa993b
JM
785
786 syscall_in.header.msgh_local_port = syscall_in.header.msgh_remote_port;
c906108c
SS
787 syscall_in.header.msgh_remote_port = original_server_send;
788
c5aa993b 789 reverse_msg_bits (&syscall_in.header, MACH_MSG_TYPE_COPY_SEND);
c906108c
SS
790
791 ret = mach_msg_send (&syscall_in.header);
792 CHK ("Forwarded syscall", ret);
793 }
c5aa993b
JM
794
795 ret = mach_port_move_member (mach_task_self (),
796 fake_server,
797 MACH_PORT_NULL);
c906108c
SS
798 CHK ("Moving fake syscall out of inferior_wait_port_set", ret);
799
c5aa993b
JM
800 ret = mach_port_move_member (mach_task_self (),
801 exec_reply,
802 inferior_wait_port_set);
c906108c
SS
803 CHK ("Moving exec_reply to inferior_wait_port_set", ret);
804
805 ret = mach_msg (&syscall_in.header, /* header */
c5aa993b
JM
806 MACH_RCV_MSG, /* options */
807 0, /* send size */
c906108c 808 sizeof (struct syscall_msg_t), /* receive size */
c5aa993b 809 inferior_wait_port_set, /* receive_name */
c906108c
SS
810 MACH_MSG_TIMEOUT_NONE,
811 MACH_PORT_NULL);
c5aa993b 812 CHK ("mach_msg (exec reply)", ret);
c906108c
SS
813
814 ret = task_suspend (inferior_task);
815 CHK ("Suspending inferior after last exec", ret);
816
817 must_suspend_thread = 0;
818
819 xx_debug ("Received exec reply from bsd server, suspended inferior task\n");
820
821#ifdef DUMP_SYSCALL
c5aa993b 822 print_msg (&syscall_in.header);
c906108c
SS
823#endif
824
825 /* Message should appear as if it came from the unix server */
826 syscall_in.header.msgh_local_port = MACH_PORT_NULL;
827
828 /* and go to the inferior task original reply port */
829 syscall_in.header.msgh_remote_port = original_exec_reply;
830
c5aa993b 831 reverse_msg_bits (&syscall_in.header, MACH_MSG_TYPE_MOVE_SEND_ONCE);
c906108c
SS
832
833 ret = mach_msg_send (&syscall_in.header);
834 CHK ("Forwarding exec reply to inferior", ret);
835
836 /* Garbage collect */
837 ret = mach_port_deallocate (inferior_task,
838 original_server_port_name);
839 CHK ("deallocating fake server send right", ret);
840
841 ret = mach_port_insert_right (inferior_task,
842 original_server_port_name,
843 original_server_send,
844 MACH_MSG_TYPE_MOVE_SEND);
845 CHK ("Restoring the original bsd server send right", ret);
846
847 ret = mach_port_destroy (mach_task_self (),
848 fake_server);
849 fake_server = MACH_PORT_DEAD;
c5aa993b 850 CHK ("mach_port_destroy (fake_server)", ret);
c906108c
SS
851
852 ret = mach_port_destroy (mach_task_self (),
853 exec_reply);
854 exec_reply = MACH_PORT_DEAD;
c5aa993b 855 CHK ("mach_port_destroy (exec_reply)", ret);
c906108c
SS
856
857 xx_debug ("Done with exec call interception\n");
858}
859
860void
fba45db2 861consume_send_rights (thread_array_t thread_list, int thread_count)
c906108c
SS
862{
863 int index;
864
865 if (!thread_count)
866 return;
867
868 for (index = 0; index < thread_count; index++)
869 {
870 /* Since thread kill command kills threads, don't check ret */
871 (void) mach_port_deallocate (mach_task_self (),
c5aa993b 872 thread_list[index]);
c906108c
SS
873 }
874}
875
876/* suspend/abort/resume a thread. */
fba45db2 877setup_thread (mach_port_t thread, int what)
c906108c
SS
878{
879 kern_return_t ret;
880
881 if (what)
882 {
883 ret = thread_suspend (thread);
884 CHK ("setup_thread thread_suspend", ret);
c5aa993b 885
c906108c
SS
886 ret = thread_abort (thread);
887 CHK ("setup_thread thread_abort", ret);
888 }
889 else
890 {
891 ret = thread_resume (thread);
892 CHK ("setup_thread thread_resume", ret);
893 }
894}
895
896int
fba45db2 897map_slot_to_mid (int slot, thread_array_t threads, int thread_count)
c906108c
SS
898{
899 kern_return_t ret;
900 int deallocate = 0;
901 int index;
902 int mid;
903
c5aa993b 904 if (!threads)
c906108c
SS
905 {
906 deallocate++;
907 ret = task_threads (inferior_task, &threads, &thread_count);
908 CHK ("Can not select a thread from a dead task", ret);
909 }
c5aa993b 910
c906108c
SS
911 if (slot < 0 || slot >= thread_count)
912 {
913 if (deallocate)
914 {
915 consume_send_rights (threads, thread_count);
c5aa993b
JM
916 (void) vm_deallocate (mach_task_self (), (vm_address_t) threads,
917 (thread_count * sizeof (mach_port_t)));
c906108c
SS
918 }
919 if (slot < 0)
920 error ("invalid slot number");
921 else
c5aa993b 922 return -(slot + 1);
c906108c
SS
923 }
924
c5aa993b 925 mid = map_port_name_to_mid (threads[slot], MACH_TYPE_THREAD);
c906108c
SS
926
927 if (deallocate)
928 {
929 consume_send_rights (threads, thread_count);
c5aa993b
JM
930 (void) vm_deallocate (mach_task_self (), (vm_address_t) threads,
931 (thread_count * sizeof (mach_port_t)));
c906108c
SS
932 }
933
934 return mid;
935}
936
937static int
fba45db2 938parse_thread_id (char *arg, int thread_count, int slots)
c906108c
SS
939{
940 kern_return_t ret;
941 int mid;
942 int slot;
943 int index;
c5aa993b 944
c906108c
SS
945 if (arg == 0)
946 return 0;
c5aa993b 947
c906108c
SS
948 while (*arg && (*arg == ' ' || *arg == '\t'))
949 arg++;
c5aa993b
JM
950
951 if (!*arg)
c906108c 952 return 0;
c5aa993b 953
c906108c
SS
954 /* Currently parse MID and @SLOTNUMBER */
955 if (*arg != '@')
956 {
957 mid = atoi (arg);
958 if (mid <= 0)
959 error ("valid thread mid expected");
960 return mid;
961 }
c5aa993b 962
c906108c
SS
963 arg++;
964 slot = atoi (arg);
965
966 if (slot < 0)
967 error ("invalid slot number");
968
969 /* If you want slot numbers to remain slot numbers, set slots.
c5aa993b 970
c906108c
SS
971 * Well, since 0 is reserved, return the ordinal number
972 * of the thread rather than the slot number. Awk, this
973 * counts as a kludge.
974 */
975 if (slots)
c5aa993b 976 return -(slot + 1);
c906108c
SS
977
978 if (thread_count && slot >= thread_count)
c5aa993b 979 return -(slot + 1);
c906108c
SS
980
981 mid = map_slot_to_mid (slot);
c5aa993b 982
c906108c
SS
983 return mid;
984}
985
986/* THREAD_ID 0 is special; it selects the first kernel
987 * thread from the list (i.e. SLOTNUMBER 0)
988 * This is used when starting the program with 'run' or when attaching.
989 *
990 * If FLAG is 0 the context is not changed, and the registers, frame, etc
991 * will continue to describe the old thread.
992 *
993 * If FLAG is nonzero, really select the thread.
994 * If FLAG is 2, the THREAD_ID is a slotnumber instead of a mid.
995 *
996 */
997kern_return_t
fba45db2 998select_thread (mach_port_t task, int thread_id, int flag)
c906108c
SS
999{
1000 thread_array_t thread_list;
1001 int thread_count;
1002 kern_return_t ret;
1003 int index;
1004 thread_t new_thread = MACH_PORT_NULL;
1005
1006 if (thread_id < 0)
1007 error ("Can't select cprocs without kernel thread");
1008
1009 ret = task_threads (task, &thread_list, &thread_count);
1010 if (ret != KERN_SUCCESS)
1011 {
1012 warning ("Can not select a thread from a dead task");
1013 m3_kill_inferior ();
1014 return KERN_FAILURE;
1015 }
1016
1017 if (thread_count == 0)
1018 {
1019 /* The task can not do anything anymore, but it still
1020 * exists as a container for memory and ports.
1021 */
1022 registers_changed ();
1023 warning ("Task %d has no threads",
1024 map_port_name_to_mid (task, MACH_TYPE_TASK));
1025 current_thread = MACH_PORT_NULL;
c5aa993b
JM
1026 (void) vm_deallocate (mach_task_self (),
1027 (vm_address_t) thread_list,
1028 (thread_count * sizeof (mach_port_t)));
c906108c
SS
1029 return KERN_FAILURE;
1030 }
1031
c5aa993b 1032 if (!thread_id || flag == 2)
c906108c
SS
1033 {
1034 /* First thread or a slotnumber */
c5aa993b 1035 if (!thread_id)
c906108c
SS
1036 new_thread = thread_list[0];
1037 else
1038 {
1039 if (thread_id < thread_count)
c5aa993b 1040 new_thread = thread_list[thread_id];
c906108c
SS
1041 else
1042 {
c5aa993b
JM
1043 (void) vm_deallocate (mach_task_self (),
1044 (vm_address_t) thread_list,
1045 (thread_count * sizeof (mach_port_t)));
c906108c
SS
1046 error ("No such thread slot number : %d", thread_id);
1047 }
1048 }
1049 }
1050 else
1051 {
1052 for (index = 0; index < thread_count; index++)
c5aa993b 1053 if (thread_id == map_port_name_to_mid (thread_list[index],
c906108c
SS
1054 MACH_TYPE_THREAD))
1055 {
c5aa993b 1056 new_thread = thread_list[index];
c906108c
SS
1057 index = -1;
1058 break;
1059 }
c5aa993b 1060
c906108c
SS
1061 if (index != -1)
1062 error ("No thread with mid %d", thread_id);
1063 }
c5aa993b 1064
c906108c
SS
1065 /* Notify when the selected thread dies */
1066 request_notify (new_thread, MACH_NOTIFY_DEAD_NAME, MACH_TYPE_THREAD);
c5aa993b
JM
1067
1068 ret = vm_deallocate (mach_task_self (),
1069 (vm_address_t) thread_list,
1070 (thread_count * sizeof (mach_port_t)));
c906108c 1071 CHK ("vm_deallocate", ret);
c5aa993b
JM
1072
1073 if (!flag)
c906108c
SS
1074 current_thread = new_thread;
1075 else
1076 {
1077#if 0
1078 if (MACH_PORT_VALID (current_thread))
1079 {
1080 /* Store the gdb's view of the thread we are deselecting
c5aa993b 1081
c906108c
SS
1082 * @@ I think gdb updates registers immediately when they are
1083 * changed, so don't do this.
1084 */
1085 ret = thread_abort (current_thread);
1086 CHK ("Could not abort system calls when saving state of old thread",
1087 ret);
1088 target_prepare_to_store ();
1089 target_store_registers (-1);
1090 }
1091#endif
1092
1093 registers_changed ();
1094
1095 current_thread = new_thread;
1096
1097 ret = thread_abort (current_thread);
1098 CHK ("Could not abort system calls when selecting a thread", ret);
1099
c5aa993b 1100 stop_pc = read_pc ();
c906108c
SS
1101 flush_cached_frames ();
1102
1103 select_frame (get_current_frame (), 0);
1104 }
1105
1106 return KERN_SUCCESS;
1107}
1108
1109/*
1110 * Switch to use thread named NEW_THREAD.
1111 * Return it's MID
1112 */
1113int
fba45db2 1114switch_to_thread (thread_t new_thread)
c906108c
SS
1115{
1116 thread_t saved_thread = current_thread;
1117 int mid;
1118
1119 mid = map_port_name_to_mid (new_thread,
1120 MACH_TYPE_THREAD);
1121 if (mid == -1)
1122 warning ("Can't map thread name 0x%x to mid", new_thread);
1123 else if (select_thread (inferior_task, mid, 1) != KERN_SUCCESS)
1124 {
1125 if (current_thread)
1126 current_thread = saved_thread;
1127 error ("Could not select thread %d", mid);
1128 }
c5aa993b 1129
c906108c
SS
1130 return mid;
1131}
1132
1133/* Do this in gdb after doing FORK but before STARTUP_INFERIOR.
1134 * Note that the registers are not yet valid in the inferior task.
1135 */
1136static int
fba45db2 1137m3_trace_him (int pid)
c906108c
SS
1138{
1139 kern_return_t ret;
1140
1141 push_target (&m3_ops);
1142
1143 inferior_task = task_by_pid (pid);
1144
c5aa993b 1145 if (!MACH_PORT_VALID (inferior_task))
c906108c
SS
1146 error ("Can not map Unix pid %d to Mach task", pid);
1147
1148 /* Clean up previous notifications and create new ones */
1149 setup_notify_port (1);
1150
1151 /* When notification appears, the inferior task has died */
1152 request_notify (inferior_task, MACH_NOTIFY_DEAD_NAME, MACH_TYPE_TASK);
1153
1154 emulator_present = have_emulator_p (inferior_task);
1155
1156 /* By default, select the first thread,
1157 * If task has no threads, gives a warning
1158 * Does not fetch registers, since they are not yet valid.
1159 */
1160 select_thread (inferior_task, 0, 0);
1161
1162 inferior_exception_port = MACH_PORT_NULL;
1163
1164 setup_exception_port ();
1165
1166 xx_debug ("Now the debugged task is created\n");
1167
1168 /* One trap to exec the shell, one to exec the program being debugged. */
1169 intercept_exec_calls (2);
1170
1171 return pid;
1172}
1173
fba45db2 1174setup_exception_port (void)
c906108c
SS
1175{
1176 kern_return_t ret;
1177
c5aa993b 1178 ret = mach_port_allocate (mach_task_self (),
c906108c
SS
1179 MACH_PORT_RIGHT_RECEIVE,
1180 &inferior_exception_port);
c5aa993b 1181 CHK ("mach_port_allocate", ret);
c906108c
SS
1182
1183 /* add send right */
1184 ret = mach_port_insert_right (mach_task_self (),
1185 inferior_exception_port,
1186 inferior_exception_port,
1187 MACH_MSG_TYPE_MAKE_SEND);
c5aa993b 1188 CHK ("mach_port_insert_right", ret);
c906108c 1189
c5aa993b 1190 ret = mach_port_move_member (mach_task_self (),
c906108c
SS
1191 inferior_exception_port,
1192 inferior_wait_port_set);
c5aa993b 1193 CHK ("mach_port_move_member", ret);
c906108c 1194
c5aa993b 1195 ret = task_get_special_port (inferior_task,
c906108c
SS
1196 TASK_EXCEPTION_PORT,
1197 &inferior_old_exception_port);
c5aa993b 1198 CHK ("task_get_special_port(old exc)", ret);
c906108c
SS
1199
1200 ret = task_set_special_port (inferior_task,
c5aa993b 1201 TASK_EXCEPTION_PORT,
c906108c 1202 inferior_exception_port);
c5aa993b 1203 CHK ("task_set_special_port", ret);
c906108c
SS
1204
1205 ret = mach_port_deallocate (mach_task_self (),
1206 inferior_exception_port);
c5aa993b 1207 CHK ("mack_port_deallocate", ret);
c906108c
SS
1208
1209#if 0
1210 /* When notify appears, the inferior_task's exception
1211 * port has been destroyed.
1212 *
1213 * Not used, since the dead_name_notification already
1214 * appears when task dies.
1215 *
1216 */
1217 request_notify (inferior_exception_port,
1218 MACH_NOTIFY_NO_SENDERS,
1219 MACH_TYPE_EXCEPTION_PORT);
1220#endif
1221}
1222
1223/* Nonzero if gdb is waiting for a message */
1224int mach_really_waiting;
1225
1226/* Wait for the inferior to stop for some reason.
1227 - Loop on notifications until inferior_task dies.
1228 - Loop on exceptions until stopped_in_exception comes true.
c5aa993b 1229 (e.g. we receive a single step trace trap)
c906108c
SS
1230 - a message arrives to gdb's message port
1231
1232 There is no other way to exit this loop.
1233
1234 Returns the inferior_pid for rest of gdb.
1235 Side effects: Set *OURSTATUS. */
1236int
fba45db2 1237mach_really_wait (int pid, struct target_waitstatus *ourstatus)
c906108c
SS
1238{
1239 kern_return_t ret;
1240 int w;
1241
c5aa993b
JM
1242 struct msg
1243 {
1244 mach_msg_header_t header;
1245 mach_msg_type_t foo;
1246 int data[8000];
1247 }
1248 in_msg, out_msg;
c906108c
SS
1249
1250 /* Either notify (death), exception or message can stop the inferior */
1251 stopped_in_exception = FALSE;
1252
1253 while (1)
1254 {
1255 QUIT;
1256
1257 stop_exception = stop_code = stop_subcode = -1;
1258 stop_thread = MACH_PORT_NULL;
1259
1260 mach_really_waiting = 1;
c5aa993b
JM
1261 ret = mach_msg (&in_msg.header, /* header */
1262 MACH_RCV_MSG, /* options */
1263 0, /* send size */
c906108c
SS
1264 sizeof (struct msg), /* receive size */
1265 currently_waiting_for, /* receive name */
1266 MACH_MSG_TIMEOUT_NONE,
1267 MACH_PORT_NULL);
1268 mach_really_waiting = 0;
c5aa993b 1269 CHK ("mach_msg (receive)", ret);
c906108c
SS
1270
1271 /* Check if we received a notify of the childs' death */
1272 if (notify_server (&in_msg.header, &out_msg.header))
1273 {
1274 /* If inferior_task is null then the inferior has
1275 gone away and we want to return to command level.
1276 Otherwise it was just an informative message and we
1277 need to look to see if there are any more. */
1278 if (inferior_task != MACH_PORT_NULL)
1279 continue;
1280 else
1281 {
1282 /* Collect Unix exit status for gdb */
1283
c5aa993b 1284 wait3 (&w, WNOHANG, 0);
c906108c
SS
1285
1286 /* This mess is here to check that the rest of
1287 * gdb knows that the inferior died. It also
1288 * tries to hack around the fact that Mach 3.0 (mk69)
1289 * unix server (ux28) does not always know what
1290 * has happened to it's children when mach-magic
1291 * is applied on them.
1292 */
c5aa993b
JM
1293 if ((!WIFEXITED (w) && WIFSTOPPED (w)) ||
1294 (WIFEXITED (w) && WEXITSTATUS (w) > 0377))
c906108c 1295 {
c5aa993b 1296 WSETEXIT (w, 0);
c906108c
SS
1297 warning ("Using exit value 0 for terminated task");
1298 }
c5aa993b 1299 else if (!WIFEXITED (w))
c906108c 1300 {
c5aa993b 1301 int sig = WTERMSIG (w);
c906108c
SS
1302
1303 /* Signals cause problems. Warn the user. */
c5aa993b 1304 if (sig != SIGKILL) /* Bad luck if garbage matches this */
c906108c
SS
1305 warning ("The terminating signal stuff may be nonsense");
1306 else if (sig > NSIG)
1307 {
c5aa993b 1308 WSETEXIT (w, 0);
c906108c
SS
1309 warning ("Using exit value 0 for terminated task");
1310 }
1311 }
1312 store_waitstatus (ourstatus, w);
1313 return inferior_pid;
1314 }
1315 }
1316
1317 /* Hmm. Check for exception, as it was not a notification.
c5aa993b
JM
1318 exc_server() does an upcall to catch_exception_raise()
1319 if this rpc is an exception. Further actions are decided
1320 there.
c906108c 1321 */
c5aa993b 1322 if (!exc_server (&in_msg.header, &out_msg.header))
c906108c
SS
1323 {
1324
1325 /* Not an exception, check for message.
c5aa993b 1326
c906108c
SS
1327 * Messages don't come from the inferior, or if they
1328 * do they better be asynchronous or it will hang.
1329 */
1330 if (gdb_message_server (&in_msg.header))
1331 continue;
1332
1333 error ("Unrecognized message received in mach_really_wait");
1334 }
1335
1336 /* Send the reply of the exception rpc to the suspended task */
1337 ret = mach_msg_send (&out_msg.header);
1338 CHK ("mach_msg_send (exc reply)", ret);
c5aa993b 1339
c906108c
SS
1340 if (stopped_in_exception)
1341 {
1342 /* Get unix state. May be changed in mach3_exception_actions() */
c5aa993b 1343 wait3 (&w, WNOHANG, 0);
c906108c
SS
1344
1345 mach3_exception_actions (&w, FALSE, "Task");
1346
1347 store_waitstatus (ourstatus, w);
1348 return inferior_pid;
1349 }
1350 }
1351}
1352
1353/* Called by macro DO_QUIT() in utils.c(quit).
1354 * This is called just before calling error() to return to command level
1355 */
1356void
fba45db2 1357mach3_quit (void)
c906108c
SS
1358{
1359 int mid;
1360 kern_return_t ret;
c5aa993b 1361
c906108c
SS
1362 if (mach_really_waiting)
1363 {
1364 ret = task_suspend (inferior_task);
c5aa993b 1365
c906108c
SS
1366 if (ret != KERN_SUCCESS)
1367 {
1368 warning ("Could not suspend task for interrupt: %s",
1369 mach_error_string (ret));
1370 mach_really_waiting = 0;
1371 return;
1372 }
1373 }
1374
1375 must_suspend_thread = 0;
1376 mach_really_waiting = 0;
1377
1378 mid = map_port_name_to_mid (current_thread, MACH_TYPE_THREAD);
1379 if (mid == -1)
1380 {
1381 warning ("Selecting first existing kernel thread");
1382 mid = 0;
1383 }
1384
c5aa993b 1385 current_thread = MACH_PORT_NULL; /* Force setup */
c906108c
SS
1386 select_thread (inferior_task, mid, 1);
1387
1388 return;
1389}
1390
1391#if 0
1392/* bogus bogus bogus. It is NOT OK to quit out of target_wait. */
1393
1394/* If ^C is typed when we are waiting for a message
1395 * and your Unix server is able to notice that we
1396 * should quit now.
1397 *
1398 * Called by REQUEST_QUIT() from utils.c(request_quit)
1399 */
1400void
fba45db2 1401mach3_request_quit (void)
c906108c
SS
1402{
1403 if (mach_really_waiting)
1404 immediate_quit = 1;
c5aa993b 1405}
c906108c
SS
1406#endif
1407
1408/*
1409 * Gdb message server.
1410 * Currently implemented is the STOP message, that causes
1411 * gdb to return to the command level like ^C had been typed from terminal.
1412 */
1413int
fba45db2 1414gdb_message_server (mach_msg_header_t *InP)
c906108c
SS
1415{
1416 kern_return_t ret;
1417 int mid;
1418
1419 if (InP->msgh_local_port == our_message_port)
1420 {
1421 /* A message coming to our_message_port. Check validity */
c5aa993b
JM
1422 switch (InP->msgh_id)
1423 {
c906108c 1424
c5aa993b
JM
1425 case GDB_MESSAGE_ID_STOP:
1426 ret = task_suspend (inferior_task);
1427 if (ret != KERN_SUCCESS)
1428 warning ("Could not suspend task for stop message: %s",
1429 mach_error_string (ret));
c906108c 1430
c5aa993b
JM
1431 /* QUIT in mach_really_wait() loop. */
1432 request_quit (0);
1433 break;
c906108c 1434
c5aa993b
JM
1435 default:
1436 warning ("Invalid message id %d received, ignored.",
1437 InP->msgh_id);
1438 break;
1439 }
c906108c
SS
1440
1441 return 1;
1442 }
1443
1444 /* Message not handled by this server */
1445 return 0;
1446}
1447
1448/* NOTE: This is not an RPC call. It is a simpleroutine.
c5aa993b 1449
c906108c
SS
1450 * This is not called from this gdb code.
1451 *
1452 * It may be called by another debugger to cause this
1453 * debugger to enter command level:
1454 *
1455 * (gdb) set stop_inferior_gdb ()
1456 * (gdb) continue
1457 *
1458 * External program "stop-gdb" implements this also.
1459 */
1460void
fba45db2 1461stop_inferior_gdb (void)
c906108c
SS
1462{
1463 kern_return_t ret;
1464
1465 /* Code generated by mig, with minor cleanups :-)
c5aa993b 1466
c906108c
SS
1467 * simpleroutine stop_inferior_gdb (our_message_port : mach_port_t);
1468 */
1469
c5aa993b
JM
1470 typedef struct
1471 {
1472 mach_msg_header_t Head;
1473 }
1474 Request;
c906108c
SS
1475
1476 Request Mess;
1477
1478 register Request *InP = &Mess;
1479
c5aa993b 1480 InP->Head.msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND, 0);
c906108c
SS
1481
1482 /* msgh_size passed as argument */
1483 InP->Head.msgh_remote_port = our_message_port;
c5aa993b
JM
1484 InP->Head.msgh_local_port = MACH_PORT_NULL;
1485 InP->Head.msgh_seqno = 0;
1486 InP->Head.msgh_id = GDB_MESSAGE_ID_STOP;
c906108c
SS
1487
1488 ret = mach_msg (&InP->Head,
c5aa993b
JM
1489 MACH_SEND_MSG | MACH_MSG_OPTION_NONE,
1490 sizeof (Request),
c906108c
SS
1491 0,
1492 MACH_PORT_NULL,
1493 MACH_MSG_TIMEOUT_NONE,
1494 MACH_PORT_NULL);
1495}
1496
1497#ifdef THREAD_ALLOWED_TO_BREAK
1498/*
1499 * Return 1 if the MID specifies the thread that caused the
1500 * last exception.
1501 * Since catch_exception_raise() selects the thread causing
1502 * the last exception to current_thread, we just check that
1503 * it is selected and the last exception was a breakpoint.
1504 */
1505int
fba45db2 1506mach_thread_for_breakpoint (int mid)
c906108c
SS
1507{
1508 int cmid = map_port_name_to_mid (current_thread, MACH_TYPE_THREAD);
1509
1510 if (mid < 0)
1511 {
c5aa993b 1512 mid = map_slot_to_mid (-(mid + 1), 0, 0);
c906108c
SS
1513 if (mid < 0)
1514 return 0; /* Don't stop, no such slot */
1515 }
1516
c5aa993b
JM
1517 if (!mid || cmid == -1)
1518 return 1; /* stop */
c906108c
SS
1519
1520 return cmid == mid && stop_exception == EXC_BREAKPOINT;
1521}
1522#endif /* THREAD_ALLOWED_TO_BREAK */
1523
1524#ifdef THREAD_PARSE_ID
1525/*
1526 * Map a thread id string (MID or a @SLOTNUMBER)
1527 * to a thread-id.
1528 *
1529 * 0 matches all threads.
1530 * Otherwise the meaning is defined only in this file.
1531 * (mach_thread_for_breakpoint uses it)
1532 *
1533 * @@ This allows non-existent MIDs to be specified.
1534 * It now also allows non-existent slots to be
1535 * specified. (Slot numbers stored are negative,
1536 * and the magnitude is one greater than the actual
1537 * slot index. (Since 0 is reserved))
1538 */
1539int
fba45db2 1540mach_thread_parse_id (char *arg)
c906108c
SS
1541{
1542 int mid;
1543 if (arg == 0)
8e1a459b 1544 error ("thread id expected");
c906108c
SS
1545 mid = parse_thread_id (arg, 0, 1);
1546
1547 return mid;
1548}
1549#endif /* THREAD_PARSE_ID */
1550
1551#ifdef THREAD_OUTPUT_ID
1552char *
fba45db2 1553mach_thread_output_id (int mid)
c906108c 1554{
c5aa993b 1555 static char foobar[20];
c906108c
SS
1556
1557 if (mid > 0)
1558 sprintf (foobar, "mid %d", mid);
1559 else if (mid < 0)
c5aa993b 1560 sprintf (foobar, "@%d", -(mid + 1));
c906108c
SS
1561 else
1562 sprintf (foobar, "*any thread*");
1563
1564 return foobar;
1565}
1566#endif /* THREAD_OUTPUT_ID */
1567
1568/* Called with hook PREPARE_TO_PROCEED() from infrun.c.
c5aa993b 1569
c906108c
SS
1570 * If we have switched threads and stopped at breakpoint return 1 otherwise 0.
1571 *
1572 * if SELECT_IT is nonzero, reselect the thread that was active when
1573 * we stopped at a breakpoint.
1574 *
1575 */
1576
fba45db2 1577mach3_prepare_to_proceed (int select_it)
c906108c
SS
1578{
1579 if (stop_thread &&
1580 stop_thread != current_thread &&
1581 stop_exception == EXC_BREAKPOINT)
1582 {
1583 int mid;
1584
c5aa993b 1585 if (!select_it)
c906108c
SS
1586 return 1;
1587
1588 mid = switch_to_thread (stop_thread);
1589
1590 return 1;
1591 }
1592
1593 return 0;
1594}
1595
1596/* this stuff here is an upcall via libmach/excServer.c
1597 and mach_really_wait which does the actual upcall.
1598
1599 The code will pass the exception to the inferior if:
1600
c5aa993b
JM
1601 - The task that signaled is not the inferior task
1602 (e.g. when debugging another debugger)
c906108c 1603
c5aa993b
JM
1604 - The user has explicitely requested to pass on the exceptions.
1605 (e.g to the default unix exception handler, which maps
1606 exceptions to signals, or the user has her own exception handler)
c906108c 1607
c5aa993b
JM
1608 - If the thread that signaled is being single-stepped and it
1609 has set it's own exception port and the exception is not
1610 EXC_BREAKPOINT. (Maybe this is not desirable?)
c906108c
SS
1611 */
1612
1613kern_return_t
fba45db2
KB
1614catch_exception_raise (mach_port_t port, thread_t thread, task_t task,
1615 int exception, int code, int subcode)
c906108c
SS
1616{
1617 kern_return_t ret;
1618 boolean_t signal_thread;
1619 int mid = map_port_name_to_mid (thread, MACH_TYPE_THREAD);
1620
c5aa993b 1621 if (!MACH_PORT_VALID (thread))
c906108c
SS
1622 {
1623 /* If the exception was sent and thread dies before we
c5aa993b 1624 receive it, THREAD will be MACH_PORT_DEAD
c906108c
SS
1625 */
1626
1627 current_thread = thread = MACH_PORT_NULL;
1628 error ("Received exception from nonexistent thread");
1629 }
1630
1631 /* Check if the task died in transit.
1632 * @@ Isn't the thread also invalid in such case?
1633 */
c5aa993b 1634 if (!MACH_PORT_VALID (task))
c906108c
SS
1635 {
1636 current_thread = thread = MACH_PORT_NULL;
1637 error ("Received exception from nonexistent task");
1638 }
1639
1640 if (exception < 0 || exception > MAX_EXCEPTION)
8e65ff28
AC
1641 internal_error (__FILE__, __LINE__,
1642 "catch_exception_raise: unknown exception code %d thread %d",
96baa820
JM
1643 exception,
1644 mid);
c906108c 1645
c5aa993b 1646 if (!MACH_PORT_VALID (inferior_task))
c906108c 1647 error ("got an exception, but inferior_task is null or dead");
c5aa993b 1648
c906108c 1649 stop_exception = exception;
c5aa993b
JM
1650 stop_code = code;
1651 stop_subcode = subcode;
1652 stop_thread = thread;
1653
1654 signal_thread = exception != EXC_BREAKPOINT &&
1655 port == singlestepped_thread_port &&
1656 MACH_PORT_VALID (thread_saved_exception_port);
c906108c
SS
1657
1658 /* If it was not our inferior or if we want to forward
1659 * the exception to the inferior's handler, do it here
1660 *
1661 * Note: If you have forwarded EXC_BREAKPOINT I trust you know why.
1662 */
1663 if (task != inferior_task ||
c5aa993b
JM
1664 signal_thread ||
1665 exception_map[exception].forward)
c906108c
SS
1666 {
1667 mach_port_t eport = inferior_old_exception_port;
1668
1669 if (signal_thread)
1670 {
1671 /*
c5aa993b
JM
1672 GDB now forwards the exeption to thread's original handler,
1673 since the user propably knows what he is doing.
1674 Give a message, though.
c906108c
SS
1675 */
1676
c5aa993b 1677 mach3_exception_actions ((WAITTYPE *) NULL, TRUE, "Thread");
c906108c
SS
1678 eport = thread_saved_exception_port;
1679 }
1680
1681 /* Send the exception to the original handler */
1682 ret = exception_raise (eport,
c5aa993b 1683 thread,
c906108c
SS
1684 task,
1685 exception,
1686 code,
1687 subcode);
1688
1689 (void) mach_port_deallocate (mach_task_self (), task);
1690 (void) mach_port_deallocate (mach_task_self (), thread);
1691
1692 /* If we come here, we don't want to trace any more, since we
1693 * will never stop for tracing anyway.
1694 */
1695 discard_single_step (thread);
1696
1697 /* Do not stop the inferior */
1698 return ret;
1699 }
c5aa993b 1700
c906108c
SS
1701 /* Now gdb handles the exception */
1702 stopped_in_exception = TRUE;
1703
1704 ret = task_suspend (task);
1705 CHK ("Error suspending inferior after exception", ret);
1706
1707 must_suspend_thread = 0;
1708
1709 if (current_thread != thread)
1710 {
1711 if (MACH_PORT_VALID (singlestepped_thread_port))
1712 /* Cleanup discards single stepping */
1713 error ("Exception from thread %d while singlestepping thread %d",
1714 mid,
1715 map_port_name_to_mid (current_thread, MACH_TYPE_THREAD));
c5aa993b 1716
c906108c
SS
1717 /* Then select the thread that caused the exception */
1718 if (select_thread (inferior_task, mid, 0) != KERN_SUCCESS)
1719 error ("Could not select thread %d causing exception", mid);
1720 else
1721 warning ("Gdb selected thread %d", mid);
1722 }
1723
1724 /* If we receive an exception that is not breakpoint
1725 * exception, we interrupt the single step and return to
1726 * debugger. Trace condition is cleared.
1727 */
1728 if (MACH_PORT_VALID (singlestepped_thread_port))
1729 {
1730 if (stop_exception != EXC_BREAKPOINT)
1731 warning ("Single step interrupted by exception");
1732 else if (port == singlestepped_thread_port)
1733 {
1734 /* Single step exception occurred, remove trace bit
1735 * and return to gdb.
1736 */
c5aa993b 1737 if (!MACH_PORT_VALID (current_thread))
c906108c 1738 error ("Single stepped thread is not valid");
c5aa993b 1739
c906108c
SS
1740 /* Resume threads, but leave the task suspended */
1741 resume_all_threads (0);
1742 }
1743 else
1744 warning ("Breakpoint while single stepping?");
1745
1746 discard_single_step (current_thread);
1747 }
c5aa993b 1748
c906108c
SS
1749 (void) mach_port_deallocate (mach_task_self (), task);
1750 (void) mach_port_deallocate (mach_task_self (), thread);
1751
1752 return KERN_SUCCESS;
1753}
1754\f
1755int
fba45db2 1756port_valid (mach_port_t port, int mask)
c906108c
SS
1757{
1758 kern_return_t ret;
1759 mach_port_type_t type;
1760
1761 ret = mach_port_type (mach_task_self (),
1762 port,
1763 &type);
1764 if (ret != KERN_SUCCESS || (type & mask) != mask)
1765 return 0;
1766 return 1;
1767}
1768\f
1769/* @@ No vm read cache implemented yet */
1770boolean_t vm_read_cache_valid = FALSE;
1771
1772/*
1773 * Read inferior task's LEN bytes from ADDR and copy it to MYADDR
1774 * in gdb's address space.
1775 *
1776 * Return 0 on failure; number of bytes read otherwise.
1777 */
1778int
fba45db2 1779mach3_read_inferior (CORE_ADDR addr, char *myaddr, int length)
c906108c
SS
1780{
1781 kern_return_t ret;
c5aa993b
JM
1782 vm_address_t low_address = (vm_address_t) trunc_page (addr);
1783 vm_size_t aligned_length =
1784 (vm_size_t) round_page (addr + length) - low_address;
1785 pointer_t copied_memory;
1786 int copy_count;
c906108c
SS
1787
1788 /* Get memory from inferior with page aligned addresses */
1789 ret = vm_read (inferior_task,
1790 low_address,
1791 aligned_length,
1792 &copied_memory,
1793 &copy_count);
1794 if (ret != KERN_SUCCESS)
1795 {
1796 /* the problem is that the inferior might be killed for whatever reason
1797 * before we go to mach_really_wait. This is one place that ought to
1798 * catch many of those errors.
1799 * @@ A better fix would be to make all external events to GDB
1800 * to arrive via a SINGLE port set. (Including user input!)
1801 */
1802
c5aa993b 1803 if (!port_valid (inferior_task, MACH_PORT_TYPE_SEND))
c906108c
SS
1804 {
1805 m3_kill_inferior ();
1806 error ("Inferior killed (task port invalid)");
1807 }
1808 else
1809 {
1810#ifdef OSF
1811 extern int errno;
1812 /* valprint.c gives nicer format if this does not
1813 screw it. Eamonn seems to like this, so I enable
1814 it if OSF is defined...
1815 */
1816 warning ("[read inferior %x failed: %s]",
1817 addr, mach_error_string (ret));
1818 errno = 0;
1819#endif
1820 return 0;
1821 }
1822 }
1823
c5aa993b 1824 memcpy (myaddr, (char *) addr - low_address + copied_memory, length);
c906108c
SS
1825
1826 ret = vm_deallocate (mach_task_self (),
1827 copied_memory,
1828 copy_count);
c5aa993b 1829 CHK ("mach3_read_inferior vm_deallocate failed", ret);
c906108c
SS
1830
1831 return length;
1832}
1833
1834#ifdef __STDC__
1835#define CHK_GOTO_OUT(str,ret) \
1836 do if (ret != KERN_SUCCESS) { errstr = #str; goto out; } while(0)
1837#else
1838#define CHK_GOTO_OUT(str,ret) \
1839 do if (ret != KERN_SUCCESS) { errstr = str; goto out; } while(0)
1840#endif
1841
c5aa993b
JM
1842struct vm_region_list
1843{
c906108c 1844 struct vm_region_list *next;
c5aa993b
JM
1845 vm_prot_t protection;
1846 vm_address_t start;
1847 vm_size_t length;
c906108c
SS
1848};
1849
c5aa993b 1850struct obstack region_obstack;
c906108c
SS
1851
1852/*
1853 * Write inferior task's LEN bytes from ADDR and copy it to MYADDR
1854 * in gdb's address space.
1855 */
1856int
fba45db2 1857mach3_write_inferior (CORE_ADDR addr, char *myaddr, int length)
c906108c
SS
1858{
1859 kern_return_t ret;
c5aa993b
JM
1860 vm_address_t low_address = (vm_address_t) trunc_page (addr);
1861 vm_size_t aligned_length =
1862 (vm_size_t) round_page (addr + length) - low_address;
1863 pointer_t copied_memory;
1864 int copy_count;
1865 int deallocate = 0;
c906108c 1866
c5aa993b 1867 char *errstr = "Bug in mach3_write_inferior";
c906108c
SS
1868
1869 struct vm_region_list *region_element;
c5aa993b 1870 struct vm_region_list *region_head = (struct vm_region_list *) NULL;
c906108c
SS
1871
1872 /* Get memory from inferior with page aligned addresses */
1873 ret = vm_read (inferior_task,
1874 low_address,
1875 aligned_length,
1876 &copied_memory,
1877 &copy_count);
1878 CHK_GOTO_OUT ("mach3_write_inferior vm_read failed", ret);
1879
1880 deallocate++;
1881
c5aa993b 1882 memcpy ((char *) addr - low_address + copied_memory, myaddr, length);
c906108c
SS
1883
1884 obstack_init (&region_obstack);
1885
1886 /* Do writes atomically.
1887 * First check for holes and unwritable memory.
1888 */
1889 {
c5aa993b
JM
1890 vm_size_t remaining_length = aligned_length;
1891 vm_address_t region_address = low_address;
c906108c
SS
1892
1893 struct vm_region_list *scan;
1894
c5aa993b 1895 while (region_address < low_address + aligned_length)
c906108c
SS
1896 {
1897 vm_prot_t protection;
1898 vm_prot_t max_protection;
1899 vm_inherit_t inheritance;
1900 boolean_t shared;
1901 mach_port_t object_name;
1902 vm_offset_t offset;
c5aa993b
JM
1903 vm_size_t region_length = remaining_length;
1904 vm_address_t old_address = region_address;
1905
c906108c
SS
1906 ret = vm_region (inferior_task,
1907 &region_address,
1908 &region_length,
1909 &protection,
1910 &max_protection,
1911 &inheritance,
1912 &shared,
1913 &object_name,
1914 &offset);
1915 CHK_GOTO_OUT ("vm_region failed", ret);
1916
1917 /* Check for holes in memory */
1918 if (old_address != region_address)
1919 {
1920 warning ("No memory at 0x%x. Nothing written",
1921 old_address);
1922 ret = KERN_SUCCESS;
1923 length = 0;
1924 goto out;
1925 }
1926
1927 if (!(max_protection & VM_PROT_WRITE))
1928 {
1929 warning ("Memory at address 0x%x is unwritable. Nothing written",
1930 old_address);
1931 ret = KERN_SUCCESS;
1932 length = 0;
1933 goto out;
1934 }
1935
1936 /* Chain the regions for later use */
c5aa993b 1937 region_element =
c906108c 1938 (struct vm_region_list *)
c5aa993b
JM
1939 obstack_alloc (&region_obstack, sizeof (struct vm_region_list));
1940
c906108c 1941 region_element->protection = protection;
c5aa993b
JM
1942 region_element->start = region_address;
1943 region_element->length = region_length;
c906108c
SS
1944
1945 /* Chain the regions along with protections */
1946 region_element->next = region_head;
c5aa993b
JM
1947 region_head = region_element;
1948
c906108c
SS
1949 region_address += region_length;
1950 remaining_length = remaining_length - region_length;
1951 }
1952
1953 /* If things fail after this, we give up.
1954 * Somebody is messing up inferior_task's mappings.
1955 */
c5aa993b 1956
c906108c
SS
1957 /* Enable writes to the chained vm regions */
1958 for (scan = region_head; scan; scan = scan->next)
1959 {
1960 boolean_t protection_changed = FALSE;
c5aa993b 1961
c906108c
SS
1962 if (!(scan->protection & VM_PROT_WRITE))
1963 {
1964 ret = vm_protect (inferior_task,
1965 scan->start,
1966 scan->length,
1967 FALSE,
1968 scan->protection | VM_PROT_WRITE);
1969 CHK_GOTO_OUT ("vm_protect: enable write failed", ret);
1970 }
1971 }
1972
1973 ret = vm_write (inferior_task,
1974 low_address,
1975 copied_memory,
1976 aligned_length);
1977 CHK_GOTO_OUT ("vm_write failed", ret);
c5aa993b 1978
c906108c
SS
1979 /* Set up the original region protections, if they were changed */
1980 for (scan = region_head; scan; scan = scan->next)
1981 {
1982 boolean_t protection_changed = FALSE;
c5aa993b 1983
c906108c
SS
1984 if (!(scan->protection & VM_PROT_WRITE))
1985 {
1986 ret = vm_protect (inferior_task,
1987 scan->start,
1988 scan->length,
1989 FALSE,
1990 scan->protection);
1991 CHK_GOTO_OUT ("vm_protect: enable write failed", ret);
1992 }
1993 }
1994 }
1995
c5aa993b 1996out:
c906108c
SS
1997 if (deallocate)
1998 {
1999 obstack_free (&region_obstack, 0);
c5aa993b 2000
c906108c
SS
2001 (void) vm_deallocate (mach_task_self (),
2002 copied_memory,
2003 copy_count);
2004 }
2005
2006 if (ret != KERN_SUCCESS)
2007 {
2008 warning ("%s %s", errstr, mach_error_string (ret));
2009 return 0;
2010 }
2011
2012 return length;
2013}
2014
ad525611
KB
2015/* Return 0 on failure, number of bytes handled otherwise. TARGET is
2016 ignored. */
c906108c 2017static int
ad525611
KB
2018m3_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write,
2019 struct target_ops *target)
c906108c
SS
2020{
2021 int result;
2022
2023 if (write)
2024 result = mach3_write_inferior (memaddr, myaddr, len);
2025 else
c5aa993b 2026 result = mach3_read_inferior (memaddr, myaddr, len);
c906108c
SS
2027
2028 return result;
2029}
c906108c 2030\f
c5aa993b 2031
c906108c 2032static char *
fba45db2 2033translate_state (int state)
c906108c 2034{
c5aa993b
JM
2035 switch (state)
2036 {
2037 case TH_STATE_RUNNING:
2038 return ("R");
2039 case TH_STATE_STOPPED:
2040 return ("S");
2041 case TH_STATE_WAITING:
2042 return ("W");
2043 case TH_STATE_UNINTERRUPTIBLE:
2044 return ("U");
2045 case TH_STATE_HALTED:
2046 return ("H");
2047 default:
2048 return ("?");
2049 }
c906108c
SS
2050}
2051
2052static char *
fba45db2 2053translate_cstate (int state)
c906108c
SS
2054{
2055 switch (state)
2056 {
c5aa993b
JM
2057 case CPROC_RUNNING:
2058 return "R";
2059 case CPROC_SWITCHING:
2060 return "S";
2061 case CPROC_BLOCKED:
2062 return "B";
2063 case CPROC_CONDWAIT:
2064 return "C";
2065 case CPROC_CONDWAIT | CPROC_SWITCHING:
2066 return "CS";
2067 default:
2068 return "?";
c906108c
SS
2069 }
2070}
2071
2072/* type == MACH_MSG_TYPE_COPY_SEND || type == MACH_MSG_TYPE_MAKE_SEND */
2073
c5aa993b 2074mach_port_t /* no mach_port_name_t found in include files. */
fba45db2 2075map_inferior_port_name (mach_port_t inferior_name, mach_msg_type_name_t type)
c906108c 2076{
c5aa993b 2077 kern_return_t ret;
c906108c 2078 mach_msg_type_name_t acquired;
c5aa993b
JM
2079 mach_port_t iport;
2080
c906108c
SS
2081 ret = mach_port_extract_right (inferior_task,
2082 inferior_name,
2083 type,
2084 &iport,
2085 &acquired);
c5aa993b 2086 CHK ("mach_port_extract_right (map_inferior_port_name)", ret);
c906108c
SS
2087
2088 if (acquired != MACH_MSG_TYPE_PORT_SEND)
c5aa993b 2089 error ("Incorrect right extracted, (map_inferior_port_name)");
c906108c
SS
2090
2091 ret = mach_port_deallocate (mach_task_self (),
2092 iport);
2093 CHK ("Deallocating mapped port (map_inferior_port_name)", ret);
2094
2095 return iport;
2096}
2097
2098/*
2099 * Naming convention:
2100 * Always return user defined name if found.
2101 * _K == A kernel thread with no matching CPROC
2102 * _C == A cproc with no current cthread
2103 * _t == A cthread with no user defined name
2104 *
2105 * The digits that follow the _names are the SLOT number of the
2106 * kernel thread if there is such a thing, otherwise just a negation
2107 * of the sequential number of such cprocs.
2108 */
2109
2110static char buf[7];
2111
2112static char *
fba45db2 2113get_thread_name (gdb_thread_t one_cproc, int id)
c906108c
SS
2114{
2115 if (one_cproc)
2116 if (one_cproc->cthread == NULL)
2117 {
2118 /* cproc not mapped to any cthread */
c5aa993b 2119 sprintf (buf, "_C%d", id);
c906108c 2120 }
c5aa993b 2121 else if (!one_cproc->cthread->name)
c906108c
SS
2122 {
2123 /* cproc and cthread, but no name */
c5aa993b 2124 sprintf (buf, "_t%d", id);
c906108c
SS
2125 }
2126 else
c5aa993b 2127 return (char *) (one_cproc->cthread->name);
c906108c
SS
2128 else
2129 {
2130 if (id < 0)
2131 warning ("Inconsistency in thread name id %d", id);
2132
2133 /* Kernel thread without cproc */
c5aa993b 2134 sprintf (buf, "_K%d", id);
c906108c
SS
2135 }
2136
2137 return buf;
2138}
2139
2140int
ad525611 2141fetch_thread_info (mach_port_t task, gdb_thread_t *mthreads_out)
c906108c 2142{
c5aa993b 2143 kern_return_t ret;
c906108c 2144 thread_array_t th_table;
c5aa993b 2145 int th_count;
c906108c 2146 gdb_thread_t mthreads = NULL;
c5aa993b 2147 int index;
c906108c
SS
2148
2149 ret = task_threads (task, &th_table, &th_count);
2150 if (ret != KERN_SUCCESS)
2151 {
2152 warning ("Error getting inferior's thread list:%s",
c5aa993b 2153 mach_error_string (ret));
c906108c
SS
2154 m3_kill_inferior ();
2155 return -1;
2156 }
c5aa993b 2157
c906108c 2158 mthreads = (gdb_thread_t)
c5aa993b
JM
2159 obstack_alloc
2160 (cproc_obstack,
2161 th_count * sizeof (struct gdb_thread));
c906108c
SS
2162
2163 for (index = 0; index < th_count; index++)
2164 {
2165 thread_t saved_thread = MACH_PORT_NULL;
2166 int mid;
2167
2168 if (must_suspend_thread)
c5aa993b 2169 setup_thread (th_table[index], 1);
c906108c
SS
2170
2171 if (th_table[index] != current_thread)
2172 {
2173 saved_thread = current_thread;
c5aa993b
JM
2174
2175 mid = switch_to_thread (th_table[index]);
c906108c
SS
2176 }
2177
c5aa993b 2178 mthreads[index].name = th_table[index];
c906108c
SS
2179 mthreads[index].cproc = NULL; /* map_cprocs_to_kernel_threads() */
2180 mthreads[index].in_emulator = FALSE;
2181 mthreads[index].slotid = index;
c5aa993b 2182
c906108c
SS
2183 mthreads[index].sp = read_register (SP_REGNUM);
2184 mthreads[index].fp = read_register (FP_REGNUM);
2185 mthreads[index].pc = read_pc ();
2186
2187 if (MACH_PORT_VALID (saved_thread))
2188 mid = switch_to_thread (saved_thread);
2189
2190 if (must_suspend_thread)
c5aa993b 2191 setup_thread (th_table[index], 0);
c906108c 2192 }
c5aa993b 2193
c906108c 2194 consume_send_rights (th_table, th_count);
c5aa993b
JM
2195 ret = vm_deallocate (mach_task_self (), (vm_address_t) th_table,
2196 (th_count * sizeof (mach_port_t)));
c906108c
SS
2197 if (ret != KERN_SUCCESS)
2198 {
2199 warning ("Error trying to deallocate thread list : %s",
2200 mach_error_string (ret));
2201 }
2202
2203 *mthreads_out = mthreads;
2204
2205 return th_count;
2206}
2207
2208
2209/*
2210 * Current emulator always saves the USP on top of
2211 * emulator stack below struct emul_stack_top stuff.
2212 */
2213CORE_ADDR
fba45db2 2214fetch_usp_from_emulator_stack (CORE_ADDR sp)
c906108c
SS
2215{
2216 CORE_ADDR stack_pointer;
2217
c5aa993b
JM
2218 sp = (sp & ~(EMULATOR_STACK_SIZE - 1)) +
2219 EMULATOR_STACK_SIZE - sizeof (struct emul_stack_top);
2220
c906108c
SS
2221 if (mach3_read_inferior (sp,
2222 &stack_pointer,
2223 sizeof (CORE_ADDR)) != sizeof (CORE_ADDR))
2224 {
2225 warning ("Can't read user sp from emulator stack address 0x%x", sp);
2226 return 0;
2227 }
2228
2229 return stack_pointer;
2230}
2231
2232#ifdef MK67
2233
2234/* get_emulation_vector() interface was changed after mk67 */
2235#define EMUL_VECTOR_COUNT 400 /* Value does not matter too much */
2236
2237#endif /* MK67 */
2238
2239/* Check if the emulator exists at task's address space.
2240 */
2241boolean_t
fba45db2 2242have_emulator_p (task_t task)
c906108c 2243{
c5aa993b 2244 kern_return_t ret;
c906108c 2245#ifndef EMUL_VECTOR_COUNT
c5aa993b
JM
2246 vm_offset_t *emulation_vector;
2247 int n;
c906108c 2248#else
c5aa993b
JM
2249 vm_offset_t emulation_vector[EMUL_VECTOR_COUNT];
2250 int n = EMUL_VECTOR_COUNT;
c906108c 2251#endif
c5aa993b
JM
2252 int i;
2253 int vector_start;
2254
c906108c
SS
2255 ret = task_get_emulation_vector (task,
2256 &vector_start,
2257#ifndef EMUL_VECTOR_COUNT
2258 &emulation_vector,
2259#else
2260 emulation_vector,
2261#endif
2262 &n);
c5aa993b 2263 CHK ("task_get_emulation_vector", ret);
c906108c
SS
2264 xx_debug ("%d vectors from %d at 0x%08x\n",
2265 n, vector_start, emulation_vector);
c5aa993b
JM
2266
2267 for (i = 0; i < n; i++)
c906108c 2268 {
c5aa993b 2269 vm_offset_t entry = emulation_vector[i];
c906108c
SS
2270
2271 if (EMULATOR_BASE <= entry && entry <= EMULATOR_END)
2272 return TRUE;
2273 else if (entry)
2274 {
2275 static boolean_t informed = FALSE;
2276 if (!informed)
2277 {
c5aa993b
JM
2278 warning ("Emulation vector address 0x08%x outside emulator space",
2279 entry);
c906108c
SS
2280 informed = TRUE;
2281 }
2282 }
2283 }
2284 return FALSE;
2285}
2286
2287/* Map cprocs to kernel threads and vice versa. */
2288
2289void
fba45db2
KB
2290map_cprocs_to_kernel_threads (gdb_thread_t cprocs, gdb_thread_t mthreads,
2291 int thread_count)
c906108c
SS
2292{
2293 int index;
2294 gdb_thread_t scan;
2295 boolean_t all_mapped = TRUE;
2296 LONGEST stack_base;
2297 LONGEST stack_size;
2298
2299 for (scan = cprocs; scan; scan = scan->next)
2300 {
2301 /* Default to: no kernel thread for this cproc */
2302 scan->reverse_map = -1;
2303
2304 /* Check if the cproc is found by its stack */
2305 for (index = 0; index < thread_count; index++)
2306 {
2307 stack_base =
2308 extract_signed_integer (scan->raw_cproc + CPROC_BASE_OFFSET,
2309 CPROC_BASE_SIZE);
c5aa993b 2310 stack_size =
c906108c
SS
2311 extract_signed_integer (scan->raw_cproc + CPROC_SIZE_OFFSET,
2312 CPROC_SIZE_SIZE);
2313 if ((mthreads + index)->sp > stack_base &&
2314 (mthreads + index)->sp <= stack_base + stack_size)
2315 {
2316 (mthreads + index)->cproc = scan;
2317 scan->reverse_map = index;
2318 break;
2319 }
2320 }
2321 all_mapped &= (scan->reverse_map != -1);
2322 }
2323
2324 /* Check for threads that are currently in the emulator.
2325 * If so, they have a different stack, and the still unmapped
2326 * cprocs may well get mapped to these threads.
2327 *
2328 * If:
2329 * - cproc stack does not match any kernel thread stack pointer
2330 * - there is at least one extra kernel thread
2331 * that has no cproc mapped above.
2332 * - some kernel thread stack pointer points to emulator space
2333 * then we find the user stack pointer saved in the emulator
2334 * stack, and try to map that to the cprocs.
2335 *
2336 * Also set in_emulator for kernel threads.
c5aa993b 2337 */
c906108c
SS
2338
2339 if (emulator_present)
2340 {
2341 for (index = 0; index < thread_count; index++)
2342 {
2343 CORE_ADDR emul_sp;
2344 CORE_ADDR usp;
2345
c5aa993b 2346 gdb_thread_t mthread = (mthreads + index);
c906108c
SS
2347 emul_sp = mthread->sp;
2348
2349 if (mthread->cproc == NULL &&
2350 EMULATOR_BASE <= emul_sp && emul_sp <= EMULATOR_END)
2351 {
2352 mthread->in_emulator = emulator_present;
c5aa993b 2353
c906108c
SS
2354 if (!all_mapped && cprocs)
2355 {
2356 usp = fetch_usp_from_emulator_stack (emul_sp);
c5aa993b 2357
c906108c 2358 /* @@ Could be more accurate */
c5aa993b 2359 if (!usp)
c906108c 2360 error ("Zero stack pointer read from emulator?");
c5aa993b 2361
c906108c
SS
2362 /* Try to match this stack pointer to the cprocs that
2363 * don't yet have a kernel thread.
2364 */
2365 for (scan = cprocs; scan; scan = scan->next)
2366 {
c5aa993b 2367
c906108c
SS
2368 /* Check is this unmapped CPROC stack contains
2369 * the user stack pointer saved in the
2370 * emulator.
2371 */
2372 if (scan->reverse_map == -1)
2373 {
2374 stack_base =
2375 extract_signed_integer
c5aa993b
JM
2376 (scan->raw_cproc + CPROC_BASE_OFFSET,
2377 CPROC_BASE_SIZE);
2378 stack_size =
c906108c 2379 extract_signed_integer
c5aa993b
JM
2380 (scan->raw_cproc + CPROC_SIZE_OFFSET,
2381 CPROC_SIZE_SIZE);
c906108c
SS
2382 if (usp > stack_base &&
2383 usp <= stack_base + stack_size)
2384 {
2385 mthread->cproc = scan;
2386 scan->reverse_map = index;
2387 break;
2388 }
2389 }
2390 }
2391 }
2392 }
2393 }
2394 }
2395}
2396\f
2397/*
2398 * Format of the thread_list command
2399 *
c5aa993b 2400 * slot mid sel name emul ks susp cstate wired address
c906108c
SS
2401 */
2402#define TL_FORMAT "%-2.2s %5d%c %-10.10s %1.1s%s%-5.5s %-2.2s %-5.5s "
2403
2404#define TL_HEADER "\n@ MID Name KState CState Where\n"
2405
2406void
fba45db2 2407print_tl_address (struct ui_file *stream, CORE_ADDR pc)
c906108c 2408{
c5aa993b
JM
2409 if (!lookup_minimal_symbol_by_pc (pc))
2410 fprintf_filtered (stream, local_hex_format (), pc);
c906108c
SS
2411 else
2412 {
2413 extern int addressprint;
2414 extern int asm_demangle;
2415
c5aa993b 2416 int store = addressprint;
c906108c
SS
2417 addressprint = 0;
2418 print_address_symbolic (pc, stream, asm_demangle, "");
2419 addressprint = store;
2420 }
2421}
2422\f
2423/* For thread names, but also for gdb_message_port external name */
2424#define MAX_NAME_LEN 50
2425
2426/* Returns the address of variable NAME or 0 if not found */
2427CORE_ADDR
fba45db2 2428lookup_address_of_variable (char *name)
c906108c
SS
2429{
2430 struct symbol *sym;
2431 CORE_ADDR symaddr = 0;
2432 struct minimal_symbol *msymbol;
2433
2434 sym = lookup_symbol (name,
c5aa993b 2435 (struct block *) NULL,
c906108c 2436 VAR_NAMESPACE,
c5aa993b
JM
2437 (int *) NULL,
2438 (struct symtab **) NULL);
c906108c
SS
2439
2440 if (sym)
2441 symaddr = SYMBOL_VALUE (sym);
2442
c5aa993b 2443 if (!symaddr)
c906108c
SS
2444 {
2445 msymbol = lookup_minimal_symbol (name, NULL, NULL);
2446
2447 if (msymbol && msymbol->type == mst_data)
2448 symaddr = SYMBOL_VALUE_ADDRESS (msymbol);
2449 }
2450
2451 return symaddr;
2452}
2453
2454static gdb_thread_t
fba45db2 2455get_cprocs (void)
c906108c
SS
2456{
2457 gdb_thread_t cproc_head;
2458 gdb_thread_t cproc_copy;
2459 CORE_ADDR their_cprocs;
35fc8285 2460 char *buf;
c906108c
SS
2461 char *name;
2462 cthread_t cthread;
2463 CORE_ADDR symaddr;
c5aa993b 2464
35fc8285 2465 buf = alloca (TARGET_PTR_BIT / HOST_CHAR_BIT);
c906108c
SS
2466 symaddr = lookup_address_of_variable ("cproc_list");
2467
c5aa993b 2468 if (!symaddr)
c906108c
SS
2469 {
2470 /* cproc_list is not in a file compiled with debugging
c5aa993b 2471 symbols, but don't give up yet */
c906108c
SS
2472
2473 symaddr = lookup_address_of_variable ("cprocs");
2474
2475 if (symaddr)
2476 {
2477 static int informed = 0;
2478 if (!informed)
2479 {
2480 informed++;
2481 warning ("Your program is loaded with an old threads library.");
2482 warning ("GDB does not know the old form of threads");
2483 warning ("so things may not work.");
2484 }
2485 }
2486 }
2487
2488 /* Stripped or no -lthreads loaded or "cproc_list" is in wrong segment. */
c5aa993b 2489 if (!symaddr)
c906108c
SS
2490 return NULL;
2491
2492 /* Get the address of the first cproc in the task */
2493 if (!mach3_read_inferior (symaddr,
2494 buf,
2495 TARGET_PTR_BIT / HOST_CHAR_BIT))
2496 error ("Can't read cproc master list at address (0x%x).", symaddr);
2497 their_cprocs = extract_address (buf, TARGET_PTR_BIT / HOST_CHAR_BIT);
2498
2499 /* Scan the CPROCs in the task.
2500 CPROCs are chained with LIST field, not NEXT field, which
2501 chains mutexes, condition variables and queues */
2502
2503 cproc_head = NULL;
2504
c5aa993b 2505 while (their_cprocs != (CORE_ADDR) 0)
c906108c
SS
2506 {
2507 CORE_ADDR cproc_copy_incarnation;
2508 cproc_copy = (gdb_thread_t) obstack_alloc (cproc_obstack,
2509 sizeof (struct gdb_thread));
2510
2511 if (!mach3_read_inferior (their_cprocs,
2512 &cproc_copy->raw_cproc[0],
2513 CPROC_SIZE))
c5aa993b 2514 error ("Can't read next cproc at 0x%x.", their_cprocs);
c906108c
SS
2515
2516 their_cprocs =
2517 extract_address (cproc_copy->raw_cproc + CPROC_LIST_OFFSET,
2518 CPROC_LIST_SIZE);
2519 cproc_copy_incarnation =
2520 extract_address (cproc_copy->raw_cproc + CPROC_INCARNATION_OFFSET,
2521 CPROC_INCARNATION_SIZE);
2522
c5aa993b 2523 if (cproc_copy_incarnation == (CORE_ADDR) 0)
c906108c
SS
2524 cproc_copy->cthread = NULL;
2525 else
2526 {
2527 /* This CPROC has an attached CTHREAD. Get its name */
c5aa993b
JM
2528 cthread = (cthread_t) obstack_alloc (cproc_obstack,
2529 sizeof (struct cthread));
c906108c
SS
2530
2531 if (!mach3_read_inferior (cproc_copy_incarnation,
2532 cthread,
c5aa993b
JM
2533 sizeof (struct cthread)))
2534 error ("Can't read next thread at 0x%x.",
2535 cproc_copy_incarnation);
c906108c
SS
2536
2537 cproc_copy->cthread = cthread;
2538
2539 if (cthread->name)
2540 {
2541 name = (char *) obstack_alloc (cproc_obstack, MAX_NAME_LEN);
2542
c5aa993b
JM
2543 if (!mach3_read_inferior (cthread->name, name, MAX_NAME_LEN))
2544 error ("Can't read next thread's name at 0x%x.", cthread->name);
c906108c
SS
2545
2546 cthread->name = name;
2547 }
2548 }
2549
2550 /* insert in front */
2551 cproc_copy->next = cproc_head;
2552 cproc_head = cproc_copy;
2553 }
2554 return cproc_head;
2555}
2556
2557#ifndef FETCH_CPROC_STATE
2558/*
2559 * Check if your machine does not grok the way this routine
2560 * fetches the FP,PC and SP of a cproc that is not
2561 * currently attached to any kernel thread (e.g. its cproc.context
2562 * field points to the place in stack where the context
2563 * is saved).
2564 *
2565 * If it doesn't, define your own routine.
2566 */
2567#define FETCH_CPROC_STATE(mth) mach3_cproc_state (mth)
2568
2569int
fba45db2 2570mach3_cproc_state (gdb_thread_t mthread)
c906108c
SS
2571{
2572 int context;
2573
c5aa993b 2574 if (!mthread || !mthread->cproc)
c906108c
SS
2575 return -1;
2576
2577 context = extract_signed_integer
2578 (mthread->cproc->raw_cproc + CPROC_CONTEXT_OFFSET,
2579 CPROC_CONTEXT_SIZE);
2580 if (context == 0)
2581 return -1;
2582
2583 mthread->sp = context + MACHINE_CPROC_SP_OFFSET;
2584
2585 if (mach3_read_inferior (context + MACHINE_CPROC_PC_OFFSET,
2586 &mthread->pc,
2587 sizeof (CORE_ADDR)) != sizeof (CORE_ADDR))
2588 {
2589 warning ("Can't read cproc pc from inferior");
2590 return -1;
2591 }
2592
2593 if (mach3_read_inferior (context + MACHINE_CPROC_FP_OFFSET,
2594 &mthread->fp,
2595 sizeof (CORE_ADDR)) != sizeof (CORE_ADDR))
2596 {
2597 warning ("Can't read cproc fp from inferior");
2598 return -1;
2599 }
2600
2601 return 0;
2602}
2603#endif /* FETCH_CPROC_STATE */
c906108c 2604\f
c5aa993b 2605
c906108c 2606void
fba45db2 2607thread_list_command (void)
c906108c
SS
2608{
2609 thread_basic_info_data_t ths;
c5aa993b 2610 int thread_count;
c906108c
SS
2611 gdb_thread_t cprocs;
2612 gdb_thread_t scan;
c5aa993b
JM
2613 int index;
2614 char *name;
2615 char selected;
2616 char *wired;
2617 int infoCnt;
c906108c 2618 kern_return_t ret;
c5aa993b
JM
2619 mach_port_t mid_or_port;
2620 gdb_thread_t their_threads;
2621 gdb_thread_t kthread;
c906108c
SS
2622
2623 int neworder = 1;
2624
2625 char *fmt = "There are %d kernel threads in task %d.\n";
c5aa993b 2626
c906108c 2627 int tmid = map_port_name_to_mid (inferior_task, MACH_TYPE_TASK);
c5aa993b 2628
c906108c 2629 MACH_ERROR_NO_INFERIOR;
c5aa993b 2630
c906108c
SS
2631 thread_count = fetch_thread_info (inferior_task,
2632 &their_threads);
2633 if (thread_count == -1)
2634 return;
c5aa993b 2635
c906108c
SS
2636 if (thread_count == 1)
2637 fmt = "There is %d kernel thread in task %d.\n";
c5aa993b 2638
c906108c 2639 printf_filtered (fmt, thread_count, tmid);
c5aa993b 2640
c906108c 2641 puts_filtered (TL_HEADER);
c5aa993b
JM
2642
2643 cprocs = get_cprocs ();
2644
c906108c 2645 map_cprocs_to_kernel_threads (cprocs, their_threads, thread_count);
c5aa993b 2646
c906108c
SS
2647 for (scan = cprocs; scan; scan = scan->next)
2648 {
2649 int mid;
2650 char buf[10];
2651 char slot[3];
2652 int cproc_state =
c5aa993b
JM
2653 extract_signed_integer
2654 (scan->raw_cproc + CPROC_STATE_OFFSET, CPROC_STATE_SIZE);
2655
c906108c 2656 selected = ' ';
c5aa993b 2657
c906108c
SS
2658 /* a wired cproc? */
2659 wired = (extract_address (scan->raw_cproc + CPROC_WIRED_OFFSET,
2660 CPROC_WIRED_SIZE)
2661 ? "wired" : "");
2662
2663 if (scan->reverse_map != -1)
c5aa993b 2664 kthread = (their_threads + scan->reverse_map);
c906108c 2665 else
c5aa993b 2666 kthread = NULL;
c906108c
SS
2667
2668 if (kthread)
2669 {
2670 /* These cprocs have a kernel thread */
c5aa993b 2671
c906108c 2672 mid = map_port_name_to_mid (kthread->name, MACH_TYPE_THREAD);
c5aa993b 2673
c906108c 2674 infoCnt = THREAD_BASIC_INFO_COUNT;
c5aa993b 2675
c906108c
SS
2676 ret = thread_info (kthread->name,
2677 THREAD_BASIC_INFO,
c5aa993b 2678 (thread_info_t) & ths,
c906108c 2679 &infoCnt);
c5aa993b 2680
c906108c
SS
2681 if (ret != KERN_SUCCESS)
2682 {
2683 warning ("Unable to get basic info on thread %d : %s",
2684 mid,
2685 mach_error_string (ret));
2686 continue;
2687 }
2688
2689 /* Who is the first to have more than 100 threads */
c5aa993b 2690 sprintf (slot, "%d", kthread->slotid % 100);
c906108c
SS
2691
2692 if (kthread->name == current_thread)
2693 selected = '*';
c5aa993b 2694
c906108c
SS
2695 if (ths.suspend_count)
2696 sprintf (buf, "%d", ths.suspend_count);
2697 else
2698 buf[0] = '\000';
2699
2700#if 0
2701 if (ths.flags & TH_FLAGS_SWAPPED)
2702 strcat (buf, "S");
2703#endif
2704
2705 if (ths.flags & TH_FLAGS_IDLE)
2706 strcat (buf, "I");
2707
2708 printf_filtered (TL_FORMAT,
2709 slot,
2710 mid,
2711 selected,
2712 get_thread_name (scan, kthread->slotid),
2713 kthread->in_emulator ? "E" : "",
2714 translate_state (ths.run_state),
2715 buf,
2716 translate_cstate (cproc_state),
2717 wired);
2718 print_tl_address (gdb_stdout, kthread->pc);
2719 }
2720 else
2721 {
2722 /* These cprocs don't have a kernel thread.
2723 * find out the calling frame with
2724 * FETCH_CPROC_STATE.
2725 */
2726
2727 struct gdb_thread state;
2728
2729#if 0
2730 /* jtv -> emcmanus: why do you want this here? */
2731 if (scan->incarnation == NULL)
c5aa993b 2732 continue; /* EMcM */
c906108c
SS
2733#endif
2734
2735 printf_filtered (TL_FORMAT,
2736 "-",
2737 -neworder, /* Pseudo MID */
2738 selected,
2739 get_thread_name (scan, -neworder),
2740 "",
2741 "-", /* kernel state */
2742 "",
2743 translate_cstate (cproc_state),
2744 "");
2745 state.cproc = scan;
2746
2747 if (FETCH_CPROC_STATE (&state) == -1)
2748 puts_filtered ("???");
2749 else
2750 print_tl_address (gdb_stdout, state.pc);
2751
2752 neworder++;
2753 }
2754 puts_filtered ("\n");
2755 }
c5aa993b 2756
c906108c
SS
2757 /* Scan for kernel threads without cprocs */
2758 for (index = 0; index < thread_count; index++)
2759 {
c5aa993b 2760 if (!their_threads[index].cproc)
c906108c
SS
2761 {
2762 int mid;
c5aa993b 2763
c906108c
SS
2764 char buf[10];
2765 char slot[3];
2766
2767 mach_port_t name = their_threads[index].name;
c5aa993b 2768
c906108c 2769 mid = map_port_name_to_mid (name, MACH_TYPE_THREAD);
c5aa993b 2770
c906108c 2771 infoCnt = THREAD_BASIC_INFO_COUNT;
c5aa993b
JM
2772
2773 ret = thread_info (name,
2774 THREAD_BASIC_INFO,
2775 (thread_info_t) & ths,
2776 &infoCnt);
2777
c906108c
SS
2778 if (ret != KERN_SUCCESS)
2779 {
2780 warning ("Unable to get basic info on thread %d : %s",
2781 mid,
2782 mach_error_string (ret));
2783 continue;
2784 }
2785
c5aa993b 2786 sprintf (slot, "%d", index % 100);
c906108c
SS
2787
2788 if (name == current_thread)
2789 selected = '*';
2790 else
2791 selected = ' ';
2792
2793 if (ths.suspend_count)
2794 sprintf (buf, "%d", ths.suspend_count);
2795 else
2796 buf[0] = '\000';
2797
2798#if 0
2799 if (ths.flags & TH_FLAGS_SWAPPED)
2800 strcat (buf, "S");
2801#endif
2802
2803 if (ths.flags & TH_FLAGS_IDLE)
2804 strcat (buf, "I");
2805
2806 printf_filtered (TL_FORMAT,
2807 slot,
2808 mid,
2809 selected,
2810 get_thread_name (NULL, index),
2811 their_threads[index].in_emulator ? "E" : "",
2812 translate_state (ths.run_state),
2813 buf,
c5aa993b 2814 "", /* No cproc state */
c906108c
SS
2815 ""); /* Can't be wired */
2816 print_tl_address (gdb_stdout, their_threads[index].pc);
2817 puts_filtered ("\n");
2818 }
2819 }
c5aa993b 2820
c906108c
SS
2821 obstack_free (cproc_obstack, 0);
2822 obstack_init (cproc_obstack);
2823}
2824\f
2825void
fba45db2 2826thread_select_command (char *args, int from_tty)
c906108c
SS
2827{
2828 int mid;
2829 thread_array_t thread_list;
2830 int thread_count;
2831 kern_return_t ret;
2832 int is_slot = 0;
2833
2834 MACH_ERROR_NO_INFERIOR;
2835
2836 if (!args)
2837 error_no_arg ("MID or @SLOTNUMBER to specify a thread to select");
2838
2839 while (*args == ' ' || *args == '\t')
2840 args++;
2841
2842 if (*args == '@')
2843 {
2844 is_slot++;
2845 args++;
2846 }
2847
c5aa993b 2848 mid = atoi (args);
c906108c
SS
2849
2850 if (mid == 0)
c5aa993b 2851 if (!is_slot || *args != '0') /* Rudimentary checks */
c906108c
SS
2852 error ("You must select threads by MID or @SLOTNUMBER");
2853
c5aa993b 2854 if (select_thread (inferior_task, mid, is_slot ? 2 : 1) != KERN_SUCCESS)
c906108c
SS
2855 return;
2856
2857 if (from_tty)
2858 printf_filtered ("Thread %d selected\n",
2859 is_slot ? map_port_name_to_mid (current_thread,
c5aa993b 2860 MACH_TYPE_THREAD) : mid);
c906108c
SS
2861}
2862\f
fba45db2 2863thread_trace (mach_port_t thread, boolean_t set)
c906108c 2864{
c5aa993b
JM
2865 int flavor = TRACE_FLAVOR;
2866 unsigned int stateCnt = TRACE_FLAVOR_SIZE;
2867 kern_return_t ret;
2868 thread_state_data_t state;
c906108c 2869
c5aa993b 2870 if (!MACH_PORT_VALID (thread))
c906108c
SS
2871 {
2872 warning ("thread_trace: invalid thread");
2873 return;
2874 }
2875
2876 if (must_suspend_thread)
2877 setup_thread (thread, 1);
2878
c5aa993b 2879 ret = thread_get_state (thread, flavor, state, &stateCnt);
c906108c 2880 CHK ("thread_trace: error reading thread state", ret);
c5aa993b 2881
c906108c
SS
2882 if (set)
2883 {
2884 TRACE_SET (thread, state);
2885 }
2886 else
2887 {
c5aa993b 2888 if (!TRACE_CLEAR (thread, state))
c906108c
SS
2889 {
2890 if (must_suspend_thread)
2891 setup_thread (thread, 0);
2892 return;
2893 }
2894 }
2895
c5aa993b 2896 ret = thread_set_state (thread, flavor, state, stateCnt);
c906108c
SS
2897 CHK ("thread_trace: error writing thread state", ret);
2898 if (must_suspend_thread)
2899 setup_thread (thread, 0);
c5aa993b 2900}
c906108c
SS
2901
2902#ifdef FLUSH_INFERIOR_CACHE
2903
2904/* When over-writing code on some machines the I-Cache must be flushed
2905 explicitly, because it is not kept coherent by the lazy hardware.
2906 This definitely includes breakpoints, for instance, or else we
2907 end up looping in mysterious Bpt traps */
2908
fba45db2 2909flush_inferior_icache (CORE_ADDR pc, int amount)
c906108c
SS
2910{
2911 vm_machine_attribute_val_t flush = MATTR_VAL_ICACHE_FLUSH;
c5aa993b
JM
2912 kern_return_t ret;
2913
c906108c
SS
2914 ret = vm_machine_attribute (inferior_task,
2915 pc,
2916 amount,
2917 MATTR_CACHE,
2918 &flush);
2919 if (ret != KERN_SUCCESS)
2920 warning ("Error flushing inferior's cache : %s",
2921 mach_error_string (ret));
2922}
c5aa993b 2923#endif /* FLUSH_INFERIOR_CACHE */
c906108c 2924\f
c5aa993b 2925
c906108c 2926static
fba45db2 2927suspend_all_threads (int from_tty)
c906108c 2928{
c5aa993b
JM
2929 kern_return_t ret;
2930 thread_array_t thread_list;
2931 int thread_count, index;
2932 int infoCnt;
c906108c
SS
2933 thread_basic_info_data_t th_info;
2934
c5aa993b 2935
c906108c
SS
2936 ret = task_threads (inferior_task, &thread_list, &thread_count);
2937 if (ret != KERN_SUCCESS)
2938 {
2939 warning ("Could not suspend inferior threads.");
2940 m3_kill_inferior ();
2941 return_to_top_level (RETURN_ERROR);
2942 }
c5aa993b 2943
c906108c
SS
2944 for (index = 0; index < thread_count; index++)
2945 {
2946 int mid;
2947
c5aa993b 2948 mid = map_port_name_to_mid (thread_list[index],
c906108c 2949 MACH_TYPE_THREAD);
c5aa993b
JM
2950
2951 ret = thread_suspend (thread_list[index]);
c906108c
SS
2952
2953 if (ret != KERN_SUCCESS)
2954 warning ("Error trying to suspend thread %d : %s",
2955 mid, mach_error_string (ret));
2956
2957 if (from_tty)
2958 {
2959 infoCnt = THREAD_BASIC_INFO_COUNT;
c5aa993b 2960 ret = thread_info (thread_list[index],
c906108c 2961 THREAD_BASIC_INFO,
c5aa993b 2962 (thread_info_t) & th_info,
c906108c
SS
2963 &infoCnt);
2964 CHK ("suspend can't get thread info", ret);
c5aa993b 2965
c906108c
SS
2966 warning ("Thread %d suspend count is %d",
2967 mid, th_info.suspend_count);
2968 }
2969 }
2970
2971 consume_send_rights (thread_list, thread_count);
c5aa993b
JM
2972 ret = vm_deallocate (mach_task_self (),
2973 (vm_address_t) thread_list,
2974 (thread_count * sizeof (int)));
c906108c
SS
2975 CHK ("Error trying to deallocate thread list", ret);
2976}
2977
2978void
fba45db2 2979thread_suspend_command (char *args, int from_tty)
c906108c
SS
2980{
2981 kern_return_t ret;
c5aa993b
JM
2982 int mid;
2983 mach_port_t saved_thread;
2984 int infoCnt;
c906108c 2985 thread_basic_info_data_t th_info;
c5aa993b 2986
c906108c
SS
2987 MACH_ERROR_NO_INFERIOR;
2988
c5aa993b
JM
2989 if (!strcasecmp (args, "all"))
2990 {
2991 suspend_all_threads (from_tty);
2992 return;
2993 }
c906108c
SS
2994
2995 saved_thread = current_thread;
2996
2997 mid = parse_thread_id (args, 0, 0);
2998
2999 if (mid < 0)
3000 error ("You can suspend only existing kernel threads with MID or @SLOTNUMBER");
3001
3002 if (mid == 0)
3003 mid = map_port_name_to_mid (current_thread, MACH_TYPE_THREAD);
c5aa993b
JM
3004 else if (select_thread (inferior_task, mid, 0) != KERN_SUCCESS)
3005 {
3006 if (current_thread)
3007 current_thread = saved_thread;
3008 error ("Could not select thread %d", mid);
3009 }
c906108c
SS
3010
3011 ret = thread_suspend (current_thread);
3012 if (ret != KERN_SUCCESS)
3013 warning ("thread_suspend failed : %s",
3014 mach_error_string (ret));
3015
3016 infoCnt = THREAD_BASIC_INFO_COUNT;
3017 ret = thread_info (current_thread,
3018 THREAD_BASIC_INFO,
c5aa993b 3019 (thread_info_t) & th_info,
c906108c
SS
3020 &infoCnt);
3021 CHK ("suspend can't get thread info", ret);
c5aa993b 3022
c906108c 3023 warning ("Thread %d suspend count is %d", mid, th_info.suspend_count);
c5aa993b 3024
c906108c
SS
3025 current_thread = saved_thread;
3026}
3027
fba45db2 3028resume_all_threads (int from_tty)
c906108c 3029{
c5aa993b
JM
3030 kern_return_t ret;
3031 thread_array_t thread_list;
3032 int thread_count, index;
3033 int mid;
3034 int infoCnt;
3035 thread_basic_info_data_t th_info;
c906108c 3036
c5aa993b
JM
3037 ret = task_threads (inferior_task, &thread_list, &thread_count);
3038 if (ret != KERN_SUCCESS)
3039 {
3040 m3_kill_inferior ();
3041 error ("task_threads", mach_error_string (ret));
3042 }
c906108c 3043
c5aa993b
JM
3044 for (index = 0; index < thread_count; index++)
3045 {
3046 infoCnt = THREAD_BASIC_INFO_COUNT;
3047 ret = thread_info (thread_list[index],
3048 THREAD_BASIC_INFO,
3049 (thread_info_t) & th_info,
3050 &infoCnt);
3051 CHK ("resume_all can't get thread info", ret);
c906108c 3052
c5aa993b
JM
3053 mid = map_port_name_to_mid (thread_list[index],
3054 MACH_TYPE_THREAD);
c906108c 3055
c5aa993b
JM
3056 if (!th_info.suspend_count)
3057 {
3058 if (mid != -1 && from_tty)
3059 warning ("Thread %d is not suspended", mid);
3060 continue;
3061 }
c906108c 3062
c5aa993b
JM
3063 ret = thread_resume (thread_list[index]);
3064
3065 if (ret != KERN_SUCCESS)
3066 warning ("Error trying to resume thread %d : %s",
3067 mid, mach_error_string (ret));
3068 else if (mid != -1 && from_tty)
3069 warning ("Thread %d suspend count is %d",
3070 mid, --th_info.suspend_count);
3071 }
3072
3073 consume_send_rights (thread_list, thread_count);
3074 ret = vm_deallocate (mach_task_self (),
3075 (vm_address_t) thread_list,
3076 (thread_count * sizeof (int)));
3077 CHK ("Error trying to deallocate thread list", ret);
c906108c
SS
3078}
3079
3080void
fba45db2 3081thread_resume_command (char *args, int from_tty)
c906108c
SS
3082{
3083 int mid;
3084 mach_port_t saved_thread;
3085 kern_return_t ret;
3086 thread_basic_info_data_t th_info;
3087 int infoCnt = THREAD_BASIC_INFO_COUNT;
c5aa993b 3088
c906108c
SS
3089 MACH_ERROR_NO_INFERIOR;
3090
c5aa993b
JM
3091 if (!strcasecmp (args, "all"))
3092 {
3093 resume_all_threads (from_tty);
3094 return;
3095 }
c906108c
SS
3096
3097 saved_thread = current_thread;
3098
3099 mid = parse_thread_id (args, 0, 0);
3100
3101 if (mid < 0)
3102 error ("You can resume only existing kernel threads with MID or @SLOTNUMBER");
3103
3104 if (mid == 0)
3105 mid = map_port_name_to_mid (current_thread, MACH_TYPE_THREAD);
c5aa993b
JM
3106 else if (select_thread (inferior_task, mid, 0) != KERN_SUCCESS)
3107 {
3108 if (current_thread)
3109 current_thread = saved_thread;
3110 return_to_top_level (RETURN_ERROR);
3111 }
c906108c
SS
3112
3113 ret = thread_info (current_thread,
3114 THREAD_BASIC_INFO,
c5aa993b 3115 (thread_info_t) & th_info,
c906108c
SS
3116 &infoCnt);
3117 CHK ("resume can't get thread info", ret);
c5aa993b
JM
3118
3119 if (!th_info.suspend_count)
c906108c
SS
3120 {
3121 warning ("Thread %d is not suspended", mid);
3122 goto out;
3123 }
3124
3125 ret = thread_resume (current_thread);
3126 if (ret != KERN_SUCCESS)
3127 warning ("thread_resume failed : %s",
3128 mach_error_string (ret));
3129 else
3130 {
3131 th_info.suspend_count--;
3132 warning ("Thread %d suspend count is %d", mid, th_info.suspend_count);
3133 }
c5aa993b
JM
3134
3135out:
c906108c
SS
3136 current_thread = saved_thread;
3137}
3138
3139void
fba45db2 3140thread_kill_command (char *args, int from_tty)
c906108c
SS
3141{
3142 int mid;
3143 kern_return_t ret;
3144 int thread_count;
3145 thread_array_t thread_table;
c5aa993b 3146 int index;
c906108c 3147 mach_port_t thread_to_kill = MACH_PORT_NULL;
c5aa993b
JM
3148
3149
c906108c
SS
3150 MACH_ERROR_NO_INFERIOR;
3151
3152 if (!args)
3153 error_no_arg ("thread mid to kill from the inferior task");
3154
3155 mid = parse_thread_id (args, 0, 0);
3156
3157 if (mid < 0)
3158 error ("You can kill only existing kernel threads with MID or @SLOTNUMBER");
3159
3160 if (mid)
3161 {
3162 ret = machid_mach_port (mid_server, mid_auth, mid, &thread_to_kill);
3163 CHK ("thread_kill_command: machid_mach_port map failed", ret);
3164 }
3165 else
3166 mid = map_port_name_to_mid (current_thread, MACH_TYPE_THREAD);
c5aa993b 3167
c906108c
SS
3168 /* Don't allow gdb to kill *any* thread in the system. Use mkill program for that */
3169 ret = task_threads (inferior_task, &thread_table, &thread_count);
3170 CHK ("Error getting inferior's thread list", ret);
c5aa993b 3171
c906108c
SS
3172 if (thread_to_kill == current_thread)
3173 {
3174 ret = thread_terminate (thread_to_kill);
3175 CHK ("Thread could not be terminated", ret);
3176
3177 if (select_thread (inferior_task, 0, 1) != KERN_SUCCESS)
3178 warning ("Last thread was killed, use \"kill\" command to kill task");
3179 }
3180 else
3181 for (index = 0; index < thread_count; index++)
c5aa993b 3182 if (thread_table[index] == thread_to_kill)
c906108c
SS
3183 {
3184 ret = thread_terminate (thread_to_kill);
3185 CHK ("Thread could not be terminated", ret);
3186 }
3187
3188 if (thread_count > 1)
3189 consume_send_rights (thread_table, thread_count);
c5aa993b
JM
3190
3191 ret = vm_deallocate (mach_task_self (), (vm_address_t) thread_table,
3192 (thread_count * sizeof (mach_port_t)));
c906108c 3193 CHK ("Error trying to deallocate thread list", ret);
c5aa993b 3194
c906108c
SS
3195 warning ("Thread %d killed", mid);
3196}
c906108c 3197\f
c5aa993b 3198
c906108c
SS
3199/* Task specific commands; add more if you like */
3200
3201void
fba45db2 3202task_resume_command (char *args, int from_tty)
c906108c
SS
3203{
3204 kern_return_t ret;
3205 task_basic_info_data_t ta_info;
3206 int infoCnt = TASK_BASIC_INFO_COUNT;
3207 int mid = map_port_name_to_mid (inferior_task, MACH_TYPE_TASK);
c5aa993b 3208
c906108c
SS
3209 MACH_ERROR_NO_INFERIOR;
3210
3211 /* Would be trivial to change, but is it desirable? */
3212 if (args)
3213 error ("Currently gdb can resume only it's inferior task");
3214
3215 ret = task_info (inferior_task,
3216 TASK_BASIC_INFO,
c5aa993b 3217 (task_info_t) & ta_info,
c906108c
SS
3218 &infoCnt);
3219 CHK ("task_resume_command: task_info failed", ret);
c5aa993b 3220
c906108c
SS
3221 if (ta_info.suspend_count == 0)
3222 error ("Inferior task %d is not suspended", mid);
3223 else if (ta_info.suspend_count == 1 &&
3224 from_tty &&
c5aa993b 3225 !query ("Suspend count is now 1. Do you know what you are doing? "))
c906108c
SS
3226 error ("Task not resumed");
3227
3228 ret = task_resume (inferior_task);
3229 CHK ("task_resume_command: task_resume", ret);
3230
3231 if (ta_info.suspend_count == 1)
3232 {
3233 warning ("Inferior task %d is no longer suspended", mid);
3234 must_suspend_thread = 1;
3235 /* @@ This is not complete: Registers change all the time when not
c5aa993b 3236 suspended! */
c906108c
SS
3237 registers_changed ();
3238 }
3239 else
3240 warning ("Inferior task %d suspend count is now %d",
c5aa993b 3241 mid, ta_info.suspend_count - 1);
c906108c
SS
3242}
3243
3244
3245void
fba45db2 3246task_suspend_command (char *args, int from_tty)
c906108c
SS
3247{
3248 kern_return_t ret;
3249 task_basic_info_data_t ta_info;
3250 int infoCnt = TASK_BASIC_INFO_COUNT;
3251 int mid = map_port_name_to_mid (inferior_task, MACH_TYPE_TASK);
c5aa993b 3252
c906108c
SS
3253 MACH_ERROR_NO_INFERIOR;
3254
3255 /* Would be trivial to change, but is it desirable? */
3256 if (args)
3257 error ("Currently gdb can suspend only it's inferior task");
3258
3259 ret = task_suspend (inferior_task);
3260 CHK ("task_suspend_command: task_suspend", ret);
3261
3262 must_suspend_thread = 0;
3263
3264 ret = task_info (inferior_task,
3265 TASK_BASIC_INFO,
c5aa993b 3266 (task_info_t) & ta_info,
c906108c
SS
3267 &infoCnt);
3268 CHK ("task_suspend_command: task_info failed", ret);
c5aa993b 3269
c906108c
SS
3270 warning ("Inferior task %d suspend count is now %d",
3271 mid, ta_info.suspend_count);
3272}
3273
3274static char *
fba45db2 3275get_size (int bytes)
c906108c 3276{
c5aa993b
JM
3277 static char size[30];
3278 int zz = bytes / 1024;
c906108c
SS
3279
3280 if (zz / 1024)
c5aa993b 3281 sprintf (size, "%-2.1f M", ((float) bytes) / (1024.0 * 1024.0));
c906108c
SS
3282 else
3283 sprintf (size, "%d K", zz);
3284
3285 return size;
3286}
3287
3288/* Does this require the target task to be suspended?? I don't think so. */
3289void
fba45db2 3290task_info_command (char *args, int from_tty)
c906108c
SS
3291{
3292 int mid = -5;
3293 mach_port_t task;
3294 kern_return_t ret;
3295 task_basic_info_data_t ta_info;
3296 int infoCnt = TASK_BASIC_INFO_COUNT;
c5aa993b 3297 int page_size = round_page (1);
c906108c 3298 int thread_count = 0;
c5aa993b 3299
c906108c
SS
3300 if (MACH_PORT_VALID (inferior_task))
3301 mid = map_port_name_to_mid (inferior_task,
3302 MACH_TYPE_TASK);
3303
3304 task = inferior_task;
3305
3306 if (args)
3307 {
3308 int tmid = atoi (args);
3309
3310 if (tmid <= 0)
3311 error ("Invalid mid %d for task info", tmid);
3312
3313 if (tmid != mid)
3314 {
3315 mid = tmid;
3316 ret = machid_mach_port (mid_server, mid_auth, tmid, &task);
3317 CHK ("task_info_command: machid_mach_port map failed", ret);
3318 }
3319 }
3320
3321 if (mid < 0)
3322 error ("You have to give the task MID as an argument");
3323
3324 ret = task_info (task,
3325 TASK_BASIC_INFO,
c5aa993b 3326 (task_info_t) & ta_info,
c906108c
SS
3327 &infoCnt);
3328 CHK ("task_info_command: task_info failed", ret);
3329
3330 printf_filtered ("\nTask info for task %d:\n\n", mid);
3331 printf_filtered (" Suspend count : %d\n", ta_info.suspend_count);
3332 printf_filtered (" Base priority : %d\n", ta_info.base_priority);
3333 printf_filtered (" Virtual size : %s\n", get_size (ta_info.virtual_size));
3334 printf_filtered (" Resident size : %s\n", get_size (ta_info.resident_size));
3335
3336 {
3337 thread_array_t thread_list;
c5aa993b 3338
c906108c
SS
3339 ret = task_threads (task, &thread_list, &thread_count);
3340 CHK ("task_info_command: task_threads", ret);
c5aa993b 3341
c906108c
SS
3342 printf_filtered (" Thread count : %d\n", thread_count);
3343
3344 consume_send_rights (thread_list, thread_count);
c5aa993b
JM
3345 ret = vm_deallocate (mach_task_self (),
3346 (vm_address_t) thread_list,
3347 (thread_count * sizeof (int)));
3348 CHK ("Error trying to deallocate thread list", ret);
c906108c
SS
3349 }
3350 if (have_emulator_p (task))
3351 printf_filtered (" Emulator at : 0x%x..0x%x\n",
3352 EMULATOR_BASE, EMULATOR_END);
3353 else
3354 printf_filtered (" No emulator.\n");
3355
3356 if (thread_count && task == inferior_task)
3357 printf_filtered ("\nUse the \"thread list\" command to see the threads\n");
3358}
3359\f
3360/* You may either FORWARD the exception to the inferior, or KEEP
3361 * it and return to GDB command level.
3362 *
3363 * exception mid [ forward | keep ]
3364 */
3365
3366static void
fba45db2 3367exception_command (char *args, int from_tty)
c906108c
SS
3368{
3369 char *scan = args;
3370 int exception;
3371 int len;
3372
3373 if (!args)
3374 error_no_arg ("exception number action");
3375
c5aa993b
JM
3376 while (*scan == ' ' || *scan == '\t')
3377 scan++;
3378
c906108c
SS
3379 if ('0' <= *scan && *scan <= '9')
3380 while ('0' <= *scan && *scan <= '9')
3381 scan++;
3382 else
3383 error ("exception number action");
3384
3385 exception = atoi (args);
3386 if (exception <= 0 || exception > MAX_EXCEPTION)
3387 error ("Allowed exception numbers are in range 1..%d",
3388 MAX_EXCEPTION);
3389
3390 if (*scan != ' ' && *scan != '\t')
3391 error ("exception number must be followed by a space");
3392 else
c5aa993b
JM
3393 while (*scan == ' ' || *scan == '\t')
3394 scan++;
c906108c
SS
3395
3396 args = scan;
3397 len = 0;
3398 while (*scan)
3399 {
3400 len++;
3401 scan++;
3402 }
3403
3404 if (!len)
c5aa993b 3405 error ("exception number action");
c906108c
SS
3406
3407 if (!strncasecmp (args, "forward", len))
c5aa993b 3408 exception_map[exception].forward = TRUE;
c906108c 3409 else if (!strncasecmp (args, "keep", len))
c5aa993b 3410 exception_map[exception].forward = FALSE;
c906108c
SS
3411 else
3412 error ("exception action is either \"keep\" or \"forward\"");
3413}
3414
3415static void
fba45db2 3416print_exception_info (int exception)
c906108c 3417{
c5aa993b 3418 boolean_t forward = exception_map[exception].forward;
c906108c 3419
c5aa993b 3420 printf_filtered ("%s\t(%d): ", exception_map[exception].name,
c906108c
SS
3421 exception);
3422 if (!forward)
c5aa993b 3423 if (exception_map[exception].sigmap != SIG_UNKNOWN)
c906108c 3424 printf_filtered ("keep and handle as signal %d\n",
c5aa993b 3425 exception_map[exception].sigmap);
c906108c
SS
3426 else
3427 printf_filtered ("keep and handle as unknown signal %d\n",
c5aa993b 3428 exception_map[exception].sigmap);
c906108c
SS
3429 else
3430 printf_filtered ("forward exception to inferior\n");
3431}
3432
3433void
fba45db2 3434exception_info (char *args, int from_tty)
c906108c
SS
3435{
3436 int exception;
3437
3438 if (!args)
3439 for (exception = 1; exception <= MAX_EXCEPTION; exception++)
3440 print_exception_info (exception);
3441 else
3442 {
3443 exception = atoi (args);
3444
3445 if (exception <= 0 || exception > MAX_EXCEPTION)
3446 error ("Invalid exception number, values from 1 to %d allowed",
3447 MAX_EXCEPTION);
3448 print_exception_info (exception);
3449 }
3450}
3451\f
3452/* Check for actions for mach exceptions.
3453 */
fba45db2 3454mach3_exception_actions (WAITTYPE *w, boolean_t force_print_only, char *who)
c906108c
SS
3455{
3456 boolean_t force_print = FALSE;
3457
c5aa993b 3458
c906108c
SS
3459 if (force_print_only ||
3460 exception_map[stop_exception].sigmap == SIG_UNKNOWN)
3461 force_print = TRUE;
3462 else
3463 WSETSTOP (*w, exception_map[stop_exception].sigmap);
3464
3465 if (exception_map[stop_exception].print || force_print)
3466 {
3467 target_terminal_ours ();
c5aa993b 3468
c906108c
SS
3469 printf_filtered ("\n%s received %s exception : ",
3470 who,
3471 exception_map[stop_exception].name);
c5aa993b 3472
c906108c
SS
3473 wrap_here (" ");
3474
c5aa993b
JM
3475 switch (stop_exception)
3476 {
3477 case EXC_BAD_ACCESS:
3478 printf_filtered ("referencing address 0x%x : %s\n",
3479 stop_subcode,
3480 mach_error_string (stop_code));
3481 break;
3482 case EXC_BAD_INSTRUCTION:
3483 printf_filtered
3484 ("illegal or undefined instruction. code %d subcode %d\n",
3485 stop_code, stop_subcode);
3486 break;
3487 case EXC_ARITHMETIC:
3488 printf_filtered ("code %d\n", stop_code);
3489 break;
3490 case EXC_EMULATION:
3491 printf_filtered ("code %d subcode %d\n", stop_code, stop_subcode);
3492 break;
3493 case EXC_SOFTWARE:
3494 printf_filtered ("%s specific, code 0x%x\n",
3495 stop_code < 0xffff ? "hardware" : "os emulation",
3496 stop_code);
3497 break;
3498 case EXC_BREAKPOINT:
3499 printf_filtered ("type %d (machine dependent)\n",
3500 stop_code);
3501 break;
3502 default:
8e65ff28
AC
3503 internal_error (__FILE__, __LINE__,
3504 "Unknown exception");
c5aa993b 3505 }
c906108c
SS
3506 }
3507}
3508\f
fba45db2 3509setup_notify_port (int create_new)
c906108c
SS
3510{
3511 kern_return_t ret;
3512
3513 if (MACH_PORT_VALID (our_notify_port))
3514 {
3515 ret = mach_port_destroy (mach_task_self (), our_notify_port);
3516 CHK ("Could not destroy our_notify_port", ret);
3517 }
3518
3519 our_notify_port = MACH_PORT_NULL;
c5aa993b 3520 notify_chain = (port_chain_t) NULL;
c906108c
SS
3521 port_chain_destroy (port_chain_obstack);
3522
3523 if (create_new)
3524 {
c5aa993b 3525 ret = mach_port_allocate (mach_task_self (),
c906108c
SS
3526 MACH_PORT_RIGHT_RECEIVE,
3527 &our_notify_port);
3528 if (ret != KERN_SUCCESS)
8e65ff28
AC
3529 internal_error (__FILE__, __LINE__,
3530 "Creating notify port %s", mach_error_string (ret));
c5aa993b
JM
3531
3532 ret = mach_port_move_member (mach_task_self (),
3533 our_notify_port,
3534 inferior_wait_port_set);
c906108c 3535 if (ret != KERN_SUCCESS)
8e65ff28
AC
3536 internal_error (__FILE__, __LINE__,
3537 "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)
8e65ff28
AC
4507 internal_error (__FILE__, __LINE__,
4508 "initial port set %s", mach_error_string (ret));
c906108c
SS
4509
4510 /* mach_really_wait now waits for this */
4511 currently_waiting_for = inferior_wait_port_set;
4512
c5aa993b 4513 ret = netname_look_up (name_server_port, hostname, "MachID", &mid_server);
c906108c
SS
4514 if (ret != KERN_SUCCESS)
4515 {
4516 mid_server = MACH_PORT_NULL;
c5aa993b 4517
c906108c 4518 warning ("initialize machid: netname_lookup_up(MachID) : %s",
c5aa993b 4519 mach_error_string (ret));
c906108c
SS
4520 warning ("Some (most?) features disabled...");
4521 }
c5aa993b
JM
4522
4523 mid_auth = mach_privileged_host_port ();
c906108c 4524 if (mid_auth == MACH_PORT_NULL)
c5aa993b
JM
4525 mid_auth = mach_task_self ();
4526
c906108c
SS
4527 obstack_init (port_chain_obstack);
4528
c5aa993b 4529 ret = mach_port_allocate (mach_task_self (),
c906108c
SS
4530 MACH_PORT_RIGHT_RECEIVE,
4531 &thread_exception_port);
4532 CHK ("Creating thread_exception_port for single stepping", ret);
c5aa993b 4533
c906108c
SS
4534 ret = mach_port_insert_right (mach_task_self (),
4535 thread_exception_port,
4536 thread_exception_port,
4537 MACH_MSG_TYPE_MAKE_SEND);
4538 CHK ("Inserting send right to thread_exception_port", ret);
4539
4540 /* Allocate message port */
4541 ret = mach_port_allocate (mach_task_self (),
4542 MACH_PORT_RIGHT_RECEIVE,
4543 &our_message_port);
4544 if (ret != KERN_SUCCESS)
4545 warning ("Creating message port %s", mach_error_string (ret));
4546 else
4547 {
c5aa993b
JM
4548 char buf[MAX_NAME_LEN];
4549 ret = mach_port_move_member (mach_task_self (),
4550 our_message_port,
4551 inferior_wait_port_set);
c906108c
SS
4552 if (ret != KERN_SUCCESS)
4553 warning ("message move member %s", mach_error_string (ret));
4554
4555
4556 /* @@@@ No way to change message port name currently */
4557 /* Foo. This assumes gdb has a unix pid */
4558 sprintf (buf, "gdb-%d", getpid ());
4559 gdb_register_port (buf, our_message_port);
4560 }
c5aa993b 4561
c906108c
SS
4562 /* Heap for thread commands */
4563 obstack_init (cproc_obstack);
4564
4565 add_mach_specific_commands ();
4566}
This page took 0.284418 seconds and 4 git commands to generate.