| /* Read a symbol table in MIPS' format (Third-Eye). | 
 |  | 
 |    Copyright (C) 1986-2023 Free Software Foundation, Inc. | 
 |  | 
 |    Contributed by Alessandro Forin (af@cs.cmu.edu) at CMU.  Major work | 
 |    by Per Bothner, John Gilmore and Ian Lance Taylor at Cygnus Support. | 
 |  | 
 |    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/>.  */ | 
 |  | 
 | /* Read symbols from an ECOFF file.  Most of the work is done in | 
 |    mdebugread.c.  */ | 
 |  | 
 | #include "defs.h" | 
 | #include "bfd.h" | 
 | #include "symtab.h" | 
 | #include "objfiles.h" | 
 | #include "stabsread.h" | 
 | #include "mdebugread.h" | 
 |  | 
 | #include "coff/sym.h" | 
 | #include "coff/internal.h" | 
 | #include "coff/ecoff.h" | 
 | #include "libcoff.h" | 
 | #include "libecoff.h" | 
 | #include "elf/common.h" | 
 | #include "elf/internal.h" | 
 | #include "elf/mips.h" | 
 |  | 
 | static void | 
 | read_alphacoff_dynamic_symtab (minimal_symbol_reader &, | 
 | 			       struct objfile *objfile); | 
 |  | 
 | /* Initialize anything that needs initializing when a completely new | 
 |    symbol file is specified (not just adding some symbols from another | 
 |    file, e.g. a shared library).  */ | 
 |  | 
 | static void | 
 | mipscoff_new_init (struct objfile *ignore) | 
 | { | 
 |   stabsread_new_init (); | 
 | } | 
 |  | 
 | /* Initialize to read a symbol file (nothing to do).  */ | 
 |  | 
 | static void | 
 | mipscoff_symfile_init (struct objfile *objfile) | 
 | { | 
 | } | 
 |  | 
 | /* Read a symbol file from a file.  */ | 
 |  | 
 | static void | 
 | mipscoff_symfile_read (struct objfile *objfile, symfile_add_flags symfile_flags) | 
 | { | 
 |   bfd *abfd = objfile->obfd.get (); | 
 |  | 
 |   minimal_symbol_reader reader (objfile); | 
 |  | 
 |   /* Now that the executable file is positioned at symbol table, | 
 |      process it and define symbols accordingly.  */ | 
 |  | 
 |   if (!((*ecoff_backend (abfd)->debug_swap.read_debug_info) | 
 | 	(abfd, NULL, &ecoff_data (abfd)->debug_info))) | 
 |     error (_("Error reading symbol table: %s"), bfd_errmsg (bfd_get_error ())); | 
 |  | 
 |   mdebug_build_psymtabs (reader, objfile, &ecoff_backend (abfd)->debug_swap, | 
 | 			 &ecoff_data (abfd)->debug_info); | 
 |  | 
 |   /* Add alpha coff dynamic symbols.  */ | 
 |  | 
 |   read_alphacoff_dynamic_symtab (reader, objfile); | 
 |  | 
 |   /* Install any minimal symbols that have been collected as the current | 
 |      minimal symbols for this objfile.  */ | 
 |  | 
 |   reader.install (); | 
 | } | 
 |  | 
 | /* Perform any local cleanups required when we are done with a | 
 |    particular objfile.  */ | 
 |  | 
 | static void | 
 | mipscoff_symfile_finish (struct objfile *objfile) | 
 | { | 
 | } | 
 |  | 
 | /* Alpha OSF/1 encapsulates the dynamic symbols in ELF format in a | 
 |    standard COFF section.  The ELF format for the symbols differs from | 
 |    the format defined in elf/external.h.  It seems that a normal ELF | 
 |    32-bit format is used, and the representation only changes because | 
 |    longs are 64-bit on the alpha.  In addition, the handling of | 
 |    text/data section indices for symbols is different from the ELF | 
 |    ABI.  As the BFD linker currently does not support dynamic linking | 
 |    on the alpha, there seems to be no reason to pollute BFD with | 
 |    another mixture of object file formats for now.  */ | 
 |  | 
 | /* Format of an alpha external ELF symbol.  */ | 
 |  | 
 | typedef struct | 
 | { | 
 |   unsigned char st_name[4];	/* Symbol name, index in string table.  */ | 
 |   unsigned char st_pad[4];	/* Pad to long word boundary.  */ | 
 |   unsigned char st_value[8];	/* Value of the symbol.  */ | 
 |   unsigned char st_size[4];	/* Associated symbol size.  */ | 
 |   unsigned char st_info[1];	/* Type and binding attributes.  */ | 
 |   unsigned char st_other[1];	/* No defined meaning, 0.  */ | 
 |   unsigned char st_shndx[2];	/* Associated section index.  */ | 
 | } Elfalpha_External_Sym; | 
 |  | 
 | /* Format of an alpha external ELF dynamic info structure.  */ | 
 |  | 
 | typedef struct | 
 | { | 
 |   unsigned char d_tag[4];	/* Tag.  */ | 
 |   unsigned char d_pad[4];	/* Pad to long word boundary.  */ | 
 |   union | 
 |   { | 
 |     unsigned char d_ptr[8];	/* Pointer value.  */ | 
 |     unsigned char d_val[4];	/* Integer value.  */ | 
 |   } | 
 |   d_un; | 
 | } Elfalpha_External_Dyn; | 
 |  | 
 | /* Struct to obtain the section pointers for alpha dynamic symbol info.  */ | 
 |  | 
 | struct alphacoff_dynsecinfo | 
 | { | 
 |   asection *sym_sect;		/* Section pointer for .dynsym section.  */ | 
 |   asection *str_sect;		/* Section pointer for .dynstr section.  */ | 
 |   asection *dyninfo_sect;	/* Section pointer for .dynamic section.  */ | 
 |   asection *got_sect;		/* Section pointer for .got section.  */ | 
 | }; | 
 |  | 
 | /* We are called once per section from read_alphacoff_dynamic_symtab. | 
 |    We need to examine each section we are passed, check to see if it | 
 |    is something we are interested in processing, and if so, stash away | 
 |    some access information for the section.  */ | 
 |  | 
 | static void | 
 | alphacoff_locate_sections (bfd *ignore_abfd, asection *sectp, void *sip) | 
 | { | 
 |   struct alphacoff_dynsecinfo *si; | 
 |  | 
 |   si = (struct alphacoff_dynsecinfo *) sip; | 
 |  | 
 |   if (strcmp (sectp->name, ".dynsym") == 0) | 
 |     si->sym_sect = sectp; | 
 |   else if (strcmp (sectp->name, ".dynstr") == 0) | 
 |     si->str_sect = sectp; | 
 |   else if (strcmp (sectp->name, ".dynamic") == 0) | 
 |     si->dyninfo_sect = sectp; | 
 |   else if (strcmp (sectp->name, ".got") == 0) | 
 |       si->got_sect = sectp; | 
 | } | 
 |  | 
 | /* Scan an alpha dynamic symbol table for symbols of interest and add | 
 |    them to the minimal symbol table.  */ | 
 |  | 
 | static void | 
 | read_alphacoff_dynamic_symtab (minimal_symbol_reader &reader, | 
 | 			       struct objfile *objfile) | 
 | { | 
 |   bfd *abfd = objfile->obfd.get (); | 
 |   struct alphacoff_dynsecinfo si; | 
 |   int sym_count; | 
 |   int i; | 
 |   int stripped; | 
 |   Elfalpha_External_Sym *x_symp; | 
 |   gdb_byte *dyninfo_p; | 
 |   gdb_byte *dyninfo_end; | 
 |   int got_entry_size = 8; | 
 |   int dt_mips_local_gotno = -1; | 
 |   int dt_mips_gotsym = -1; | 
 |  | 
 |   /* We currently only know how to handle alpha dynamic symbols.  */ | 
 |   if (bfd_get_arch (abfd) != bfd_arch_alpha) | 
 |     return; | 
 |  | 
 |   /* Locate the dynamic symbols sections and read them in.  */ | 
 |   memset ((char *) &si, 0, sizeof (si)); | 
 |   bfd_map_over_sections (abfd, alphacoff_locate_sections, (void *) & si); | 
 |   if (si.sym_sect == NULL || si.str_sect == NULL | 
 |       || si.dyninfo_sect == NULL || si.got_sect == NULL) | 
 |     return; | 
 |  | 
 |   gdb::byte_vector sym_sec (bfd_section_size (si.sym_sect)); | 
 |   gdb::byte_vector str_sec (bfd_section_size (si.str_sect)); | 
 |   gdb::byte_vector dyninfo_sec (bfd_section_size (si.dyninfo_sect)); | 
 |   gdb::byte_vector got_sec (bfd_section_size (si.got_sect)); | 
 |  | 
 |   if (!bfd_get_section_contents (abfd, si.sym_sect, sym_sec.data (), | 
 | 				 (file_ptr) 0, sym_sec.size ())) | 
 |     return; | 
 |   if (!bfd_get_section_contents (abfd, si.str_sect, str_sec.data (), | 
 | 				 (file_ptr) 0, str_sec.size ())) | 
 |     return; | 
 |   if (!bfd_get_section_contents (abfd, si.dyninfo_sect, dyninfo_sec.data (), | 
 | 				 (file_ptr) 0, dyninfo_sec.size ())) | 
 |     return; | 
 |   if (!bfd_get_section_contents (abfd, si.got_sect, got_sec.data (), | 
 | 				 (file_ptr) 0, got_sec.size ())) | 
 |     return; | 
 |  | 
 |   /* Find the number of local GOT entries and the index for the | 
 |      first dynamic symbol in the GOT.  */ | 
 |   for ((dyninfo_p = dyninfo_sec.data (), | 
 | 	dyninfo_end = dyninfo_p + dyninfo_sec.size ()); | 
 |        dyninfo_p < dyninfo_end; | 
 |        dyninfo_p += sizeof (Elfalpha_External_Dyn)) | 
 |     { | 
 |       Elfalpha_External_Dyn *x_dynp = (Elfalpha_External_Dyn *) dyninfo_p; | 
 |       long dyn_tag; | 
 |  | 
 |       dyn_tag = bfd_h_get_32 (abfd, (bfd_byte *) x_dynp->d_tag); | 
 |       if (dyn_tag == DT_NULL) | 
 | 	break; | 
 |       else if (dyn_tag == DT_MIPS_LOCAL_GOTNO) | 
 | 	{ | 
 | 	  if (dt_mips_local_gotno < 0) | 
 | 	    dt_mips_local_gotno | 
 | 	      = bfd_h_get_32 (abfd, (bfd_byte *) x_dynp->d_un.d_val); | 
 | 	} | 
 |       else if (dyn_tag == DT_MIPS_GOTSYM) | 
 | 	{ | 
 | 	  if (dt_mips_gotsym < 0) | 
 | 	    dt_mips_gotsym | 
 | 	      = bfd_h_get_32 (abfd, (bfd_byte *) x_dynp->d_un.d_val); | 
 | 	} | 
 |     } | 
 |   if (dt_mips_local_gotno < 0 || dt_mips_gotsym < 0) | 
 |     return; | 
 |  | 
 |   /* Scan all dynamic symbols and enter them into the minimal symbol | 
 |      table if appropriate.  */ | 
 |   sym_count = sym_sec.size () / sizeof (Elfalpha_External_Sym); | 
 |   stripped = (bfd_get_symcount (abfd) == 0); | 
 |  | 
 |   /* Skip first symbol, which is a null dummy.  */ | 
 |   for (i = 1, x_symp = (Elfalpha_External_Sym *) sym_sec.data () + 1; | 
 |        i < sym_count; | 
 |        i++, x_symp++) | 
 |     { | 
 |       unsigned long strx; | 
 |       char *name; | 
 |       bfd_vma sym_value; | 
 |       unsigned char sym_info; | 
 |       unsigned int sym_shndx; | 
 |       int isglobal; | 
 |       enum minimal_symbol_type ms_type; | 
 |  | 
 |       strx = bfd_h_get_32 (abfd, (bfd_byte *) x_symp->st_name); | 
 |       if (strx >= str_sec.size ()) | 
 | 	continue; | 
 |       name = (char *) (str_sec.data () + strx); | 
 |       if (*name == '\0' || *name == '.') | 
 | 	continue; | 
 |  | 
 |       sym_value = bfd_h_get_64 (abfd, (bfd_byte *) x_symp->st_value); | 
 |       sym_info = bfd_h_get_8 (abfd, (bfd_byte *) x_symp->st_info); | 
 |       sym_shndx = bfd_h_get_16 (abfd, (bfd_byte *) x_symp->st_shndx); | 
 |       if (sym_shndx >= (SHN_LORESERVE & 0xffff)) | 
 | 	sym_shndx += SHN_LORESERVE - (SHN_LORESERVE & 0xffff); | 
 |       isglobal = (ELF_ST_BIND (sym_info) == STB_GLOBAL); | 
 |  | 
 |       if (sym_shndx == SHN_UNDEF) | 
 | 	{ | 
 | 	  /* Handle undefined functions which are defined in a shared | 
 | 	     library.  */ | 
 | 	  if (ELF_ST_TYPE (sym_info) != STT_FUNC | 
 | 	      || ELF_ST_BIND (sym_info) != STB_GLOBAL) | 
 | 	    continue; | 
 |  | 
 | 	  ms_type = mst_solib_trampoline; | 
 |  | 
 | 	  /* If sym_value is nonzero, it points to the shared library | 
 | 	     trampoline entry, which is what we are looking for. | 
 |  | 
 | 	     If sym_value is zero, then we have to get the GOT entry | 
 | 	     for the symbol. | 
 |  | 
 | 	     If the GOT entry is nonzero, it represents the quickstart | 
 | 	     address of the function and we use that as the symbol | 
 | 	     value. | 
 |  | 
 | 	     If the GOT entry is zero, the function address has to be | 
 | 	     resolved by the runtime loader before the executable is | 
 | 	     started.  We are unable to find any meaningful address | 
 | 	     for these functions in the executable file, so we skip | 
 | 	     them.  */ | 
 | 	  if (sym_value == 0) | 
 | 	    { | 
 | 	      int got_entry_offset = | 
 | 		(i - dt_mips_gotsym + dt_mips_local_gotno) * got_entry_size; | 
 |  | 
 | 	      if (got_entry_offset < 0 | 
 | 		  || got_entry_offset >= got_sec.size ()) | 
 | 		continue; | 
 | 	      sym_value = | 
 | 		bfd_h_get_64 (abfd, | 
 | 			      (bfd_byte *) (got_sec.data () | 
 | 					    + got_entry_offset)); | 
 | 	      if (sym_value == 0) | 
 | 		continue; | 
 | 	    } | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  /* Symbols defined in the executable itself.  We only care | 
 | 	     about them if this is a stripped executable, otherwise | 
 | 	     they have been retrieved from the normal symbol table | 
 | 	     already.  */ | 
 | 	  if (!stripped) | 
 | 	    continue; | 
 |  | 
 | 	  if (sym_shndx == SHN_MIPS_TEXT) | 
 | 	    { | 
 | 	      if (isglobal) | 
 | 		ms_type = mst_text; | 
 | 	      else | 
 | 		ms_type = mst_file_text; | 
 | 	    } | 
 | 	  else if (sym_shndx == SHN_MIPS_DATA) | 
 | 	    { | 
 | 	      if (isglobal) | 
 | 		ms_type = mst_data; | 
 | 	      else | 
 | 		ms_type = mst_file_data; | 
 | 	    } | 
 | 	  else if (sym_shndx == SHN_MIPS_ACOMMON) | 
 | 	    { | 
 | 	      if (isglobal) | 
 | 		ms_type = mst_bss; | 
 | 	      else | 
 | 		ms_type = mst_file_bss; | 
 | 	    } | 
 | 	  else if (sym_shndx == SHN_ABS) | 
 | 	    { | 
 | 	      ms_type = mst_abs; | 
 | 	    } | 
 | 	  else | 
 | 	    { | 
 | 	      continue; | 
 | 	    } | 
 | 	} | 
 |  | 
 |       reader.record (name, unrelocated_addr (sym_value), ms_type); | 
 |     } | 
 | } | 
 |  | 
 | /* Initialization.  */ | 
 |  | 
 | static const struct sym_fns ecoff_sym_fns = | 
 | { | 
 |   mipscoff_new_init,		/* init anything gbl to entire symtab */ | 
 |   mipscoff_symfile_init,	/* read initial info, setup for sym_read() */ | 
 |   mipscoff_symfile_read,	/* read a symbol file into symtab */ | 
 |   mipscoff_symfile_finish,	/* finished with file, cleanup */ | 
 |   default_symfile_offsets,	/* dummy FIXME til implem sym reloc */ | 
 |   default_symfile_segments,	/* Get segment information from a file.  */ | 
 |   NULL, | 
 |   default_symfile_relocate,	/* Relocate a debug section.  */ | 
 |   NULL,				/* sym_probe_fns */ | 
 | }; | 
 |  | 
 | void _initialize_mipsread (); | 
 | void | 
 | _initialize_mipsread () | 
 | { | 
 |   add_symtab_fns (bfd_target_ecoff_flavour, &ecoff_sym_fns); | 
 | } |