#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"
#include "regcache.h"
#include "source.h"
#include "completer.h"
#include "exceptions.h"
#include <dirent.h>
#include <libgen.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <mach/machine.h>
#include <CoreFoundation/CoreFoundation.h>
#include "readline/tilde.h"
#include "macosx-nat-utils.h"
static char *find_info_plist_filename_from_bundle_name (const char *bundle,
const char *bundle_suffix);
#if USE_DEBUG_SYMBOLS_FRAMEWORK
extern CFArrayRef DBGCopyMatchingUUIDsForURL (CFURLRef path,
int cpuType,
int cpuSubtype);
extern CFURLRef DBGCopyDSYMURLForUUID (CFUUIDRef uuid);
#endif
static const char dsym_extension[] = ".dSYM";
static const char dsym_bundle_subdir[] = "Contents/Resources/DWARF/";
static const int dsym_extension_len = (sizeof (dsym_extension) - 1);
static const int dsym_bundle_subdir_len = (sizeof (dsym_bundle_subdir) - 1);
static int dsym_locate_enabled = 1;
#define APPLE_DSYM_EXT_AND_SUBDIRECTORY ".dSYM/Contents/Resources/DWARF/"
int
actually_do_stack_frame_prologue (unsigned int count_limit,
unsigned int print_limit,
unsigned int wordsize,
unsigned int *count,
struct frame_info **out_fi,
void (print_fun) (struct ui_out * uiout, int frame_num,
CORE_ADDR pc, CORE_ADDR fp));
enum gdb_osabi osabi_seen_in_attached_dyld = GDB_OSABI_UNKNOWN;
#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_global (lname, lname, VAR_DOMAIN, 0);
if ((sym == NULL) && (lname[0] == '_'))
sym = lookup_symbol_global (lname + 1, lname + 1, VAR_DOMAIN, 0);
if (sym != NULL && SYMBOL_BLOCK_VALUE (sym) != NULL)
return BLOCK_LOWEST_PC (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;
if (macho_sect <= 0 || macho_sect > abfd->tdata.mach_o_data->nsects)
{
warning ("Bad symbol - type is N_SECT but section is %d", macho_sect);
return 0;
}
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));
}
struct sal_chain
{
struct sal_chain *next;
struct symtab_and_line sal;
};
int
macosx_enable_exception_callback (enum exception_event_kind kind, int enable)
{
return 1;
}
struct symtabs_and_lines *
macosx_find_exception_catchpoints (enum exception_event_kind kind,
struct objfile *restrict_objfile)
{
struct symtabs_and_lines *return_sals;
char *symbol_name;
struct objfile *objfile;
struct minimal_symbol *msymbol;
unsigned int hash;
struct sal_chain *sal_chain = 0;
switch (kind)
{
case EX_EVENT_THROW:
symbol_name = "__cxa_throw";
break;
case EX_EVENT_CATCH:
symbol_name = "__cxa_begin_catch";
break;
default:
error ("We currently only handle \"throw\" and \"catch\"");
}
hash = msymbol_hash (symbol_name) % MINIMAL_SYMBOL_HASH_SIZE;
ALL_OBJFILES (objfile)
{
for (msymbol = objfile->msymbol_hash[hash];
msymbol != NULL; msymbol = msymbol->hash_next)
if (MSYMBOL_TYPE (msymbol) == mst_text
&& (strcmp_iw (SYMBOL_LINKAGE_NAME (msymbol), symbol_name) == 0))
{
CORE_ADDR catchpoint_address;
CORE_ADDR past_prologue;
struct sal_chain *next
= (struct sal_chain *) alloca (sizeof (struct sal_chain));
next->next = sal_chain;
init_sal (&next->sal);
next->sal.symtab = NULL;
catchpoint_address = SYMBOL_VALUE_ADDRESS (msymbol);
past_prologue = SKIP_PROLOGUE (catchpoint_address);
next->sal.pc = past_prologue;
next->sal.line = 0;
next->sal.end = past_prologue;
sal_chain = next;
}
}
if (sal_chain)
{
int index = 0;
struct sal_chain *temp;
for (temp = sal_chain; temp != NULL; temp = temp->next)
index++;
return_sals = (struct symtabs_and_lines *)
xmalloc (sizeof (struct symtabs_and_lines));
return_sals->nelts = index;
return_sals->sals =
(struct symtab_and_line *) xmalloc (index *
sizeof (struct symtab_and_line));
for (index = 0; sal_chain; sal_chain = sal_chain->next, index++)
return_sals->sals[index] = sal_chain->sal;
return return_sals;
}
else
return NULL;
}
struct exception_event_record *
macosx_get_current_exception_event ()
{
static struct exception_event_record *exception_event = NULL;
struct frame_info *curr_frame;
struct frame_info *fi;
CORE_ADDR pc;
int stop_func_found;
char *stop_name;
char *typeinfo_str;
if (exception_event == NULL)
{
exception_event = (struct exception_event_record *)
xmalloc (sizeof (struct exception_event_record));
exception_event->exception_type = NULL;
}
curr_frame = get_current_frame ();
if (!curr_frame)
return (struct exception_event_record *) NULL;
pc = get_frame_pc (curr_frame);
stop_func_found = find_pc_partial_function (pc, &stop_name, NULL, NULL);
if (!stop_func_found)
return (struct exception_event_record *) NULL;
if (strcmp (stop_name, "__cxa_throw") == 0)
{
fi = get_prev_frame (curr_frame);
if (!fi)
return (struct exception_event_record *) NULL;
exception_event->throw_sal = find_pc_line (get_frame_pc (fi), 1);
exception_event->catch_sal.pc = 0x0;
exception_event->catch_sal.line = 0;
exception_event->kind = EX_EVENT_THROW;
}
else if (strcmp (stop_name, "__cxa_begin_catch") == 0)
{
fi = get_prev_frame (curr_frame);
if (!fi)
return (struct exception_event_record *) NULL;
exception_event->catch_sal = find_pc_line (get_frame_pc (fi), 1);
exception_event->throw_sal.pc = 0x0;
exception_event->throw_sal.line = 0;
exception_event->kind = EX_EVENT_CATCH;
}
#ifdef THROW_CATCH_FIND_TYPEINFO
typeinfo_str =
THROW_CATCH_FIND_TYPEINFO (curr_frame, exception_event->kind);
#else
typeinfo_str = NULL;
#endif
if (exception_event->exception_type != NULL)
xfree (exception_event->exception_type);
if (typeinfo_str == NULL)
{
exception_event->exception_type = NULL;
}
else
{
exception_event->exception_type = xstrdup (typeinfo_str);
}
return exception_event;
}
void
update_command (char *args, int from_tty)
{
registers_changed ();
reinit_frame_cache ();
}
void
stack_flush_command (char *args, int from_tty)
{
reinit_frame_cache ();
if (from_tty)
printf_filtered ("Stack cache flushed.\n");
}
static void
open_command (char *args, int from_tty)
{
const char *filename = NULL;
const char *fullname = NULL;
struct stat sb;
int line_no = 0;
warning ("open command no longer supported - may be back in a future build.");
return;
if (args == NULL || args[0] == '\0')
{
filename = NULL;
line_no = 0;
}
else
{
char *colon_pos = strrchr (args, ':');
if (colon_pos == NULL)
line_no = 0;
else
{
line_no = atoi (colon_pos + 1);
*colon_pos = '\0';
}
filename = args;
}
if (filename == NULL)
{
struct symtab_and_line cursal = get_current_source_symtab_and_line ();
if (cursal.symtab)
fullname = symtab_to_fullname (cursal.symtab);
else
error ("No currently selected source file available; "
"please specify one.");
line_no = cursal.line + get_lines_to_list () / 2;
}
if (fullname == NULL)
{
struct symtab *s = lookup_symtab (filename);
if (s)
fullname = symtab_to_fullname (s);
else
error ("Filename '%s' not found in this program's debug information.",
filename);
}
if (stat (fullname, &sb) == 0)
filename = fullname;
else
if (stat (filename, &sb) != 0)
error ("File '%s' not found.", filename);
}
static CFUUIDRef
get_uuidref_for_bfd (struct bfd *abfd)
{
uint8_t uuid[16];
if (abfd == NULL)
return NULL;
if (bfd_mach_o_get_uuid (abfd, uuid, sizeof (uuid)))
return CFUUIDCreateWithBytes (kCFAllocatorDefault,
uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5],
uuid[6], uuid[7], uuid[8], uuid[9], uuid[10], uuid[11],
uuid[12], uuid[13], uuid[14], uuid[15]);
return NULL;
}
static CFMutableArrayRef
gdb_DBGCopyMatchingUUIDsForURL (const char *path)
{
if (path == NULL || path[0] == '\0')
return NULL;
CFAllocatorRef alloc = kCFAllocatorDefault;
CFMutableArrayRef uuid_array = NULL;
struct gdb_exception e;
bfd *abfd;
TRY_CATCH (e, RETURN_MASK_ERROR)
{
abfd = symfile_bfd_open (path, 0);
}
if (abfd == NULL || e.reason == RETURN_ERROR)
return NULL;
if (bfd_check_format (abfd, bfd_archive)
&& strcmp (bfd_get_target (abfd), "mach-o-fat") == 0)
{
bfd *nbfd = NULL;
for (;;)
{
nbfd = bfd_openr_next_archived_file (abfd, nbfd);
if (nbfd == NULL)
break;
if (!bfd_check_format (nbfd, bfd_object)
&& !bfd_check_format (nbfd, bfd_archive))
continue;
CFUUIDRef nbfd_uuid = get_uuidref_for_bfd (nbfd);
if (nbfd_uuid != NULL)
{
if (uuid_array == NULL)
uuid_array = CFArrayCreateMutable(alloc, 0, &kCFTypeArrayCallBacks);
if (uuid_array)
CFArrayAppendValue (uuid_array, nbfd_uuid);
CFRelease (nbfd_uuid);
}
}
}
else
{
CFUUIDRef abfd_uuid = get_uuidref_for_bfd (abfd);
if (abfd_uuid != NULL)
{
if (uuid_array == NULL)
uuid_array = CFArrayCreateMutable(alloc, 0, &kCFTypeArrayCallBacks);
if (uuid_array)
CFArrayAppendValue (uuid_array, abfd_uuid);
CFRelease (abfd_uuid);
}
}
bfd_close (abfd);
return uuid_array;
}
CFMutableDictionaryRef
create_dsym_uuids_for_path (char *dsym_bundle_path)
{
char path[PATH_MAX];
struct dirent* dp = NULL;
DIR* dirp = NULL;
char* dsym_path = NULL;
CFMutableDictionaryRef paths_and_uuids;
strncpy (path, dsym_bundle_path, sizeof (path));
if (path[sizeof (path) - 1])
return NULL;
int path_len = strlen (path);
if (path_len > 0)
{
if (path[path_len-1] != '/')
{
path[path_len] = '/';
if (path_len + 1 < sizeof (path))
path[++path_len] = '\0';
else
return NULL;
}
}
if (dsym_bundle_subdir_len + 1 > sizeof (path) - path_len)
return NULL;
strncat (path, dsym_bundle_subdir, sizeof (path) - path_len - 1);
if (path[sizeof (path) - 1])
return NULL;
dirp = opendir (path);
if (dirp == NULL)
return NULL;
path_len = strlen (path);
paths_and_uuids = CFDictionaryCreateMutable (kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
while (dsym_path == NULL && (dp = readdir (dirp)) != NULL)
{
if (dp->d_type == DT_DIR)
continue;
int full_path_len = path_len + dp->d_namlen + 1;
if (sizeof (path) > full_path_len)
{
CFURLRef path_url = NULL;
CFArrayRef uuid_array = NULL;
strcpy(&path[path_len], dp->d_name);
path_url = CFURLCreateWithBytes (NULL, (UInt8 *) path, full_path_len,
kCFStringEncodingUTF8, NULL);
if (path_url == NULL)
continue;
uuid_array = gdb_DBGCopyMatchingUUIDsForURL (path);
if (uuid_array != NULL)
CFDictionarySetValue (paths_and_uuids, path_url, uuid_array);
CFRelease (path_url);
path_url = NULL;
if (uuid_array != NULL)
CFRelease (uuid_array);
uuid_array = NULL;
}
}
closedir (dirp);
if (CFDictionaryGetCount (paths_and_uuids) == 0)
{
CFRelease (paths_and_uuids);
return NULL;
}
else
return paths_and_uuids;
}
struct search_baton
{
CFUUIDRef test_uuid;
int found_it;
CFURLRef path_url;
};
void
paths_and_uuids_map_func (const void *in_url,
const void *in_array,
void *in_results)
{
const CFURLRef path_url = (CFURLRef) in_url;
const CFArrayRef uuid_array = (CFArrayRef) in_array;
struct search_baton *results = (struct search_baton *) in_results;
const CFIndex count = CFArrayGetCount (uuid_array);
CFIndex i;
if (results->found_it)
return;
for (i = 0; i < count; i++)
{
CFUUIDRef tmp_uuid = CFArrayGetValueAtIndex (uuid_array, i);
if (CFEqual (tmp_uuid, results->test_uuid))
{
results->path_url = path_url;
CFRetain (path_url);
results->found_it = 1;
break;
}
}
}
static char *
locate_dsym_mach_in_bundle (CFUUIDRef uuid_ref, char *dsym_bundle_path)
{
CFMutableDictionaryRef paths_and_uuids;
struct search_baton results;
paths_and_uuids = create_dsym_uuids_for_path (dsym_bundle_path);
if (paths_and_uuids == NULL)
return NULL;
results.found_it = 0;
results.test_uuid = uuid_ref;
CFDictionaryApplyFunction (paths_and_uuids, paths_and_uuids_map_func,
&results);
CFRelease (paths_and_uuids);
if (results.found_it)
{
char path[PATH_MAX];
path[PATH_MAX-1] = '\0';
if (CFURLGetFileSystemRepresentation (results.path_url, 1,
(UInt8 *)path, sizeof (path)))
return xstrdup (path);
else
return NULL;
}
else
return NULL;
}
#if USE_DEBUG_SYMBOLS_FRAMEWORK
static char *
locate_dsym_using_framework (struct objfile *objfile)
{
unsigned char uuid[16];
CFURLRef dsym_bundle_url = NULL;
char* dsym_path = NULL;
if (bfd_mach_o_get_uuid (objfile->obfd, uuid, sizeof (uuid)))
{
CFUUIDRef uuid_ref = CFUUIDCreateWithBytes (kCFAllocatorDefault, uuid[0],
uuid[1], uuid[2], uuid[3],
uuid[4], uuid[5], uuid[6],
uuid[7], uuid[8], uuid[9],
uuid[10], uuid[11], uuid[12],
uuid[13], uuid[14], uuid[15]);
if (uuid_ref == NULL)
return NULL;
dsym_bundle_url = DBGCopyDSYMURLForUUID (uuid_ref);
if (dsym_bundle_url)
{
char path[PATH_MAX];
path[PATH_MAX-1] = '\0';
if (CFURLGetFileSystemRepresentation (dsym_bundle_url, 1,
(UInt8 *)path, sizeof (path)))
{
char *dsym_ext = strcasestr (path, dsym_extension);
int search_bundle_dir = ((dsym_ext == NULL) ||
(dsym_ext[dsym_extension_len] == '\0') ||
(dsym_ext[dsym_extension_len] == '/' &&
dsym_ext[dsym_extension_len+1] == '\0'));
if (search_bundle_dir)
{
dsym_path = locate_dsym_mach_in_bundle (uuid_ref, path);
}
else
{
dsym_path = xstrdup (path);
}
}
CFRelease (dsym_bundle_url);
dsym_bundle_url = NULL;
}
CFRelease (uuid_ref);
uuid_ref = NULL;
}
return dsym_path;
}
#endif
char *
macosx_locate_dsym (struct objfile *objfile)
{
char *basename_str;
char *dot_ptr;
char *slash_ptr;
char *dsymfile;
const char *executable_name;
if (objfile->symflags != OBJF_SYM_ALL)
return NULL;
if (objfile->not_loaded_kext_filename != NULL)
executable_name = objfile->not_loaded_kext_filename;
else
executable_name = objfile->name;
if (strcasestr (executable_name, ".dSYM") == NULL)
{
basename_str = basename (executable_name);
dsymfile = alloca (strlen (executable_name)
+ strlen (APPLE_DSYM_EXT_AND_SUBDIRECTORY)
+ strlen (basename_str)
+ 1);
strcpy (dsymfile, executable_name);
strcat (dsymfile, APPLE_DSYM_EXT_AND_SUBDIRECTORY);
strcat (dsymfile, basename_str);
if (file_exists_p (dsymfile))
return xstrdup (dsymfile);
strcpy (dsymfile, dirname (executable_name));
strcat (dsymfile, "/");
while ((dot_ptr = strrchr (dsymfile, '.')))
{
slash_ptr = strchr (dot_ptr, '/');
if (slash_ptr)
{
*slash_ptr = '\0';
strcat (slash_ptr, APPLE_DSYM_EXT_AND_SUBDIRECTORY);
strcat (slash_ptr, basename_str);
if (file_exists_p (dsymfile))
return xstrdup (dsymfile);
}
*dot_ptr = '\0';
strcat (dot_ptr, APPLE_DSYM_EXT_AND_SUBDIRECTORY);
strcat (dot_ptr, basename_str);
if (file_exists_p (dsymfile))
return xstrdup (dsymfile);
*dot_ptr = '\0';
slash_ptr = strrchr (dsymfile, '/');
if (!slash_ptr)
break;
*slash_ptr = '\0';
}
#if USE_DEBUG_SYMBOLS_FRAMEWORK
if (dsym_locate_enabled)
return locate_dsym_using_framework (objfile);
#endif
}
return NULL;
}
struct objfile *
macosx_find_objfile_matching_dsym_in_bundle (char *dsym_bundle_path, char **out_full_path)
{
CFMutableDictionaryRef paths_and_uuids;
struct search_baton results;
struct objfile *objfile;
struct objfile *out_objfile = NULL;
paths_and_uuids = create_dsym_uuids_for_path (dsym_bundle_path);
if (paths_and_uuids == NULL)
return NULL;
results.found_it = 0;
*out_full_path = NULL;
ALL_OBJFILES (objfile)
{
unsigned char uuid[16];
if (bfd_mach_o_get_uuid (objfile->obfd, uuid, sizeof (uuid)))
{
CFUUIDRef uuid_ref = CFUUIDCreateWithBytes (kCFAllocatorDefault, uuid[0],
uuid[1], uuid[2], uuid[3],
uuid[4], uuid[5], uuid[6],
uuid[7], uuid[8], uuid[9],
uuid[10], uuid[11], uuid[12],
uuid[13], uuid[14], uuid[15]);
if (uuid_ref == NULL)
continue;
results.test_uuid = uuid_ref;
CFDictionaryApplyFunction (paths_and_uuids, paths_and_uuids_map_func,
&results);
CFRelease (uuid_ref);
if (results.found_it)
{
*out_full_path = xmalloc (PATH_MAX);
*(*out_full_path) = '\0';
if (CFURLGetFileSystemRepresentation (results.path_url, 1,
(UInt8 *) (*out_full_path), PATH_MAX - 1))
{
out_objfile = objfile;
}
else
{
warning ("Could not get file system representation for URL:");
CFShow (results.path_url);
*out_full_path = NULL;
out_objfile = NULL;
}
CFRelease (results.path_url);
goto cleanup_and_return;
}
}
else
continue;
}
cleanup_and_return:
CFRelease (paths_and_uuids);
return out_objfile;
}
char *
macosx_kext_info (const char *filename,
const char **bundle_executable_name_from_plist,
const char **bundle_identifier_name_from_plist)
{
char *info_plist_name;
char *t;
*bundle_executable_name_from_plist = NULL;
*bundle_identifier_name_from_plist = NULL;
const void *plist = NULL;
info_plist_name = find_info_plist_filename_from_bundle_name
(filename, ".kext");
if (info_plist_name == NULL)
return NULL;
plist = macosx_parse_plist (info_plist_name);
*bundle_executable_name_from_plist = macosx_get_plist_posix_value (plist,
"CFBundleExecutable");
*bundle_identifier_name_from_plist = macosx_get_plist_string_value (plist,
"CFBundleIdentifier");
macosx_free_plist (&plist);
t = strstr (info_plist_name, "/Contents");
if (t != NULL)
t[0] = '\0';
t = strstr (info_plist_name, "/Info.plist");
if (t != NULL)
t[0] = '\0';
if (*bundle_executable_name_from_plist == NULL
|| *bundle_identifier_name_from_plist == NULL)
return NULL;
else
return info_plist_name;
}
static char *
find_info_plist_filename_from_bundle_name (const char *bundle,
const char *bundle_suffix)
{
char *t;
char *bundle_copy;
char tmp_path[PATH_MAX];
char realpath_buf[PATH_MAX];
char *retval = NULL;
bundle_copy = tilde_expand (bundle);
tmp_path[0] = '\0';
t = strstr (bundle_copy, bundle_suffix);
if (t != NULL && t > bundle_copy)
{
t += strlen (bundle_suffix);
if (t[0] == '/')
{
strncpy (tmp_path, bundle_copy, t - bundle_copy);
tmp_path[t - bundle_copy] = '\0';
}
}
t = strstr (bundle_copy, bundle_suffix);
if (t != NULL && t > bundle_copy && t[strlen (bundle_suffix)] == '\0')
{
strcpy (tmp_path, bundle_copy);
}
if (tmp_path[0] == '\0')
return NULL;
strcpy (realpath_buf, tmp_path);
strcat (realpath_buf, "/Contents/Info.plist");
if (file_exists_p (realpath_buf))
{
retval = realpath_buf;
}
else
{
strcpy (realpath_buf, tmp_path);
strcat (realpath_buf, "/Info.plist");
if (file_exists_p (realpath_buf))
{
retval = realpath_buf;
}
}
if (retval == NULL)
return retval;
tmp_path[0] = '\0';
if (realpath (realpath_buf, tmp_path) == NULL)
retval = xstrdup (realpath_buf);
else
retval = xstrdup (tmp_path);
xfree (bundle_copy);
return retval;
}
extern const bfd_arch_info_type *bfd_default_compatible
(const bfd_arch_info_type *a, const bfd_arch_info_type *b);
static enum gdb_osabi
generic_mach_o_osabi_sniffer_use_dyld_hint (bfd *abfd,
enum bfd_architecture arch,
unsigned long mach_32,
unsigned long mach_64)
{
if (osabi_seen_in_attached_dyld == GDB_OSABI_UNKNOWN)
return GDB_OSABI_UNKNOWN;
bfd *nbfd = NULL;
for (;;)
{
nbfd = bfd_openr_next_archived_file (abfd, nbfd);
if (nbfd == NULL)
break;
if (bfd_check_format (nbfd, bfd_archive))
return GDB_OSABI_UNKNOWN;
if (!bfd_check_format (nbfd, bfd_object))
continue;
if (bfd_default_compatible (bfd_get_arch_info (nbfd),
bfd_lookup_arch (arch,
mach_64))
&& osabi_seen_in_attached_dyld == GDB_OSABI_DARWIN64)
return GDB_OSABI_DARWIN64;
else if (bfd_default_compatible (bfd_get_arch_info (nbfd),
bfd_lookup_arch (arch,
mach_32))
&& osabi_seen_in_attached_dyld == GDB_OSABI_DARWIN)
return GDB_OSABI_DARWIN;
}
return GDB_OSABI_UNKNOWN;
}
enum gdb_osabi
generic_mach_o_osabi_sniffer (bfd *abfd, enum bfd_architecture arch,
unsigned long mach_32,
unsigned long mach_64,
int (*query_64_bit_fn) ())
{
enum gdb_osabi ret;
ret = generic_mach_o_osabi_sniffer_use_dyld_hint (abfd, arch, mach_32, mach_64);
if (ret == GDB_OSABI_DARWIN64 || ret == GDB_OSABI_DARWIN)
return ret;
if (bfd_check_format (abfd, bfd_archive))
{
bfd *nbfd = NULL;
if (strcmp (bfd_get_target (abfd), "mach-o-fat") == 0)
{
enum gdb_osabi best = GDB_OSABI_UNKNOWN;
enum gdb_osabi cur = GDB_OSABI_UNKNOWN;
for (;;)
{
nbfd = bfd_openr_next_archived_file (abfd, nbfd);
if (nbfd == NULL)
break;
if (!bfd_check_format (nbfd, bfd_object)
&& !bfd_check_format (nbfd, bfd_archive))
continue;
cur = generic_mach_o_osabi_sniffer (nbfd, arch,
mach_32, mach_64,
query_64_bit_fn);
if (cur == GDB_OSABI_DARWIN64 &&
best != GDB_OSABI_DARWIN64 && query_64_bit_fn ())
best = cur;
if (cur == GDB_OSABI_DARWIN
&& best != GDB_OSABI_DARWIN64
&& best != GDB_OSABI_DARWIN)
best = cur;
}
return best;
}
else
{
for (;;)
{
nbfd = bfd_openr_next_archived_file (abfd, nbfd);
if (nbfd == NULL)
break;
if (!bfd_check_format (nbfd, bfd_object))
continue;
return generic_mach_o_osabi_sniffer (nbfd, arch,
mach_32, mach_64,
query_64_bit_fn);
}
}
}
if (!bfd_check_format (abfd, bfd_object))
return GDB_OSABI_UNKNOWN;
if (bfd_get_arch (abfd) == arch)
{
if (bfd_default_compatible (bfd_get_arch_info (abfd),
bfd_lookup_arch (arch,
mach_64)))
return GDB_OSABI_DARWIN64;
if (bfd_default_compatible (bfd_get_arch_info (abfd),
bfd_lookup_arch (arch,
mach_32)))
return GDB_OSABI_DARWIN;
return GDB_OSABI_UNKNOWN;
}
return GDB_OSABI_UNKNOWN;
}
int
fast_show_stack_trace_prologue (unsigned int count_limit,
unsigned int print_limit,
unsigned int wordsize,
CORE_ADDR *sigtramp_start_ptr,
CORE_ADDR *sigtramp_end_ptr,
unsigned int *count,
struct frame_info **out_fi,
void (print_fun) (struct ui_out * uiout, int frame_num,
CORE_ADDR pc, CORE_ADDR fp))
{
ULONGEST pc = 0;
struct frame_id selected_frame_id;
struct frame_info *selected_frame;
if (*sigtramp_start_ptr == 0)
{
char *name;
struct minimal_symbol *msymbol;
msymbol = lookup_minimal_symbol ("_sigtramp", NULL, NULL);
if (msymbol == NULL)
warning
("Couldn't find minimal symbol for \"_sigtramp\" - "
"backtraces may be unreliable");
else
{
pc = SYMBOL_VALUE_ADDRESS (msymbol);
if (find_pc_partial_function (pc, &name,
sigtramp_start_ptr, sigtramp_end_ptr) == 0)
{
warning
("Couldn't find minimal bounds for \"_sigtramp\" - "
"backtraces may be unreliable");
*sigtramp_start_ptr = (CORE_ADDR) -1;
*sigtramp_end_ptr = (CORE_ADDR) -1;
}
}
}
selected_frame_id = get_frame_id (get_selected_frame (NULL));
flush_cached_frames ();
selected_frame = frame_find_by_id (selected_frame_id);
if (selected_frame == NULL)
select_frame (get_current_frame ());
else
select_frame (selected_frame);
actually_do_stack_frame_prologue (count_limit,
print_limit,
wordsize,
count,
out_fi,
NULL);
return actually_do_stack_frame_prologue (count_limit,
print_limit,
wordsize,
count,
out_fi,
print_fun);
}
int
actually_do_stack_frame_prologue (unsigned int count_limit,
unsigned int print_limit,
unsigned int wordsize,
unsigned int *count,
struct frame_info **out_fi,
void (print_fun) (struct ui_out * uiout, int frame_num,
CORE_ADDR pc, CORE_ADDR fp))
{
CORE_ADDR fp;
ULONGEST pc;
struct frame_info *fi = NULL;
int i;
int more_frames;
int old_load_state;
start_again:
if (print_fun)
ui_out_begin (uiout, ui_out_type_list, "frames");
i = 0;
more_frames = 1;
pc = 0;
if (i >= count_limit)
{
more_frames = 0;
goto count_finish;
}
fi = get_current_frame ();
if (fi == NULL)
{
more_frames = -1;
goto count_finish;
}
old_load_state = pc_set_load_state (get_frame_pc (fi), OBJF_SYM_ALL, 0);
if (old_load_state >= 0 && old_load_state != OBJF_SYM_ALL && print_fun == NULL)
{
flush_cached_frames ();
goto start_again;
}
if (print_fun && (i < print_limit))
print_fun (uiout, i, get_frame_pc (fi), get_frame_base (fi));
i = 1;
do
{
if (i >= count_limit)
{
more_frames = 0;
goto count_finish;
}
fi = get_prev_frame (fi);
if (fi == NULL)
{
more_frames = 0;
goto count_finish;
}
pc = get_frame_pc (fi);
fp = get_frame_base (fi);
old_load_state = pc_set_load_state (pc, OBJF_SYM_ALL, 0);
if (old_load_state >= 0 && old_load_state != OBJF_SYM_ALL && print_fun == NULL)
{
flush_cached_frames ();
goto start_again;
}
if (print_fun && (i < print_limit))
print_fun (uiout, i, pc, fp);
i++;
if (!backtrace_past_main && inside_main_func (fi)
&& get_frame_type (fi) != INLINED_FRAME)
{
more_frames = 0;
goto count_finish;
}
}
while (i < 5);
count_finish:
*out_fi = fi;
*count = i;
return more_frames;
}
void
_initialize_macosx_tdep ()
{
struct cmd_list_element *c;
macosx_symbol_types_init ();
add_info ("trampoline", info_trampoline_command,
"Resolve function for DYLD trampoline stub and/or Objective-C call");
c = add_com ("open", class_support, open_command, _("\
Open the named source file in an application determined by LaunchServices.\n\
With no arguments, open the currently selected source file.\n\
Also takes file:line to hilight the file at the given line."));
set_cmd_completer (c, filename_completer);
add_com_alias ("op", "open", class_support, 1);
add_com_alias ("ope", "open", class_support, 1);
add_com ("flushstack", class_maintenance, stack_flush_command,
"Force gdb to flush its stack-frame cache (maintainer command)");
add_com_alias ("flush", "flushregs", class_maintenance, 1);
add_com ("update", class_obscure, update_command,
"Re-read current state information from inferior.");
add_setshow_boolean_cmd ("locate-dsym", class_obscure,
&dsym_locate_enabled, _("\
Set locate dSYM files using the DebugSymbols framework."), _("\
Show locate dSYM files using the DebugSymbols framework."), _("\
If set, gdb will try and locate dSYM files using the DebugSymbols framework."),
NULL, NULL,
&setlist, &showlist);
}