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