* srec.c, tekhex.c: Include libiberty.h. Delete static array hex_value and
authorKen Raeburn <raeburn@cygnus>
Thu, 12 Jan 1995 21:37:32 +0000 (21:37 +0000)
committerKen Raeburn <raeburn@cygnus>
Thu, 12 Jan 1995 21:37:32 +0000 (21:37 +0000)
replace references to it with references to hex_init, hex_p, and hex_value.
* tekhex.c (digs): Now const.

bfd/srec.c

index f3612df10dbb5fc120b782e2d208ce92e1ccba88..3ec152faeabf2635dd66912ac7e8e87134b88285 100644 (file)
@@ -106,10 +106,20 @@ DESCRIPTION
 #include "bfd.h"
 #include "sysdep.h"
 #include "libbfd.h"
+#include "libiberty.h"
+
+static void srec_init PARAMS ((void));
+static boolean srec_mkobject PARAMS ((bfd *));
+static int srec_get_byte PARAMS ((bfd *, boolean *));
+static void srec_bad_byte PARAMS ((bfd *, unsigned int, int, boolean));
+static boolean srec_scan PARAMS ((bfd *));
+static const bfd_target *srec_object_p PARAMS ((bfd *));
+static const bfd_target *symbolsrec_object_p PARAMS ((bfd *));
+static boolean srec_read_section PARAMS ((bfd *, asection *, bfd_byte *));
 
 static boolean srec_write_record PARAMS ((bfd *, int, bfd_vma,
-                                         const unsigned char *,
-                                         const unsigned char *));
+                                         const bfd_byte *,
+                                         const bfd_byte *));
 static boolean srec_write_header PARAMS ((bfd *));
 static boolean srec_write_symbols PARAMS ((bfd *));
 
@@ -117,18 +127,13 @@ static boolean srec_write_symbols PARAMS ((bfd *));
 
 static CONST char digs[] = "0123456789ABCDEF";
 
-/* Table that gets filled in with numbers corresponding to hex chars. */
-
-static char hex_value[256];
-
-#define NOT_HEX 20
-#define NIBBLE(x) hex_value[(unsigned char)(x)]
+#define NIBBLE(x) hex_value(x)
 #define HEX(buffer) ((NIBBLE((buffer)[0])<<4) + NIBBLE((buffer)[1]))
 #define TOHEX(d, x, ch) \
        d[1] = digs[(x) & 0xf]; \
        d[0] = digs[((x)>>4)&0xf]; \
        ch += ((x) & 0xff);
-#define        ISHEX(x)  (hex_value[(unsigned char)(x)] != NOT_HEX)
+#define        ISHEX(x)  hex_p(x)
 
 /* Initialize by filling in the hex conversion array. */
 
@@ -141,57 +146,49 @@ srec_init ()
   if (inited == false)
     {
       inited = true;
-
-      for (i = 0; i < sizeof (hex_value); i++)
-       {
-         hex_value[i] = NOT_HEX;
-       }
-      for (i = 0; i < 10; i++)
-       {
-         hex_value[i + '0'] = i;
-       }
-      for (i = 0; i < 6; i++)
-       {
-         hex_value[i + 'a'] = i + 10;
-         hex_value[i + 'A'] = i + 10;
-       }
+      hex_init ();
     }
 }
 
-
 /* The maximum number of bytes on a line is FF */
 #define MAXCHUNK 0xff
 /* The number of bytes we fit onto a line on output */
 #define CHUNK 21
 
-/* We cannot output our srecords as we see them, we have to glue them
-   together, this is done in this structure : */
+/* When writing an S-record file, the S-records can not be output as
+   they are seen.  This structure is used to hold them in memory.  */
 
 struct srec_data_list_struct
 {
-  unsigned char *data;
+  struct srec_data_list_struct *next;
+  bfd_byte *data;
   bfd_vma where;
   bfd_size_type size;
-  struct srec_data_list_struct *next;
+};
 
+typedef struct srec_data_list_struct srec_data_list_type;
 
+/* When scanning the S-record file, a linked list of srec_symbol
+   structures is built to represent the symbol table (if there is
+   one).  */
+
+struct srec_symbol
+{
+  struct srec_symbol *next;
+  const char *name;
+  bfd_vma val;
 };
-typedef struct srec_data_list_struct srec_data_list_type;
 
