OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [gdb/] [m3-nat.c] - Blame information for rev 1774

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.