xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/darwin-nat-info.c (revision 122b5006ee1bd67145794b4cde92f4fe4781a5ec)
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 }
866