+/* The S-record tdata information.  */
 
 typedef struct srec_data_struct
   {
     srec_data_list_type *head;
     srec_data_list_type *tail;
     unsigned int type;
-
-    int done_symbol_read;
-    int count;
-    asymbol *symbols;
-    char *strings;
-    int symbol_idx;
-    int string_size;
-    int string_idx;
+    struct srec_symbol *symbols;
+    struct srec_symbol *symtail;
+    asymbol *csymbols;
   }
 tdata_type;
 
@@ -199,323 +196,393 @@ static boolean srec_write_section PARAMS ((bfd *, tdata_type *,
                                           srec_data_list_type *));
 static boolean srec_write_terminator PARAMS ((bfd *, tdata_type *));
 
-/*
-   called once per input S-Record, used to work out vma and size of data.
- */
-
-static bfd_vma low, high;
+/* Set up the S-record tdata information.  */
 
-/*ARGSUSED*/
-static void
-size_symbols (abfd, buf, len, val)
+static boolean
+srec_mkobject (abfd)
      bfd *abfd;
-     char *buf;
-     int len;
-     int val;
 {
-  abfd->symcount++;
-  abfd->tdata.srec_data->string_size += len + 1;
-}
+  srec_init ();
 
-static void
-fillup_symbols (abfd, buf, len, val)
-     bfd *abfd;
-     char *buf;
-     int len;
-     int val;
-{
-  if (!abfd->tdata.srec_data->done_symbol_read)
+  if (abfd->tdata.srec_data == NULL)
     {
-      asymbol *p;
-      if (abfd->tdata.srec_data->symbols == 0)
+      tdata_type *tdata = (tdata_type *) bfd_alloc (abfd, sizeof (tdata_type));
+      if (tdata == NULL)
        {
-         abfd->tdata.srec_data->symbols = (asymbol *) bfd_alloc (abfd, abfd->symcount * sizeof (asymbol));
-         abfd->tdata.srec_data->strings = (char *) bfd_alloc (abfd, abfd->tdata.srec_data->string_size);
-         if (!abfd->tdata.srec_data->symbols || !abfd->tdata.srec_data->strings)
-           {
-             bfd_set_error (bfd_error_no_memory);
-             abort ();         /* FIXME */
-           }
-         abfd->tdata.srec_data->symbol_idx = 0;
-         abfd->tdata.srec_data->string_idx = 0;
+         bfd_set_error (bfd_error_no_memory);
+         return false;
        }
-
-      p = abfd->tdata.srec_data->symbols + abfd->tdata.srec_data->symbol_idx++;
-      p->the_bfd = abfd;
-      p->name = abfd->tdata.srec_data->strings + abfd->tdata.srec_data->string_idx;
-      memcpy ((char *) (p->name), buf, len + 1);
-      abfd->tdata.srec_data->string_idx += len + 1;
-      p->value = val;
-      p->flags = BSF_EXPORT | BSF_GLOBAL;
-      p->section = bfd_abs_section_ptr;
-      p->udata.p = NULL;
+      abfd->tdata.srec_data = tdata;
+      tdata->type = 1;
+      tdata->head = NULL;
+      tdata->tail = NULL;
+      tdata->symbols = NULL;
+      tdata->symtail = NULL;
+      tdata->csymbols = NULL;
     }
-}
-/*ARGSUSED*/
-static void
-size_srec (abfd, section, address, raw, length)
-     bfd *abfd;
-     asection *section;
-     bfd_vma address;
-     bfd_byte *raw;
-     unsigned int length;
-{
-  if (address < low)
-    low = address;
-  if (address + length > high)
-    high = address + length - 1;
-}
 
+  return true;
+}
 
-/*
- called once per input S-Record, copies data from input into bfd_alloc'd area
- */
+/* Read a byte from an S record file.  Set *ERRORPTR if an error
+   occurred.  Return EOF on error or end of file.  */
 
-/*ARGSUSED*/
-static void
-fillup (abfd, section, address, raw, length)
+static int
+srec_get_byte (abfd, errorptr)
      bfd *abfd;
-     asection *section;
-     bfd_vma address;
-     bfd_byte *raw;
-     unsigned int length;
+     boolean *errorptr;
 {
-  unsigned int i;
-  bfd_byte *dst =
-  (bfd_byte *) (section->used_by_bfd) + address - section->vma;
-  /* length -1 because we don't read in the checksum */
-  for (i = 0; i < length - 1; i++)
+  bfd_byte c;
+
+  if (bfd_read (&c, 1, 1, abfd) != 1)
     {
-      *dst = HEX (raw);
-      dst++;
-      raw += 2;
+      if (bfd_get_error () != bfd_error_file_truncated)
+       *errorptr = true;
+      return EOF;
     }
+
+  return (int) (c & 0xff);
 }
 
