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