#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 "block.h"
#include "libaout.h"
#include "aout/aout64.h"
#include "complaints.h"
#include "mach-o.h"
#include "objc-lang.h"
#include "macosx-tdep.h"
#if 0
struct deprecated_complaint unknown_macho_symtype_complaint =
{ "unknown Mach-O symbol type %s", 0, 0 };
struct deprecated_complaint unknown_macho_section_complaint =
{ "unknown Mach-O section value %s (assuming DATA)", 0, 0 };
struct deprecated_complaint unsupported_indirect_symtype_complaint =
{ "unsupported Mach-O symbol type %s (indirect)", 0, 0 };
#endif
#define BFD_GETB16(addr) ((addr[0] << 8) | addr[1])
#define BFD_GETB32(addr) ((((((uint32_t) addr[0] << 8) | addr[1]) << 8) | addr[2]) << 8 | addr[3])
#define BFD_GETB64(addr) ((((((((((uint64_t) addr[0] << 8) | addr[1]) << 8) | addr[2]) << 8 | addr[3]) << 8 | addr[4]) << 8 | addr[5]) << 8 | addr[6]) << 8 | addr[7])
#define BFD_GETL16(addr) ((addr[1] << 8) | addr[0])
#define BFD_GETL32(addr) ((((((uint32_t) addr[3] << 8) | addr[2]) << 8) | addr[1]) << 8 | addr[0])
#define BFD_GETL64(addr) ((((((((((uint64_t) addr[7] << 8) | addr[6]) << 8) | addr[5]) << 8 | addr[4]) << 8 | 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_sect, abfd)
unsigned char macho_type;
unsigned char macho_sect;
bfd *abfd;
{
unsigned char ntype = macosx_symbol_types[macho_type];
if ((macho_type & BFD_MACH_O_N_TYPE) == BFD_MACH_O_N_SECT)
{
if (macho_sect == 1)
{
ntype |= N_TEXT;
}
else if ((macho_sect > 0)
&& (macho_sect <= abfd->tdata.mach_o_data->nsects))
{
const bfd_mach_o_section *sect =
abfd->tdata.mach_o_data->sections[macho_sect - 1];
if (sect == NULL)
{
}
else if ((sect->segname != NULL)
&& (strcmp (sect->segname, "__DATA") == 0))
{
if ((sect->sectname != NULL)
&& (strcmp (sect->sectname, "__bss") == 0))
ntype |= N_BSS;
else
ntype |= N_DATA;
}
else if ((sect->segname != NULL)
&& (strcmp (sect->segname, "__TEXT") == 0))
{
ntype |= N_TEXT;
}
else
{
ntype |= N_DATA;
}
}
else
{
ntype |= N_DATA;
}
}
return ntype;
}
void
macosx_internalize_symbol (in, sect_p, ext, abfd)
struct internal_nlist *in;
int *sect_p;
struct external_nlist *ext;
bfd *abfd;
{
int symwide = (bfd_mach_o_version (abfd) > 1);
if (bfd_header_big_endian (abfd))
{
in->n_strx = BFD_GETB32 (ext->e_strx);
in->n_desc = BFD_GETB16 (ext->e_desc);
if (symwide)
in->n_value = BFD_GETB64 (ext->e_value);
else
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);
if (symwide)
in->n_value = BFD_GETL64 (ext->e_value);
else
in->n_value = BFD_GETL32 (ext->e_value);
}
else
{
error ("unable to internalize symbol (unknown endianness)");
}
if ((ext->e_type[0] & BFD_MACH_O_N_TYPE) == BFD_MACH_O_N_SECT)
*sect_p = 1;
else
*sect_p = 0;
in->n_type = macosx_symbol_type (ext->e_type[0], ext->e_other[0], abfd);
in->n_other = ext->e_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_DOMAIN, 0, 0);
if ((sym == NULL) && (lname[0] == '_'))
sym = lookup_symbol (lname + 1, 0, VAR_DOMAIN, 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_LINKAGE_NAME (msymbol), DYLD_PREFIX, strlen (DYLD_PREFIX)) != 0)
return NULL;
return SYMBOL_LINKAGE_NAME (msymbol) + strlen (DYLD_PREFIX);
}
CORE_ADDR
macosx_skip_trampoline_code (CORE_ADDR pc)
{
CORE_ADDR newpc;
newpc = dyld_symbol_stub_function_address (pc, NULL);
if (newpc != 0)
return newpc;
newpc = decode_fix_and_continue_trampoline (pc);
if (newpc != 0)
return newpc;
return 0;
}
int
macosx_record_symbols_from_sect_p (bfd *abfd, unsigned char macho_type,
unsigned char macho_sect)
{
const bfd_mach_o_section *sect =
abfd->tdata.mach_o_data->sections[macho_sect - 1];
if ((sect->flags & BFD_MACH_O_SECTION_TYPE_MASK) ==
BFD_MACH_O_S_SYMBOL_STUBS)
return 0;
else
return 1;
}
int
macosx_in_solib_return_trampoline (CORE_ADDR pc, char *name)
{
return 0;
}
int
macosx_in_solib_call_trampoline (CORE_ADDR pc, char *name)
{
if (macosx_skip_trampoline_code (pc) != 0)
{
return 1;
}
return 0;
}
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);
trampoline = macosx_skip_trampoline_code (address);
find_objc_msgcall (trampoline, &objc);
fprintf_filtered
(gdb_stderr, "Function at 0x%s becomes 0x%s becomes 0x%s\n",
paddr_nz (address), paddr_nz (trampoline), paddr_nz (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");
}