Automatic date update in version.in
[external/binutils.git] / gdb / darwin-nat-info.c
1 /* Darwin support for GDB, the GNU debugger.
2    Copyright (C) 1997-2019 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 (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 (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_start;
611   mach_vm_size_t r_size;
612   natural_t r_depth;
613   mach_msg_type_number_t r_info_size;
614   vm_region_submap_short_info_data_64_t r_info;
615   kern_return_t kret;
616   struct ui_out *uiout = current_uiout;
617
618   ui_out_emit_table table_emitter (uiout, 9, -1, "regions");
619
620   if (gdbarch_addr_bit (target_gdbarch ()) <= 32)
621     {
622       uiout->table_header (10, ui_left, "start", "Start");
623       uiout->table_header (10, ui_left, "end", "End");
624     }
625   else
626     {
627       uiout->table_header (18, ui_left, "start", "Start");
628       uiout->table_header (18, ui_left, "end", "End");
629     }
630   uiout->table_header (3, ui_left, "min-prot", "Min");
631   uiout->table_header (3, ui_left, "max-prot", "Max");
632   uiout->table_header (5, ui_left, "inheritence", "Inh");
633   uiout->table_header (9, ui_left, "share-mode", "Shr");
634   uiout->table_header (1, ui_left, "depth", "D");
635   uiout->table_header (3, ui_left, "submap", "Sm");
636   uiout->table_header (0, ui_noalign, "tag", "Tag");
637
638   uiout->table_body ();
639
640   r_start = 0;
641   r_depth = 0;
642   while (1)
643     {
644       const char *tag;
645
646       r_info_size = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
647       r_size = -1;
648       kret = mach_vm_region_recurse (task, &r_start, &r_size, &r_depth,
649                                      (vm_region_recurse_info_t) &r_info,
650                                      &r_info_size);
651       if (kret != KERN_SUCCESS)
652         break;
653
654       {
655         ui_out_emit_tuple tuple_emitter (uiout, "regions-row");
656
657         uiout->field_core_addr ("start", target_gdbarch (), r_start);
658         uiout->field_core_addr ("end", target_gdbarch (), r_start + r_size);
659         uiout->field_string ("min-prot",
660                              unparse_protection (r_info.protection));
661         uiout->field_string ("max-prot",
662                              unparse_protection (r_info.max_protection));
663         uiout->field_string ("inheritence",
664                              unparse_inheritance (r_info.inheritance));
665         uiout->field_string ("share-mode",
666                              unparse_share_mode (r_info.share_mode));
667         uiout->field_int ("depth", r_depth);
668         uiout->field_string ("submap",
669                              r_info.is_submap ? _("sm ") : _("obj"));
670         tag = unparse_user_tag (r_info.user_tag);
671         if (tag)
672           uiout->field_string ("tag", tag);
673         else
674           uiout->field_int ("tag", r_info.user_tag);
675       }
676
677       uiout->text ("\n");
678
679       if (r_info.is_submap)
680         r_depth++;
681       else
682         r_start += r_size;
683     }
684 }
685
686
687 static void
688 darwin_debug_region (task_t task, mach_vm_address_t address)
689 {
690   darwin_debug_regions (task, address, 1);
691 }
692
693 static void
694 info_mach_regions_command (const char *args, int from_tty)
695 {
696   task_t task;
697
698   task = get_task_from_args (args);
699   if (task == TASK_NULL)
700     return;
701   
702   darwin_debug_regions (task, 0, -1);
703 }
704
705 static void
706 info_mach_regions_recurse_command (const char *args, int from_tty)
707 {
708   task_t task;
709
710   task = get_task_from_args (args);
711   if (task == TASK_NULL)
712     return;
713   
714   darwin_debug_regions_recurse (task);
715 }
716
717 static void
718 info_mach_region_command (const char *exp, int from_tty)
719 {
720   struct value *val;
721   mach_vm_address_t address;
722   struct inferior *inf;
723
724   expression_up expr = parse_expression (exp);
725   val = evaluate_expression (expr.get ());
726   if (TYPE_IS_REFERENCE (value_type (val)))
727     {
728       val = value_ind (val);
729     }
730   address = value_as_address (val);
731
732   if (inferior_ptid == null_ptid)
733     error (_("Inferior not available"));
734
735   inf = current_inferior ();
736   darwin_inferior *priv = get_darwin_inferior (inf);
737   darwin_debug_region (priv->task, address);
738 }
739
740 static void
741 disp_exception (const darwin_exception_info *info)
742 {
743   int i;
744
745   printf_filtered (_("%d exceptions:\n"), info->count);
746   for (i = 0; i < info->count; i++)
747     {
748       exception_mask_t mask = info->masks[i];
749
750       printf_filtered (_("port 0x%04x, behavior: "), info->ports[i]);
751       switch (info->behaviors[i])
752         {
753         case EXCEPTION_DEFAULT:
754           printf_unfiltered (_("default"));
755           break;
756         case EXCEPTION_STATE:
757           printf_unfiltered (_("state"));
758           break;
759         case EXCEPTION_STATE_IDENTITY:
760           printf_unfiltered (_("state-identity"));
761           break;
762         default:
763           printf_unfiltered (_("0x%x"), info->behaviors[i]);
764         }
765       printf_unfiltered (_(", masks:"));
766       if (mask & EXC_MASK_BAD_ACCESS)
767         printf_unfiltered (_(" BAD_ACCESS"));
768       if (mask & EXC_MASK_BAD_INSTRUCTION)
769         printf_unfiltered (_(" BAD_INSTRUCTION"));
770       if (mask & EXC_MASK_ARITHMETIC)
771         printf_unfiltered (_(" ARITHMETIC"));
772       if (mask & EXC_MASK_EMULATION)
773         printf_unfiltered (_(" EMULATION"));
774       if (mask & EXC_MASK_SOFTWARE)
775         printf_unfiltered (_(" SOFTWARE"));
776       if (mask & EXC_MASK_BREAKPOINT)
777         printf_unfiltered (_(" BREAKPOINT"));
778       if (mask & EXC_MASK_SYSCALL)
779         printf_unfiltered (_(" SYSCALL"));
780       if (mask & EXC_MASK_MACH_SYSCALL)
781         printf_unfiltered (_(" MACH_SYSCALL"));
782       if (mask & EXC_MASK_RPC_ALERT)
783         printf_unfiltered (_(" RPC_ALERT"));
784       if (mask & EXC_MASK_CRASH)
785         printf_unfiltered (_(" CRASH"));
786       printf_unfiltered (_("\n"));
787     }
788 }
789
790 static void
791 info_mach_exceptions_command (const char *args, int from_tty)
792 {
793   kern_return_t kret;
794   darwin_exception_info info;
795
796   info.count = sizeof (info.ports) / sizeof (info.ports[0]);
797
798   if (args != NULL)
799     {
800       if (strcmp (args, "saved") == 0)
801         {
802           if (inferior_ptid == null_ptid)
803             printf_unfiltered (_("No inferior running\n"));
804
805           darwin_inferior *priv = get_darwin_inferior (current_inferior ());
806
807           disp_exception (&priv->exception_info);
808           return;
809         }
810       else if (strcmp (args, "host") == 0)
811         {
812           /* FIXME: This need a privilegied host port!  */
813           kret = host_get_exception_ports
814             (darwin_host_self, EXC_MASK_ALL, info.masks,
815              &info.count, info.ports, info.behaviors, info.flavors);
816           MACH_CHECK_ERROR (kret);
817           disp_exception (&info);
818         }
819       else
820         error (_("Parameter is saved, host or none"));
821     }
822   else
823     {
824       struct inferior *inf;
825
826       if (inferior_ptid == null_ptid)
827         printf_unfiltered (_("No inferior running\n"));
828       inf = current_inferior ();
829       
830       darwin_inferior *priv = get_darwin_inferior (inf);
831
832       kret = task_get_exception_ports
833         (priv->task, EXC_MASK_ALL, info.masks,
834          &info.count, info.ports, info.behaviors, info.flavors);
835       MACH_CHECK_ERROR (kret);
836       disp_exception (&info);
837     }
838 }
839
840 void
841 _initialize_darwin_info_commands (void)
842 {
843   add_info ("mach-tasks", info_mach_tasks_command,
844             _("Get list of tasks in system."));
845   add_info ("mach-ports", info_mach_ports_command,
846             _("Get list of ports in a task."));
847   add_info ("mach-port", info_mach_port_command,
848             _("Get info on a specific port."));
849   add_info ("mach-task", info_mach_task_command,
850             _("Get info on a specific task."));
851   add_info ("mach-threads", info_mach_threads_command,
852             _("Get list of threads in a task."));
853   add_info ("mach-thread", info_mach_thread_command,
854             _("Get info on a specific thread."));
855
856   add_info ("mach-regions", info_mach_regions_command,
857             _("Get information on all mach region for the task."));
858   add_info ("mach-regions-rec", info_mach_regions_recurse_command,
859             _("Get information on all mach sub region for the task."));
860   add_info ("mach-region", info_mach_region_command,
861             _("Get information on mach region at given address."));
862
863   add_info ("mach-exceptions", info_mach_exceptions_command,
864             _("Disp mach exceptions."));
865 }