macosx-nat-dyld-process.c [plain text]
#include "defs.h"
#include "inferior.h"
#include "symtab.h"
#include "gdbcmd.h"
#include "objfiles.h"
#include "mach-o.h"
#include "gdbcore.h"
#include "gdb_regex.h"
#include "gdb-stabs.h"
#include "gdb_assert.h"
#include "interps.h"
#include "objc-lang.h"
#include "gdb_stat.h"
#include "arch-utils.h"
#include "gdbarch.h"
#include "symfile.h"
#include "gdb_stat.h"
#include <mach-o/nlist.h>
#include <mach-o/loader.h>
#ifdef USE_MMALLOC
#include "mmprivate.h"
#endif
#if defined (TARGET_POWERPC)
#include "ppc-macosx-tdep.h"
#elif defined(TARGET_I386)
#include "i386-tdep.h"
#elif defined(TARGET_ARM)
#include "arm-tdep.h"
#endif
#include <sys/mman.h>
#include <string.h>
#include "macosx-nat-dyld-info.h"
#include "macosx-nat-dyld-path.h"
#include "macosx-nat-dyld-io.h"
#include "macosx-nat-dyld.h"
#include "macosx-nat-inferior.h"
#include "macosx-nat-mutils.h"
#include "macosx-nat-dyld-process.h"
#define INVALID_ADDRESS ((CORE_ADDR) (-1))
extern int dyld_preload_libraries_flag;
extern int dyld_filter_events_flag;
extern int dyld_always_read_from_memory_flag;
extern char *dyld_symbols_prefix;
extern int dyld_load_dyld_symbols_flag;
extern int dyld_load_dyld_shlib_symbols_flag;
extern int dyld_load_cfm_shlib_symbols_flag;
extern int dyld_print_basenames_flag;
extern int dyld_reload_on_downgrade_flag;
extern char *dyld_load_rules;
extern char *dyld_minimal_load_rules;
static int dyld_check_uuids_flag = 0;
#if defined(TARGET_POWERPC)
#include "ppc-tdep.h"
#elif defined (TARGET_I386)
#include "amd64-tdep.h"
#include "i386-tdep.h"
#elif defined (TARGET_ARM)
#include "arm-tdep.h"
#else
#error "Unrecognized target architecture."
#endif
#if WITH_CFM
extern int inferior_auto_start_cfm_flag;
#endif
extern macosx_inferior_status *macosx_status;
extern macosx_dyld_thread_status macosx_dyld_status;
struct bfd_memory_footprint {
const char *filename;
CORE_ADDR seg1addr;
int num;
int num_allocated;
struct bfd_memory_footprint_group *groups;
};
struct bfd_memory_footprint_group {
int offset;
int length;
};
static void mark_buckets_as_used (struct pre_run_memory_map *map, int i, struct bfd_memory_footprint *fp);
static int
dyld_print_status ()
{
return !ui_out_is_mi_like_p (uiout);
}
void
dyld_add_inserted_libraries (struct dyld_objfile_info *info,
const struct dyld_path_info *d)
{
const char *s1, *s2;
CHECK_FATAL (info != NULL);
CHECK_FATAL (d != NULL);
s1 = d->insert_libraries;
if (s1 == NULL)
{
return;
}
while (*s1 != '\0')
{
struct dyld_objfile_entry *e = NULL;
char *tmp_name, *real_name;
s2 = strchr (s1, ':');
if (s2 == NULL)
{
s2 = strchr (s1, '\0');
}
CHECK_FATAL (s2 != NULL);
tmp_name = savestring (s1, (s2 - s1));
char *fixed_name = dyld_fix_path (tmp_name);
if (fixed_name != tmp_name)
{
xfree (tmp_name);
tmp_name = fixed_name;
}
real_name = xmalloc (PATH_MAX + 1);
if (realpath (tmp_name, real_name) != NULL)
{
e = dyld_objfile_entry_alloc (info);
e->user_name = real_name;
e->reason = dyld_reason_init;
}
else
warning ("Couldn't get real path for inserted library %s\n", tmp_name);
xfree (tmp_name);
s1 = s2;
while (*s1 == ':')
{
s1++;
}
}
}
void
dyld_add_image_libraries (struct dyld_objfile_info *info, bfd *abfd)
{
struct mach_o_data_struct *mdata = NULL;
int i;
CHECK_FATAL (info != NULL);
if (abfd == NULL)
{
return;
}
if (!bfd_mach_o_valid (abfd))
{
return;
}
mdata = abfd->tdata.mach_o_data;
if (mdata == NULL)
{
dyld_debug ("dyld_add_image_libraries: mdata == NULL\n");
return;
}
for (i = 0; i < mdata->header.ncmds; i++)
{
struct bfd_mach_o_load_command *cmd = &mdata->commands[i];
switch (cmd->type)
{
case BFD_MACH_O_LC_REEXPORT_DYLIB:
case BFD_MACH_O_LC_LOAD_WEAK_DYLIB:
case BFD_MACH_O_LC_LOAD_DYLINKER:
case BFD_MACH_O_LC_LOAD_DYLIB:
case BFD_MACH_O_LC_LOAD_UPWARD_DYLIB:
{
struct dyld_objfile_entry *e = NULL;
char *name = NULL;
char *fixed_name = NULL;
switch (cmd->type)
{
case BFD_MACH_O_LC_LOAD_DYLINKER:
{
bfd_mach_o_dylinker_command *dcmd = &cmd->command.dylinker;
name = xmalloc (dcmd->name_len + 1);
bfd_seek (abfd, dcmd->name_offset, SEEK_SET);
if (bfd_bread (name, dcmd->name_len, abfd) != dcmd->name_len)
{
warning
("Unable to find library name for LC_LOAD_DYLINKER command; ignoring");
xfree (name);
continue;
}
name[dcmd->name_len] = '\0';
fixed_name = dyld_fix_path (name);
if (fixed_name != name)
{
xfree (name);
name = fixed_name;
}
break;
}
case BFD_MACH_O_LC_LOAD_DYLIB:
case BFD_MACH_O_LC_LOAD_UPWARD_DYLIB:
case BFD_MACH_O_LC_LOAD_WEAK_DYLIB:
case BFD_MACH_O_LC_REEXPORT_DYLIB:
{
bfd_mach_o_dylib_command *dcmd = &cmd->command.dylib;
name = xmalloc (dcmd->name_len + 1);
bfd_seek (abfd, dcmd->name_offset, SEEK_SET);
if (bfd_bread (name, dcmd->name_len, abfd) != dcmd->name_len)
{
warning
("Unable to find library name for LC_LOAD_DYLIB, LC_LOAD_UPWARD_DYLIB, LC_LOAD_WEAK_DYLIB or LC_REEXPORT_DYLIB command; ignoring");
xfree (name);
continue;
}
name[dcmd->name_len] = '\0';
if (name[0] == '@'
&& (strncmp (name, "@rpath", 6) == 0
|| strncmp (name, "@loader_path", 12) == 0))
{
xfree (name);
name = NULL;
break;
}
fixed_name = dyld_fix_path (name);
if (fixed_name != name)
{
xfree (name);
name = fixed_name;
}
break;
}
default:
abort ();
}
if (name == NULL)
continue;
if (name[0] == '\0')
{
warning
("No image name specified by LC_LOAD command; ignoring");
xfree (name);
name = NULL;
}
{
char buf[PATH_MAX];
if (realpath (name, buf) != NULL)
{
xfree (name);
name = xstrdup (buf);
}
}
if (name)
{
int j, skip_this_dylib = 0;
DYLD_ALL_OBJFILE_INFO_ENTRIES (info, e, j)
{
if (e->reason == dyld_reason_init && e->text_name_valid == 1
&& e->text_name && strcmp (e->text_name, name) == 0)
skip_this_dylib = 1;
}
if (skip_this_dylib)
{
xfree (name);
continue;
}
}
e = dyld_objfile_entry_alloc (info);
e->text_name = name;
e->text_name_valid = 1;
e->reason = dyld_reason_init;
switch (cmd->type)
{
case BFD_MACH_O_LC_LOAD_DYLINKER:
e->prefix = dyld_symbols_prefix;
break;
case BFD_MACH_O_LC_LOAD_DYLIB:
case BFD_MACH_O_LC_LOAD_UPWARD_DYLIB:
case BFD_MACH_O_LC_REEXPORT_DYLIB:
break;
case BFD_MACH_O_LC_LOAD_WEAK_DYLIB:
e->reason |= dyld_reason_weak_mask;
break;
default:
abort ();
};
}
default:
break;
}
}
}
void
dyld_resolve_filename_image (const struct macosx_dyld_thread_status *s,
struct dyld_objfile_entry *e)
{
struct mach_header header;
CHECK_FATAL (e->allocated);
if (e->image_name_valid)
{
return;
}
if (!e->dyld_valid)
{
return;
}
target_read_memory (e->dyld_addr, (gdb_byte *) &header,
sizeof (struct mach_header));
switch (header.filetype)
{
case MH_DYLINKER:
case MH_DYLIB:
break;
case MH_BUNDLE:
case BFD_MACH_O_MH_BUNDLE_KEXT:
break;
default:
return;
}
e->image_name = dyld_find_dylib_name (header.ncmds, e->dyld_addr);
if (e->image_name == NULL)
{
dyld_debug ("Unable to determine filename for loaded object "
"(no LC_ID load command)\n");
}
else
{
dyld_debug ("Determined filename for loaded object from image\n");
e->image_name_valid = 1;
}
}
char *
dyld_find_dylib_name (CORE_ADDR addr, int ncmds)
{
CORE_ADDR curpos;
int i;
char *image_name = NULL;
curpos = addr + sizeof (struct mach_header);
for (i = 0; i < ncmds; i++)
{
struct load_command cmd;
struct dylib_command dcmd;
struct dylinker_command dlcmd;
char name[256];
target_read_memory (curpos, (gdb_byte *) &cmd,
sizeof (struct load_command));
if (cmd.cmd == LC_ID_DYLIB)
{
target_read_memory (curpos, (gdb_byte *) &dcmd,
sizeof (struct dylib_command));
target_read_memory (curpos + dcmd.dylib.name.offset, (gdb_byte *) name, 256);
image_name = savestring (name, strlen (name));
break;
}
else if (cmd.cmd == LC_ID_DYLINKER)
{
target_read_memory (curpos, (gdb_byte *) &dlcmd,
sizeof (struct dylinker_command));
target_read_memory (curpos + dlcmd.name.offset, (gdb_byte *) name, 256);
image_name = savestring (name, strlen (name));
break;
}
curpos += cmd.cmdsize;
}
return image_name;
}
void
dyld_resolve_filenames (const struct macosx_dyld_thread_status *s,
struct dyld_objfile_info *new)
{
int i;
struct dyld_objfile_entry *e;
CHECK_FATAL (s != NULL);
CHECK_FATAL (new != NULL);
DYLD_ALL_OBJFILE_INFO_ENTRIES (new, e, i)
{
if (e->dyld_name_valid)
continue;
dyld_resolve_filename_image (s, e);
}
}
static CORE_ADDR
library_offset (struct dyld_objfile_entry *e)
{
int wordsize = gdbarch_tdep (current_gdbarch)->wordsize;
CHECK_FATAL (e != NULL);
if (e->image_addr_valid && e->dyld_valid)
{
if (wordsize == 4)
CHECK_FATAL (e->dyld_addr ==
((e->image_addr + e->dyld_slide) & 0xffffffff));
else
CHECK_FATAL (e->dyld_addr == e->image_addr + e->dyld_slide);
}
if (e->dyld_valid)
return e->dyld_addr;
else if (e->loaded_from_memory)
return e->loaded_addr;
else if (e->image_addr_valid)
if (e->pre_run_slide_addr_valid)
if (wordsize == 4)
return (e->image_addr + e->pre_run_slide_addr) & 0xffffffff;
else
return e->image_addr + e->pre_run_slide_addr;
else
return e->image_addr;
else
return 0;
}
int
dyld_parse_load_level (const char *s)
{
if (strcmp (s, "all") == 0)
{
return OBJF_SYM_ALL;
}
else if (strcmp (s, "container") == 0)
{
return OBJF_SYM_CONTAINER;
}
else if (strcmp (s, "extern") == 0)
{
return OBJF_SYM_EXTERN;
}
else if (strcmp (s, "none") == 0)
{
return OBJF_SYM_NONE;
}
else
{
warning ("unknown setting \"%s\"; using \"none\"\n", s);
return OBJF_SYM_NONE;
}
}
int
dyld_resolve_load_flag (const struct dyld_path_info *d,
struct dyld_objfile_entry *e, const char *rules)
{
const char *name = NULL;
const char *leaf = NULL;
char **prules = NULL;
char **trule = NULL;
int nrules = 0;
int crule = 0;
name = dyld_entry_string (e, 1);
if (name == NULL)
return OBJF_SYM_NONE;
leaf = strrchr (name, '/');
leaf = ((leaf != NULL) ? leaf : name);
if (rules != NULL)
{
prules = buildargv (rules);
if (prules == NULL)
{
warning ("unable to parse load rules");
return OBJF_SYM_NONE;
}
}
nrules = 0;
if (prules != NULL)
{
for (trule = prules; *trule != NULL; trule++)
{
nrules++;
}
}
if ((nrules % 3) != 0)
{
warning
("unable to parse load-rules (number of rule clauses must be a "
"multiple of 3)");
return OBJF_SYM_NONE;
}
nrules /= 3;
for (crule = 0; crule < nrules; crule++)
{
char *matchreason = prules[crule * 3];
char *matchname = prules[(crule * 3) + 1];
char *setting = prules[(crule * 3) + 2];
const char *reason = NULL;
const char *name = NULL;
regex_t reasonbuf;
regex_t namebuf;
int ret;
switch (e->reason & dyld_reason_type_mask)
{
case dyld_reason_user:
reason = "user";
break;
case dyld_reason_init:
reason = "dyld";
break;
case dyld_reason_executable:
reason = "exec";
break;
case dyld_reason_dyld:
reason = "dyld";
break;
case dyld_reason_cfm:
reason = "cfm";
break;
default:
reason = "INVALID";
break;
}
if (e->objfile)
{
if (e->loaded_from_memory)
{
name = "memory";
}
else
{
name = e->loaded_name;
}
}
else
{
name = dyld_entry_filename (e, d, DYLD_ENTRY_FILENAME_LOADED);
if (name == NULL)
{
if (!(e->reason & dyld_reason_weak_mask))
{
warning ("Unable to resolve \"%s\"; not loading.", name);
}
return OBJF_SYM_NONE;
}
}
ret = regcomp (&reasonbuf, matchreason, REG_NOSUB);
if (ret != 0)
{
warning ("unable to compile regular expression \"%s\"",
matchreason);
continue;
}
ret = regcomp (&namebuf, matchname, REG_NOSUB);
if (ret != 0)
{
warning ("unable to compile regular expression \"%s\"",
matchreason);
continue;
}
ret = regexec (&reasonbuf, reason, 0, 0, 0);
if (ret != 0)
continue;
ret = regexec (&namebuf, name, 0, 0, 0);
if (ret != 0)
continue;
return dyld_parse_load_level (setting);
}
return -1;
}
int
dyld_minimal_load_flag (const struct dyld_path_info *d,
struct dyld_objfile_entry *e)
{
int ret = dyld_resolve_load_flag (d, e, dyld_minimal_load_rules);
return (ret >= 0) ? ret : OBJF_SYM_NONE;
}
int
dyld_default_load_flag (const struct dyld_path_info *d,
struct dyld_objfile_entry *e)
{
int ret = dyld_resolve_load_flag (d, e, dyld_load_rules);
if (ret >= 0)
return ret;
if (e->reason != dyld_reason_cfm)
{
if (dyld_load_dyld_shlib_symbols_flag)
return OBJF_SYM_ALL;
}
else
{
if (dyld_load_cfm_shlib_symbols_flag)
return OBJF_SYM_ALL;
}
return OBJF_SYM_NONE;
}
#define IS_ALIGNED_TO_4096_P(num) (((num) & ~(4096 - 1)) == (num))
#define ALIGN_TO_4096(num) (IS_ALIGNED_TO_4096_P((num)) ? \
(num) : \
((num) + 4096) & ~(4096 - 1))
static struct bfd_memory_footprint *
scan_bfd_for_memory_groups (struct bfd *abfd, struct pre_run_memory_map *map)
{
asection *asect;
int seg1addr_set = 0;
CORE_ADDR current_bucket_start_addr = (CORE_ADDR)-1;
CORE_ADDR current_bucket_end_addr = (CORE_ADDR)-1;
struct bfd_memory_footprint *fp = (struct bfd_memory_footprint *)
xmalloc (sizeof (struct bfd_memory_footprint));
fp->groups = (struct bfd_memory_footprint_group *)
xmalloc (sizeof (struct bfd_memory_footprint_group) * 2);
fp->num = 0;
fp->num_allocated = 2;
fp->filename = abfd->filename;
for (asect = abfd->sections; asect != NULL; asect = asect->next)
{
CORE_ADDR this_seg_start, this_seg_end, this_seg_len;
if (asect->segment_mark == 0)
continue;
if (strcmp (asect->name, "LC_SEGMENT.__PAGEZERO") == 0)
continue;
this_seg_start = bfd_section_vma (abfd, asect);
this_seg_len = bfd_section_size (abfd, asect);
this_seg_end = this_seg_start + this_seg_len;
this_seg_end = ALIGN_TO_4096 (this_seg_end);
if (this_seg_start == 0)
continue;
if (seg1addr_set == 0)
{
seg1addr_set = 1;
fp->seg1addr = this_seg_start;
fp->groups[0].offset = 0;
current_bucket_start_addr = this_seg_start;
current_bucket_end_addr = current_bucket_start_addr +
((this_seg_len / map->bucket_size) + 1) * map->bucket_size;
if (current_bucket_end_addr < current_bucket_start_addr)
current_bucket_end_addr = (CORE_ADDR) -1;
continue;
}
if (this_seg_end < current_bucket_end_addr)
{
continue;
}
if (this_seg_start <= current_bucket_end_addr + map->bucket_size
&& this_seg_end > current_bucket_end_addr)
{
current_bucket_end_addr = current_bucket_start_addr +
(((this_seg_end - current_bucket_start_addr) /
map->bucket_size) + 1)
* map->bucket_size;
if (current_bucket_end_addr < current_bucket_start_addr)
current_bucket_end_addr = (CORE_ADDR) -1;
continue;
}
fp->groups[fp->num].length =
(current_bucket_end_addr - current_bucket_start_addr) /
map->bucket_size;
fp->num++;
if (fp->num == fp->num_allocated)
{
fp->num_allocated *= 2;
fp->groups = (struct bfd_memory_footprint_group *)
xrealloc (fp->groups,
sizeof (struct bfd_memory_footprint_group) * fp->num_allocated);
}
fp->groups[fp->num].offset = ((this_seg_start - current_bucket_end_addr)
/ map->bucket_size) + 1
+ fp->groups[fp->num - 1].length;
current_bucket_start_addr = this_seg_start;
current_bucket_end_addr = current_bucket_start_addr +
((this_seg_len / map->bucket_size) + 1) * map->bucket_size;
if (current_bucket_end_addr < current_bucket_start_addr)
current_bucket_end_addr = (CORE_ADDR) -1;
}
if (seg1addr_set != 0)
{
fp->groups[fp->num].length =
(current_bucket_end_addr - current_bucket_start_addr) /
map->bucket_size;
CORE_ADDR recalculated_endaddr = current_bucket_start_addr +
(map->bucket_size * fp->groups[fp->num].length);
if (recalculated_endaddr < current_bucket_end_addr)
fp->groups[fp->num].length += 1;
fp->num++;
}
else
{
fp->groups[0].offset = 0;
fp->groups[0].length = 0;
}
return fp;
}
struct pre_run_memory_map *
create_pre_run_memory_map (struct bfd *abfd)
{
struct bfd_memory_footprint *fp;
int i;
struct pre_run_memory_map *map = (struct pre_run_memory_map *)
xmalloc (sizeof (struct pre_run_memory_map));
if (gdbarch_tdep (current_gdbarch)->wordsize == 4)
{
map->number_of_buckets = 400;
map->bucket_size = UINT_MAX / map->number_of_buckets;
map->bucket_size &= ~(4096 - 1);
}
else
{
map->number_of_buckets = 4000;
map->bucket_size = ULLONG_MAX / map->number_of_buckets;
map->bucket_size &= ~(4096 - 1);
}
map->buckets = (int *) xmalloc (sizeof (int) * map->number_of_buckets);
memset (map->buckets, 0, map->number_of_buckets * sizeof (int));
fp = scan_bfd_for_memory_groups (abfd, map);
i = fp->seg1addr / map->bucket_size;
mark_buckets_as_used (map, i, fp);
return map;
}
static int
find_next_hole (struct pre_run_memory_map *map,
int starting_bucket,
int buckets)
{
int i;
i = starting_bucket;
while (i < map->number_of_buckets)
{
int j;
if (i + buckets >= map->number_of_buckets)
return -1;
if (map->buckets[i] == 1)
{
i++;
continue;
}
j = i;
while (j - i < buckets)
{
if (map->buckets[j] == 0)
j++;
else
break;
}
if (j - i == buckets)
{
return i;
}
i = j + 1;
}
return -1;
}
static int
hole_at_p (struct pre_run_memory_map *map,
int starting_bucket,
int buckets)
{
int i = starting_bucket;
if (starting_bucket >= map->number_of_buckets)
return 0;
while (i - starting_bucket < buckets
&& i < map->number_of_buckets
&& map->buckets[i] == 0)
{
i++;
}
if (i - starting_bucket == buckets)
return 1;
else
return 0;
}
static void
mark_buckets_as_used (struct pre_run_memory_map *map, int startingbucket,
struct bfd_memory_footprint *fp)
{
int memgrp, k;
for (memgrp = 0; memgrp < fp->num; memgrp++)
{
struct bfd_memory_footprint_group *group = &fp->groups[memgrp];
int initial_bkt = startingbucket + group->offset;
if (initial_bkt + group->length > map->number_of_buckets)
warning ("sharedlibrary preload-libraries exceeded map array while "
"processing '%s'", fp->filename);
for (k = 0; k < group->length; k++)
if (initial_bkt + k < map->number_of_buckets)
map->buckets[initial_bkt + k] = 1;
}
}
void
free_pre_run_memory_map (struct pre_run_memory_map *map)
{
if (map)
xfree (map->buckets);
xfree (map);
}
static void
free_memory_footprint (struct bfd_memory_footprint *fp)
{
if (fp)
xfree (fp->groups);
xfree (fp);
}
static CORE_ADDR
slide_bfd_in_pre_run_memory_map (struct bfd *abfd,
struct pre_run_memory_map *map)
{
int i = 0;
int j, k;
int intended_loadaddr_bucket;
struct bfd_memory_footprint *fp;
CORE_ADDR intended_loadaddr;
int can_load_at_preferred_addr;
fp = scan_bfd_for_memory_groups (abfd, map);
intended_loadaddr = fp->seg1addr;
intended_loadaddr_bucket = fp->seg1addr / map->bucket_size;
can_load_at_preferred_addr = 1;
for (k = 0; k < fp->num; k++)
if (!hole_at_p (map, intended_loadaddr_bucket, fp->groups[k].length))
{
can_load_at_preferred_addr = 0;
break;
}
if (can_load_at_preferred_addr)
{
mark_buckets_as_used (map, intended_loadaddr_bucket, fp);
free_memory_footprint (fp);
return 0;
}
while (i < map->number_of_buckets)
{
j = find_next_hole (map, i, fp->groups[0].length);
if (j == -1)
{
free_memory_footprint (fp);
return 0;
}
for (k = 1; k < fp->num; k++)
{
if (!hole_at_p (map, j + fp->groups[k].offset, fp->groups[k].length))
break;
}
if (k == fp->num)
{
CORE_ADDR loadaddr;
mark_buckets_as_used (map, j, fp);
free_memory_footprint (fp);
loadaddr = map->bucket_size * j;
return loadaddr - intended_loadaddr;
}
i += fp->groups[0].length;
}
free_memory_footprint (fp);
return 0;
}
void
dyld_load_library_from_file (const struct dyld_path_info *d,
struct dyld_objfile_entry *e,
int print_errors)
{
const char *name = NULL;
struct stat dummy;
name = dyld_entry_filename (e, d, DYLD_ENTRY_FILENAME_LOADED);
if (name == NULL)
{
if (print_errors)
{
char *s = dyld_entry_string (e, 1);
warning ("No image filename available for %s.", s);
xfree (s);
}
return;
}
if (stat (name, &dummy) != 0)
{
if ((print_errors) && (! (e->reason & dyld_reason_weak_mask)))
{
#if !(defined (TARGET_ARM) && defined (NM_NEXTSTEP))
char *s = dyld_entry_string (e, 1);
warning ("Unable to read symbols for %s (file not found).", s);
xfree (s);
#endif
}
return;
}
{
struct ui_file *prev_stderr = gdb_stderr;
gdb_stderr = gdb_null;
CHECK_FATAL (e->abfd == NULL);
e->abfd = symfile_bfd_open_safe (name, 0, GDB_OSABI_UNKNOWN);
gdb_stderr = prev_stderr;
if (e->abfd == NULL)
{
#if 0
if (print_errors)
warning (error_last_message ());
#endif
return;
}
}
e->loaded_name = bfd_get_filename (e->abfd);
e->loaded_from_memory = 0;
e->loaded_error = 0;
}
void
dyld_load_library_from_memory (const struct dyld_path_info *d,
struct dyld_objfile_entry *e,
int print_errors)
{
const char *name = NULL;
if (!e->dyld_valid && !core_bfd)
{
if (print_errors)
{
#if !(defined (TARGET_ARM) && defined (NM_NEXTSTEP))
char *s = dyld_entry_string (e, dyld_print_basenames_flag);
warning ("Unable to read symbols from %s (not yet mapped into memory).", s);
xfree (s);
#endif
}
return;
}
name = dyld_entry_filename (e, d, DYLD_ENTRY_FILENAME_LOADED);
CHECK_FATAL (e->abfd == NULL);
CORE_ADDR slide = e->dyld_slide;
CORE_ADDR length = e->dyld_length;
if (core_bfd)
{
slide = INVALID_ADDRESS;
}
if (e->dyld_length == 0)
{
length = INVALID_ADDRESS;
}
e->abfd = inferior_bfd (name, e->dyld_addr, slide, length);
if (e->abfd == NULL)
{
warning ("Could not read dyld entry: %s from inferior memory at 0x%s "
"with slide 0x%s and length %lu.", name, paddr_nz (e->dyld_addr),
paddr_nz (slide), length);
return;
}
e->loaded_memaddr = e->dyld_addr;
e->loaded_from_memory = 1;
e->loaded_error = 0;
}
void
dyld_load_library (const struct dyld_path_info *d,
struct dyld_objfile_entry *e)
{
int read_from_memory = 0;
int print_errors = 1;
CHECK_FATAL (e->allocated);
if ((e->abfd != NULL) || (e->objfile != NULL))
return;
if (e->reason & dyld_reason_executable_mask)
CHECK_FATAL (e->objfile == symfile_objfile);
try_again_please:
print_errors = !e->loaded_error;
if (e->reason == dyld_reason_cfm)
read_from_memory = 1;
if (dyld_always_read_from_memory_flag)
read_from_memory = 1;
if (core_bfd)
read_from_memory = 1;
if (read_from_memory)
dyld_load_library_from_memory (d, e, print_errors);
else if (e->abfd == NULL)
{
dyld_load_library_from_file (d, e, print_errors);
if (e->abfd == NULL)
{
read_from_memory = 1;
if (target_is_remote ())
{
e->load_flag = OBJF_SYM_CONTAINER;
}
goto try_again_please;
}
else if (bfd_mach_o_stub_library (e->abfd) || bfd_mach_o_encrypted_binary (e->abfd))
{
e->load_flag = OBJF_SYM_CONTAINER | OBJF_SYM_DONT_CHANGE;
bfd_close (e->abfd);
e->abfd = NULL;
e->loaded_name = NULL;
read_from_memory = 1;
goto try_again_please;
}
else if (dyld_check_uuids_flag && e->dyld_valid)
{
struct mach_o_data_struct *mdata = NULL;
int i;
bfd_vma uuid_addr = (bfd_vma) -1;
unsigned char mem_uuid[16];
int matches = 0;
unsigned char file_uuid[16];
CHECK_FATAL (bfd_mach_o_valid (e->abfd));
mdata = e->abfd->tdata.mach_o_data;
for (i = 0; i < mdata->header.ncmds; i++)
{
if (mdata->commands[i].type == BFD_MACH_O_LC_UUID)
{
uuid_addr = mdata->commands[i].offset;
bfd_mach_o_get_uuid (e->abfd, file_uuid, sizeof (file_uuid));
break;
}
}
if (uuid_addr != (bfd_vma) -1)
{
struct gdb_exception exc;
int error = 0;
int found_uuid = 0;
uuid_addr += e->dyld_addr;
TRY_CATCH (exc, RETURN_MASK_ALL)
{
error = target_read_uuid (uuid_addr, mem_uuid);
}
if (exc.reason == NO_ERROR && error == 0)
matches = (memcmp(mem_uuid, file_uuid, sizeof (file_uuid)) == 0);
if (!matches)
{
struct mach_header header;
bfd_vma curpos;
struct load_command cmd;
target_read_mach_header (e->dyld_addr, &header);
curpos = e->dyld_addr + target_get_mach_header_size (&header);
for (i = 0; i < header.ncmds; i++)
{
if (target_read_load_command (curpos, &cmd) != 0)
break;
if (cmd.cmd == BFD_MACH_O_LC_UUID)
{
if (target_read_uuid (curpos, mem_uuid) == 0)
found_uuid = 1;
break;
}
curpos += cmd.cmdsize;
}
matches = (memcmp(mem_uuid, file_uuid, sizeof (file_uuid)) == 0);
}
if (!matches)
{
warning (_("UUID mismatch detected with the loaded library "
"- on disk is:\n\t%s"),
e->abfd->filename);
if (ui_out_is_mi_like_p (uiout))
{
struct cleanup *notify_cleanup =
make_cleanup_ui_out_notify_begin_end (uiout,
"uuid-mismatch-with-loaded-file");
ui_out_field_string (uiout, "file", e->abfd->filename);
do_cleanups (notify_cleanup);
}
bfd_close (e->abfd);
e->abfd = NULL;
e->loaded_name = NULL;
read_from_memory = 1;
goto try_again_please;
}
}
}
}
if (e->abfd == NULL)
{
e->loaded_error = 1;
return;
}
if (e->reason & dyld_reason_init && macosx_dyld_status.pre_run_memory_map)
{
CORE_ADDR addr = slide_bfd_in_pre_run_memory_map (e->abfd,
macosx_dyld_status.pre_run_memory_map);
e->pre_run_slide_addr_valid = 1;
e->pre_run_slide_addr = addr;
}
if (e->reason & dyld_reason_image_mask)
{
asection *text_sect =
bfd_get_section_by_name (e->abfd, TEXT_SEGMENT_NAME);
if (text_sect != NULL)
{
e->image_addr = bfd_section_vma (e->abfd, text_sect);
e->image_addr_valid = 1;
}
}
if (e->reason & dyld_reason_executable_mask)
symfile_objfile = e->objfile;
}
void
dyld_load_libraries (const struct dyld_path_info *d,
struct dyld_objfile_info *result)
{
int i;
struct dyld_objfile_entry *e;
CHECK_FATAL (result != NULL);
DYLD_ALL_OBJFILE_INFO_ENTRIES (result, e, i)
{
if (e->load_flag < 0)
{
e->load_flag =
dyld_default_load_flag (d, e) | dyld_minimal_load_flag (d, e);
}
if (e->load_flag)
{
dyld_load_library (d, e);
}
}
}
void
dyld_symfile_loaded_hook (struct objfile *o)
{
if (o == find_libobjc_objfile ())
{
objc_init_trampoline_observer ();
objc_init_runtime_version ();
}
}
void
dyld_slide_objfile (struct objfile *objfile, CORE_ADDR dyld_slide,
struct section_offsets *new_offsets)
{
int i;
if (objfile)
{
struct cleanup *offset_cleanup;
if (new_offsets == NULL)
{
new_offsets =
(struct section_offsets *)
xmalloc (SIZEOF_N_SECTION_OFFSETS (objfile->num_sections));
for (i = 0; i < objfile->num_sections; i++)
{
new_offsets->offsets[i] = dyld_slide;
}
offset_cleanup = make_cleanup (xfree, new_offsets);
}
else
offset_cleanup = make_cleanup (null_cleanup, NULL);
objfile_relocate (objfile, new_offsets);
tell_objc_msgsend_cacher_objfile_changed (objfile);
if (info_verbose)
printf_filtered ("Relocating symbols from %s...", objfile->name);
gdb_flush (gdb_stdout);
if (objfile->separate_debug_objfile != NULL)
{
struct section_offsets *dsym_offsets;
int num_dsym_offsets;
macho_calculate_offsets_for_dsym (objfile,
objfile->separate_debug_objfile->obfd,
NULL,
new_offsets,
objfile->num_sections,
&dsym_offsets,
&num_dsym_offsets);
make_cleanup (xfree, dsym_offsets);
objfile_relocate (objfile->separate_debug_objfile, dsym_offsets);
}
do_cleanups (offset_cleanup);
if (info_verbose)
printf_filtered ("done\n");
}
}
static void
dyld_load_symfile_internal (struct dyld_objfile_entry *e,
int preserving_objfile_p)
{
struct section_addr_info *addrs;
int i;
int using_orig_objfile = 0;
if (e->loaded_error)
return;
CHECK_FATAL (e->allocated);
if (e->reason & dyld_reason_executable_mask)
CHECK_FATAL (e->objfile == symfile_objfile);
if (e->dyld_valid)
{
e->loaded_addr = e->dyld_addr;
e->loaded_addrisoffset = 0;
}
else if (e->image_addr_valid)
{
e->loaded_addr = e->image_addr;
e->loaded_addrisoffset = 0;
}
else
{
e->loaded_addr = e->dyld_slide;
e->loaded_addrisoffset = 1;
}
if (e->loaded_from_memory == 1)
{
e->loaded_memaddr = e->loaded_addr;
}
if (e->objfile != NULL && !preserving_objfile_p)
{
dyld_slide_objfile (e->objfile, e->dyld_slide, e->dyld_section_offsets);
}
else
{
volatile struct gdb_exception exc;
CHECK_FATAL (e->abfd != NULL);
if (dyld_objfile_entry_in_shared_cache(e)
&& e->dyld_section_offsets == NULL
&& e->dyld_valid)
e->dyld_section_offsets =
get_sectoffs_for_shared_cache_dylib (e, e->loaded_addr);
if (e->dyld_section_offsets == NULL)
{
addrs = alloc_section_addr_info (bfd_count_sections (e->abfd));
for (i = 0; i < addrs->num_sections; i++)
{
addrs->other[i].name = NULL;
if (e->dyld_valid == 0 && e->pre_run_slide_addr_valid == 1)
addrs->other[i].addr = e->pre_run_slide_addr;
else
addrs->other[i].addr = e->dyld_slide;
addrs->other[i].sectindex = 0;
}
addrs->addrs_are_offsets = 1;
}
else
addrs = NULL;
if (e->objfile == NULL)
{
e->objfile = symbol_file_add_bfd_safe (e->abfd,
0,
addrs,
e->dyld_section_offsets,
0, 0,
e->load_flag,
0,
e->prefix, NULL);
}
else
{
using_orig_objfile = 1;
int i, num_offsets;
struct bfd_section *this_sect;
num_offsets = 0;
if (e->dyld_section_offsets != NULL)
{
this_sect = e->abfd->sections;
for (i = 0;
i < bfd_count_sections (e->abfd);
i++, this_sect = this_sect->next)
{
if (objfile_keeps_section (e->abfd, this_sect))
num_offsets++;
}
}
TRY_CATCH (exc, RETURN_MASK_ALL)
{
e->objfile =
symbol_file_add_with_addrs_or_offsets_using_objfile (e->objfile,
e->abfd,
0,
addrs,
e->dyld_section_offsets,
num_offsets,
0, 0,
e->load_flag,
0,
e->prefix, NULL);
}
if (exc.reason == RETURN_ERROR)
e->objfile = NULL;
}
e->abfd = NULL;
if (e->objfile == NULL)
{
e->loaded_error = 1;
return;
}
e->loaded_name = e->objfile->name;
const char *segname = "LC_SEGMENT.__DATA.__commpage";
asection *commsec;
commsec = bfd_get_section_by_name (e->objfile->obfd, segname);
if (commsec != NULL)
{
char *buf;
bfd_size_type len;
char *bfdname;
len = bfd_section_size (e->objfile->obfd, commsec);
buf = xmalloc (len * sizeof (char));
bfdname = xmalloc (strlen (e->objfile->obfd->filename) + 128);
sprintf (bfdname, "%s[%s]", e->objfile->obfd->filename, segname);
if (bfd_get_section_contents
(e->objfile->obfd, commsec, buf, 0, len) != TRUE)
warning ("unable to read commpage data");
e->commpage_bfd = bfd_memopenr (bfdname, NULL, (bfd_byte *) buf, len);
if (!bfd_check_format (e->commpage_bfd, bfd_object))
{
bfd_close (e->commpage_bfd);
e->commpage_bfd = NULL;
}
if (e->commpage_bfd != NULL)
{
if (!using_orig_objfile)
{
e->commpage_objfile =
symbol_file_add_bfd_safe (e->commpage_bfd,
0,
NULL,
0,
0, 0,
e->load_flag,
0,
e->prefix, NULL);
}
else
{
TRY_CATCH (exc, RETURN_MASK_ALL)
{
e->commpage_objfile =
symbol_file_add_bfd_using_objfile (e->commpage_objfile,
e->commpage_bfd,
0,
NULL,
0,
0, 0,
e->load_flag,
0,
e->prefix);
}
if (exc.reason == RETURN_ERROR)
e->commpage_objfile = NULL;
}
}
e->commpage_bfd = NULL;
}
}
dyld_symfile_loaded_hook (e->objfile);
if (e->reason & dyld_reason_executable_mask)
{
CHECK_FATAL ((symfile_objfile == NULL)
|| (symfile_objfile == e->objfile));
symfile_objfile = e->objfile;
return;
}
}
void
dyld_load_symfile (struct dyld_objfile_entry *e)
{
dyld_load_symfile_internal (e, 0);
}
void
dyld_load_symfile_preserving_objfile (struct dyld_objfile_entry *e)
{
dyld_load_symfile_internal (e, 1);
}
void
dyld_load_symfiles (struct dyld_objfile_info *result)
{
int i;
int first = 1;
struct dyld_objfile_entry *e;
CHECK_FATAL (result != NULL);
DYLD_ALL_OBJFILE_INFO_ENTRIES (result, e, i)
{
char load_char;
if (e->loaded_error)
continue;
if (e->abfd == NULL && e->objfile == NULL)
continue;
if (e->objfile != NULL)
{
if (e->dyld_valid && e->loaded_addr == e->dyld_addr
&& !e->loaded_addrisoffset)
continue;
if (e->dyld_valid && e->loaded_addr == e->dyld_slide
&& e->loaded_addrisoffset)
continue;
if (e->image_addr_valid && e->loaded_addr == e->image_addr
&& !e->loaded_addrisoffset)
continue;
if (!e->dyld_valid && !e->image_addr_valid)
continue;
}
load_char = (e->objfile != NULL) ? '+' : '.';
if (first && !info_verbose && dyld_print_status ())
{
first = 0;
printf_filtered ("Reading symbols for shared libraries ");
gdb_flush (gdb_stdout);
}
dyld_load_symfile (e);
if (!info_verbose && dyld_print_status ())
{
printf_filtered ("%c", load_char);
gdb_flush (gdb_stdout);
}
}
if (!first && !info_verbose && dyld_print_status ())
{
printf_filtered (" done\n");
gdb_flush (gdb_stdout);
}
}
struct objfile *
dyld_lookup_objfile_safe (struct dyld_objfile_entry *e)
{
struct objfile *o, *temp;
ALL_OBJFILES_SAFE (o, temp)
if (e->objfile == o)
return o;
return NULL;
}
int
dyld_objfile_allocated (struct objfile *o)
{
struct objfile *objfile, *temp;
ALL_OBJFILES_SAFE (objfile, temp)
{
if (o == objfile)
{
return 1;
}
}
return 0;
}
void
dyld_purge_objfiles (struct dyld_objfile_info *info)
{
struct dyld_objfile_entry *e;
int i;
DYLD_ALL_OBJFILE_INFO_ENTRIES (info, e, i)
if (e->objfile != NULL)
if (dyld_lookup_objfile_safe (e) == NULL)
dyld_remove_objfile (e);
}
struct dyld_objfile_entry *
dyld_lookup_objfile_entry (struct dyld_objfile_info *info, struct objfile *o)
{
int i;
struct dyld_objfile_entry *e;
DYLD_ALL_OBJFILE_INFO_ENTRIES (info, e, i)
if (e->objfile == o)
return e;
return NULL;
}
enum dyld_reload_result
dyld_should_reload_objfile_for_flags (struct dyld_objfile_entry *e)
{
if (e->load_flag == e->objfile->symflags)
return DYLD_NO_CHANGE;
else if (e->objfile->symflags & OBJF_SYM_DONT_CHANGE)
{
e->load_flag = e->objfile->symflags;
return DYLD_NO_CHANGE;
}
else if (e->load_flag & ~e->objfile->symflags)
return DYLD_UPGRADE;
else
{
if (dyld_reload_on_downgrade_flag)
return DYLD_DOWNGRADE;
else
return DYLD_NO_CHANGE;
}
}
void
remove_objfile_from_dyld_records (struct objfile *obj)
{
struct dyld_objfile_info *info = &macosx_dyld_status.current_info;
struct dyld_objfile_entry *e;
int i;
DYLD_ALL_OBJFILE_INFO_ENTRIES (info, e, i)
if (e->objfile == obj)
dyld_remove_objfile (e);
}
extern int inferior_auto_start_dyld_flag;
int
dyld_is_objfile_loaded (struct objfile *obj)
{
if (inferior_auto_start_dyld_flag == 0)
return 1;
struct dyld_objfile_entry *e;
int i;
struct macosx_dyld_thread_status *status = &macosx_dyld_status;
if (obj == NULL)
return 0;
if (obj->separate_debug_objfile_backlink != NULL)
return dyld_is_objfile_loaded (obj->separate_debug_objfile_backlink);
if (obj->syms_only_objfile == 1)
return 1;
if (bfd_hash_lookup (&obj->obfd->section_htab, "LC_ID_DYLINKER", 0, 0) != NULL)
return 1;
DYLD_ALL_OBJFILE_INFO_ENTRIES (&status->current_info, e, i)
if (e->objfile == obj || e->commpage_objfile == obj)
if (e->dyld_name != NULL
|| (e->dyld_addr != 0 && e->dyld_addr != INVALID_ADDRESS))
return 1;
return 0;
}
void
dyld_remove_objfile_internal (struct dyld_objfile_entry *e,
int delete_p)
{
char *s = NULL;
CHECK_FATAL (e->allocated);
if (e->reason & dyld_reason_executable_mask)
CHECK_FATAL (e->objfile == symfile_objfile);
if (e->objfile == NULL)
{
return;
}
CHECK_FATAL (dyld_objfile_allocated (e->objfile));
s = dyld_entry_string (e, dyld_print_basenames_flag);
if (info_verbose)
{
printf_filtered ("Removing symbols for %s\n", s);
}
xfree (s);
gdb_flush (gdb_stdout);
if (delete_p)
{
free_objfile (e->objfile);
e->objfile = NULL;
}
else
clear_objfile (e->objfile);
if (e->abfd != NULL)
bfd_close (e->abfd);
e->abfd = NULL;
if (e->dyld_section_offsets != NULL)
{
xfree (e->dyld_section_offsets);
e->dyld_section_offsets = NULL;
}
if (e->commpage_objfile != NULL)
{
if (delete_p)
{
free_objfile (e->commpage_objfile);
e->commpage_objfile = NULL;
}
else
clear_objfile (e->commpage_objfile);
if (e->commpage_bfd != NULL)
bfd_close (e->commpage_bfd);
e->commpage_bfd = NULL;
}
e->loaded_name = NULL;
e->loaded_memaddr = 0;
e->pre_run_slide_addr_valid = 0;
e->pre_run_slide_addr = 0;
gdb_flush (gdb_stdout);
if (e->reason & dyld_reason_executable_mask)
{
symfile_objfile = e->objfile;
}
}
void
dyld_remove_objfile (struct dyld_objfile_entry *e)
{
dyld_remove_objfile_internal (e, 1);
}
void
dyld_clear_objfile (struct dyld_objfile_entry *e)
{
dyld_remove_objfile_internal (e, 0);
}
void
dyld_remove_objfiles (const struct dyld_path_info *d,
struct dyld_objfile_info *result)
{
int i;
int first = 1;
struct dyld_objfile_entry *e;
CHECK_FATAL (result != NULL);
DYLD_ALL_OBJFILE_INFO_ENTRIES (result, e, i)
{
int should_reload = 0;
if (e->load_flag < 0)
{
e->load_flag =
dyld_default_load_flag (d, e) | dyld_minimal_load_flag (d, e);
}
if (e->reason & dyld_reason_executable_mask)
CHECK_FATAL (e->objfile == symfile_objfile);
if (e->objfile != NULL)
{
if (e->user_name != NULL
&& strcmp (e->user_name, e->objfile->name) != 0)
should_reload = 1;
if (dyld_should_reload_objfile_for_flags (e))
should_reload = 1;
}
if (should_reload)
{
dyld_remove_objfile (e);
if (first && !info_verbose && dyld_print_status ())
{
first = 0;
printf_filtered ("Removing symbols for unused shared libraries ");
gdb_flush (gdb_stdout);
}
if (!info_verbose && dyld_print_status ())
{
printf_filtered (".");
gdb_flush (gdb_stdout);
}
}
}
if (!first && !info_verbose && dyld_print_status ())
{
printf_filtered (" done\n");
gdb_flush (gdb_stdout);
}
}
static int
dyld_libraries_similar (struct dyld_path_info *d,
struct dyld_objfile_entry *f,
struct dyld_objfile_entry *l)
{
const char *fname = NULL;
const char *lname = NULL;
const char *fbase = NULL;
const char *lbase = NULL;
int flen = 0;
int llen = 0;
CHECK_FATAL (f != NULL);
CHECK_FATAL (l != NULL);
if (library_offset (f) != 0 && library_offset (l) != 0)
{
return (library_offset (f) == library_offset (l));
}
fname = dyld_entry_filename (f, d, DYLD_ENTRY_FILENAME_LOADED);
lname = dyld_entry_filename (l, d, DYLD_ENTRY_FILENAME_LOADED);
if (lname != NULL && fname != NULL)
{
int f_is_framework, f_is_bundle;
int l_is_framework, l_is_bundle;
dyld_library_basename (fname, &fbase, &flen, &f_is_framework,
&f_is_bundle);
dyld_library_basename (lname, &lbase, &llen, &l_is_framework,
&l_is_bundle);
if (flen != llen || strncmp (fbase, lbase, llen) != 0)
{
xfree ((char *) fbase);
xfree ((char *) lbase);
return 0;
}
xfree ((char *) fbase);
xfree ((char *) lbase);
if (f_is_framework != l_is_framework)
return 0;
if (f_is_bundle != l_is_bundle)
return 0;
return 1;
}
return 0;
}
int
dyld_libraries_compatible (struct dyld_path_info *d,
struct dyld_objfile_entry *newent,
struct dyld_objfile_entry *oldent)
{
const char *newname = NULL;
const char *oldname = NULL;
CHECK_FATAL (oldent != NULL);
CHECK_FATAL (newent != NULL);
if (oldent->prefix != NULL || newent->prefix != NULL)
{
if (oldent->prefix == NULL || newent->prefix == NULL)
return 0;
if (strcmp (oldent->prefix, newent->prefix) != 0)
return 0;
}
newname = dyld_entry_filename (newent, d, DYLD_ENTRY_FILENAME_LOADED);
oldname = dyld_entry_filename (oldent, d, DYLD_ENTRY_FILENAME_LOADED);
if (oldent->loaded_from_memory && oldent->loaded_addr == newent->dyld_addr)
return dyld_libraries_similar (d, newent, oldent);
if (oldname != NULL || newname != NULL)
{
if (oldname == NULL || newname == NULL)
return 0;
if (oldent->loaded_from_memory && newent->loaded_from_memory)
{
char *mem_obj_str = "[memory object \"";
int offset = strlen (mem_obj_str);
if ((strstr (newname, mem_obj_str) == newname
&& strstr (newname, oldname) == newname + offset)
||(strstr (oldname, mem_obj_str) == oldname
&& strstr (oldname, newname) == oldname + offset))
return dyld_libraries_similar (d, newent, oldent);
}
else
{
if (strcmp (oldname, newname) != 0)
return 0;
}
}
if (oldent->loaded_from_memory != newent->loaded_from_memory)
{
return 0;
}
return dyld_libraries_similar (d, newent, oldent);
}
void
dyld_objfile_move_load_data (struct dyld_objfile_entry *src,
struct dyld_objfile_entry *dst)
{
bfd *dst_bfd = NULL;
bfd *src_bfd = NULL;
int reload = 0;
enum gdb_osabi reload_osabi = GDB_OSABI_UNKNOWN;
gdb_assert (dst->commpage_bfd == NULL);
if (dst->abfd)
dst_bfd = dst->abfd;
else if (dst->objfile && dst->objfile->obfd)
dst_bfd = dst->objfile->obfd;
if (src->abfd)
src_bfd = src->abfd;
else if (src->objfile && src->objfile->obfd)
src_bfd = src->objfile->obfd;
if (dst_bfd && src_bfd)
{
struct mach_o_data_struct *dst_mdata = dst_bfd->tdata.mach_o_data;
struct mach_o_data_struct *src_mdata = src_bfd->tdata.mach_o_data;
if (dst_mdata && src_mdata && dst_mdata != src_mdata)
{
if (dst_mdata->header.magic != src_mdata->header.magic ||
dst_mdata->header.cputype != src_mdata->header.cputype ||
dst_mdata->header.cpusubtype != src_mdata->header.cpusubtype)
{
reload = 1;
reload_osabi = macosx_get_osabi_from_dyld_entry (dst_bfd);
}
}
}
if (dst-> abfd != NULL && src->abfd != dst->abfd)
bfd_close (dst->abfd);
gdb_assert (src->objfile == dst->objfile || dst->objfile == NULL);
gdb_assert (dst->commpage_objfile == NULL);
dst->abfd = src->abfd;
dst->objfile = src->objfile;
if (reload)
reread_symbols_for_objfile (dst->objfile, 0, reload_osabi, NULL);
if (src->dyld_valid == 0
&& dst->dyld_valid == 1
&& src->pre_run_slide_addr_valid == 1
&& src->pre_run_slide_addr != 0)
{
dyld_slide_objfile (dst->objfile, dst->dyld_slide, 0);
}
dst->commpage_bfd = src->commpage_bfd;
dst->commpage_objfile = src->commpage_objfile;
if (src->load_flag > 0 && dst->load_flag < 0)
{
dst->load_flag = src->load_flag;
}
dst->prefix = src->prefix;
dst->loaded_name = src->loaded_name;
dst->loaded_memaddr = src->loaded_memaddr;
dst->loaded_addr = src->loaded_addr;
dst->loaded_offset = src->loaded_offset;
dst->loaded_addrisoffset = src->loaded_addrisoffset;
dst->loaded_from_memory = src->loaded_from_memory;
dst->loaded_error = src->loaded_error;
dst->pre_run_slide_addr_valid = src->pre_run_slide_addr_valid;
dst->pre_run_slide_addr = src->pre_run_slide_addr;
src->objfile = NULL;
src->abfd = NULL;
src->dyld_section_offsets = NULL;
src->commpage_bfd = NULL;
src->commpage_objfile = NULL;
src->load_flag = -1;
src->loaded_name = NULL;
src->loaded_memaddr = 0;
src->loaded_addr = 0;
src->loaded_offset = 0;
src->loaded_addrisoffset = 0;
src->loaded_from_memory = 0;
src->loaded_error = 0;
src->pre_run_slide_addr = 0;
src->pre_run_slide_addr_valid = 0;
dyld_objfile_entry_clear (src);
}
void
dyld_check_discarded (struct dyld_objfile_info *info)
{
int j;
for (j = 0; j < info->nents; j++)
{
struct dyld_objfile_entry *e = &info->entries[j];
if (e->abfd == NULL && e->objfile == NULL && !e->loaded_error)
{
dyld_objfile_entry_clear (e);
}
}
}
void
dyld_merge_shlib (const struct macosx_dyld_thread_status *s,
struct dyld_path_info *d,
struct dyld_objfile_info *oldinfos,
struct dyld_objfile_entry *newent)
{
int i;
struct dyld_objfile_entry *oldent;
DYLD_ALL_OBJFILE_INFO_ENTRIES (oldinfos, oldent, i)
if (dyld_libraries_compatible (d, newent, oldent))
{
dyld_objfile_move_load_data (oldent, newent);
if (newent->reason & dyld_reason_executable_mask)
symfile_objfile = newent->objfile;
return;
}
if (newent->reason & dyld_reason_image_mask)
DYLD_ALL_OBJFILE_INFO_ENTRIES (oldinfos, oldent, i)
if (oldent->objfile != NULL && dyld_libraries_similar (d, newent, oldent))
{
dyld_objfile_move_load_data (oldent, newent);
if (newent->reason & dyld_reason_executable_mask)
symfile_objfile = newent->objfile;
return;
}
}
void
dyld_prune_shlib (struct dyld_path_info *d,
struct dyld_objfile_info *obj_info,
struct dyld_objfile_entry *new)
{
struct dyld_objfile_entry *o;
int i;
DYLD_ALL_OBJFILE_INFO_ENTRIES (obj_info, o, i)
{
if ((o->reason & dyld_reason_executable_mask)
&& (new->reason & dyld_reason_executable_mask))
{
if (o->objfile != NULL && o->objfile != new->objfile)
{
tell_breakpoints_objfile_changed (o->objfile);
tell_objc_msgsend_cacher_objfile_changed (o->objfile);
}
dyld_objfile_entry_clear (o);
continue;
}
if (dyld_libraries_similar (d, o, new))
{
if (o->objfile != NULL)
{
tell_breakpoints_objfile_changed (o->objfile);
tell_objc_msgsend_cacher_objfile_changed (o->objfile);
}
dyld_remove_objfile (o);
dyld_objfile_entry_clear (o);
}
}
}
void
dyld_merge_shlibs (const struct macosx_dyld_thread_status *s,
struct dyld_path_info *d,
struct dyld_objfile_info *old,
struct dyld_objfile_info *new)
{
struct dyld_objfile_entry *n = NULL;
struct dyld_objfile_entry *o = NULL;
int i;
CHECK_FATAL (old != NULL);
CHECK_FATAL (new != NULL);
CHECK_FATAL (old != new);
dyld_resolve_filenames (s, new);
DYLD_ALL_OBJFILE_INFO_ENTRIES (new, n, i)
if (n->objfile == NULL)
dyld_merge_shlib (s, d, old, n);
DYLD_ALL_OBJFILE_INFO_ENTRIES (new, n, i)
dyld_prune_shlib (d, old, n);
DYLD_ALL_OBJFILE_INFO_ENTRIES (old, o, i)
{
struct dyld_objfile_entry *e = NULL;
e = dyld_objfile_entry_alloc (new);
*e = *o;
e->reason |= dyld_reason_cached_mask;
dyld_objfile_entry_clear (o);
}
}
static void
dyld_shlibs_updated (struct dyld_objfile_info *info)
{
dyld_objfile_info_pack (info);
update_section_tables_dyld (info);
update_current_target ();
reread_symbols ();
breakpoint_update ();
re_enable_breakpoints_in_shlibs (0);
}
void
dyld_update_shlibs (struct dyld_path_info *d, struct dyld_objfile_info *result)
{
struct cleanup *timer_cleanup = NULL;
static int dyld_timer = -1;
CHECK_FATAL (result != NULL);
if (maint_use_timers)
timer_cleanup = start_timer (&dyld_timer, "dyld_update_shlibs", "");
dyld_debug ("dyld_update_shlibs: updating shared library information\n");
dyld_remove_objfiles (d, result);
dyld_load_libraries (d, result);
dyld_load_symfiles (result);
dyld_shlibs_updated (result);
if (maint_use_timers)
do_cleanups (timer_cleanup);
}
void
dyld_purge_cached_libraries (struct dyld_objfile_info *info)
{
int i;
struct dyld_objfile_entry *e;
CHECK_FATAL (info != NULL);
DYLD_ALL_OBJFILE_INFO_ENTRIES (info, e, i)
if (e->reason & dyld_reason_cached_mask)
{
dyld_remove_objfile (e);
dyld_objfile_entry_clear (e);
}
dyld_shlibs_updated (info);
}
void
_initialize_macosx_nat_dyld_process ()
{
add_setshow_boolean_cmd ("check-uuids", class_obscure,
&dyld_check_uuids_flag, _("\
Set if GDB should check the binary UUID between the file on disk and the one loaded in memory."), _("\
Set if GDB should check the binary UUID between the file on disk and the one loaded in memory."), NULL,
NULL, NULL,
&setshliblist, &showshliblist);
}