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