-/* Pass over an S-Record file, calling one of the above functions on each
-   record.  */
+/* Report a problem in an S record file.  FIXME: This probably should
+   not call fprintf, but we really do need some mechanism for printing
+   error messages.  */
 
-static int
-white (x)
-     char x;
-{
-  return (x == ' ' || x == '\t' || x == '\n' || x == '\r');
-}
-static int
-skipwhite (src, abfd)
-     char *src;
+static void
+srec_bad_byte (abfd, lineno, c, error)
      bfd *abfd;
+     unsigned int lineno;
+     int c;
+     boolean error;
 {
-  int eof = 0;
-  while (white (*src) && !eof)
+  if (c == EOF)
     {
-      eof = (boolean) (bfd_read (src, 1, 1, abfd) != 1);
+      if (! error)
+       bfd_set_error (bfd_error_file_truncated);
+    }
+  else
+    {
+      char buf[10];
+
+      if (! isprint (c))
+       sprintf (buf, "\\%03o", (unsigned int) c);
+      else
+       {
+         buf[0] = c;
+         buf[1] = '\0';
+       }
+      fprintf (stderr, "%s:%d: Unexpected character `%s' in S-record file\n",
+              bfd_get_filename (abfd), lineno, buf);
+      bfd_set_error (bfd_error_bad_value);
     }
-  return eof;
 }
 
+/* Add a new symbol found in an S-record file.  */
+
 static boolean
-srec_mkobject (abfd)
+srec_new_symbol (abfd, name, val)
      bfd *abfd;
+     const char *name;
+     bfd_vma val;
 {
-  if (abfd->tdata.srec_data == 0)
+  struct srec_symbol *n;
+
+  n = (struct srec_symbol *) bfd_alloc (abfd, sizeof (struct srec_symbol));
+  if (n == NULL)
     {
-      tdata_type *tdata = (tdata_type *) bfd_alloc (abfd, sizeof (tdata_type));
-      if (!tdata)
-       {
-         bfd_set_error (bfd_error_no_memory);
-         return false;
-       }
-      abfd->tdata.srec_data = tdata;
-      tdata->type = 1;
-      tdata->head = NULL;
-      tdata->tail = NULL;
+      bfd_set_error (bfd_error_no_memory);
+      return false;
     }
-  return true;
 
+  n->name = name;
+  n->val = val;
+
+  if (abfd->tdata.srec_data->symbols == NULL)
+    abfd->tdata.srec_data->symbols = n;
+  else
+    abfd->tdata.srec_data->symtail->next = n;
+  abfd->tdata.srec_data->symtail = n;
+  n->next = NULL;
+
+  ++abfd->symcount;
+
+  return true;
 }
 
-static void
-pass_over (abfd, func, symbolfunc, section)
+/* Read the S record file and turn it into sections.  We create a new
+   section for each contiguous set of bytes.  */
+
+static boolean
+srec_scan (abfd)
      bfd *abfd;
-     void (*func) ();
-     void (*symbolfunc) ();
-     asection *section;
 {
-  unsigned int bytes_on_line;
-  boolean eof = false;
+  int c;
+  unsigned int lineno = 1;
+  boolean error = false;
+  bfd_byte *buf = NULL;
+  size_t bufsize = 0;
+  asection *sec = NULL;
 
-  srec_mkobject (abfd);
-  /* To the front of the file */
   if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0)
