This commit was manufactured by cvs2svn to create branch 'binutils-
[external/binutils.git] / bfd / srec.c
index 6c6f875..6226773 100644 (file)
@@ -1,29 +1,32 @@
 /* BFD back-end for s-record objects.
-   Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+   Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011
+   Free Software Foundation, Inc.
    Written by Steve Chamberlain of Cygnus Support <sac@cygnus.com>.
 
-This file is part of BFD, the Binary File Descriptor library.
+   This file is part of BFD, the Binary File Descriptor library.
 
-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 2 of the License, or
-(at your option) any later version.
+   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.
+   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, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
 
-/*
-SUBSECTION
+
+/* SUBSECTION
        S-Record handling
 
-DESCRIPTION
-       
+   DESCRIPTION
+
        Ordinary S-Records cannot hold anything but addresses and
        data, so that's all that we implement.
 
@@ -41,11 +44,11 @@ DESCRIPTION
        up and output them when it's time to close the bfd.
 
        An s record looks like:
-       
-EXAMPLE
+
+   EXAMPLE
        S<type><length><address><data><checksum>
-       
-DESCRIPTION
+
+   DESCRIPTION
        Where
        o length
        is the number of bytes following upto the checksum. Note that
@@ -60,7 +63,7 @@ DESCRIPTION
        7) four byte address termination record
        8) three byte address termination record
        9) two byte address termination record
-       
+
        o address
        is the start address of the data following, or in the case of
        a termination record, the start address of the image
@@ -70,11 +73,10 @@ DESCRIPTION
        is the sum of all the raw byte data in the record, from the length
        upwards, modulo 256 and subtracted from 255.
 
-
-SUBSECTION
+   SUBSECTION
        Symbol S-Record handling
 
-DESCRIPTION
+   DESCRIPTION
        Some ICE equipment understands an addition to the standard
        S-Record format; symbols and their addresses can be sent
        before the data.
@@ -86,7 +88,7 @@ DESCRIPTION
 
        so a short symbol table could look like:
 
-EXAMPLE
+   EXAMPLE
        $$ flash.x
        $$ flash.c
          _port6 $0
@@ -97,547 +99,860 @@ EXAMPLE
          _end $8036
        $$
 
-DESCRIPTION
+   DESCRIPTION
        We allow symbols to be anywhere in the data stream - the module names
-       are always ignored.
-               
-*/
+       are always ignored.  */
 
-#include "bfd.h"
 #include "sysdep.h"
+#include "bfd.h"
 #include "libbfd.h"
+#include "libiberty.h"
+#include "safe-ctype.h"
 
-/* Macros for converting between hex and binary */
 
-static CONST char digs[] = "0123456789ABCDEF";
+/* Macros for converting between hex and binary.  */
 
-static char hex_value[1 + (unsigned char) ~0];
+static const char digs[] = "0123456789ABCDEF";
 
-#define NOT_HEX 20
-#define NIBBLE(x) hex_value[(unsigned char)(x)]
-#define HEX(buffer) ((NIBBLE((buffer)[0])<<4) + NIBBLE((buffer)[1]))
+#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)
-
-
-
-static void
-DEFUN_VOID (srec_init)
-{
-  unsigned int i;
-  static boolean inited = false;
-
-  if (inited == false)
-    {
+#define        ISHEX(x)    hex_p(x)
 
-      inited = true;
+/* The maximum number of address+data+crc bytes on a line is FF.  */
+#define MAXCHUNK 0xff
 
-      for (i = 0; i < sizeof (hex_value); i++)
-       {
-         hex_value[i] = NOT_HEX;
-       }
+/* Default size for a CHUNK.  */
+#define DEFAULT_CHUNK 16
 
-      for (i = 0; i < 10; i++)
-       {
-         hex_value[i + '0'] = i;
+/* The number of data bytes we actually fit onto a line on output.
+   This variable can be modified by objcopy's --srec-len parameter.
+   For a 0x75 byte record you should set --srec-len=0x70.  */
+unsigned int Chunk = DEFAULT_CHUNK;
 
-       }
-      for (i = 0; i < 6; i++)
-       {
-         hex_value[i + 'a'] = i + 10;
-         hex_value[i + 'A'] = i + 10;
-       }
-    }
-}
-
-
-/* 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
+/* The type of srec output (free or forced to S3).
+   This variable can be modified by objcopy's --srec-forceS3
+   parameter.  */
+bfd_boolean S3Forced = FALSE;
 
-/* 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;
 
+/* Initialize by filling in the hex conversion array.  */
 
-/*
-   called once per input S-Record, used to work out vma and size of data.
- */
-
-static bfd_vma low, high;
-
-/*ARGSUSED*/
 static void
-size_symbols (abfd, buf, len, val)
-     bfd *abfd;
-     char *buf;
-     int len;
-     int val;
+srec_init (void)
 {
-  abfd->symcount++;
-  abfd->tdata.srec_data->string_size += len + 1;
-}
+  static bfd_boolean inited = FALSE;
 
-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 (! inited)
     {
-      asymbol *p;
-      if (abfd->tdata.srec_data->symbols == 0)
-       {
-         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;
-       }
-
-      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;
-      p->udata = 0;
+      inited = TRUE;
+      hex_init ();
     }
 }
-/*ARGSUSED*/
-static void
-DEFUN (size_srec, (abfd, section, address, raw, length),
-       bfd * abfd AND
-       asection * section AND
-       bfd_vma address AND
-       bfd_byte * raw AND
-       unsigned int length)
+
+/* Set up the S-record tdata information.  */
+
+static bfd_boolean
+srec_mkobject (bfd *abfd)
 {
-  if (address < low)
-    low = address;
-  if (address + length > high)
-    high = address + length - 1;
-}
+  tdata_type *tdata;
 
+  srec_init ();
 
-/*
- called once per input S-Record, copies data from input into bfd_alloc'd area
- */
+  tdata = (tdata_type *) bfd_alloc (abfd, sizeof (tdata_type));
+  if (tdata == NULL)
+    return FALSE;
 
-/*ARGSUSED*/
-static void
-DEFUN (fillup, (abfd, section, address, raw, length),
-       bfd * abfd AND
-       asection * section AND
-       bfd_vma address AND
-       bfd_byte * raw AND
-       unsigned int length)
-{
-  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++)
-    {
-      *dst = HEX (raw);
-      dst++;
-      raw += 2;
-    }
+  abfd->tdata.srec_data = tdata;
+  tdata->type = 1;
+  tdata->head = NULL;
+  tdata->tail = NULL;
+  tdata->symbols = NULL;
+  tdata->symtail = NULL;
+  tdata->csymbols = NULL;
+
+  return TRUE;
 }
 
