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