-    abort ();
-  while (eof == false)
+    goto error_return;
+
+  while ((c = srec_get_byte (abfd, &error)) != EOF)
     {
-      char buffer[MAXCHUNK];
-      char *src = buffer;
-      char type;
-      bfd_vma address = 0;
-
-      /* Find first 'S' or $ */
-      eof = (boolean) (bfd_read (src, 1, 1, abfd) != 1);
-      switch (*src)
+      /* We only build sections from contiguous S-records, so if this
+         is not an S-record, then stop building a section.  */
+      if (c != 'S' && c != '\r' && c != '\n')
+       sec = NULL;
+
+      switch (c)
        {
        default:
-         if (eof)
-           return;
+         srec_bad_byte (abfd, lineno, c, error);
+         goto error_return;
+
+       case '\n':
+         ++lineno;
+         break;
+
+       case '\r':
          break;
 
        case '$':
-         /* Inside a symbol definition - just ignore the module name */
-         while (*src != '\n' && !eof)
+         /* Starting a module name, which we ignore.  */
+         while ((c = srec_get_byte (abfd, &error)) != '\n'
+                && c != EOF)
+           ;
+         if (c == EOF)
            {
-             eof = (boolean) (bfd_read (src, 1, 1, abfd) != 1);
+             srec_bad_byte (abfd, lineno, c, error);
+             goto error_return;
            }
+
+         ++lineno;
+
          break;
 
        case ' ':
-         /* spaces - maybe just before a symbol */
-         while (*src != '\n' && *src != '\r' && white (*src))
-           {
-             eof = skipwhite (src, abfd);
+         {
+           char *symname;
+           bfd_vma symval;
+
+           /* Starting a symbol definition.  */
+           while ((c = srec_get_byte (abfd, &error)) != EOF
+                  && (c == ' ' || c == '\t'))
+             ;
+           if (c == EOF)
+             {
+               srec_bad_byte (abfd, lineno, c, error);
+               goto error_return;
+             }
 
+           obstack_1grow (&abfd->memory, c);
+           while ((c = srec_get_byte (abfd, &error)) != EOF
+                  && ! isspace (c))
+             obstack_1grow (&abfd->memory, c);
+           if (c == EOF)
              {
-               int val = 0;
-               int slen = 0;
-               char symbol[MAXCHUNK];
+               srec_bad_byte (abfd, lineno, c, error);
+               goto error_return;
+             }
 
-               /* get the symbol part */
-               while (!eof && !white (*src) && slen < MAXCHUNK)
-                 {
-                   symbol[slen++] = *src;
-                   eof = (boolean) (bfd_read (src, 1, 1, abfd) != 1);
-                 }
-               symbol[slen] = 0;
-               eof = skipwhite (src, abfd);
-               /* skip the $ for the hex value */
-               if (*src == '$')
-                 {
-                   eof = (boolean) (bfd_read (src, 1, 1, abfd) != 1);
-                 }
+           symname = obstack_finish (&abfd->memory);
+           if (symname == NULL)
+             {
+               bfd_set_error (bfd_error_no_memory);
+               goto error_return;
+             }
+      
+           while ((c = srec_get_byte (abfd, &error)) != EOF
+                  && (c == ' ' || c == '\t'))
+             ;
+           if (c == EOF)
+             {
+               srec_bad_byte (abfd, lineno, c, error);
+               goto error_return;
+             }
 
-               /* Scan off the hex number */
-               while (isxdigit (*src))
+           /* Skip a dollar sign before the hex value.  */
+           if (c == '$')
+             {
+               c = srec_get_byte (abfd, &error);
+               if (c == EOF)
                  {
-                   val *= 16;
-                   if (isdigit (*src))
-                     val += *src - '0';
-                   else if (isupper (*src))
-                     {
-                       val += *src - 'A' + 10;
-                     }
-                   else
-                     {
-                       val += *src - 'a' + 10;
-                     }
-                   eof = (boolean) (bfd_read (src, 1, 1, abfd) != 1);
+                   srec_bad_byte (abfd, lineno, c, error);
+                   goto error_return;
                  }
-               symbolfunc (abfd, symbol, slen, val);
              }
-           }
+
+           symval = 0;
+           while (ISHEX (c))
+             {
+               symval <<= 4;
+               symval += NIBBLE (c);
+               c = srec_get_byte (abfd, &error);
+             }
+
+           if (c == EOF || ! isspace (c))
+             {
+               srec_bad_byte (abfd, lineno, c, error);
+               goto error_return;
+             }
+
+           if (! srec_new_symbol (abfd, symname, symval))
+             goto error_return;
+
+           if (c == '\n')
+             ++lineno;
+
+         }
          break;
+    
        case 'S':
-         src++;
+         {
+           file_ptr pos;
+           char hdr[3];
+           unsigned int bytes;
+           bfd_vma address;
+           bfd_byte *data;
 
-         /* Fetch the type and the length */
-         if (bfd_read (src, 1, 3, abfd) != 3)
-           abort (); /* FIXME */
+           /* Starting an S-record.  */
 
-         type = *src++;
+           pos = bfd_tell (abfd) - 1;
 
-         if (!ISHEX (src[0]) || !ISHEX (src[1]))
-           break;
+           if (bfd_read (hdr, 1, 3, abfd) != 3)
+             goto error_return;
 
-         bytes_on_line = HEX (src);
+           if (! ISHEX (hdr[1]) || ! ISHEX (hdr[2]))
+             {
+               if (! ISHEX (hdr[1]))
+                 c = hdr[1];
+               else
+                 c = hdr[2];
+               srec_bad_byte (abfd, lineno, c, error);
+               goto error_return;
+             }
 
-         if (bytes_on_line > MAXCHUNK / 2)
-           break;
-         src += 2;
+           bytes = HEX (hdr + 1);
+           if (bytes * 2 > bufsize)
+             {
+               if (buf != NULL)
+                 free (buf);
+               buf = (bfd_byte *) malloc (bytes * 2);
+               if (buf == NULL)
+                 {
+                   bfd_set_error (bfd_error_no_memory);
+                   goto error_return;
+                 }
+               bufsize = bytes * 2;
+             }
 
-         if (bfd_read (src, 1, bytes_on_line * 2, abfd) != bytes_on_line * 2)
-           abort (); /* FIXME */
+           if (bfd_read (buf, 1, bytes * 2, abfd) != bytes * 2)
+             goto error_return;
 
-         switch (type)
-           {
-           case '0':
-           case '5':
-             /* Prologue - ignore */
-             break;
-           case '3':
-             address = HEX (src);
-             src += 2;
-             bytes_on_line--;
-
-           case '2':
-             address = HEX (src) | (address << 8);
-             src += 2;
-             bytes_on_line--;
-           case '1':
-             address = HEX (src) | (address << 8);
-             src += 2;
-             address = HEX (src) | (address << 8);
-             src += 2;
-             bytes_on_line -= 2;
-             func (abfd, section, address, src, bytes_on_line);
-             break;
-
-           case '7':
-             address = HEX (src);
-             src += 2;
-             bytes_on_line--;
-           case '8':
-             address = HEX (src) | (address << 8);
-             src += 2;
-             bytes_on_line--;
-           case '9':
-             address = HEX (src) | (address << 8);
-             src += 2;
-             address = HEX (src) | (address << 8);
-             src += 2;
-             bytes_on_line -= 2;
-             abfd->start_address = address;
-             return;
-
-           default:
-             return;
-           }
+           /* Ignore the checksum byte.  */
+           --bytes;
+
+           address = 0;
+           data = buf;
+           switch (hdr[0])
+             {
+             case '0':
+             case '5':
+               /* Prologue--ignore the file name, but stop building a
+                   section at this point.  */
+               sec = NULL;
+               break;
+
+             case '3':
+               address = HEX (data);
+               data += 2;
+               --bytes;
+               /* Fall through.  */
+             case '2':
+               address = (address << 8) | HEX (data);
+               data += 2;
+               --bytes;
+               /* Fall through.  */
+             case '1':
+               address = (address << 8) | HEX (data);
+               data += 2;
+               address = (address << 8) | HEX (data);
+               data += 2;
+               bytes -= 2;
+
+               if (sec != NULL
+                   && sec->vma + sec->_raw_size == address)
+                 {
+                   /* This data goes at the end of the section we are
+                       currently building.  */
+                   sec->_raw_size += bytes;
+                 }
+               else
+                 {
+                   char secbuf[20];
+                   char *secname;
+
+                   sprintf (secbuf, ".sec%d", bfd_count_sections (abfd) + 1);
+                   secname = (char *) bfd_alloc (abfd, strlen (secbuf) + 1);
+                   strcpy (secname, secbuf);
+                   sec = bfd_make_section (abfd, secname);
+                   if (sec == NULL)
+                     goto error_return;
+                   sec->flags = SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC;
+                   sec->vma = address;
+                   sec->_raw_size = bytes;
+                   sec->filepos = pos;
+                 }
+
+               break;
+
+             case '7':
+               address = HEX (data);
+               data += 2;
+               /* Fall through.  */
+             case '8':
+               address = (address << 8) | HEX (data);
+               data += 2;
+               /* Fall through.  */
+             case '9':
+               address = (address << 8) | HEX (data);
+               data += 2;
+               address = (address << 8) | HEX (data);
+               data += 2;
+
+               /* This is a termination record.  */
+               abfd->start_address = address;
+
+               if (buf != NULL)
+                 free (buf);
+
+               return true;
+             }
+         }
+         break;
        }
     }
 