-/* Pass over an S-Record file, calling one of the above functions on each
-   record.  */
+/* Read a byte from an S record file.  Set *ERRORPTR if an error
+   occurred.  Return EOF on error or end of file.  */
 
-static int 
-white (x)
-     char x;
-{
-  return (x == ' ' || x == '\t' || x == '\n' || x == '\r');
-}
 static int
-skipwhite (src, abfd)
-     char *src;
-     bfd *abfd;
+srec_get_byte (bfd *abfd, bfd_boolean *errorptr)
 {
-  int eof = 0;
-  while (white (*src) && !eof)
+  bfd_byte c;
+
+  if (bfd_bread (&c, (bfd_size_type) 1, abfd) != 1)
     {
-      eof = (boolean) (bfd_read (src, 1, 1, abfd) != 1);
+      if (bfd_get_error () != bfd_error_file_truncated)
+       *errorptr = TRUE;
+      return EOF;
     }
-  return eof;
+
+  return (int) (c & 0xff);
 }
 
-static boolean
-DEFUN (srec_mkobject, (abfd),
-       bfd * abfd)
+/* 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 void
+srec_bad_byte (bfd *abfd,
+              unsigned int lineno,
+              int c,
+              bfd_boolean error)
 {
-  if (abfd->tdata.srec_data == 0)
+  if (c == EOF)
+    {
+      if (! error)
+       bfd_set_error (bfd_error_file_truncated);
+    }
+  else
     {
-      tdata_type *tdata = (tdata_type *) bfd_alloc (abfd, sizeof (tdata_type));
-      if (!tdata)
+      char buf[10];
+
+      if (! ISPRINT (c))
+       sprintf (buf, "\\%03o", (unsigned int) c);
+      else
        {
-         bfd_set_error (bfd_error_no_memory);
-         return false;
+         buf[0] = c;
+         buf[1] = '\0';
        }
-      abfd->tdata.srec_data = tdata;
-      tdata->type = 1;
-      tdata->head = (srec_data_list_type *) NULL;
+      (*_bfd_error_handler)
+       (_("%B:%d: Unexpected character `%s' in S-record file\n"),
+        abfd, lineno, buf);
+      bfd_set_error (bfd_error_bad_value);
     }
-  return true;
-
 }
 
-static void 
-pass_over (abfd, func, symbolfunc, section)
-     bfd *abfd;
-     void (*func) ();
-     void (*symbolfunc) ();
-     asection *section;
+/* Add a new symbol found in an S-record file.  */
+
+static bfd_boolean
+srec_new_symbol (bfd *abfd, const char *name, bfd_vma val)
 {
-  unsigned int bytes_on_line;
-  boolean eof = false;
+  struct srec_symbol *n;
+
+  n = (struct srec_symbol *) bfd_alloc (abfd, sizeof (* n));
+  if (n == NULL)
+    return FALSE;
 
-  srec_mkobject (abfd);
-  /* To the front of the file */
-  bfd_seek (abfd, (file_ptr) 0, SEEK_SET);
-  while (eof == false)
+  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;
+}
+
+/* Read the S record file and turn it into sections.  We create a new
+   section for each contiguous set of bytes.  */
+
+static bfd_boolean
+srec_scan (bfd *abfd)
+{
+  int c;
+  unsigned int lineno = 1;
+  bfd_boolean error = FALSE;
+  bfd_byte *buf = NULL;
+  size_t bufsize = 0;
+  asection *sec = NULL;
+  char *symbuf = NULL;
+
+  if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0)
+    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))
+         do
            {
-             eof = skipwhite (src, abfd);
+             bfd_size_type alc;
+             char *p, *symname;
+             bfd_vma symval;
+
+             /* Starting a symbol definition.  */
+             while ((c = srec_get_byte (abfd, &error)) != EOF
+                    && (c == ' ' || c == '\t'))
+               ;
+
+             if (c == '\n' || c == '\r')
+               break;
+
+             if (c == EOF)
+               {
+                 srec_bad_byte (abfd, lineno, c, error);
+                 goto error_return;
+               }
+
+             alc = 10;
+             symbuf = (char *) bfd_malloc (alc + 1);
+             if (symbuf == NULL)
+               goto error_return;
+
+             p = symbuf;
+
+             *p++ = c;
+             while ((c = srec_get_byte (abfd, &error)) != EOF
+                    && ! ISSPACE (c))
+               {
+                 if ((bfd_size_type) (p - symbuf) >= alc)
+                   {
+                     char *n;
+
+                     alc *= 2;
+                     n = (char *) bfd_realloc (symbuf, alc + 1);
+                     if (n == NULL)
+                       goto error_return;
+                     p = n + (p - symbuf);
+                     symbuf = n;
+                   }
+
+                 *p++ = c;
+               }
+
+             if (c == EOF)
+               {
+                 srec_bad_byte (abfd, lineno, c, error);
+                 goto error_return;
+               }
+
+             *p++ = '\0';
+             symname = (char *) bfd_alloc (abfd, (bfd_size_type) (p - symbuf));
+             if (symname == NULL)
+               goto error_return;
+             strcpy (symname, symbuf);
+             free (symbuf);
+             symbuf = NULL;
+
+             while ((c = srec_get_byte (abfd, &error)) != EOF
+                    && (c == ' ' || c == '\t'))
+               ;
+             if (c == EOF)
+               {
+                 srec_bad_byte (abfd, lineno, c, error);
+                 goto error_return;
+               }
+
+             /* Skip a dollar sign before the hex value.  */
+             if (c == '$')
+               {
+                 c = srec_get_byte (abfd, &error);
+                 if (c == EOF)
+                   {
+                     srec_bad_byte (abfd, lineno, c, error);
+                     goto error_return;
+                   }
+               }
+
+             symval = 0;
+             while (ISHEX (c))
+               {
+                 symval <<= 4;
+                 symval += NIBBLE (c);
+                 c = srec_get_byte (abfd, &error);
+                 if (c == EOF)
+                   {
+                     srec_bad_byte (abfd, lineno, c, error);
+                     goto error_return;
+                   }
+               }
+
+             if (! srec_new_symbol (abfd, symname, symval))
+               goto error_return;
+           }
+         while (c == ' ' || c == '\t')
+           ;
+
+         if (c == '\n')
+           ++lineno;
+         else if (c != '\r')
+           {
+             srec_bad_byte (abfd, lineno, c, error);
+             goto error_return;
+           }
+
+         break;
+
+       case 'S':
+         {
+           file_ptr pos;
+           char hdr[3];
+           unsigned int bytes;
+           bfd_vma address;
+           bfd_byte *data;
+           unsigned char check_sum;
+
+           /* Starting an S-record.  */
+
+           pos = bfd_tell (abfd) - 1;
+
+           if (bfd_bread (hdr, (bfd_size_type) 3, abfd) != 3)
+             goto error_return;
 
+           if (! ISHEX (hdr[1]) || ! ISHEX (hdr[2]))
              {
-               int val = 0;
-               int slen = 0;
-               char symbol[MAXCHUNK];
+               if (! ISHEX (hdr[1]))
+                 c = hdr[1];
+               else
+                 c = hdr[2];
+               srec_bad_byte (abfd, lineno, c, error);
+               goto error_return;
+             }
+
+           check_sum = bytes = HEX (hdr + 1);
+           if (bytes * 2 > bufsize)
+             {
+               if (buf != NULL)
+                 free (buf);
+               buf = (bfd_byte *) bfd_malloc ((bfd_size_type) bytes * 2);
+               if (buf == NULL)
+                 goto error_return;
+               bufsize = bytes * 2;
+             }
 
-               /* get the symbol part */
-               while (!eof && !white (*src) && slen < MAXCHUNK)
+           if (bfd_bread (buf, (bfd_size_type) bytes * 2, abfd) != bytes * 2)
+             goto error_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':
+               check_sum += HEX (data);
+               address = HEX (data);
+               data += 2;
+               --bytes;
+               /* Fall through.  */
+             case '2':
+               check_sum += HEX (data);
+               address = (address << 8) | HEX (data);
+               data += 2;
+               --bytes;
+               /* Fall through.  */
+             case '1':
+               check_sum += HEX (data);
+               address = (address << 8) | HEX (data);
+               data += 2;
+               check_sum += HEX (data);
+               address = (address << 8) | HEX (data);
+               data += 2;
+               bytes -= 2;
+
+               if (sec != NULL
+                   && sec->vma + sec->size == address)
                  {
-                   symbol[slen++] = *src;
-                   eof = (boolean) (bfd_read (src, 1, 1, abfd) != 1);
+                   /* This data goes at the end of the section we are
+                      currently building.  */
+                   sec->size += bytes;
                  }
-               symbol[slen] = 0;
-               eof = skipwhite (src, abfd);
-               /* skip the $ for the hex value */
-               if (*src == '$')
+               else
                  {
-                   eof = (boolean) (bfd_read (src, 1, 1, abfd) != 1);
+                   char secbuf[20];
+                   char *secname;
+                   bfd_size_type amt;
+                   flagword flags;
+
+                   sprintf (secbuf, ".sec%d", bfd_count_sections (abfd) + 1);
+                   amt = strlen (secbuf) + 1;
+                   secname = (char *) bfd_alloc (abfd, amt);
+                   strcpy (secname, secbuf);
+                   flags = SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC;
+                   sec = bfd_make_section_with_flags (abfd, secname, flags);
+                   if (sec == NULL)
+                     goto error_return;
+                   sec->vma = address;
+                   sec->lma = address;
+                   sec->size = bytes;
+                   sec->filepos = pos;
                  }
 
-               /* Scan off the hex number */
-               while (isxdigit (*src))
+               while (bytes > 0)
                  {
-                   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);
+                   check_sum += HEX (data);
+                   data += 2;
+                   bytes--;
+                 }
+               check_sum = 255 - (check_sum & 0xff);
+               if (check_sum != HEX (data))
+                 {
+                   (*_bfd_error_handler)
+                     (_("%B:%d: Bad checksum in S-record file\n"),
+                      abfd, lineno);
+                   bfd_set_error (bfd_error_bad_value);
+                   goto error_return;
                  }
