2008-11-27  Tristan Gingold  <gingold@adacore.com>

	* NEWS: Add entry for new native configuration: Darwin.
	* configure.host: Add Darwin host.
	* configure.tgt: Add Darwin target.
	* defs.h (enum gdb_osabi): Add GDB_OSABI_DARWIN.
	* osabi.c (gdb_osabi_names): Add name for Darwin abi.
	* i386-darwin-nat.c: New file.
	* i386-darwin-tdep.c: New file.
	* machoread.c: New file.
	* darwin-nat-info.c: New file.
	* darwin-nat.c: New file.
	* darwin-nat.h: New file.
	* darwin.defs: New file.
	* config/i386/darwin.mh: New file.

gdb/doc:
2008-11-27  Tristan Gingold  <gingold@adacore.com>

	* gdb.texinfo (Darwin): Document Darwin specific features.
This commit is contained in:
Tristan Gingold 2008-11-27 09:23:01 +00:00
parent 6c7c4ca467
commit a80b95ba67
17 changed files with 3731 additions and 0 deletions

View File

@ -1,3 +1,19 @@
2008-11-27 Tristan Gingold <gingold@adacore.com>
* NEWS: Add entry for new native configuration: Darwin.
* configure.host: Add Darwin host.
* configure.tgt: Add Darwin target.
* defs.h (enum gdb_osabi): Add GDB_OSABI_DARWIN.
* osabi.c (gdb_osabi_names): Add name for Darwin abi.
* i386-darwin-nat.c: New file.
* i386-darwin-tdep.c: New file.
* machoread.c: New file.
* darwin-nat-info.c: New file.
* darwin-nat.c: New file.
* darwin-nat.h: New file.
* darwin.defs: New file.
* config/i386/darwin.mh: New file.
2008-11-26 Tristan Gingold <gingold@adacore.com>
* MAINTAINERS: Add myself for write after approval privileges.

View File

@ -172,6 +172,10 @@ macro undef
These allow macros to be defined, undefined, and listed
interactively.
* New native configurations
x86/x86_64 Darwin i[34567]86-*-darwin*
* New targets
x86 DICOS i[34567]86-*-dicos*

10
gdb/config/i386/darwin.mh Normal file
View File

@ -0,0 +1,10 @@
# Host: IA86 running Darwin
NATDEPFILES = fork-child.o machoread.o darwin-nat.o excServer.o \
i386-darwin-nat.o i386-nat.o amd64-nat.o darwin-nat-info.o
# Trick so that excServer.c is not the default target!
_all: all
excServer.c: darwin.defs
/usr/bin/mig -I. $<

View File

@ -62,6 +62,8 @@ esac
case "${host}" in
*-*-darwin*) gdb_host=darwin ;;
alpha*-*-osf[3456789]*) gdb_host=alpha-osf3 ;;
alpha*-*-linux*) gdb_host=alpha-linux ;;
alpha*-*-freebsd* | alpha*-*-kfreebsd*-gnu)

View File

@ -145,6 +145,11 @@ hppa*-*-*)
gdb_target_obs="hppa-tdep.o"
;;
i[34567]86-*-darwin*)
# Target: Darwin/i386
gdb_target_obs="amd64-tdep.o i386-tdep.o i387-tdep.o \
i386-darwin-tdep.o"
;;
i[34567]86-*-dicos*)
# Target: DICOS/i386
gdb_target_obs="i386-tdep.o i387-tdep.o \

847
gdb/darwin-nat-info.c Normal file
View File

