| /* Darwin support for GDB, the GNU debugger. |
| Copyright (C) 1997-2021 Free Software Foundation, Inc. |
| |
| Contributed by Apple Computer, Inc. |
| |
| This file is part of GDB. |
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
| |
| /* The name of the ppc_thread_state structure, and the names of its |
| members, have been changed for Unix conformance reasons. The easiest |
| way to have gdb build on systems with the older names and systems |
| with the newer names is to build this compilation unit with the |
| non-conformant define below. This doesn't seem to cause the resulting |
| binary any problems but it seems like it could cause us problems in |
| the future. It'd be good to remove this at some point when compiling on |
| Tiger is no longer important. */ |
| |
| #include "defs.h" |
| #include "symtab.h" |
| #include "gdbtypes.h" |
| #include "gdbcore.h" |
| #include "value.h" |
| #include "gdbcmd.h" |
| #include "inferior.h" |
| #include "gdbarch.h" |
| |
| #include <sys/sysctl.h> |
| |
| #include "darwin-nat.h" |
| |
| #include <mach/thread_info.h> |
| #include <mach/thread_act.h> |
| #include <mach/task.h> |
| #include <mach/vm_map.h> |
| #include <mach/mach_port.h> |
| #include <mach/mach_init.h> |
| #include <mach/mach_vm.h> |
| |
| #define CHECK_ARGS(what, args) do { \ |
| if ((NULL == args) || ((args[0] != '0') && (args[1] != 'x'))) \ |
| error(_("%s must be specified with 0x..."), what); \ |
| } while (0) |
| |
| #define PRINT_FIELD(structure, field) \ |
| printf_unfiltered(_(#field":\t%#lx\n"), (unsigned long) (structure)->field) |
| |
| #define PRINT_TV_FIELD(structure, field) \ |
| printf_unfiltered(_(#field":\t%u.%06u sec\n"), \ |
| (unsigned) (structure)->field.seconds, \ |
| (unsigned) (structure)->field.microseconds) |
| |
| #define task_self mach_task_self |
| #define task_by_unix_pid task_for_pid |
| #define port_name_array_t mach_port_array_t |
| #define port_type_array_t mach_port_array_t |
| |
| static void |
| info_mach_tasks_command (const char *args, int from_tty) |
| { |
| int sysControl[4]; |
| int count, index; |
| size_t length; |
| struct kinfo_proc *procInfo; |
| |
| sysControl[0] = CTL_KERN; |
| sysControl[1] = KERN_PROC; |
| sysControl[2] = KERN_PROC_ALL; |
| |
| sysctl (sysControl, 3, NULL, &length, NULL, 0); |
| procInfo = (struct kinfo_proc *) xmalloc (length); |
| sysctl (sysControl, 3, procInfo, &length, NULL, 0); |
| |
| count = (length / sizeof (struct kinfo_proc)); |
| printf_unfiltered (_("%d processes:\n"), count); |
| for (index = 0; index < count; ++index) |
| { |
| kern_return_t result; |
| mach_port_t taskPort; |
| |
| result = |
| task_by_unix_pid (mach_task_self (), procInfo[index].kp_proc.p_pid, |
| &taskPort); |
| if (KERN_SUCCESS == result) |
| { |
| printf_unfiltered (_(" %s is %d has task %#x\n"), |
| procInfo[index].kp_proc.p_comm, |
| procInfo[index].kp_proc.p_pid, taskPort); |
| } |
| else |
| { |
| printf_unfiltered (_(" %s is %d unknown task port\n"), |
| procInfo[index].kp_proc.p_comm, |
| procInfo[index].kp_proc.p_pid); |
| } |
| } |
| |
| xfree (procInfo); |
| } |
| |
| static task_t |
| get_task_from_args (const char *args) |
| { |
| task_t task; |
| char *eptr; |
| |
| if (args == NULL || *args == 0) |
| { |
| if (inferior_ptid == null_ptid) |
| printf_unfiltered (_("No inferior running\n")); |
| |
| darwin_inferior *priv = get_darwin_inferior (current_inferior ()); |
| |
| return priv->task; |
| } |
| if (strcmp (args, "gdb") == 0) |
| return mach_task_self (); |
| task = strtoul (args, &eptr, 0); |
| if (*eptr) |
| { |
| printf_unfiltered (_("cannot parse task id '%s'\n"), args); |
| return TASK_NULL; |
| } |
| return task; |
| } |
| |
| static void |
| info_mach_task_command (const char *args, int from_tty) |
| { |
| union |
| { |
| struct task_basic_info basic; |
| struct task_events_info events; |
| struct task_thread_times_info thread_times; |
| } task_info_data; |
| |
| kern_return_t result; |
| unsigned int info_count; |
| task_t task; |
| |
| task = get_task_from_args (args); |
| if (task == TASK_NULL) |
| return; |
| |
| printf_unfiltered (_("TASK_BASIC_INFO for 0x%x:\n"), task); |
| info_count = TASK_BASIC_INFO_COUNT; |
| result = task_info (task, |
| TASK_BASIC_INFO, |
| (task_info_t) & task_info_data.basic, &info_count); |
| MACH_CHECK_ERROR (result); |
| |
| PRINT_FIELD (&task_info_data.basic, suspend_count); |
| PRINT_FIELD (&task_info_data.basic, virtual_size); |
| PRINT_FIELD (&task_info_data.basic, resident_size); |
| PRINT_TV_FIELD (&task_info_data.basic, user_time); |
| PRINT_TV_FIELD (&task_info_data.basic, system_time); |
| printf_unfiltered (_("\nTASK_EVENTS_INFO:\n")); |
| info_count = TASK_EVENTS_INFO_COUNT; |
| result = task_info (task, |
| TASK_EVENTS_INFO, |
| (task_info_t) & task_info_data.events, &info_count); |
| MACH_CHECK_ERROR (result); |
| |
| PRINT_FIELD (&task_info_data.events, faults); |
| #if 0 |
| PRINT_FIELD (&task_info_data.events, zero_fills); |
| PRINT_FIELD (&task_info_data.events, reactivations); |
| #endif |
| PRINT_FIELD (&task_info_data.events, pageins); |
| PRINT_FIELD (&task_info_data.events, cow_faults); |
| PRINT_FIELD (&task_info_data.events, messages_sent); |
| PRINT_FIELD (&task_info_data.events, messages_received); |
| printf_unfiltered (_("\nTASK_THREAD_TIMES_INFO:\n")); |
| info_count = TASK_THREAD_TIMES_INFO_COUNT; |
| result = task_info (task, |
| TASK_THREAD_TIMES_INFO, |
| (task_info_t) & task_info_data.thread_times, |
| &info_count); |
| MACH_CHECK_ERROR (result); |
| PRINT_TV_FIELD (&task_info_data.thread_times, user_time); |
| PRINT_TV_FIELD (&task_info_data.thread_times, system_time); |
| } |
| |
| static void |
| info_mach_ports_command (const char *args, int from_tty) |
| { |
| port_name_array_t names; |
| port_type_array_t types; |
| unsigned int name_count, type_count; |
| kern_return_t result; |
| int index; |
| task_t task; |
| |
| task = get_task_from_args (args); |
| if (task == TASK_NULL) |
| return; |
| |
| result = mach_port_names (task, &names, &name_count, &types, &type_count); |
| MACH_CHECK_ERROR (result); |
| |
| gdb_assert (name_count == type_count); |
| |
| printf_unfiltered (_("Ports for task 0x%x:\n"), task); |
| printf_unfiltered (_("port type\n")); |
| for (index = 0; index < name_count; ++index) |
| { |
| mach_port_t port = names[index]; |
| unsigned int j; |
| struct type_descr |
| { |
| mach_port_type_t type; |
| const char *name; |
| mach_port_right_t right; |
| }; |
| static struct type_descr descrs[] = |
| { |
| {MACH_PORT_TYPE_SEND, "send", MACH_PORT_RIGHT_SEND}, |
| {MACH_PORT_TYPE_SEND_ONCE, "send-once", MACH_PORT_RIGHT_SEND_ONCE}, |
| {MACH_PORT_TYPE_RECEIVE, "receive", MACH_PORT_RIGHT_RECEIVE}, |
| {MACH_PORT_TYPE_PORT_SET, "port-set", MACH_PORT_RIGHT_PORT_SET}, |
| {MACH_PORT_TYPE_DEAD_NAME, "dead", MACH_PORT_RIGHT_DEAD_NAME} |
| }; |
| |
| printf_unfiltered (_("%04x: %08x "), port, types[index]); |
| for (j = 0; j < sizeof(descrs) / sizeof(*descrs); j++) |
| if (types[index] & descrs[j].type) |
| { |
| mach_port_urefs_t ref; |
| kern_return_t ret; |
| |
| printf_unfiltered (_(" %s("), descrs[j].name); |
| ret = mach_port_get_refs (task, port, descrs[j].right, &ref); |
| if (ret != KERN_SUCCESS) |
| printf_unfiltered (_("??")); |
| else |
| printf_unfiltered (_("%u"), ref); |
| printf_unfiltered (_(" refs)")); |
| } |
| |
| if (task == task_self ()) |
| { |
| if (port == task_self()) |
| printf_unfiltered (_(" gdb-task")); |
| else if (port == darwin_host_self) |
| printf_unfiltered (_(" host-self")); |
| else if (port == darwin_ex_port) |
| printf_unfiltered (_(" gdb-exception")); |
| else if (port == darwin_port_set) |
| printf_unfiltered (_(" gdb-port_set")); |
| else if (inferior_ptid != null_ptid) |
| { |
| struct inferior *inf = current_inferior (); |
| darwin_inferior *priv = get_darwin_inferior (inf); |
| |
| if (port == priv->task) |
| printf_unfiltered (_(" inferior-task")); |
| else if (port == priv->notify_port) |
| printf_unfiltered (_(" inferior-notify")); |
| else |
| { |
| for (int k = 0; k < priv->exception_info.count; k++) |
| if (port == priv->exception_info.ports[k]) |
| { |
| printf_unfiltered (_(" inferior-excp-port")); |
| break; |
| } |
| |
| for (darwin_thread_t *t : priv->threads) |
| { |
| if (port == t->gdb_port) |
| { |
| printf_unfiltered (_(" inferior-thread for 0x%x"), |
| priv->task); |
| break; |
| } |
| } |
| |
| } |
| } |
| } |
| printf_unfiltered (_("\n")); |
| } |
| |
| vm_deallocate (task_self (), (vm_address_t) names, |
| (name_count * sizeof (mach_port_t))); |
| vm_deallocate (task_self (), (vm_address_t) types, |
| (type_count * sizeof (mach_port_type_t))); |
| } |
| |
| |
| static void |
| darwin_debug_port_info (task_t task, mach_port_t port) |
| { |
| kern_return_t kret; |
| mach_port_status_t status; |
| mach_msg_type_number_t len = sizeof (status); |
| |
| kret = mach_port_get_attributes |
| (task, port, MACH_PORT_RECEIVE_STATUS, (mach_port_info_t)&status, &len); |
| MACH_CHECK_ERROR (kret); |
| |
| printf_unfiltered (_("Port 0x%lx in task 0x%lx:\n"), (unsigned long) port, |
| (unsigned long) task); |
| printf_unfiltered (_(" port set: 0x%x\n"), status.mps_pset); |
| printf_unfiltered (_(" seqno: 0x%x\n"), status.mps_seqno); |
| printf_unfiltered (_(" mscount: 0x%x\n"), status.mps_mscount); |
| printf_unfiltered (_(" qlimit: 0x%x\n"), status.mps_qlimit); |
| printf_unfiltered (_(" msgcount: 0x%x\n"), status.mps_msgcount); |
| printf_unfiltered (_(" sorights: 0x%x\n"), status.mps_sorights); |
| printf_unfiltered (_(" srights: 0x%x\n"), status.mps_srights); |
| printf_unfiltered (_(" pdrequest: 0x%x\n"), status.mps_pdrequest); |
| printf_unfiltered (_(" nsrequest: 0x%x\n"), status.mps_nsrequest); |
| printf_unfiltered (_(" flags: 0x%x\n"), status.mps_flags); |
| } |
| |
| static void |
| info_mach_port_command (const char *args, int from_tty) |
| { |
| task_t task; |
| mach_port_t port; |
| |
| CHECK_ARGS (_("Task and port"), args); |
| sscanf (args, "0x%x 0x%x", &task, &port); |
| |
| darwin_debug_port_info (task, port); |
| } |
| |
| static void |
| info_mach_threads_command (const char *args, int from_tty) |
| { |
| thread_array_t threads; |
| unsigned int thread_count; |
| kern_return_t result; |
| task_t task; |
| int i; |
| |
| task = get_task_from_args (args); |
| if (task == TASK_NULL) |
| return; |
| |
| result = task_threads (task, &threads, &thread_count); |
| MACH_CHECK_ERROR (result); |
| |
| printf_unfiltered (_("Threads in task %#x:\n"), task); |
| for (i = 0; i < thread_count; ++i) |
| { |
| printf_unfiltered (_(" %#x\n"), threads[i]); |
| mach_port_deallocate (task_self (), threads[i]); |
| } |
| |
| vm_deallocate (task_self (), (vm_address_t) threads, |
| (thread_count * sizeof (thread_t))); |
| } |
| |
| static void |
| info_mach_thread_command (const char *args, int from_tty) |
| { |
| union |
| { |
| struct thread_basic_info basic; |
| } thread_info_data; |
| |
| thread_t thread; |
| kern_return_t result; |
| unsigned int info_count; |
| |
| CHECK_ARGS (_("Thread"), args); |
| sscanf (args, "0x%x", &thread); |
| |
| printf_unfiltered (_("THREAD_BASIC_INFO\n")); |
| info_count = THREAD_BASIC_INFO_COUNT; |
| result = thread_info (thread, |
| THREAD_BASIC_INFO, |
| (thread_info_t) & thread_info_data.basic, |
| &info_count); |
| MACH_CHECK_ERROR (result); |
| |
| #if 0 |
| PRINT_FIELD (&thread_info_data.basic, user_time); |
| PRINT_FIELD (&thread_info_data.basic, system_time); |
| #endif |
| PRINT_FIELD (&thread_info_data.basic, cpu_usage); |
| PRINT_FIELD (&thread_info_data.basic, run_state); |
| PRINT_FIELD (&thread_info_data.basic, flags); |
| PRINT_FIELD (&thread_info_data.basic, suspend_count); |
| PRINT_FIELD (&thread_info_data.basic, sleep_time); |
| } |
| |
| static const char * |
| unparse_protection (vm_prot_t p) |
| { |
| switch (p) |
| { |
| case VM_PROT_NONE: |
| return "---"; |
| case VM_PROT_READ: |
| return "r--"; |
| case VM_PROT_WRITE: |
| return "-w-"; |
| case VM_PROT_READ | VM_PROT_WRITE: |
| return "rw-"; |
| case VM_PROT_EXECUTE: |
| return "--x"; |
| case VM_PROT_EXECUTE | VM_PROT_READ: |
| return "r-x"; |
| case VM_PROT_EXECUTE | VM_PROT_WRITE: |
| return "-wx"; |
| case VM_PROT_EXECUTE | VM_PROT_WRITE | VM_PROT_READ: |
| return "rwx"; |
| default: |
| return "???"; |
| } |
| } |
| |
| static const char * |
| unparse_inheritance (vm_inherit_t i) |
| { |
| switch (i) |
| { |
| case VM_INHERIT_SHARE: |
| return _("share"); |
| case VM_INHERIT_COPY: |
| return _("copy "); |
| case VM_INHERIT_NONE: |
| return _("none "); |
| default: |
| return _("??? "); |
| } |
| } |
| |
| static const char * |
| unparse_share_mode (unsigned char p) |
| { |
| switch (p) |
| { |
| case SM_COW: |
| return _("cow"); |
| case SM_PRIVATE: |
| return _("private"); |
| case SM_EMPTY: |
| return _("empty"); |
| case SM_SHARED: |
| return _("shared"); |
| case SM_TRUESHARED: |
| return _("true-shrd"); |
| case SM_PRIVATE_ALIASED: |
| return _("prv-alias"); |
| case SM_SHARED_ALIASED: |
| return _("shr-alias"); |
| default: |
| return _("???"); |
| } |
| } |
| |
| static const char * |
| unparse_user_tag (unsigned int tag) |
| { |
| switch (tag) |
| { |
| case 0: |
| return _("default"); |
| case VM_MEMORY_MALLOC: |
| return _("malloc"); |
| case VM_MEMORY_MALLOC_SMALL: |
| return _("malloc_small"); |
| case VM_MEMORY_MALLOC_LARGE: |
| return _("malloc_large"); |
| case VM_MEMORY_MALLOC_HUGE: |
| return _("malloc_huge"); |
| case VM_MEMORY_SBRK: |
| return _("sbrk"); |
| case VM_MEMORY_REALLOC: |
| return _("realloc"); |
| case VM_MEMORY_MALLOC_TINY: |
| return _("malloc_tiny"); |
| case VM_MEMORY_ANALYSIS_TOOL: |
| return _("analysis_tool"); |
| case VM_MEMORY_MACH_MSG: |
| return _("mach_msg"); |
| case VM_MEMORY_IOKIT: |
| return _("iokit"); |
| case VM_MEMORY_STACK: |
| return _("stack"); |
| case VM_MEMORY_GUARD: |
| return _("guard"); |
| case VM_MEMORY_SHARED_PMAP: |
| return _("shared_pmap"); |
| case VM_MEMORY_DYLIB: |
| return _("dylib"); |
| case VM_MEMORY_APPKIT: |
| return _("appkit"); |
| case VM_MEMORY_FOUNDATION: |
| return _("foundation"); |
| default: |
| return NULL; |
| } |
| } |
| |
| static void |
| darwin_debug_regions (task_t task, mach_vm_address_t address, int max) |
| { |
| kern_return_t kret; |
| vm_region_basic_info_data_64_t info, prev_info; |
| mach_vm_address_t prev_address; |
| mach_vm_size_t size, prev_size; |
| |
| mach_port_t object_name; |
| mach_msg_type_number_t count; |
| |
| int nsubregions = 0; |
| int num_printed = 0; |
| |
| count = VM_REGION_BASIC_INFO_COUNT_64; |
| kret = mach_vm_region (task, &address, &size, VM_REGION_BASIC_INFO_64, |
| (vm_region_info_t) &info, &count, &object_name); |
| if (kret != KERN_SUCCESS) |
| { |
| printf_filtered (_("No memory regions.")); |
| return; |
| } |
| memcpy (&prev_info, &info, sizeof (vm_region_basic_info_data_64_t)); |
| prev_address = address; |
| prev_size = size; |
| nsubregions = 1; |
| |
| for (;;) |
| { |
| int print = 0; |
| int done = 0; |
| |
| address = prev_address + prev_size; |
| |
| /* Check to see if address space has wrapped around. */ |
| if (address == 0) |
| print = done = 1; |
| |
| if (!done) |
| { |
| count = VM_REGION_BASIC_INFO_COUNT_64; |
| kret = |
| mach_vm_region (task, &address, &size, VM_REGION_BASIC_INFO_64, |
| (vm_region_info_t) &info, &count, &object_name); |
| if (kret != KERN_SUCCESS) |
| { |
| size = 0; |
| print = done = 1; |
| } |
| } |
| |
| if (address != prev_address + prev_size) |
| print = 1; |
| |
| if ((info.protection != prev_info.protection) |
| || (info.max_protection != prev_info.max_protection) |
| || (info.inheritance != prev_info.inheritance) |
| || (info.shared != prev_info.reserved) |
| || (info.reserved != prev_info.reserved)) |
| print = 1; |
| |
| if (print) |
| { |
| printf_filtered (_("%s-%s %s/%s %s %s %s"), |
| paddress (target_gdbarch (), prev_address), |
| paddress (target_gdbarch (), prev_address + prev_size), |
| unparse_protection (prev_info.protection), |
| unparse_protection (prev_info.max_protection), |
| unparse_inheritance (prev_info.inheritance), |
| prev_info.shared ? _("shrd") : _("priv"), |
| prev_info.reserved ? _("reserved") : _("not-rsvd")); |
| |
| if (nsubregions > 1) |
| printf_filtered (_(" (%d sub-rgn)"), nsubregions); |
| |
| printf_filtered (_("\n")); |
| |
| prev_address = address; |
| prev_size = size; |
| memcpy (&prev_info, &info, sizeof (vm_region_basic_info_data_64_t)); |
| nsubregions = 1; |
| |
| num_printed++; |
| } |
| else |
| { |
| prev_size += size; |
| nsubregions++; |
| } |
| |
| if ((max > 0) && (num_printed >= max)) |
| done = 1; |
| |
| if (done) |
| break; |
| } |
| } |
| |
| static void |
| darwin_debug_regions_recurse (task_t task) |
| { |
| mach_vm_address_t r_start; |
| mach_vm_size_t r_size; |
| natural_t r_depth; |
| mach_msg_type_number_t r_info_size; |
| vm_region_submap_short_info_data_64_t r_info; |
| kern_return_t kret; |
| struct ui_out *uiout = current_uiout; |
| |
| ui_out_emit_table table_emitter (uiout, 9, -1, "regions"); |
| |
| if (gdbarch_addr_bit (target_gdbarch ()) <= 32) |
| { |
| uiout->table_header (10, ui_left, "start", "Start"); |
| uiout->table_header (10, ui_left, "end", "End"); |
| } |
| else |
| { |
| uiout->table_header (18, ui_left, "start", "Start"); |
| uiout->table_header (18, ui_left, "end", "End"); |
| } |
| uiout->table_header (3, ui_left, "min-prot", "Min"); |
| uiout->table_header (3, ui_left, "max-prot", "Max"); |
| uiout->table_header (5, ui_left, "inheritence", "Inh"); |
| uiout->table_header (9, ui_left, "share-mode", "Shr"); |
| uiout->table_header (1, ui_left, "depth", "D"); |
| uiout->table_header (3, ui_left, "submap", "Sm"); |
| uiout->table_header (0, ui_noalign, "tag", "Tag"); |
| |
| uiout->table_body (); |
| |
| r_start = 0; |
| r_depth = 0; |
| while (1) |
| { |
| const char *tag; |
| |
| r_info_size = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64; |
| r_size = -1; |
| kret = mach_vm_region_recurse (task, &r_start, &r_size, &r_depth, |
| (vm_region_recurse_info_t) &r_info, |
| &r_info_size); |
| if (kret != KERN_SUCCESS) |
| break; |
| |
| { |
| ui_out_emit_tuple tuple_emitter (uiout, "regions-row"); |
| |
| uiout->field_core_addr ("start", target_gdbarch (), r_start); |
| uiout->field_core_addr ("end", target_gdbarch (), r_start + r_size); |
| uiout->field_string ("min-prot", |
| unparse_protection (r_info.protection)); |
| uiout->field_string ("max-prot", |
| unparse_protection (r_info.max_protection)); |
| uiout->field_string ("inheritence", |
| unparse_inheritance (r_info.inheritance)); |
| uiout->field_string ("share-mode", |
| unparse_share_mode (r_info.share_mode)); |
| uiout->field_signed ("depth", r_depth); |
| uiout->field_string ("submap", |
| r_info.is_submap ? _("sm ") : _("obj")); |
| tag = unparse_user_tag (r_info.user_tag); |
| if (tag) |
| uiout->field_string ("tag", tag); |
| else |
| uiout->field_signed ("tag", r_info.user_tag); |
| } |
| |
| uiout->text ("\n"); |
| |
| if (r_info.is_submap) |
| r_depth++; |
| else |
| r_start += r_size; |
| } |
| } |
| |
| |
| static void |
| darwin_debug_region (task_t task, mach_vm_address_t address) |
| { |
| darwin_debug_regions (task, address, 1); |
| } |
| |
| static void |
| info_mach_regions_command (const char *args, int from_tty) |
| { |
| task_t task; |
| |
| task = get_task_from_args (args); |
| if (task == TASK_NULL) |
| return; |
| |
| darwin_debug_regions (task, 0, -1); |
| } |
| |
| static void |
| info_mach_regions_recurse_command (const char *args, int from_tty) |
| { |
| task_t task; |
| |
| task = get_task_from_args (args); |
| if (task == TASK_NULL) |
| return; |
| |
| darwin_debug_regions_recurse (task); |
| } |
| |
| static void |
| info_mach_region_command (const char *exp, int from_tty) |
| { |
| struct value *val; |
| mach_vm_address_t address; |
| struct inferior *inf; |
| |
| expression_up expr = parse_expression (exp); |
| val = evaluate_expression (expr.get ()); |
| if (TYPE_IS_REFERENCE (value_type (val))) |
| { |
| val = value_ind (val); |
| } |
| address = value_as_address (val); |
| |
| if (inferior_ptid == null_ptid) |
| error (_("Inferior not available")); |
| |
| inf = current_inferior (); |
| darwin_inferior *priv = get_darwin_inferior (inf); |
| darwin_debug_region (priv->task, address); |
| } |
| |
| static void |
| disp_exception (const darwin_exception_info *info) |
| { |
| int i; |
| |
| printf_filtered (_("%d exceptions:\n"), info->count); |
| for (i = 0; i < info->count; i++) |
| { |
| exception_mask_t mask = info->masks[i]; |
| |
| printf_filtered (_("port 0x%04x, behavior: "), info->ports[i]); |
| switch (info->behaviors[i]) |
| { |
| case EXCEPTION_DEFAULT: |
| printf_unfiltered (_("default")); |
| break; |
| case EXCEPTION_STATE: |
| printf_unfiltered (_("state")); |
| break; |
| case EXCEPTION_STATE_IDENTITY: |
| printf_unfiltered (_("state-identity")); |
| break; |
| default: |
| printf_unfiltered (_("0x%x"), info->behaviors[i]); |
| } |
| printf_unfiltered (_(", masks:")); |
| if (mask & EXC_MASK_BAD_ACCESS) |
| printf_unfiltered (_(" BAD_ACCESS")); |
| if (mask & EXC_MASK_BAD_INSTRUCTION) |
| printf_unfiltered (_(" BAD_INSTRUCTION")); |
| if (mask & EXC_MASK_ARITHMETIC) |
| printf_unfiltered (_(" ARITHMETIC")); |
| if (mask & EXC_MASK_EMULATION) |
| printf_unfiltered (_(" EMULATION")); |
| if (mask & EXC_MASK_SOFTWARE) |
| printf_unfiltered (_(" SOFTWARE")); |
| if (mask & EXC_MASK_BREAKPOINT) |
| printf_unfiltered (_(" BREAKPOINT")); |
| if (mask & EXC_MASK_SYSCALL) |
| printf_unfiltered (_(" SYSCALL")); |
| if (mask & EXC_MASK_MACH_SYSCALL) |
| printf_unfiltered (_(" MACH_SYSCALL")); |
| if (mask & EXC_MASK_RPC_ALERT) |
| printf_unfiltered (_(" RPC_ALERT")); |
| if (mask & EXC_MASK_CRASH) |
| printf_unfiltered (_(" CRASH")); |
| printf_unfiltered (_("\n")); |
| } |
| } |
| |
| static void |
| info_mach_exceptions_command (const char *args, int from_tty) |
| { |
| kern_return_t kret; |
| darwin_exception_info info; |
| |
| info.count = sizeof (info.ports) / sizeof (info.ports[0]); |
| |
| if (args != NULL) |
| { |
| if (strcmp (args, "saved") == 0) |
| { |
| if (inferior_ptid == null_ptid) |
| printf_unfiltered (_("No inferior running\n")); |
| |
| darwin_inferior *priv = get_darwin_inferior (current_inferior ()); |
| |
| disp_exception (&priv->exception_info); |
| return; |
| } |
| else if (strcmp (args, "host") == 0) |
| { |
| /* FIXME: This needs a privileged host port! */ |
| kret = host_get_exception_ports |
| (darwin_host_self, EXC_MASK_ALL, info.masks, |
| &info.count, info.ports, info.behaviors, info.flavors); |
| MACH_CHECK_ERROR (kret); |
| disp_exception (&info); |
| } |
| else |
| error (_("Parameter is saved, host or none")); |
| } |
| else |
| { |
| struct inferior *inf; |
| |
| if (inferior_ptid == null_ptid) |
| printf_unfiltered (_("No inferior running\n")); |
| inf = current_inferior (); |
| |
| darwin_inferior *priv = get_darwin_inferior (inf); |
| |
| kret = task_get_exception_ports |
| (priv->task, EXC_MASK_ALL, info.masks, |
| &info.count, info.ports, info.behaviors, info.flavors); |
| MACH_CHECK_ERROR (kret); |
| disp_exception (&info); |
| } |
| } |
| |
| void _initialize_darwin_info_commands (); |
| void |
| _initialize_darwin_info_commands () |
| { |
| add_info ("mach-tasks", info_mach_tasks_command, |
| _("Get list of tasks in system.")); |
| add_info ("mach-ports", info_mach_ports_command, |
| _("Get list of ports in a task.")); |
| add_info ("mach-port", info_mach_port_command, |
| _("Get info on a specific port.")); |
| add_info ("mach-task", info_mach_task_command, |
| _("Get info on a specific task.")); |
| add_info ("mach-threads", info_mach_threads_command, |
| _("Get list of threads in a task.")); |
| add_info ("mach-thread", info_mach_thread_command, |
| _("Get info on a specific thread.")); |
| |
| add_info ("mach-regions", info_mach_regions_command, |
| _("Get information on all mach region for the task.")); |
| add_info ("mach-regions-rec", info_mach_regions_recurse_command, |
| _("Get information on all mach sub region for the task.")); |
| add_info ("mach-region", info_mach_region_command, |
| _("Get information on mach region at given address.")); |
| |
| add_info ("mach-exceptions", info_mach_exceptions_command, |
| _("Disp mach exceptions.")); |
| } |