|  | /* Darwin support for GDB, the GNU debugger. | 
|  | Copyright (C) 2008-2024 Free Software Foundation, Inc. | 
|  |  | 
|  | Contributed by AdaCore. | 
|  |  | 
|  | 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 "symtab.h" | 
|  | #include "gdbtypes.h" | 
|  | #include "bfd.h" | 
|  | #include "symfile.h" | 
|  | #include "objfiles.h" | 
|  | #include "cli/cli-cmds.h" | 
|  | #include "gdbcore.h" | 
|  | #include "mach-o.h" | 
|  | #include "aout/stab_gnu.h" | 
|  | #include "complaints.h" | 
|  | #include "gdb_bfd.h" | 
|  | #include <string> | 
|  | #include <algorithm> | 
|  | #include "dwarf2/public.h" | 
|  |  | 
|  | /* If non-zero displays debugging message.  */ | 
|  | static unsigned int mach_o_debug_level = 0; | 
|  |  | 
|  | #define macho_debug(LEVEL, FMT, ...) \ | 
|  | debug_prefixed_printf_cond_nofunc (mach_o_debug_level > LEVEL, \ | 
|  | "machoread", FMT, ## __VA_ARGS__) | 
|  |  | 
|  | /* Dwarf debugging information are never in the final executable.  They stay | 
|  | in object files and the executable contains the list of object files read | 
|  | during the link. | 
|  | Each time an oso (other source) is found in the executable, the reader | 
|  | creates such a structure.  They are read after the processing of the | 
|  | executable.  */ | 
|  |  | 
|  | struct oso_el | 
|  | { | 
|  | oso_el (asymbol **oso_sym_, asymbol **end_sym_, unsigned int nbr_syms_) | 
|  | : name((*oso_sym_)->name), | 
|  | mtime((*oso_sym_)->value), | 
|  | oso_sym(oso_sym_), | 
|  | end_sym(end_sym_), | 
|  | nbr_syms(nbr_syms_) | 
|  | { | 
|  | } | 
|  |  | 
|  | /* Object file name.  Can also be a member name.  */ | 
|  | const char *name; | 
|  |  | 
|  | /* Associated time stamp.  */ | 
|  | unsigned long mtime; | 
|  |  | 
|  | /* Stab symbols range for this OSO.  */ | 
|  | asymbol **oso_sym; | 
|  | asymbol **end_sym; | 
|  |  | 
|  | /* Number of interesting stabs in the range.  */ | 
|  | unsigned int nbr_syms; | 
|  | }; | 
|  |  | 
|  | static void | 
|  | macho_new_init (struct objfile *objfile) | 
|  | { | 
|  | } | 
|  |  | 
|  | static void | 
|  | macho_symfile_init (struct objfile *objfile) | 
|  | { | 
|  | } | 
|  |  | 
|  | /* Add symbol SYM to the minimal symbol table of OBJFILE.  */ | 
|  |  | 
|  | static void | 
|  | macho_symtab_add_minsym (minimal_symbol_reader &reader, | 
|  | struct objfile *objfile, const asymbol *sym) | 
|  | { | 
|  | if (sym->name == NULL || *sym->name == '\0') | 
|  | { | 
|  | /* Skip names that don't exist (shouldn't happen), or names | 
|  | that are null strings (may happen).  */ | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (sym->flags & (BSF_GLOBAL | BSF_LOCAL | BSF_WEAK)) | 
|  | { | 
|  | unrelocated_addr symaddr; | 
|  | enum minimal_symbol_type ms_type; | 
|  |  | 
|  | /* Bfd symbols are section relative.  */ | 
|  | symaddr = unrelocated_addr (sym->value + sym->section->vma); | 
|  |  | 
|  | if (sym->section == bfd_abs_section_ptr) | 
|  | ms_type = mst_abs; | 
|  | else if (sym->section->flags & SEC_CODE) | 
|  | { | 
|  | if (sym->flags & (BSF_GLOBAL | BSF_WEAK)) | 
|  | ms_type = mst_text; | 
|  | else | 
|  | ms_type = mst_file_text; | 
|  | } | 
|  | else if (sym->section->flags & SEC_ALLOC) | 
|  | { | 
|  | if (sym->flags & (BSF_GLOBAL | BSF_WEAK)) | 
|  | { | 
|  | if (sym->section->flags & SEC_LOAD) | 
|  | ms_type = mst_data; | 
|  | else | 
|  | ms_type = mst_bss; | 
|  | } | 
|  | else if (sym->flags & BSF_LOCAL) | 
|  | { | 
|  | /* Not a special stabs-in-elf symbol, do regular | 
|  | symbol processing.  */ | 
|  | if (sym->section->flags & SEC_LOAD) | 
|  | ms_type = mst_file_data; | 
|  | else | 
|  | ms_type = mst_file_bss; | 
|  | } | 
|  | else | 
|  | ms_type = mst_unknown; | 
|  | } | 
|  | else | 
|  | return;	/* Skip this symbol.  */ | 
|  |  | 
|  | reader.record_with_info (sym->name, symaddr, ms_type, | 
|  | gdb_bfd_section_index (objfile->obfd.get (), | 
|  | sym->section)); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Build the minimal symbol table from SYMBOL_TABLE of length | 
|  | NUMBER_OF_SYMBOLS for OBJFILE.  Registers OSO filenames found.  */ | 
|  |  | 
|  | static void | 
|  | macho_symtab_read (minimal_symbol_reader &reader, | 
|  | struct objfile *objfile, | 
|  | long number_of_symbols, asymbol **symbol_table, | 
|  | std::vector<oso_el> *oso_vector_ptr) | 
|  | { | 
|  | long i; | 
|  | const asymbol *file_so = NULL; | 
|  | asymbol **oso_file = NULL; | 
|  | unsigned int nbr_syms = 0; | 
|  |  | 
|  | /* Current state while reading stabs.  */ | 
|  | enum | 
|  | { | 
|  | /* Not within an SO part.  Only non-debugging symbols should be present, | 
|  | and will be added to the minimal symbols table.  */ | 
|  | S_NO_SO, | 
|  |  | 
|  | /* First SO read.  Introduce an SO section, and may be followed by a second | 
|  | SO.  The SO section should contain onl debugging symbols.  */ | 
|  | S_FIRST_SO, | 
|  |  | 
|  | /* Second non-null SO found, just after the first one.  Means that the first | 
|  | is in fact a directory name.  */ | 
|  | S_SECOND_SO, | 
|  |  | 
|  | /* Non-null OSO found.  Debugging info are DWARF in this OSO file.  */ | 
|  | S_DWARF_FILE, | 
|  |  | 
|  | S_STAB_FILE | 
|  | } state = S_NO_SO; | 
|  |  | 
|  | for (i = 0; i < number_of_symbols; i++) | 
|  | { | 
|  | const asymbol *sym = symbol_table[i]; | 
|  | bfd_mach_o_asymbol *mach_o_sym = (bfd_mach_o_asymbol *)sym; | 
|  |  | 
|  | switch (state) | 
|  | { | 
|  | case S_NO_SO: | 
|  | if (mach_o_sym->n_type == N_SO) | 
|  | { | 
|  | /* Start of object stab.  */ | 
|  | if (sym->name == NULL || sym->name[0] == 0) | 
|  | { | 
|  | /* Unexpected empty N_SO.  */ | 
|  | complaint (_("Unexpected empty N_SO stab")); | 
|  | } | 
|  | else | 
|  | { | 
|  | file_so = sym; | 
|  | state = S_FIRST_SO; | 
|  | } | 
|  | } | 
|  | else if (sym->flags & BSF_DEBUGGING) | 
|  | { | 
|  | if (mach_o_sym->n_type == N_OPT) | 
|  | { | 
|  | /* No complaint for OPT.  */ | 
|  | break; | 
|  | } | 
|  |  | 
|  | /* Debugging symbols are not expected here.  */ | 
|  | complaint (_("%s: Unexpected debug stab outside SO markers"), | 
|  | objfile_name (objfile)); | 
|  | } | 
|  | else | 
|  | { | 
|  | /* Non-debugging symbols go to the minimal symbol table.  */ | 
|  | macho_symtab_add_minsym (reader, objfile, sym); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case S_FIRST_SO: | 
|  | case S_SECOND_SO: | 
|  | if (mach_o_sym->n_type == N_SO) | 
|  | { | 
|  | if (sym->name == NULL || sym->name[0] == 0) | 
|  | { | 
|  | /* Unexpected empty N_SO.  */ | 
|  | complaint (_("Empty SO section")); | 
|  | state = S_NO_SO; | 
|  | } | 
|  | else if (state == S_FIRST_SO) | 
|  | { | 
|  | /* Second SO stab for the file name.  */ | 
|  | file_so = sym; | 
|  | state = S_SECOND_SO; | 
|  | } | 
|  | else | 
|  | complaint (_("Three SO in a raw")); | 
|  | } | 
|  | else if (mach_o_sym->n_type == N_OSO) | 
|  | { | 
|  | if (sym->name == NULL || sym->name[0] == 0) | 
|  | { | 
|  | /* Empty OSO.  Means that this file was compiled with | 
|  | stabs.  */ | 
|  | state = S_STAB_FILE; | 
|  | warning (_("stabs debugging not supported for %s"), | 
|  | file_so->name); | 
|  | } | 
|  | else | 
|  | { | 
|  | /* Non-empty OSO for a Dwarf file.  */ | 
|  | oso_file = symbol_table + i; | 
|  | nbr_syms = 0; | 
|  | state = S_DWARF_FILE; | 
|  | } | 
|  | } | 
|  | else | 
|  | complaint (_("Unexpected stab after SO")); | 
|  | break; | 
|  |  | 
|  | case S_STAB_FILE: | 
|  | case S_DWARF_FILE: | 
|  | if (mach_o_sym->n_type == N_SO) | 
|  | { | 
|  | if (sym->name == NULL || sym->name[0] == 0) | 
|  | { | 
|  | /* End of file.  */ | 
|  | if (state == S_DWARF_FILE) | 
|  | oso_vector_ptr->emplace_back (oso_file, symbol_table + i, | 
|  | nbr_syms); | 
|  | state = S_NO_SO; | 
|  | } | 
|  | else | 
|  | { | 
|  | complaint (_("Missing nul SO")); | 
|  | file_so = sym; | 
|  | state = S_FIRST_SO; | 
|  | } | 
|  | } | 
|  | else if (sym->flags & BSF_DEBUGGING) | 
|  | { | 
|  | if (state == S_STAB_FILE) | 
|  | { | 
|  | /* FIXME: to be implemented.  */ | 
|  | } | 
|  | else | 
|  | { | 
|  | switch (mach_o_sym->n_type) | 
|  | { | 
|  | case N_FUN: | 
|  | if (sym->name == NULL || sym->name[0] == 0) | 
|  | break; | 
|  | [[fallthrough]]; | 
|  | case N_STSYM: | 
|  | /* Interesting symbol.  */ | 
|  | nbr_syms++; | 
|  | break; | 
|  | case N_ENSYM: | 
|  | case N_BNSYM: | 
|  | case N_GSYM: | 
|  | break; | 
|  | default: | 
|  | complaint (_("unhandled stab for dwarf OSO file")); | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  | else | 
|  | complaint (_("non-debugging symbol within SO")); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (state != S_NO_SO) | 
|  | complaint (_("missing nul SO")); | 
|  | } | 
|  |  | 
|  | /* If NAME describes an archive member (ie: ARCHIVE '(' MEMBER ')'), | 
|  | returns the length of the archive name. | 
|  | Returns -1 otherwise.  */ | 
|  |  | 
|  | static int | 
|  | get_archive_prefix_len (const char *name) | 
|  | { | 
|  | const char *lparen; | 
|  | int name_len = strlen (name); | 
|  |  | 
|  | if (name_len == 0 || name[name_len - 1] != ')') | 
|  | return -1; | 
|  |  | 
|  | lparen = strrchr (name, '('); | 
|  | if (lparen == NULL || lparen == name) | 
|  | return -1; | 
|  | return lparen - name; | 
|  | } | 
|  |  | 
|  | /* Compare function to std::sort OSOs, so that members of a library | 
|  | are gathered.  */ | 
|  |  | 
|  | static bool | 
|  | oso_el_compare_name (const oso_el &l, const oso_el &r) | 
|  | { | 
|  | return strcmp (l.name, r.name) < 0; | 
|  | } | 
|  |  | 
|  | /* Hash table entry structure for the stabs symbols in the main object file. | 
|  | This is used to speed up lookup for symbols in the OSO.  */ | 
|  |  | 
|  | struct macho_sym_hash_entry | 
|  | { | 
|  | struct bfd_hash_entry base; | 
|  | const asymbol *sym; | 
|  | }; | 
|  |  | 
|  | /* Routine to create an entry in the hash table.  */ | 
|  |  | 
|  | static struct bfd_hash_entry * | 
|  | macho_sym_hash_newfunc (struct bfd_hash_entry *entry, | 
|  | struct bfd_hash_table *table, | 
|  | const char *string) | 
|  | { | 
|  | struct macho_sym_hash_entry *ret = (struct macho_sym_hash_entry *) entry; | 
|  |  | 
|  | /* Allocate the structure if it has not already been allocated by a | 
|  | subclass.  */ | 
|  | if (ret == NULL) | 
|  | ret = (struct macho_sym_hash_entry *) bfd_hash_allocate (table, | 
|  | sizeof (* ret)); | 
|  | if (ret == NULL) | 
|  | return NULL; | 
|  |  | 
|  | /* Call the allocation method of the superclass.  */ | 
|  | ret = (struct macho_sym_hash_entry *) | 
|  | bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string); | 
|  |  | 
|  | if (ret) | 
|  | { | 
|  | /* Initialize the local fields.  */ | 
|  | ret->sym = NULL; | 
|  | } | 
|  |  | 
|  | return (struct bfd_hash_entry *) ret; | 
|  | } | 
|  |  | 
|  | /* Get the value of SYM from the minimal symtab of MAIN_OBJFILE.  This is used | 
|  | to get the value of global and common symbols.  */ | 
|  |  | 
|  | static CORE_ADDR | 
|  | macho_resolve_oso_sym_with_minsym (struct objfile *main_objfile, asymbol *sym) | 
|  | { | 
|  | /* For common symbol and global symbols, use the min symtab.  */ | 
|  | const char *name = sym->name; | 
|  |  | 
|  | if (*name != '\0' | 
|  | && *name == bfd_get_symbol_leading_char (main_objfile->obfd.get ())) | 
|  | ++name; | 
|  |  | 
|  | bound_minimal_symbol msym | 
|  | = lookup_minimal_symbol (current_program_space, name, main_objfile); | 
|  | if (msym.minsym == NULL) | 
|  | { | 
|  | warning (_("can't find symbol '%s' in minsymtab"), name); | 
|  | return 0; | 
|  | } | 
|  | else | 
|  | return msym.value_address (); | 
|  | } | 
|  |  | 
|  | /* Add oso file OSO/ABFD as a symbol file.  */ | 
|  |  | 
|  | static void | 
|  | macho_add_oso_symfile (oso_el *oso, const gdb_bfd_ref_ptr &abfd, | 
|  | const char *name, | 
|  | struct objfile *main_objfile, | 
|  | symfile_add_flags symfile_flags) | 
|  | { | 
|  | int storage; | 
|  | int i; | 
|  | asymbol **symbol_table; | 
|  | asymbol **symp; | 
|  | struct bfd_hash_table table; | 
|  | int nbr_sections; | 
|  |  | 
|  | /* Per section flag to mark which section have been rebased.  */ | 
|  | unsigned char *sections_rebased; | 
|  |  | 
|  | macho_debug (0, _("Loading debugging symbols from oso: %s\n"), oso->name); | 
|  |  | 
|  | if (!bfd_check_format (abfd.get (), bfd_object)) | 
|  | { | 
|  | warning (_("`%s': can't read symbols: %s."), oso->name, | 
|  | bfd_errmsg (bfd_get_error ())); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (abfd->my_archive == nullptr | 
|  | && oso->mtime != gdb_bfd_get_mtime (abfd.get ())) | 
|  | { | 
|  | warning (_("`%s': file time stamp mismatch."), oso->name); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (!bfd_hash_table_init_n (&table, macho_sym_hash_newfunc, | 
|  | sizeof (struct macho_sym_hash_entry), | 
|  | oso->nbr_syms)) | 
|  | { | 
|  | warning (_("`%s': can't create hash table"), oso->name); | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* Read symbols table.  */ | 
|  | storage = bfd_get_symtab_upper_bound (abfd.get ()); | 
|  | symbol_table = (asymbol **) xmalloc (storage); | 
|  | bfd_canonicalize_symtab (abfd.get (), symbol_table); | 
|  |  | 
|  | /* Init section flags.  */ | 
|  | nbr_sections = bfd_count_sections (abfd.get ()); | 
|  | sections_rebased = (unsigned char *) alloca (nbr_sections); | 
|  | for (i = 0; i < nbr_sections; i++) | 
|  | sections_rebased[i] = 0; | 
|  |  | 
|  | /* Put symbols for the OSO file in the hash table.  */ | 
|  | for (symp = oso->oso_sym; symp != oso->end_sym; symp++) | 
|  | { | 
|  | const asymbol *sym = *symp; | 
|  | bfd_mach_o_asymbol *mach_o_sym = (bfd_mach_o_asymbol *)sym; | 
|  |  | 
|  | switch (mach_o_sym->n_type) | 
|  | { | 
|  | case N_ENSYM: | 
|  | case N_BNSYM: | 
|  | case N_GSYM: | 
|  | sym = NULL; | 
|  | break; | 
|  | case N_FUN: | 
|  | if (sym->name == NULL || sym->name[0] == 0) | 
|  | sym = NULL; | 
|  | break; | 
|  | case N_STSYM: | 
|  | break; | 
|  | default: | 
|  | sym = NULL; | 
|  | break; | 
|  | } | 
|  | if (sym != NULL) | 
|  | { | 
|  | struct macho_sym_hash_entry *ent; | 
|  |  | 
|  | ent = (struct macho_sym_hash_entry *) | 
|  | bfd_hash_lookup (&table, sym->name, TRUE, FALSE); | 
|  | if (ent->sym != NULL) | 
|  | complaint (_("Duplicated symbol %s in symbol table"), sym->name); | 
|  | else | 
|  | { | 
|  | macho_debug (4, _("Adding symbol %s (addr: %s)\n"), | 
|  | sym->name, paddress (main_objfile->arch (), | 
|  | sym->value)); | 
|  | ent->sym = sym; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Relocate symbols of the OSO.  */ | 
|  | for (i = 0; symbol_table[i]; i++) | 
|  | { | 
|  | asymbol *sym = symbol_table[i]; | 
|  | bfd_mach_o_asymbol *mach_o_sym = (bfd_mach_o_asymbol *)sym; | 
|  |  | 
|  | if (mach_o_sym->n_type & BFD_MACH_O_N_STAB) | 
|  | continue; | 
|  | if ((mach_o_sym->n_type & BFD_MACH_O_N_TYPE) == BFD_MACH_O_N_UNDF | 
|  | && sym->value != 0) | 
|  | { | 
|  | /* For common symbol use the min symtab and modify the OSO | 
|  | symbol table.  */ | 
|  | CORE_ADDR res; | 
|  |  | 
|  | res = macho_resolve_oso_sym_with_minsym (main_objfile, sym); | 
|  | if (res != 0) | 
|  | { | 
|  | sym->section = bfd_com_section_ptr; | 
|  | sym->value = res; | 
|  | } | 
|  | } | 
|  | else if ((mach_o_sym->n_type & BFD_MACH_O_N_TYPE) == BFD_MACH_O_N_SECT) | 
|  | { | 
|  | /* Normal symbol.  */ | 
|  | asection *sec = sym->section; | 
|  | bfd_mach_o_section *msec; | 
|  | unsigned int sec_type; | 
|  |  | 
|  | /* Skip buggy ones.  */ | 
|  | if (sec == NULL || sections_rebased[sec->index] != 0) | 
|  | continue; | 
|  |  | 
|  | /* Only consider regular, non-debugging sections.  */ | 
|  | msec = bfd_mach_o_get_mach_o_section (sec); | 
|  | sec_type = msec->flags & BFD_MACH_O_SECTION_TYPE_MASK; | 
|  | if ((sec_type == BFD_MACH_O_S_REGULAR | 
|  | || sec_type == BFD_MACH_O_S_ZEROFILL) | 
|  | && (msec->flags & BFD_MACH_O_S_ATTR_DEBUG) == 0) | 
|  | { | 
|  | CORE_ADDR addr = 0; | 
|  |  | 
|  | if ((mach_o_sym->n_type & BFD_MACH_O_N_EXT) != 0) | 
|  | { | 
|  | /* Use the min symtab for global symbols.  */ | 
|  | addr = macho_resolve_oso_sym_with_minsym (main_objfile, sym); | 
|  | } | 
|  | else | 
|  | { | 
|  | struct macho_sym_hash_entry *ent; | 
|  |  | 
|  | ent = (struct macho_sym_hash_entry *) | 
|  | bfd_hash_lookup (&table, sym->name, FALSE, FALSE); | 
|  | if (ent != NULL) | 
|  | addr = bfd_asymbol_value (ent->sym); | 
|  | } | 
|  |  | 
|  | /* Adjust the section.  */ | 
|  | if (addr != 0) | 
|  | { | 
|  | CORE_ADDR res = addr - sym->value; | 
|  |  | 
|  | macho_debug (3, _("resolve sect %s with %s (set to %s)\n"), | 
|  | sec->name, sym->name, | 
|  | paddress (main_objfile->arch (), res)); | 
|  | bfd_set_section_vma (sec, res); | 
|  | sections_rebased[sec->index] = 1; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | /* Mark the section as never rebased.  */ | 
|  | sections_rebased[sec->index] = 2; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | bfd_hash_table_free (&table); | 
|  |  | 
|  | /* We need to clear SYMFILE_MAINLINE to avoid interactive question | 
|  | from symfile.c:symbol_file_add_with_addrs_or_offsets.  */ | 
|  | symbol_file_add_from_bfd | 
|  | (abfd, name, symfile_flags & ~(SYMFILE_MAINLINE | SYMFILE_VERBOSE), | 
|  | NULL, | 
|  | main_objfile->flags & (OBJF_SHARED | OBJF_READNOW | OBJF_USERLOADED), | 
|  | main_objfile); | 
|  | } | 
|  |  | 
|  | /* Read symbols from the vector of oso files. | 
|  |  | 
|  | Note that this function sorts OSO_VECTOR_PTR.  */ | 
|  |  | 
|  | static void | 
|  | macho_symfile_read_all_oso (std::vector<oso_el> *oso_vector_ptr, | 
|  | struct objfile *main_objfile, | 
|  | symfile_add_flags symfile_flags) | 
|  | { | 
|  | int ix; | 
|  | oso_el *oso; | 
|  |  | 
|  | /* Sort oso by name so that files from libraries are gathered.  */ | 
|  | std::sort (oso_vector_ptr->begin (), oso_vector_ptr->end (), | 
|  | oso_el_compare_name); | 
|  |  | 
|  | for (ix = 0; ix < oso_vector_ptr->size ();) | 
|  | { | 
|  | int pfx_len; | 
|  |  | 
|  | oso = &(*oso_vector_ptr)[ix]; | 
|  |  | 
|  | /* Check if this is a library name.  */ | 
|  | pfx_len = get_archive_prefix_len (oso->name); | 
|  | if (pfx_len > 0) | 
|  | { | 
|  | int last_ix; | 
|  | oso_el *oso2; | 
|  | int ix2; | 
|  |  | 
|  | std::string archive_name (oso->name, pfx_len); | 
|  |  | 
|  | /* Compute number of oso for this archive.  */ | 
|  | for (last_ix = ix; last_ix < oso_vector_ptr->size (); last_ix++) | 
|  | { | 
|  | oso2 = &(*oso_vector_ptr)[last_ix]; | 
|  | if (strncmp (oso2->name, archive_name.c_str (), pfx_len) != 0) | 
|  | break; | 
|  | } | 
|  |  | 
|  | /* Open the archive and check the format.  */ | 
|  | gdb_bfd_ref_ptr archive_bfd (gdb_bfd_open (archive_name.c_str (), | 
|  | gnutarget)); | 
|  | if (archive_bfd == NULL) | 
|  | { | 
|  | warning (_("Could not open OSO archive file \"%s\""), | 
|  | archive_name.c_str ()); | 
|  | ix = last_ix; | 
|  | continue; | 
|  | } | 
|  | if (!bfd_check_format (archive_bfd.get (), bfd_archive)) | 
|  | { | 
|  | warning (_("OSO archive file \"%s\" not an archive."), | 
|  | archive_name.c_str ()); | 
|  | ix = last_ix; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | gdb_bfd_ref_ptr member_bfd | 
|  | (gdb_bfd_openr_next_archived_file (archive_bfd.get (), NULL)); | 
|  |  | 
|  | if (member_bfd == NULL) | 
|  | { | 
|  | warning (_("Could not read archive members out of " | 
|  | "OSO archive \"%s\""), archive_name.c_str ()); | 
|  | ix = last_ix; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | /* Load all oso in this library.  */ | 
|  | while (member_bfd != NULL) | 
|  | { | 
|  | const char *member_name = bfd_get_filename (member_bfd.get ()); | 
|  | int member_len = strlen (member_name); | 
|  |  | 
|  | /* If this member is referenced, add it as a symfile.  */ | 
|  | for (ix2 = ix; ix2 < last_ix; ix2++) | 
|  | { | 
|  | oso2 = &(*oso_vector_ptr)[ix2]; | 
|  |  | 
|  | if (oso2->name | 
|  | && strlen (oso2->name) == pfx_len + member_len + 2 | 
|  | && !memcmp (member_name, oso2->name + pfx_len + 1, | 
|  | member_len)) | 
|  | { | 
|  | macho_add_oso_symfile (oso2, member_bfd, | 
|  | bfd_get_filename (member_bfd.get ()), | 
|  | main_objfile, symfile_flags); | 
|  | oso2->name = NULL; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | member_bfd = gdb_bfd_openr_next_archived_file (archive_bfd.get (), | 
|  | member_bfd.get ()); | 
|  | } | 
|  | for (ix2 = ix; ix2 < last_ix; ix2++) | 
|  | { | 
|  | oso2 = &(*oso_vector_ptr)[ix2]; | 
|  |  | 
|  | if (oso2->name != NULL) | 
|  | warning (_("Could not find specified archive member " | 
|  | "for OSO name \"%s\""), oso->name); | 
|  | } | 
|  | ix = last_ix; | 
|  | } | 
|  | else | 
|  | { | 
|  | gdb_bfd_ref_ptr abfd (gdb_bfd_open (oso->name, gnutarget)); | 
|  | if (abfd == NULL) | 
|  | warning (_("`%s': can't open to read symbols: %s."), oso->name, | 
|  | bfd_errmsg (bfd_get_error ())); | 
|  | else | 
|  | macho_add_oso_symfile (oso, abfd, oso->name, main_objfile, | 
|  | symfile_flags); | 
|  |  | 
|  | ix++; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /* DSYM (debug symbols) files contain the debug info of an executable. | 
|  | This is a separate file created by dsymutil(1) and is similar to debug | 
|  | link feature on ELF. | 
|  | DSYM files are located in a subdirectory.  Append DSYM_SUFFIX to the | 
|  | executable name and the executable base name to get the DSYM file name.  */ | 
|  | #define DSYM_SUFFIX ".dSYM/Contents/Resources/DWARF/" | 
|  |  | 
|  | /* Check if a dsym file exists for OBJFILE.  If so, returns a bfd for it | 
|  | and return *FILENAMEP with its original filename. | 
|  | Return NULL if no valid dsym file is found (FILENAMEP is not used in | 
|  | such case).  */ | 
|  |  | 
|  | static gdb_bfd_ref_ptr | 
|  | macho_check_dsym (struct objfile *objfile, std::string *filenamep) | 
|  | { | 
|  | size_t name_len = strlen (objfile_name (objfile)); | 
|  | size_t dsym_len = strlen (DSYM_SUFFIX); | 
|  | const char *base_name = lbasename (objfile_name (objfile)); | 
|  | size_t base_len = strlen (base_name); | 
|  | char *dsym_filename = (char *) alloca (name_len + dsym_len + base_len + 1); | 
|  | bfd_mach_o_load_command *main_uuid; | 
|  | bfd_mach_o_load_command *dsym_uuid; | 
|  |  | 
|  | strcpy (dsym_filename, objfile_name (objfile)); | 
|  | strcpy (dsym_filename + name_len, DSYM_SUFFIX); | 
|  | strcpy (dsym_filename + name_len + dsym_len, base_name); | 
|  |  | 
|  | if (access (dsym_filename, R_OK) != 0) | 
|  | return NULL; | 
|  |  | 
|  | if (bfd_mach_o_lookup_command (objfile->obfd.get (), | 
|  | BFD_MACH_O_LC_UUID, &main_uuid) == 0) | 
|  | { | 
|  | warning (_("can't find UUID in %s"), objfile_name (objfile)); | 
|  | return NULL; | 
|  | } | 
|  | gdb_bfd_ref_ptr dsym_bfd (gdb_bfd_openr (dsym_filename, gnutarget)); | 
|  | if (dsym_bfd == NULL) | 
|  | { | 
|  | warning (_("can't open dsym file %s"), dsym_filename); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | if (!bfd_check_format (dsym_bfd.get (), bfd_object)) | 
|  | { | 
|  | warning (_("bad dsym file format: %s"), bfd_errmsg (bfd_get_error ())); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | if (bfd_mach_o_lookup_command (dsym_bfd.get (), | 
|  | BFD_MACH_O_LC_UUID, &dsym_uuid) == 0) | 
|  | { | 
|  | warning (_("can't find UUID in %s"), dsym_filename); | 
|  | return NULL; | 
|  | } | 
|  | if (memcmp (dsym_uuid->command.uuid.uuid, main_uuid->command.uuid.uuid, | 
|  | sizeof (main_uuid->command.uuid.uuid))) | 
|  | { | 
|  | warning (_("dsym file UUID doesn't match the one in %s"), | 
|  | objfile_name (objfile)); | 
|  | return NULL; | 
|  | } | 
|  | *filenamep = std::string (dsym_filename); | 
|  | return dsym_bfd; | 
|  | } | 
|  |  | 
|  | static void | 
|  | macho_symfile_read (struct objfile *objfile, symfile_add_flags symfile_flags) | 
|  | { | 
|  | bfd *abfd = objfile->obfd.get (); | 
|  | long storage_needed; | 
|  | std::vector<oso_el> oso_vector; | 
|  | /* We have to hold on to the symbol table until the call to | 
|  | macho_symfile_read_all_oso at the end of this function.  */ | 
|  | gdb::def_vector<asymbol *> symbol_table; | 
|  |  | 
|  | dwarf2_initialize_objfile (objfile); | 
|  |  | 
|  | /* Get symbols from the symbol table only if the file is an executable. | 
|  | The symbol table of object files is not relocated and is expected to | 
|  | be in the executable.  */ | 
|  | if (bfd_get_file_flags (abfd) & (EXEC_P | DYNAMIC)) | 
|  | { | 
|  | std::string dsym_filename; | 
|  |  | 
|  | /* Process the normal symbol table first.  */ | 
|  | storage_needed = bfd_get_symtab_upper_bound (objfile->obfd.get ()); | 
|  | if (storage_needed < 0) | 
|  | error (_("Can't read symbols from %s: %s"), | 
|  | bfd_get_filename (objfile->obfd.get ()), | 
|  | bfd_errmsg (bfd_get_error ())); | 
|  |  | 
|  | if (storage_needed > 0) | 
|  | { | 
|  | long symcount; | 
|  |  | 
|  | symbol_table.resize (storage_needed / sizeof (asymbol *)); | 
|  |  | 
|  | minimal_symbol_reader reader (objfile); | 
|  |  | 
|  | symcount = bfd_canonicalize_symtab (objfile->obfd.get (), | 
|  | symbol_table.data ()); | 
|  |  | 
|  | if (symcount < 0) | 
|  | error (_("Can't read symbols from %s: %s"), | 
|  | bfd_get_filename (objfile->obfd.get ()), | 
|  | bfd_errmsg (bfd_get_error ())); | 
|  |  | 
|  | macho_symtab_read (reader, objfile, symcount, symbol_table.data (), | 
|  | &oso_vector); | 
|  |  | 
|  | reader.install (); | 
|  | } | 
|  |  | 
|  | /* Try to read .eh_frame / .debug_frame.  */ | 
|  | dwarf2_build_frame_info (objfile); | 
|  |  | 
|  | /* Check for DSYM file.  */ | 
|  | gdb_bfd_ref_ptr dsym_bfd (macho_check_dsym (objfile, &dsym_filename)); | 
|  | if (dsym_bfd != NULL) | 
|  | { | 
|  | struct bfd_section *asect, *dsect; | 
|  |  | 
|  | macho_debug (0, _("dsym file found\n")); | 
|  |  | 
|  | /* Set dsym section size.  */ | 
|  | for (asect = objfile->obfd->sections, dsect = dsym_bfd->sections; | 
|  | asect && dsect; | 
|  | asect = asect->next, dsect = dsect->next) | 
|  | { | 
|  | if (strcmp (asect->name, dsect->name) != 0) | 
|  | break; | 
|  | bfd_set_section_size (dsect, bfd_section_size (asect)); | 
|  | } | 
|  |  | 
|  | /* Add the dsym file as a separate file.  */ | 
|  | symbol_file_add_separate (dsym_bfd, dsym_filename.c_str (), | 
|  | symfile_flags, objfile); | 
|  |  | 
|  | /* Don't try to read dwarf2 from main file or shared libraries.  */ | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Then the oso.  */ | 
|  | if (!oso_vector.empty ()) | 
|  | macho_symfile_read_all_oso (&oso_vector, objfile, symfile_flags); | 
|  | } | 
|  |  | 
|  | static bfd_byte * | 
|  | macho_symfile_relocate (struct objfile *objfile, asection *sectp, | 
|  | bfd_byte *buf) | 
|  | { | 
|  | bfd *abfd = objfile->obfd.get (); | 
|  |  | 
|  | /* We're only interested in sections with relocation | 
|  | information.  */ | 
|  | if ((sectp->flags & SEC_RELOC) == 0) | 
|  | return NULL; | 
|  |  | 
|  | macho_debug (0, _("Relocate section '%s' of %s\n"), | 
|  | sectp->name, objfile_name (objfile)); | 
|  |  | 
|  | return bfd_simple_get_relocated_section_contents (abfd, sectp, buf, NULL); | 
|  | } | 
|  |  | 
|  | static void | 
|  | macho_symfile_finish (struct objfile *objfile) | 
|  | { | 
|  | } | 
|  |  | 
|  | static void | 
|  | macho_symfile_offsets (struct objfile *objfile, | 
|  | const section_addr_info &addrs) | 
|  | { | 
|  | unsigned int i; | 
|  |  | 
|  | /* Allocate section_offsets.  */ | 
|  | objfile->section_offsets.assign (gdb_bfd_count_sections (objfile->obfd.get ()), 0); | 
|  |  | 
|  | /* This code is run when we first add the objfile with | 
|  | symfile_add_with_addrs_or_offsets, when "addrs" not "offsets" are | 
|  | passed in.  The place in symfile.c where the addrs are applied | 
|  | depends on the addrs having section names.  But in the dyld code | 
|  | we build an anonymous array of addrs, so that code is a no-op. | 
|  | Because of that, we have to apply the addrs to the sections here. | 
|  | N.B. if an objfile slides after we've already created it, then it | 
|  | goes through objfile_relocate.  */ | 
|  |  | 
|  | for (i = 0; i < addrs.size (); i++) | 
|  | { | 
|  | for (obj_section *osect : objfile->sections ()) | 
|  | { | 
|  | const char *bfd_sect_name = osect->the_bfd_section->name; | 
|  |  | 
|  | if (bfd_sect_name == addrs[i].name) | 
|  | { | 
|  | osect->set_offset (addrs[i].addr); | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | objfile->sect_index_text = 0; | 
|  |  | 
|  | for (obj_section *osect : objfile->sections ()) | 
|  | { | 
|  | const char *bfd_sect_name = osect->the_bfd_section->name; | 
|  | int sect_index = osect - objfile->sections_start; | 
|  |  | 
|  | if (startswith (bfd_sect_name, "LC_SEGMENT.")) | 
|  | bfd_sect_name += 11; | 
|  | if (strcmp (bfd_sect_name, "__TEXT") == 0 | 
|  | || strcmp (bfd_sect_name, "__TEXT.__text") == 0) | 
|  | objfile->sect_index_text = sect_index; | 
|  | } | 
|  | } | 
|  |  | 
|  | static const struct sym_fns macho_sym_fns = { | 
|  | macho_new_init,               /* init anything gbl to entire symtab */ | 
|  | macho_symfile_init,           /* read initial info, setup for sym_read() */ | 
|  | macho_symfile_read,           /* read a symbol file into symtab */ | 
|  | macho_symfile_finish,         /* finished with file, cleanup */ | 
|  | macho_symfile_offsets,        /* xlate external to internal form */ | 
|  | default_symfile_segments,	/* Get segment information from a file.  */ | 
|  | NULL, | 
|  | macho_symfile_relocate,	/* Relocate a debug section.  */ | 
|  | NULL,				/* sym_get_probes */ | 
|  | }; | 
|  |  | 
|  | void _initialize_machoread (); | 
|  | void | 
|  | _initialize_machoread () | 
|  | { | 
|  | add_symtab_fns (bfd_target_mach_o_flavour, &macho_sym_fns); | 
|  |  | 
|  | add_setshow_zuinteger_cmd ("mach-o", class_obscure, | 
|  | &mach_o_debug_level, | 
|  | _("Set if printing Mach-O symbols processing."), | 
|  | _("Show if printing Mach-O symbols processing."), | 
|  | NULL, NULL, NULL, | 
|  | &setdebuglist, &showdebuglist); | 
|  | } |