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