-}
+  if (error)
+    goto error_return;
 
-static const bfd_target *
-object_p (abfd)
-     bfd *abfd;
-{
-  asection *section;
-  /* We create one section called .text for all the contents,
-     and allocate enough room for the entire file.  */
-
-  section = bfd_make_section (abfd, ".text");
-  section->_raw_size = 0;
-  section->vma = 0xffffffff;
-  low = 0xffffffff;
-  high = 0;
-  pass_over (abfd, size_srec, size_symbols, section);
-  section->_raw_size = high - low;
-  section->vma = low;
-  section->flags = SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC;
-
-  if (abfd->symcount)
-    abfd->flags |= HAS_SYMS;
-  return abfd->xvec;
+  if (buf != NULL)
+    free (buf);
+
+  return true;
+
+ error_return:
+  if (buf != NULL)
+    free (buf);
+  return false;
 }
 
+/* Check whether an existing file is an S-record file.  */
+
 static const bfd_target *
 srec_object_p (abfd)
      bfd *abfd;
 {
-  char b[4];
+  bfd_byte b[4];
 
   srec_init ();
 
@@ -524,33 +591,166 @@ srec_object_p (abfd)
     return NULL;
 
   if (b[0] != 'S' || !ISHEX (b[1]) || !ISHEX (b[2]) || !ISHEX (b[3]))
-    return (const bfd_target *) NULL;
+    {
+      bfd_set_error (bfd_error_wrong_format);
+      return NULL;
+    }
 
-  /* We create one section called .text for all the contents,
-     and allocate enough room for the entire file.  */
+  if (! srec_mkobject (abfd)
+      || ! srec_scan (abfd))
+    return NULL;
 
-  return object_p (abfd);
+  return abfd->xvec;
 }
 
