* som.c (som_bfd_count_ar_symbols): New helper function.
authorJeff Law <law@redhat.com>
Sun, 13 Feb 1994 23:34:52 +0000 (23:34 +0000)
committerJeff Law <law@redhat.com>
Sun, 13 Feb 1994 23:34:52 +0000 (23:34 +0000)
        (som_bfd_fill_in_ar_symbols): New helper function.
        (som_slurp_armap): New function to read a SOM LST.

bfd/ChangeLog
bfd/som.c

index 3a7966eea804b663589db9e83d2b9e8684099e89..484a5b12a33a254b8c98a528821453cc7cb35654 100644 (file)
@@ -1,5 +1,9 @@
 Sun Feb 13 14:30:00 1994  Jeffrey A. Law  (law@snake.cs.utah.edu)
 
+       * som.c (som_bfd_count_ar_symbols): New helper function.
+       (som_bfd_fill_in_ar_symbols): New helper function.
+       (som_slurp_armap): New function to read a SOM LST.
+
        * som.h: Include <lst.h> and <ar.h>.
 
 Sat Feb 12 22:34:14 1994  Jeffrey A. Law  (law@snake.cs.utah.edu)
index 1ce4713ba2ad6287afa91a023e180203bccdb377..13e94e3809fa805201ba83f5f8b2b483b7cb5666 100644 (file)
--- a/bfd/som.c
+++ b/bfd/som.c
@@ -191,7 +191,14 @@ static const reloc_howto_type * som_bfd_reloc_type_lookup
        PARAMS ((bfd_arch_info_type *, bfd_reloc_code_real_type));
 static char som_section_type PARAMS ((const char *));
 static int som_decode_symclass PARAMS ((asymbol *));
+static boolean som_bfd_count_ar_symbols PARAMS ((bfd *, struct lst_header *,
+                                                symindex *));
 