@ -0,0 +1,847 @@
/* Darwin support for GDB, the GNU debugger.
Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2008
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 2 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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* 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 <sys/param.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 (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 (char *args)
{
task_t task;
char *eptr;
if (args == NULL || *args == 0)
{
if (darwin_inf->task == TASK_NULL)
printf_unfiltered (_("No inferior running\n"));
return darwin_inf->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 (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 (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_not_port)
printf_unfiltered (_(" gdb-notifier"));
else if (port == darwin_ex_port)
printf_unfiltered (_(" gdb-exception"));
else if (port == darwin_port_set)
printf_unfiltered (_(" gdb-port_set"));
else if (darwin_inf && port == darwin_inf->task)
printf_unfiltered (_(" inferior-task"));
else if (darwin_inf && darwin_inf->threads)
{
int k;
thread_t t;
for (k = 0; VEC_iterate(thread_t, darwin_inf->threads, k, t); k++)
if (port == t)
{
printf_unfiltered (_(" inferior-thread for 0x%x"),
darwin_inf->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)));
}
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 (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 (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 (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"),
paddr(prev_address),
paddr(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_addr;
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;
int ret;
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;
printf_filtered (_("%s-%s %s/%s %-5s %-10s %2d %s"),
paddr(r_start),
paddr(r_start + r_size),
unparse_protection (r_info.protection),
unparse_protection (r_info.max_protection),
unparse_inheritance (r_info.inheritance),
unparse_share_mode (r_info.share_mode),
r_depth,
r_info.is_submap ? _("sm ") : _("obj"));
tag = unparse_user_tag (r_info.user_tag);
if (tag)
printf_unfiltered (_(" %s\n"), tag);
else
printf_unfiltered (_(" %u\n"), r_info.user_tag);
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 (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 (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 (char *exp, int from_tty)
{
struct expression *expr;
struct value *val;
mach_vm_address_t address;
expr = parse_expression (exp);
val = evaluate_expression (expr);
if (TYPE_CODE (value_type (val)) == TYPE_CODE_REF)
{
val = value_ind (val);
}
/* In rvalue contexts, such as this, functions are coerced into
pointers to functions. */
if (TYPE_CODE (value_type (val)) == TYPE_CODE_FUNC
&& VALUE_LVAL (val) == lval_memory)
{
address = VALUE_ADDRESS (val);
}
else
{
address = value_as_address (val);
}
if ((!darwin_inf) || (darwin_inf->task == TASK_NULL))
error (_("Inferior not available"));
darwin_debug_region (darwin_inf->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 (char *args, int from_tty)
{
int i;
task_t task;
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 (darwin_inf->task == TASK_NULL)
error (_("No inferior running\n"));
disp_exception (&darwin_inf->exception_info);
return;
}
else if (strcmp (args, "host") == 0)
{
/* FIXME: This need a the privilegied 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
{
if (darwin_inf->task == TASK_NULL)
error (_("No inferior running\n"));
kret = task_get_exception_ports
(darwin_inf->task, EXC_MASK_ALL, info.masks,
&info.count, info.ports, info.behaviors, info.flavors);
MACH_CHECK_ERROR (kret);
disp_exception (&info);
}
}
static void
darwin_list_gdb_ports (const char *msg)
{
mach_port_name_array_t names;
mach_port_type_array_t types;
unsigned int name_count, type_count;
kern_return_t result;
int i;
result = mach_port_names (mach_task_self (),
&names, &name_count, &types, &type_count);
MACH_CHECK_ERROR (result);
gdb_assert (name_count == type_count);
printf_unfiltered (_("Ports for %s:"), msg);
for (i = 0; i < name_count; ++i)
printf_unfiltered (_(" 0x%04x"), names[i]);
printf_unfiltered (_("\n"));
vm_deallocate (mach_task_self (), (vm_address_t) names,
(name_count * sizeof (mach_port_t)));
vm_deallocate (mach_task_self (), (vm_address_t) types,
(type_count * sizeof (mach_port_type_t)));
}
void
_initialize_darwin_info_commands (void)
{
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."));
}

1307
gdb/darwin-nat.c Normal file

File diff suppressed because it is too large Load Diff

107
gdb/darwin-nat.h Normal file
View File

@ -0,0 +1,107 @@
/* Common things used by the various darwin files
Copyright (C) 1995, 1996, 1997, 1999, 2000, 2007, 2008
Free Software Foundation, Inc.
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/>.
*/
#ifndef __DARWIN_NAT_H__
#define __DARWIN_NAT_H__
#include <mach/mach.h>
#include "gdb_assert.h"
/* Define the threads vector type. */
DEF_VEC_I (thread_t);
/* Describe the mach exception handling state for a task. This state is saved
before being changed and restored when a process is detached.
For more information on these fields see task_get_exception_ports manual
page. */
struct darwin_exception_info
{
/* Exceptions handled by the port. */
exception_mask_t masks[EXC_TYPES_COUNT];
/* Ports receiving exception messages. */
mach_port_t ports[EXC_TYPES_COUNT];
/* Type of messages sent. */
exception_behavior_t behaviors[EXC_TYPES_COUNT];
/* Type of state to be sent. */
thread_state_flavor_t flavors[EXC_TYPES_COUNT];
/* Number of elements set. */
mach_msg_type_number_t count;
};
typedef struct darwin_exception_info darwin_exception_info;
/* Describe an inferior. */
struct darwin_inferior
{
/* Inferior PID. */
int pid;
/* Corresponding task port. */
task_t task;
/* Previous port for request notification on task. */
mach_port_t prev_not_port;
/* Initial exception handling. */
darwin_exception_info exception_info;
/* Sorted vector of known threads. */
VEC(thread_t) *threads;
};
typedef struct darwin_inferior darwin_inferior;
/* Current inferior. */
extern darwin_inferior *darwin_inf;
/* Exception port. */
extern mach_port_t darwin_ex_port;
/* Notification port. */
extern mach_port_t darwin_not_port;
/* Port set. */
extern mach_port_t darwin_port_set;
/* A copy of mach_host_self (). */
extern mach_port_t darwin_host_self;
/* ASSERT_FUNCTION is defined in gdb_assert.h (or not). */
#ifdef ASSERT_FUNCTION
#define MACH_CHECK_ERROR(ret) \
mach_check_error (ret, __FILE__, __LINE__, ASSERT_FUNCTION)
#else
#define MACH_CHECK_ERROR(ret) \
mach_check_error (ret, __FILE__, __LINE__, "??")
#endif
extern void mach_check_error (kern_return_t ret, const char *file,
unsigned int line, const char *func);
void darwin_set_sstep (thread_t thread, int enable);
/* This one is called in darwin-nat.c, but needs to be provided by the
platform specific nat code. It allows each platform to add platform specific
stuff to the darwin_ops. */
extern void darwin_complete_target (struct target_ops *target);
void darwin_check_osabi (darwin_inferior *inf, thread_t thread);
#endif /* __DARWIN_NAT_H__ */

6
gdb/darwin.defs Normal file
View File

@ -0,0 +1,6 @@
#include "config.h"
#ifdef HAVE_64_BIT_MACH_EXCEPTIONS
#import <mach/mach_exc.defs>
#else
#import <mach/exc.defs>
#endif

View File

@ -957,6 +957,7 @@ enum gdb_osabi
GDB_OSABI_CYGWIN,
GDB_OSABI_AIX,
GDB_OSABI_DICOS,
GDB_OSABI_DARWIN,
GDB_OSABI_INVALID /* keep this last */
};

View File

@ -1,3 +1,7 @@
2008-11-27 Tristan Gingold <gingold@adacore.com>
* gdb.texinfo (Darwin): Document Darwin specific features.
2008-11-25 Jan Kratochvil <jan.kratochvil@redhat.com>
* gdbint.texinfo (Target Conditionals): Extend the

View File

@ -14675,6 +14675,7 @@ configurations.
* Cygwin Native:: Features specific to the Cygwin port
* Hurd Native:: Features specific to @sc{gnu} Hurd
* Neutrino:: Features specific to QNX Neutrino
* Darwin:: Features specific to Darwin
@end menu
@node HP-UX
@ -15456,6 +15457,48 @@ Neutrino support.
Show the current state of QNX Neutrino messages.
@end table
@node Darwin
@subsection Darwin
@cindex Darwin
@value{GDBN} provides the following commands specific to the Darwin target:
@table @code
@item set debug darwin @var{num}
@kindex set debug darwin
When set to a non zero value, enables debugging messages specific to
the Darwin support. Higher values produce more verbose output.
@item show debug darwin
@kindex show debug darwin
Show the current state of Darwin messages.
@item set debug mach-o @var{num}
@kindex set debug mach-o
When set to a non zero value, enables debugging messages while
@value{GDBN} is reading Darwin object files. (@dfn{Mach-O} is the
file format used on Darwin for object and executable files.) Higher
values produce more verbose output. This is a command to diagnose
problems internal to @value{GDBN} and should not be needed in normal
usage.
@item show debug mach-o
@kindex show debug mach-o
Show the current state of Mach-O file messages.
@item set mach-exceptions on
@itemx set mach-exceptions off
@kindex set mach-exceptions
On Darwin, faults are first reported as a Mach exception and are then
mapped to a Posix signal. Use this command to turn on trapping of
Mach exceptions in the inferior. This might be sometimes useful to
better understand the cause of a fault. The default is off.
@item show mach-exceptions
@kindex show mach-exceptions
Show the current state of exceptions trapping.
@end table
@node Embedded OS
@section Embedded Operating Systems

492
gdb/i386-darwin-nat.c Normal file
View File

@ -0,0 +1,492 @@
/* Darwin support for GDB, the GNU debugger.
Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2008
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/>. */
#include "defs.h"
#include "frame.h"
#include "inferior.h"
#include "target.h"
#include "symfile.h"
#include "symtab.h"
#include "objfiles.h"
#include "gdbcmd.h"
#include "regcache.h"
#include "gdb_assert.h"
#include "i386-tdep.h"
#include "amd64-nat.h"
#include "i387-tdep.h"
#include "gdbarch.h"
#include "arch-utils.h"
#include "darwin-nat.h"
#include "i386-darwin-tdep.h"
/* Read register values from the inferior process.
If REGNO is -1, do this for all registers.
Otherwise, REGNO specifies which register (so we can save time). */
static void
i386_darwin_fetch_inferior_registers (struct regcache *regcache, int regno)
{
thread_t current_thread = ptid_get_tid (inferior_ptid);
int fetched = 0;
struct gdbarch *gdbarch = get_regcache_arch (regcache);
if (gdbarch_ptr_bit (gdbarch) == 64)
{
if (regno == -1 || amd64_native_gregset_supplies_p (gdbarch, regno))
{
x86_thread_state_t gp_regs;
unsigned int gp_count = x86_THREAD_STATE_COUNT;
kern_return_t ret;
ret = thread_get_state
(current_thread, x86_THREAD_STATE, (thread_state_t) & gp_regs,
&gp_count);
if (ret != KERN_SUCCESS)
{
printf_unfiltered (_("Error calling thread_get_state for GP registers for thread 0x%ulx"), current_thread);
MACH_CHECK_ERROR (ret);
}
amd64_supply_native_gregset (regcache, &gp_regs.uts, -1);
fetched++;
}
if (regno == -1 || !amd64_native_gregset_supplies_p (gdbarch, regno))
{
x86_float_state_t fp_regs;
unsigned int fp_count = x86_FLOAT_STATE_COUNT;
kern_return_t ret;
ret = thread_get_state
(current_thread, x86_FLOAT_STATE, (thread_state_t) & fp_regs,
&fp_count);
if (ret != KERN_SUCCESS)
{
printf_unfiltered (_("Error calling thread_get_state for float registers for thread 0x%ulx"), current_thread);
MACH_CHECK_ERROR (ret);
}
i387_supply_fxsave (regcache, -1, &fp_regs.ufs.fs64);
fetched++;
}
}
else
{
if (regno == -1 || regno < I386_NUM_GREGS)
{
i386_thread_state_t gp_regs;
unsigned int gp_count = i386_THREAD_STATE_COUNT;
kern_return_t ret;
int i;
ret = thread_get_state
(current_thread, i386_THREAD_STATE, (thread_state_t) & gp_regs,
&gp_count);
if (ret != KERN_SUCCESS)
{
printf_unfiltered (_("Error calling thread_get_state for GP registers for thread 0x%ulx"), current_thread);
MACH_CHECK_ERROR (ret);
}
for (i = 0; i < I386_NUM_GREGS; i++)
regcache_raw_supply
(regcache, i,
(char *)&gp_regs + i386_darwin_thread_state_reg_offset[i]);
fetched++;
}
if (regno == -1
|| (regno >= I386_ST0_REGNUM && regno < I386_SSE_NUM_REGS))
{
i386_float_state_t fp_regs;
unsigned int fp_count = i386_FLOAT_STATE_COUNT;
kern_return_t ret;
ret = thread_get_state
(current_thread, i386_FLOAT_STATE, (thread_state_t) & fp_regs,
&fp_count);
if (ret != KERN_SUCCESS)
{
printf_unfiltered (_("Error calling thread_get_state for float registers for thread 0x%ulx"), current_thread);
MACH_CHECK_ERROR (ret);
}
i387_supply_fxsave (regcache, -1, &fp_regs.__fpu_fcw);
fetched++;
}
}
if (! fetched)
{
warning (_("unknown register %d"), regno);
regcache_raw_supply (regcache, regno, NULL);
}
}
/* Store our register values back into the inferior.
If REGNO is -1, do this for all registers.
Otherwise, REGNO specifies which register (so we can save time). */
static void
i386_darwin_store_inferior_registers (struct regcache *regcache, int regno)
{
thread_t current_thread = ptid_get_tid (inferior_ptid);
struct gdbarch *gdbarch = get_regcache_arch (regcache);
if (gdbarch_ptr_bit (gdbarch) == 64)
{
if (regno == -1 || amd64_native_gregset_supplies_p (gdbarch, regno))
{
x86_thread_state_t gp_regs;
kern_return_t ret;
unsigned int gp_count = x86_THREAD_STATE_COUNT;
ret = thread_get_state
(current_thread, x86_THREAD_STATE, (thread_state_t) &gp_regs,
&gp_count);
MACH_CHECK_ERROR (ret);
gdb_assert (gp_regs.tsh.flavor == x86_THREAD_STATE64);
gdb_assert (gp_regs.tsh.count == x86_THREAD_STATE64_COUNT);
amd64_collect_native_gregset (regcache, &gp_regs.uts, regno);
ret = thread_set_state (current_thread, x86_THREAD_STATE,
(thread_state_t) &gp_regs,
x86_THREAD_STATE_COUNT);
MACH_CHECK_ERROR (ret);
}
if (regno == -1 || !amd64_native_gregset_supplies_p (gdbarch, regno))
{
x86_float_state_t fp_regs;
kern_return_t ret;
unsigned int fp_count = x86_FLOAT_STATE_COUNT;
ret = thread_get_state
(current_thread, x86_FLOAT_STATE, (thread_state_t) & fp_regs,
&fp_count);
MACH_CHECK_ERROR (ret);
gdb_assert (fp_regs.fsh.flavor == x86_FLOAT_STATE64);
gdb_assert (fp_regs.fsh.count == x86_FLOAT_STATE64_COUNT);
i387_collect_fxsave (regcache, regno, &fp_regs.ufs.fs64.__fpu_fcw);
ret = thread_set_state (current_thread, x86_FLOAT_STATE,
(thread_state_t) & fp_regs,
x86_FLOAT_STATE_COUNT);
MACH_CHECK_ERROR (ret);
}
}
else
{
if (regno == -1 || regno < I386_NUM_GREGS)
{
i386_thread_state_t gp_regs;
kern_return_t ret;
unsigned int gp_count = i386_THREAD_STATE_COUNT;
int i;
ret = thread_get_state
(current_thread, i386_THREAD_STATE, (thread_state_t) & gp_regs,
&gp_count);
MACH_CHECK_ERROR (ret);
for (i = 0; i < I386_NUM_GREGS; i++)
if (regno == -1 || regno == i)
regcache_raw_collect
(regcache, i,
(char *)&gp_regs + i386_darwin_thread_state_reg_offset[i]);
ret = thread_set_state (current_thread, i386_THREAD_STATE,
(thread_state_t) & gp_regs,
i386_THREAD_STATE_COUNT);
MACH_CHECK_ERROR (ret);
}
if (regno == -1
|| (regno >= I386_ST0_REGNUM && regno < I386_SSE_NUM_REGS))
{
i386_float_state_t fp_regs;
unsigned int fp_count = i386_FLOAT_STATE_COUNT;
kern_return_t ret;
ret = thread_get_state
(current_thread, i386_FLOAT_STATE, (thread_state_t) & fp_regs,
&fp_count);
MACH_CHECK_ERROR (ret);
i387_collect_fxsave (regcache, regno, &fp_regs.__fpu_fcw);
ret = thread_set_state (current_thread, i386_FLOAT_STATE,
(thread_state_t) & fp_regs,
i386_FLOAT_STATE_COUNT);
MACH_CHECK_ERROR (ret);
}
}
}
/* Support for debug registers, boosted mostly from i386-linux-nat.c. */
#ifndef DR_FIRSTADDR
#define DR_FIRSTADDR 0
#endif
#ifndef DR_LASTADDR
#define DR_LASTADDR 3
#endif
#ifndef DR_STATUS
#define DR_STATUS 6
#endif
#ifndef DR_CONTROL
#define DR_CONTROL 7
#endif
static void
i386_darwin_dr_set (int regnum, uint32_t value)
{
int current_pid;
thread_t current_thread;
x86_debug_state_t dr_regs;
kern_return_t ret;
unsigned int dr_count = x86_DEBUG_STATE_COUNT;
gdb_assert (regnum >= 0 && regnum <= DR_CONTROL);
current_thread = ptid_get_tid (inferior_ptid);
dr_regs.dsh.flavor = x86_DEBUG_STATE32;
dr_regs.dsh.count = x86_DEBUG_STATE32_COUNT;
dr_count = x86_DEBUG_STATE_COUNT;
ret = thread_get_state (current_thread, x86_DEBUG_STATE,
(thread_state_t) &dr_regs, &dr_count);
if (ret != KERN_SUCCESS)
{
printf_unfiltered (_("Error reading debug registers thread 0x%x via thread_get_state\n"), (int) current_thread);
MACH_CHECK_ERROR (ret);
}
switch (regnum)
{
case 0:
dr_regs.uds.ds32.__dr0 = value;
break;
case 1:
dr_regs.uds.ds32.__dr1 = value;
break;
case 2:
dr_regs.uds.ds32.__dr2 = value;
break;
case 3:
dr_regs.uds.ds32.__dr3 = value;
break;
case 4:
dr_regs.uds.ds32.__dr4 = value;
break;
case 5:
dr_regs.uds.ds32.__dr5 = value;
break;
case 6:
dr_regs.uds.ds32.__dr6 = value;
break;
case 7:
dr_regs.uds.ds32.__dr7 = value;
break;
}
ret = thread_set_state (current_thread, x86_DEBUG_STATE,
(thread_state_t) &dr_regs, dr_count);
if (ret != KERN_SUCCESS)
{
printf_unfiltered (_("Error writing debug registers thread 0x%x via thread_get_state\n"), (int) current_thread);
MACH_CHECK_ERROR (ret);
}
}
static uint32_t
i386_darwin_dr_get (int regnum)
{
thread_t current_thread;
x86_debug_state_t dr_regs;
kern_return_t ret;
unsigned int dr_count = x86_DEBUG_STATE_COUNT;
gdb_assert (regnum >= 0 && regnum <= DR_CONTROL);
current_thread = ptid_get_tid (inferior_ptid);
dr_regs.dsh.flavor = x86_DEBUG_STATE32;
dr_regs.dsh.count = x86_DEBUG_STATE32_COUNT;
dr_count = x86_DEBUG_STATE_COUNT;
ret = thread_get_state (current_thread, x86_DEBUG_STATE,
(thread_state_t) &dr_regs, &dr_count);
if (ret != KERN_SUCCESS)
{
printf_unfiltered (_("Error reading debug registers thread 0x%x via thread_get_state\n"), (int) current_thread);
MACH_CHECK_ERROR (ret);
}
switch (regnum)
{
case 0:
return dr_regs.uds.ds32.__dr0;
case 1:
return dr_regs.uds.ds32.__dr1;
case 2:
return dr_regs.uds.ds32.__dr2;
case 3:
return dr_regs.uds.ds32.__dr3;
case 4:
return dr_regs.uds.ds32.__dr4;
case 5:
return dr_regs.uds.ds32.__dr5;
case 6:
return dr_regs.uds.ds32.__dr6;
case 7:
return dr_regs.uds.ds32.__dr7;
default:
return -1;
}
}
void
i386_darwin_dr_set_control (unsigned long control)
{
i386_darwin_dr_set (DR_CONTROL, control);
}
void
i386_darwin_dr_set_addr (int regnum, CORE_ADDR addr)
{
gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
i386_darwin_dr_set (DR_FIRSTADDR + regnum, addr);
}
void
i386_darwin_dr_reset_addr (int regnum)
{
gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
i386_darwin_dr_set (DR_FIRSTADDR + regnum, 0L);
}
unsigned long
i386_darwin_dr_get_status (void)
{
return i386_darwin_dr_get (DR_STATUS);
}
void
darwin_check_osabi (darwin_inferior *inf, thread_t thread)
{
if (gdbarch_osabi (current_gdbarch) == GDB_OSABI_UNKNOWN)
{
/* Attaching to a process. Let's figure out what kind it is. */
x86_thread_state_t gp_regs;
struct gdbarch_info info;
unsigned int gp_count = x86_THREAD_STATE_COUNT;
kern_return_t ret;
ret = thread_get_state (thread, x86_THREAD_STATE,
(thread_state_t) &gp_regs, &gp_count);
if (ret != KERN_SUCCESS)
{
MACH_CHECK_ERROR (ret);
return;
}
gdbarch_info_init (&info);
gdbarch_info_fill (&info);
info.byte_order = gdbarch_byte_order (current_gdbarch);
info.osabi = GDB_OSABI_DARWIN;
if (gp_regs.tsh.flavor == x86_THREAD_STATE64)
info.bfd_arch_info = bfd_lookup_arch (bfd_arch_i386,
bfd_mach_x86_64);
else
info.bfd_arch_info = bfd_lookup_arch (bfd_arch_i386,
bfd_mach_i386_i386);
gdbarch_update_p (info);
}
}
#define X86_EFLAGS_T 0x100UL
void
darwin_set_sstep (thread_t thread, int enable)
{
x86_thread_state_t regs;
unsigned int count = x86_THREAD_STATE_COUNT;
kern_return_t kret;
kret = thread_get_state (thread, x86_THREAD_STATE,
(thread_state_t) &regs, &count);
if (kret != KERN_SUCCESS)
{
printf_unfiltered (_("darwin_set_sstep: error %x, thread=%x\n"),
kret, thread);
return;
}
switch (regs.tsh.flavor)
{
case x86_THREAD_STATE32:
{
__uint32_t bit = enable ? X86_EFLAGS_T : 0;
if ((regs.uts.ts32.__eflags & X86_EFLAGS_T) == bit)
return;
regs.uts.ts32.__eflags = (regs.uts.ts32.__eflags & ~X86_EFLAGS_T) | bit;
kret = thread_set_state (thread, x86_THREAD_STATE,
(thread_state_t) &regs, count);
MACH_CHECK_ERROR (kret);
}
break;
case x86_THREAD_STATE64:
{
__uint64_t bit = enable ? X86_EFLAGS_T : 0;
if ((regs.uts.ts64.__rflags & X86_EFLAGS_T) == bit)
return;
regs.uts.ts64.__rflags = (regs.uts.ts64.__rflags & ~X86_EFLAGS_T) | bit;
kret = thread_set_state (thread, x86_THREAD_STATE,
(thread_state_t) &regs, count);
MACH_CHECK_ERROR (kret);
}
break;
default:
error (_("darwin_set_sstep: unknown flavour: %d\n"), regs.tsh.flavor);
}
}
void
darwin_complete_target (struct target_ops *target)
{
amd64_native_gregset64_reg_offset = amd64_darwin_thread_state_reg_offset;
amd64_native_gregset64_num_regs = amd64_darwin_thread_state_num_regs;
amd64_native_gregset32_reg_offset = i386_darwin_thread_state_reg_offset;
amd64_native_gregset32_num_regs = i386_darwin_thread_state_num_regs;
target->to_fetch_registers = i386_darwin_fetch_inferior_registers;
target->to_store_registers = i386_darwin_store_inferior_registers;
}

159
gdb/i386-darwin-tdep.c Normal file
View File

@ -0,0 +1,159 @@
/* Darwin support for GDB, the GNU debugger.
Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2005, 2008
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/>. */
#include "defs.h"
#include "frame.h"
#include "inferior.h"
#include "gdbcore.h"
#include "target.h"
#include "floatformat.h"
#include "symtab.h"
#include "regcache.h"
#include "libbfd.h"
#include "objfiles.h"
#include "i387-tdep.h"
#include "i386-tdep.h"
#include "amd64-tdep.h"
#include "osabi.h"
#include "ui-out.h"
#include "symtab.h"
#include "frame.h"
#include "gdb_assert.h"
#include "i386-darwin-tdep.h"
/* Offsets into the struct i386_thread_state where we'll find the saved regs.
From <mach/i386/thread_status.h> and i386-tdep.h. */
int i386_darwin_thread_state_reg_offset[] =
{
0 * 4, /* EAX */
2 * 4, /* ECX */
3 * 4, /* EDX */
1 * 4, /* EBX */
7 * 4, /* ESP */
6 * 4, /* EBP */
5 * 4, /* ESI */
4 * 4, /* EDI */
10 * 4, /* EIP */
9 * 4, /* EFLAGS */
11 * 4, /* CS */
8, /* SS */
12 * 4, /* DS */
13 * 4, /* ES */
14 * 4, /* FS */
15 * 4 /* GS */
};
const int i386_darwin_thread_state_num_regs =
ARRAY_SIZE (i386_darwin_thread_state_reg_offset);
/* Offsets into the struct x86_thread_state64 where we'll find the saved regs.
From <mach/i386/thread_status.h> and amd64-tdep.h. */
int amd64_darwin_thread_state_reg_offset[] =
{
0 * 8, /* %rax */
1 * 8, /* %rbx */
2 * 8, /* %rcx */
3 * 8, /* %rdx */
5 * 8, /* %rsi */
4 * 8, /* %rdi */
6 * 8, /* %rbp */
7 * 8, /* %rsp */
8 * 8, /* %r8 ... */
9 * 8,
10 * 8,
11 * 8,
12 * 8,
13 * 8,
14 * 8,
15 * 8, /* ... %r15 */
16 * 8, /* %rip */
17 * 8, /* %rflags */
18 * 8, /* %cs */
-1, /* %ss */
-1, /* %ds */
-1, /* %es */
19 * 8, /* %fs */
20 * 8 /* %gs */
};
const int amd64_darwin_thread_state_num_regs =
ARRAY_SIZE (amd64_darwin_thread_state_reg_offset);
static void
i386_darwin_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
/* We support the SSE registers. */
tdep->num_xmm_regs = I386_NUM_XREGS - 1;
set_gdbarch_num_regs (gdbarch, I386_SSE_NUM_REGS);
tdep->struct_return = reg_struct_return;
tdep->sigcontext_addr = NULL;
tdep->sc_reg_offset = i386_darwin_thread_state_reg_offset;
tdep->sc_num_regs = 16;
tdep->jb_pc_offset = 20;
}
static void
x86_darwin_init_abi_64 (struct gdbarch_info info, struct gdbarch *gdbarch)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
amd64_init_abi (info, gdbarch);
tdep->struct_return = reg_struct_return;
/* We don't do signals yet. */
tdep->sigcontext_addr = NULL;
tdep->sc_reg_offset = amd64_darwin_thread_state_reg_offset;
tdep->sc_num_regs = ARRAY_SIZE (amd64_darwin_thread_state_reg_offset);
tdep->jb_pc_offset = 148;
}
static enum gdb_osabi
i386_mach_o_osabi_sniffer (bfd *abfd)
{
if (!bfd_check_format (abfd, bfd_object))
return GDB_OSABI_UNKNOWN;
if (bfd_get_arch (abfd) == bfd_arch_i386)
return GDB_OSABI_DARWIN;
return GDB_OSABI_UNKNOWN;
}
void
_initialize_i386_darwin_tdep (void)
{
gdbarch_register_osabi_sniffer (bfd_arch_unknown, bfd_target_mach_o_flavour,
i386_mach_o_osabi_sniffer);
gdbarch_register_osabi (bfd_arch_i386, bfd_mach_i386_i386,
GDB_OSABI_DARWIN, i386_darwin_init_abi);
gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64,
GDB_OSABI_DARWIN, x86_darwin_init_abi_64);
}