-               symbolfunc (abfd, symbol, slen, val);
-             }
-           }
-         break;
-       case 'S':
-         src++;
-
-         /* Fetch the type and the length */
-         bfd_read (src, 1, 3, abfd);
 
-         type = *src++;
+               break;
+
+             case '7':
+               check_sum += HEX (data);
+               address = HEX (data);
+               data += 2;
+               /* Fall through.  */
+             case '8':
+               check_sum += HEX (data);
+               address = (address << 8) | HEX (data);
+               data += 2;
+               /* Fall through.  */
+             case '9':
+               check_sum += HEX (data);
+               address = (address << 8) | HEX (data);
+               data += 2;
+               check_sum += HEX (data);
+               address = (address << 8) | HEX (data);
+               data += 2;
+
+               /* This is a termination record.  */
+               abfd->start_address = address;
+
+               check_sum = 255 - (check_sum & 0xff);
+               if (check_sum != HEX (data))
+                 {
+                   (*_bfd_error_handler)
+                     (_("%B:%d: Bad checksum in S-record file\n"),
+                      abfd, lineno);
+                   bfd_set_error (bfd_error_bad_value);
+                   goto error_return;
+                 }
 
-         if (!ISHEX (src[0]) || !ISHEX (src[1]))
-           break;
+               if (buf != NULL)
+                 free (buf);
 
-         bytes_on_line = HEX (src);
+               return TRUE;
+             }
+         }
+         break;
+       }
+    }
 
-         if (bytes_on_line > MAXCHUNK / 2)
-           break;
-         src += 2;
+  if (error)
+    goto error_return;
 
-         bfd_read (src, 1, bytes_on_line * 2, abfd);
+  if (buf != NULL)
+    free (buf);
 
-         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;
-           default:
-             return;
-           }
-       }
-    }
+  return TRUE;
 
+ error_return:
+  if (symbuf != NULL)
+    free (symbuf);
+  if (buf != NULL)
+    free (buf);
+  return FALSE;
 }
 
-static 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;
-}
+/* Check whether an existing file is an S-record file.  */
 
-static bfd_target *
-DEFUN (srec_object_p, (abfd),
-       bfd * abfd)
+static const bfd_target *
+srec_object_p (bfd *abfd)
 {
-  char b[4];
+  void * tdata_save;
+  bfd_byte b[4];
 
   srec_init ();
 
-  bfd_seek (abfd, (file_ptr) 0, SEEK_SET);
-  bfd_read (b, 1, 4, abfd);
+  if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0
+      || bfd_bread (b, (bfd_size_type) 4, abfd) != 4)
+    return NULL;
 
   if (b[0] != 'S' || !ISHEX (b[1]) || !ISHEX (b[2]) || !ISHEX (b[3]))
