Back to index

cell-binutils  2.17cvs20070401
srec.c
Go to the documentation of this file.
00001 /* BFD back-end for s-record objects.
00002    Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
00003    2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
00004    Free Software Foundation, Inc.
00005    Written by Steve Chamberlain of Cygnus Support <sac@cygnus.com>.
00006 
00007    This file is part of BFD, the Binary File Descriptor library.
00008 
00009    This program is free software; you can redistribute it and/or modify
00010    it under the terms of the GNU General Public License as published by
00011    the Free Software Foundation; either version 2 of the License, or
00012    (at your option) any later version.
00013 
00014    This program is distributed in the hope that it will be useful,
00015    but WITHOUT ANY WARRANTY; without even the implied warranty of
00016    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017    GNU General Public License for more details.
00018 
00019    You should have received a copy of the GNU General Public License
00020    along with this program; if not, write to the Free Software
00021    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
00022 
00023 /* SUBSECTION
00024        S-Record handling
00025 
00026    DESCRIPTION
00027 
00028        Ordinary S-Records cannot hold anything but addresses and
00029        data, so that's all that we implement.
00030 
00031        The only interesting thing is that S-Records may come out of
00032        order and there is no header, so an initial scan is required
00033        to discover the minimum and maximum addresses used to create
00034        the vma and size of the only section we create.  We
00035        arbitrarily call this section ".text".
00036 
00037        When bfd_get_section_contents is called the file is read
00038        again, and this time the data is placed into a bfd_alloc'd
00039        area.
00040 
00041        Any number of sections may be created for output, we save them
00042        up and output them when it's time to close the bfd.
00043 
00044        An s record looks like:
00045 
00046    EXAMPLE
00047        S<type><length><address><data><checksum>
00048 
00049    DESCRIPTION
00050        Where
00051        o length
00052        is the number of bytes following upto the checksum. Note that
00053        this is not the number of chars following, since it takes two
00054        chars to represent a byte.
00055        o type
00056        is one of:
00057        0) header record
00058        1) two byte address data record
00059        2) three byte address data record
00060        3) four byte address data record
00061        7) four byte address termination record
00062        8) three byte address termination record
00063        9) two byte address termination record
00064 
00065        o address
00066        is the start address of the data following, or in the case of
00067        a termination record, the start address of the image
00068        o data
00069        is the data.
00070        o checksum
00071        is the sum of all the raw byte data in the record, from the length
00072        upwards, modulo 256 and subtracted from 255.
00073 
00074    SUBSECTION
00075        Symbol S-Record handling
00076 
00077    DESCRIPTION
00078        Some ICE equipment understands an addition to the standard
00079        S-Record format; symbols and their addresses can be sent
00080        before the data.
00081 
00082        The format of this is:
00083        ($$ <modulename>
00084               (<space> <symbol> <address>)*)
00085        $$
00086 
00087        so a short symbol table could look like:
00088 
00089    EXAMPLE
00090        $$ flash.x
00091        $$ flash.c
00092          _port6 $0
00093          _delay $4
00094          _start $14
00095          _etext $8036
00096          _edata $8036
00097          _end $8036
00098        $$
00099 
00100    DESCRIPTION
00101        We allow symbols to be anywhere in the data stream - the module names
00102        are always ignored.  */
00103 
00104 #include "bfd.h"
00105 #include "sysdep.h"
00106 #include "libbfd.h"
00107 #include "libiberty.h"
00108 #include "safe-ctype.h"
00109 
00110 
00111 /* Macros for converting between hex and binary.  */
00112 
00113 static const char digs[] = "0123456789ABCDEF";
00114 
00115 #define NIBBLE(x)    hex_value(x)
00116 #define HEX(buffer) ((NIBBLE ((buffer)[0])<<4) + NIBBLE ((buffer)[1]))
00117 #define TOHEX(d, x, ch) \
00118        d[1] = digs[(x) & 0xf]; \
00119        d[0] = digs[((x)>>4)&0xf]; \
00120        ch += ((x) & 0xff);
00121 #define       ISHEX(x)    hex_p(x)
00122 
00123 /* The maximum number of address+data+crc bytes on a line is FF.  */
00124 #define MAXCHUNK 0xff
00125 
00126 /* Default size for a CHUNK.  */
00127 #define DEFAULT_CHUNK 16
00128 
00129 /* The number of data bytes we actually fit onto a line on output.
00130    This variable can be modified by objcopy's --srec-len parameter.
00131    For a 0x75 byte record you should set --srec-len=0x70.  */
00132 unsigned int Chunk = DEFAULT_CHUNK;
00133 
00134 /* The type of srec output (free or forced to S3).
00135    This variable can be modified by objcopy's --srec-forceS3
00136    parameter.  */
00137 bfd_boolean S3Forced = FALSE;
00138 
00139 /* When writing an S-record file, the S-records can not be output as
00140    they are seen.  This structure is used to hold them in memory.  */
00141 
00142 struct srec_data_list_struct
00143 {
00144   struct srec_data_list_struct *next;
00145   bfd_byte *data;
00146   bfd_vma where;
00147   bfd_size_type size;
00148 };
00149 
00150 typedef struct srec_data_list_struct srec_data_list_type;
00151 
00152 /* When scanning the S-record file, a linked list of srec_symbol
00153    structures is built to represent the symbol table (if there is
00154    one).  */
00155 
00156 struct srec_symbol
00157 {
00158   struct srec_symbol *next;
00159   const char *name;
00160   bfd_vma val;
00161 };
00162 
00163 /* The S-record tdata information.  */
00164 
00165 typedef struct srec_data_struct
00166   {
00167     srec_data_list_type *head;
00168     srec_data_list_type *tail;
00169     unsigned int type;
00170     struct srec_symbol *symbols;
00171     struct srec_symbol *symtail;
00172     asymbol *csymbols;
00173   }
00174 tdata_type;
00175 
00176 /* Initialize by filling in the hex conversion array.  */
00177 
00178 static void
00179 srec_init (void)
00180 {
00181   static bfd_boolean inited = FALSE;
00182 
00183   if (! inited)
00184     {
00185       inited = TRUE;
00186       hex_init ();
00187     }
00188 }
00189 
00190 /* Set up the S-record tdata information.  */
00191 
00192 static bfd_boolean
00193 srec_mkobject (bfd *abfd)
00194 {
00195   tdata_type *tdata;
00196 
00197   srec_init ();
00198 
00199   tdata = bfd_alloc (abfd, sizeof (tdata_type));
00200   if (tdata == NULL)
00201     return FALSE;
00202 
00203   abfd->tdata.srec_data = tdata;
00204   tdata->type = 1;
00205   tdata->head = NULL;
00206   tdata->tail = NULL;
00207   tdata->symbols = NULL;
00208   tdata->symtail = NULL;
00209   tdata->csymbols = NULL;
00210 
00211   return TRUE;
00212 }
00213 
00214 /* Read a byte from an S record file.  Set *ERRORPTR if an error
00215    occurred.  Return EOF on error or end of file.  */
00216 
00217 static int
00218 srec_get_byte (bfd *abfd, bfd_boolean *errorptr)
00219 {
00220   bfd_byte c;
00221 
00222   if (bfd_bread (&c, (bfd_size_type) 1, abfd) != 1)
00223     {
00224       if (bfd_get_error () != bfd_error_file_truncated)
00225        *errorptr = TRUE;
00226       return EOF;
00227     }
00228 
00229   return (int) (c & 0xff);
00230 }
00231 
00232 /* Report a problem in an S record file.  FIXME: This probably should
00233    not call fprintf, but we really do need some mechanism for printing
00234    error messages.  */
00235 
00236 static void
00237 srec_bad_byte (bfd *abfd,
00238               unsigned int lineno,
00239               int c,
00240               bfd_boolean error)
00241 {
00242   if (c == EOF)
00243     {
00244       if (! error)
00245        bfd_set_error (bfd_error_file_truncated);
00246     }
00247   else
00248     {
00249       char buf[10];
00250 
00251       if (! ISPRINT (c))
00252        sprintf (buf, "\\%03o", (unsigned int) c);
00253       else
00254        {
00255          buf[0] = c;
00256          buf[1] = '\0';
00257        }
00258       (*_bfd_error_handler)
00259        (_("%B:%d: Unexpected character `%s' in S-record file\n"),
00260         abfd, lineno, buf);
00261       bfd_set_error (bfd_error_bad_value);
00262     }
00263 }
00264 
00265 /* Add a new symbol found in an S-record file.  */
00266 
00267 static bfd_boolean
00268 srec_new_symbol (bfd *abfd, const char *name, bfd_vma val)
00269 {
00270   struct srec_symbol *n;
00271 
00272   n = bfd_alloc (abfd, sizeof (* n));
00273   if (n == NULL)
00274     return FALSE;
00275 
00276   n->name = name;
00277   n->val = val;
00278 
00279   if (abfd->tdata.srec_data->symbols == NULL)
00280     abfd->tdata.srec_data->symbols = n;
00281   else
00282     abfd->tdata.srec_data->symtail->next = n;
00283   abfd->tdata.srec_data->symtail = n;
00284   n->next = NULL;
00285 
00286   ++abfd->symcount;
00287 
00288   return TRUE;
00289 }
00290 
00291 /* Read the S record file and turn it into sections.  We create a new
00292    section for each contiguous set of bytes.  */
00293 
00294 static bfd_boolean
00295 srec_scan (bfd *abfd)
00296 {
00297   int c;
00298   unsigned int lineno = 1;
00299   bfd_boolean error = FALSE;
00300   bfd_byte *buf = NULL;
00301   size_t bufsize = 0;
00302   asection *sec = NULL;
00303   char *symbuf = NULL;
00304 
00305   if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0)
00306     goto error_return;
00307 
00308   while ((c = srec_get_byte (abfd, &error)) != EOF)
00309     {
00310       /* We only build sections from contiguous S-records, so if this
00311         is not an S-record, then stop building a section.  */
00312       if (c != 'S' && c != '\r' && c != '\n')
00313        sec = NULL;
00314 
00315       switch (c)
00316        {
00317        default:
00318          srec_bad_byte (abfd, lineno, c, error);
00319          goto error_return;
00320 
00321        case '\n':
00322          ++lineno;
00323          break;
00324 
00325        case '\r':
00326          break;
00327 
00328        case '$':
00329          /* Starting a module name, which we ignore.  */
00330          while ((c = srec_get_byte (abfd, &error)) != '\n'
00331                && c != EOF)
00332            ;
00333          if (c == EOF)
00334            {
00335              srec_bad_byte (abfd, lineno, c, error);
00336              goto error_return;
00337            }
00338 
00339          ++lineno;
00340          break;
00341 
00342        case ' ':
00343          do
00344            {
00345              bfd_size_type alc;
00346              char *p, *symname;
00347              bfd_vma symval;
00348 
00349              /* Starting a symbol definition.  */
00350              while ((c = srec_get_byte (abfd, &error)) != EOF
00351                    && (c == ' ' || c == '\t'))
00352               ;
00353 
00354              if (c == '\n' || c == '\r')
00355               break;
00356 
00357              if (c == EOF)
00358               {
00359                 srec_bad_byte (abfd, lineno, c, error);
00360                 goto error_return;
00361               }
00362 
00363              alc = 10;
00364              symbuf = bfd_malloc (alc + 1);
00365              if (symbuf == NULL)
00366               goto error_return;
00367 
00368              p = symbuf;
00369 
00370              *p++ = c;
00371              while ((c = srec_get_byte (abfd, &error)) != EOF
00372                    && ! ISSPACE (c))
00373               {
00374                 if ((bfd_size_type) (p - symbuf) >= alc)
00375                   {
00376                     char *n;
00377 
00378                     alc *= 2;
00379                     n = bfd_realloc (symbuf, alc + 1);
00380                     if (n == NULL)
00381                      goto error_return;
00382                     p = n + (p - symbuf);
00383                     symbuf = n;
00384                   }
00385 
00386                 *p++ = c;
00387               }
00388 
00389              if (c == EOF)
00390               {
00391                 srec_bad_byte (abfd, lineno, c, error);
00392                 goto error_return;
00393               }
00394 
00395              *p++ = '\0';
00396              symname = bfd_alloc (abfd, (bfd_size_type) (p - symbuf));
00397              if (symname == NULL)
00398               goto error_return;
00399              strcpy (symname, symbuf);
00400              free (symbuf);
00401              symbuf = NULL;
00402 
00403              while ((c = srec_get_byte (abfd, &error)) != EOF
00404                    && (c == ' ' || c == '\t'))
00405               ;
00406              if (c == EOF)
00407               {
00408                 srec_bad_byte (abfd, lineno, c, error);
00409                 goto error_return;
00410               }
00411 
00412              /* Skip a dollar sign before the hex value.  */
00413              if (c == '$')
00414               {
00415                 c = srec_get_byte (abfd, &error);
00416                 if (c == EOF)
00417                   {
00418                     srec_bad_byte (abfd, lineno, c, error);
00419                     goto error_return;
00420                   }
00421               }
00422 
00423              symval = 0;
00424              while (ISHEX (c))
00425               {
00426                 symval <<= 4;
00427                 symval += NIBBLE (c);
00428                 c = srec_get_byte (abfd, &error);
00429               }
00430 
00431              if (! srec_new_symbol (abfd, symname, symval))
00432               goto error_return;
00433            }
00434          while (c == ' ' || c == '\t')
00435            ;
00436 
00437          if (c == '\n')
00438            ++lineno;
00439          else if (c != '\r')
00440            {
00441              srec_bad_byte (abfd, lineno, c, error);
00442              goto error_return;
00443            }
00444 
00445          break;
00446 
00447        case 'S':
00448          {
00449            file_ptr pos;
00450            char hdr[3];
00451            unsigned int bytes;
00452            bfd_vma address;
00453            bfd_byte *data;
00454 
00455            /* Starting an S-record.  */
00456 
00457            pos = bfd_tell (abfd) - 1;
00458 
00459            if (bfd_bread (hdr, (bfd_size_type) 3, abfd) != 3)
00460              goto error_return;
00461 
00462            if (! ISHEX (hdr[1]) || ! ISHEX (hdr[2]))
00463              {
00464               if (! ISHEX (hdr[1]))
00465                 c = hdr[1];
00466               else
00467                 c = hdr[2];
00468               srec_bad_byte (abfd, lineno, c, error);
00469               goto error_return;
00470              }
00471 
00472            bytes = HEX (hdr + 1);
00473            if (bytes * 2 > bufsize)
00474              {
00475               if (buf != NULL)
00476                 free (buf);
00477               buf = bfd_malloc ((bfd_size_type) bytes * 2);
00478               if (buf == NULL)
00479                 goto error_return;
00480               bufsize = bytes * 2;
00481              }
00482 
00483            if (bfd_bread (buf, (bfd_size_type) bytes * 2, abfd) != bytes * 2)
00484              goto error_return;
00485 
00486            /* Ignore the checksum byte.  */
00487            --bytes;
00488 
00489            address = 0;
00490            data = buf;
00491            switch (hdr[0])
00492              {
00493              case '0':
00494              case '5':
00495               /* Prologue--ignore the file name, but stop building a
00496                  section at this point.  */
00497               sec = NULL;
00498               break;
00499 
00500              case '3':
00501               address = HEX (data);
00502               data += 2;
00503               --bytes;
00504               /* Fall through.  */
00505              case '2':
00506               address = (address << 8) | HEX (data);
00507               data += 2;
00508               --bytes;
00509               /* Fall through.  */
00510              case '1':
00511               address = (address << 8) | HEX (data);
00512               data += 2;
00513               address = (address << 8) | HEX (data);
00514               data += 2;
00515               bytes -= 2;
00516 
00517               if (sec != NULL
00518                   && sec->vma + sec->size == address)
00519                 {
00520                   /* This data goes at the end of the section we are
00521                      currently building.  */
00522                   sec->size += bytes;
00523                 }
00524               else
00525                 {
00526                   char secbuf[20];
00527                   char *secname;
00528                   bfd_size_type amt;
00529                   flagword flags;
00530 
00531                   sprintf (secbuf, ".sec%d", bfd_count_sections (abfd) + 1);
00532                   amt = strlen (secbuf) + 1;
00533                   secname = bfd_alloc (abfd, amt);
00534                   strcpy (secname, secbuf);
00535                   flags = SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC;
00536                   sec = bfd_make_section_with_flags (abfd, secname, flags);
00537                   if (sec == NULL)
00538                     goto error_return;
00539                   sec->vma = address;
00540                   sec->lma = address;
00541                   sec->size = bytes;
00542                   sec->filepos = pos;
00543                 }
00544               break;
00545 
00546              case '7':
00547               address = HEX (data);
00548               data += 2;
00549               /* Fall through.  */
00550              case '8':
00551               address = (address << 8) | HEX (data);
00552               data += 2;
00553               /* Fall through.  */
00554              case '9':
00555               address = (address << 8) | HEX (data);
00556               data += 2;
00557               address = (address << 8) | HEX (data);
00558               data += 2;
00559 
00560               /* This is a termination record.  */
00561               abfd->start_address = address;
00562 
00563               if (buf != NULL)
00564                 free (buf);
00565 
00566               return TRUE;
00567              }
00568          }
00569          break;
00570        }
00571     }
00572 
00573   if (error)
00574     goto error_return;
00575 
00576   if (buf != NULL)
00577     free (buf);
00578 
00579   return TRUE;
00580 
00581  error_return:
00582   if (symbuf != NULL)
00583     free (symbuf);
00584   if (buf != NULL)
00585     free (buf);
00586   return FALSE;
00587 }
00588 
00589 /* Check whether an existing file is an S-record file.  */
00590 
00591 static const bfd_target *
00592 srec_object_p (bfd *abfd)
00593 {
00594   void * tdata_save;
00595   bfd_byte b[4];
00596 
00597   srec_init ();
00598 
00599   if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0
00600       || bfd_bread (b, (bfd_size_type) 4, abfd) != 4)
00601     return NULL;
00602 
00603   if (b[0] != 'S' || !ISHEX (b[1]) || !ISHEX (b[2]) || !ISHEX (b[3]))
00604     {
00605       bfd_set_error (bfd_error_wrong_format);
00606       return NULL;
00607     }
00608 
00609   tdata_save = abfd->tdata.any;
00610   if (! srec_mkobject (abfd) || ! srec_scan (abfd))
00611     {
00612       if (abfd->tdata.any != tdata_save && abfd->tdata.any != NULL)
00613        bfd_release (abfd, abfd->tdata.any);
00614       abfd->tdata.any = tdata_save;
00615       return NULL;
00616     }
00617 
00618   if (abfd->symcount > 0)
00619     abfd->flags |= HAS_SYMS;
00620 
00621   return abfd->xvec;
00622 }
00623 
00624 /* Check whether an existing file is an S-record file with symbols.  */
00625 
00626 static const bfd_target *
00627 symbolsrec_object_p (bfd *abfd)
00628 {
00629   void * tdata_save;
00630   char b[2];
00631 
00632   srec_init ();
00633 
00634   if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0
00635       || bfd_bread (b, (bfd_size_type) 2, abfd) != 2)
00636     return NULL;
00637 
00638   if (b[0] != '$' || b[1] != '$')
00639     {
00640       bfd_set_error (bfd_error_wrong_format);
00641       return NULL;
00642     }
00643 
00644   tdata_save = abfd->tdata.any;
00645   if (! srec_mkobject (abfd) || ! srec_scan (abfd))
00646     {
00647       if (abfd->tdata.any != tdata_save && abfd->tdata.any != NULL)
00648        bfd_release (abfd, abfd->tdata.any);
00649       abfd->tdata.any = tdata_save;
00650       return NULL;
00651     }
00652 
00653   if (abfd->symcount > 0)
00654     abfd->flags |= HAS_SYMS;
00655 
00656   return abfd->xvec;
00657 }
00658 
00659 /* Read in the contents of a section in an S-record file.  */
00660 
00661 static bfd_boolean
00662 srec_read_section (bfd *abfd, asection *section, bfd_byte *contents)
00663 {
00664   int c;
00665   bfd_size_type sofar = 0;
00666   bfd_boolean error = FALSE;
00667   bfd_byte *buf = NULL;
00668   size_t bufsize = 0;
00669 
00670   if (bfd_seek (abfd, section->filepos, SEEK_SET) != 0)
00671     goto error_return;
00672 
00673   while ((c = srec_get_byte (abfd, &error)) != EOF)
00674     {
00675       bfd_byte hdr[3];
00676       unsigned int bytes;
00677       bfd_vma address;
00678       bfd_byte *data;
00679 
00680       if (c == '\r' || c == '\n')
00681        continue;
00682 
00683       /* This is called after srec_scan has already been called, so we
00684         ought to know the exact format.  */
00685       BFD_ASSERT (c == 'S');
00686 
00687       if (bfd_bread (hdr, (bfd_size_type) 3, abfd) != 3)
00688        goto error_return;
00689 
00690       BFD_ASSERT (ISHEX (hdr[1]) && ISHEX (hdr[2]));
00691 
00692       bytes = HEX (hdr + 1);
00693 
00694       if (bytes * 2 > bufsize)
00695        {
00696          if (buf != NULL)
00697            free (buf);
00698          buf = bfd_malloc ((bfd_size_type) bytes * 2);
00699          if (buf == NULL)
00700            goto error_return;
00701          bufsize = bytes * 2;
00702        }
00703 
00704       if (bfd_bread (buf, (bfd_size_type) bytes * 2, abfd) != bytes * 2)
00705        goto error_return;
00706 
00707       address = 0;
00708       data = buf;
00709       switch (hdr[0])
00710        {
00711        default:
00712          BFD_ASSERT (sofar == section->size);
00713          if (buf != NULL)
00714            free (buf);
00715          return TRUE;
00716 
00717        case '3':
00718          address = HEX (data);
00719          data += 2;
00720          --bytes;
00721          /* Fall through.  */
00722        case '2':
00723          address = (address << 8) | HEX (data);
00724          data += 2;
00725          --bytes;
00726          /* Fall through.  */
00727        case '1':
00728          address = (address << 8) | HEX (data);
00729          data += 2;
00730          address = (address << 8) | HEX (data);
00731          data += 2;
00732          bytes -= 2;
00733 
00734          if (address != section->vma + sofar)
00735            {
00736              /* We've come to the end of this section.  */
00737              BFD_ASSERT (sofar == section->size);
00738              if (buf != NULL)
00739               free (buf);
00740              return TRUE;
00741            }
00742 
00743          /* Don't consider checksum.  */
00744          --bytes;
00745 
00746          while (bytes-- != 0)
00747            {
00748              contents[sofar] = HEX (data);
00749              data += 2;
00750              ++sofar;
00751            }
00752 
00753          break;
00754        }
00755     }
00756 
00757   if (error)
00758     goto error_return;
00759 
00760   BFD_ASSERT (sofar == section->size);
00761 
00762   if (buf != NULL)
00763     free (buf);
00764 
00765   return TRUE;
00766 
00767  error_return:
00768   if (buf != NULL)
00769     free (buf);
00770   return FALSE;
00771 }
00772 
00773 /* Get the contents of a section in an S-record file.  */
00774 
00775 static bfd_boolean
00776 srec_get_section_contents (bfd *abfd,
00777                         asection *section,
00778                         void * location,
00779                         file_ptr offset,
00780                         bfd_size_type count)
00781 {
00782   if (section->used_by_bfd == NULL)
00783     {
00784       section->used_by_bfd = bfd_alloc (abfd, section->size);
00785       if (section->used_by_bfd == NULL && section->size != 0)
00786        return FALSE;
00787 
00788       if (! srec_read_section (abfd, section, section->used_by_bfd))
00789        return FALSE;
00790     }
00791 
00792   memcpy (location, (bfd_byte *) section->used_by_bfd + offset,
00793          (size_t) count);
00794 
00795   return TRUE;
00796 }
00797 
00798 /* Set the architecture.  We accept an unknown architecture here.  */
00799 
00800 static bfd_boolean
00801 srec_set_arch_mach (bfd *abfd, enum bfd_architecture arch, unsigned long mach)
00802 {
00803   if (arch != bfd_arch_unknown)
00804     return bfd_default_set_arch_mach (abfd, arch, mach);
00805 
00806   abfd->arch_info = & bfd_default_arch_struct;
00807   return TRUE;
00808 }
00809 
00810 /* We have to save up all the Srecords for a splurge before output.  */
00811 
00812 static bfd_boolean
00813 srec_set_section_contents (bfd *abfd,
00814                         sec_ptr section,
00815                         const void * location,
00816                         file_ptr offset,
00817                         bfd_size_type bytes_to_do)
00818 {
00819   tdata_type *tdata = abfd->tdata.srec_data;
00820   srec_data_list_type *entry;
00821 
00822   entry = bfd_alloc (abfd, sizeof (* entry));
00823   if (entry == NULL)
00824     return FALSE;
00825 
00826   if (bytes_to_do
00827       && (section->flags & SEC_ALLOC)
00828       && (section->flags & SEC_LOAD))
00829     {
00830       bfd_byte *data;
00831 
00832       data = bfd_alloc (abfd, bytes_to_do);
00833       if (data == NULL)
00834        return FALSE;
00835       memcpy ((void *) data, location, (size_t) bytes_to_do);
00836 
00837       /* Ff S3Forced is TRUE then always select S3 records,
00838         regardless of the siez of the addresses.  */
00839       if (S3Forced)
00840        tdata->type = 3;
00841       else if ((section->lma + offset + bytes_to_do - 1) <= 0xffff)
00842        ;  /* The default, S1, is OK.  */
00843       else if ((section->lma + offset + bytes_to_do - 1) <= 0xffffff
00844               && tdata->type <= 2)
00845        tdata->type = 2;
00846       else
00847        tdata->type = 3;
00848 
00849       entry->data = data;
00850       entry->where = section->lma + offset;
00851       entry->size = bytes_to_do;
00852 
00853       /* Sort the records by address.  Optimize for the common case of
00854         adding a record to the end of the list.  */
00855       if (tdata->tail != NULL
00856          && entry->where >= tdata->tail->where)
00857        {
00858          tdata->tail->next = entry;
00859          entry->next = NULL;
00860          tdata->tail = entry;
00861        }
00862       else
00863        {
00864          srec_data_list_type **look;
00865 
00866          for (look = &tdata->head;
00867               *look != NULL && (*look)->where < entry->where;
00868               look = &(*look)->next)
00869            ;
00870          entry->next = *look;
00871          *look = entry;
00872          if (entry->next == NULL)
00873            tdata->tail = entry;
00874        }
00875     }
00876   return TRUE;
00877 }
00878 
00879 /* Write a record of type, of the supplied number of bytes. The
00880    supplied bytes and length don't have a checksum. That's worked out
00881    here.  */
00882 
00883 static bfd_boolean
00884 srec_write_record (bfd *abfd,
00885                  unsigned int type,
00886                  bfd_vma address,
00887                  const bfd_byte *data,
00888                  const bfd_byte *end)
00889 {
00890   char buffer[2 * MAXCHUNK + 6];
00891   unsigned int check_sum = 0;
00892   const bfd_byte *src = data;
00893   char *dst = buffer;
00894   char *length;
00895   bfd_size_type wrlen;
00896 
00897   *dst++ = 'S';
00898   *dst++ = '0' + type;
00899 
00900   length = dst;
00901   dst += 2;                 /* Leave room for dst.  */
00902 
00903   switch (type)
00904     {
00905     case 3:
00906     case 7:
00907       TOHEX (dst, (address >> 24), check_sum);
00908       dst += 2;
00909     case 8:
00910     case 2:
00911       TOHEX (dst, (address >> 16), check_sum);
00912       dst += 2;
00913     case 9:
00914     case 1:
00915     case 0:
00916       TOHEX (dst, (address >> 8), check_sum);
00917       dst += 2;
00918       TOHEX (dst, (address), check_sum);
00919       dst += 2;
00920       break;
00921 
00922     }
00923   for (src = data; src < end; src++)
00924     {
00925       TOHEX (dst, *src, check_sum);
00926       dst += 2;
00927     }
00928 
00929   /* Fill in the length.  */
00930   TOHEX (length, (dst - length) / 2, check_sum);
00931   check_sum &= 0xff;
00932   check_sum = 255 - check_sum;
00933   TOHEX (dst, check_sum, check_sum);
00934   dst += 2;
00935 
00936   *dst++ = '\r';
00937   *dst++ = '\n';
00938   wrlen = dst - buffer;
00939 
00940   return bfd_bwrite ((void *) buffer, wrlen, abfd) == wrlen;
00941 }
00942 
00943 static bfd_boolean
00944 srec_write_header (bfd *abfd)
00945 {
00946   unsigned int len = strlen (abfd->filename);
00947 
00948   /* I'll put an arbitrary 40 char limit on header size.  */
00949   if (len > 40)
00950     len = 40;
00951 
00952   return srec_write_record (abfd, 0, (bfd_vma) 0,
00953                          (bfd_byte *) abfd->filename,
00954                          (bfd_byte *) abfd->filename + len);
00955 }
00956 
00957 static bfd_boolean
00958 srec_write_section (bfd *abfd,
00959                   tdata_type *tdata,
00960                   srec_data_list_type *list)
00961 {
00962   unsigned int octets_written = 0;
00963   bfd_byte *location = list->data;
00964 
00965   /* Validate number of data bytes to write.  The srec length byte
00966      counts the address, data and crc bytes.  S1 (tdata->type == 1)
00967      records have two address bytes, S2 (tdata->type == 2) records
00968      have three, and S3 (tdata->type == 3) records have four.
00969      The total length can't exceed 255, and a zero data length will
00970      spin for a long time.  */
00971   if (Chunk == 0)
00972     Chunk = 1;
00973   else if (Chunk > MAXCHUNK - tdata->type - 2)
00974     Chunk = MAXCHUNK - tdata->type - 2;
00975 
00976   while (octets_written < list->size)
00977     {
00978       bfd_vma address;
00979       unsigned int octets_this_chunk = list->size - octets_written;
00980 
00981       if (octets_this_chunk > Chunk)
00982        octets_this_chunk = Chunk;
00983 
00984       address = list->where + octets_written / bfd_octets_per_byte (abfd);
00985 
00986       if (! srec_write_record (abfd,
00987                             tdata->type,
00988                             address,
00989                             location,
00990                             location + octets_this_chunk))
00991        return FALSE;
00992 
00993       octets_written += octets_this_chunk;
00994       location += octets_this_chunk;
00995     }
00996 
00997   return TRUE;
00998 }
00999 
01000 static bfd_boolean
01001 srec_write_terminator (bfd *abfd, tdata_type *tdata)
01002 {
01003   return srec_write_record (abfd, 10 - tdata->type,
01004                          abfd->start_address, NULL, NULL);
01005 }
01006 
01007 static bfd_boolean
01008 srec_write_symbols (bfd *abfd)
01009 {
01010   /* Dump out the symbols of a bfd.  */
01011   int i;
01012   int count = bfd_get_symcount (abfd);
01013 
01014   if (count)
01015     {
01016       bfd_size_type len;
01017       asymbol **table = bfd_get_outsymbols (abfd);
01018 
01019       len = strlen (abfd->filename);
01020       if (bfd_bwrite ("$$ ", (bfd_size_type) 3, abfd) != 3
01021          || bfd_bwrite (abfd->filename, len, abfd) != len
01022          || bfd_bwrite ("\r\n", (bfd_size_type) 2, abfd) != 2)
01023        return FALSE;
01024 
01025       for (i = 0; i < count; i++)
01026        {
01027          asymbol *s = table[i];
01028          if (! bfd_is_local_label (abfd, s)
01029              && (s->flags & BSF_DEBUGGING) == 0)
01030            {
01031              /* Just dump out non debug symbols.  */
01032              char buf[43], *p;
01033 
01034              len = strlen (s->name);
01035              if (bfd_bwrite ("  ", (bfd_size_type) 2, abfd) != 2
01036                 || bfd_bwrite (s->name, len, abfd) != len)
01037               return FALSE;
01038 
01039              sprintf_vma (buf + 2, (s->value
01040                                  + s->section->output_section->lma
01041                                  + s->section->output_offset));
01042              p = buf + 2;
01043              while (p[0] == '0' && p[1] != 0)
01044               p++;
01045              len = strlen (p);
01046              p[len] = '\r';
01047              p[len + 1] = '\n';
01048              *--p = '$';
01049              *--p = ' ';
01050              len += 4;
01051              if (bfd_bwrite (p, len, abfd) != len)
01052               return FALSE;
01053            }
01054        }
01055       if (bfd_bwrite ("$$ \r\n", (bfd_size_type) 5, abfd) != 5)
01056        return FALSE;
01057     }
01058 
01059   return TRUE;
01060 }
01061 
01062 static bfd_boolean
01063 internal_srec_write_object_contents (bfd *abfd, int symbols)
01064 {
01065   tdata_type *tdata = abfd->tdata.srec_data;
01066   srec_data_list_type *list;
01067 
01068   if (symbols)
01069     {
01070       if (! srec_write_symbols (abfd))
01071        return FALSE;
01072     }
01073 
01074   if (! srec_write_header (abfd))
01075     return FALSE;
01076 
01077   /* Now wander though all the sections provided and output them.  */
01078   list = tdata->head;
01079 
01080   while (list != (srec_data_list_type *) NULL)
01081     {
01082       if (! srec_write_section (abfd, tdata, list))
01083        return FALSE;
01084       list = list->next;
01085     }
01086   return srec_write_terminator (abfd, tdata);
01087 }
01088 
01089 static bfd_boolean
01090 srec_write_object_contents (bfd *abfd)
01091 {
01092   return internal_srec_write_object_contents (abfd, 0);
01093 }
01094 
01095 static bfd_boolean
01096 symbolsrec_write_object_contents (bfd *abfd)
01097 {
01098   return internal_srec_write_object_contents (abfd, 1);
01099 }
01100 
01101 static int
01102 srec_sizeof_headers (bfd *abfd ATTRIBUTE_UNUSED,
01103                    struct bfd_link_info *info ATTRIBUTE_UNUSED)
01104 {
01105   return 0;
01106 }
01107 
01108 /* Return the amount of memory needed to read the symbol table.  */
01109 
01110 static long
01111 srec_get_symtab_upper_bound (bfd *abfd)
01112 {
01113   return (bfd_get_symcount (abfd) + 1) * sizeof (asymbol *);
01114 }
01115 
01116 /* Return the symbol table.  */
01117 
01118 static long
01119 srec_canonicalize_symtab (bfd *abfd, asymbol **alocation)
01120 {
01121   bfd_size_type symcount = bfd_get_symcount (abfd);
01122   asymbol *csymbols;
01123   unsigned int i;
01124 
01125   csymbols = abfd->tdata.srec_data->csymbols;
01126   if (csymbols == NULL)
01127     {
01128       asymbol *c;
01129       struct srec_symbol *s;
01130 
01131       csymbols = bfd_alloc (abfd, symcount * sizeof (asymbol));
01132       if (csymbols == NULL && symcount != 0)
01133        return 0;
01134       abfd->tdata.srec_data->csymbols = csymbols;
01135 
01136       for (s = abfd->tdata.srec_data->symbols, c = csymbols;
01137           s != NULL;
01138           s = s->next, ++c)
01139        {
01140          c->the_bfd = abfd;
01141          c->name = s->name;
01142          c->value = s->val;
01143          c->flags = BSF_GLOBAL;
01144          c->section = bfd_abs_section_ptr;
01145          c->udata.p = NULL;
01146        }
01147     }
01148 
01149   for (i = 0; i < symcount; i++)
01150     *alocation++ = csymbols++;
01151   *alocation = NULL;
01152 
01153   return symcount;
01154 }
01155 
01156 static void
01157 srec_get_symbol_info (bfd *ignore_abfd ATTRIBUTE_UNUSED,
01158                     asymbol *symbol,
01159                     symbol_info *ret)
01160 {
01161   bfd_symbol_info (symbol, ret);
01162 }
01163 
01164 static void
01165 srec_print_symbol (bfd *abfd,
01166                  void * afile,
01167                  asymbol *symbol,
01168                  bfd_print_symbol_type how)
01169 {
01170   FILE *file = (FILE *) afile;
01171 
01172   switch (how)
01173     {
01174     case bfd_print_symbol_name:
01175       fprintf (file, "%s", symbol->name);
01176       break;
01177     default:
01178       bfd_print_symbol_vandf (abfd, (void *) file, symbol);
01179       fprintf (file, " %-5s %s",
01180               symbol->section->name,
01181               symbol->name);
01182     }
01183 }
01184 
01185 #define       srec_close_and_cleanup                    _bfd_generic_close_and_cleanup
01186 #define srec_bfd_free_cached_info                 _bfd_generic_bfd_free_cached_info
01187 #define srec_new_section_hook                     _bfd_generic_new_section_hook
01188 #define srec_bfd_is_target_special_symbol         ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false)
01189 #define srec_bfd_is_local_label_name              bfd_generic_is_local_label_name
01190 #define srec_get_lineno                           _bfd_nosymbols_get_lineno
01191 #define srec_find_nearest_line                    _bfd_nosymbols_find_nearest_line
01192 #define srec_find_inliner_info                    _bfd_nosymbols_find_inliner_info
01193 #define srec_make_empty_symbol                    _bfd_generic_make_empty_symbol
01194 #define srec_bfd_make_debug_symbol                _bfd_nosymbols_bfd_make_debug_symbol
01195 #define srec_read_minisymbols                     _bfd_generic_read_minisymbols
01196 #define srec_minisymbol_to_symbol                 _bfd_generic_minisymbol_to_symbol
01197 #define srec_get_section_contents_in_window       _bfd_generic_get_section_contents_in_window
01198 #define srec_bfd_get_relocated_section_contents   bfd_generic_get_relocated_section_contents
01199 #define srec_bfd_relax_section                    bfd_generic_relax_section
01200 #define srec_bfd_gc_sections                      bfd_generic_gc_sections
01201 #define srec_bfd_merge_sections                   bfd_generic_merge_sections
01202 #define srec_bfd_is_group_section                 bfd_generic_is_group_section
01203 #define srec_bfd_discard_group                    bfd_generic_discard_group
01204 #define srec_section_already_linked               _bfd_generic_section_already_linked
01205 #define srec_bfd_link_hash_table_create           _bfd_generic_link_hash_table_create
01206 #define srec_bfd_link_hash_table_free             _bfd_generic_link_hash_table_free
01207 #define srec_bfd_link_add_symbols                 _bfd_generic_link_add_symbols
01208 #define srec_bfd_link_just_syms                   _bfd_generic_link_just_syms
01209 #define srec_bfd_final_link                       _bfd_generic_final_link
01210 #define srec_bfd_link_split_section               _bfd_generic_link_split_section
01211 
01212 const bfd_target srec_vec =
01213 {
01214   "srec",                   /* Name.  */
01215   bfd_target_srec_flavour,
01216   BFD_ENDIAN_UNKNOWN,              /* Target byte order.  */
01217   BFD_ENDIAN_UNKNOWN,              /* Target headers byte order.  */
01218   (HAS_RELOC | EXEC_P |            /* Object flags.  */
01219    HAS_LINENO | HAS_DEBUG |
01220    HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
01221   (SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS
01222    | SEC_ALLOC | SEC_LOAD | SEC_RELOC),   /* Section flags.  */
01223   0,                        /* Leading underscore.  */
01224   ' ',                      /* AR_pad_char.  */
01225   16,                       /* AR_max_namelen.  */
01226   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
01227   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
01228   bfd_getb16, bfd_getb_signed_16, bfd_putb16,    /* Data.  */
01229   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
01230   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
01231   bfd_getb16, bfd_getb_signed_16, bfd_putb16,    /* Hdrs.  */
01232 
01233   {
01234     _bfd_dummy_target,
01235     srec_object_p,          /* bfd_check_format.  */
01236     _bfd_dummy_target,
01237     _bfd_dummy_target,
01238   },
01239   {
01240     bfd_false,
01241     srec_mkobject,
01242     _bfd_generic_mkarchive,
01243     bfd_false,
01244   },
01245   {                         /* bfd_write_contents.  */
01246     bfd_false,
01247     srec_write_object_contents,
01248     _bfd_write_archive_contents,
01249     bfd_false,
01250   },
01251 
01252   BFD_JUMP_TABLE_GENERIC (srec),
01253   BFD_JUMP_TABLE_COPY (_bfd_generic),
01254   BFD_JUMP_TABLE_CORE (_bfd_nocore),
01255   BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
01256   BFD_JUMP_TABLE_SYMBOLS (srec),
01257   BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
01258   BFD_JUMP_TABLE_WRITE (srec),
01259   BFD_JUMP_TABLE_LINK (srec),
01260   BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
01261 
01262   NULL,
01263 
01264   NULL
01265 };
01266 
01267 const bfd_target symbolsrec_vec =
01268 {
01269   "symbolsrec",                    /* Name.  */
01270   bfd_target_srec_flavour,
01271   BFD_ENDIAN_UNKNOWN,              /* Target byte order.  */
01272   BFD_ENDIAN_UNKNOWN,              /* Target headers byte order.  */
01273   (HAS_RELOC | EXEC_P |            /* Object flags.  */
01274    HAS_LINENO | HAS_DEBUG |
01275    HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
01276   (SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS
01277    | SEC_ALLOC | SEC_LOAD | SEC_RELOC),   /* Section flags.  */
01278   0,                        /* Leading underscore.  */
01279   ' ',                      /* AR_pad_char.  */
01280   16,                       /* AR_max_namelen.  */
01281   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
01282   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
01283   bfd_getb16, bfd_getb_signed_16, bfd_putb16,    /* Data.  */
01284   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
01285   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
01286   bfd_getb16, bfd_getb_signed_16, bfd_putb16,    /* Headers.  */
01287 
01288   {
01289     _bfd_dummy_target,
01290     symbolsrec_object_p,    /* bfd_check_format.  */
01291     _bfd_dummy_target,
01292     _bfd_dummy_target,
01293   },
01294   {
01295     bfd_false,
01296     srec_mkobject,
01297     _bfd_generic_mkarchive,
01298     bfd_false,
01299   },
01300   {                         /* bfd_write_contents.  */
01301     bfd_false,
01302     symbolsrec_write_object_contents,
01303     _bfd_write_archive_contents,
01304     bfd_false,
01305   },
01306 
01307   BFD_JUMP_TABLE_GENERIC (srec),
01308   BFD_JUMP_TABLE_COPY (_bfd_generic),
01309   BFD_JUMP_TABLE_CORE (_bfd_nocore),
01310   BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
01311   BFD_JUMP_TABLE_SYMBOLS (srec),
01312   BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
01313   BFD_JUMP_TABLE_WRITE (srec),
01314   BFD_JUMP_TABLE_LINK (srec),
01315   BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
01316 
01317   NULL,
01318 
01319   NULL
01320 };