+/* Check whether an existing file is an S-record file with symbols.  */
 
 static const bfd_target *
 symbolsrec_object_p (abfd)
      bfd *abfd;
 {
-  char b[4];
+  char b[2];
 
   srec_init ();
 
   if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0
-      || bfd_read (b, 1, 4, abfd) != 4)
+      || bfd_read (b, 1, 2, abfd) != 2)
     return NULL;
 
   if (b[0] != '$' || b[1] != '$')
-    return (const bfd_target *) NULL;
+    {
+      bfd_set_error (bfd_error_wrong_format);
+      return NULL;
+    }
 
-  return object_p (abfd);
+  if (! srec_mkobject (abfd)
+      || ! srec_scan (abfd))
+    return NULL;
+
+  return abfd->xvec;
 }
 
+/* Read in the contents of a section in an S-record file.  */
+
+static boolean
+srec_read_section (abfd, section, contents)
+     bfd *abfd;
+     asection *section;
+     bfd_byte *contents;
+{
+  int c;
+  bfd_size_type sofar = 0;
+  boolean error = false;
+  bfd_byte *buf = NULL;
+  size_t bufsize = 0;
+
+  if (bfd_seek (abfd, section->filepos, SEEK_SET) != 0)
+    goto error_return;
+
+  while ((c = srec_get_byte (abfd, &error)) != EOF)
+    {
+      bfd_byte hdr[3];
+      unsigned int bytes;
+      bfd_vma address;
+      bfd_byte *data;
+
+      if (c == '\r' || c == '\n')
+       continue;
+
+      /* This is called after srec_scan has already been called, so we
+         ought to know the exact format.  */
+      BFD_ASSERT (c == 'S');
+
+      if (bfd_read (hdr, 1, 3, abfd) != 3)
+       goto error_return;
+
+      BFD_ASSERT (ISHEX (hdr[1]) && ISHEX (hdr[2]));
+
+      bytes = HEX (hdr + 1);
+
+      if (bytes * 2 > bufsize)
+       {
+         if (buf != NULL)
+           free (buf);
+         buf = (bfd_byte *) malloc (bytes * 2);
+         if (buf == NULL)
+           {
+             bfd_set_error (bfd_error_no_memory);
+             goto error_return;
+           }
+         bufsize = bytes * 2;
+       }
+
+      if (bfd_read (buf, 1, bytes * 2, abfd) != bytes * 2)
+       goto error_return;
+
+      address = 0;
+      data = buf;
+      switch (hdr[0])
+       {
+       default:
+         BFD_ASSERT (sofar == section->_raw_size);
+         if (buf != NULL)
+           free (buf);
+         return true;
+
+       case '3':
+         address = HEX (data);
+         data += 2;
+         --bytes;
+         /* Fall through.  */
+       case '2':
+         address = (address << 8) | HEX (data);
+         data += 2;
+         --bytes;
+         /* Fall through.  */
+       case '1':
+         address = (address << 8) | HEX (data);
+         data += 2;
+         address = (address << 8) | HEX (data);
+         data += 2;
+         bytes -= 2;
+
+         if (address != section->vma + sofar)
+           {
+             /* We've come to the end of this section.  */
+             BFD_ASSERT (sofar == section->_raw_size);
+             if (buf != NULL)
+               free (buf);
+             return true;
+           }
+
+         /* Don't consider checksum.  */
+         --bytes;
+
+         while (bytes-- != 0)
+           {
+             contents[sofar] = HEX (data);
+             data += 2;
+             ++sofar;
+           }
+
+         break;
+       }
+    }
+
+  if (error)
+    goto error_return;
+
+  BFD_ASSERT (sofar == section->_raw_size);
+
+  if (buf != NULL)
+    free (buf);
+
+  return true;
+
+ error_return:
+  if (buf != NULL)
+    free (buf);
+  return false;
+}
+
+/* Get the contents of a section in an S-record file.  */
 
 static boolean
 srec_get_section_contents (abfd, section, location, offset, count)
