Change tui_data_item_window::content to be a unique_xmalloc_ptr
[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 #include "gdbarch.h"
38
39 #include <sys/sysctl.h>
40
41 #include "darwin-nat.h"
42
43 #include <mach/thread_info.h>
44 #include <mach/thread_act.h>
45 #include <mach/task.h>
46 #include <mach/vm_map.h>
47 #include <mach/mach_port.h>
48 #include <mach/mach_init.h>
49 #include <mach/mach_vm.h>
50
51 #define CHECK_ARGS(what, args) do { \
52   if ((NULL == args) || ((args[0] != '0') && (args[1] != 'x'))) \
53     error(_("%s must be specified with 0x..."), what);          \
54 } while (0)
55
56 #define PRINT_FIELD(structure, field) \
57   printf_unfiltered(_(#field":\t%#lx\n"), (unsigned long) (structure)->field)
58
59 #define PRINT_TV_FIELD(structure, field) \
60   printf_unfiltered(_(#field":\t%u.%06u sec\n"),        \
61   (unsigned) (structure)->field.seconds, \
62   (unsigned) (structure)->field.microseconds)
63
64 #define task_self mach_task_self
65 #define task_by_unix_pid task_for_pid
66 #define port_name_array_t mach_port_array_t
67 #define port_type_array_t mach_port_array_t
68
69 static void
70 info_mach_tasks_command (const char *args, int from_tty)
71 {
72   int sysControl[4];
73   int count, index;
74   size_t length;
75   struct kinfo_proc *procInfo;
76
77   sysControl[0] = CTL_KERN;
78   sysControl[1] = KERN_PROC;
79   sysControl[2] = KERN_PROC_ALL;
80
81   sysctl (sysControl, 3, NULL, &length, NULL, 0);
82   procInfo = (struct kinfo_proc *) xmalloc (length);
83   sysctl (sysControl, 3, procInfo, &length, NULL, 0);
84
85   count = (length / sizeof (struct kinfo_proc));
86   printf_unfiltered (_("%d processes:\n"), count);
87   for (index = 0; index < count; ++index)
88     {
89       kern_return_t result;
90       mach_port_t taskPort;
91
92       result =
93         task_by_unix_pid (mach_task_self (), procInfo[index].kp_proc.p_pid,
94                           &taskPort);
95       if (KERN_SUCCESS == result)
96         {
97           printf_unfiltered (_("    %s is %d has task %#x\n"),
98                              procInfo[index].kp_proc.p_comm,
99                              procInfo[index].kp_proc.p_pid, taskPort);
100         }
101       else
102         {
103           printf_unfiltered (_("    %s is %d unknown task port\n"),
104                              procInfo[index].kp_proc.p_comm,
105                              procInfo[index].kp_proc.p_pid);
106         }
107     }
108
109   xfree (procInfo);
110 }
111
112 static task_t
113 get_task_from_args (const char *args)
114 {
115   task_t task;
116   char *eptr;
117
118   if (args == NULL || *args == 0)
119     {
120       if (inferior_ptid == null_ptid)
121         printf_unfiltered (_("No inferior running\n"));
122
123       darwin_inferior *priv = get_darwin_inferior (current_inferior ());
124
125       return priv->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 (const 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 (const 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 (inferior_ptid != null_ptid)
262             {
263               struct inferior *inf = current_inferior ();
264               darwin_inferior *priv = get_darwin_inferior (inf);
265
266               if (port == priv->task)
267                 printf_unfiltered (_(" inferior-task"));
268               else if (port == priv->notify_port)
269                 printf_unfiltered (_(" inferior-notify"));
270               else
271                 {
272                   for (int k = 0; k < priv->exception_info.count; k++)
273                     if (port == priv->exception_info.ports[k])
274                       {
275                         printf_unfiltered (_(" inferior-excp-port"));
276                         break;
277                       }
278
279                   for (darwin_thread_t *t : priv->threads)
280                     {
281                       if (port == t->gdb_port)
282                         {
283                           printf_unfiltered (_(" inferior-thread for 0x%x"),
284                                              priv->task);
285                           break;
286                         }
287                     }
288
289                 }
290             }
291         }
292       printf_unfiltered (_("\n"));
293     }
294
295   vm_deallocate (task_self (), (vm_address_t) names,
296                  (name_count * sizeof (mach_port_t)));
297   vm_deallocate (task_self (), (vm_address_t) types,
298                  (type_count * sizeof (mach_port_type_t)));
299 }
300
301
302 static void
303 darwin_debug_port_info (task_t task, mach_port_t port)
304 {
305   kern_return_t kret;
306   mach_port_status_t status;
307   mach_msg_type_number_t len = sizeof (status);
308
309   kret = mach_port_get_attributes
310     (task, port, MACH_PORT_RECEIVE_STATUS, (mach_port_info_t)&status, &len);
311   MACH_CHECK_ERROR (kret);
312
313   printf_unfiltered (_("Port 0x%lx in task 0x%lx:\n"), (unsigned long) port,
314                      (unsigned long) task);
315   printf_unfiltered (_("  port set: 0x%x\n"), status.mps_pset);
316   printf_unfiltered (_("     seqno: 0x%x\n"), status.mps_seqno);
317   printf_unfiltered (_("   mscount: 0x%x\n"), status.mps_mscount);
318   printf_unfiltered (_("    qlimit: 0x%x\n"), status.mps_qlimit);
319   printf_unfiltered (_("  msgcount: 0x%x\n"), status.mps_msgcount);
320   printf_unfiltered (_("  sorights: 0x%x\n"), status.mps_sorights);
321   printf_unfiltered (_("   srights: 0x%x\n"), status.mps_srights);
322   printf_unfiltered (_(" pdrequest: 0x%x\n"), status.mps_pdrequest);
323   printf_unfiltered (_(" nsrequest: 0x%x\n"), status.mps_nsrequest);
324   printf_unfiltered (_("     flags: 0x%x\n"), status.mps_flags);
325 }
326
327 static void
328 info_mach_port_command (const char *args, int from_tty)
329 {
330   task_t task;
331   mach_port_t port;
332
333   CHECK_ARGS (_("Task and port"), args);
334   sscanf (args, "0x%x 0x%x", &task, &port);
335
336   darwin_debug_port_info (task, port);
337 }
338
339 static void
340 info_mach_threads_command (const char *args, int from_tty)
341 {
342   thread_array_t threads;
343   unsigned int thread_count;
344   kern_return_t result;
345   task_t task;
346   int i;
347
348   task = get_task_from_args (args);
349   if (task == TASK_NULL)
350     return;
351
352   result = task_threads (task, &threads, &thread_count);
353   MACH_CHECK_ERROR (result);
354
355   printf_unfiltered (_("Threads in task %#x:\n"), task);
356   for (i = 0; i < thread_count; ++i)
357     {
358       printf_unfiltered (_("    %#x\n"), threads[i]);
359       mach_port_deallocate (task_self (), threads[i]);
360     }
361
362   vm_deallocate (task_self (), (vm_address_t) threads,
363                  (thread_count * sizeof (thread_t)));
364 }
365
366 static void
367 info_mach_thread_command (const char *args, int from_tty)
368 {
369   union
370   {
371     struct thread_basic_info basic;
372   } thread_info_data;
373
374   thread_t thread;
375   kern_return_t result;
376   unsigned int info_count;
377
378   CHECK_ARGS (_("Thread"), args);
379   sscanf (args, "0x%x", &thread);
380
381   printf_unfiltered (_("THREAD_BASIC_INFO\n"));
382   info_count = THREAD_BASIC_INFO_COUNT;
383   result = thread_info (thread,
384                         THREAD_BASIC_INFO,
385                         (thread_info_t) & thread_info_data.basic,
386                         &info_count);
387   MACH_CHECK_ERROR (result);
388
389 #if 0
390   PRINT_FIELD (&thread_info_data.basic, user_time);
391   PRINT_FIELD (&thread_info_data.basic, system_time);
392 #endif
393   PRINT_FIELD (&thread_info_data.basic, cpu_usage);
394   PRINT_FIELD (&thread_info_data.basic, run_state);
395   PRINT_FIELD (&thread_info_data.basic, flags);
396   PRINT_FIELD (&thread_info_data.basic, suspend_count);
397   PRINT_FIELD (&thread_info_data.basic, sleep_time);
398 }
399
400 static const char *
401 unparse_protection (vm_prot_t p)
402 {
403   switch (p)
404     {
405     case VM_PROT_NONE:
406       return "---";
407     case VM_PROT_READ:
408       return "r--";
409     case VM_PROT_WRITE:
410       return "-w-";
411     case VM_PROT_READ | VM_PROT_WRITE:
412       return "rw-";
413     case VM_PROT_EXECUTE:
414       return "--x";
415     case VM_PROT_EXECUTE | VM_PROT_READ:
416       return "r-x";
417     case VM_PROT_EXECUTE | VM_PROT_WRITE:
418       return "-wx";
419     case VM_PROT_EXECUTE | VM_PROT_WRITE | VM_PROT_READ:
420       return "rwx";
421     default:
422       return "???";
423     }
424 }
425
426 static const char *
427 unparse_inheritance (vm_inherit_t i)
428 {
429   switch (i)
430     {
431     case VM_INHERIT_SHARE:
432       return _("share");
433     case VM_INHERIT_COPY:
434       return _("copy ");
435     case VM_INHERIT_NONE:
436       return _("none ");
437     default:
438       return _("???  ");
439     }
440 }
441
442 static const char *
443 unparse_share_mode (unsigned char p)
444 {
445   switch (p)
446     {
447     case SM_COW:
448       return _("cow");
449     case SM_PRIVATE:
450       return _("private");
451     case SM_EMPTY:
452       return _("empty");
453     case SM_SHARED:
454       return _("shared");
455     case SM_TRUESHARED:
456       return _("true-shrd");
457     case SM_PRIVATE_ALIASED:
458       return _("prv-alias");
459     case SM_SHARED_ALIASED:
460       return _("shr-alias");
461     default:
462       return _("???");
463     }
464 }
465
466 static const char *
467 unparse_user_tag (unsigned int tag)
468 {
469   switch (tag)
470     {
471     case 0:
472       return _("default");
473     case VM_MEMORY_MALLOC:
474       return _("malloc");
475     case VM_MEMORY_MALLOC_SMALL:
476       return _("malloc_small");
477     case VM_MEMORY_MALLOC_LARGE:
478       return _("malloc_large");
479     case VM_MEMORY_MALLOC_HUGE:
480       return _("malloc_huge");
481     case VM_MEMORY_SBRK:
482       return _("sbrk");
483     case VM_MEMORY_REALLOC:
484       return _("realloc");
485     case VM_MEMORY_MALLOC_TINY:
486       return _("malloc_tiny");
487     case VM_MEMORY_ANALYSIS_TOOL:
488       return _("analysis_tool");
489     case VM_MEMORY_MACH_MSG:
490       return _("mach_msg");
491     case VM_MEMORY_IOKIT:
492       return _("iokit");
493     case VM_MEMORY_STACK:
494       return _("stack");
495     case VM_MEMORY_GUARD:
496       return _("guard");
497     case VM_MEMORY_SHARED_PMAP:
498       return _("shared_pmap");
499     case VM_MEMORY_DYLIB:
500       return _("dylib");
501     case VM_MEMORY_APPKIT:
502       return _("appkit");
503     case VM_MEMORY_FOUNDATION:
504       return _("foundation");
505     default:
506       return NULL;
507     }
508 }
509
510 static void
511 darwin_debug_regions (task_t task, mach_vm_address_t address, int max)
512 {
513   kern_return_t kret;
514   vm_region_basic_info_data_64_t info, prev_info;
515   mach_vm_address_t prev_address;
516   mach_vm_size_t size, prev_size;
517
518   mach_port_t object_name;
519   mach_msg_type_number_t count;
520
521   int nsubregions = 0;
522   int num_printed = 0;
523
524   count = VM_REGION_BASIC_INFO_COUNT_64;
525   kret = mach_vm_region (task, &address, &size, VM_REGION_BASIC_INFO_64,
526                          (vm_region_info_t) &info, &count, &object_name);
527   if (kret != KERN_SUCCESS)
528     {
529       printf_filtered (_("No memory regions."));
530       return;
531     }
532   memcpy (&prev_info, &info, sizeof (vm_region_basic_info_data_64_t));
533   prev_address = address;
534   prev_size = size;
535   nsubregions = 1;
536
537   for (;;)
538     {
539       int print = 0;
540       int done = 0;
541
542       address = prev_address + prev_size;
543
544       /* Check to see if address space has wrapped around.  */
545       if (address == 0)
546         print = done = 1;
547
548       if (!done)
549         {
550           count = VM_REGION_BASIC_INFO_COUNT_64;
551           kret =
552             mach_vm_region (task, &address, &size, VM_REGION_BASIC_INFO_64,
553                               (vm_region_info_t) &info, &count, &object_name);
554           if (kret != KERN_SUCCESS)
555             {
556               size = 0;
557               print = done = 1;
558             }
559         }
560
561       if (address != prev_address + prev_size)
562         print = 1;
563
564       if ((info.protection != prev_info.protection)
565           || (info.max_protection != prev_info.max_protection)
566           || (info.inheritance != prev_info.inheritance)
567           || (info.shared != prev_info.reserved)
568           || (info.reserved != prev_info.reserved))
569         print = 1;
570
571       if (print)
572         {
573           printf_filtered (_("%s-%s %s/%s  %s %s %s"),
574                            paddress (target_gdbarch (), prev_address),
575                            paddress (target_gdbarch (), prev_address + prev_size),
576                            unparse_protection (prev_info.protection),
577                            unparse_protection (prev_info.max_protection),
578                            unparse_inheritance (prev_info.inheritance),
579                            prev_info.shared ? _("shrd") : _("priv"),
580                            prev_info.reserved ? _("reserved") : _("not-rsvd"));
581
582           if (nsubregions > 1)
583             printf_filtered (_(" (%d sub-rgn)"), nsubregions);
584
585           printf_filtered (_("\n"));
586
587           prev_address = address;
588           prev_size = size;
589           memcpy (&prev_info, &info, sizeof (vm_region_basic_info_data_64_t));
590           nsubregions = 1;
591
592           num_printed++;
593         }
594       else
595         {
596           prev_size += size;
597           nsubregions++;
598         }
599
600       if ((max > 0) && (num_printed >= max))
601         done = 1;
602
603       if (done)
604         break;
605     }
606 }
607
608 static void
609 darwin_debug_regions_recurse (task_t task)
610 {
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   struct ui_out *uiout = current_uiout;
618
619   ui_out_emit_table table_emitter (uiout, 9, -1, "regions");
620
621   if (gdbarch_addr_bit (target_gdbarch ()) <= 32)
622     {
623       uiout->table_header (10, ui_left, "start", "Start");
624       uiout->table_header (10, ui_left, "end", "End");
625     }
626   else
627     {
628       uiout->table_header (18, ui_left, "start", "Start");
629       uiout->table_header (18, ui_left, "end", "End");
630     }
631   uiout->table_header (3, ui_left, "min-prot", "Min");
632   uiout->table_header (3, ui_left, "max-prot", "Max");
633   uiout->table_header (5, ui_left, "inheritence", "Inh");
634   uiout->table_header (9, ui_left, "share-mode", "Shr");
635   uiout->table_header (1, ui_left, "depth", "D");
636   uiout->table_header (3, ui_left, "submap", "Sm");
637   uiout->table_header (0, ui_noalign, "tag", "Tag");
638
639   uiout->table_body ();
640
641   r_start = 0;
642   r_depth = 0;
643   while (1)
644     {
645       const char *tag;
646
647       r_info_size = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
648       r_size = -1;
649       kret = mach_vm_region_recurse (task, &r_start, &r_size, &r_depth,
650                                      (vm_region_recurse_info_t) &r_info,
651                                      &r_info_size);
652       if (kret != KERN_SUCCESS)
653         break;
654
655       {
656         ui_out_emit_tuple tuple_emitter (uiout, "regions-row");
657
658         uiout->field_core_addr ("start", target_gdbarch (), r_start);
659         uiout->field_core_addr ("end", target_gdbarch (), r_start + r_size);
660         uiout->field_string ("min-prot",
661                              unparse_protection (r_info.protection));
662         uiout->field_string ("max-prot",
663                              unparse_protection (r_info.max_protection));
664         uiout->field_string ("inheritence",
665                              unparse_inheritance (r_info.inheritance));
666         uiout->field_string ("share-mode",
667                              unparse_share_mode (r_info.share_mode));
668         uiout->field_signed ("depth", r_depth);
669         uiout->field_string ("submap",
670                              r_info.is_submap ? _("sm ") : _("obj"));
671         tag = unparse_user_tag (r_info.user_tag);
672         if (tag)
673           uiout->field_string ("tag", tag);
674         else
675           uiout->field_signed ("tag", r_info.user_tag);
676       }
677
678       uiout->text ("\n");
679
680       if (r_info.is_submap)
681         r_depth++;
682       else
683         r_start += r_size;
684     }
685 }
686
687
688 static void
689 darwin_debug_region (task_t task, mach_vm_address_t address)
690 {
691   darwin_debug_regions (task, address, 1);
692 }
693
694 static void
695 info_mach_regions_command (const char *args, int from_tty)
696 {
697   task_t task;
698
699   task = get_task_from_args (args);
700   if (task == TASK_NULL)
701     return;
702   
703   darwin_debug_regions (task, 0, -1);
704 }
705
706 static void
707 info_mach_regions_recurse_command (const char *args, int from_tty)
708 {
709   task_t task;
710
711   task = get_task_from_args (args);
712   if (task == TASK_NULL)
713     return;
714   
715   darwin_debug_regions_recurse (task);
716 }
717
718 static void
719 info_mach_region_command (const char *exp, int from_tty)
720 {
721   struct value *val;
722   mach_vm_address_t address;
723   struct inferior *inf;
724
725   expression_up expr = parse_expression (exp);
726   val = evaluate_expression (expr.get ());
727   if (TYPE_IS_REFERENCE (value_type (val)))
728     {
729       val = value_ind (val);
730     }
731   address = value_as_address (val);
732
733   if (inferior_ptid == null_ptid)
734     error (_("Inferior not available"));
735
736   inf = current_inferior ();
737   darwin_inferior *priv = get_darwin_inferior (inf);
738   darwin_debug_region (priv->task, address);
739 }
740
741 static void
742 disp_exception (const darwin_exception_info *info)
743 {
744   int i;
745
746   printf_filtered (_("%d exceptions:\n"), info->count);
747   for (i = 0; i < info->count; i++)
748     {
749       exception_mask_t mask = info->masks[i];
750
751       printf_filtered (_("port 0x%04x, behavior: "), info->ports[i]);
752       switch (info->behaviors[i])
753         {
754         case EXCEPTION_DEFAULT:
755           printf_unfiltered (_("default"));
756           break;
757         case EXCEPTION_STATE:
758           printf_unfiltered (_("state"));
759           break;
760         case EXCEPTION_STATE_IDENTITY:
761           printf_unfiltered (_("state-identity"));
762           break;
763         default:
764           printf_unfiltered (_("0x%x"), info->behaviors[i]);
765         }
766       printf_unfiltered (_(", masks:"));
767       if (mask & EXC_MASK_BAD_ACCESS)
768         printf_unfiltered (_(" BAD_ACCESS"));
769       if (mask & EXC_MASK_BAD_INSTRUCTION)
770         printf_unfiltered (_(" BAD_INSTRUCTION"));
771       if (mask & EXC_MASK_ARITHMETIC)
772         printf_unfiltered (_(" ARITHMETIC"));
773       if (mask & EXC_MASK_EMULATION)
774         printf_unfiltered (_(" EMULATION"));
775       if (mask & EXC_MASK_SOFTWARE)
776         printf_unfiltered (_(" SOFTWARE"));
777       if (mask & EXC_MASK_BREAKPOINT)
778         printf_unfiltered (_(" BREAKPOINT"));
779       if (mask & EXC_MASK_SYSCALL)
780         printf_unfiltered (_(" SYSCALL"));
781       if (mask & EXC_MASK_MACH_SYSCALL)
782         printf_unfiltered (_(" MACH_SYSCALL"));
783       if (mask & EXC_MASK_RPC_ALERT)
784         printf_unfiltered (_(" RPC_ALERT"));
785       if (mask & EXC_MASK_CRASH)
786         printf_unfiltered (_(" CRASH"));
787       printf_unfiltered (_("\n"));
788     }
789 }
790
791 static void
792 info_mach_exceptions_command (const char *args, int from_tty)
793 {
794   kern_return_t kret;
795   darwin_exception_info info;
796
797   info.count = sizeof (info.ports) / sizeof (info.ports[0]);
798
799   if (args != NULL)
800     {
801       if (strcmp (args, "saved") == 0)
802         {
803           if (inferior_ptid == null_ptid)
804             printf_unfiltered (_("No inferior running\n"));
805
806           darwin_inferior *priv = get_darwin_inferior (current_inferior ());
807
808           disp_exception (&priv->exception_info);
809           return;
810         }
811       else if (strcmp (args, "host") == 0)
812         {
813           /* FIXME: This need a privilegied host port!  */
814           kret = host_get_exception_ports
815             (darwin_host_self, EXC_MASK_ALL, info.masks,
816              &info.count, info.ports, info.behaviors, info.flavors);
817           MACH_CHECK_ERROR (kret);
818           disp_exception (&info);
819         }
820       else
821         error (_("Parameter is saved, host or none"));
822     }
823   else
824     {
825       struct inferior *inf;
826
827       if (inferior_ptid == null_ptid)
828         printf_unfiltered (_("No inferior running\n"));
829       inf = current_inferior ();
830       
831       darwin_inferior *priv = get_darwin_inferior (inf);
832
833       kret = task_get_exception_ports
834         (priv->task, EXC_MASK_ALL, info.masks,
835          &info.count, info.ports, info.behaviors, info.flavors);
836       MACH_CHECK_ERROR (kret);
837       disp_exception (&info);
838     }
839 }
840
841 void
842 _initialize_darwin_info_commands (void)
843 {
844   add_info ("mach-tasks", info_mach_tasks_command,
845             _("Get list of tasks in system."));
846   add_info ("mach-ports", info_mach_ports_command,
847             _("Get list of ports in a task."));
848   add_info ("mach-port", info_mach_port_command,
849             _("Get info on a specific port."));
850   add_info ("mach-task", info_mach_task_command,
851             _("Get info on a specific task."));
852   add_info ("mach-threads", info_mach_threads_command,
853             _("Get list of threads in a task."));
854   add_info ("mach-thread", info_mach_thread_command,
855             _("Get info on a specific thread."));
856
857   add_info ("mach-regions", info_mach_regions_command,
858             _("Get information on all mach region for the task."));
859   add_info ("mach-regions-rec", info_mach_regions_recurse_command,
860             _("Get information on all mach sub region for the task."));
861   add_info ("mach-region", info_mach_region_command,
862             _("Get information on mach region at given address."));
863
864   add_info ("mach-exceptions", info_mach_exceptions_command,
865             _("Disp mach exceptions."));
866 }