-    return (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.  */
+  tdata_save = abfd->tdata.any;
+  if (! srec_mkobject (abfd) || ! srec_scan (abfd))
+    {
+      if (abfd->tdata.any != tdata_save && abfd->tdata.any != NULL)
+       bfd_release (abfd, abfd->tdata.any);
+      abfd->tdata.any = tdata_save;
+      return NULL;
+    }
+
+  if (abfd->symcount > 0)
+    abfd->flags |= HAS_SYMS;
 
-  return object_p (abfd);
+  return abfd->xvec;
 }
 
+/* Check whether an existing file is an S-record file with symbols.  */
 
-static bfd_target *
-DEFUN (symbolsrec_object_p, (abfd),
-       bfd * abfd)
+static const bfd_target *
+symbolsrec_object_p (bfd *abfd)
 {
-  char b[4];
+  void * tdata_save;
+  char b[2];
 
   srec_init ();
 
-  bfd_seek (abfd, (file_ptr) 0, SEEK_SET);
-  bfd_read (b, 1, 4, abfd);
+  if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0
+      || bfd_bread (b, (bfd_size_type) 2, abfd) != 2)
+    return NULL;
 
   if (b[0] != '$' || b[1] != '$')
-    return (bfd_target *) NULL;
+    {
+      bfd_set_error (bfd_error_wrong_format);
+      return NULL;
+    }
+
+  tdata_save = abfd->tdata.any;
+  if (! srec_mkobject (abfd) || ! srec_scan (abfd))
+    {
+      if (abfd->tdata.any != tdata_save && abfd->tdata.any != NULL)
+       bfd_release (abfd, abfd->tdata.any);
+      abfd->tdata.any = tdata_save;
+      return NULL;
+    }
+
+  if (abfd->symcount > 0)
+    abfd->flags |= HAS_SYMS;
 
-  return object_p (abfd);
+  return abfd->xvec;
 }
 
+/* Read in the contents of a section in an S-record file.  */
 
-static boolean
-DEFUN (srec_get_section_contents, (abfd, section, location, offset, count),
-       bfd * abfd AND
-       asection * section AND
-       PTR location AND
-       file_ptr offset AND
-       bfd_size_type count)
+static bfd_boolean
+srec_read_section (bfd *abfd, asection *section, bfd_byte *contents)
 {
-  if (section->used_by_bfd == (PTR) NULL)
+  int c;
+  bfd_size_type sofar = 0;
+  bfd_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)
     {
-      section->used_by_bfd = (PTR) bfd_alloc (abfd, section->_raw_size);
-      if (!section->used_by_bfd)
+      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_bread (hdr, (bfd_size_type) 3, abfd) != 3)
+       goto error_return;
+
+      BFD_ASSERT (ISHEX (hdr[1]) && ISHEX (hdr[2]));
+
+      bytes = HEX (hdr + 1);
+
+      if (bytes * 2 > bufsize)
        {
-         bfd_set_error (bfd_error_no_memory);
-         return false;
+         if (buf != NULL)
+           free (buf);
+         buf = (bfd_byte *) bfd_malloc ((bfd_size_type) bytes * 2);
+         if (buf == NULL)
+           goto error_return;
+         bufsize = bytes * 2;
        }
 
-      pass_over (abfd, fillup, fillup_symbols, section);
+      if (bfd_bread (buf, (bfd_size_type) bytes * 2, abfd) != bytes * 2)
+       goto error_return;
+
+      address = 0;
+      data = buf;
+      switch (hdr[0])
+       {
+       default:
+         BFD_ASSERT (sofar == section->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->size);
+             if (buf != NULL)
+               free (buf);
+             return TRUE;
+           }
+
+         /* Don't consider checksum.  */
+         --bytes;
+
+         while (bytes-- != 0)
+           {
+             contents[sofar] = HEX (data);
+             data += 2;
+             ++sofar;
+           }
+
+         break;
+       }
     }
-  memcpy ((PTR) location,
-                (PTR) ((char *) (section->used_by_bfd) + offset),
-                count);
-  return true;
-}
 