+static boolean som_bfd_fill_in_ar_symbols PARAMS ((bfd *, struct lst_header *,
+                                                  carsym **syms));
+static boolean som_slurp_armap PARAMS ((bfd *));
+static boolean som_write_armap PARAMS ((bfd *));
+static boolean som_slurp_extended_name_table PARAMS ((bfd *));
 
 /* Map SOM section names to POSIX/BSD single-character symbol types.
 
@@ -4190,18 +4197,381 @@ som_get_symbol_info (ignore_abfd, symbol, ret)
   ret->name = symbol->name;
 }
 
+/* Count the number of symbols in the archive symbol table.  Necessary
+   so that we can allocate space for all the carsyms at once.  */
+
+static boolean
+som_bfd_count_ar_symbols (abfd, lst_header, count)
+     bfd *abfd;
+     struct lst_header *lst_header;
+     symindex *count;
+{
+  unsigned int i;
+  unsigned int hash_table[lst_header->hash_size];
+  file_ptr lst_filepos = bfd_tell (abfd) - sizeof (struct lst_header);
+
+  /* Don't forget to initialize the counter!  */
+  *count = 0;
+
+  /* Read in the hash table.  The has table is an array of 32bit file offsets
+     which point to the hash chains.  */
+  if (bfd_read ((PTR) hash_table, lst_header->hash_size, 4, abfd)
+      != lst_header->hash_size * 4)
+    {
+      bfd_error = system_call_error;
+      return false;
+    }
+
+  /* Walk each chain counting the number of symbols found on that particular
+     chain.  */
+  for (i = 0; i < lst_header->hash_size; i++)
+    {
+      struct lst_symbol_record lst_symbol;
+
+      /* An empty chain has zero as it's file offset.  */
+      if (hash_table[i] == 0)
+       continue;
+
+      /* Seek to the first symbol in this hash chain.  */
+      if (bfd_seek (abfd, lst_filepos + hash_table[i], SEEK_SET) < 0)
+       {
+         bfd_error = system_call_error;
+         return false;
+       }
+
+      /* Read in this symbol and update the counter.  */
+      if (bfd_read ((PTR) & lst_symbol, 1, sizeof (lst_symbol), abfd)
+         != sizeof (lst_symbol))
+       {
+         bfd_error = system_call_error;
+         return false;
+       }
+      (*count)++;
+
+      /* Now iterate through the rest of the symbols on this chain.  */
+      while (lst_symbol.next_entry)
+       {
+
+         /* Seek to the next symbol.  */
+         if (bfd_seek (abfd, lst_filepos + lst_symbol.next_entry, SEEK_SET)
+             < 0)
+           {
+             bfd_error = system_call_error;
+             return false;
+           }
+
+         /* Read the symbol in and update the counter.  */
+         if (bfd_read ((PTR) & lst_symbol, 1, sizeof (lst_symbol), abfd)
+             != sizeof (lst_symbol))
+           {
+             bfd_error = system_call_error;
+             return false;
+           }
+         (*count)++;
+       }
+    }
+  return true;
+}
+
+/* Fill in the canonical archive symbols (SYMS) from the archive described
+   by ABFD and LST_HEADER.  */
+
+static boolean
+som_bfd_fill_in_ar_symbols (abfd, lst_header, syms)
+     bfd *abfd;
+     struct lst_header *lst_header;
+     carsym **syms;
+{
+  unsigned int i, len;
+  carsym *set = syms[0];
+  unsigned int hash_table[lst_header->hash_size];
+  struct som_entry som_dict[lst_header->module_count];
+  file_ptr lst_filepos = bfd_tell (abfd) - sizeof (struct lst_header);
+
+  /* Read in the hash table.  The has table is an array of 32bit file offsets
+     which point to the hash chains.  */
+  if (bfd_read ((PTR) hash_table, lst_header->hash_size, 4, abfd)
+      != lst_header->hash_size * 4)
+    {
+      bfd_error = system_call_error;
+      return false;
+    }
+
+  /* Seek to and read in the SOM dictionary.  We will need this to fill
+     in the carsym's filepos field.  */
+  if (bfd_seek (abfd, lst_filepos + lst_header->dir_loc, SEEK_SET) < 0)
+    {
+      bfd_error = system_call_error;
+      return false;
+    }
+
+  if (bfd_read ((PTR) som_dict, lst_header->module_count, 
+               sizeof (struct som_entry), abfd)
+      != lst_header->module_count * sizeof (struct som_entry))
+    {
+      bfd_error = system_call_error;
+      return false;
+    }
+
+  /* Walk each chain filling in the carsyms as we go along.  */
+  for (i = 0; i < lst_header->hash_size; i++)
+    {
+      struct lst_symbol_record lst_symbol;
+
+      /* An empty chain has zero as it's file offset.  */
+      if (hash_table[i] == 0)
+       continue;
+
+      /* Seek to and read the first symbol on the chain.  */
+      if (bfd_seek (abfd, lst_filepos + hash_table[i], SEEK_SET) < 0)
+       {
+         bfd_error = system_call_error;
+         return false;
+       }
+
+      if (bfd_read ((PTR) & lst_symbol, 1, sizeof (lst_symbol), abfd)
+         != sizeof (lst_symbol))
+       {
+         bfd_error = system_call_error;
+         return false;
+       }
+
+      /* Get the name of the symbol, first get the length which is stored
+        as a 32bit integer just before the symbol.
+
+        One might ask why we don't just read in the entire string table
+        and index into it.  Well, according to the SOM ABI the string
+        index can point *anywhere* in the archive to save space, so just
+        using the string table would not be safe.  */
+      if (bfd_seek (abfd, lst_filepos + lst_header->string_loc
+                           + lst_symbol.name.n_strx - 4, SEEK_SET) < 0)
+       {
+         bfd_error = system_call_error;
+         return false;
+       }
+
+      if (bfd_read (&len, 1, 4, abfd) != 4)
+       {
+         bfd_error = system_call_error;
+         return false;
+       }
+
+      /* Allocate space for the name and null terminate it too.  */
+      set->name = bfd_zalloc (abfd, len + 1);
+      if (!set->name)
+       {
+         bfd_error = no_memory;
+         return false;
+       }
+      if (bfd_read (set->name, 1, len, abfd) != len)
+       {
+         bfd_error = system_call_error;
+         return false;
+       }
+      set->name[len] = 0;
+
+      /* Fill in the file offset.  Note that the "location" field points
+        to the SOM itself, not the ar_hdr in front of it.  */
+      set->file_offset = som_dict[lst_symbol.som_index].location
+                         - sizeof (struct ar_hdr);
+
+      /* Go to the next symbol.  */
+      set++;
+
+      /* Iterate through the rest of the chain.  */
+      while (lst_symbol.next_entry)
+       {
+         /* Seek to the next symbol and read it in.  */
+         if (bfd_seek (abfd, lst_filepos + lst_symbol.next_entry, SEEK_SET)
+             < 0)
+           {
+             bfd_error = system_call_error;
+             return false;
+           }
+
+         if (bfd_read ((PTR) & lst_symbol, 1, sizeof (lst_symbol), abfd)
+             != sizeof (lst_symbol))
+           {
+             bfd_error = system_call_error;
+             return false;
+           }
+
+         /* Seek to the name length & string and read them in.  */
+         if (bfd_seek (abfd, lst_filepos + lst_header->string_loc 
+                               + lst_symbol.name.n_strx - 4, SEEK_SET) < 0)
+           {
+             bfd_error = system_call_error;
+             return false;
+           }
+
+         if (bfd_read (&len, 1, 4, abfd) != 4)
+           {
+             bfd_error = system_call_error;
+             return false;
+           }
+
+         /* Allocate space for the name and null terminate it too.  */
+         set->name = bfd_zalloc (abfd, len + 1);
+         if (!set->name)
+           {
+             bfd_error = no_memory;
+             return false;
+           }
+         if (bfd_read (set->name, 1, len, abfd) != len)
+           {
+             bfd_error = system_call_error;
+             return false;
+           }
+         set->name[len] = 0;
+
+         /* Fill in the file offset.  Note that the "location" field points
+            to the SOM itself, not the ar_hdr in front of it.  */
+         set->file_offset = som_dict[lst_symbol.som_index].location
+                              - sizeof (struct ar_hdr);
+
+         /* Go on to the next symbol.  */
+         set++;
+       }
+    }
+  /* If we haven't died by now, then we successfully read the entire 
+     archive symbol table.  */
+  return true;
+}
+
+/* Read in the LST from the archive.  */
+static boolean
+som_slurp_armap (abfd)
+     bfd *abfd;
+{
+  struct lst_header lst_header;
+  struct ar_hdr ar_header;
+  unsigned int parsed_size;
+  struct artdata *ardata = bfd_ardata (abfd);
+  char nextname[17];
+  int i = bfd_read ((PTR) nextname, 1, 16, abfd);
+
+  /* Special cases.  */
+  if (i == 0)
+    return true;
+  if (i != 16)
+    return false;
+
+  if (bfd_seek (abfd, (file_ptr) - 16, SEEK_CUR) < 0)
+    {
+      bfd_error = system_call_error;
+      return false;
+    }
+
+  /* For archives without .o files there is no symbol table.  */
+  if (strncmp (nextname, "/               ", 16))
+    {
+      bfd_has_map (abfd) = false;
+      return true;
+    }
+
+  /* Read in and sanity check the archive header.  */
+  if (bfd_read ((PTR) &ar_header, 1, sizeof (struct ar_hdr), abfd)
+      != sizeof (struct ar_hdr))
+    {
+      bfd_error = system_call_error;
+      return false;
+    }
+
+  if (strncmp (ar_header.ar_fmag, ARFMAG, 2))
+    {
+      bfd_error = malformed_archive;
+      return NULL;
+    }
+
+  /* How big is the archive symbol table entry?  */
+  errno = 0;
+  parsed_size = strtol (ar_header.ar_size, NULL, 10);
+  if (errno != 0)
+    {
+      bfd_error = malformed_archive;
+      return NULL;
+    }
+
+  /* Save off the file offset of the first real user data.  */
+  ardata->first_file_filepos = bfd_tell (abfd) + parsed_size;
+
+  /* Read in the library symbol table.  We'll make heavy use of this
+     in just a minute.  */
+  if (bfd_read ((PTR) & lst_header, 1, sizeof (struct lst_header), abfd)
+      != sizeof (struct lst_header))
+    {
+      bfd_error = system_call_error;
+      return false;
+    }
+
+  /* Sanity check.  */
+  if (lst_header.a_magic != LIBMAGIC)
+    {
+      bfd_error = malformed_archive;
+      return NULL;
+    }
+
+  /* Count the number of symbols in the library symbol table.  */
+  if (som_bfd_count_ar_symbols (abfd, &lst_header, &ardata->symdef_count)
+      == false)
+    return false;
+
+  /* Get back to the start of the library symbol table.  */
+  if (bfd_seek (abfd, ardata->first_file_filepos - parsed_size 
+                       + sizeof (struct lst_header), SEEK_SET) < 0)
+    {
+      bfd_error = system_call_error;
+      return false;
+    }
+
+  /* Initializae the cache and allocate space for the library symbols.  */
+  ardata->cache = 0;
+  ardata->symdefs = (carsym *) bfd_alloc (abfd,
+                                         (ardata->symdef_count
+                                          * sizeof (carsym)));
+  if (!ardata->symdefs)
+    {
+      bfd_error = no_memory;
+      return false;
+    }
+
+  /* Now fill in the canonical archive symbols.  */
+  if (som_bfd_fill_in_ar_symbols (abfd, &lst_header, &ardata->symdefs)
+      == false)
+    return false;
+
+  /* Notify the generic archive code that we have a symbol map.  */
+  bfd_has_map (abfd) = true;
+  return true;
+}
+
+/* Write out the LST for the archive.  Not supported yet.  */
+static boolean
+som_write_armap (abfd)
+     bfd *abfd;
+{
+  return false;
+}
+
+/* Apparently the extened names are never used, even though they appear
+   in the SOM ABI.  Hmmm.  */
+static boolean
+som_slurp_extended_name_table (abfd)
+     bfd *abfd;
+{
+  bfd_ardata (abfd)->extended_names = NULL;
+  return true;
+}
+
 /* End of miscellaneous support functions. */
 
 #define som_bfd_debug_info_start        bfd_void
 #define som_bfd_debug_info_end          bfd_void
 #define som_bfd_debug_info_accumulate   (PROTO(void,(*),(bfd*, struct sec *))) bfd_void
 
-#define som_openr_next_archived_file    bfd_generic_openr_next_archived_file
-#define som_generic_stat_arch_elt       bfd_generic_stat_arch_elt
-#define som_slurp_armap                  bfd_false
-#define som_slurp_extended_name_table    _bfd_slurp_extended_name_table
-#define som_truncate_arname              (void (*)())bfd_nullvoidptr
-#define som_write_armap                  0
+#define som_openr_next_archived_file   bfd_generic_openr_next_archived_file
+#define som_generic_stat_arch_elt      bfd_generic_stat_arch_elt
+#define som_truncate_arname            bfd_bsd_truncate_arname
 
 #define som_get_lineno                   (struct lineno_cache_entry *(*)())bfd_nullvoidptr
 #define        som_close_and_cleanup              bfd_generic_close_and_cleanup