1 /* Darwin support for GDB, the GNU debugger.
2    Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2008, 2009, 2010, 2011
3    Free Software Foundation, Inc.
4 
5    Contributed by Apple Computer, Inc.
6 
7    This file is part of GDB.
8 
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
21 
22 /* The name of the ppc_thread_state structure, and the names of its
23    members, have been changed for Unix conformance reasons.  The easiest
24    way to have gdb build on systems with the older names and systems
25    with the newer names is to build this compilation unit with the
26    non-conformant define below.  This doesn't seem to cause the resulting
27    binary any problems but it seems like it could cause us problems in
28    the future.  It'd be good to remove this at some point when compiling on
29    Tiger is no longer important.  */
30 
31 #include "defs.h"
32 #include "symtab.h"
33 #include "gdbtypes.h"
34 #include "gdbcore.h"
35 #include "value.h"
36 #include "gdbcmd.h"
37 #include "inferior.h"
38 
39 #include <sys/param.h>
40 #include <sys/sysctl.h>
41 
42 #include "darwin-nat.h"
43 
44 #include <mach/thread_info.h>
45 #include <mach/thread_act.h>
46 #include <mach/task.h>
47 #include <mach/vm_map.h>
48 #include <mach/mach_port.h>
49 #include <mach/mach_init.h>
50 #include <mach/mach_vm.h>
51 
52 #define CHECK_ARGS(what, args) do { \
53   if ((NULL == args) || ((args[0] != '0') && (args[1] != 'x'))) \
54     error(_("%s must be specified with 0x..."), what);		\
55 } while (0)
56 
57 #define PRINT_FIELD(structure, field) \
58   printf_unfiltered(_(#field":\t%#lx\n"), (unsigned long) (structure)->field)
59 
60 #define PRINT_TV_FIELD(structure, field) \
61   printf_unfiltered(_(#field":\t%u.%06u sec\n"),	\
62   (unsigned) (structure)->field.seconds, \
63   (unsigned) (structure)->field.microseconds)
64 
65 #define task_self mach_task_self
66 #define task_by_unix_pid task_for_pid
67 #define port_name_array_t mach_port_array_t
68 #define port_type_array_t mach_port_array_t
69 
70 static void
info_mach_tasks_command(char * args,int from_tty)71 info_mach_tasks_command (char *args, int from_tty)
72 {
73   int sysControl[4];
74   int count, index;
75   size_t length;
76   struct kinfo_proc *procInfo;
77 
78   sysControl[0] = CTL_KERN;
79   sysControl[1] = KERN_PROC;
80   sysControl[2] = KERN_PROC_ALL;
81 
82   sysctl (sysControl, 3, NULL, &length, NULL, 0);
83   procInfo = (struct kinfo_proc *) xmalloc (length);
84   sysctl (sysControl, 3, procInfo, &length, NULL, 0);
85 
86   count = (length / sizeof (struct kinfo_proc));
87   printf_unfiltered (_("%d processes:\n"), count);
88   for (index = 0; index < count; ++index)
89     {
90       kern_return_t result;
91       mach_port_t taskPort;
92 
93       result =
94         task_by_unix_pid (mach_task_self (), procInfo[index].kp_proc.p_pid,
95                           &taskPort);
96       if (KERN_SUCCESS == result)
97         {
98           printf_unfiltered (_("    %s is %d has task %#x\n"),
99                              procInfo[index].kp_proc.p_comm,
100                              procInfo[index].kp_proc.p_pid, taskPort);
101         }
102       else
103         {
104           printf_unfiltered (_("    %s is %d unknown task port\n"),
105                              procInfo[index].kp_proc.p_comm,
106                              procInfo[index].kp_proc.p_pid);
107         }
108     }
109 
110   xfree (procInfo);
111 }
112 
113 static task_t
get_task_from_args(char * args)114 get_task_from_args (char *args)
115 {
116   task_t task;
117   char *eptr;
118 
119   if (args == NULL || *args == 0)
120     {
121       if (ptid_equal (inferior_ptid, null_ptid))
122 	printf_unfiltered (_("No inferior running\n"));
123       return current_inferior ()->private->task;
124     }
125   if (strcmp (args, "gdb") == 0)
126     return mach_task_self ();
127   task = strtoul (args, &eptr, 0);
128   if (*eptr)
129     {
130       printf_unfiltered (_("cannot parse task id '%s'\n"), args);
131       return TASK_NULL;
132     }
133   return task;
134 }
135 
136 static void
info_mach_task_command(char * args,int from_tty)137 info_mach_task_command (char *args, int from_tty)
138 {
139   union
140   {
141     struct task_basic_info basic;
142     struct task_events_info events;
143     struct task_thread_times_info thread_times;
144   } task_info_data;
145 
146   kern_return_t result;
147   unsigned int info_count;
148   task_t task;
149 
150   task = get_task_from_args (args);
151   if (task == TASK_NULL)
152     return;
153 
154   printf_unfiltered (_("TASK_BASIC_INFO for 0x%x:\n"), task);
155   info_count = TASK_BASIC_INFO_COUNT;
156   result = task_info (task,
157                       TASK_BASIC_INFO,
158                       (task_info_t) & task_info_data.basic, &info_count);
159   MACH_CHECK_ERROR (result);
160 
161   PRINT_FIELD (&task_info_data.basic, suspend_count);
162   PRINT_FIELD (&task_info_data.basic, virtual_size);
163   PRINT_FIELD (&task_info_data.basic, resident_size);
164   PRINT_TV_FIELD (&task_info_data.basic, user_time);
165   PRINT_TV_FIELD (&task_info_data.basic, system_time);
166   printf_unfiltered (_("\nTASK_EVENTS_INFO:\n"));
167   info_count = TASK_EVENTS_INFO_COUNT;
168   result = task_info (task,
169                       TASK_EVENTS_INFO,
170                       (task_info_t) & task_info_data.events, &info_count);
171   MACH_CHECK_ERROR (result);
172 
173   PRINT_FIELD (&task_info_data.events, faults);
174 #if 0
175   PRINT_FIELD (&task_info_data.events, zero_fills);
176   PRINT_FIELD (&task_info_data.events, reactivations);
177 #endif
178   PRINT_FIELD (&task_info_data.events, pageins);
179   PRINT_FIELD (&task_info_data.events, cow_faults);
180   PRINT_FIELD (&task_info_data.events, messages_sent);
181   PRINT_FIELD (&task_info_data.events, messages_received);
182   printf_unfiltered (_("\nTASK_THREAD_TIMES_INFO:\n"));
183   info_count = TASK_THREAD_TIMES_INFO_COUNT;
184   result = task_info (task,
185                       TASK_THREAD_TIMES_INFO,
186                       (task_info_t) & task_info_data.thread_times,
187                       &info_count);
188   MACH_CHECK_ERROR (result);
189   PRINT_TV_FIELD (&task_info_data.thread_times, user_time);
190   PRINT_TV_FIELD (&task_info_data.thread_times, system_time);
191 }
192 
193 static void
info_mach_ports_command(char * args,int from_tty)194 info_mach_ports_command (char *args, int from_tty)
195 {
196   port_name_array_t names;
197   port_type_array_t types;
198   unsigned int name_count, type_count;
199   kern_return_t result;
200   int index;
201   task_t task;
202 
203   task = get_task_from_args (args);
204   if (task == TASK_NULL)
205     return;
206 
207   result = mach_port_names (task, &names, &name_count, &types, &type_count);
208   MACH_CHECK_ERROR (result);
209 
210   gdb_assert (name_count == type_count);
211 
212   printf_unfiltered (_("Ports for task 0x%x:\n"), task);
213   printf_unfiltered (_("port   type\n"));
214   for (index = 0; index < name_count; ++index)
215     {
216       mach_port_t port = names[index];
217       unsigned int j;
218       struct type_descr
219       {
220 	mach_port_type_t type;
221 	const char *name;
222 	mach_port_right_t right;
223       };
224       static struct type_descr descrs[] =
225 	{
226 	  {MACH_PORT_TYPE_SEND, "send", MACH_PORT_RIGHT_SEND},
227 	  {MACH_PORT_TYPE_SEND_ONCE, "send-once", MACH_PORT_RIGHT_SEND_ONCE},
228 	  {MACH_PORT_TYPE_RECEIVE, "receive", MACH_PORT_RIGHT_RECEIVE},
229 	  {MACH_PORT_TYPE_PORT_SET, "port-set", MACH_PORT_RIGHT_PORT_SET},
230 	  {MACH_PORT_TYPE_DEAD_NAME, "dead", MACH_PORT_RIGHT_DEAD_NAME}
231 	};
232 
233       printf_unfiltered (_("%04x: %08x "), port, types[index]);
234       for (j = 0; j < sizeof(descrs) / sizeof(*descrs); j++)
235 	if (types[index] & descrs[j].type)
236 	  {
237 	    mach_port_urefs_t ref;
238 	    kern_return_t ret;
239 
240 	    printf_unfiltered (_(" %s("), descrs[j].name);
241 	    ret = mach_port_get_refs (task, port, descrs[j].right, &ref);
242 	    if (ret != KERN_SUCCESS)
243 	      printf_unfiltered (_("??"));
244 	    else
245 	      printf_unfiltered (_("%u"), ref);
246 	    printf_unfiltered (_(" refs)"));
247 	  }
248 
249       if (task == task_self ())
250 	{
251 	  if (port == task_self())
252 	    printf_unfiltered (_(" gdb-task"));
253 	  else if (port == darwin_host_self)
254 	    printf_unfiltered (_(" host-self"));
255 	  else if (port == darwin_ex_port)
256 	    printf_unfiltered (_(" gdb-exception"));
257 	  else if (port == darwin_port_set)
258 	    printf_unfiltered (_(" gdb-port_set"));
259 	  else if (!ptid_equal (inferior_ptid, null_ptid))
260 	    {
261 	      struct inferior *inf = current_inferior ();
262 
263 	      if (port == inf->private->task)
264 		printf_unfiltered (_(" inferior-task"));
265 	      else if (port == inf->private->notify_port)
266 		printf_unfiltered (_(" inferior-notify"));
267 	      else
268 		{
269 		  int k;
270 		  darwin_thread_t *t;
271 
272 		  for (k = 0; k < inf->private->exception_info.count; k++)
273 		    if (port == inf->private->exception_info.ports[k])
274 		      {
275 			printf_unfiltered (_(" inferior-excp-port"));
276 			break;
277 		      }
278 
279 		  if (inf->private->threads)
280 		    {
281 		      for (k = 0;
282 			   VEC_iterate(darwin_thread_t,
283 				       inf->private->threads, k, t);
284 			   k++)
285 			if (port == t->gdb_port)
286 			  {
287 			    printf_unfiltered (_(" inferior-thread for 0x%x"),
288 					       inf->private->task);
289 			    break;
290 			  }
291 		    }
292 		}
293 	    }
294 	}
295       printf_unfiltered (_("\n"));
296     }
297 
298   vm_deallocate (task_self (), (vm_address_t) names,
299                  (name_count * sizeof (mach_port_t)));
300   vm_deallocate (task_self (), (vm_address_t) types,
301                  (type_count * sizeof (mach_port_type_t)));
302 }
303 
304 
305 void
darwin_debug_port_info(task_t task,mach_port_t port)306 darwin_debug_port_info (task_t task, mach_port_t port)
307 {
308   kern_return_t kret;
309   mach_port_status_t status;
310   mach_msg_type_number_t len = sizeof (status);
311 
312   kret = mach_port_get_attributes
313     (task, port, MACH_PORT_RECEIVE_STATUS, (mach_port_info_t)&status, &len);
314   MACH_CHECK_ERROR (kret);
315 
316   printf_unfiltered (_("Port 0x%lx in task 0x%lx:\n"), (unsigned long) port,
317                      (unsigned long) task);
318   printf_unfiltered (_("  port set: 0x%x\n"), status.mps_pset);
319   printf_unfiltered (_("     seqno: 0x%x\n"), status.mps_seqno);
320   printf_unfiltered (_("   mscount: 0x%x\n"), status.mps_mscount);
321   printf_unfiltered (_("    qlimit: 0x%x\n"), status.mps_qlimit);
322   printf_unfiltered (_("  msgcount: 0x%x\n"), status.mps_msgcount);
323   printf_unfiltered (_("  sorights: 0x%x\n"), status.mps_sorights);
324   printf_unfiltered (_("   srights: 0x%x\n"), status.mps_srights);
325   printf_unfiltered (_(" pdrequest: 0x%x\n"), status.mps_pdrequest);
326   printf_unfiltered (_(" nsrequest: 0x%x\n"), status.mps_nsrequest);
327   printf_unfiltered (_("     flags: 0x%x\n"), status.mps_flags);
328 }
329 
330 static void
info_mach_port_command(char * args,int from_tty)331 info_mach_port_command (char *args, int from_tty)
332 {
333   task_t task;
334   mach_port_t port;
335 
336   CHECK_ARGS (_("Task and port"), args);
337   sscanf (args, "0x%x 0x%x", &task, &port);
338 
339   darwin_debug_port_info (task, port);
340 }
341 
342 static void
info_mach_threads_command(char * args,int from_tty)343 info_mach_threads_command (char *args, int from_tty)
344 {
345   thread_array_t threads;
346   unsigned int thread_count;
347   kern_return_t result;
348   task_t task;
349   int i;
350 
351   task = get_task_from_args (args);
352   if (task == TASK_NULL)
353     return;
354 
355   result = task_threads (task, &threads, &thread_count);
356   MACH_CHECK_ERROR (result);
357 
358   printf_unfiltered (_("Threads in task %#x:\n"), task);
359   for (i = 0; i < thread_count; ++i)
360     {
361       printf_unfiltered (_("    %#x\n"), threads[i]);
362       mach_port_deallocate (task_self (), threads[i]);
363     }
364 
365   vm_deallocate (task_self (), (vm_address_t) threads,
366                  (thread_count * sizeof (thread_t)));
367 }
368 
369 static void
info_mach_thread_command(char * args,int from_tty)370 info_mach_thread_command (char *args, int from_tty)
371 {
372   union
373   {
374     struct thread_basic_info basic;
375   } thread_info_data;
376 
377   thread_t thread;
378   kern_return_t result;
379   unsigned int info_count;
380 
381   CHECK_ARGS (_("Thread"), args);
382   sscanf (args, "0x%x", &thread);
383 
384   printf_unfiltered (_("THREAD_BASIC_INFO\n"));
385   info_count = THREAD_BASIC_INFO_COUNT;
386   result = thread_info (thread,
387 			THREAD_BASIC_INFO,
388 			(thread_info_t) & thread_info_data.basic,
389 			&info_count);
390   MACH_CHECK_ERROR (result);
391 
392 #if 0
393   PRINT_FIELD (&thread_info_data.basic, user_time);
394   PRINT_FIELD (&thread_info_data.basic, system_time);
395 #endif
396   PRINT_FIELD (&thread_info_data.basic, cpu_usage);
397   PRINT_FIELD (&thread_info_data.basic, run_state);
398   PRINT_FIELD (&thread_info_data.basic, flags);
399   PRINT_FIELD (&thread_info_data.basic, suspend_count);
400   PRINT_FIELD (&thread_info_data.basic, sleep_time);
401 }
402 
403 static const char *
unparse_protection(vm_prot_t p)404 unparse_protection (vm_prot_t p)
405 {
406   switch (p)
407     {
408     case VM_PROT_NONE:
409       return "---";
410     case VM_PROT_READ:
411       return "r--";
412     case VM_PROT_WRITE:
413       return "-w-";
414     case VM_PROT_READ | VM_PROT_WRITE:
415       return "rw-";
416     case VM_PROT_EXECUTE:
417       return "--x";
418     case VM_PROT_EXECUTE | VM_PROT_READ:
419       return "r-x";
420     case VM_PROT_EXECUTE | VM_PROT_WRITE:
421       return "-wx";
422     case VM_PROT_EXECUTE | VM_PROT_WRITE | VM_PROT_READ:
423       return "rwx";
424     default:
425       return "???";
426     }
427 }
428 
429 static const char *
unparse_inheritance(vm_inherit_t i)430 unparse_inheritance (vm_inherit_t i)
431 {
432   switch (i)
433     {
434     case VM_INHERIT_SHARE:
435       return _("share");
436     case VM_INHERIT_COPY:
437       return _("copy ");
438     case VM_INHERIT_NONE:
439       return _("none ");
440     default:
441       return _("???  ");
442     }
443 }
444 
445 static const char *
unparse_share_mode(unsigned char p)446 unparse_share_mode (unsigned char p)
447 {
448   switch (p)
449     {
450     case SM_COW:
451       return _("cow");
452     case SM_PRIVATE:
453       return _("private");
454     case SM_EMPTY:
455       return _("empty");
456     case SM_SHARED:
457       return _("shared");
458     case SM_TRUESHARED:
459       return _("true-shrd");
460     case SM_PRIVATE_ALIASED:
461       return _("prv-alias");
462     case SM_SHARED_ALIASED:
463       return _("shr-alias");
464     default:
465       return _("???");
466     }
467 }
468 
469 static const char *
unparse_user_tag(unsigned int tag)470 unparse_user_tag (unsigned int tag)
471 {
472   switch (tag)
473     {
474     case 0:
475       return _("default");
476     case VM_MEMORY_MALLOC:
477       return _("malloc");
478     case VM_MEMORY_MALLOC_SMALL:
479       return _("malloc_small");
480     case VM_MEMORY_MALLOC_LARGE:
481       return _("malloc_large");
482     case VM_MEMORY_MALLOC_HUGE:
483       return _("malloc_huge");
484     case VM_MEMORY_SBRK:
485       return _("sbrk");
486     case VM_MEMORY_REALLOC:
487       return _("realloc");
488     case VM_MEMORY_MALLOC_TINY:
489       return _("malloc_tiny");
490     case VM_MEMORY_ANALYSIS_TOOL:
491       return _("analysis_tool");
492     case VM_MEMORY_MACH_MSG:
493       return _("mach_msg");
494     case VM_MEMORY_IOKIT:
495       return _("iokit");
496     case VM_MEMORY_STACK:
497       return _("stack");
498     case VM_MEMORY_GUARD:
499       return _("guard");
500     case VM_MEMORY_SHARED_PMAP:
501       return _("shared_pmap");
502     case VM_MEMORY_DYLIB:
503       return _("dylib");
504     case VM_MEMORY_APPKIT:
505       return _("appkit");
506     case VM_MEMORY_FOUNDATION:
507       return _("foundation");
508     default:
509       return NULL;
510     }
511 }
512 
513 static void
darwin_debug_regions(task_t task,mach_vm_address_t address,int max)514 darwin_debug_regions (task_t task, mach_vm_address_t address, int max)
515 {
516   kern_return_t kret;
517   vm_region_basic_info_data_64_t info, prev_info;
518   mach_vm_address_t prev_address;
519   mach_vm_size_t size, prev_size;
520 
521   mach_port_t object_name;
522   mach_msg_type_number_t count;
523 
524   int nsubregions = 0;
525   int num_printed = 0;
526 
527   count = VM_REGION_BASIC_INFO_COUNT_64;
528   kret = mach_vm_region (task, &address, &size, VM_REGION_BASIC_INFO_64,
529 			 (vm_region_info_t) &info, &count, &object_name);
530   if (kret != KERN_SUCCESS)
531     {
532       printf_filtered (_("No memory regions."));
533       return;
534     }
535   memcpy (&prev_info, &info, sizeof (vm_region_basic_info_data_64_t));
536   prev_address = address;
537   prev_size = size;
538   nsubregions = 1;
539 
540   for (;;)
541     {
542       int print = 0;
543       int done = 0;
544 
545       address = prev_address + prev_size;
546 
547       /* Check to see if address space has wrapped around.  */
548       if (address == 0)
549         print = done = 1;
550 
551       if (!done)
552         {
553           count = VM_REGION_BASIC_INFO_COUNT_64;
554           kret =
555             mach_vm_region (task, &address, &size, VM_REGION_BASIC_INFO_64,
556                  	      (vm_region_info_t) &info, &count, &object_name);
557           if (kret != KERN_SUCCESS)
558             {
559               size = 0;
560               print = done = 1;
561             }
562         }
563 
564       if (address != prev_address + prev_size)
565         print = 1;
566 
567       if ((info.protection != prev_info.protection)
568           || (info.max_protection != prev_info.max_protection)
569           || (info.inheritance != prev_info.inheritance)
570           || (info.shared != prev_info.reserved)
571           || (info.reserved != prev_info.reserved))
572         print = 1;
573 
574       if (print)
575         {
576           printf_filtered (_("%s-%s %s/%s  %s %s %s"),
577                            paddress (target_gdbarch, prev_address),
578                            paddress (target_gdbarch, prev_address + prev_size),
579                            unparse_protection (prev_info.protection),
580                            unparse_protection (prev_info.max_protection),
581                            unparse_inheritance (prev_info.inheritance),
582                            prev_info.shared ? _("shrd") : _("priv"),
583                            prev_info.reserved ? _("reserved") : _("not-rsvd"));
584 
585           if (nsubregions > 1)
586             printf_filtered (_(" (%d sub-rgn)"), nsubregions);
587 
588           printf_filtered (_("\n"));
589 
590           prev_address = address;
591           prev_size = size;
592           memcpy (&prev_info, &info, sizeof (vm_region_basic_info_data_64_t));
593           nsubregions = 1;
594 
595           num_printed++;
596         }
597       else
598         {
599           prev_size += size;
600           nsubregions++;
601         }
602 
603       if ((max > 0) && (num_printed >= max))
604         done = 1;
605 
606       if (done)
607         break;
608     }
609 }
610 
611 static void
darwin_debug_regions_recurse(task_t task)612 darwin_debug_regions_recurse (task_t task)
613 {
614   mach_vm_address_t r_addr;
615   mach_vm_address_t r_start;
616   mach_vm_size_t r_size;
617   natural_t r_depth;
618   mach_msg_type_number_t r_info_size;
619   vm_region_submap_short_info_data_64_t r_info;
620   kern_return_t kret;
621   int ret;
622   struct cleanup *table_chain;
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
darwin_debug_region(task_t task,mach_vm_address_t address)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
info_mach_regions_command(char * args,int from_tty)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
info_mach_regions_recurse_command(char * args,int from_tty)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
info_mach_region_command(char * exp,int from_tty)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
disp_exception(const darwin_exception_info * info)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
info_mach_exceptions_command(char * args,int from_tty)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
_initialize_darwin_info_commands(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 }
872