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