Remove unnecessary function prototypes.
[external/binutils.git] / gdb / darwin-nat-info.c
1 /* Darwin support for GDB, the GNU debugger.
2    Copyright (C) 1997-2017 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       uiout->table_header (10, ui_left, "start", "Start");
628       uiout->table_header (10, ui_left, "end", "End");
629     }
630   else
631     {
632       uiout->table_header (18, ui_left, "start", "Start");
633       uiout->table_header (18, ui_left, "end", "End");
634     }
635   uiout->table_header (3, ui_left, "min-prot", "Min");
636   uiout->table_header (3, ui_left, "max-prot", "Max");
637   uiout->table_header (5, ui_left, "inheritence", "Inh");
638   uiout->table_header (9, ui_left, "share-mode", "Shr");
639   uiout->table_header (1, ui_left, "depth", "D");
640   uiout->table_header (3, ui_left, "submap", "Sm");
641   uiout->table_header (0, ui_noalign, "tag", "Tag");
642
643   uiout->table_body ();
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       uiout->field_core_addr ("start", target_gdbarch (), r_start);
662       uiout->field_core_addr ("end", target_gdbarch (), r_start + r_size);
663       uiout->field_string ("min-prot",
664                            unparse_protection (r_info.protection));
665       uiout->field_string ("max-prot",
666                            unparse_protection (r_info.max_protection));
667       uiout->field_string ("inheritence",
668                            unparse_inheritance (r_info.inheritance));
669       uiout->field_string ("share-mode",
670                            unparse_share_mode (r_info.share_mode));
671       uiout->field_int ("depth", r_depth);
672       uiout->field_string ("submap",
673                            r_info.is_submap ? _("sm ") : _("obj"));
674       tag = unparse_user_tag (r_info.user_tag);
675       if (tag)
676         uiout->field_string ("tag", tag);
677       else
678         uiout->field_int ("tag", r_info.user_tag);
679
680       do_cleanups (row_chain);
681
682       if (!uiout->is_mi_like_p ())
683         uiout->text ("\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 value *val;
729   mach_vm_address_t address;
730   struct inferior *inf;
731
732   expression_up expr = parse_expression (exp);
733   val = evaluate_expression (expr.get ());
734   if (TYPE_IS_REFERENCE (value_type (val)))
735     {
736       val = value_ind (val);
737     }
738   address = value_as_address (val);
739
740   if (ptid_equal (inferior_ptid, null_ptid))
741     error (_("Inferior not available"));
742
743   inf = current_inferior ();
744   darwin_debug_region (inf->priv->task, address);
745 }
746
747 static void
748 disp_exception (const darwin_exception_info *info)
749 {
750   int i;
751
752   printf_filtered (_("%d exceptions:\n"), info->count);
753   for (i = 0; i < info->count; i++)
754     {
755       exception_mask_t mask = info->masks[i];
756
757       printf_filtered (_("port 0x%04x, behavior: "), info->ports[i]);
758       switch (info->behaviors[i])
759         {
760         case EXCEPTION_DEFAULT:
761           printf_unfiltered (_("default"));
762           break;
763         case EXCEPTION_STATE:
764           printf_unfiltered (_("state"));
765           break;
766         case EXCEPTION_STATE_IDENTITY:
767           printf_unfiltered (_("state-identity"));
768           break;
769         default:
770           printf_unfiltered (_("0x%x"), info->behaviors[i]);
771         }
772       printf_unfiltered (_(", masks:"));
773       if (mask & EXC_MASK_BAD_ACCESS)
774         printf_unfiltered (_(" BAD_ACCESS"));
775       if (mask & EXC_MASK_BAD_INSTRUCTION)
776         printf_unfiltered (_(" BAD_INSTRUCTION"));
777       if (mask & EXC_MASK_ARITHMETIC)
778         printf_unfiltered (_(" ARITHMETIC"));
779       if (mask & EXC_MASK_EMULATION)
780         printf_unfiltered (_(" EMULATION"));
781       if (mask & EXC_MASK_SOFTWARE)
782         printf_unfiltered (_(" SOFTWARE"));
783       if (mask & EXC_MASK_BREAKPOINT)
784         printf_unfiltered (_(" BREAKPOINT"));
785       if (mask & EXC_MASK_SYSCALL)
786         printf_unfiltered (_(" SYSCALL"));
787       if (mask & EXC_MASK_MACH_SYSCALL)
788         printf_unfiltered (_(" MACH_SYSCALL"));
789       if (mask & EXC_MASK_RPC_ALERT)
790         printf_unfiltered (_(" RPC_ALERT"));
791       if (mask & EXC_MASK_CRASH)
792         printf_unfiltered (_(" CRASH"));
793       printf_unfiltered (_("\n"));
794     }
795 }
796
797 static void
798 info_mach_exceptions_command (char *args, int from_tty)
799 {
800   int i;
801   task_t task;
802   kern_return_t kret;
803   darwin_exception_info info;
804
805   info.count = sizeof (info.ports) / sizeof (info.ports[0]);
806
807   if (args != NULL)
808     {
809       if (strcmp (args, "saved") == 0)
810         {
811           if (ptid_equal (inferior_ptid, null_ptid))
812             printf_unfiltered (_("No inferior running\n"));
813           disp_exception (&current_inferior ()->priv->exception_info);
814           return;
815         }
816       else if (strcmp (args, "host") == 0)
817         {
818           /* FIXME: This need a privilegied host port!  */
819           kret = host_get_exception_ports
820             (darwin_host_self, EXC_MASK_ALL, info.masks,
821              &info.count, info.ports, info.behaviors, info.flavors);
822           MACH_CHECK_ERROR (kret);
823           disp_exception (&info);
824         }
825       else
826         error (_("Parameter is saved, host or none"));
827     }
828   else
829     {
830       struct inferior *inf;
831
832       if (ptid_equal (inferior_ptid, null_ptid))
833         printf_unfiltered (_("No inferior running\n"));
834       inf = current_inferior ();
835       
836       kret = task_get_exception_ports
837         (inf->priv->task, EXC_MASK_ALL, info.masks,
838          &info.count, info.ports, info.behaviors, info.flavors);
839       MACH_CHECK_ERROR (kret);
840       disp_exception (&info);
841     }
842 }
843
844 void
845 _initialize_darwin_info_commands (void)
846 {
847   add_info ("mach-tasks", info_mach_tasks_command,
848             _("Get list of tasks in system."));
849   add_info ("mach-ports", info_mach_ports_command,
850             _("Get list of ports in a task."));
851   add_info ("mach-port", info_mach_port_command,
852             _("Get info on a specific port."));
853   add_info ("mach-task", info_mach_task_command,
854             _("Get info on a specific task."));
855   add_info ("mach-threads", info_mach_threads_command,
856             _("Get list of threads in a task."));
857   add_info ("mach-thread", info_mach_thread_command,
858             _("Get info on a specific thread."));
859
860   add_info ("mach-regions", info_mach_regions_command,
861             _("Get information on all mach region for the task."));
862   add_info ("mach-regions-rec", info_mach_regions_recurse_command,
863             _("Get information on all mach sub region for the task."));
864   add_info ("mach-region", info_mach_region_command,
865             _("Get information on mach region at given address."));
866
867   add_info ("mach-exceptions", info_mach_exceptions_command,
868             _("Disp mach exceptions."));
869 }