X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fsolib-darwin.c;h=f63f924b8a56fce4b3f7331970d16fccbc15421b;hb=f00a2de2a7556c59bce93f7ced44afa8e1bbf7c3;hp=9309c359c1e2a4b7733df3edb773e172337030d8;hpb=ca5268b6be265580b91ef75c1a1a9815f581ae42;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/solib-darwin.c b/gdb/solib-darwin.c index 9309c359c1..f63f924b8a 100644 --- a/gdb/solib-darwin.c +++ b/gdb/solib-darwin.c @@ -1,6 +1,6 @@ /* Handle Darwin shared libraries for GDB, the GNU Debugger. - Copyright (C) 2009-2015 Free Software Foundation, Inc. + Copyright (C) 2009-2017 Free Software Foundation, Inc. This file is part of GDB. @@ -67,7 +67,7 @@ struct gdb_dyld_all_image_infos /* Current all_image_infos version. */ #define DYLD_VERSION_MIN 1 -#define DYLD_VERSION_MAX 14 +#define DYLD_VERSION_MAX 15 /* Per PSPACE specific data. */ struct darwin_info @@ -96,7 +96,8 @@ get_darwin_info (void) { struct darwin_info *info; - info = program_space_data (current_program_space, solib_darwin_pspace_data); + info = (struct darwin_info *) program_space_data (current_program_space, + solib_darwin_pspace_data); if (info != NULL) return info; @@ -131,7 +132,7 @@ darwin_load_image_infos (struct darwin_info *info) /* The structure has 4 fields: version (4 bytes), count (4 bytes), info (pointer) and notifier (pointer). */ - len = 4 + 4 + 2 * ptr_type->length; + len = 4 + 4 + 2 * TYPE_LENGTH (ptr_type); gdb_assert (len <= sizeof (buf)); memset (&info->all_image, 0, sizeof (info->all_image)); @@ -147,29 +148,21 @@ darwin_load_image_infos (struct darwin_info *info) 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 + ptr_type->length, ptr_type); + (buf + 8 + TYPE_LENGTH (ptr_type), ptr_type); } /* Link map info to include in an allocated so_list entry. */ -struct lm_info +struct lm_info_darwin : public lm_info_base { /* The target location of lm. */ - CORE_ADDR lm_addr; -}; - -struct darwin_so_list -{ - /* Common field. */ - struct so_list sl; - /* Darwin specific data. */ - struct lm_info li; + CORE_ADDR lm_addr = 0; }; /* Lookup the value for a specific symbol. */ static CORE_ADDR -lookup_symbol_from_bfd (bfd *abfd, char *symname) +lookup_symbol_from_bfd (bfd *abfd, const char *symname) { long storage_needed; asymbol **symbol_table; @@ -229,7 +222,7 @@ find_program_interpreter (void) Note that darwin-nat.c implements pid_to_exec_file. */ static int -open_symbol_file_object (void *from_ttyp) +open_symbol_file_object (int from_tty) { return 0; } @@ -270,7 +263,6 @@ darwin_current_sos (void) unsigned long hdr_val; char *file_path; int errcode; - struct darwin_so_list *dnew; struct so_list *newobj; struct cleanup *old_chain; @@ -301,17 +293,17 @@ darwin_current_sos (void) break; /* Create and fill the new so_list element. */ - dnew = XCNEW (struct darwin_so_list); - newobj = &dnew->sl; - old_chain = make_cleanup (xfree, dnew); + newobj = XCNEW (struct so_list); + old_chain = make_cleanup (xfree, newobj); - newobj->lm_info = &dnew->li; + lm_info_darwin *li = new lm_info_darwin; + newobj->lm_info = li; strncpy (newobj->so_name, file_path, SO_NAME_MAX_PATH_SIZE - 1); newobj->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0'; strcpy (newobj->so_original_name, newobj->so_name); xfree (file_path); - newobj->lm_info->lm_addr = load_addr; + li->lm_addr = load_addr; if (head == NULL) head = newobj; @@ -325,14 +317,43 @@ darwin_current_sos (void) return head; } -/* Get the load address of the executable. We assume that the dyld info are - correct. */ +/* 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_read_exec_load_addr (struct darwin_info *info) +darwin_validate_exec_header (CORE_ADDR load_addr) { - struct type *ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr; 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; @@ -343,33 +364,47 @@ darwin_read_exec_load_addr (struct darwin_info *info) CORE_ADDR iinfo = info->all_image.info + i * image_info_size; gdb_byte buf[image_info_size]; CORE_ADDR load_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); - - /* 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; - /* Check executable. */ - hdr_val = extract_unsigned_integer - (hdr.filetype, sizeof (hdr.filetype), byte_order); - if (hdr_val == BFD_MACH_O_MH_EXECUTE) + 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. */ @@ -379,19 +414,11 @@ darwin_in_dynsym_resolve_code (CORE_ADDR pc) return 0; } - -/* No special symbol handling. */ - -static void -darwin_special_symbol_handling (void) -{ -} - /* 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 bfd * +static gdb_bfd_ref_ptr gdb_bfd_mach_o_fat_extract (bfd *abfd, bfd_format format, const bfd_arch_info_type *arch) { @@ -405,7 +432,7 @@ gdb_bfd_mach_o_fat_extract (bfd *abfd, bfd_format format, else gdb_bfd_mark_parent (result, abfd); - return result; + return gdb_bfd_ref_ptr (result); } /* Extract dyld_all_image_addr when the process was just created, assuming the @@ -416,8 +443,6 @@ darwin_solib_get_all_image_info_addr_at_init (struct darwin_info *info) { char *interp_name; CORE_ADDR load_addr = 0; - bfd *dyld_bfd = NULL; - struct cleanup *cleanup; /* This method doesn't work with an attached process. */ if (current_inferior ()->attach_flag) @@ -428,42 +453,30 @@ darwin_solib_get_all_image_info_addr_at_init (struct darwin_info *info) if (!interp_name) return; - cleanup = make_cleanup (null_cleanup, NULL); - /* Create a bfd for the interpreter. */ - dyld_bfd = gdb_bfd_open (interp_name, gnutarget, -1); - if (dyld_bfd) + gdb_bfd_ref_ptr dyld_bfd (gdb_bfd_open (interp_name, gnutarget, -1)); + if (dyld_bfd != NULL) { - bfd *sub; - - make_cleanup_bfd_unref (dyld_bfd); - sub = gdb_bfd_mach_o_fat_extract (dyld_bfd, bfd_object, - gdbarch_bfd_arch_info (target_gdbarch ())); - if (sub) - { - dyld_bfd = sub; - make_cleanup_bfd_unref (sub); - } + gdb_bfd_ref_ptr sub + (gdb_bfd_mach_o_fat_extract (dyld_bfd.get (), bfd_object, + gdbarch_bfd_arch_info (target_gdbarch ()))); + if (sub != NULL) + dyld_bfd = sub; else - dyld_bfd = NULL; - } - if (!dyld_bfd) - { - do_cleanups (cleanup); - return; + dyld_bfd.release (); } + 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)); + - 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, "_dyld_all_image_infos"); - - do_cleanups (cleanup); + lookup_symbol_from_bfd (dyld_bfd.get (), "_dyld_all_image_infos"); if (info->all_image_addr == 0) return; @@ -471,22 +484,28 @@ darwin_solib_get_all_image_info_addr_at_init (struct darwin_info *info) info->all_image_addr += load_addr; } -/* Extract dyld_all_image_addr reading it from +/* 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 + 8 + 4]; + gdb_byte buf[8]; LONGEST len; - enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ()); + struct type *ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr; + + /* Sanity check. */ + if (TYPE_LENGTH (ptr_type) > sizeof (buf)) + return; len = target_read (¤t_target, TARGET_OBJECT_DARWIN_DYLD_INFO, NULL, - buf, 0, sizeof (buf)); - if (len != sizeof (buf)) + buf, 0, TYPE_LENGTH (ptr_type)); + if (len <= 0) return; - info->all_image_addr = extract_unsigned_integer (buf, 8, byte_order); + /* 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. */ @@ -515,10 +534,25 @@ darwin_solib_create_inferior_hook (int from_tty) return; } + /* Add the breakpoint which is hit by dyld when the list of solib is + modified. */ create_solib_event_breakpoint (target_gdbarch (), info->all_image.notifier); - /* Possible relocate the main executable (PIE). */ - load_addr = darwin_read_exec_load_addr (info); + 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 && symfile_objfile != NULL) { CORE_ADDR vmaddr; @@ -544,6 +578,9 @@ darwin_clear_solib (void) 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. @@ -553,8 +590,10 @@ static void darwin_relocate_section_addresses (struct so_list *so, struct target_section *sec) { - sec->addr += so->lm_info->lm_addr; - sec->endaddr += so->lm_info->lm_addr; + 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'. */ @@ -569,21 +608,19 @@ darwin_relocate_section_addresses (struct so_list *so, so->addr_low = sec->addr; } -static struct symbol * +static struct block_symbol darwin_lookup_lib_symbol (struct objfile *objfile, const char *name, const domain_enum domain) { - return NULL; + return (struct block_symbol) {NULL, NULL}; } -static bfd * +static gdb_bfd_ref_ptr darwin_bfd_open (char *pathname) { char *found_pathname; int found_file; - bfd *abfd; - bfd *res; /* Search for shared library file. */ found_pathname = solib_find (pathname, &found_file); @@ -591,32 +628,26 @@ darwin_bfd_open (char *pathname) perror_with_name (pathname); /* Open bfd for shared library. */ - abfd = solib_bfd_fopen (found_pathname, found_file); + gdb_bfd_ref_ptr abfd (solib_bfd_fopen (found_pathname, found_file)); - res = gdb_bfd_mach_o_fat_extract (abfd, bfd_object, - gdbarch_bfd_arch_info (target_gdbarch ())); - if (!res) - { - make_cleanup_bfd_unref (abfd); - error (_("`%s': not a shared-library: %s"), - bfd_get_filename (abfd), bfd_errmsg (bfd_get_error ())); - } + 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. */ - xfree (bfd_get_filename (res)); + xfree (bfd_get_filename (res.get ())); res->filename = xstrdup (pathname); - gdb_bfd_unref (abfd); return res; } struct target_so_ops darwin_so_ops; -/* -Wmissing-prototypes */ -extern initialize_file_ftype _initialize_darwin_solib; - void _initialize_darwin_solib (void) { @@ -628,11 +659,9 @@ _initialize_darwin_solib (void) 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.special_symbol_handling = darwin_special_symbol_handling; 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.lookup_lib_global_symbol = darwin_lookup_lib_symbol; darwin_so_ops.bfd_open = darwin_bfd_open; - darwin_so_ops.validate = default_solib_validate; }