xref: /dflybsd-src/contrib/gdb-7/bfd/srec.c (revision ec70266467411565ead9166ad4c1dbb79ff7cd77)
15796c8dcSSimon Schubert /* BFD back-end for s-record objects.
25796c8dcSSimon Schubert    Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
3*a45ae5f8SJohn Marino    2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011
45796c8dcSSimon Schubert    Free Software Foundation, Inc.
55796c8dcSSimon Schubert    Written by Steve Chamberlain of Cygnus Support <sac@cygnus.com>.
65796c8dcSSimon Schubert 
75796c8dcSSimon Schubert    This file is part of BFD, the Binary File Descriptor library.
85796c8dcSSimon Schubert 
95796c8dcSSimon Schubert    This program is free software; you can redistribute it and/or modify
105796c8dcSSimon Schubert    it under the terms of the GNU General Public License as published by
115796c8dcSSimon Schubert    the Free Software Foundation; either version 3 of the License, or
125796c8dcSSimon Schubert    (at your option) any later version.
135796c8dcSSimon Schubert 
145796c8dcSSimon Schubert    This program is distributed in the hope that it will be useful,
155796c8dcSSimon Schubert    but WITHOUT ANY WARRANTY; without even the implied warranty of
165796c8dcSSimon Schubert    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
175796c8dcSSimon Schubert    GNU General Public License for more details.
185796c8dcSSimon Schubert 
195796c8dcSSimon Schubert    You should have received a copy of the GNU General Public License
205796c8dcSSimon Schubert    along with this program; if not, write to the Free Software
215796c8dcSSimon Schubert    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
225796c8dcSSimon Schubert    MA 02110-1301, USA.  */
235796c8dcSSimon Schubert 
245796c8dcSSimon Schubert 
255796c8dcSSimon Schubert /* SUBSECTION
265796c8dcSSimon Schubert 	S-Record handling
275796c8dcSSimon Schubert 
285796c8dcSSimon Schubert    DESCRIPTION
295796c8dcSSimon Schubert 
305796c8dcSSimon Schubert 	Ordinary S-Records cannot hold anything but addresses and
315796c8dcSSimon Schubert 	data, so that's all that we implement.
325796c8dcSSimon Schubert 
335796c8dcSSimon Schubert 	The only interesting thing is that S-Records may come out of
345796c8dcSSimon Schubert 	order and there is no header, so an initial scan is required
355796c8dcSSimon Schubert 	to discover the minimum and maximum addresses used to create
365796c8dcSSimon Schubert 	the vma and size of the only section we create.  We
375796c8dcSSimon Schubert 	arbitrarily call this section ".text".
385796c8dcSSimon Schubert 
395796c8dcSSimon Schubert 	When bfd_get_section_contents is called the file is read
405796c8dcSSimon Schubert 	again, and this time the data is placed into a bfd_alloc'd
415796c8dcSSimon Schubert 	area.
425796c8dcSSimon Schubert 
435796c8dcSSimon Schubert 	Any number of sections may be created for output, we save them
445796c8dcSSimon Schubert 	up and output them when it's time to close the bfd.
455796c8dcSSimon Schubert 
465796c8dcSSimon Schubert 	An s record looks like:
475796c8dcSSimon Schubert 
485796c8dcSSimon Schubert    EXAMPLE
495796c8dcSSimon Schubert 	S<type><length><address><data><checksum>
505796c8dcSSimon Schubert 
515796c8dcSSimon Schubert    DESCRIPTION
525796c8dcSSimon Schubert 	Where
535796c8dcSSimon Schubert 	o length
545796c8dcSSimon Schubert 	is the number of bytes following upto the checksum. Note that
555796c8dcSSimon Schubert 	this is not the number of chars following, since it takes two
565796c8dcSSimon Schubert 	chars to represent a byte.
575796c8dcSSimon Schubert 	o type
585796c8dcSSimon Schubert 	is one of:
595796c8dcSSimon Schubert 	0) header record
605796c8dcSSimon Schubert 	1) two byte address data record
615796c8dcSSimon Schubert 	2) three byte address data record
625796c8dcSSimon Schubert 	3) four byte address data record
635796c8dcSSimon Schubert 	7) four byte address termination record
645796c8dcSSimon Schubert 	8) three byte address termination record
655796c8dcSSimon Schubert 	9) two byte address termination record
665796c8dcSSimon Schubert 
675796c8dcSSimon Schubert 	o address
685796c8dcSSimon Schubert 	is the start address of the data following, or in the case of
695796c8dcSSimon Schubert 	a termination record, the start address of the image
705796c8dcSSimon Schubert 	o data
715796c8dcSSimon Schubert 	is the data.
725796c8dcSSimon Schubert 	o checksum
735796c8dcSSimon Schubert 	is the sum of all the raw byte data in the record, from the length
745796c8dcSSimon Schubert 	upwards, modulo 256 and subtracted from 255.
755796c8dcSSimon Schubert 
765796c8dcSSimon Schubert    SUBSECTION
775796c8dcSSimon Schubert 	Symbol S-Record handling
785796c8dcSSimon Schubert 
795796c8dcSSimon Schubert    DESCRIPTION
805796c8dcSSimon Schubert 	Some ICE equipment understands an addition to the standard
815796c8dcSSimon Schubert 	S-Record format; symbols and their addresses can be sent
825796c8dcSSimon Schubert 	before the data.
835796c8dcSSimon Schubert 
845796c8dcSSimon Schubert 	The format of this is:
855796c8dcSSimon Schubert 	($$ <modulename>
865796c8dcSSimon Schubert 		(<space> <symbol> <address>)*)
875796c8dcSSimon Schubert 	$$
885796c8dcSSimon Schubert 
895796c8dcSSimon Schubert 	so a short symbol table could look like:
905796c8dcSSimon Schubert 
915796c8dcSSimon Schubert    EXAMPLE
925796c8dcSSimon Schubert 	$$ flash.x
935796c8dcSSimon Schubert 	$$ flash.c
945796c8dcSSimon Schubert 	  _port6 $0
955796c8dcSSimon Schubert 	  _delay $4
965796c8dcSSimon Schubert 	  _start $14
975796c8dcSSimon Schubert 	  _etext $8036
985796c8dcSSimon Schubert 	  _edata $8036
995796c8dcSSimon Schubert  	  _end $8036
1005796c8dcSSimon Schubert 	$$
1015796c8dcSSimon Schubert 
1025796c8dcSSimon Schubert    DESCRIPTION
1035796c8dcSSimon Schubert 	We allow symbols to be anywhere in the data stream - the module names
1045796c8dcSSimon Schubert 	are always ignored.  */
1055796c8dcSSimon Schubert 
1065796c8dcSSimon Schubert #include "sysdep.h"
1075796c8dcSSimon Schubert #include "bfd.h"
1085796c8dcSSimon Schubert #include "libbfd.h"
1095796c8dcSSimon Schubert #include "libiberty.h"
1105796c8dcSSimon Schubert #include "safe-ctype.h"
1115796c8dcSSimon Schubert 
1125796c8dcSSimon Schubert 
1135796c8dcSSimon Schubert /* Macros for converting between hex and binary.  */
1145796c8dcSSimon Schubert 
1155796c8dcSSimon Schubert static const char digs[] = "0123456789ABCDEF";
1165796c8dcSSimon Schubert 
1175796c8dcSSimon Schubert #define NIBBLE(x)    hex_value(x)
1185796c8dcSSimon Schubert #define HEX(buffer) ((NIBBLE ((buffer)[0])<<4) + NIBBLE ((buffer)[1]))
1195796c8dcSSimon Schubert #define TOHEX(d, x, ch) \
1205796c8dcSSimon Schubert 	d[1] = digs[(x) & 0xf]; \
1215796c8dcSSimon Schubert 	d[0] = digs[((x)>>4)&0xf]; \
1225796c8dcSSimon Schubert 	ch += ((x) & 0xff);
1235796c8dcSSimon Schubert #define	ISHEX(x)    hex_p(x)
1245796c8dcSSimon Schubert 
1255796c8dcSSimon Schubert /* The maximum number of address+data+crc bytes on a line is FF.  */
1265796c8dcSSimon Schubert #define MAXCHUNK 0xff
1275796c8dcSSimon Schubert 
1285796c8dcSSimon Schubert /* Default size for a CHUNK.  */
1295796c8dcSSimon Schubert #define DEFAULT_CHUNK 16
1305796c8dcSSimon Schubert 
1315796c8dcSSimon Schubert /* The number of data bytes we actually fit onto a line on output.
1325796c8dcSSimon Schubert    This variable can be modified by objcopy's --srec-len parameter.
1335796c8dcSSimon Schubert    For a 0x75 byte record you should set --srec-len=0x70.  */
1345796c8dcSSimon Schubert unsigned int Chunk = DEFAULT_CHUNK;
1355796c8dcSSimon Schubert 
1365796c8dcSSimon Schubert /* The type of srec output (free or forced to S3).
1375796c8dcSSimon Schubert    This variable can be modified by objcopy's --srec-forceS3
1385796c8dcSSimon Schubert    parameter.  */
1395796c8dcSSimon Schubert bfd_boolean S3Forced = FALSE;
1405796c8dcSSimon Schubert 
1415796c8dcSSimon Schubert /* When writing an S-record file, the S-records can not be output as
1425796c8dcSSimon Schubert    they are seen.  This structure is used to hold them in memory.  */
1435796c8dcSSimon Schubert 
1445796c8dcSSimon Schubert struct srec_data_list_struct
1455796c8dcSSimon Schubert {
1465796c8dcSSimon Schubert   struct srec_data_list_struct *next;
1475796c8dcSSimon Schubert   bfd_byte *data;
1485796c8dcSSimon Schubert   bfd_vma where;
1495796c8dcSSimon Schubert   bfd_size_type size;
1505796c8dcSSimon Schubert };
1515796c8dcSSimon Schubert 
1525796c8dcSSimon Schubert typedef struct srec_data_list_struct srec_data_list_type;
1535796c8dcSSimon Schubert 
1545796c8dcSSimon Schubert /* When scanning the S-record file, a linked list of srec_symbol
1555796c8dcSSimon Schubert    structures is built to represent the symbol table (if there is
1565796c8dcSSimon Schubert    one).  */
1575796c8dcSSimon Schubert 
1585796c8dcSSimon Schubert struct srec_symbol
1595796c8dcSSimon Schubert {
1605796c8dcSSimon Schubert   struct srec_symbol *next;
1615796c8dcSSimon Schubert   const char *name;
1625796c8dcSSimon Schubert   bfd_vma val;
1635796c8dcSSimon Schubert };
1645796c8dcSSimon Schubert 
1655796c8dcSSimon Schubert /* The S-record tdata information.  */
1665796c8dcSSimon Schubert 
1675796c8dcSSimon Schubert typedef struct srec_data_struct
1685796c8dcSSimon Schubert   {
1695796c8dcSSimon Schubert     srec_data_list_type *head;
1705796c8dcSSimon Schubert     srec_data_list_type *tail;
1715796c8dcSSimon Schubert     unsigned int type;
1725796c8dcSSimon Schubert     struct srec_symbol *symbols;
1735796c8dcSSimon Schubert     struct srec_symbol *symtail;
1745796c8dcSSimon Schubert     asymbol *csymbols;
1755796c8dcSSimon Schubert   }
1765796c8dcSSimon Schubert tdata_type;
1775796c8dcSSimon Schubert 
1785796c8dcSSimon Schubert /* Initialize by filling in the hex conversion array.  */
1795796c8dcSSimon Schubert 
1805796c8dcSSimon Schubert static void
srec_init(void)1815796c8dcSSimon Schubert srec_init (void)
1825796c8dcSSimon Schubert {
1835796c8dcSSimon Schubert   static bfd_boolean inited = FALSE;
1845796c8dcSSimon Schubert 
1855796c8dcSSimon Schubert   if (! inited)
1865796c8dcSSimon Schubert     {
1875796c8dcSSimon Schubert       inited = TRUE;
1885796c8dcSSimon Schubert       hex_init ();
1895796c8dcSSimon Schubert     }
1905796c8dcSSimon Schubert }
1915796c8dcSSimon Schubert 
1925796c8dcSSimon Schubert /* Set up the S-record tdata information.  */
1935796c8dcSSimon Schubert 
1945796c8dcSSimon Schubert static bfd_boolean
srec_mkobject(bfd * abfd)1955796c8dcSSimon Schubert srec_mkobject (bfd *abfd)
1965796c8dcSSimon Schubert {
1975796c8dcSSimon Schubert   tdata_type *tdata;
1985796c8dcSSimon Schubert 
1995796c8dcSSimon Schubert   srec_init ();
2005796c8dcSSimon Schubert 
2015796c8dcSSimon Schubert   tdata = (tdata_type *) bfd_alloc (abfd, sizeof (tdata_type));
2025796c8dcSSimon Schubert   if (tdata == NULL)
2035796c8dcSSimon Schubert     return FALSE;
2045796c8dcSSimon Schubert 
2055796c8dcSSimon Schubert   abfd->tdata.srec_data = tdata;
2065796c8dcSSimon Schubert   tdata->type = 1;
2075796c8dcSSimon Schubert   tdata->head = NULL;
2085796c8dcSSimon Schubert   tdata->tail = NULL;
2095796c8dcSSimon Schubert   tdata->symbols = NULL;
2105796c8dcSSimon Schubert   tdata->symtail = NULL;
2115796c8dcSSimon Schubert   tdata->csymbols = NULL;
2125796c8dcSSimon Schubert 
2135796c8dcSSimon Schubert   return TRUE;
2145796c8dcSSimon Schubert }
2155796c8dcSSimon Schubert 
2165796c8dcSSimon Schubert /* Read a byte from an S record file.  Set *ERRORPTR if an error
2175796c8dcSSimon Schubert    occurred.  Return EOF on error or end of file.  */
2185796c8dcSSimon Schubert 
2195796c8dcSSimon Schubert static int
srec_get_byte(bfd * abfd,bfd_boolean * errorptr)2205796c8dcSSimon Schubert srec_get_byte (bfd *abfd, bfd_boolean *errorptr)
2215796c8dcSSimon Schubert {
2225796c8dcSSimon Schubert   bfd_byte c;
2235796c8dcSSimon Schubert 
2245796c8dcSSimon Schubert   if (bfd_bread (&c, (bfd_size_type) 1, abfd) != 1)
2255796c8dcSSimon Schubert     {
2265796c8dcSSimon Schubert       if (bfd_get_error () != bfd_error_file_truncated)
2275796c8dcSSimon Schubert 	*errorptr = TRUE;
2285796c8dcSSimon Schubert       return EOF;
2295796c8dcSSimon Schubert     }
2305796c8dcSSimon Schubert 
2315796c8dcSSimon Schubert   return (int) (c & 0xff);
2325796c8dcSSimon Schubert }
2335796c8dcSSimon Schubert 
2345796c8dcSSimon Schubert /* Report a problem in an S record file.  FIXME: This probably should
2355796c8dcSSimon Schubert    not call fprintf, but we really do need some mechanism for printing
2365796c8dcSSimon Schubert    error messages.  */
2375796c8dcSSimon Schubert 
2385796c8dcSSimon Schubert static void
srec_bad_byte(bfd * abfd,unsigned int lineno,int c,bfd_boolean error)2395796c8dcSSimon Schubert srec_bad_byte (bfd *abfd,
2405796c8dcSSimon Schubert 	       unsigned int lineno,
2415796c8dcSSimon Schubert 	       int c,
2425796c8dcSSimon Schubert 	       bfd_boolean error)
2435796c8dcSSimon Schubert {
2445796c8dcSSimon Schubert   if (c == EOF)
2455796c8dcSSimon Schubert     {
2465796c8dcSSimon Schubert       if (! error)
2475796c8dcSSimon Schubert 	bfd_set_error (bfd_error_file_truncated);
2485796c8dcSSimon Schubert     }
2495796c8dcSSimon Schubert   else
2505796c8dcSSimon Schubert     {
2515796c8dcSSimon Schubert       char buf[10];
2525796c8dcSSimon Schubert 
2535796c8dcSSimon Schubert       if (! ISPRINT (c))
2545796c8dcSSimon Schubert 	sprintf (buf, "\\%03o", (unsigned int) c);
2555796c8dcSSimon Schubert       else
2565796c8dcSSimon Schubert 	{
2575796c8dcSSimon Schubert 	  buf[0] = c;
2585796c8dcSSimon Schubert 	  buf[1] = '\0';
2595796c8dcSSimon Schubert 	}
2605796c8dcSSimon Schubert       (*_bfd_error_handler)
2615796c8dcSSimon Schubert 	(_("%B:%d: Unexpected character `%s' in S-record file\n"),
2625796c8dcSSimon Schubert 	 abfd, lineno, buf);
2635796c8dcSSimon Schubert       bfd_set_error (bfd_error_bad_value);
2645796c8dcSSimon Schubert     }
2655796c8dcSSimon Schubert }
2665796c8dcSSimon Schubert 
2675796c8dcSSimon Schubert /* Add a new symbol found in an S-record file.  */
2685796c8dcSSimon Schubert 
2695796c8dcSSimon Schubert static bfd_boolean
srec_new_symbol(bfd * abfd,const char * name,bfd_vma val)2705796c8dcSSimon Schubert srec_new_symbol (bfd *abfd, const char *name, bfd_vma val)
2715796c8dcSSimon Schubert {
2725796c8dcSSimon Schubert   struct srec_symbol *n;
2735796c8dcSSimon Schubert 
2745796c8dcSSimon Schubert   n = (struct srec_symbol *) bfd_alloc (abfd, sizeof (* n));
2755796c8dcSSimon Schubert   if (n == NULL)
2765796c8dcSSimon Schubert     return FALSE;
2775796c8dcSSimon Schubert 
2785796c8dcSSimon Schubert   n->name = name;
2795796c8dcSSimon Schubert   n->val = val;
2805796c8dcSSimon Schubert 
2815796c8dcSSimon Schubert   if (abfd->tdata.srec_data->symbols == NULL)
2825796c8dcSSimon Schubert     abfd->tdata.srec_data->symbols = n;
2835796c8dcSSimon Schubert   else
2845796c8dcSSimon Schubert     abfd->tdata.srec_data->symtail->next = n;
2855796c8dcSSimon Schubert   abfd->tdata.srec_data->symtail = n;
2865796c8dcSSimon Schubert   n->next = NULL;
2875796c8dcSSimon Schubert 
2885796c8dcSSimon Schubert   ++abfd->symcount;
2895796c8dcSSimon Schubert 
2905796c8dcSSimon Schubert   return TRUE;
2915796c8dcSSimon Schubert }
2925796c8dcSSimon Schubert 
2935796c8dcSSimon Schubert /* Read the S record file and turn it into sections.  We create a new
2945796c8dcSSimon Schubert    section for each contiguous set of bytes.  */
2955796c8dcSSimon Schubert 
2965796c8dcSSimon Schubert static bfd_boolean
srec_scan(bfd * abfd)2975796c8dcSSimon Schubert srec_scan (bfd *abfd)
2985796c8dcSSimon Schubert {
2995796c8dcSSimon Schubert   int c;
3005796c8dcSSimon Schubert   unsigned int lineno = 1;
3015796c8dcSSimon Schubert   bfd_boolean error = FALSE;
3025796c8dcSSimon Schubert   bfd_byte *buf = NULL;
3035796c8dcSSimon Schubert   size_t bufsize = 0;
3045796c8dcSSimon Schubert   asection *sec = NULL;
3055796c8dcSSimon Schubert   char *symbuf = NULL;
3065796c8dcSSimon Schubert 
3075796c8dcSSimon Schubert   if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0)
3085796c8dcSSimon Schubert     goto error_return;
3095796c8dcSSimon Schubert 
3105796c8dcSSimon Schubert   while ((c = srec_get_byte (abfd, &error)) != EOF)
3115796c8dcSSimon Schubert     {
3125796c8dcSSimon Schubert       /* We only build sections from contiguous S-records, so if this
3135796c8dcSSimon Schubert 	 is not an S-record, then stop building a section.  */
3145796c8dcSSimon Schubert       if (c != 'S' && c != '\r' && c != '\n')
3155796c8dcSSimon Schubert 	sec = NULL;
3165796c8dcSSimon Schubert 
3175796c8dcSSimon Schubert       switch (c)
3185796c8dcSSimon Schubert 	{
3195796c8dcSSimon Schubert 	default:
3205796c8dcSSimon Schubert 	  srec_bad_byte (abfd, lineno, c, error);
3215796c8dcSSimon Schubert 	  goto error_return;
3225796c8dcSSimon Schubert 
3235796c8dcSSimon Schubert 	case '\n':
3245796c8dcSSimon Schubert 	  ++lineno;
3255796c8dcSSimon Schubert 	  break;
3265796c8dcSSimon Schubert 
3275796c8dcSSimon Schubert 	case '\r':
3285796c8dcSSimon Schubert 	  break;
3295796c8dcSSimon Schubert 
3305796c8dcSSimon Schubert 	case '$':
3315796c8dcSSimon Schubert 	  /* Starting a module name, which we ignore.  */
3325796c8dcSSimon Schubert 	  while ((c = srec_get_byte (abfd, &error)) != '\n'
3335796c8dcSSimon Schubert 		 && c != EOF)
3345796c8dcSSimon Schubert 	    ;
3355796c8dcSSimon Schubert 	  if (c == EOF)
3365796c8dcSSimon Schubert 	    {
3375796c8dcSSimon Schubert 	      srec_bad_byte (abfd, lineno, c, error);
3385796c8dcSSimon Schubert 	      goto error_return;
3395796c8dcSSimon Schubert 	    }
3405796c8dcSSimon Schubert 
3415796c8dcSSimon Schubert 	  ++lineno;
3425796c8dcSSimon Schubert 	  break;
3435796c8dcSSimon Schubert 
3445796c8dcSSimon Schubert 	case ' ':
3455796c8dcSSimon Schubert 	  do
3465796c8dcSSimon Schubert 	    {
3475796c8dcSSimon Schubert 	      bfd_size_type alc;
3485796c8dcSSimon Schubert 	      char *p, *symname;
3495796c8dcSSimon Schubert 	      bfd_vma symval;
3505796c8dcSSimon Schubert 
3515796c8dcSSimon Schubert 	      /* Starting a symbol definition.  */
3525796c8dcSSimon Schubert 	      while ((c = srec_get_byte (abfd, &error)) != EOF
3535796c8dcSSimon Schubert 		     && (c == ' ' || c == '\t'))
3545796c8dcSSimon Schubert 		;
3555796c8dcSSimon Schubert 
3565796c8dcSSimon Schubert 	      if (c == '\n' || c == '\r')
3575796c8dcSSimon Schubert 		break;
3585796c8dcSSimon Schubert 
3595796c8dcSSimon Schubert 	      if (c == EOF)
3605796c8dcSSimon Schubert 		{
3615796c8dcSSimon Schubert 		  srec_bad_byte (abfd, lineno, c, error);
3625796c8dcSSimon Schubert 		  goto error_return;
3635796c8dcSSimon Schubert 		}
3645796c8dcSSimon Schubert 
3655796c8dcSSimon Schubert 	      alc = 10;
3665796c8dcSSimon Schubert 	      symbuf = (char *) bfd_malloc (alc + 1);
3675796c8dcSSimon Schubert 	      if (symbuf == NULL)
3685796c8dcSSimon Schubert 		goto error_return;
3695796c8dcSSimon Schubert 
3705796c8dcSSimon Schubert 	      p = symbuf;
3715796c8dcSSimon Schubert 
3725796c8dcSSimon Schubert 	      *p++ = c;
3735796c8dcSSimon Schubert 	      while ((c = srec_get_byte (abfd, &error)) != EOF
3745796c8dcSSimon Schubert 		     && ! ISSPACE (c))
3755796c8dcSSimon Schubert 		{
3765796c8dcSSimon Schubert 		  if ((bfd_size_type) (p - symbuf) >= alc)
3775796c8dcSSimon Schubert 		    {
3785796c8dcSSimon Schubert 		      char *n;
3795796c8dcSSimon Schubert 
3805796c8dcSSimon Schubert 		      alc *= 2;
3815796c8dcSSimon Schubert 		      n = (char *) bfd_realloc (symbuf, alc + 1);
3825796c8dcSSimon Schubert 		      if (n == NULL)
3835796c8dcSSimon Schubert 			goto error_return;
3845796c8dcSSimon Schubert 		      p = n + (p - symbuf);
3855796c8dcSSimon Schubert 		      symbuf = n;
3865796c8dcSSimon Schubert 		    }
3875796c8dcSSimon Schubert 
3885796c8dcSSimon Schubert 		  *p++ = c;
3895796c8dcSSimon Schubert 		}
3905796c8dcSSimon Schubert 
3915796c8dcSSimon Schubert 	      if (c == EOF)
3925796c8dcSSimon Schubert 		{
3935796c8dcSSimon Schubert 		  srec_bad_byte (abfd, lineno, c, error);
3945796c8dcSSimon Schubert 		  goto error_return;
3955796c8dcSSimon Schubert 		}
3965796c8dcSSimon Schubert 
3975796c8dcSSimon Schubert 	      *p++ = '\0';
3985796c8dcSSimon Schubert 	      symname = (char *) bfd_alloc (abfd, (bfd_size_type) (p - symbuf));
3995796c8dcSSimon Schubert 	      if (symname == NULL)
4005796c8dcSSimon Schubert 		goto error_return;
4015796c8dcSSimon Schubert 	      strcpy (symname, symbuf);
4025796c8dcSSimon Schubert 	      free (symbuf);
4035796c8dcSSimon Schubert 	      symbuf = NULL;
4045796c8dcSSimon Schubert 
4055796c8dcSSimon Schubert 	      while ((c = srec_get_byte (abfd, &error)) != EOF
4065796c8dcSSimon Schubert 		     && (c == ' ' || c == '\t'))
4075796c8dcSSimon Schubert 		;
4085796c8dcSSimon Schubert 	      if (c == EOF)
4095796c8dcSSimon Schubert 		{
4105796c8dcSSimon Schubert 		  srec_bad_byte (abfd, lineno, c, error);
4115796c8dcSSimon Schubert 		  goto error_return;
4125796c8dcSSimon Schubert 		}
4135796c8dcSSimon Schubert 
4145796c8dcSSimon Schubert 	      /* Skip a dollar sign before the hex value.  */
4155796c8dcSSimon Schubert 	      if (c == '$')
4165796c8dcSSimon Schubert 		{
4175796c8dcSSimon Schubert 		  c = srec_get_byte (abfd, &error);
4185796c8dcSSimon Schubert 		  if (c == EOF)
4195796c8dcSSimon Schubert 		    {
4205796c8dcSSimon Schubert 		      srec_bad_byte (abfd, lineno, c, error);
4215796c8dcSSimon Schubert 		      goto error_return;
4225796c8dcSSimon Schubert 		    }
4235796c8dcSSimon Schubert 		}
4245796c8dcSSimon Schubert 
4255796c8dcSSimon Schubert 	      symval = 0;
4265796c8dcSSimon Schubert 	      while (ISHEX (c))
4275796c8dcSSimon Schubert 		{
4285796c8dcSSimon Schubert 		  symval <<= 4;
4295796c8dcSSimon Schubert 		  symval += NIBBLE (c);
4305796c8dcSSimon Schubert 		  c = srec_get_byte (abfd, &error);
4315796c8dcSSimon Schubert 		  if (c == EOF)
4325796c8dcSSimon Schubert 		    {
4335796c8dcSSimon Schubert 		      srec_bad_byte (abfd, lineno, c, error);
4345796c8dcSSimon Schubert 		      goto error_return;
4355796c8dcSSimon Schubert 		    }
4365796c8dcSSimon Schubert 		}
4375796c8dcSSimon Schubert 
4385796c8dcSSimon Schubert 	      if (! srec_new_symbol (abfd, symname, symval))
4395796c8dcSSimon Schubert 		goto error_return;
4405796c8dcSSimon Schubert 	    }
4415796c8dcSSimon Schubert 	  while (c == ' ' || c == '\t')
4425796c8dcSSimon Schubert 	    ;
4435796c8dcSSimon Schubert 
4445796c8dcSSimon Schubert 	  if (c == '\n')
4455796c8dcSSimon Schubert 	    ++lineno;
4465796c8dcSSimon Schubert 	  else if (c != '\r')
4475796c8dcSSimon Schubert 	    {
4485796c8dcSSimon Schubert 	      srec_bad_byte (abfd, lineno, c, error);
4495796c8dcSSimon Schubert 	      goto error_return;
4505796c8dcSSimon Schubert 	    }
4515796c8dcSSimon Schubert 
4525796c8dcSSimon Schubert 	  break;
4535796c8dcSSimon Schubert 
4545796c8dcSSimon Schubert 	case 'S':
4555796c8dcSSimon Schubert 	  {
4565796c8dcSSimon Schubert 	    file_ptr pos;
4575796c8dcSSimon Schubert 	    char hdr[3];
4585796c8dcSSimon Schubert 	    unsigned int bytes;
4595796c8dcSSimon Schubert 	    bfd_vma address;
4605796c8dcSSimon Schubert 	    bfd_byte *data;
4615796c8dcSSimon Schubert 	    unsigned char check_sum;
4625796c8dcSSimon Schubert 
4635796c8dcSSimon Schubert 	    /* Starting an S-record.  */
4645796c8dcSSimon Schubert 
4655796c8dcSSimon Schubert 	    pos = bfd_tell (abfd) - 1;
4665796c8dcSSimon Schubert 
4675796c8dcSSimon Schubert 	    if (bfd_bread (hdr, (bfd_size_type) 3, abfd) != 3)
4685796c8dcSSimon Schubert 	      goto error_return;
4695796c8dcSSimon Schubert 
4705796c8dcSSimon Schubert 	    if (! ISHEX (hdr[1]) || ! ISHEX (hdr[2]))
4715796c8dcSSimon Schubert 	      {
4725796c8dcSSimon Schubert 		if (! ISHEX (hdr[1]))
4735796c8dcSSimon Schubert 		  c = hdr[1];
4745796c8dcSSimon Schubert 		else
4755796c8dcSSimon Schubert 		  c = hdr[2];
4765796c8dcSSimon Schubert 		srec_bad_byte (abfd, lineno, c, error);
4775796c8dcSSimon Schubert 		goto error_return;
4785796c8dcSSimon Schubert 	      }
4795796c8dcSSimon Schubert 
4805796c8dcSSimon Schubert 	    check_sum = bytes = HEX (hdr + 1);
4815796c8dcSSimon Schubert 	    if (bytes * 2 > bufsize)
4825796c8dcSSimon Schubert 	      {
4835796c8dcSSimon Schubert 		if (buf != NULL)
4845796c8dcSSimon Schubert 		  free (buf);
4855796c8dcSSimon Schubert 		buf = (bfd_byte *) bfd_malloc ((bfd_size_type) bytes * 2);
4865796c8dcSSimon Schubert 		if (buf == NULL)
4875796c8dcSSimon Schubert 		  goto error_return;
4885796c8dcSSimon Schubert 		bufsize = bytes * 2;
4895796c8dcSSimon Schubert 	      }
4905796c8dcSSimon Schubert 
4915796c8dcSSimon Schubert 	    if (bfd_bread (buf, (bfd_size_type) bytes * 2, abfd) != bytes * 2)
4925796c8dcSSimon Schubert 	      goto error_return;
4935796c8dcSSimon Schubert 
4945796c8dcSSimon Schubert 	    /* Ignore the checksum byte.  */
4955796c8dcSSimon Schubert 	    --bytes;
4965796c8dcSSimon Schubert 
4975796c8dcSSimon Schubert 	    address = 0;
4985796c8dcSSimon Schubert 	    data = buf;
4995796c8dcSSimon Schubert 	    switch (hdr[0])
5005796c8dcSSimon Schubert 	      {
5015796c8dcSSimon Schubert 	      case '0':
5025796c8dcSSimon Schubert 	      case '5':
5035796c8dcSSimon Schubert 		/* Prologue--ignore the file name, but stop building a
5045796c8dcSSimon Schubert 		   section at this point.  */
5055796c8dcSSimon Schubert 		sec = NULL;
5065796c8dcSSimon Schubert 		break;
5075796c8dcSSimon Schubert 
5085796c8dcSSimon Schubert 	      case '3':
5095796c8dcSSimon Schubert 		check_sum += HEX (data);
5105796c8dcSSimon Schubert 		address = HEX (data);
5115796c8dcSSimon Schubert 		data += 2;
5125796c8dcSSimon Schubert 		--bytes;
5135796c8dcSSimon Schubert 		/* Fall through.  */
5145796c8dcSSimon Schubert 	      case '2':
5155796c8dcSSimon Schubert 		check_sum += HEX (data);
5165796c8dcSSimon Schubert 		address = (address << 8) | HEX (data);
5175796c8dcSSimon Schubert 		data += 2;
5185796c8dcSSimon Schubert 		--bytes;
5195796c8dcSSimon Schubert 		/* Fall through.  */
5205796c8dcSSimon Schubert 	      case '1':
5215796c8dcSSimon Schubert 		check_sum += HEX (data);
5225796c8dcSSimon Schubert 		address = (address << 8) | HEX (data);
5235796c8dcSSimon Schubert 		data += 2;
5245796c8dcSSimon Schubert 		check_sum += HEX (data);
5255796c8dcSSimon Schubert 		address = (address << 8) | HEX (data);
5265796c8dcSSimon Schubert 		data += 2;
5275796c8dcSSimon Schubert 		bytes -= 2;
5285796c8dcSSimon Schubert 
5295796c8dcSSimon Schubert 		if (sec != NULL
5305796c8dcSSimon Schubert 		    && sec->vma + sec->size == address)
5315796c8dcSSimon Schubert 		  {
5325796c8dcSSimon Schubert 		    /* This data goes at the end of the section we are
5335796c8dcSSimon Schubert 		       currently building.  */
5345796c8dcSSimon Schubert 		    sec->size += bytes;
5355796c8dcSSimon Schubert 		  }
5365796c8dcSSimon Schubert 		else
5375796c8dcSSimon Schubert 		  {
5385796c8dcSSimon Schubert 		    char secbuf[20];
5395796c8dcSSimon Schubert 		    char *secname;
5405796c8dcSSimon Schubert 		    bfd_size_type amt;
5415796c8dcSSimon Schubert 		    flagword flags;
5425796c8dcSSimon Schubert 
5435796c8dcSSimon Schubert 		    sprintf (secbuf, ".sec%d", bfd_count_sections (abfd) + 1);
5445796c8dcSSimon Schubert 		    amt = strlen (secbuf) + 1;
5455796c8dcSSimon Schubert 		    secname = (char *) bfd_alloc (abfd, amt);
5465796c8dcSSimon Schubert 		    strcpy (secname, secbuf);
5475796c8dcSSimon Schubert 		    flags = SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC;
5485796c8dcSSimon Schubert 		    sec = bfd_make_section_with_flags (abfd, secname, flags);
5495796c8dcSSimon Schubert 		    if (sec == NULL)
5505796c8dcSSimon Schubert 		      goto error_return;
5515796c8dcSSimon Schubert 		    sec->vma = address;
5525796c8dcSSimon Schubert 		    sec->lma = address;
5535796c8dcSSimon Schubert 		    sec->size = bytes;
5545796c8dcSSimon Schubert 		    sec->filepos = pos;
5555796c8dcSSimon Schubert 		  }
5565796c8dcSSimon Schubert 
5575796c8dcSSimon Schubert 		while (bytes > 0)
5585796c8dcSSimon Schubert 		  {
5595796c8dcSSimon Schubert 		    check_sum += HEX (data);
5605796c8dcSSimon Schubert 		    data += 2;
5615796c8dcSSimon Schubert 		    bytes--;
5625796c8dcSSimon Schubert 		  }
5635796c8dcSSimon Schubert 		check_sum = 255 - (check_sum & 0xff);
5645796c8dcSSimon Schubert 		if (check_sum != HEX (data))
5655796c8dcSSimon Schubert 		  {
5665796c8dcSSimon Schubert 		    (*_bfd_error_handler)
5675796c8dcSSimon Schubert 		      (_("%B:%d: Bad checksum in S-record file\n"),
5685796c8dcSSimon Schubert 		       abfd, lineno);
5695796c8dcSSimon Schubert 		    bfd_set_error (bfd_error_bad_value);
5705796c8dcSSimon Schubert 		    goto error_return;
5715796c8dcSSimon Schubert 		  }
5725796c8dcSSimon Schubert 
5735796c8dcSSimon Schubert 		break;
5745796c8dcSSimon Schubert 
5755796c8dcSSimon Schubert 	      case '7':
5765796c8dcSSimon Schubert 		check_sum += HEX (data);
5775796c8dcSSimon Schubert 		address = HEX (data);
5785796c8dcSSimon Schubert 		data += 2;
5795796c8dcSSimon Schubert 		/* Fall through.  */
5805796c8dcSSimon Schubert 	      case '8':
5815796c8dcSSimon Schubert 		check_sum += HEX (data);
5825796c8dcSSimon Schubert 		address = (address << 8) | HEX (data);
5835796c8dcSSimon Schubert 		data += 2;
5845796c8dcSSimon Schubert 		/* Fall through.  */
5855796c8dcSSimon Schubert 	      case '9':
5865796c8dcSSimon Schubert 		check_sum += HEX (data);
5875796c8dcSSimon Schubert 		address = (address << 8) | HEX (data);
5885796c8dcSSimon Schubert 		data += 2;
5895796c8dcSSimon Schubert 		check_sum += HEX (data);
5905796c8dcSSimon Schubert 		address = (address << 8) | HEX (data);
5915796c8dcSSimon Schubert 		data += 2;
5925796c8dcSSimon Schubert 
5935796c8dcSSimon Schubert 		/* This is a termination record.  */
5945796c8dcSSimon Schubert 		abfd->start_address = address;
5955796c8dcSSimon Schubert 
5965796c8dcSSimon Schubert 		check_sum = 255 - (check_sum & 0xff);
5975796c8dcSSimon Schubert 		if (check_sum != HEX (data))
5985796c8dcSSimon Schubert 		  {
5995796c8dcSSimon Schubert 		    (*_bfd_error_handler)
6005796c8dcSSimon Schubert 		      (_("%B:%d: Bad checksum in S-record file\n"),
6015796c8dcSSimon Schubert 		       abfd, lineno);
6025796c8dcSSimon Schubert 		    bfd_set_error (bfd_error_bad_value);
6035796c8dcSSimon Schubert 		    goto error_return;
6045796c8dcSSimon Schubert 		  }
6055796c8dcSSimon Schubert 
6065796c8dcSSimon Schubert 		if (buf != NULL)
6075796c8dcSSimon Schubert 		  free (buf);
6085796c8dcSSimon Schubert 
6095796c8dcSSimon Schubert 		return TRUE;
6105796c8dcSSimon Schubert 	      }
6115796c8dcSSimon Schubert 	  }
6125796c8dcSSimon Schubert 	  break;
6135796c8dcSSimon Schubert 	}
6145796c8dcSSimon Schubert     }
6155796c8dcSSimon Schubert 
6165796c8dcSSimon Schubert   if (error)
6175796c8dcSSimon Schubert     goto error_return;
6185796c8dcSSimon Schubert 
6195796c8dcSSimon Schubert   if (buf != NULL)
6205796c8dcSSimon Schubert     free (buf);
6215796c8dcSSimon Schubert 
6225796c8dcSSimon Schubert   return TRUE;
6235796c8dcSSimon Schubert 
6245796c8dcSSimon Schubert  error_return:
6255796c8dcSSimon Schubert   if (symbuf != NULL)
6265796c8dcSSimon Schubert     free (symbuf);
6275796c8dcSSimon Schubert   if (buf != NULL)
6285796c8dcSSimon Schubert     free (buf);
6295796c8dcSSimon Schubert   return FALSE;
6305796c8dcSSimon Schubert }
6315796c8dcSSimon Schubert 
6325796c8dcSSimon Schubert /* Check whether an existing file is an S-record file.  */
6335796c8dcSSimon Schubert 
6345796c8dcSSimon Schubert static const bfd_target *
srec_object_p(bfd * abfd)6355796c8dcSSimon Schubert srec_object_p (bfd *abfd)
6365796c8dcSSimon Schubert {
6375796c8dcSSimon Schubert   void * tdata_save;
6385796c8dcSSimon Schubert   bfd_byte b[4];
6395796c8dcSSimon Schubert 
6405796c8dcSSimon Schubert   srec_init ();
6415796c8dcSSimon Schubert 
6425796c8dcSSimon Schubert   if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0
6435796c8dcSSimon Schubert       || bfd_bread (b, (bfd_size_type) 4, abfd) != 4)
6445796c8dcSSimon Schubert     return NULL;
6455796c8dcSSimon Schubert 
6465796c8dcSSimon Schubert   if (b[0] != 'S' || !ISHEX (b[1]) || !ISHEX (b[2]) || !ISHEX (b[3]))
6475796c8dcSSimon Schubert     {
6485796c8dcSSimon Schubert       bfd_set_error (bfd_error_wrong_format);
6495796c8dcSSimon Schubert       return NULL;
6505796c8dcSSimon Schubert     }
6515796c8dcSSimon Schubert 
6525796c8dcSSimon Schubert   tdata_save = abfd->tdata.any;
6535796c8dcSSimon Schubert   if (! srec_mkobject (abfd) || ! srec_scan (abfd))
6545796c8dcSSimon Schubert     {
6555796c8dcSSimon Schubert       if (abfd->tdata.any != tdata_save && abfd->tdata.any != NULL)
6565796c8dcSSimon Schubert 	bfd_release (abfd, abfd->tdata.any);
6575796c8dcSSimon Schubert       abfd->tdata.any = tdata_save;
6585796c8dcSSimon Schubert       return NULL;
6595796c8dcSSimon Schubert     }
6605796c8dcSSimon Schubert 
6615796c8dcSSimon Schubert   if (abfd->symcount > 0)
6625796c8dcSSimon Schubert     abfd->flags |= HAS_SYMS;
6635796c8dcSSimon Schubert 
6645796c8dcSSimon Schubert   return abfd->xvec;
6655796c8dcSSimon Schubert }
6665796c8dcSSimon Schubert 
6675796c8dcSSimon Schubert /* Check whether an existing file is an S-record file with symbols.  */
6685796c8dcSSimon Schubert 
6695796c8dcSSimon Schubert static const bfd_target *
symbolsrec_object_p(bfd * abfd)6705796c8dcSSimon Schubert symbolsrec_object_p (bfd *abfd)
6715796c8dcSSimon Schubert {
6725796c8dcSSimon Schubert   void * tdata_save;
6735796c8dcSSimon Schubert   char b[2];
6745796c8dcSSimon Schubert 
6755796c8dcSSimon Schubert   srec_init ();
6765796c8dcSSimon Schubert 
6775796c8dcSSimon Schubert   if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0
6785796c8dcSSimon Schubert       || bfd_bread (b, (bfd_size_type) 2, abfd) != 2)
6795796c8dcSSimon Schubert     return NULL;
6805796c8dcSSimon Schubert 
6815796c8dcSSimon Schubert   if (b[0] != '$' || b[1] != '$')
6825796c8dcSSimon Schubert     {
6835796c8dcSSimon Schubert       bfd_set_error (bfd_error_wrong_format);
6845796c8dcSSimon Schubert       return NULL;
6855796c8dcSSimon Schubert     }
6865796c8dcSSimon Schubert 
6875796c8dcSSimon Schubert   tdata_save = abfd->tdata.any;
6885796c8dcSSimon Schubert   if (! srec_mkobject (abfd) || ! srec_scan (abfd))
6895796c8dcSSimon Schubert     {
6905796c8dcSSimon Schubert       if (abfd->tdata.any != tdata_save && abfd->tdata.any != NULL)
6915796c8dcSSimon Schubert 	bfd_release (abfd, abfd->tdata.any);
6925796c8dcSSimon Schubert       abfd->tdata.any = tdata_save;
6935796c8dcSSimon Schubert       return NULL;
6945796c8dcSSimon Schubert     }
6955796c8dcSSimon Schubert 
6965796c8dcSSimon Schubert   if (abfd->symcount > 0)
6975796c8dcSSimon Schubert     abfd->flags |= HAS_SYMS;
6985796c8dcSSimon Schubert 
6995796c8dcSSimon Schubert   return abfd->xvec;
7005796c8dcSSimon Schubert }
7015796c8dcSSimon Schubert 
7025796c8dcSSimon Schubert /* Read in the contents of a section in an S-record file.  */
7035796c8dcSSimon Schubert 
7045796c8dcSSimon Schubert static bfd_boolean
srec_read_section(bfd * abfd,asection * section,bfd_byte * contents)7055796c8dcSSimon Schubert srec_read_section (bfd *abfd, asection *section, bfd_byte *contents)
7065796c8dcSSimon Schubert {
7075796c8dcSSimon Schubert   int c;
7085796c8dcSSimon Schubert   bfd_size_type sofar = 0;
7095796c8dcSSimon Schubert   bfd_boolean error = FALSE;
7105796c8dcSSimon Schubert   bfd_byte *buf = NULL;
7115796c8dcSSimon Schubert   size_t bufsize = 0;
7125796c8dcSSimon Schubert 
7135796c8dcSSimon Schubert   if (bfd_seek (abfd, section->filepos, SEEK_SET) != 0)
7145796c8dcSSimon Schubert     goto error_return;
7155796c8dcSSimon Schubert 
7165796c8dcSSimon Schubert   while ((c = srec_get_byte (abfd, &error)) != EOF)
7175796c8dcSSimon Schubert     {
7185796c8dcSSimon Schubert       bfd_byte hdr[3];
7195796c8dcSSimon Schubert       unsigned int bytes;
7205796c8dcSSimon Schubert       bfd_vma address;
7215796c8dcSSimon Schubert       bfd_byte *data;
7225796c8dcSSimon Schubert 
7235796c8dcSSimon Schubert       if (c == '\r' || c == '\n')
7245796c8dcSSimon Schubert 	continue;
7255796c8dcSSimon Schubert 
7265796c8dcSSimon Schubert       /* This is called after srec_scan has already been called, so we
7275796c8dcSSimon Schubert 	 ought to know the exact format.  */
7285796c8dcSSimon Schubert       BFD_ASSERT (c == 'S');
7295796c8dcSSimon Schubert 
7305796c8dcSSimon Schubert       if (bfd_bread (hdr, (bfd_size_type) 3, abfd) != 3)
7315796c8dcSSimon Schubert 	goto error_return;
7325796c8dcSSimon Schubert 
7335796c8dcSSimon Schubert       BFD_ASSERT (ISHEX (hdr[1]) && ISHEX (hdr[2]));
7345796c8dcSSimon Schubert 
7355796c8dcSSimon Schubert       bytes = HEX (hdr + 1);
7365796c8dcSSimon Schubert 
7375796c8dcSSimon Schubert       if (bytes * 2 > bufsize)
7385796c8dcSSimon Schubert 	{
7395796c8dcSSimon Schubert 	  if (buf != NULL)
7405796c8dcSSimon Schubert 	    free (buf);
7415796c8dcSSimon Schubert 	  buf = (bfd_byte *) bfd_malloc ((bfd_size_type) bytes * 2);
7425796c8dcSSimon Schubert 	  if (buf == NULL)
7435796c8dcSSimon Schubert 	    goto error_return;
7445796c8dcSSimon Schubert 	  bufsize = bytes * 2;
7455796c8dcSSimon Schubert 	}
7465796c8dcSSimon Schubert 
7475796c8dcSSimon Schubert       if (bfd_bread (buf, (bfd_size_type) bytes * 2, abfd) != bytes * 2)
7485796c8dcSSimon Schubert 	goto error_return;
7495796c8dcSSimon Schubert 
7505796c8dcSSimon Schubert       address = 0;
7515796c8dcSSimon Schubert       data = buf;
7525796c8dcSSimon Schubert       switch (hdr[0])
7535796c8dcSSimon Schubert 	{
7545796c8dcSSimon Schubert 	default:
7555796c8dcSSimon Schubert 	  BFD_ASSERT (sofar == section->size);
7565796c8dcSSimon Schubert 	  if (buf != NULL)
7575796c8dcSSimon Schubert 	    free (buf);
7585796c8dcSSimon Schubert 	  return TRUE;
7595796c8dcSSimon Schubert 
7605796c8dcSSimon Schubert 	case '3':
7615796c8dcSSimon Schubert 	  address = HEX (data);
7625796c8dcSSimon Schubert 	  data += 2;
7635796c8dcSSimon Schubert 	  --bytes;
7645796c8dcSSimon Schubert 	  /* Fall through.  */
7655796c8dcSSimon Schubert 	case '2':
7665796c8dcSSimon Schubert 	  address = (address << 8) | HEX (data);
7675796c8dcSSimon Schubert 	  data += 2;
7685796c8dcSSimon Schubert 	  --bytes;
7695796c8dcSSimon Schubert 	  /* Fall through.  */
7705796c8dcSSimon Schubert 	case '1':
7715796c8dcSSimon Schubert 	  address = (address << 8) | HEX (data);
7725796c8dcSSimon Schubert 	  data += 2;
7735796c8dcSSimon Schubert 	  address = (address << 8) | HEX (data);
7745796c8dcSSimon Schubert 	  data += 2;
7755796c8dcSSimon Schubert 	  bytes -= 2;
7765796c8dcSSimon Schubert 
7775796c8dcSSimon Schubert 	  if (address != section->vma + sofar)
7785796c8dcSSimon Schubert 	    {
7795796c8dcSSimon Schubert 	      /* We've come to the end of this section.  */
7805796c8dcSSimon Schubert 	      BFD_ASSERT (sofar == section->size);
7815796c8dcSSimon Schubert 	      if (buf != NULL)
7825796c8dcSSimon Schubert 		free (buf);
7835796c8dcSSimon Schubert 	      return TRUE;
7845796c8dcSSimon Schubert 	    }
7855796c8dcSSimon Schubert 
7865796c8dcSSimon Schubert 	  /* Don't consider checksum.  */
7875796c8dcSSimon Schubert 	  --bytes;
7885796c8dcSSimon Schubert 
7895796c8dcSSimon Schubert 	  while (bytes-- != 0)
7905796c8dcSSimon Schubert 	    {
7915796c8dcSSimon Schubert 	      contents[sofar] = HEX (data);
7925796c8dcSSimon Schubert 	      data += 2;
7935796c8dcSSimon Schubert 	      ++sofar;
7945796c8dcSSimon Schubert 	    }
7955796c8dcSSimon Schubert 
7965796c8dcSSimon Schubert 	  break;
7975796c8dcSSimon Schubert 	}
7985796c8dcSSimon Schubert     }
7995796c8dcSSimon Schubert 
8005796c8dcSSimon Schubert   if (error)
8015796c8dcSSimon Schubert     goto error_return;
8025796c8dcSSimon Schubert 
8035796c8dcSSimon Schubert   BFD_ASSERT (sofar == section->size);
8045796c8dcSSimon Schubert 
8055796c8dcSSimon Schubert   if (buf != NULL)
8065796c8dcSSimon Schubert     free (buf);
8075796c8dcSSimon Schubert 
8085796c8dcSSimon Schubert   return TRUE;
8095796c8dcSSimon Schubert 
8105796c8dcSSimon Schubert  error_return:
8115796c8dcSSimon Schubert   if (buf != NULL)
8125796c8dcSSimon Schubert     free (buf);
8135796c8dcSSimon Schubert   return FALSE;
8145796c8dcSSimon Schubert }
8155796c8dcSSimon Schubert 
8165796c8dcSSimon Schubert /* Get the contents of a section in an S-record file.  */
8175796c8dcSSimon Schubert 
8185796c8dcSSimon Schubert static bfd_boolean
srec_get_section_contents(bfd * abfd,asection * section,void * location,file_ptr offset,bfd_size_type count)8195796c8dcSSimon Schubert srec_get_section_contents (bfd *abfd,
8205796c8dcSSimon Schubert 			   asection *section,
8215796c8dcSSimon Schubert 			   void * location,
8225796c8dcSSimon Schubert 			   file_ptr offset,
8235796c8dcSSimon Schubert 			   bfd_size_type count)
8245796c8dcSSimon Schubert {
8255796c8dcSSimon Schubert   if (count == 0)
8265796c8dcSSimon Schubert     return TRUE;
8275796c8dcSSimon Schubert 
8285796c8dcSSimon Schubert   if (offset + count < count
8295796c8dcSSimon Schubert       || offset + count > section->size)
8305796c8dcSSimon Schubert     {
8315796c8dcSSimon Schubert       bfd_set_error (bfd_error_invalid_operation);
8325796c8dcSSimon Schubert       return FALSE;
8335796c8dcSSimon Schubert     }
8345796c8dcSSimon Schubert 
8355796c8dcSSimon Schubert   if (section->used_by_bfd == NULL)
8365796c8dcSSimon Schubert     {
8375796c8dcSSimon Schubert       section->used_by_bfd = bfd_alloc (abfd, section->size);
8385796c8dcSSimon Schubert       if (section->used_by_bfd == NULL)
8395796c8dcSSimon Schubert 	return FALSE;
8405796c8dcSSimon Schubert 
8415796c8dcSSimon Schubert       if (! srec_read_section (abfd, section,
8425796c8dcSSimon Schubert                                (bfd_byte *) section->used_by_bfd))
8435796c8dcSSimon Schubert 	return FALSE;
8445796c8dcSSimon Schubert     }
8455796c8dcSSimon Schubert 
8465796c8dcSSimon Schubert   memcpy (location, (bfd_byte *) section->used_by_bfd + offset,
8475796c8dcSSimon Schubert 	  (size_t) count);
8485796c8dcSSimon Schubert 
8495796c8dcSSimon Schubert   return TRUE;
8505796c8dcSSimon Schubert }
8515796c8dcSSimon Schubert 
8525796c8dcSSimon Schubert /* Set the architecture.  We accept an unknown architecture here.  */
8535796c8dcSSimon Schubert 
8545796c8dcSSimon Schubert static bfd_boolean
srec_set_arch_mach(bfd * abfd,enum bfd_architecture arch,unsigned long mach)8555796c8dcSSimon Schubert srec_set_arch_mach (bfd *abfd, enum bfd_architecture arch, unsigned long mach)
8565796c8dcSSimon Schubert {
8575796c8dcSSimon Schubert   if (arch != bfd_arch_unknown)
8585796c8dcSSimon Schubert     return bfd_default_set_arch_mach (abfd, arch, mach);
8595796c8dcSSimon Schubert 
8605796c8dcSSimon Schubert   abfd->arch_info = & bfd_default_arch_struct;
8615796c8dcSSimon Schubert   return TRUE;
8625796c8dcSSimon Schubert }
8635796c8dcSSimon Schubert 
8645796c8dcSSimon Schubert /* We have to save up all the Srecords for a splurge before output.  */
8655796c8dcSSimon Schubert 
8665796c8dcSSimon Schubert static bfd_boolean
srec_set_section_contents(bfd * abfd,sec_ptr section,const void * location,file_ptr offset,bfd_size_type bytes_to_do)8675796c8dcSSimon Schubert srec_set_section_contents (bfd *abfd,
8685796c8dcSSimon Schubert 			   sec_ptr section,
8695796c8dcSSimon Schubert 			   const void * location,
8705796c8dcSSimon Schubert 			   file_ptr offset,
8715796c8dcSSimon Schubert 			   bfd_size_type bytes_to_do)
8725796c8dcSSimon Schubert {
8735796c8dcSSimon Schubert   tdata_type *tdata = abfd->tdata.srec_data;
8745796c8dcSSimon Schubert   srec_data_list_type *entry;
8755796c8dcSSimon Schubert 
8765796c8dcSSimon Schubert   entry = (srec_data_list_type *) bfd_alloc (abfd, sizeof (* entry));
8775796c8dcSSimon Schubert   if (entry == NULL)
8785796c8dcSSimon Schubert     return FALSE;
8795796c8dcSSimon Schubert 
8805796c8dcSSimon Schubert   if (bytes_to_do
8815796c8dcSSimon Schubert       && (section->flags & SEC_ALLOC)
8825796c8dcSSimon Schubert       && (section->flags & SEC_LOAD))
8835796c8dcSSimon Schubert     {
8845796c8dcSSimon Schubert       bfd_byte *data;
8855796c8dcSSimon Schubert 
8865796c8dcSSimon Schubert       data = (bfd_byte *) bfd_alloc (abfd, bytes_to_do);
8875796c8dcSSimon Schubert       if (data == NULL)
8885796c8dcSSimon Schubert 	return FALSE;
8895796c8dcSSimon Schubert       memcpy ((void *) data, location, (size_t) bytes_to_do);
8905796c8dcSSimon Schubert 
8915796c8dcSSimon Schubert       /* Ff S3Forced is TRUE then always select S3 records,
8925796c8dcSSimon Schubert 	 regardless of the siez of the addresses.  */
8935796c8dcSSimon Schubert       if (S3Forced)
8945796c8dcSSimon Schubert 	tdata->type = 3;
8955796c8dcSSimon Schubert       else if ((section->lma + offset + bytes_to_do - 1) <= 0xffff)
8965796c8dcSSimon Schubert 	;  /* The default, S1, is OK.  */
8975796c8dcSSimon Schubert       else if ((section->lma + offset + bytes_to_do - 1) <= 0xffffff
8985796c8dcSSimon Schubert 	       && tdata->type <= 2)
8995796c8dcSSimon Schubert 	tdata->type = 2;
9005796c8dcSSimon Schubert       else
9015796c8dcSSimon Schubert 	tdata->type = 3;
9025796c8dcSSimon Schubert 
9035796c8dcSSimon Schubert       entry->data = data;
9045796c8dcSSimon Schubert       entry->where = section->lma + offset;
9055796c8dcSSimon Schubert       entry->size = bytes_to_do;
9065796c8dcSSimon Schubert 
9075796c8dcSSimon Schubert       /* Sort the records by address.  Optimize for the common case of
9085796c8dcSSimon Schubert 	 adding a record to the end of the list.  */
9095796c8dcSSimon Schubert       if (tdata->tail != NULL
9105796c8dcSSimon Schubert 	  && entry->where >= tdata->tail->where)
9115796c8dcSSimon Schubert 	{
9125796c8dcSSimon Schubert 	  tdata->tail->next = entry;
9135796c8dcSSimon Schubert 	  entry->next = NULL;
9145796c8dcSSimon Schubert 	  tdata->tail = entry;
9155796c8dcSSimon Schubert 	}
9165796c8dcSSimon Schubert       else
9175796c8dcSSimon Schubert 	{
9185796c8dcSSimon Schubert 	  srec_data_list_type **look;
9195796c8dcSSimon Schubert 
9205796c8dcSSimon Schubert 	  for (look = &tdata->head;
9215796c8dcSSimon Schubert 	       *look != NULL && (*look)->where < entry->where;
9225796c8dcSSimon Schubert 	       look = &(*look)->next)
9235796c8dcSSimon Schubert 	    ;
9245796c8dcSSimon Schubert 	  entry->next = *look;
9255796c8dcSSimon Schubert 	  *look = entry;
9265796c8dcSSimon Schubert 	  if (entry->next == NULL)
9275796c8dcSSimon Schubert 	    tdata->tail = entry;
9285796c8dcSSimon Schubert 	}
9295796c8dcSSimon Schubert     }
9305796c8dcSSimon Schubert   return TRUE;
9315796c8dcSSimon Schubert }
9325796c8dcSSimon Schubert 
9335796c8dcSSimon Schubert /* Write a record of type, of the supplied number of bytes. The
9345796c8dcSSimon Schubert    supplied bytes and length don't have a checksum. That's worked out
9355796c8dcSSimon Schubert    here.  */
9365796c8dcSSimon Schubert 
9375796c8dcSSimon Schubert static bfd_boolean
srec_write_record(bfd * abfd,unsigned int type,bfd_vma address,const bfd_byte * data,const bfd_byte * end)9385796c8dcSSimon Schubert srec_write_record (bfd *abfd,
9395796c8dcSSimon Schubert 		   unsigned int type,
9405796c8dcSSimon Schubert 		   bfd_vma address,
9415796c8dcSSimon Schubert 		   const bfd_byte *data,
9425796c8dcSSimon Schubert 		   const bfd_byte *end)
9435796c8dcSSimon Schubert {
9445796c8dcSSimon Schubert   char buffer[2 * MAXCHUNK + 6];
9455796c8dcSSimon Schubert   unsigned int check_sum = 0;
9465796c8dcSSimon Schubert   const bfd_byte *src = data;
9475796c8dcSSimon Schubert   char *dst = buffer;
9485796c8dcSSimon Schubert   char *length;
9495796c8dcSSimon Schubert   bfd_size_type wrlen;
9505796c8dcSSimon Schubert 
9515796c8dcSSimon Schubert   *dst++ = 'S';
9525796c8dcSSimon Schubert   *dst++ = '0' + type;
9535796c8dcSSimon Schubert 
9545796c8dcSSimon Schubert   length = dst;
9555796c8dcSSimon Schubert   dst += 2;			/* Leave room for dst.  */
9565796c8dcSSimon Schubert 
9575796c8dcSSimon Schubert   switch (type)
9585796c8dcSSimon Schubert     {
9595796c8dcSSimon Schubert     case 3:
9605796c8dcSSimon Schubert     case 7:
9615796c8dcSSimon Schubert       TOHEX (dst, (address >> 24), check_sum);
9625796c8dcSSimon Schubert       dst += 2;
9635796c8dcSSimon Schubert     case 8:
9645796c8dcSSimon Schubert     case 2:
9655796c8dcSSimon Schubert       TOHEX (dst, (address >> 16), check_sum);
9665796c8dcSSimon Schubert       dst += 2;
9675796c8dcSSimon Schubert     case 9:
9685796c8dcSSimon Schubert     case 1:
9695796c8dcSSimon Schubert     case 0:
9705796c8dcSSimon Schubert       TOHEX (dst, (address >> 8), check_sum);
9715796c8dcSSimon Schubert       dst += 2;
9725796c8dcSSimon Schubert       TOHEX (dst, (address), check_sum);
9735796c8dcSSimon Schubert       dst += 2;
9745796c8dcSSimon Schubert       break;
9755796c8dcSSimon Schubert 
9765796c8dcSSimon Schubert     }
9775796c8dcSSimon Schubert   for (src = data; src < end; src++)
9785796c8dcSSimon Schubert     {
9795796c8dcSSimon Schubert       TOHEX (dst, *src, check_sum);
9805796c8dcSSimon Schubert       dst += 2;
9815796c8dcSSimon Schubert     }
9825796c8dcSSimon Schubert 
9835796c8dcSSimon Schubert   /* Fill in the length.  */
9845796c8dcSSimon Schubert   TOHEX (length, (dst - length) / 2, check_sum);
9855796c8dcSSimon Schubert   check_sum &= 0xff;
9865796c8dcSSimon Schubert   check_sum = 255 - check_sum;
9875796c8dcSSimon Schubert   TOHEX (dst, check_sum, check_sum);
9885796c8dcSSimon Schubert   dst += 2;
9895796c8dcSSimon Schubert 
9905796c8dcSSimon Schubert   *dst++ = '\r';
9915796c8dcSSimon Schubert   *dst++ = '\n';
9925796c8dcSSimon Schubert   wrlen = dst - buffer;
9935796c8dcSSimon Schubert 
9945796c8dcSSimon Schubert   return bfd_bwrite ((void *) buffer, wrlen, abfd) == wrlen;
9955796c8dcSSimon Schubert }
9965796c8dcSSimon Schubert 
9975796c8dcSSimon Schubert static bfd_boolean
srec_write_header(bfd * abfd)9985796c8dcSSimon Schubert srec_write_header (bfd *abfd)
9995796c8dcSSimon Schubert {
10005796c8dcSSimon Schubert   unsigned int len = strlen (abfd->filename);
10015796c8dcSSimon Schubert 
10025796c8dcSSimon Schubert   /* I'll put an arbitrary 40 char limit on header size.  */
10035796c8dcSSimon Schubert   if (len > 40)
10045796c8dcSSimon Schubert     len = 40;
10055796c8dcSSimon Schubert 
10065796c8dcSSimon Schubert   return srec_write_record (abfd, 0, (bfd_vma) 0,
10075796c8dcSSimon Schubert 			    (bfd_byte *) abfd->filename,
10085796c8dcSSimon Schubert 			    (bfd_byte *) abfd->filename + len);
10095796c8dcSSimon Schubert }
10105796c8dcSSimon Schubert 
10115796c8dcSSimon Schubert static bfd_boolean
srec_write_section(bfd * abfd,tdata_type * tdata,srec_data_list_type * list)10125796c8dcSSimon Schubert srec_write_section (bfd *abfd,
10135796c8dcSSimon Schubert 		    tdata_type *tdata,
10145796c8dcSSimon Schubert 		    srec_data_list_type *list)
10155796c8dcSSimon Schubert {
10165796c8dcSSimon Schubert   unsigned int octets_written = 0;
10175796c8dcSSimon Schubert   bfd_byte *location = list->data;
10185796c8dcSSimon Schubert 
10195796c8dcSSimon Schubert   /* Validate number of data bytes to write.  The srec length byte
10205796c8dcSSimon Schubert      counts the address, data and crc bytes.  S1 (tdata->type == 1)
10215796c8dcSSimon Schubert      records have two address bytes, S2 (tdata->type == 2) records
10225796c8dcSSimon Schubert      have three, and S3 (tdata->type == 3) records have four.
10235796c8dcSSimon Schubert      The total length can't exceed 255, and a zero data length will
10245796c8dcSSimon Schubert      spin for a long time.  */
10255796c8dcSSimon Schubert   if (Chunk == 0)
10265796c8dcSSimon Schubert     Chunk = 1;
10275796c8dcSSimon Schubert   else if (Chunk > MAXCHUNK - tdata->type - 2)
10285796c8dcSSimon Schubert     Chunk = MAXCHUNK - tdata->type - 2;
10295796c8dcSSimon Schubert 
10305796c8dcSSimon Schubert   while (octets_written < list->size)
10315796c8dcSSimon Schubert     {
10325796c8dcSSimon Schubert       bfd_vma address;
10335796c8dcSSimon Schubert       unsigned int octets_this_chunk = list->size - octets_written;
10345796c8dcSSimon Schubert 
10355796c8dcSSimon Schubert       if (octets_this_chunk > Chunk)
10365796c8dcSSimon Schubert 	octets_this_chunk = Chunk;
10375796c8dcSSimon Schubert 
10385796c8dcSSimon Schubert       address = list->where + octets_written / bfd_octets_per_byte (abfd);
10395796c8dcSSimon Schubert 
10405796c8dcSSimon Schubert       if (! srec_write_record (abfd,
10415796c8dcSSimon Schubert 			       tdata->type,
10425796c8dcSSimon Schubert 			       address,
10435796c8dcSSimon Schubert 			       location,
10445796c8dcSSimon Schubert 			       location + octets_this_chunk))
10455796c8dcSSimon Schubert 	return FALSE;
10465796c8dcSSimon Schubert 
10475796c8dcSSimon Schubert       octets_written += octets_this_chunk;
10485796c8dcSSimon Schubert       location += octets_this_chunk;
10495796c8dcSSimon Schubert     }
10505796c8dcSSimon Schubert 
10515796c8dcSSimon Schubert   return TRUE;
10525796c8dcSSimon Schubert }
10535796c8dcSSimon Schubert 
10545796c8dcSSimon Schubert static bfd_boolean
srec_write_terminator(bfd * abfd,tdata_type * tdata)10555796c8dcSSimon Schubert srec_write_terminator (bfd *abfd, tdata_type *tdata)
10565796c8dcSSimon Schubert {
10575796c8dcSSimon Schubert   return srec_write_record (abfd, 10 - tdata->type,
10585796c8dcSSimon Schubert 			    abfd->start_address, NULL, NULL);
10595796c8dcSSimon Schubert }
10605796c8dcSSimon Schubert 
10615796c8dcSSimon Schubert static bfd_boolean
srec_write_symbols(bfd * abfd)10625796c8dcSSimon Schubert srec_write_symbols (bfd *abfd)
10635796c8dcSSimon Schubert {
10645796c8dcSSimon Schubert   /* Dump out the symbols of a bfd.  */
10655796c8dcSSimon Schubert   int i;
10665796c8dcSSimon Schubert   int count = bfd_get_symcount (abfd);
10675796c8dcSSimon Schubert 
10685796c8dcSSimon Schubert   if (count)
10695796c8dcSSimon Schubert     {
10705796c8dcSSimon Schubert       bfd_size_type len;
10715796c8dcSSimon Schubert       asymbol **table = bfd_get_outsymbols (abfd);
10725796c8dcSSimon Schubert 
10735796c8dcSSimon Schubert       len = strlen (abfd->filename);
10745796c8dcSSimon Schubert       if (bfd_bwrite ("$$ ", (bfd_size_type) 3, abfd) != 3
10755796c8dcSSimon Schubert 	  || bfd_bwrite (abfd->filename, len, abfd) != len
10765796c8dcSSimon Schubert 	  || bfd_bwrite ("\r\n", (bfd_size_type) 2, abfd) != 2)
10775796c8dcSSimon Schubert 	return FALSE;
10785796c8dcSSimon Schubert 
10795796c8dcSSimon Schubert       for (i = 0; i < count; i++)
10805796c8dcSSimon Schubert 	{
10815796c8dcSSimon Schubert 	  asymbol *s = table[i];
10825796c8dcSSimon Schubert 	  if (! bfd_is_local_label (abfd, s)
10835796c8dcSSimon Schubert 	      && (s->flags & BSF_DEBUGGING) == 0)
10845796c8dcSSimon Schubert 	    {
10855796c8dcSSimon Schubert 	      /* Just dump out non debug symbols.  */
10865796c8dcSSimon Schubert 	      char buf[43], *p;
10875796c8dcSSimon Schubert 
10885796c8dcSSimon Schubert 	      len = strlen (s->name);
10895796c8dcSSimon Schubert 	      if (bfd_bwrite ("  ", (bfd_size_type) 2, abfd) != 2
10905796c8dcSSimon Schubert 		  || bfd_bwrite (s->name, len, abfd) != len)
10915796c8dcSSimon Schubert 		return FALSE;
10925796c8dcSSimon Schubert 
10935796c8dcSSimon Schubert 	      sprintf_vma (buf + 2, (s->value
10945796c8dcSSimon Schubert 				     + s->section->output_section->lma
10955796c8dcSSimon Schubert 				     + s->section->output_offset));
10965796c8dcSSimon Schubert 	      p = buf + 2;
10975796c8dcSSimon Schubert 	      while (p[0] == '0' && p[1] != 0)
10985796c8dcSSimon Schubert 		p++;
10995796c8dcSSimon Schubert 	      len = strlen (p);
11005796c8dcSSimon Schubert 	      p[len] = '\r';
11015796c8dcSSimon Schubert 	      p[len + 1] = '\n';
11025796c8dcSSimon Schubert 	      *--p = '$';
11035796c8dcSSimon Schubert 	      *--p = ' ';
11045796c8dcSSimon Schubert 	      len += 4;
11055796c8dcSSimon Schubert 	      if (bfd_bwrite (p, len, abfd) != len)
11065796c8dcSSimon Schubert 		return FALSE;
11075796c8dcSSimon Schubert 	    }
11085796c8dcSSimon Schubert 	}
11095796c8dcSSimon Schubert       if (bfd_bwrite ("$$ \r\n", (bfd_size_type) 5, abfd) != 5)
11105796c8dcSSimon Schubert 	return FALSE;
11115796c8dcSSimon Schubert     }
11125796c8dcSSimon Schubert 
11135796c8dcSSimon Schubert   return TRUE;
11145796c8dcSSimon Schubert }
11155796c8dcSSimon Schubert 
11165796c8dcSSimon Schubert static bfd_boolean
internal_srec_write_object_contents(bfd * abfd,int symbols)11175796c8dcSSimon Schubert internal_srec_write_object_contents (bfd *abfd, int symbols)
11185796c8dcSSimon Schubert {
11195796c8dcSSimon Schubert   tdata_type *tdata = abfd->tdata.srec_data;
11205796c8dcSSimon Schubert   srec_data_list_type *list;
11215796c8dcSSimon Schubert 
11225796c8dcSSimon Schubert   if (symbols)
11235796c8dcSSimon Schubert     {
11245796c8dcSSimon Schubert       if (! srec_write_symbols (abfd))
11255796c8dcSSimon Schubert 	return FALSE;
11265796c8dcSSimon Schubert     }
11275796c8dcSSimon Schubert 
11285796c8dcSSimon Schubert   if (! srec_write_header (abfd))
11295796c8dcSSimon Schubert     return FALSE;
11305796c8dcSSimon Schubert 
11315796c8dcSSimon Schubert   /* Now wander though all the sections provided and output them.  */
11325796c8dcSSimon Schubert   list = tdata->head;
11335796c8dcSSimon Schubert 
11345796c8dcSSimon Schubert   while (list != (srec_data_list_type *) NULL)
11355796c8dcSSimon Schubert     {
11365796c8dcSSimon Schubert       if (! srec_write_section (abfd, tdata, list))
11375796c8dcSSimon Schubert 	return FALSE;
11385796c8dcSSimon Schubert       list = list->next;
11395796c8dcSSimon Schubert     }
11405796c8dcSSimon Schubert   return srec_write_terminator (abfd, tdata);
11415796c8dcSSimon Schubert }
11425796c8dcSSimon Schubert 
11435796c8dcSSimon Schubert static bfd_boolean
srec_write_object_contents(bfd * abfd)11445796c8dcSSimon Schubert srec_write_object_contents (bfd *abfd)
11455796c8dcSSimon Schubert {
11465796c8dcSSimon Schubert   return internal_srec_write_object_contents (abfd, 0);
11475796c8dcSSimon Schubert }
11485796c8dcSSimon Schubert 
11495796c8dcSSimon Schubert static bfd_boolean
symbolsrec_write_object_contents(bfd * abfd)11505796c8dcSSimon Schubert symbolsrec_write_object_contents (bfd *abfd)
11515796c8dcSSimon Schubert {
11525796c8dcSSimon Schubert   return internal_srec_write_object_contents (abfd, 1);
11535796c8dcSSimon Schubert }
11545796c8dcSSimon Schubert 
11555796c8dcSSimon Schubert static int
srec_sizeof_headers(bfd * abfd ATTRIBUTE_UNUSED,struct bfd_link_info * info ATTRIBUTE_UNUSED)11565796c8dcSSimon Schubert srec_sizeof_headers (bfd *abfd ATTRIBUTE_UNUSED,
11575796c8dcSSimon Schubert 		     struct bfd_link_info *info ATTRIBUTE_UNUSED)
11585796c8dcSSimon Schubert {
11595796c8dcSSimon Schubert   return 0;
11605796c8dcSSimon Schubert }
11615796c8dcSSimon Schubert 
11625796c8dcSSimon Schubert /* Return the amount of memory needed to read the symbol table.  */
11635796c8dcSSimon Schubert 
11645796c8dcSSimon Schubert static long
srec_get_symtab_upper_bound(bfd * abfd)11655796c8dcSSimon Schubert srec_get_symtab_upper_bound (bfd *abfd)
11665796c8dcSSimon Schubert {
11675796c8dcSSimon Schubert   return (bfd_get_symcount (abfd) + 1) * sizeof (asymbol *);
11685796c8dcSSimon Schubert }
11695796c8dcSSimon Schubert 
11705796c8dcSSimon Schubert /* Return the symbol table.  */
11715796c8dcSSimon Schubert 
11725796c8dcSSimon Schubert static long
srec_canonicalize_symtab(bfd * abfd,asymbol ** alocation)11735796c8dcSSimon Schubert srec_canonicalize_symtab (bfd *abfd, asymbol **alocation)
11745796c8dcSSimon Schubert {
11755796c8dcSSimon Schubert   bfd_size_type symcount = bfd_get_symcount (abfd);
11765796c8dcSSimon Schubert   asymbol *csymbols;
11775796c8dcSSimon Schubert   unsigned int i;
11785796c8dcSSimon Schubert 
11795796c8dcSSimon Schubert   csymbols = abfd->tdata.srec_data->csymbols;
11805796c8dcSSimon Schubert   if (csymbols == NULL && symcount != 0)
11815796c8dcSSimon Schubert     {
11825796c8dcSSimon Schubert       asymbol *c;
11835796c8dcSSimon Schubert       struct srec_symbol *s;
11845796c8dcSSimon Schubert 
11855796c8dcSSimon Schubert       csymbols = (asymbol *) bfd_alloc (abfd, symcount * sizeof (asymbol));
11865796c8dcSSimon Schubert       if (csymbols == NULL)
11875796c8dcSSimon Schubert 	return -1;
11885796c8dcSSimon Schubert       abfd->tdata.srec_data->csymbols = csymbols;
11895796c8dcSSimon Schubert 
11905796c8dcSSimon Schubert       for (s = abfd->tdata.srec_data->symbols, c = csymbols;
11915796c8dcSSimon Schubert 	   s != NULL;
11925796c8dcSSimon Schubert 	   s = s->next, ++c)
11935796c8dcSSimon Schubert 	{
11945796c8dcSSimon Schubert 	  c->the_bfd = abfd;
11955796c8dcSSimon Schubert 	  c->name = s->name;
11965796c8dcSSimon Schubert 	  c->value = s->val;
11975796c8dcSSimon Schubert 	  c->flags = BSF_GLOBAL;
11985796c8dcSSimon Schubert 	  c->section = bfd_abs_section_ptr;
11995796c8dcSSimon Schubert 	  c->udata.p = NULL;
12005796c8dcSSimon Schubert 	}
12015796c8dcSSimon Schubert     }
12025796c8dcSSimon Schubert 
12035796c8dcSSimon Schubert   for (i = 0; i < symcount; i++)
12045796c8dcSSimon Schubert     *alocation++ = csymbols++;
12055796c8dcSSimon Schubert   *alocation = NULL;
12065796c8dcSSimon Schubert 
12075796c8dcSSimon Schubert   return symcount;
12085796c8dcSSimon Schubert }
12095796c8dcSSimon Schubert 
12105796c8dcSSimon Schubert static void
srec_get_symbol_info(bfd * ignore_abfd ATTRIBUTE_UNUSED,asymbol * symbol,symbol_info * ret)12115796c8dcSSimon Schubert srec_get_symbol_info (bfd *ignore_abfd ATTRIBUTE_UNUSED,
12125796c8dcSSimon Schubert 		      asymbol *symbol,
12135796c8dcSSimon Schubert 		      symbol_info *ret)
12145796c8dcSSimon Schubert {
12155796c8dcSSimon Schubert   bfd_symbol_info (symbol, ret);
12165796c8dcSSimon Schubert }
12175796c8dcSSimon Schubert 
12185796c8dcSSimon Schubert static void
srec_print_symbol(bfd * abfd,void * afile,asymbol * symbol,bfd_print_symbol_type how)12195796c8dcSSimon Schubert srec_print_symbol (bfd *abfd,
12205796c8dcSSimon Schubert 		   void * afile,
12215796c8dcSSimon Schubert 		   asymbol *symbol,
12225796c8dcSSimon Schubert 		   bfd_print_symbol_type how)
12235796c8dcSSimon Schubert {
12245796c8dcSSimon Schubert   FILE *file = (FILE *) afile;
12255796c8dcSSimon Schubert 
12265796c8dcSSimon Schubert   switch (how)
12275796c8dcSSimon Schubert     {
12285796c8dcSSimon Schubert     case bfd_print_symbol_name:
12295796c8dcSSimon Schubert       fprintf (file, "%s", symbol->name);
12305796c8dcSSimon Schubert       break;
12315796c8dcSSimon Schubert     default:
12325796c8dcSSimon Schubert       bfd_print_symbol_vandf (abfd, (void *) file, symbol);
12335796c8dcSSimon Schubert       fprintf (file, " %-5s %s",
12345796c8dcSSimon Schubert 	       symbol->section->name,
12355796c8dcSSimon Schubert 	       symbol->name);
12365796c8dcSSimon Schubert     }
12375796c8dcSSimon Schubert }
12385796c8dcSSimon Schubert 
12395796c8dcSSimon Schubert #define	srec_close_and_cleanup                    _bfd_generic_close_and_cleanup
12405796c8dcSSimon Schubert #define srec_bfd_free_cached_info                 _bfd_generic_bfd_free_cached_info
12415796c8dcSSimon Schubert #define srec_new_section_hook                     _bfd_generic_new_section_hook
12425796c8dcSSimon Schubert #define srec_bfd_is_target_special_symbol         ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false)
12435796c8dcSSimon Schubert #define srec_bfd_is_local_label_name              bfd_generic_is_local_label_name
12445796c8dcSSimon Schubert #define srec_get_lineno                           _bfd_nosymbols_get_lineno
12455796c8dcSSimon Schubert #define srec_find_nearest_line                    _bfd_nosymbols_find_nearest_line
12465796c8dcSSimon Schubert #define srec_find_inliner_info                    _bfd_nosymbols_find_inliner_info
12475796c8dcSSimon Schubert #define srec_make_empty_symbol                    _bfd_generic_make_empty_symbol
12485796c8dcSSimon Schubert #define srec_bfd_make_debug_symbol                _bfd_nosymbols_bfd_make_debug_symbol
12495796c8dcSSimon Schubert #define srec_read_minisymbols                     _bfd_generic_read_minisymbols
12505796c8dcSSimon Schubert #define srec_minisymbol_to_symbol                 _bfd_generic_minisymbol_to_symbol
12515796c8dcSSimon Schubert #define srec_get_section_contents_in_window       _bfd_generic_get_section_contents_in_window
12525796c8dcSSimon Schubert #define srec_bfd_get_relocated_section_contents   bfd_generic_get_relocated_section_contents
12535796c8dcSSimon Schubert #define srec_bfd_relax_section                    bfd_generic_relax_section
12545796c8dcSSimon Schubert #define srec_bfd_gc_sections                      bfd_generic_gc_sections
1255*a45ae5f8SJohn Marino #define srec_bfd_lookup_section_flags             bfd_generic_lookup_section_flags
12565796c8dcSSimon Schubert #define srec_bfd_merge_sections                   bfd_generic_merge_sections
12575796c8dcSSimon Schubert #define srec_bfd_is_group_section                 bfd_generic_is_group_section
12585796c8dcSSimon Schubert #define srec_bfd_discard_group                    bfd_generic_discard_group
12595796c8dcSSimon Schubert #define srec_section_already_linked               _bfd_generic_section_already_linked
12605796c8dcSSimon Schubert #define srec_bfd_define_common_symbol             bfd_generic_define_common_symbol
12615796c8dcSSimon Schubert #define srec_bfd_link_hash_table_create           _bfd_generic_link_hash_table_create
12625796c8dcSSimon Schubert #define srec_bfd_link_hash_table_free             _bfd_generic_link_hash_table_free
12635796c8dcSSimon Schubert #define srec_bfd_link_add_symbols                 _bfd_generic_link_add_symbols
12645796c8dcSSimon Schubert #define srec_bfd_link_just_syms                   _bfd_generic_link_just_syms
1265cf7f2e2dSJohn Marino #define srec_bfd_copy_link_hash_symbol_type \
1266cf7f2e2dSJohn Marino   _bfd_generic_copy_link_hash_symbol_type
12675796c8dcSSimon Schubert #define srec_bfd_final_link                       _bfd_generic_final_link
12685796c8dcSSimon Schubert #define srec_bfd_link_split_section               _bfd_generic_link_split_section
12695796c8dcSSimon Schubert 
12705796c8dcSSimon Schubert const bfd_target srec_vec =
12715796c8dcSSimon Schubert {
12725796c8dcSSimon Schubert   "srec",			/* Name.  */
12735796c8dcSSimon Schubert   bfd_target_srec_flavour,
12745796c8dcSSimon Schubert   BFD_ENDIAN_UNKNOWN,		/* Target byte order.  */
12755796c8dcSSimon Schubert   BFD_ENDIAN_UNKNOWN,		/* Target headers byte order.  */
12765796c8dcSSimon Schubert   (HAS_RELOC | EXEC_P |		/* Object flags.  */
12775796c8dcSSimon Schubert    HAS_LINENO | HAS_DEBUG |
12785796c8dcSSimon Schubert    HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
12795796c8dcSSimon Schubert   (SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS
12805796c8dcSSimon Schubert    | SEC_ALLOC | SEC_LOAD | SEC_RELOC),	/* Section flags.  */
12815796c8dcSSimon Schubert   0,				/* Leading underscore.  */
12825796c8dcSSimon Schubert   ' ',				/* AR_pad_char.  */
12835796c8dcSSimon Schubert   16,				/* AR_max_namelen.  */
1284*a45ae5f8SJohn Marino   0,				/* match priority.  */
12855796c8dcSSimon Schubert   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
12865796c8dcSSimon Schubert   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
12875796c8dcSSimon Schubert   bfd_getb16, bfd_getb_signed_16, bfd_putb16,	/* Data.  */
12885796c8dcSSimon Schubert   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
12895796c8dcSSimon Schubert   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
12905796c8dcSSimon Schubert   bfd_getb16, bfd_getb_signed_16, bfd_putb16,	/* Hdrs.  */
12915796c8dcSSimon Schubert 
12925796c8dcSSimon Schubert   {
12935796c8dcSSimon Schubert     _bfd_dummy_target,
12945796c8dcSSimon Schubert     srec_object_p,		/* bfd_check_format.  */
12955796c8dcSSimon Schubert     _bfd_dummy_target,
12965796c8dcSSimon Schubert     _bfd_dummy_target,
12975796c8dcSSimon Schubert   },
12985796c8dcSSimon Schubert   {
12995796c8dcSSimon Schubert     bfd_false,
13005796c8dcSSimon Schubert     srec_mkobject,
13015796c8dcSSimon Schubert     _bfd_generic_mkarchive,
13025796c8dcSSimon Schubert     bfd_false,
13035796c8dcSSimon Schubert   },
13045796c8dcSSimon Schubert   {				/* bfd_write_contents.  */
13055796c8dcSSimon Schubert     bfd_false,
13065796c8dcSSimon Schubert     srec_write_object_contents,
13075796c8dcSSimon Schubert     _bfd_write_archive_contents,
13085796c8dcSSimon Schubert     bfd_false,
13095796c8dcSSimon Schubert   },
13105796c8dcSSimon Schubert 
13115796c8dcSSimon Schubert   BFD_JUMP_TABLE_GENERIC (srec),
13125796c8dcSSimon Schubert   BFD_JUMP_TABLE_COPY (_bfd_generic),
13135796c8dcSSimon Schubert   BFD_JUMP_TABLE_CORE (_bfd_nocore),
13145796c8dcSSimon Schubert   BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
13155796c8dcSSimon Schubert   BFD_JUMP_TABLE_SYMBOLS (srec),
13165796c8dcSSimon Schubert   BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
13175796c8dcSSimon Schubert   BFD_JUMP_TABLE_WRITE (srec),
13185796c8dcSSimon Schubert   BFD_JUMP_TABLE_LINK (srec),
13195796c8dcSSimon Schubert   BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
13205796c8dcSSimon Schubert 
13215796c8dcSSimon Schubert   NULL,
13225796c8dcSSimon Schubert 
13235796c8dcSSimon Schubert   NULL
13245796c8dcSSimon Schubert };
13255796c8dcSSimon Schubert 
13265796c8dcSSimon Schubert const bfd_target symbolsrec_vec =
13275796c8dcSSimon Schubert {
13285796c8dcSSimon Schubert   "symbolsrec",			/* Name.  */
13295796c8dcSSimon Schubert   bfd_target_srec_flavour,
13305796c8dcSSimon Schubert   BFD_ENDIAN_UNKNOWN,		/* Target byte order.  */
13315796c8dcSSimon Schubert   BFD_ENDIAN_UNKNOWN,		/* Target headers byte order.  */
13325796c8dcSSimon Schubert   (HAS_RELOC | EXEC_P |		/* Object flags.  */
13335796c8dcSSimon Schubert    HAS_LINENO | HAS_DEBUG |
13345796c8dcSSimon Schubert    HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
13355796c8dcSSimon Schubert   (SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS
13365796c8dcSSimon Schubert    | SEC_ALLOC | SEC_LOAD | SEC_RELOC),	/* Section flags.  */
13375796c8dcSSimon Schubert   0,				/* Leading underscore.  */
13385796c8dcSSimon Schubert   ' ',				/* AR_pad_char.  */
13395796c8dcSSimon Schubert   16,				/* AR_max_namelen.  */
1340*a45ae5f8SJohn Marino   0,				/* match priority.  */
13415796c8dcSSimon Schubert   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
13425796c8dcSSimon Schubert   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
13435796c8dcSSimon Schubert   bfd_getb16, bfd_getb_signed_16, bfd_putb16,	/* Data.  */
13445796c8dcSSimon Schubert   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
13455796c8dcSSimon Schubert   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
13465796c8dcSSimon Schubert   bfd_getb16, bfd_getb_signed_16, bfd_putb16,	/* Headers.  */
13475796c8dcSSimon Schubert 
13485796c8dcSSimon Schubert   {
13495796c8dcSSimon Schubert     _bfd_dummy_target,
13505796c8dcSSimon Schubert     symbolsrec_object_p,	/* bfd_check_format.  */
13515796c8dcSSimon Schubert     _bfd_dummy_target,
13525796c8dcSSimon Schubert     _bfd_dummy_target,
13535796c8dcSSimon Schubert   },
13545796c8dcSSimon Schubert   {
13555796c8dcSSimon Schubert     bfd_false,
13565796c8dcSSimon Schubert     srec_mkobject,
13575796c8dcSSimon Schubert     _bfd_generic_mkarchive,
13585796c8dcSSimon Schubert     bfd_false,
13595796c8dcSSimon Schubert   },
13605796c8dcSSimon Schubert   {				/* bfd_write_contents.  */
13615796c8dcSSimon Schubert     bfd_false,
13625796c8dcSSimon Schubert     symbolsrec_write_object_contents,
13635796c8dcSSimon Schubert     _bfd_write_archive_contents,
13645796c8dcSSimon Schubert     bfd_false,
13655796c8dcSSimon Schubert   },
13665796c8dcSSimon Schubert 
13675796c8dcSSimon Schubert   BFD_JUMP_TABLE_GENERIC (srec),
13685796c8dcSSimon Schubert   BFD_JUMP_TABLE_COPY (_bfd_generic),
13695796c8dcSSimon Schubert   BFD_JUMP_TABLE_CORE (_bfd_nocore),
13705796c8dcSSimon Schubert   BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
13715796c8dcSSimon Schubert   BFD_JUMP_TABLE_SYMBOLS (srec),
13725796c8dcSSimon Schubert   BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
13735796c8dcSSimon Schubert   BFD_JUMP_TABLE_WRITE (srec),
13745796c8dcSSimon Schubert   BFD_JUMP_TABLE_LINK (srec),
13755796c8dcSSimon Schubert   BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
13765796c8dcSSimon Schubert 
13775796c8dcSSimon Schubert   NULL,
13785796c8dcSSimon Schubert 
13795796c8dcSSimon Schubert   NULL
13805796c8dcSSimon Schubert };
1381