@@ -560,35 +760,25 @@ srec_get_section_contents (abfd, section, location, offset, count)
      file_ptr offset;
      bfd_size_type count;
 {
-  if (section->used_by_bfd == (PTR) NULL)
+  if (section->used_by_bfd == NULL)
     {
-      section->used_by_bfd = (PTR) bfd_alloc (abfd, section->_raw_size);
-      if (!section->used_by_bfd)
+      section->used_by_bfd = bfd_alloc (abfd, section->_raw_size);
+      if (section->used_by_bfd == NULL
+         && section->_raw_size != 0)
        {
          bfd_set_error (bfd_error_no_memory);
          return false;
        }
 
-      pass_over (abfd, fillup, fillup_symbols, section);
+      if (! srec_read_section (abfd, section, section->used_by_bfd))
+       return false;
     }
-  memcpy ((PTR) location,
-         (PTR) ((char *) (section->used_by_bfd) + offset),
-         count);
-  return true;
-}
 
+  memcpy (location, (bfd_byte *) section->used_by_bfd + offset, count);
 
-
-boolean
-srec_set_arch_mach (abfd, arch, machine)
-     bfd *abfd;
-     enum bfd_architecture arch;
-     unsigned long machine;
-{
-  return bfd_default_set_arch_mach (abfd, arch, machine);
+  return true;
 }
 
-
 /* we have to save up all the Srecords for a splurge before output,
    also remember   */
 
