| /* Handle Darwin shared libraries for GDB, the GNU Debugger. | 
 |  | 
 |    Copyright (C) 2009-2022 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/>.  */ | 
 |  | 
 | #include "defs.h" | 
 |  | 
 | #include "symtab.h" | 
 | #include "bfd.h" | 
 | #include "symfile.h" | 
 | #include "objfiles.h" | 
 | #include "gdbcore.h" | 
 | #include "target.h" | 
 | #include "inferior.h" | 
 | #include "regcache.h" | 
 | #include "gdbthread.h" | 
 | #include "gdb_bfd.h" | 
 |  | 
 | #include "solist.h" | 
 | #include "solib.h" | 
 | #include "solib-svr4.h" | 
 |  | 
 | #include "bfd-target.h" | 
 | #include "elf-bfd.h" | 
 | #include "exec.h" | 
 | #include "auxv.h" | 
 | #include "mach-o.h" | 
 | #include "mach-o/external.h" | 
 |  | 
 | struct gdb_dyld_image_info | 
 | { | 
 |   /* Base address (which corresponds to the Mach-O header).  */ | 
 |   CORE_ADDR mach_header; | 
 |   /* Image file path.  */ | 
 |   CORE_ADDR file_path; | 
 |   /* st.m_time of image file.  */ | 
 |   unsigned long mtime; | 
 | }; | 
 |  | 
 | /* Content of inferior dyld_all_image_infos structure. | 
 |    See /usr/include/mach-o/dyld_images.h for the documentation.  */ | 
 | struct gdb_dyld_all_image_infos | 
 | { | 
 |   /* Version (1).  */ | 
 |   unsigned int version; | 
 |   /* Number of images.  */ | 
 |   unsigned int count; | 
 |   /* Image description.  */ | 
 |   CORE_ADDR info; | 
 |   /* Notifier (function called when a library is added or removed).  */ | 
 |   CORE_ADDR notifier; | 
 | }; | 
 |  | 
 | /* Current all_image_infos version.  */ | 
 | #define DYLD_VERSION_MIN 1 | 
 | #define DYLD_VERSION_MAX 15 | 
 |  | 
 | /* Per PSPACE specific data.  */ | 
 | struct darwin_info | 
 | { | 
 |   /* Address of structure dyld_all_image_infos in inferior.  */ | 
 |   CORE_ADDR all_image_addr = 0; | 
 |  | 
 |   /* Gdb copy of dyld_all_info_infos.  */ | 
 |   struct gdb_dyld_all_image_infos all_image {}; | 
 | }; | 
 |  | 
 | /* Per-program-space data key.  */ | 
 | static program_space_key<darwin_info> solib_darwin_pspace_data; | 
 |  | 
 | /* Get the current darwin data.  If none is found yet, add it now.  This | 
 |    function always returns a valid object.  */ | 
 |  | 
 | static struct darwin_info * | 
 | get_darwin_info (void) | 
 | { | 
 |   struct darwin_info *info; | 
 |  | 
 |   info = solib_darwin_pspace_data.get (current_program_space); | 
 |   if (info != NULL) | 
 |     return info; | 
 |  | 
 |   return solib_darwin_pspace_data.emplace (current_program_space); | 
 | } | 
 |  | 
 | /* Return non-zero if the version in dyld_all_image is known.  */ | 
 |  | 
 | static int | 
 | darwin_dyld_version_ok (const struct darwin_info *info) | 
 | { | 
 |   return info->all_image.version >= DYLD_VERSION_MIN | 
 |     && info->all_image.version <= DYLD_VERSION_MAX; | 
 | } | 
 |  | 
 | /* Read dyld_all_image from inferior.  */ | 
 |  | 
 | static void | 
 | darwin_load_image_infos (struct darwin_info *info) | 
 | { | 
 |   gdb_byte buf[24]; | 
 |   enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ()); | 
 |   struct type *ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr; | 
 |   int len; | 
 |  | 
 |   /* If the structure address is not known, don't continue.  */ | 
 |   if (info->all_image_addr == 0) | 
 |     return; | 
 |  | 
 |   /* The structure has 4 fields: version (4 bytes), count (4 bytes), | 
 |      info (pointer) and notifier (pointer).  */ | 
 |   len = 4 + 4 + 2 * TYPE_LENGTH (ptr_type); | 
 |   gdb_assert (len <= sizeof (buf)); | 
 |   memset (&info->all_image, 0, sizeof (info->all_image)); | 
 |  | 
 |   /* Read structure raw bytes from target.  */ | 
 |   if (target_read_memory (info->all_image_addr, buf, len)) | 
 |     return; | 
 |  | 
 |   /* Extract the fields.  */ | 
 |   info->all_image.version = extract_unsigned_integer (buf, 4, byte_order); | 
 |   if (!darwin_dyld_version_ok (info)) | 
 |     return; | 
 |  | 
 |   info->all_image.count = extract_unsigned_integer (buf + 4, 4, byte_order); | 
 |   info->all_image.info = extract_typed_address (buf + 8, ptr_type); | 
 |   info->all_image.notifier = extract_typed_address | 
 |     (buf + 8 + TYPE_LENGTH (ptr_type), ptr_type); | 
 | } | 
 |  | 
 | /* Link map info to include in an allocated so_list entry.  */ | 
 |  | 
 | struct lm_info_darwin : public lm_info_base | 
 | { | 
 |   /* The target location of lm.  */ | 
 |   CORE_ADDR lm_addr = 0; | 
 | }; | 
 |  | 
 | /* Lookup the value for a specific symbol.  */ | 
 |  | 
 | static CORE_ADDR | 
 | lookup_symbol_from_bfd (bfd *abfd, const char *symname) | 
 | { | 
 |   long storage_needed; | 
 |   asymbol **symbol_table; | 
 |   unsigned int number_of_symbols; | 
 |   unsigned int i; | 
 |   CORE_ADDR symaddr = 0; | 
 |  | 
 |   storage_needed = bfd_get_symtab_upper_bound (abfd); | 
 |  | 
 |   if (storage_needed <= 0) | 
 |     return 0; | 
 |  | 
 |   symbol_table = (asymbol **) xmalloc (storage_needed); | 
 |   number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table); | 
 |  | 
 |   for (i = 0; i < number_of_symbols; i++) | 
 |     { | 
 |       asymbol *sym = symbol_table[i]; | 
 |  | 
 |       if (strcmp (sym->name, symname) == 0 | 
 | 	  && (sym->section->flags & (SEC_CODE | SEC_DATA)) != 0) | 
 | 	{ | 
 | 	  /* BFD symbols are section relative.  */ | 
 | 	  symaddr = sym->value + sym->section->vma; | 
 | 	  break; | 
 | 	} | 
 |     } | 
 |   xfree (symbol_table); | 
 |  | 
 |   return symaddr; | 
 | } | 
 |  | 
 | /* Return program interpreter string.  */ | 
 |  | 
 | static char * | 
 | find_program_interpreter (void) | 
 | { | 
 |   char *buf = NULL; | 
 |  | 
 |   /* If we have an current exec_bfd, get the interpreter from the load | 
 |      commands.  */ | 
 |   if (current_program_space->exec_bfd ()) | 
 |     { | 
 |       bfd_mach_o_load_command *cmd; | 
 |  | 
 |       if (bfd_mach_o_lookup_command (current_program_space->exec_bfd (), | 
 | 				     BFD_MACH_O_LC_LOAD_DYLINKER, &cmd) == 1) | 
 | 	return cmd->command.dylinker.name_str; | 
 |     } | 
 |  | 
 |   /* If we didn't find it, read from memory. | 
 |      FIXME: todo.  */ | 
 |   return buf; | 
 | } | 
 |  | 
 | /*  Not used.  I don't see how the main symbol file can be found: the | 
 |     interpreter name is needed and it is known from the executable file. | 
 |     Note that darwin-nat.c implements pid_to_exec_file.  */ | 
 |  | 
 | static int | 
 | open_symbol_file_object (int from_tty) | 
 | { | 
 |   return 0; | 
 | } | 
 |  | 
 | /* Build a list of currently loaded shared objects.  See solib-svr4.c.  */ | 
 |  | 
 | static struct so_list * | 
 | darwin_current_sos (void) | 
 | { | 
 |   struct type *ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr; | 
 |   enum bfd_endian byte_order = type_byte_order (ptr_type); | 
 |   int ptr_len = TYPE_LENGTH (ptr_type); | 
 |   unsigned int image_info_size; | 
 |   struct so_list *head = NULL; | 
 |   struct so_list *tail = NULL; | 
 |   int i; | 
 |   struct darwin_info *info = get_darwin_info (); | 
 |  | 
 |   /* Be sure image infos are loaded.  */ | 
 |   darwin_load_image_infos (info); | 
 |  | 
 |   if (!darwin_dyld_version_ok (info)) | 
 |     return NULL; | 
 |  | 
 |   image_info_size = ptr_len * 3; | 
 |  | 
 |   /* Read infos for each solib. | 
 |      The first entry was rumored to be the executable itself, but this is not | 
 |      true when a large number of shared libraries are used (table expanded ?). | 
 |      We now check all entries, but discard executable images.  */ | 
 |   for (i = 0; i < info->all_image.count; i++) | 
 |     { | 
 |       CORE_ADDR iinfo = info->all_image.info + i * image_info_size; | 
 |       gdb_byte buf[image_info_size]; | 
 |       CORE_ADDR load_addr; | 
 |       CORE_ADDR path_addr; | 
 |       struct mach_o_header_external hdr; | 
 |       unsigned long hdr_val; | 
 |  | 
 |       /* Read image info from inferior.  */ | 
 |       if (target_read_memory (iinfo, buf, image_info_size)) | 
 | 	break; | 
 |  | 
 |       load_addr = extract_typed_address (buf, ptr_type); | 
 |       path_addr = extract_typed_address (buf + ptr_len, ptr_type); | 
 |  | 
 |       /* Read Mach-O header from memory.  */ | 
 |       if (target_read_memory (load_addr, (gdb_byte *) &hdr, sizeof (hdr) - 4)) | 
 | 	break; | 
 |       /* Discard wrong magic numbers.  Shouldn't happen.  */ | 
 |       hdr_val = extract_unsigned_integer | 
 | 	(hdr.magic, sizeof (hdr.magic), byte_order); | 
 |       if (hdr_val != BFD_MACH_O_MH_MAGIC && hdr_val != BFD_MACH_O_MH_MAGIC_64) | 
 | 	continue; | 
 |       /* Discard executable.  Should happen only once.  */ | 
 |       hdr_val = extract_unsigned_integer | 
 | 	(hdr.filetype, sizeof (hdr.filetype), byte_order); | 
 |       if (hdr_val == BFD_MACH_O_MH_EXECUTE) | 
 | 	continue; | 
 |  | 
 |       gdb::unique_xmalloc_ptr<char> file_path | 
 | 	= target_read_string (path_addr, SO_NAME_MAX_PATH_SIZE - 1); | 
 |       if (file_path == nullptr) | 
 | 	break; | 
 |  | 
 |       /* Create and fill the new so_list element.  */ | 
 |       gdb::unique_xmalloc_ptr<struct so_list> newobj (XCNEW (struct so_list)); | 
 |  | 
 |       lm_info_darwin *li = new lm_info_darwin; | 
 |       newobj->lm_info = li; | 
 |  | 
 |       strncpy (newobj->so_name, file_path.get (), SO_NAME_MAX_PATH_SIZE - 1); | 
 |       newobj->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0'; | 
 |       strcpy (newobj->so_original_name, newobj->so_name); | 
 |       li->lm_addr = load_addr; | 
 |  | 
 |       if (head == NULL) | 
 | 	head = newobj.get (); | 
 |       else | 
 | 	tail->next = newobj.get (); | 
 |       tail = newobj.release (); | 
 |     } | 
 |  | 
 |   return head; | 
 | } | 
 |  | 
 | /* Check LOAD_ADDR points to a Mach-O executable header.  Return LOAD_ADDR | 
 |    in case of success, 0 in case of failure.  */ | 
 |  | 
 | static CORE_ADDR | 
 | darwin_validate_exec_header (CORE_ADDR load_addr) | 
 | { | 
 |   enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ()); | 
 |   struct mach_o_header_external hdr; | 
 |   unsigned long hdr_val; | 
 |  | 
 |   /* Read Mach-O header from memory.  */ | 
 |   if (target_read_memory (load_addr, (gdb_byte *) &hdr, sizeof (hdr) - 4)) | 
 |     return 0; | 
 |  | 
 |   /* Discard wrong magic numbers.  Shouldn't happen.  */ | 
 |   hdr_val = extract_unsigned_integer | 
 |     (hdr.magic, sizeof (hdr.magic), byte_order); | 
 |   if (hdr_val != BFD_MACH_O_MH_MAGIC && hdr_val != BFD_MACH_O_MH_MAGIC_64) | 
 |     return 0; | 
 |  | 
 |   /* Check executable.  */ | 
 |   hdr_val = extract_unsigned_integer | 
 |     (hdr.filetype, sizeof (hdr.filetype), byte_order); | 
 |   if (hdr_val == BFD_MACH_O_MH_EXECUTE) | 
 |     return load_addr; | 
 |  | 
 |   return 0; | 
 | } | 
 |  | 
 | /* Get the load address of the executable using dyld list of images. | 
 |    We assume that the dyld info are correct (which is wrong if the target | 
 |    is stopped at the first instruction).  */ | 
 |  | 
 | static CORE_ADDR | 
 | darwin_read_exec_load_addr_from_dyld (struct darwin_info *info) | 
 | { | 
 |   struct type *ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr; | 
 |   int ptr_len = TYPE_LENGTH (ptr_type); | 
 |   unsigned int image_info_size = ptr_len * 3; | 
 |   int i; | 
 |  | 
 |   /* Read infos for each solib.  One of them should be the executable.  */ | 
 |   for (i = 0; i < info->all_image.count; i++) | 
 |     { | 
 |       CORE_ADDR iinfo = info->all_image.info + i * image_info_size; | 
 |       gdb_byte buf[image_info_size]; | 
 |       CORE_ADDR load_addr; | 
 |  | 
 |       /* Read image info from inferior.  */ | 
 |       if (target_read_memory (iinfo, buf, image_info_size)) | 
 | 	break; | 
 |  | 
 |       load_addr = extract_typed_address (buf, ptr_type); | 
 |       if (darwin_validate_exec_header (load_addr) == load_addr) | 
 | 	return load_addr; | 
 |     } | 
 |  | 
 |   return 0; | 
 | } | 
 |  | 
 | /* Get the load address of the executable when the PC is at the dyld | 
 |    entry point using parameter passed by the kernel (at SP). */ | 
 |  | 
 | static CORE_ADDR | 
 | darwin_read_exec_load_addr_at_init (struct darwin_info *info) | 
 | { | 
 |   struct gdbarch *gdbarch = target_gdbarch (); | 
 |   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); | 
 |   int addr_size = gdbarch_addr_bit (gdbarch) / 8; | 
 |   ULONGEST load_ptr_addr; | 
 |   ULONGEST load_addr; | 
 |   gdb_byte buf[8]; | 
 |  | 
 |   /* Get SP.  */ | 
 |   if (regcache_cooked_read_unsigned (get_current_regcache (), | 
 | 				     gdbarch_sp_regnum (gdbarch), | 
 | 				     &load_ptr_addr) != REG_VALID) | 
 |     return 0; | 
 |  | 
 |   /* Read value at SP (image load address).  */ | 
 |   if (target_read_memory (load_ptr_addr, buf, addr_size)) | 
 |     return 0; | 
 |  | 
 |   load_addr = extract_unsigned_integer (buf, addr_size, byte_order); | 
 |  | 
 |   return darwin_validate_exec_header (load_addr); | 
 | } | 
 |  | 
 | /* Return 1 if PC lies in the dynamic symbol resolution code of the | 
 |    run time loader.  */ | 
 |  | 
 | static int | 
 | darwin_in_dynsym_resolve_code (CORE_ADDR pc) | 
 | { | 
 |   return 0; | 
 | } | 
 |  | 
 | /* A wrapper for bfd_mach_o_fat_extract that handles reference | 
 |    counting properly.  This will either return NULL, or return a new | 
 |    reference to a BFD.  */ | 
 |  | 
 | static gdb_bfd_ref_ptr | 
 | gdb_bfd_mach_o_fat_extract (bfd *abfd, bfd_format format, | 
 | 			    const bfd_arch_info_type *arch) | 
 | { | 
 |   bfd *result = bfd_mach_o_fat_extract (abfd, format, arch); | 
 |  | 
 |   if (result == NULL) | 
 |     return NULL; | 
 |  | 
 |   if (result == abfd) | 
 |     gdb_bfd_ref (result); | 
 |   else | 
 |     gdb_bfd_mark_parent (result, abfd); | 
 |  | 
 |   return gdb_bfd_ref_ptr (result); | 
 | } | 
 |  | 
 | /* Return the BFD for the program interpreter.  */ | 
 |  | 
 | static gdb_bfd_ref_ptr | 
 | darwin_get_dyld_bfd () | 
 | { | 
 |   char *interp_name; | 
 |  | 
 |   /* This method doesn't work with an attached process.  */ | 
 |   if (current_inferior ()->attach_flag) | 
 |     return NULL; | 
 |  | 
 |   /* Find the program interpreter.  */ | 
 |   interp_name = find_program_interpreter (); | 
 |   if (!interp_name) | 
 |     return NULL; | 
 |  | 
 |   /* Create a bfd for the interpreter.  */ | 
 |   gdb_bfd_ref_ptr dyld_bfd (gdb_bfd_open (interp_name, gnutarget)); | 
 |   if (dyld_bfd != NULL) | 
 |     { | 
 |       gdb_bfd_ref_ptr sub | 
 | 	(gdb_bfd_mach_o_fat_extract (dyld_bfd.get (), bfd_object, | 
 | 				     gdbarch_bfd_arch_info (target_gdbarch ()))); | 
 |       dyld_bfd = sub; | 
 |     } | 
 |   return dyld_bfd; | 
 | } | 
 |  | 
 | /* Extract dyld_all_image_addr when the process was just created, assuming the | 
 |    current PC is at the entry of the dynamic linker.  */ | 
 |  | 
 | static void | 
 | darwin_solib_get_all_image_info_addr_at_init (struct darwin_info *info) | 
 | { | 
 |   CORE_ADDR load_addr = 0; | 
 |   gdb_bfd_ref_ptr dyld_bfd = darwin_get_dyld_bfd (); | 
 |  | 
 |   if (dyld_bfd == NULL) | 
 |     return; | 
 |  | 
 |   /* We find the dynamic linker's base address by examining | 
 |      the current pc (which should point at the entry point for the | 
 |      dynamic linker) and subtracting the offset of the entry point.  */ | 
 |   load_addr = (regcache_read_pc (get_current_regcache ()) | 
 | 	       - bfd_get_start_address (dyld_bfd.get ())); | 
 |  | 
 |   /* Now try to set a breakpoint in the dynamic linker.  */ | 
 |   info->all_image_addr = | 
 |     lookup_symbol_from_bfd (dyld_bfd.get (), "_dyld_all_image_infos"); | 
 |  | 
 |   if (info->all_image_addr == 0) | 
 |     return; | 
 |  | 
 |   info->all_image_addr += load_addr; | 
 | } | 
 |  | 
 | /* Extract dyld_all_image_addr reading it from | 
 |    TARGET_OBJECT_DARWIN_DYLD_INFO.  */ | 
 |  | 
 | static void | 
 | darwin_solib_read_all_image_info_addr (struct darwin_info *info) | 
 | { | 
 |   gdb_byte buf[8]; | 
 |   LONGEST len; | 
 |   struct type *ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr; | 
 |  | 
 |   /* Sanity check.  */ | 
 |   if (TYPE_LENGTH (ptr_type) > sizeof (buf)) | 
 |     return; | 
 |  | 
 |   len = target_read (current_inferior ()->top_target (), | 
 | 		     TARGET_OBJECT_DARWIN_DYLD_INFO, | 
 | 		     NULL, buf, 0, TYPE_LENGTH (ptr_type)); | 
 |   if (len <= 0) | 
 |     return; | 
 |  | 
 |   /* The use of BIG endian is intended, as BUF is a raw stream of bytes.  This | 
 |       makes the support of remote protocol easier.  */ | 
 |   info->all_image_addr = extract_unsigned_integer (buf, len, BFD_ENDIAN_BIG); | 
 | } | 
 |  | 
 | /* Shared library startup support.  See documentation in solib-svr4.c.  */ | 
 |  | 
 | static void | 
 | darwin_solib_create_inferior_hook (int from_tty) | 
 | { | 
 |   /* Everything below only makes sense if we have a running inferior.  */ | 
 |   if (!target_has_execution ()) | 
 |     return; | 
 |  | 
 |   struct darwin_info *info = get_darwin_info (); | 
 |   CORE_ADDR load_addr; | 
 |  | 
 |   info->all_image_addr = 0; | 
 |  | 
 |   darwin_solib_read_all_image_info_addr (info); | 
 |  | 
 |   if (info->all_image_addr == 0) | 
 |     darwin_solib_get_all_image_info_addr_at_init (info); | 
 |  | 
 |   if (info->all_image_addr == 0) | 
 |     return; | 
 |  | 
 |   darwin_load_image_infos (info); | 
 |  | 
 |   if (!darwin_dyld_version_ok (info)) | 
 |     { | 
 |       warning (_("unhandled dyld version (%d)"), info->all_image.version); | 
 |       return; | 
 |     } | 
 |  | 
 |   if (info->all_image.count != 0) | 
 |     { | 
 |       /* Possible relocate the main executable (PIE).  */ | 
 |       load_addr = darwin_read_exec_load_addr_from_dyld (info); | 
 |     } | 
 |   else | 
 |     { | 
 |       /* Possible issue: | 
 | 	 Do not break on the notifier if dyld is not initialized (deduced from | 
 | 	 count == 0).  In that case, dyld hasn't relocated itself and the | 
 | 	 notifier may point to a wrong address.  */ | 
 |  | 
 |       load_addr = darwin_read_exec_load_addr_at_init (info); | 
 |     } | 
 |  | 
 |   if (load_addr != 0 && current_program_space->symfile_object_file != NULL) | 
 |     { | 
 |       CORE_ADDR vmaddr; | 
 |  | 
 |       /* Find the base address of the executable.  */ | 
 |       vmaddr = bfd_mach_o_get_base_address (current_program_space->exec_bfd ()); | 
 |  | 
 |       /* Relocate.  */ | 
 |       if (vmaddr != load_addr) | 
 | 	objfile_rebase (current_program_space->symfile_object_file, | 
 | 			load_addr - vmaddr); | 
 |     } | 
 |  | 
 |   /* Set solib notifier (to reload list of shared libraries).  */ | 
 |   CORE_ADDR notifier = info->all_image.notifier; | 
 |  | 
 |   if (info->all_image.count == 0) | 
 |     { | 
 |       /* Dyld hasn't yet relocated itself, so the notifier address may | 
 | 	 be incorrect (as it has to be relocated).  */ | 
 |       CORE_ADDR start | 
 | 	= bfd_get_start_address (current_program_space->exec_bfd ()); | 
 |       if (start == 0) | 
 | 	notifier = 0; | 
 |       else | 
 | 	{ | 
 | 	  gdb_bfd_ref_ptr dyld_bfd = darwin_get_dyld_bfd (); | 
 | 	  if (dyld_bfd != NULL) | 
 | 	    { | 
 | 	      CORE_ADDR dyld_bfd_start_address; | 
 | 	      CORE_ADDR dyld_relocated_base_address; | 
 | 	      CORE_ADDR pc; | 
 |  | 
 | 	      dyld_bfd_start_address = bfd_get_start_address (dyld_bfd.get()); | 
 |  | 
 | 	      /* We find the dynamic linker's base address by examining | 
 | 		 the current pc (which should point at the entry point | 
 | 		 for the dynamic linker) and subtracting the offset of | 
 | 		 the entry point.  */ | 
 |  | 
 | 	      pc = regcache_read_pc (get_current_regcache ()); | 
 | 	      dyld_relocated_base_address = pc - dyld_bfd_start_address; | 
 |  | 
 | 	      /* We get the proper notifier relocated address by | 
 | 		 adding the dyld relocated base address to the current | 
 | 		 notifier offset value.  */ | 
 |  | 
 | 	      notifier += dyld_relocated_base_address; | 
 | 	    } | 
 | 	} | 
 |     } | 
 |  | 
 |   /* Add the breakpoint which is hit by dyld when the list of solib is | 
 |      modified.  */ | 
 |   if (notifier != 0) | 
 |     create_solib_event_breakpoint (target_gdbarch (), notifier); | 
 | } | 
 |  | 
 | static void | 
 | darwin_clear_solib (void) | 
 | { | 
 |   struct darwin_info *info = get_darwin_info (); | 
 |  | 
 |   info->all_image_addr = 0; | 
 |   info->all_image.version = 0; | 
 | } | 
 |  | 
 | static void | 
 | darwin_free_so (struct so_list *so) | 
 | { | 
 |   lm_info_darwin *li = (lm_info_darwin *) so->lm_info; | 
 |  | 
 |   delete li; | 
 | } | 
 |  | 
 | /* The section table is built from bfd sections using bfd VMAs. | 
 |    Relocate these VMAs according to solib info.  */ | 
 |  | 
 | static void | 
 | darwin_relocate_section_addresses (struct so_list *so, | 
 | 				   struct target_section *sec) | 
 | { | 
 |   lm_info_darwin *li = (lm_info_darwin *) so->lm_info; | 
 |  | 
 |   sec->addr += li->lm_addr; | 
 |   sec->endaddr += li->lm_addr; | 
 |  | 
 |   /* Best effort to set addr_high/addr_low.  This is used only by | 
 |      'info sharedlibary'.  */ | 
 |   if (so->addr_high == 0) | 
 |     { | 
 |       so->addr_low = sec->addr; | 
 |       so->addr_high = sec->endaddr; | 
 |     } | 
 |   if (sec->endaddr > so->addr_high) | 
 |     so->addr_high = sec->endaddr; | 
 |   if (sec->addr < so->addr_low) | 
 |     so->addr_low = sec->addr; | 
 | } | 
 |  | 
 | static gdb_bfd_ref_ptr | 
 | darwin_bfd_open (const char *pathname) | 
 | { | 
 |   int found_file; | 
 |  | 
 |   /* Search for shared library file.  */ | 
 |   gdb::unique_xmalloc_ptr<char> found_pathname | 
 |     = solib_find (pathname, &found_file); | 
 |   if (found_pathname == NULL) | 
 |     perror_with_name (pathname); | 
 |  | 
 |   /* Open bfd for shared library.  */ | 
 |   gdb_bfd_ref_ptr abfd (solib_bfd_fopen (found_pathname.get (), found_file)); | 
 |  | 
 |   gdb_bfd_ref_ptr res | 
 |     (gdb_bfd_mach_o_fat_extract (abfd.get (), bfd_object, | 
 | 				 gdbarch_bfd_arch_info (target_gdbarch ()))); | 
 |   if (res == NULL) | 
 |     error (_("`%s': not a shared-library: %s"), | 
 | 	   bfd_get_filename (abfd.get ()), bfd_errmsg (bfd_get_error ())); | 
 |  | 
 |   /* The current filename for fat-binary BFDs is a name generated | 
 |      by BFD, usually a string containing the name of the architecture. | 
 |      Reset its value to the actual filename.  */ | 
 |   bfd_set_filename (res.get (), pathname); | 
 |  | 
 |   return res; | 
 | } | 
 |  | 
 | struct target_so_ops darwin_so_ops; | 
 |  | 
 | void _initialize_darwin_solib (); | 
 | void | 
 | _initialize_darwin_solib () | 
 | { | 
 |   darwin_so_ops.relocate_section_addresses = darwin_relocate_section_addresses; | 
 |   darwin_so_ops.free_so = darwin_free_so; | 
 |   darwin_so_ops.clear_solib = darwin_clear_solib; | 
 |   darwin_so_ops.solib_create_inferior_hook = darwin_solib_create_inferior_hook; | 
 |   darwin_so_ops.current_sos = darwin_current_sos; | 
 |   darwin_so_ops.open_symbol_file_object = open_symbol_file_object; | 
 |   darwin_so_ops.in_dynsym_resolve_code = darwin_in_dynsym_resolve_code; | 
 |   darwin_so_ops.bfd_open = darwin_bfd_open; | 
 | } |