1/* Darwin support for GDB, the GNU debugger.
2   Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2008, 2009, 2010, 2011
3   Free Software Foundation, Inc.
4
5   Contributed by Apple Computer, 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 3 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, see <http://www.gnu.org/licenses/>.  */
21
22/* The name of the ppc_thread_state structure, and the names of its
23   members, have been changed for Unix conformance reasons.  The easiest
24   way to have gdb build on systems with the older names and systems
25   with the newer names is to build this compilation unit with the
26   non-conformant define below.  This doesn't seem to cause the resulting
27   binary any problems but it seems like it could cause us problems in
28   the future.  It'd be good to remove this at some point when compiling on
29   Tiger is no longer important.  */
30
31#include "defs.h"
32#include "symtab.h"
33#include "gdbtypes.h"
34#include "gdbcore.h"
35#include "value.h"
36#include "gdbcmd.h"
37#include "inferior.h"
38
39#include <sys/param.h>
40#include <sys/sysctl.h>
41
42#include "darwin-nat.h"
43
44#include <mach/thread_info.h>
45#include <mach/thread_act.h>
46#include <mach/task.h>
47#include <mach/vm_map.h>
48#include <mach/mach_port.h>
49#include <mach/mach_init.h>
50#include <mach/mach_vm.h>
51
52#define CHECK_ARGS(what, args) do { \
53  if ((NULL == args) || ((args[0] != '0') && (args[1] != 'x'))) \
54    error(_("%s must be specified with 0x..."), what);		\
55} while (0)
56
57#define PRINT_FIELD(structure, field) \
58  printf_unfiltered(_(#field":\t%#lx\n"), (unsigned long) (structure)->field)
59
60#define PRINT_TV_FIELD(structure, field) \
61  printf_unfiltered(_(#field":\t%u.%06u sec\n"),	\
62  (unsigned) (structure)->field.seconds, \
63  (unsigned) (structure)->field.microseconds)
64
65#define task_self mach_task_self
66#define task_by_unix_pid task_for_pid
67#define port_name_array_t mach_port_array_t
68#define port_type_array_t mach_port_array_t
69
70static void
71info_mach_tasks_command (char *args, int from_tty)
72{
73  int sysControl[4];
74  int count, index;
75  size_t length;
76  struct kinfo_proc *procInfo;
77
78  sysControl[0] = CTL_KERN;
79  sysControl[1] = KERN_PROC;
80  sysControl[2] = KERN_PROC_ALL;
81
82  sysctl (sysControl, 3, NULL, &length, NULL, 0);
83  procInfo = (struct kinfo_proc *) xmalloc (length);
84  sysctl (sysControl, 3, procInfo, &length, NULL, 0);
85
86  count = (length / sizeof (struct kinfo_proc));
87  printf_unfiltered (_("%d processes:\n"), count);
88  for (index = 0; index < count; ++index)
89    {
90      kern_return_t result;
91      mach_port_t taskPort;
92
93      result =
94        task_by_unix_pid (mach_task_self (), procInfo[index].kp_proc.p_pid,
95                          &taskPort);
96      if (KERN_SUCCESS == result)
97        {
98          printf_unfiltered (_("    %s is %d has task %#x\n"),
99                             procInfo[index].kp_proc.p_comm,
100                             procInfo[index].kp_proc.p_pid, taskPort);
101        }
102      else
103        {
104          printf_unfiltered (_("    %s is %d unknown task port\n"),
105                             procInfo[index].kp_proc.p_comm,
106                             procInfo[index].kp_proc.p_pid);
107        }
108    }
109
110  xfree (procInfo);
111}
112
113static task_t
114get_task_from_args (char *args)
115{
116  task_t task;
117  char *eptr;
118
119  if (args == NULL || *args == 0)
120    {
121      if (ptid_equal (inferior_ptid, null_ptid))
122	printf_unfiltered (_("No inferior running\n"));
123      return current_inferior ()->private->task;
124    }
125  if (strcmp (args, "gdb") == 0)
126    return mach_task_self ();
127  task = strtoul (args, &eptr, 0);
128  if (*eptr)
129    {
130      printf_unfiltered (_("cannot parse task id '%s'\n"), args);
131      return TASK_NULL;
132    }
133  return task;
134}
135
136static void
137info_mach_task_command (char *args, int from_tty)
138{
139  union
140  {
141    struct task_basic_info basic;
142    struct task_events_info events;
143    struct task_thread_times_info thread_times;
144  } task_info_data;
145
146  kern_return_t result;
147  unsigned int info_count;
148  task_t task;
149
150  task = get_task_from_args (args);
151  if (task == TASK_NULL)
152    return;
153
154  printf_unfiltered (_("TASK_BASIC_INFO for 0x%x:\n"), task);
155  info_count = TASK_BASIC_INFO_COUNT;
156  result = task_info (task,
157                      TASK_BASIC_INFO,
158                      (task_info_t) & task_info_data.basic, &info_count);
159  MACH_CHECK_ERROR (result);
160
161  PRINT_FIELD (&task_info_data.basic, suspend_count);
162  PRINT_FIELD (&task_info_data.basic, virtual_size);
163  PRINT_FIELD (&task_info_data.basic, resident_size);
164  PRINT_TV_FIELD (&task_info_data.basic, user_time);
165  PRINT_TV_FIELD (&task_info_data.basic, system_time);
166  printf_unfiltered (_("\nTASK_EVENTS_INFO:\n"));
167  info_count = TASK_EVENTS_INFO_COUNT;
168  result = task_info (task,
169                      TASK_EVENTS_INFO,
170                      (task_info_t) & task_info_data.events, &info_count);
171  MACH_CHECK_ERROR (result);
172
173  PRINT_FIELD (&task_info_data.events, faults);
174#if 0
175  PRINT_FIELD (&task_info_data.events, zero_fills);
176  PRINT_FIELD (&task_info_data.events, reactivations);
177#endif
178  PRINT_FIELD (&task_info_data.events, pageins);
179  PRINT_FIELD (&task_info_data.events, cow_faults);
180  PRINT_FIELD (&task_info_data.events, messages_sent);
181  PRINT_FIELD (&task_info_data.events, messages_received);
182  printf_unfiltered (_("\nTASK_THREAD_TIMES_INFO:\n"));
183  info_count = TASK_THREAD_TIMES_INFO_COUNT;
184  result = task_info (task,
185                      TASK_THREAD_TIMES_INFO,
186                      (task_info_t) & task_info_data.thread_times,
187                      &info_count);
188  MACH_CHECK_ERROR (result);
189  PRINT_TV_FIELD (&task_info_data.thread_times, user_time);
190  PRINT_TV_FIELD (&task_info_data.thread_times, system_time);
191}
192
193static void
194info_mach_ports_command (char *args, int from_tty)
195{
196  port_name_array_t names;
197  port_type_array_t types;
198  unsigned int name_count, type_count;
199  kern_return_t result;
200  int index;
201  task_t task;
202
203  task = get_task_from_args (args);
204  if (task == TASK_NULL)
205    return;
206
207  result = mach_port_names (task, &names, &name_count, &types, &type_count);
208  MACH_CHECK_ERROR (result);
209
210  gdb_assert (name_count == type_count);
211
212  printf_unfiltered (_("Ports for task 0x%x:\n"), task);
213  printf_unfiltered (_("port   type\n"));
214  for (index = 0; index < name_count; ++index)
215    {
216      mach_port_t port = names[index];
217      unsigned int j;
218      struct type_descr
219      {
220	mach_port_type_t type;
221	const char *name;
222	mach_port_right_t right;
223      };
224      static struct type_descr descrs[] =
225	{
226	  {MACH_PORT_TYPE_SEND, "send", MACH_PORT_RIGHT_SEND},
227	  {MACH_PORT_TYPE_SEND_ONCE, "send-once", MACH_PORT_RIGHT_SEND_ONCE},
228	  {MACH_PORT_TYPE_RECEIVE, "receive", MACH_PORT_RIGHT_RECEIVE},
229	  {MACH_PORT_TYPE_PORT_SET, "port-set", MACH_PORT_RIGHT_PORT_SET},
230	  {MACH_PORT_TYPE_DEAD_NAME, "dead", MACH_PORT_RIGHT_DEAD_NAME}
231	};
232
233      printf_unfiltered (_("%04x: %08x "), port, types[index]);
234      for (j = 0; j < sizeof(descrs) / sizeof(*descrs); j++)
235	if (types[index] & descrs[j].type)
236	  {
237	    mach_port_urefs_t ref;
238	    kern_return_t ret;
239
240	    printf_unfiltered (_(" %s("), descrs[j].name);
241	    ret = mach_port_get_refs (task, port, descrs[j].right, &ref);
242	    if (ret != KERN_SUCCESS)
243	      printf_unfiltered (_("??"));
244	    else
245	      printf_unfiltered (_("%u"), ref);
246	    printf_unfiltered (_(" refs)"));
247	  }
248
249      if (task == task_self ())
250	{
251	  if (port == task_self())
252	    printf_unfiltered (_(" gdb-task"));
253	  else if (port == darwin_host_self)
254	    printf_unfiltered (_(" host-self"));
255	  else if (port == darwin_ex_port)
256	    printf_unfiltered (_(" gdb-exception"));
257	  else if (port == darwin_port_set)
258	    printf_unfiltered (_(" gdb-port_set"));
259	  else if (!ptid_equal (inferior_ptid, null_ptid))
260	    {
261	      struct inferior *inf = current_inferior ();
262
263	      if (port == inf->private->task)
264		printf_unfiltered (_(" inferior-task"));
265	      else if (port == inf->private->notify_port)
266		printf_unfiltered (_(" inferior-notify"));
267	      else
268		{
269		  int k;
270		  darwin_thread_t *t;
271
272		  for (k = 0; k < inf->private->exception_info.count; k++)
273		    if (port == inf->private->exception_info.ports[k])
274		      {
275			printf_unfiltered (_(" inferior-excp-port"));
276			break;
277		      }
278
279		  if (inf->private->threads)
280		    {
281		      for (k = 0;
282			   VEC_iterate(darwin_thread_t,
283				       inf->private->threads, k, t);
284			   k++)
285			if (port == t->gdb_port)
286			  {
287			    printf_unfiltered (_(" inferior-thread for 0x%x"),
288					       inf->private->task);
289			    break;
290			  }
291		    }
292		}
293	    }
294	}
295      printf_unfiltered (_("\n"));
296    }
297
298  vm_deallocate (task_self (), (vm_address_t) names,
299                 (name_count * sizeof (mach_port_t)));
300  vm_deallocate (task_self (), (vm_address_t) types,
301                 (type_count * sizeof (mach_port_type_t)));
302}
303
304
305void
306darwin_debug_port_info (task_t task, mach_port_t port)
307{
308  kern_return_t kret;
309  mach_port_status_t status;
310  mach_msg_type_number_t len = sizeof (status);
311
312  kret = mach_port_get_attributes
313    (task, port, MACH_PORT_RECEIVE_STATUS, (mach_port_info_t)&status, &len);
314  MACH_CHECK_ERROR (kret);
315
316  printf_unfiltered (_("Port 0x%lx in task 0x%lx:\n"), (unsigned long) port,
317                     (unsigned long) task);
318  printf_unfiltered (_("  port set: 0x%x\n"), status.mps_pset);
319  printf_unfiltered (_("     seqno: 0x%x\n"), status.mps_seqno);
320  printf_unfiltered (_("   mscount: 0x%x\n"), status.mps_mscount);
321  printf_unfiltered (_("    qlimit: 0x%x\n"), status.mps_qlimit);
322  printf_unfiltered (_("  msgcount: 0x%x\n"), status.mps_msgcount);
323  printf_unfiltered (_("  sorights: 0x%x\n"), status.mps_sorights);
324  printf_unfiltered (_("   srights: 0x%x\n"), status.mps_srights);
325  printf_unfiltered (_(" pdrequest: 0x%x\n"), status.mps_pdrequest);
326  printf_unfiltered (_(" nsrequest: 0x%x\n"), status.mps_nsrequest);
327  printf_unfiltered (_("     flags: 0x%x\n"), status.mps_flags);
328}
329
330static void
331info_mach_port_command (char *args, int from_tty)
332{
333  task_t task;
334  mach_port_t port;
335
336  CHECK_ARGS (_("Task and port"), args);
337  sscanf (args, "0x%x 0x%x", &task, &port);
338
339  darwin_debug_port_info (task, port);
340}
341
342static void
343info_mach_threads_command (char *args, int from_tty)
344{
345  thread_array_t threads;
346  unsigned int thread_count;
347  kern_return_t result;
348  task_t task;
349  int i;
350
351  task = get_task_from_args (args);
352  if (task == TASK_NULL)
353    return;
354
355  result = task_threads (task, &threads, &thread_count);
356  MACH_CHECK_ERROR (result);
357
358  printf_unfiltered (_("Threads in task %#x:\n"), task);
359  for (i = 0; i < thread_count; ++i)
360    {
361      printf_unfiltered (_("    %#x\n"), threads[i]);
362      mach_port_deallocate (task_self (), threads[i]);
363    }
364
365  vm_deallocate (task_self (), (vm_address_t) threads,
366                 (thread_count * sizeof (thread_t)));
367}
368
369static void
370info_mach_thread_command (char *args, int from_tty)
371{
372  union
373  {
374    struct thread_basic_info basic;
375  } thread_info_data;
376
377  thread_t thread;
378  kern_return_t result;
379  unsigned int info_count;
380
381  CHECK_ARGS (_("Thread"), args);
382  sscanf (args, "0x%x", &thread);
383
384  printf_unfiltered (_("THREAD_BASIC_INFO\n"));
385  info_count = THREAD_BASIC_INFO_COUNT;
386  result = thread_info (thread,
387			THREAD_BASIC_INFO,
388			(thread_info_t) & thread_info_data.basic,
389			&info_count);
390  MACH_CHECK_ERROR (result);
391
392#if 0
393  PRINT_FIELD (&thread_info_data.basic, user_time);
394  PRINT_FIELD (&thread_info_data.basic, system_time);
395#endif
396  PRINT_FIELD (&thread_info_data.basic, cpu_usage);
397  PRINT_FIELD (&thread_info_data.basic, run_state);
398  PRINT_FIELD (&thread_info_data.basic, flags);
399  PRINT_FIELD (&thread_info_data.basic, suspend_count);
400  PRINT_FIELD (&thread_info_data.basic, sleep_time);
401}
402
403static const char *
404unparse_protection (vm_prot_t p)
405{
406  switch (p)
407    {
408    case VM_PROT_NONE:
409      return "---";
410    case VM_PROT_READ:
411      return "r--";
412    case VM_PROT_WRITE:
413      return "-w-";
414    case VM_PROT_READ | VM_PROT_WRITE:
415      return "rw-";
416    case VM_PROT_EXECUTE:
417      return "--x";
418    case VM_PROT_EXECUTE | VM_PROT_READ:
419      return "r-x";
420    case VM_PROT_EXECUTE | VM_PROT_WRITE:
421      return "-wx";
422    case VM_PROT_EXECUTE | VM_PROT_WRITE | VM_PROT_READ:
423      return "rwx";
424    default:
425      return "???";
426    }
427}
428
429static const char *
430unparse_inheritance (vm_inherit_t i)
431{
432  switch (i)
433    {
434    case VM_INHERIT_SHARE:
435      return _("share");
436    case VM_INHERIT_COPY:
437      return _("copy ");
438    case VM_INHERIT_NONE:
439      return _("none ");
440    default:
441      return _("???  ");
442    }
443}
444
445static const char *
446unparse_share_mode (unsigned char p)
447{
448  switch (p)
449    {
450    case SM_COW:
451      return _("cow");
452    case SM_PRIVATE:
453      return _("private");
454    case SM_EMPTY:
455      return _("empty");
456    case SM_SHARED:
457      return _("shared");
458    case SM_TRUESHARED:
459      return _("true-shrd");
460    case SM_PRIVATE_ALIASED:
461      return _("prv-alias");
462    case SM_SHARED_ALIASED:
463      return _("shr-alias");
464    default:
465      return _("???");
466    }
467}
468
469static const char *
470unparse_user_tag (unsigned int tag)
471{
472  switch (tag)
473    {
474    case 0:
475      return _("default");
476    case VM_MEMORY_MALLOC:
477      return _("malloc");
478    case VM_MEMORY_MALLOC_SMALL:
479      return _("malloc_small");
480    case VM_MEMORY_MALLOC_LARGE:
481      return _("malloc_large");
482    case VM_MEMORY_MALLOC_HUGE:
483      return _("malloc_huge");
484    case VM_MEMORY_SBRK:
485      return _("sbrk");
486    case VM_MEMORY_REALLOC:
487      return _("realloc");
488    case VM_MEMORY_MALLOC_TINY:
489      return _("malloc_tiny");
490    case VM_MEMORY_ANALYSIS_TOOL:
491      return _("analysis_tool");
492    case VM_MEMORY_MACH_MSG:
493      return _("mach_msg");
494    case VM_MEMORY_IOKIT:
495      return _("iokit");
496    case VM_MEMORY_STACK:
497      return _("stack");
498    case VM_MEMORY_GUARD:
499      return _("guard");
500    case VM_MEMORY_SHARED_PMAP:
501      return _("shared_pmap");
502    case VM_MEMORY_DYLIB:
503      return _("dylib");
504    case VM_MEMORY_APPKIT:
505      return _("appkit");
506    case VM_MEMORY_FOUNDATION:
507      return _("foundation");
508    default:
509      return NULL;
510    }
511}
512
513static void
514darwin_debug_regions (task_t task, mach_vm_address_t address, int max)
515{
516  kern_return_t kret;
517  vm_region_basic_info_data_64_t info, prev_info;
518  mach_vm_address_t prev_address;
519  mach_vm_size_t size, prev_size;
520
521  mach_port_t object_name;
522  mach_msg_type_number_t count;
523
524  int nsubregions = 0;
525  int num_printed = 0;
526
527  count = VM_REGION_BASIC_INFO_COUNT_64;
528  kret = mach_vm_region (task, &address, &size, VM_REGION_BASIC_INFO_64,
529			 (vm_region_info_t) &info, &count, &object_name);
530  if (kret != KERN_SUCCESS)
531    {
532      printf_filtered (_("No memory regions."));
533      return;
534    }
535  memcpy (&prev_info, &info, sizeof (vm_region_basic_info_data_64_t));
536  prev_address = address;
537  prev_size = size;
538  nsubregions = 1;
539
540  for (;;)
541    {
542      int print = 0;
543      int done = 0;
544
545      address = prev_address + prev_size;
546
547      /* Check to see if address space has wrapped around.  */
548      if (address == 0)
549        print = done = 1;
550
551      if (!done)
552        {
553          count = VM_REGION_BASIC_INFO_COUNT_64;
554          kret =
555            mach_vm_region (task, &address, &size, VM_REGION_BASIC_INFO_64,
556                 	      (vm_region_info_t) &info, &count, &object_name);
557          if (kret != KERN_SUCCESS)
558            {
559              size = 0;
560              print = done = 1;
561            }
562        }
563
564      if (address != prev_address + prev_size)
565        print = 1;
566
567      if ((info.protection != prev_info.protection)
568          || (info.max_protection != prev_info.max_protection)
569          || (info.inheritance != prev_info.inheritance)
570          || (info.shared != prev_info.reserved)
571          || (info.reserved != prev_info.reserved))
572        print = 1;
573
574      if (print)
575        {
576          printf_filtered (_("%s-%s %s/%s  %s %s %s"),
577                           paddress (target_gdbarch, prev_address),
578                           paddress (target_gdbarch, prev_address + prev_size),
579                           unparse_protection (prev_info.protection),
580                           unparse_protection (prev_info.max_protection),
581                           unparse_inheritance (prev_info.inheritance),
582                           prev_info.shared ? _("shrd") : _("priv"),
583                           prev_info.reserved ? _("reserved") : _("not-rsvd"));
584
585          if (nsubregions > 1)
586            printf_filtered (_(" (%d sub-rgn)"), nsubregions);
587
588          printf_filtered (_("\n"));
589
590          prev_address = address;
591          prev_size = size;
592          memcpy (&prev_info, &info, sizeof (vm_region_basic_info_data_64_t));
593          nsubregions = 1;
594
595          num_printed++;
596        }
597      else
598        {
599          prev_size += size;
600          nsubregions++;
601        }
602
603      if ((max > 0) && (num_printed >= max))
604        done = 1;
605
606      if (done)
607        break;
608    }
609}
610
611static void
612darwin_debug_regions_recurse (task_t task)
613{
614  mach_vm_address_t r_addr;
615  mach_vm_address_t r_start;
616  mach_vm_size_t r_size;
617  natural_t r_depth;
618  mach_msg_type_number_t r_info_size;
619  vm_region_submap_short_info_data_64_t r_info;
620  kern_return_t kret;
621  int ret;
622  struct cleanup *table_chain;
623
624  table_chain = make_cleanup_ui_out_table_begin_end (uiout, 9, -1, "regions");
625
626  if (gdbarch_addr_bit (target_gdbarch) <= 32)
627    {
628      ui_out_table_header (uiout, 10, ui_left, "start", "Start");
629      ui_out_table_header (uiout, 10, ui_left, "end", "End");
630    }
631  else
632    {
633      ui_out_table_header (uiout, 18, ui_left, "start", "Start");
634      ui_out_table_header (uiout, 18, ui_left, "end", "End");
635    }
636  ui_out_table_header (uiout, 3, ui_left, "min-prot", "Min");
637  ui_out_table_header (uiout, 3, ui_left, "max-prot", "Max");
638  ui_out_table_header (uiout, 5, ui_left, "inheritence", "Inh");
639  ui_out_table_header (uiout, 9, ui_left, "share-mode", "Shr");
640  ui_out_table_header (uiout, 1, ui_left, "depth", "D");
641  ui_out_table_header (uiout, 3, ui_left, "submap", "Sm");
642  ui_out_table_header (uiout, 0, ui_noalign, "tag", "Tag");
643
644  ui_out_table_body (uiout);
645
646  r_start = 0;
647  r_depth = 0;
648  while (1)
649    {
650      const char *tag;
651      struct cleanup *row_chain;
652
653      r_info_size = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
654      r_size = -1;
655      kret = mach_vm_region_recurse (task, &r_start, &r_size, &r_depth,
656				     (vm_region_recurse_info_t) &r_info,
657				     &r_info_size);
658      if (kret != KERN_SUCCESS)
659	break;
660      row_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "regions-row");
661
662      ui_out_field_core_addr (uiout, "start", target_gdbarch, r_start);
663      ui_out_field_core_addr (uiout, "end", target_gdbarch, r_start + r_size);
664      ui_out_field_string (uiout, "min-prot",
665			   unparse_protection (r_info.protection));
666      ui_out_field_string (uiout, "max-prot",
667			   unparse_protection (r_info.max_protection));
668      ui_out_field_string (uiout, "inheritence",
669			   unparse_inheritance (r_info.inheritance));
670      ui_out_field_string (uiout, "share-mode",
671			   unparse_share_mode (r_info.share_mode));
672      ui_out_field_int (uiout, "depth", r_depth);
673      ui_out_field_string (uiout, "submap",
674			   r_info.is_submap ? _("sm ") : _("obj"));
675      tag = unparse_user_tag (r_info.user_tag);
676      if (tag)
677	ui_out_field_string (uiout, "tag", tag);
678      else
679	ui_out_field_int (uiout, "tag", r_info.user_tag);
680
681      do_cleanups (row_chain);
682
683      if (!ui_out_is_mi_like_p (uiout))
684	ui_out_text (uiout, "\n");
685
686      if (r_info.is_submap)
687	r_depth++;
688      else
689	r_start += r_size;
690    }
691  do_cleanups (table_chain);
692
693}
694
695
696static void
697darwin_debug_region (task_t task, mach_vm_address_t address)
698{
699  darwin_debug_regions (task, address, 1);
700}
701
702static void
703info_mach_regions_command (char *args, int from_tty)
704{
705  task_t task;
706
707  task = get_task_from_args (args);
708  if (task == TASK_NULL)
709    return;
710
711  darwin_debug_regions (task, 0, -1);
712}
713
714static void
715info_mach_regions_recurse_command (char *args, int from_tty)
716{
717  task_t task;
718
719  task = get_task_from_args (args);
720  if (task == TASK_NULL)
721    return;
722
723  darwin_debug_regions_recurse (task);
724}
725
726static void
727info_mach_region_command (char *exp, int from_tty)
728{
729  struct expression *expr;
730  struct value *val;
731  mach_vm_address_t address;
732  struct inferior *inf;
733
734  expr = parse_expression (exp);
735  val = evaluate_expression (expr);
736  if (TYPE_CODE (value_type (val)) == TYPE_CODE_REF)
737    {
738      val = value_ind (val);
739    }
740  address = value_as_address (val);
741
742  if (ptid_equal (inferior_ptid, null_ptid))
743    error (_("Inferior not available"));
744
745  inf = current_inferior ();
746  darwin_debug_region (inf->private->task, address);
747}
748
749static void
750disp_exception (const darwin_exception_info *info)
751{
752  int i;
753
754  printf_filtered (_("%d exceptions:\n"), info->count);
755  for (i = 0; i < info->count; i++)
756    {
757      exception_mask_t mask = info->masks[i];
758
759      printf_filtered (_("port 0x%04x, behavior: "), info->ports[i]);
760      switch (info->behaviors[i])
761	{
762	case EXCEPTION_DEFAULT:
763	  printf_unfiltered (_("default"));
764	  break;
765	case EXCEPTION_STATE:
766	  printf_unfiltered (_("state"));
767	  break;
768	case EXCEPTION_STATE_IDENTITY:
769	  printf_unfiltered (_("state-identity"));
770	  break;
771	default:
772	  printf_unfiltered (_("0x%x"), info->behaviors[i]);
773	}
774      printf_unfiltered (_(", masks:"));
775      if (mask & EXC_MASK_BAD_ACCESS)
776	printf_unfiltered (_(" BAD_ACCESS"));
777      if (mask & EXC_MASK_BAD_INSTRUCTION)
778	printf_unfiltered (_(" BAD_INSTRUCTION"));
779      if (mask & EXC_MASK_ARITHMETIC)
780	printf_unfiltered (_(" ARITHMETIC"));
781      if (mask & EXC_MASK_EMULATION)
782	printf_unfiltered (_(" EMULATION"));
783      if (mask & EXC_MASK_SOFTWARE)
784	printf_unfiltered (_(" SOFTWARE"));
785      if (mask & EXC_MASK_BREAKPOINT)
786	printf_unfiltered (_(" BREAKPOINT"));
787      if (mask & EXC_MASK_SYSCALL)
788	printf_unfiltered (_(" SYSCALL"));
789      if (mask & EXC_MASK_MACH_SYSCALL)
790	printf_unfiltered (_(" MACH_SYSCALL"));
791      if (mask & EXC_MASK_RPC_ALERT)
792	printf_unfiltered (_(" RPC_ALERT"));
793      if (mask & EXC_MASK_CRASH)
794	printf_unfiltered (_(" CRASH"));
795      printf_unfiltered (_("\n"));
796    }
797}
798
799static void
800info_mach_exceptions_command (char *args, int from_tty)
801{
802  int i;
803  task_t task;
804  kern_return_t kret;
805  darwin_exception_info info;
806
807  info.count = sizeof (info.ports) / sizeof (info.ports[0]);
808
809  if (args != NULL)
810    {
811      if (strcmp (args, "saved") == 0)
812	{
813	  if (ptid_equal (inferior_ptid, null_ptid))
814	    printf_unfiltered (_("No inferior running\n"));
815	  disp_exception (&current_inferior ()->private->exception_info);
816	  return;
817	}
818      else if (strcmp (args, "host") == 0)
819	{
820	  /* FIXME: This need a privilegied host port!  */
821	  kret = host_get_exception_ports
822	    (darwin_host_self, EXC_MASK_ALL, info.masks,
823	     &info.count, info.ports, info.behaviors, info.flavors);
824	  MACH_CHECK_ERROR (kret);
825	  disp_exception (&info);
826	}
827      else
828	error (_("Parameter is saved, host or none"));
829    }
830  else
831    {
832      struct inferior *inf;
833
834      if (ptid_equal (inferior_ptid, null_ptid))
835	printf_unfiltered (_("No inferior running\n"));
836      inf = current_inferior ();
837
838      kret = task_get_exception_ports
839	(inf->private->task, EXC_MASK_ALL, info.masks,
840	 &info.count, info.ports, info.behaviors, info.flavors);
841      MACH_CHECK_ERROR (kret);
842      disp_exception (&info);
843    }
844}
845
846void
847_initialize_darwin_info_commands (void)
848{
849  add_info ("mach-tasks", info_mach_tasks_command,
850            _("Get list of tasks in system."));
851  add_info ("mach-ports", info_mach_ports_command,
852            _("Get list of ports in a task."));
853  add_info ("mach-port", info_mach_port_command,
854            _("Get info on a specific port."));
855  add_info ("mach-task", info_mach_task_command,
856            _("Get info on a specific task."));
857  add_info ("mach-threads", info_mach_threads_command,
858            _("Get list of threads in a task."));
859  add_info ("mach-thread", info_mach_thread_command,
860            _("Get info on a specific thread."));
861
862  add_info ("mach-regions", info_mach_regions_command,
863            _("Get information on all mach region for the task."));
864  add_info ("mach-regions-rec", info_mach_regions_recurse_command,
865            _("Get information on all mach sub region for the task."));
866  add_info ("mach-region", info_mach_region_command,
867            _("Get information on mach region at given address."));
868
869  add_info ("mach-exceptions", info_mach_exceptions_command,
870            _("Disp mach exceptions."));
871}
872