@@ -614,7 +804,7 @@ srec_set_section_contents (abfd, section, location, offset, bytes_to_do)
   if ((section->flags & SEC_ALLOC)
       && (section->flags & SEC_LOAD))
     {
-      unsigned char *data = (unsigned char *) bfd_alloc (abfd, bytes_to_do);
+      bfd_byte *data = (bfd_byte *) bfd_alloc (abfd, bytes_to_do);
       if (data == NULL)
        {
          bfd_set_error (bfd_error_no_memory);
@@ -675,17 +865,15 @@ srec_write_record (abfd, type, address, data, end)
      bfd *abfd;
      int type;
      bfd_vma address;
-     const unsigned char *data;
-     const unsigned char *end;
+     const bfd_byte *data;
+     const bfd_byte *end;
 {
   char buffer[MAXCHUNK];
-
   unsigned int check_sum = 0;
-  CONST unsigned char *src = data;
+  CONST bfd_byte *src = data;
   char *dst = buffer;
   char *length;
 
-
   *dst++ = 'S';
   *dst++ = '0' + type;
 
@@ -738,8 +926,8 @@ static boolean
 srec_write_header (abfd)
      bfd *abfd;
 {
-  unsigned char buffer[MAXCHUNK];
-  unsigned char *dst = buffer;
+  bfd_byte buffer[MAXCHUNK];
+  bfd_byte *dst = buffer;
   unsigned int i;
 
   /* I'll put an arbitary 40 char limit on header size */
@@ -757,7 +945,7 @@ srec_write_section (abfd, tdata, list)
      srec_data_list_type *list;
 {
   unsigned int bytes_written = 0;
-  unsigned char *location = list->data;
+  bfd_byte *location = list->data;
 
   while (bytes_written < list->size)
     {
@@ -791,7 +979,7 @@ srec_write_terminator (abfd, tdata)
      bfd *abfd;
      tdata_type *tdata;
 {
-  unsigned char buffer[2];
+  bfd_byte buffer[2];
 
   return srec_write_record (abfd, 10 - tdata->type,
                            abfd->start_address, buffer, buffer);
@@ -930,29 +1118,58 @@ srec_make_empty_symbol (abfd)
   return new;
 }
 
+/* Return the amount of memory needed to read the symbol table.  */
+
 static long
 srec_get_symtab_upper_bound (abfd)
      bfd *abfd;
 {
-  /* Read in all the info */
-  if (! srec_get_section_contents (abfd, abfd->sections, 0, 0, 0))
-    return -1;
-  return (bfd_get_symcount (abfd) + 1) * (sizeof (asymbol *));
+  return (bfd_get_symcount (abfd) + 1) * sizeof (asymbol *);
 }
 
+/* Return the symbol table.  */
+
 static long
 srec_get_symtab (abfd, alocation)
      bfd *abfd;
      asymbol **alocation;
 {
-  int lim = abfd->symcount;
-  int i;
-  for (i = 0; i < lim; i++)
+  unsigned int symcount = bfd_get_symcount (abfd);
+  asymbol *csymbols;
+  unsigned int i;
+
+  csymbols = abfd->tdata.srec_data->csymbols;
+  if (csymbols == NULL)
     {
-      alocation[i] = abfd->tdata.srec_data->symbols + i;
+      asymbol *c;
+      struct srec_symbol *s;
+
+      csymbols = (asymbol *) bfd_alloc (abfd, symcount * sizeof (asymbol));
+      if (csymbols == NULL && symcount != 0)
+       {
+         bfd_set_error (bfd_error_no_memory);
+         return false;
+       }
+      abfd->tdata.srec_data->csymbols = csymbols;
+
+      for (s = abfd->tdata.srec_data->symbols, c = csymbols;
+          s != NULL;
+          s = s->next, ++c)
+       {
+         c->the_bfd = abfd;
+         c->name = s->name;
+         c->value = s->val;
+         c->flags = BSF_GLOBAL;
+         c->section = bfd_abs_section_ptr;
+         c->udata.p = NULL;
+       }
     }
-  alocation[i] = 0;
-  return lim;
+       
+  for (i = 0; i < symcount; i++)
+    *alocation++ = csymbols++;
+  *alocation = NULL;
+
+  return symcount;
 }
 
 /*ARGSUSED*/
@@ -997,6 +1214,14 @@ srec_print_symbol (ignore_abfd, afile, symbol, how)
 #define srec_find_nearest_line _bfd_nosymbols_find_nearest_line
 #define srec_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol
 
+#define srec_get_reloc_upper_bound \
+  ((long (*) PARAMS ((bfd *, asection *))) bfd_0l)
+#define srec_canonicalize_reloc \
+  ((long (*) PARAMS ((bfd *, asection *, arelent **, asymbol **))) bfd_0l)
+#define srec_bfd_reloc_type_lookup _bfd_norelocs_bfd_reloc_type_lookup
+
+#define srec_set_arch_mach bfd_default_set_arch_mach
+
 #define srec_bfd_get_relocated_section_contents \
   bfd_generic_get_relocated_section_contents
 #define srec_bfd_relax_section bfd_generic_relax_section
@@ -1050,7 +1275,7 @@ const bfd_target srec_vec =
   BFD_JUMP_TABLE_CORE (_bfd_nocore),
   BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
   BFD_JUMP_TABLE_SYMBOLS (srec),
-  BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
+  BFD_JUMP_TABLE_RELOCS (srec),
   BFD_JUMP_TABLE_WRITE (srec),
   BFD_JUMP_TABLE_LINK (srec),
   BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
@@ -1106,7 +1331,7 @@ const bfd_target symbolsrec_vec =
   BFD_JUMP_TABLE_CORE (_bfd_nocore),
   BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
   BFD_JUMP_TABLE_SYMBOLS (srec),
-  BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
+  BFD_JUMP_TABLE_RELOCS (srec),
   BFD_JUMP_TABLE_WRITE (srec),
   BFD_JUMP_TABLE_LINK (srec),
   BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),