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