#include "defs.h"
#include "inferior.h"
#include "target.h"
#include "symfile.h"
#include "symtab.h"
#include "objfiles.h"
#include "gdbcmd.h"
#include "language.h"
#include "libaout.h"
#include "aout/aout64.h"
#include "complaints.h"
#include "mach-o.h"
#include "objc-lang.h"
#include "macosx-tdep.h"
struct complaint unknown_macho_symtype_complaint =
{"unknown Mach-O symbol type %s", 0, 0};
struct complaint unknown_macho_section_complaint =
{"unknown Mach-O section value %s (assuming DATA)", 0, 0};
struct complaint unsupported_indirect_symtype_complaint =
{"unsupported Mach-O symbol type %s (indirect)", 0, 0};
#define BFD_GETB16(addr) ((addr[0] << 8) | addr[1])
#define BFD_GETB32(addr) ((((((unsigned long) addr[0] << 8) | addr[1]) << 8) | addr[2]) << 8 | addr[3])
#define BFD_GETL16(addr) ((addr[1] << 8) | addr[0])
#define BFD_GETL32(addr) ((((((unsigned long) addr[3] << 8) | addr[2]) << 8) | addr[1]) << 8 | addr[0])
unsigned char macosx_symbol_types[256];
static unsigned char macosx_symbol_type_base (macho_type)
unsigned char macho_type;
{
unsigned char mtype = macho_type;
unsigned char ntype = 0;
if (macho_type & BFD_MACH_O_N_STAB) {
return macho_type;
}
if (mtype & BFD_MACH_O_N_PEXT) {
mtype &= ~BFD_MACH_O_N_PEXT;
ntype |= N_EXT;
}
if (mtype & BFD_MACH_O_N_EXT) {
mtype &= ~BFD_MACH_O_N_EXT;
ntype |= N_EXT;
}
switch (mtype & BFD_MACH_O_N_TYPE) {
case BFD_MACH_O_N_SECT:
break;
case BFD_MACH_O_N_PBUD:
ntype |= N_UNDF;
break;
case BFD_MACH_O_N_ABS:
ntype |= N_ABS;
break;
case BFD_MACH_O_N_UNDF:
ntype |= N_UNDF;
break;
case BFD_MACH_O_N_INDR:
return macho_type;
default:
return macho_type;
}
mtype &= ~BFD_MACH_O_N_TYPE;
CHECK_FATAL (mtype == 0);
return ntype;
}
static void macosx_symbol_types_init ()
{
unsigned int i;
for (i = 0; i < 256; i++) {
macosx_symbol_types[i] = macosx_symbol_type_base (i);
}
}
static unsigned char macosx_symbol_type (macho_type, macho_other)
unsigned char macho_type;
unsigned char macho_other;
{
unsigned char ntype = macosx_symbol_types[macho_type];
if ((macho_type & BFD_MACH_O_N_TYPE) == BFD_MACH_O_N_SECT) {
if (macho_other == 1) {
ntype |= N_TEXT;
} else {
ntype |= N_DATA;
}
}
return ntype;
}
void macosx_internalize_symbol (in, ext, abfd)
struct internal_nlist *in;
struct external_nlist *ext;
bfd *abfd;
{
if (bfd_header_big_endian (abfd)) {
in->n_strx = BFD_GETB32 (ext->e_strx);
in->n_desc = BFD_GETB16 (ext->e_desc);
in->n_value = BFD_GETB32 (ext->e_value);
} else if (bfd_header_little_endian (abfd)) {
in->n_strx = BFD_GETL32 (ext->e_strx);
in->n_desc = BFD_GETL16 (ext->e_desc);
in->n_value = BFD_GETL32 (ext->e_value);
} else {
error ("unable to internalize symbol (unknown endianness)");
}
in->n_type = macosx_symbol_type (ext->e_type[0], ext->e_other[0]);
in->n_other = 0;
}
CORE_ADDR dyld_symbol_stub_function_address (CORE_ADDR pc, const char **name)
{
struct symbol *sym = NULL;
struct minimal_symbol *msym = NULL;
const char *lname = NULL;
lname = dyld_symbol_stub_function_name (pc);
if (name)
*name = lname;
if (lname == NULL)
return 0;
sym = lookup_symbol (lname, 0, VAR_NAMESPACE, 0, 0);
if ((sym == NULL) && (lname[0] == '_'))
sym = lookup_symbol (lname + 1, 0, VAR_NAMESPACE, 0, 0);
if (sym != NULL && SYMBOL_BLOCK_VALUE (sym) != NULL)
return BLOCK_START (SYMBOL_BLOCK_VALUE (sym));
msym = lookup_minimal_symbol (lname, NULL, NULL);
if ((msym == 0) && (lname[0] == '_'))
msym = lookup_minimal_symbol (lname + 1, NULL, NULL);
if (msym != NULL)
return SYMBOL_VALUE_ADDRESS (msym);
return 0;
}
const char *dyld_symbol_stub_function_name (CORE_ADDR pc)
{
struct minimal_symbol *msymbol = NULL;
const char *DYLD_PREFIX = "dyld_stub_";
msymbol = lookup_minimal_symbol_by_pc (pc);
if (msymbol == NULL)
return NULL;
if (SYMBOL_VALUE_ADDRESS (msymbol) != pc)
return NULL;
if (strncmp (SYMBOL_NAME (msymbol), DYLD_PREFIX, strlen (DYLD_PREFIX)) != 0)
return NULL;
return SYMBOL_NAME (msymbol) + strlen (DYLD_PREFIX);
}
static void info_trampoline_command (char *exp, int from_tty)
{
struct expression *expr;
struct value *val;
CORE_ADDR address;
CORE_ADDR trampoline;
CORE_ADDR objc;
expr = parse_expression (exp);
val = evaluate_expression (expr);
if (TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_REF)
val = value_ind (val);
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 defined (TARGET_POWERPC)
trampoline = ppc_macosx_skip_trampoline_code (address);
#elif defined (TARGET_I386)
trampoline = i386_macosx_skip_trampoline_code (address);
#else
#error unknown architecture
#endif
find_objc_msgcall (trampoline, &objc);
fprintf_filtered
(gdb_stderr, "Function at 0x%lx becomes 0x%lx becomes 0x%lx\n",
(unsigned long) address, (unsigned long) trampoline, (unsigned long) objc);
}
void
_initialize_macosx_tdep ()
{
macosx_symbol_types_init ();
add_info ("trampoline", info_trampoline_command,
"Resolve function for DYLD trampoline stub and/or Objective-C call");
}