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