X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fsolib-darwin.c;h=1ad781d686bd66bae1447a1ae1aa99433f48458e;hb=74375d182e992778ef8701278c02a742db6be77e;hp=7109eadde370ab1f1758bd1e8a653186ca45bb9a;hpb=f9a062ffb59ebed937221b852eab2abbd43111ed;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/solib-darwin.c b/gdb/solib-darwin.c index 7109eadde3..1ad781d686 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-2012 Free Software Foundation, Inc. + Copyright (C) 2009-2020 Free Software Foundation, Inc. This file is part of GDB. @@ -30,8 +30,6 @@ #include "gdbthread.h" #include "gdb_bfd.h" -#include "gdb_assert.h" - #include "solist.h" #include "solib.h" #include "solib-svr4.h" @@ -40,7 +38,6 @@ #include "elf-bfd.h" #include "exec.h" #include "auxv.h" -#include "exceptions.h" #include "mach-o.h" #include "mach-o/external.h" @@ -70,29 +67,20 @@ struct gdb_dyld_all_image_infos /* Current all_image_infos version. */ #define DYLD_VERSION_MIN 1 -#define DYLD_VERSION_MAX 12 +#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; + CORE_ADDR all_image_addr = 0; /* Gdb copy of dyld_all_info_infos. */ - struct gdb_dyld_all_image_infos all_image; + struct gdb_dyld_all_image_infos all_image {}; }; /* Per-program-space data key. */ -static const struct program_space_data *solib_darwin_pspace_data; - -static void -darwin_pspace_data_cleanup (struct program_space *pspace, void *arg) -{ - struct darwin_info *info; - - info = program_space_data (pspace, solib_darwin_pspace_data); - xfree (info); -} +static program_space_key solib_darwin_pspace_data; /* Get the current darwin data. If none is found yet, add it now. This function always returns a valid object. */ @@ -102,14 +90,11 @@ get_darwin_info (void) { struct darwin_info *info; - info = program_space_data (current_program_space, solib_darwin_pspace_data); + info = solib_darwin_pspace_data.get (current_program_space); if (info != NULL) return info; - info = XZALLOC (struct darwin_info); - set_program_space_data (current_program_space, - solib_darwin_pspace_data, info); - return info; + return solib_darwin_pspace_data.emplace (current_program_space); } /* Return non-zero if the version in dyld_all_image is known. */ @@ -127,8 +112,8 @@ 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; + 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. */ @@ -137,7 +122,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)); @@ -153,29 +138,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; @@ -210,10 +187,10 @@ lookup_symbol_from_bfd (bfd *abfd, char *symname) /* Return program interpreter string. */ -static gdb_byte * +static char * find_program_interpreter (void) { - gdb_byte *buf = NULL; + char *buf = NULL; /* If we have an exec_bfd, get the interpreter from the load commands. */ if (exec_bfd) @@ -235,7 +212,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; } @@ -245,8 +222,8 @@ open_symbol_file_object (void *from_ttyp) static struct so_list * darwin_current_sos (void) { - struct type *ptr_type = builtin_type (target_gdbarch)->builtin_data_ptr; - enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch); + 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; @@ -269,16 +246,13 @@ darwin_current_sos (void) for (i = 0; i < info->all_image.count; i++) { CORE_ADDR iinfo = info->all_image.info + i * image_info_size; - char buf[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; - char *file_path; + gdb::unique_xmalloc_ptr file_path; int errcode; - struct darwin_so_list *dnew; - struct so_list *new; - struct cleanup *old_chain; /* Read image info from inferior. */ if (target_read_memory (iinfo, buf, image_info_size)) @@ -288,7 +262,7 @@ darwin_current_sos (void) path_addr = extract_typed_address (buf + ptr_len, ptr_type); /* Read Mach-O header from memory. */ - if (target_read_memory (load_addr, (char *) &hdr, sizeof (hdr) - 4)) + 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 @@ -307,30 +281,114 @@ darwin_current_sos (void) break; /* Create and fill the new so_list element. */ - dnew = XZALLOC (struct darwin_so_list); - new = &dnew->sl; - old_chain = make_cleanup (xfree, dnew); + gdb::unique_xmalloc_ptr newobj (XCNEW (struct so_list)); - new->lm_info = &dnew->li; + lm_info_darwin *li = new lm_info_darwin; + newobj->lm_info = li; - strncpy (new->so_name, file_path, SO_NAME_MAX_PATH_SIZE - 1); - new->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0'; - strcpy (new->so_original_name, new->so_name); - xfree (file_path); - new->lm_info->lm_addr = load_addr; + 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 = new; + head = newobj.get (); else - tail->next = new; - tail = new; - - discard_cleanups (old_chain); + 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. */ @@ -340,70 +398,76 @@ 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. */ -/* No special symbol handling. */ - -static void -darwin_special_symbol_handling (void) +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); } -/* Extract dyld_all_image_addr when the process was just created, assuming the - current PC is at the entry of the dynamic linker. */ +/* Return the BFD for the program interpreter. */ -static void -darwin_solib_get_all_image_info_addr_at_init (struct darwin_info *info) +static gdb_bfd_ref_ptr +darwin_get_dyld_bfd () { - gdb_byte *interp_name; - CORE_ADDR load_addr = 0; - bfd *dyld_bfd = NULL; - struct cleanup *cleanup; + char *interp_name; /* This method doesn't work with an attached process. */ if (current_inferior ()->attach_flag) - return; + return NULL; /* Find the program interpreter. */ interp_name = find_program_interpreter (); if (!interp_name) - return; - - cleanup = make_cleanup (null_cleanup, NULL); + return NULL; /* Create a bfd for the interpreter. */ - dyld_bfd = gdb_bfd_ref (bfd_openr (interp_name, gnutarget)); - 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 = bfd_mach_o_fat_extract (dyld_bfd, bfd_object, - gdbarch_bfd_arch_info (target_gdbarch)); - if (sub) - { - dyld_bfd = gdb_bfd_ref (sub); - make_cleanup_bfd_unref (sub); - } - else - dyld_bfd = NULL; - } - if (!dyld_bfd) - { - do_cleanups (cleanup); - return; + 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)); + - 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; @@ -411,22 +475,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; - len = target_read (¤t_target, TARGET_OBJECT_DARWIN_DYLD_INFO, NULL, - buf, 0, sizeof (buf)); - if (len != sizeof (buf)) + /* Sanity check. */ + if (TYPE_LENGTH (ptr_type) > sizeof (buf)) return; - info->all_image_addr = extract_unsigned_integer (buf, 8, byte_order); + len = target_read (current_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. */ @@ -435,6 +505,7 @@ static void darwin_solib_create_inferior_hook (int from_tty) { struct darwin_info *info = get_darwin_info (); + CORE_ADDR load_addr; info->all_image_addr = 0; @@ -448,8 +519,81 @@ darwin_solib_create_inferior_hook (int from_tty) darwin_load_image_infos (info); - if (darwin_dyld_version_ok (info)) - create_solib_event_breakpoint (target_gdbarch, info->all_image.notifier); + 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 && symfile_objfile != NULL) + { + CORE_ADDR vmaddr; + + /* Find the base address of the executable. */ + vmaddr = bfd_mach_o_get_base_address (exec_bfd); + + /* Relocate. */ + if (vmaddr != load_addr) + objfile_rebase (symfile_objfile, 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 (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 @@ -464,6 +608,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. @@ -473,8 +620,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'. */ @@ -489,60 +638,46 @@ darwin_relocate_section_addresses (struct so_list *so, so->addr_low = sec->addr; } -static struct symbol * -darwin_lookup_lib_symbol (const struct objfile *objfile, - const char *name, - const domain_enum domain) +static gdb_bfd_ref_ptr +darwin_bfd_open (const char *pathname) { - return NULL; -} - -static bfd * -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); + gdb::unique_xmalloc_ptr found_pathname + = solib_find (pathname, &found_file); if (found_pathname == NULL) 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.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 (), xstrdup (pathname)); - res = 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 ())); - } return res; } struct target_so_ops darwin_so_ops; -/* -Wmissing-prototypes */ -extern initialize_file_ftype _initialize_darwin_solib; - void _initialize_darwin_solib (void) { - solib_darwin_pspace_data - = register_program_space_data_with_cleanup (darwin_pspace_data_cleanup); - 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.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; }