33
gdb/i386-darwin-tdep.h Normal file
View File

@ -0,0 +1,33 @@
/* Target-dependent code for Darwin x86.
Copyright (C) 2008 Free Software Foundation, 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/>. */
#ifndef __I386_DARWIN_TDEP_H__
#define __I386_DARWIN_TDEP_H__
/* Mapping between the general-purpose registers in Darwin x86 thread_state
struct and GDB's register cache layout. */
extern int i386_darwin_thread_state_reg_offset[];
extern const int i386_darwin_thread_state_num_regs;
/* Mapping between the general-purpose registers in Darwin x86-64 thread
state and GDB's register cache layout.
Indexed by amd64_regnum. */
extern int amd64_darwin_thread_state_reg_offset[];
extern const int amd64_darwin_thread_state_num_regs;
#endif /* __I386_DARWIN_TDEP_H__ */

694
gdb/machoread.c Normal file
View File

@ -0,0 +1,694 @@
/* Darwin support for GDB, the GNU debugger.
Copyright (C) 2008 Free Software Foundation, Inc.
Contributed by AdaCore.
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/>.
*/
#include "defs.h"
#include "symtab.h"
#include "gdbtypes.h"
#include "bfd.h"
#include "symfile.h"
#include "objfiles.h"
#include "buildsym.h"
#include "gdbcmd.h"
#include "gdbcore.h"
#include "mach-o.h"
#include "gdb_assert.h"
#include "aout/stab_gnu.h"
#include "vec.h"
#include <string.h>
/* If non-zero displays debugging message. */
static int mach_o_debug_level = 0;
static void
macho_new_init (struct objfile *objfile)
{
}
static void
macho_symfile_init (struct objfile *objfile)
{
objfile->flags |= OBJF_REORDERED;
init_entry_point_info (objfile);
}
/* Dwarf debugging information are never in the final executable. They stay
in object files and the executable contains the list of object files read
during the link.
Each time an oso (other source) is found in the executable, the reader
creates such a structure. They are read after the processing of the
executable.
*/
typedef struct oso_el
{
/* Object file name. */
const char *name;
/* Associated time stamp. */
unsigned long mtime;
/* Number of sections. This is the length of SYMBOLS and OFFSETS array. */
int num_sections;
/* Each seaction of the object file is represented by a symbol and its
offset. */
asymbol **symbols;
bfd_vma *offsets;
}
oso_el;
/* Vector of object files to be read after the executable. */
DEF_VEC_O (oso_el);
static VEC (oso_el) *oso_vector;
/* Add a new OSO to the vector. */
static void
macho_add_oso (const asymbol *oso_sym, int nbr_sections,
asymbol **symbols, bfd_vma *offsets)
{
oso_el el;
el.name = oso_sym->name;
el.mtime = oso_sym->value;
el.num_sections = nbr_sections;
el.symbols = symbols;
el.offsets = offsets;
VEC_safe_push (oso_el, oso_vector, &el);
}
/* Build the minimal symbol table from SYMBOL_TABLE of length
NUMBER_OF_SYMBOLS for OBJFILE.
Read OSO files at the end. */
static void
macho_symtab_read (struct objfile *objfile,
long number_of_symbols, asymbol **symbol_table)
{
struct gdbarch *gdbarch = get_objfile_arch (objfile);
long storage_needed;
asymbol *sym;
long i, j;
CORE_ADDR offset;
enum minimal_symbol_type ms_type;
unsigned int nbr_sections = bfd_count_sections (objfile->obfd);
asymbol **first_symbol = NULL;
bfd_vma *first_offset = NULL;
const asymbol *oso_file = NULL;
for (i = 0; i < number_of_symbols; i++)
{
sym = symbol_table[i];
offset = ANOFFSET (objfile->section_offsets, sym->section->index);
if (sym->flags & BSF_DEBUGGING)
{
unsigned char type = BFD_MACH_O_SYM_NTYPE(sym);
bfd_vma addr;
switch (type)
{
case N_SO:
if ((sym->name == NULL || sym->name[0] == 0)
&& oso_file != NULL)
{
macho_add_oso (oso_file, nbr_sections,
first_symbol, first_offset);
first_symbol = NULL;
first_offset = NULL;
oso_file = NULL;
}
break;
case N_FUN:
case N_STSYM:
if (sym->name == NULL || sym->name[0] == '\0')
break;
/* Fall through. */
case N_BNSYM:
gdb_assert (oso_file != NULL);
addr = sym->value
+ bfd_get_section_vma (sym->section->bfd, sym->section);
if (addr != 0
&& first_symbol[sym->section->index] == NULL)
{
first_symbol[sym->section->index] = sym;
first_offset[sym->section->index] = addr + offset;
}
break;
case N_GSYM:
gdb_assert (oso_file != NULL);
if (first_symbol[sym->section->index] == NULL)
first_symbol[sym->section->index] = sym;
break;
case N_OSO:
gdb_assert (oso_file == NULL);
first_symbol = (asymbol **)xmalloc (nbr_sections
* sizeof (asymbol *));
first_offset = (bfd_vma *)xmalloc (nbr_sections
* sizeof (bfd_vma));
for (j = 0; j < nbr_sections; j++)
first_symbol[j] = NULL;
oso_file = sym;
break;
}
continue;
}
if (sym->name == NULL || *sym->name == '\0')
{
/* Skip names that don't exist (shouldn't happen), or names
that are null strings (may happen). */
continue;
}
if (sym->flags & (BSF_GLOBAL | BSF_LOCAL | BSF_WEAK))
{
struct minimal_symbol *msym;
CORE_ADDR symaddr;
/* Bfd symbols are section relative. */
symaddr = sym->value + sym->section->vma;
/* Select global/local/weak symbols. Note that bfd puts abs
symbols in their own section, so all symbols we are
interested in will have a section. */
/* Relocate all non-absolute and non-TLS symbols by the
section offset. */
if (sym->section != &bfd_abs_section
&& !(sym->section->flags & SEC_THREAD_LOCAL))
symaddr += offset;
if (sym->section == &bfd_abs_section)
ms_type = mst_abs;
else if (sym->section->flags & SEC_CODE)
{
if (sym->flags & (BSF_GLOBAL | BSF_WEAK))
ms_type = mst_text;
else
ms_type = mst_file_text;
}
else if (sym->section->flags & SEC_ALLOC)
{
if (sym->flags & (BSF_GLOBAL | BSF_WEAK))
{
if (sym->section->flags & SEC_LOAD)
ms_type = mst_data;
else
ms_type = mst_bss;
}
else if (sym->flags & BSF_LOCAL)
{
/* Not a special stabs-in-elf symbol, do regular
symbol processing. */
if (sym->section->flags & SEC_LOAD)
ms_type = mst_file_data;
else
ms_type = mst_file_bss;
}
else
ms_type = mst_unknown;
}
else
continue; /* Skip this symbol. */
gdb_assert (sym->section->index < nbr_sections);
if (oso_file != NULL
&& first_symbol[sym->section->index] == NULL)
{
first_symbol[sym->section->index] = sym;
first_offset[sym->section->index] = symaddr;
}
msym = prim_record_minimal_symbol_and_info
(sym->name, symaddr, ms_type, sym->section->index,
sym->section, objfile);
}
}
if (oso_file != NULL)
macho_add_oso (oso_file, nbr_sections, first_symbol, first_offset);
}
/* If NAME describes an archive member (ie: ARCHIVE '(' MEMBER ')'),
returns the length of the archive name.
Returns -1 otherwise. */
static int
get_archive_prefix_len (const char *name)
{
char *lparen;
int name_len = strlen (name);
if (name_len == 0 || name[name_len - 1] != ')')
return -1;
lparen = strrchr (name, '(');
if (lparen == NULL || lparen == name)
return -1;
return lparen - name;
}
/* Read symbols from the vector of oso files. */
static void
macho_oso_symfile (struct objfile *main_objfile)
{
int ix;
VEC (oso_el) *vec;
oso_el *oso;
char leading_char;
/* TODO: Sort them, group library search. */
vec = oso_vector;
oso_vector = NULL;
leading_char = bfd_get_symbol_leading_char (main_objfile->obfd);
for (ix = 0; VEC_iterate (oso_el, vec, ix, oso); ix++)
{
struct section_addr_info *addrs;
int pfx_len;
int len;
int i;
oso_el el;
if (mach_o_debug_level > 0)
printf_unfiltered (_("Loading symbols from oso: %s\n"), oso->name);
/* Compute addr length. */
len = 0;
for (i = 0; i < oso->num_sections; i++)
if (oso->symbols[i] != NULL)
len++;
addrs = alloc_section_addr_info (len);
len = 0;
for (i = 0; i < oso->num_sections; i++)
if (oso->symbols[i] != NULL)
{
if (oso->offsets[i])
addrs->other[len].addr = oso->offsets[i];
else
{
struct minimal_symbol *msym;
const char *name = oso->symbols[i]->name;
if (name[0] == leading_char)
++name;
if (mach_o_debug_level > 3)
printf_unfiltered (_("resolv sec %s with %s\n"),
oso->symbols[i]->section->name,
oso->symbols[i]->name);
msym = lookup_minimal_symbol (name, NULL, main_objfile);
if (msym == NULL)
{
warning (_("can't find symbol '%s' in minsymtab"),
oso->symbols[i]->name);
addrs->other[len].addr = 0;
}
else
addrs->other[len].addr = SYMBOL_VALUE_ADDRESS (msym);
}
addrs->other[len].name = (char *)oso->symbols[i]->section->name;
len++;
}
if (mach_o_debug_level > 1)
{
int j;
for (j = 0; j < addrs->num_sections; j++)
printf_unfiltered
(_(" %s: %s\n"),
core_addr_to_string (addrs->other[j].addr),
addrs->other[j].name);
}
/* Check if this is a library name. */
pfx_len = get_archive_prefix_len (oso->name);
if (pfx_len > 0)
{
bfd *archive_bfd;
bfd *member_bfd;
char *archive_name = (char *) alloca (pfx_len + 1);
int member_len;
member_len = strlen (oso->name + pfx_len + 1) - 1;
memcpy (archive_name, oso->name, pfx_len);
archive_name[pfx_len] = '\0';
/* Open the archive and check the format. */
archive_bfd = bfd_openr (archive_name, gnutarget);
if (archive_bfd == NULL)
{
warning (_("Could not open OSO archive file \"%s\""),
archive_name);
continue;
}
if (!bfd_check_format (archive_bfd, bfd_archive))
{
warning (_("OSO archive file \"%s\" not an archive."),
archive_name);
bfd_close (archive_bfd);
continue;
}
member_bfd = bfd_openr_next_archived_file (archive_bfd, NULL);
if (member_bfd == NULL)
{
warning (_("Could not read archive members out of "
"OSO archive \"%s\""), archive_name);
bfd_close (archive_bfd);
continue;
}
while (member_bfd != NULL)
{
bfd *prev = member_bfd;
const char *member_name = member_bfd->filename;
if (strlen (member_name) == member_len
&& !memcmp (member_name, oso->name + pfx_len + 1, member_len))
break;
member_bfd = bfd_openr_next_archived_file
(archive_bfd, member_bfd);
bfd_close (prev);
}
if (member_bfd == NULL)
{
warning (_("Could not find specified archive member "
"for OSO name \"%s\""), oso->name);
bfd_close (archive_bfd);
continue;
}
bfd_set_cacheable (member_bfd, 1);
if (!bfd_check_format (member_bfd, bfd_object))
{
warning (_("`%s': can't read symbols: %s."), oso->name,
bfd_errmsg (bfd_get_error ()));
bfd_close (member_bfd);
}
else
symbol_file_add_from_bfd (member_bfd, 0, addrs, 0, 0);
}
else
{
bfd *abfd;
abfd = bfd_openr (oso->name, gnutarget);
if (!abfd)
{
warning (_("`%s': can't open to read symbols: %s."), oso->name,
bfd_errmsg (bfd_get_error ()));
continue;
}
bfd_set_cacheable (abfd, 1);
if (!bfd_check_format (abfd, bfd_object))
{
bfd_close (abfd);
warning (_("`%s': can't read symbols: %s."), oso->name,
bfd_errmsg (bfd_get_error ()));
continue;
}
symbol_file_add_from_bfd (abfd, 0, addrs, 0, 0);
}
xfree (oso->symbols);
xfree (oso->offsets);
}
VEC_free (oso_el, vec);
}
/* DSYM (debug symbols) files contain the debug info of an executable.
This is a separate file created by dsymutil(1) and is similar to debug
link feature on ELF.
DSYM files are located in a subdirectory. Append DSYM_SUFFIX to the
executable name and the executable base name to get the DSYM file name. */
#define DSYM_SUFFIX ".dSYM/Contents/Resources/DWARF/"
/* Check if a dsym file exists for OBJFILE. If so, returns a bfd for it.
Return NULL if no valid dsym file is found. */
static bfd *
macho_check_dsym (struct objfile *objfile)
{
size_t name_len = strlen (objfile->name);
size_t dsym_len = strlen (DSYM_SUFFIX);
const char *base_name = lbasename (objfile->name);
size_t base_len = strlen (base_name);
char *dsym_filename = alloca (name_len + dsym_len + base_len + 1);
bfd *dsym_bfd;
asection *sect;
bfd_byte main_uuid[16];
bfd_byte dsym_uuid[16];
strcpy (dsym_filename, objfile->name);
strcpy (dsym_filename + name_len, DSYM_SUFFIX);
strcpy (dsym_filename + name_len + dsym_len, base_name);
if (access (dsym_filename, R_OK) != 0)
return NULL;
sect = bfd_get_section_by_name (objfile->obfd, "LC_UUID");
if (sect == NULL)
{
warning (_("can't find UUID in %s"), objfile->name);
return NULL;
}
if (!bfd_get_section_contents (objfile->obfd, sect, main_uuid,
0, sizeof (main_uuid)))
{
warning (_("can't read UUID in %s"), objfile->name);
return NULL;
}
dsym_filename = xstrdup (dsym_filename);
dsym_bfd = bfd_openr (dsym_filename, gnutarget);
if (dsym_bfd == NULL)
{
warning (_("can't open dsym file %s"), dsym_filename);
xfree (dsym_filename);
return NULL;
}
if (!bfd_check_format (dsym_bfd, bfd_object))
{
bfd_close (dsym_bfd);
warning (_("bad dsym file format: %s"), bfd_errmsg (bfd_get_error ()));
xfree (dsym_filename);
return NULL;
}
sect = bfd_get_section_by_name (dsym_bfd, "LC_UUID");
if (sect == NULL)
{
warning (_("can't find UUID in %s"), dsym_filename);
bfd_close (dsym_bfd);
xfree (dsym_filename);
return NULL;
}
if (!bfd_get_section_contents (dsym_bfd, sect, dsym_uuid,
0, sizeof (dsym_uuid)))
{
warning (_("can't read UUID in %s"), dsym_filename);
bfd_close (dsym_bfd);
xfree (dsym_filename);
return NULL;
}
if (memcmp (dsym_uuid, main_uuid, sizeof (main_uuid)))
{
warning (_("dsym file UUID doesn't match the one in %s"), objfile->name);
bfd_close (dsym_bfd);
xfree (dsym_filename);
return NULL;
}
return dsym_bfd;
}
static void
macho_symfile_read (struct objfile *objfile, int mainline)
{
bfd *abfd = objfile->obfd;
struct cleanup *back_to;
CORE_ADDR offset;
long storage_needed;
bfd *dsym_bfd;
init_minimal_symbol_collection ();
back_to = make_cleanup_discard_minimal_symbols ();
/* Get symbols from the symbol table only if the file is an executable.
The symbol table of object files is not relocated and is expected to
be in the executable. */
if (bfd_get_file_flags (abfd) & EXEC_P)
{
/* Process the normal symbol table first. */
storage_needed = bfd_get_symtab_upper_bound (objfile->obfd);
if (storage_needed < 0)
error (_("Can't read symbols from %s: %s"),
bfd_get_filename (objfile->obfd),
bfd_errmsg (bfd_get_error ()));
if (storage_needed > 0)
{
asymbol **symbol_table;
long symcount;
symbol_table = (asymbol **) xmalloc (storage_needed);
make_cleanup (xfree, symbol_table);
symcount = bfd_canonicalize_symtab (objfile->obfd, symbol_table);
if (symcount < 0)
error (_("Can't read symbols from %s: %s"),
bfd_get_filename (objfile->obfd),
bfd_errmsg (bfd_get_error ()));
macho_symtab_read (objfile, symcount, symbol_table);
}
install_minimal_symbols (objfile);
/* Check for DSYM file. */
dsym_bfd = macho_check_dsym (objfile);
if (dsym_bfd != NULL)
{
int ix;
oso_el *oso;
if (mach_o_debug_level > 0)
printf_unfiltered (_("dsym file found\n"));
/* Remove oso. They won't be used. */
for (ix = 0; VEC_iterate (oso_el, oso_vector, ix, oso); ix++)
{
xfree (oso->symbols);
xfree (oso->offsets);
}
VEC_free (oso_el, oso_vector);
oso_vector = NULL;
/* Now recurse: read dwarf from dsym. */
symbol_file_add_from_bfd (dsym_bfd, 0, NULL, 0, 0);
/* Don't try to read dwarf2 from main file. */
return;
}
}
if (dwarf2_has_info (objfile))
{
/* DWARF 2 sections */
dwarf2_build_psymtabs (objfile, mainline);
}
/* FIXME: kettenis/20030504: This still needs to be integrated with
dwarf2read.c in a better way. */
dwarf2_build_frame_info (objfile);
/* Then the oso. */
if (oso_vector != NULL)
macho_oso_symfile (objfile);
}
static void
macho_symfile_finish (struct objfile *objfile)
{
}
static void
macho_symfile_offsets (struct objfile *objfile,
struct section_addr_info *addrs)
{
unsigned int i;
unsigned int num_sections;
struct obj_section *osect;
/* Allocate section_offsets. */
objfile->num_sections = bfd_count_sections (objfile->obfd);
objfile->section_offsets = (struct section_offsets *)
obstack_alloc (&objfile->objfile_obstack,
SIZEOF_N_SECTION_OFFSETS (objfile->num_sections));
memset (objfile->section_offsets, 0,
SIZEOF_N_SECTION_OFFSETS (objfile->num_sections));
/* This code is run when we first add the objfile with
symfile_add_with_addrs_or_offsets, when "addrs" not "offsets" are
passed in. The place in symfile.c where the addrs are applied
depends on the addrs having section names. But in the dyld code
we build an anonymous array of addrs, so that code is a no-op.
Because of that, we have to apply the addrs to the sections here.
N.B. if an objfile slides after we've already created it, then it
goes through objfile_relocate. */
for (i = 0; i < addrs->num_sections; i++)
{
if (addrs->other[i].name == NULL)
continue;
ALL_OBJFILE_OSECTIONS (objfile, osect)
{
const char *bfd_sect_name = osect->the_bfd_section->name;
if (strcmp (bfd_sect_name, addrs->other[i].name) == 0)
{
obj_section_offset (osect) = addrs->other[i].addr;
break;
}
}
}
objfile->sect_index_text = 0;
ALL_OBJFILE_OSECTIONS (objfile, osect)
{
const char *bfd_sect_name = osect->the_bfd_section->name;
int sect_index = osect->the_bfd_section->index;
if (strcmp (bfd_sect_name, "LC_SEGMENT.__TEXT") == 0)
objfile->sect_index_text = sect_index;
else if (strcmp (bfd_sect_name, "LC_SEGMENT.__TEXT.__text") == 0)
objfile->sect_index_text = sect_index;
}
}
static struct sym_fns macho_sym_fns = {
bfd_target_mach_o_flavour,
macho_new_init, /* sym_new_init: init anything gbl to entire symtab */
macho_symfile_init, /* sym_init: read initial info, setup for sym_read() */
macho_symfile_read, /* sym_read: read a symbol file into symtab */
macho_symfile_finish, /* sym_finish: finished with file, cleanup */
macho_symfile_offsets, /* sym_offsets: xlate external to internal form */
NULL /* next: pointer to next struct sym_fns */
};
void
_initialize_machoread ()
{
add_symtab_fns (&macho_sym_fns);
add_setshow_zinteger_cmd ("mach-o", class_obscure,
&mach_o_debug_level, _("\
Set if printing Mach-O symbols processing."), _("\
Show if printing Mach-O symbols processing."), NULL,
NULL, NULL,
&setdebuglist, &showdebuglist);
}

View File

@ -73,6 +73,7 @@ static const char * const gdb_osabi_names[] =
"Cygwin",
"AIX",
"DICOS",
"Darwin",
"<invalid>"
};