X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fsolib-darwin.c;h=d66938fb90561ad90583fa58cc79722b24463e18;hb=632e107b32c0fe8aede62e070b00756e9fdd2c01;hp=c37049abf25070d3d018f8d7a6c8c352f373765a;hpb=487ad57ccfe1434e21774117d20dfd9e23f12afa;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/solib-darwin.c b/gdb/solib-darwin.c index c37049abf2..d66938fb90 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-2013 Free Software Foundation, Inc. + Copyright (C) 2009-2018 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,7 +67,7 @@ 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 @@ -99,11 +96,12 @@ 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; - info = XZALLOC (struct darwin_info); + info = XCNEW (struct darwin_info); set_program_space_data (current_program_space, solib_darwin_pspace_data, info); return info; @@ -134,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)); @@ -150,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; @@ -232,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; } @@ -271,10 +261,9 @@ darwin_current_sos (void) 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 so_list *newobj; struct cleanup *old_chain; /* Read image info from inferior. */ @@ -304,23 +293,22 @@ 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); + newobj = XCNEW (struct so_list); + old_chain = make_cleanup (xfree, newobj); - 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; else - tail->next = new; - tail = new; + tail->next = newobj; + tail = newobj; discard_cleanups (old_chain); } @@ -328,14 +316,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; @@ -346,33 +363,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. */ @@ -382,19 +413,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) { @@ -408,7 +431,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 @@ -419,8 +442,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) @@ -431,42 +452,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; @@ -474,22 +483,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. */ @@ -513,34 +528,36 @@ darwin_solib_create_inferior_hook (int from_tty) darwin_load_image_infos (info); if (!darwin_dyld_version_ok (info)) - return; + { + warning (_("unhandled dyld version (%d)"), info->all_image.version); + 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 = 0; - struct mach_o_data_struct *md = bfd_mach_o_get_data (exec_bfd); - unsigned int i, num; + CORE_ADDR vmaddr; /* Find the base address of the executable. */ - for (i = 0; i < md->header.ncmds; i++) - { - struct bfd_mach_o_load_command *cmd = &md->commands[i]; - - if (cmd->type != BFD_MACH_O_LC_SEGMENT - && cmd->type != BFD_MACH_O_LC_SEGMENT_64) - continue; - if (cmd->command.segment.fileoff == 0 - && cmd->command.segment.vmaddr != 0 - && cmd->command.segment.filesize != 0) - { - vmaddr = cmd->command.segment.vmaddr; - break; - } - } + vmaddr = bfd_mach_o_get_base_address (exec_bfd); /* Relocate. */ if (vmaddr != load_addr) @@ -560,6 +577,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. @@ -569,8 +589,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'. */ @@ -585,48 +607,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, +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 * -darwin_bfd_open (char *pathname) +static gdb_bfd_ref_ptr +darwin_bfd_open (const 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)); - 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.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) { @@ -638,7 +658,6 @@ _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;