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