+  if (error)
+    goto error_return;
+
+  BFD_ASSERT (sofar == section->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.  */
 
-boolean
-DEFUN (srec_set_arch_mach, (abfd, arch, machine),
-       bfd * abfd AND
-       enum bfd_architecture arch AND
-       unsigned long machine)
+static bfd_boolean
+srec_get_section_contents (bfd *abfd,
+                          asection *section,
+                          void * location,
+                          file_ptr offset,
+                          bfd_size_type count)
 {
-  return bfd_default_set_arch_mach (abfd, arch, machine);
+  if (count == 0)
+    return TRUE;
+
+  if (offset + count < count
+      || offset + count > section->size)
+    {
+      bfd_set_error (bfd_error_invalid_operation);
+      return FALSE;
+    }
+
+  if (section->used_by_bfd == NULL)
+    {
+      section->used_by_bfd = bfd_alloc (abfd, section->size);
+      if (section->used_by_bfd == NULL)
+       return FALSE;
+
+      if (! srec_read_section (abfd, section,
+                               (bfd_byte *) section->used_by_bfd))
+       return FALSE;
+    }
+
+  memcpy (location, (bfd_byte *) section->used_by_bfd + offset,
+         (size_t) count);
+
+  return TRUE;
 }
 
+/* Set the architecture.  We accept an unknown architecture here.  */
+
+static bfd_boolean
+srec_set_arch_mach (bfd *abfd, enum bfd_architecture arch, unsigned long mach)
+{
+  if (arch != bfd_arch_unknown)
+    return bfd_default_set_arch_mach (abfd, arch, mach);
+
+  abfd->arch_info = & bfd_default_arch_struct;
+  return TRUE;
+}
 
-/* we have to save up all the Srecords for a splurge before output,
-   also remember   */
+/* We have to save up all the Srecords for a splurge before output.  */
 
-static boolean
-DEFUN (srec_set_section_contents, (abfd, section, location, offset, bytes_to_do),
-       bfd * abfd AND
-       sec_ptr section AND
-       PTR location AND
-       file_ptr offset AND
-       bfd_size_type bytes_to_do)
+static bfd_boolean
+srec_set_section_contents (bfd *abfd,
+                          sec_ptr section,
+                          const void * location,
+                          file_ptr offset,
+                          bfd_size_type bytes_to_do)
 {
   tdata_type *tdata = abfd->tdata.srec_data;
-  srec_data_list_type *entry = (srec_data_list_type *)
-    bfd_alloc (abfd, sizeof (srec_data_list_type));
+  srec_data_list_type *entry;
 
-  if (!entry)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      return false;
-    }
+  entry = (srec_data_list_type *) bfd_alloc (abfd, sizeof (* entry));
+  if (entry == NULL)
+    return FALSE;
 
-  if ((section->flags & SEC_ALLOC)
+  if (bytes_to_do
+      && (section->flags & SEC_ALLOC)
       && (section->flags & SEC_LOAD))
     {
-      unsigned char *data = (unsigned char *) bfd_alloc (abfd, bytes_to_do);
-      if (!data)
-       {
-         bfd_set_error (bfd_error_no_memory);
-         return false;
-       }
-      memcpy ((PTR) data, location, bytes_to_do);
+      bfd_byte *data;
+
+      data = (bfd_byte *) bfd_alloc (abfd, bytes_to_do);
+      if (data == NULL)
+       return FALSE;
+      memcpy ((void *) data, location, (size_t) bytes_to_do);
+
+      /* Ff S3Forced is TRUE then always select S3 records,
+        regardless of the siez of the addresses.  */
+      if (S3Forced)
+       tdata->type = 3;
+      else if ((section->lma + offset + bytes_to_do - 1) <= 0xffff)
+       ;  /* The default, S1, is OK.  */
+      else if ((section->lma + offset + bytes_to_do - 1) <= 0xffffff
+              && tdata->type <= 2)
+       tdata->type = 2;
+      else
+       tdata->type = 3;
 
-      if ((section->lma + offset + bytes_to_do) <= 0xffff)
-       {
+      entry->data = data;
+      entry->where = section->lma + offset;
+      entry->size = bytes_to_do;
 
-       }
-      else if ((section->lma + offset + bytes_to_do) <= 0xffffff
-              && tdata->type < 2)
+      /* Sort the records by address.  Optimize for the common case of
+        adding a record to the end of the list.  */
+      if (tdata->tail != NULL
+         && entry->where >= tdata->tail->where)
        {
-         tdata->type = 2;
+         tdata->tail->next = entry;
+         entry->next = NULL;
+         tdata->tail = entry;
        }
       else
        {
-         tdata->type = 3;
+         srec_data_list_type **look;
+
+         for (look = &tdata->head;
+              *look != NULL && (*look)->where < entry->where;
+              look = &(*look)->next)
+           ;
+         entry->next = *look;
+         *look = entry;
+         if (entry->next == NULL)
+           tdata->tail = entry;
        }
-
-      entry->data = data;
-      entry->where = section->lma + offset;
-      entry->size = bytes_to_do;
-      entry->next = tdata->head;
-      tdata->head = entry;
     }
-  return true;
+  return TRUE;
 }
 
 /* Write a record of type, of the supplied number of bytes. The
    supplied bytes and length don't have a checksum. That's worked out
-   here
-*/
-static
-void 
-DEFUN (srec_write_record, (abfd, type, address, data, end),
-       bfd * abfd AND
-       char type AND
-       bfd_vma address AND
-       CONST unsigned char *data AND
-       CONST unsigned char *end)
-
+   here.  */
+
+static bfd_boolean
+srec_write_record (bfd *abfd,
+                  unsigned int type,
+                  bfd_vma address,
+                  const bfd_byte *data,
+                  const bfd_byte *end)
 {
-  char buffer[MAXCHUNK];
-
+  char buffer[2 * MAXCHUNK + 6];
   unsigned int check_sum = 0;
-  CONST unsigned char *src = data;
+  const bfd_byte *src = data;
   char *dst = buffer;
   char *length;
-
+  bfd_size_type wrlen;
 
   *dst++ = 'S';
   *dst++ = '0' + type;
 
   length = dst;
-  dst += 2;                    /* leave room for dst*/
+  dst += 2;                    /* Leave room for dst.  */
 
   switch (type)
     {
@@ -665,7 +980,7 @@ DEFUN (srec_write_record, (abfd, type, address, data, end),
       dst += 2;
     }
 
-  /* Fill in the length */
+  /* Fill in the length */
   TOHEX (length, (dst - length) / 2, check_sum);
   check_sum &= 0xff;
   check_sum = 255 - check_sum;
@@ -674,311 +989,311 @@ DEFUN (srec_write_record, (abfd, type, address, data, end),
 
   *dst++ = '\r';
   *dst++ = '\n';
-  bfd_write ((PTR) buffer, 1, dst - buffer, abfd);
-}
-
+  wrlen = dst - buffer;
 
+  return bfd_bwrite ((void *) buffer, wrlen, abfd) == wrlen;
+}
 
-static void
-DEFUN (srec_write_header, (abfd),
-       bfd * abfd)
+static bfd_boolean
+srec_write_header (bfd *abfd)
 {
-  unsigned char buffer[MAXCHUNK];
-  unsigned char *dst = buffer;
-  unsigned int i;
+  unsigned int len = strlen (abfd->filename);
 
-  /* I'll put an arbitary 40 char limit on header size */
-  for (i = 0; i < 40 && abfd->filename[i]; i++)
-    {
-      *dst++ = abfd->filename[i];
-    }
-  srec_write_record (abfd, 0, 0, buffer, dst);
+  /* I'll put an arbitrary 40 char limit on header size.  */
+  if (len > 40)
+    len = 40;
+
+  return srec_write_record (abfd, 0, (bfd_vma) 0,
+                           (bfd_byte *) abfd->filename,
+                           (bfd_byte *) abfd->filename + len);
 }
 
-static void
-DEFUN (srec_write_section, (abfd, tdata, list),
-       bfd * abfd AND
-       tdata_type * tdata AND
-       srec_data_list_type * list)
+static bfd_boolean
+srec_write_section (bfd *abfd,
+                   tdata_type *tdata,
+                   srec_data_list_type *list)
 {
-  unsigned int bytes_written = 0;
-  unsigned char *location = list->data;
-
-  while (bytes_written < list->size)
+  unsigned int octets_written = 0;
+  bfd_byte *location = list->data;
+
+  /* Validate number of data bytes to write.  The srec length byte
+     counts the address, data and crc bytes.  S1 (tdata->type == 1)
+     records have two address bytes, S2 (tdata->type == 2) records
+     have three, and S3 (tdata->type == 3) records have four.
+     The total length can't exceed 255, and a zero data length will
+     spin for a long time.  */
+  if (Chunk == 0)
+    Chunk = 1;
+  else if (Chunk > MAXCHUNK - tdata->type - 2)
+    Chunk = MAXCHUNK - tdata->type - 2;
+
+  while (octets_written < list->size)
     {
       bfd_vma address;
+      unsigned int octets_this_chunk = list->size - octets_written;
 
-      unsigned int bytes_this_chunk = list->size - bytes_written;
-
-      if (bytes_this_chunk > CHUNK)
-       {
-         bytes_this_chunk = CHUNK;
-       }
+      if (octets_this_chunk > Chunk)
+       octets_this_chunk = Chunk;
 
-      address = list->where + bytes_written;
+      address = list->where + octets_written / bfd_octets_per_byte (abfd);
 
-      srec_write_record (abfd,
-                        tdata->type,
-                        address,
-                        location,
-                        location + bytes_this_chunk);
+      if (! srec_write_record (abfd,
+                              tdata->type,
+                              address,
+                              location,
+                              location + octets_this_chunk))
+       return FALSE;
 
-      bytes_written += bytes_this_chunk;
-      location += bytes_this_chunk;
+      octets_written += octets_this_chunk;
+      location += octets_this_chunk;
     }
 
+  return TRUE;
 }
 
-static void
-DEFUN (srec_write_terminator, (abfd, tdata),
-       bfd * abfd AND
-       tdata_type * tdata)
+static bfd_boolean
+srec_write_terminator (bfd *abfd, tdata_type *tdata)
 {
-  unsigned char buffer[2];
-
-  srec_write_record (abfd, 10 - tdata->type,
-                    abfd->start_address, buffer, buffer);
+  return srec_write_record (abfd, 10 - tdata->type,
+                           abfd->start_address, NULL, NULL);
 }
 
-
-
-static void
-srec_write_symbols (abfd)
-     bfd *abfd;
+static bfd_boolean
+srec_write_symbols (bfd *abfd)
 {
-  char buffer[MAXCHUNK];
-  /* Dump out the symbols of a bfd */
+  /* Dump out the symbols of a bfd.  */
   int i;
-  int len = bfd_get_symcount (abfd);
+  int count = bfd_get_symcount (abfd);
 
-  if (len)
+  if (count)
     {
+      bfd_size_type len;
       asymbol **table = bfd_get_outsymbols (abfd);
-      sprintf (buffer, "$$ %s\r\n", abfd->filename);
 
-      bfd_write (buffer, strlen (buffer), 1, abfd);
+      len = strlen (abfd->filename);
+      if (bfd_bwrite ("$$ ", (bfd_size_type) 3, abfd) != 3
+         || bfd_bwrite (abfd->filename, len, abfd) != len
+         || bfd_bwrite ("\r\n", (bfd_size_type) 2, abfd) != 2)
+       return FALSE;
 
-      for (i = 0; i < len; i++)
+      for (i = 0; i < count; i++)
        {
          asymbol *s = table[i];
-#if 0
-         int len = strlen (s->name);
-
-         /* If this symbol has a .[ocs] in it, it's probably a file name
-        and we'll output that as the module name */
-
-         if (len > 3 && s->name[len - 2] == '.')
+         if (! bfd_is_local_label (abfd, s)
+             && (s->flags & BSF_DEBUGGING) == 0)
            {
-             int l;
-             sprintf (buffer, "$$ %s\r\n", s->name);
-             l = strlen (buffer);
-             bfd_write (buffer, l, 1, abfd);
-           }
-         else
-#endif
-           if (s->flags & (BSF_GLOBAL | BSF_LOCAL)
-               && (s->flags & BSF_DEBUGGING) == 0
-               && s->name[0] != '.'
-               && s->name[0] != 't')
-           {
-             /* Just dump out non debug symbols */
-
-             int l;
-             char buf2[40], *p;
-
-             sprintf_vma (buf2,
-                          s->value + s->section->output_section->lma
-                          + s->section->output_offset);
-             p = buf2;
+             /* Just dump out non debug symbols.  */
+             char buf[43], *p;
+
+             len = strlen (s->name);
+             if (bfd_bwrite ("  ", (bfd_size_type) 2, abfd) != 2
+                 || bfd_bwrite (s->name, len, abfd) != len)
+               return FALSE;
+
+             sprintf_vma (buf + 2, (s->value
+                                    + s->section->output_section->lma
+                                    + s->section->output_offset));
+             p = buf + 2;
              while (p[0] == '0' && p[1] != 0)
                p++;
-             sprintf (buffer, "  %s $%s\r\n", s->name, p);
-             l = strlen (buffer);
-             bfd_write (buffer, l, 1, abfd);
+             len = strlen (p);
+             p[len] = '\r';
+             p[len + 1] = '\n';
+             *--p = '$';
+             *--p = ' ';
+             len += 4;
+             if (bfd_bwrite (p, len, abfd) != len)
+               return FALSE;
            }
        }
-      sprintf (buffer, "$$ \r\n");
-      bfd_write (buffer, strlen (buffer), 1, abfd);
+      if (bfd_bwrite ("$$ \r\n", (bfd_size_type) 5, abfd) != 5)
+       return FALSE;
     }
+
+  return TRUE;
 }
 
-static boolean
-internal_srec_write_object_contents (abfd, symbols)
-     bfd *abfd;
-     int symbols;
+static bfd_boolean
+internal_srec_write_object_contents (bfd *abfd, int symbols)
 {
   tdata_type *tdata = abfd->tdata.srec_data;
   srec_data_list_type *list;
 
   if (symbols)
-    srec_write_symbols (abfd);
+    {
+      if (! srec_write_symbols (abfd))
+       return FALSE;
+    }
 
-  srec_write_header (abfd);
+  if (! srec_write_header (abfd))
+    return FALSE;
 
-  /* Now wander though all the sections provided and output them */
+  /* Now wander though all the sections provided and output them */
   list = tdata->head;
 
   while (list != (srec_data_list_type *) NULL)
     {
-      srec_write_section (abfd, tdata, list);
+      if (! srec_write_section (abfd, tdata, list))
+       return FALSE;
       list = list->next;
     }
-  srec_write_terminator (abfd, tdata);
-  return true;
+  return srec_write_terminator (abfd, tdata);
 }
 
-static boolean
-srec_write_object_contents (abfd)
-     bfd *abfd;
+static bfd_boolean
+srec_write_object_contents (bfd *abfd)
 {
   return internal_srec_write_object_contents (abfd, 0);
 }
 
-static boolean
-symbolsrec_write_object_contents (abfd)
-     bfd *abfd;
+static bfd_boolean
+symbolsrec_write_object_contents (bfd *abfd)
 {
   return internal_srec_write_object_contents (abfd, 1);
 }
 
-/*ARGSUSED*/
 static int
-DEFUN (srec_sizeof_headers, (abfd, exec),
-       bfd * abfd AND
-       boolean exec)
+srec_sizeof_headers (bfd *abfd ATTRIBUTE_UNUSED,
+                    struct bfd_link_info *info ATTRIBUTE_UNUSED)
 {
   return 0;
 }
 
-static asymbol *
-DEFUN (srec_make_empty_symbol, (abfd),
-       bfd * abfd)
-{
-  asymbol *new = (asymbol *) bfd_zalloc (abfd, sizeof (asymbol));
-  if (new)
-    new->the_bfd = abfd;
-  return new;
-}
+/* Return the amount of memory needed to read the symbol table.  */
 
-static unsigned int
-srec_get_symtab_upper_bound (abfd)
-     bfd *abfd;
+static long
+srec_get_symtab_upper_bound (bfd *abfd)
 {
-  /* Read in all the info */
-  srec_get_section_contents (abfd, abfd->sections, 0, 0, 0);
-  return (bfd_get_symcount (abfd) + 1) * (sizeof (asymbol *));
+  return (bfd_get_symcount (abfd) + 1) * sizeof (asymbol *);
 }
 
-static unsigned int
-DEFUN (srec_get_symtab, (abfd, alocation),
-       bfd * abfd AND
-       asymbol ** alocation)
+/* Return the symbol table.  */
+
+static long
+srec_canonicalize_symtab (bfd *abfd, asymbol **alocation)
 {
-  int lim = abfd->symcount;
-  int i;
-  for (i = 0; i < lim; i++)
+  bfd_size_type symcount = bfd_get_symcount (abfd);
+  asymbol *csymbols;
+  unsigned int i;
+
+  csymbols = abfd->tdata.srec_data->csymbols;
+  if (csymbols == NULL && symcount != 0)
     {
-      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)
+       return -1;
+      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*/
-void
-DEFUN (srec_get_symbol_info, (ignore_abfd, symbol, ret),
-       bfd * ignore_abfd AND
-       asymbol * symbol AND
-       symbol_info * ret)
+static void
+srec_get_symbol_info (bfd *ignore_abfd ATTRIBUTE_UNUSED,
+                     asymbol *symbol,
+                     symbol_info *ret)
 {
   bfd_symbol_info (symbol, ret);
 }
 
-/*ARGSUSED*/
-void
-DEFUN (srec_print_symbol, (ignore_abfd, afile, symbol, how),
-       bfd * ignore_abfd AND
-       PTR afile AND
-       asymbol * symbol AND
-       bfd_print_symbol_type how)
+static void
+srec_print_symbol (bfd *abfd,
+                  void * afile,
+                  asymbol *symbol,
+                  bfd_print_symbol_type how)
 {
   FILE *file = (FILE *) afile;
+
   switch (how)
     {
     case bfd_print_symbol_name:
       fprintf (file, "%s", symbol->name);
       break;
     default:
-      bfd_print_symbol_vandf ((PTR) file, symbol);
+      bfd_print_symbol_vandf (abfd, (void *) file, symbol);
       fprintf (file, " %-5s %s",
               symbol->section->name,
               symbol->name);
-
     }
 }
 
-#define FOO PROTO
-#define srec_new_section_hook (FOO(boolean, (*), (bfd *, asection *)))bfd_true
-
-#define srec_get_reloc_upper_bound (FOO(unsigned int, (*),(bfd*, asection *)))bfd_false
-#define srec_canonicalize_reloc (FOO(unsigned int, (*),(bfd*,asection *, arelent **, asymbol **))) bfd_0
-
-
-
-#define srec_openr_next_archived_file (FOO(bfd *, (*), (bfd*,bfd*))) bfd_nullvoidptr
-#define srec_find_nearest_line (FOO(boolean, (*),(bfd*,asection*,asymbol**,bfd_vma, CONST char**, CONST char**, unsigned int *))) bfd_false
-#define srec_generic_stat_arch_elt  (FOO(int, (*), (bfd *,struct stat *))) bfd_0
-
-
-#define srec_core_file_failing_command (char *(*)())(bfd_nullvoidptr)
-#define srec_core_file_failing_signal (int (*)())bfd_0
-#define srec_core_file_matches_executable_p (FOO(boolean, (*),(bfd*, bfd*)))bfd_false
-#define srec_slurp_armap bfd_true
-#define srec_slurp_extended_name_table bfd_true
-#define srec_truncate_arname (void (*)())bfd_nullvoidptr
-#define srec_write_armap  (FOO( boolean, (*),(bfd *, unsigned int, struct orl *, unsigned int, int))) bfd_nullvoidptr
-#define srec_get_lineno (struct lineno_cache_entry *(*)())bfd_nullvoidptr
-#define        srec_close_and_cleanup  bfd_generic_close_and_cleanup
-#define srec_bfd_debug_info_start bfd_void
-#define srec_bfd_debug_info_end bfd_void
-#define srec_bfd_debug_info_accumulate  (FOO(void, (*), (bfd *,         asection *))) bfd_void
-#define srec_bfd_get_relocated_section_contents bfd_generic_get_relocated_section_contents
-#define srec_bfd_relax_section bfd_generic_relax_section
-#define srec_bfd_reloc_type_lookup \
-  ((CONST struct reloc_howto_struct *(*) PARAMS ((bfd *, bfd_reloc_code_real_type))) bfd_nullvoidptr)
-#define srec_bfd_make_debug_symbol \
-  ((asymbol *(*) PARAMS ((bfd *, void *, unsigned long))) bfd_nullvoidptr)
-#define srec_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
-#define srec_bfd_link_add_symbols _bfd_generic_link_add_symbols
-#define srec_bfd_final_link _bfd_generic_final_link
-
-bfd_target srec_vec =
+#define        srec_close_and_cleanup                    _bfd_generic_close_and_cleanup
+#define srec_bfd_free_cached_info                 _bfd_generic_bfd_free_cached_info
+#define srec_new_section_hook                     _bfd_generic_new_section_hook
+#define srec_bfd_is_target_special_symbol         ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false)
+#define srec_bfd_is_local_label_name              bfd_generic_is_local_label_name
+#define srec_get_lineno                           _bfd_nosymbols_get_lineno
+#define srec_find_nearest_line                    _bfd_nosymbols_find_nearest_line
+#define srec_find_inliner_info                    _bfd_nosymbols_find_inliner_info
+#define srec_make_empty_symbol                    _bfd_generic_make_empty_symbol
+#define srec_bfd_make_debug_symbol                _bfd_nosymbols_bfd_make_debug_symbol
+#define srec_read_minisymbols                     _bfd_generic_read_minisymbols
+#define srec_minisymbol_to_symbol                 _bfd_generic_minisymbol_to_symbol
+#define srec_get_section_contents_in_window       _bfd_generic_get_section_contents_in_window
+#define srec_bfd_get_relocated_section_contents   bfd_generic_get_relocated_section_contents
+#define srec_bfd_relax_section                    bfd_generic_relax_section
+#define srec_bfd_gc_sections                      bfd_generic_gc_sections
+#define srec_bfd_lookup_section_flags             bfd_generic_lookup_section_flags
+#define srec_bfd_merge_sections                   bfd_generic_merge_sections
+#define srec_bfd_is_group_section                 bfd_generic_is_group_section
+#define srec_bfd_discard_group                    bfd_generic_discard_group
+#define srec_section_already_linked               _bfd_generic_section_already_linked
+#define srec_bfd_define_common_symbol             bfd_generic_define_common_symbol
+#define srec_bfd_link_hash_table_create           _bfd_generic_link_hash_table_create
+#define srec_bfd_link_hash_table_free             _bfd_generic_link_hash_table_free
+#define srec_bfd_link_add_symbols                 _bfd_generic_link_add_symbols
+#define srec_bfd_link_just_syms                   _bfd_generic_link_just_syms
+#define srec_bfd_copy_link_hash_symbol_type \
+  _bfd_generic_copy_link_hash_symbol_type
+#define srec_bfd_final_link                       _bfd_generic_final_link
+#define srec_bfd_link_split_section               _bfd_generic_link_split_section
+
+const bfd_target srec_vec =
 {
-  "srec",                      /* name */
+  "srec",                      /* Name.  */
   bfd_target_srec_flavour,
-  true,                                /* target byte order */
-  true,                                /* target headers byte order */
-  (HAS_RELOC | EXEC_P |                /* object flags */
+  BFD_ENDIAN_UNKNOWN,          /* Target byte order.  */
+  BFD_ENDIAN_UNKNOWN,          /* Target headers byte order.  */
+  (HAS_RELOC | EXEC_P |                /* Object flags.  */
    HAS_LINENO | HAS_DEBUG |
    HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
   (SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS
-   | SEC_ALLOC | SEC_LOAD | SEC_RELOC),        /* section flags */
-  0,                           /* leading underscore */
-  ' ',                         /* ar_pad_char */
-  16,                          /* ar_max_namelen */
-  1,                           /* minimum alignment */
+   | SEC_ALLOC | SEC_LOAD | SEC_RELOC),        /* Section flags.  */
+  0,                           /* Leading underscore.  */
+  ' ',                         /* AR_pad_char.  */
+  16,                          /* AR_max_namelen.  */
+  0,                           /* match priority.  */
   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
-  bfd_getb16, bfd_getb_signed_16, bfd_putb16,  /* data */
+  bfd_getb16, bfd_getb_signed_16, bfd_putb16,  /* Data.  */
   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
-  bfd_getb16, bfd_getb_signed_16, bfd_putb16,  /* hdrs */
+  bfd_getb16, bfd_getb_signed_16, bfd_putb16,  /* Hdrs.  */
 
   {
     _bfd_dummy_target,
-    srec_object_p,             /* bfd_check_format */
-    (struct bfd_target * (*)()) bfd_nullvoidptr,
-    (struct bfd_target * (*)()) bfd_nullvoidptr,
+    srec_object_p,             /* bfd_check_format */
+    _bfd_dummy_target,
+    _bfd_dummy_target,
   },
   {
     bfd_false,
@@ -986,44 +1301,55 @@ bfd_target srec_vec =
     _bfd_generic_mkarchive,
     bfd_false,
   },
-  {                            /* bfd_write_contents */
+  {                            /* bfd_write_contents */
     bfd_false,
     srec_write_object_contents,
     _bfd_write_archive_contents,
     bfd_false,
   },
-  JUMP_TABLE (srec)
-};
 
+  BFD_JUMP_TABLE_GENERIC (srec),
+  BFD_JUMP_TABLE_COPY (_bfd_generic),
+  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_WRITE (srec),
+  BFD_JUMP_TABLE_LINK (srec),
+  BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
 
+  NULL,
 
-bfd_target symbolsrec_vec =
+  NULL
+};
+
+const bfd_target symbolsrec_vec =
 {
-  "symbolsrec",                        /* name */
+  "symbolsrec",                        /* Name.  */
   bfd_target_srec_flavour,
-  true,                                /* target byte order */
-  true,                                /* target headers byte order */
-  (HAS_RELOC | EXEC_P |                /* object flags */
+  BFD_ENDIAN_UNKNOWN,          /* Target byte order.  */
+  BFD_ENDIAN_UNKNOWN,          /* Target headers byte order.  */
+  (HAS_RELOC | EXEC_P |                /* Object flags.  */
    HAS_LINENO | HAS_DEBUG |
    HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
   (SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS
-   | SEC_ALLOC | SEC_LOAD | SEC_RELOC),        /* section flags */
-  0,                           /* leading underscore */
-  ' ',                         /* ar_pad_char */
-  16,                          /* ar_max_namelen */
-  1,                           /* minimum alignment */
+   | SEC_ALLOC | SEC_LOAD | SEC_RELOC),        /* Section flags.  */
+  0,                           /* Leading underscore.  */
+  ' ',                         /* AR_pad_char.  */
+  16,                          /* AR_max_namelen.  */
+  0,                           /* match priority.  */
   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
-  bfd_getb16, bfd_getb_signed_16, bfd_putb16,  /* data */
+  bfd_getb16, bfd_getb_signed_16, bfd_putb16,  /* Data.  */
   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
-  bfd_getb16, bfd_getb_signed_16, bfd_putb16,  /* hdrs */
+  bfd_getb16, bfd_getb_signed_16, bfd_putb16,  /* Headers.  */
 
   {
     _bfd_dummy_target,
-    symbolsrec_object_p,       /* bfd_check_format */
-    (struct bfd_target * (*)()) bfd_nullvoidptr,
-    (struct bfd_target * (*)()) bfd_nullvoidptr,
+    symbolsrec_object_p,       /* bfd_check_format */
+    _bfd_dummy_target,
+    _bfd_dummy_target,
   },
   {
     bfd_false,
@@ -1031,12 +1357,24 @@ bfd_target symbolsrec_vec =
     _bfd_generic_mkarchive,
     bfd_false,
   },
-  {                            /* bfd_write_contents */
+  {                            /* bfd_write_contents */
     bfd_false,
     symbolsrec_write_object_contents,
     _bfd_write_archive_contents,
     bfd_false,
   },
-  JUMP_TABLE (srec),
-  (PTR) 0
+
+  BFD_JUMP_TABLE_GENERIC (srec),
+  BFD_JUMP_TABLE_COPY (_bfd_generic),
+  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_WRITE (srec),
+  BFD_JUMP_TABLE_LINK (srec),
+  BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
+
+  NULL,
+
+  NULL
 };