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