133965Sjdp/* BFD back-end for s-record objects.
278828Sobrien   Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
3218822Sdim   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
438889Sjdp   Free Software Foundation, Inc.
533965Sjdp   Written by Steve Chamberlain of Cygnus Support <sac@cygnus.com>.
633965Sjdp
7218822Sdim   This file is part of BFD, the Binary File Descriptor library.
833965Sjdp
9218822Sdim   This program is free software; you can redistribute it and/or modify
10218822Sdim   it under the terms of the GNU General Public License as published by
11218822Sdim   the Free Software Foundation; either version 2 of the License, or
12218822Sdim   (at your option) any later version.
1333965Sjdp
14218822Sdim   This program is distributed in the hope that it will be useful,
15218822Sdim   but WITHOUT ANY WARRANTY; without even the implied warranty of
16218822Sdim   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17218822Sdim   GNU General Public License for more details.
1833965Sjdp
19218822Sdim   You should have received a copy of the GNU General Public License
20218822Sdim   along with this program; if not, write to the Free Software
21218822Sdim   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
2233965Sjdp
23218822Sdim/* SUBSECTION
2433965Sjdp	S-Record handling
2533965Sjdp
26218822Sdim   DESCRIPTION
2777298Sobrien
2833965Sjdp	Ordinary S-Records cannot hold anything but addresses and
2933965Sjdp	data, so that's all that we implement.
3033965Sjdp
3133965Sjdp	The only interesting thing is that S-Records may come out of
3233965Sjdp	order and there is no header, so an initial scan is required
3333965Sjdp	to discover the minimum and maximum addresses used to create
3433965Sjdp	the vma and size of the only section we create.  We
3533965Sjdp	arbitrarily call this section ".text".
3633965Sjdp
3733965Sjdp	When bfd_get_section_contents is called the file is read
3833965Sjdp	again, and this time the data is placed into a bfd_alloc'd
3933965Sjdp	area.
4033965Sjdp
4133965Sjdp	Any number of sections may be created for output, we save them
4233965Sjdp	up and output them when it's time to close the bfd.
4333965Sjdp
4433965Sjdp	An s record looks like:
4577298Sobrien
46218822Sdim   EXAMPLE
4733965Sjdp	S<type><length><address><data><checksum>
4877298Sobrien
49218822Sdim   DESCRIPTION
5033965Sjdp	Where
5133965Sjdp	o length
5233965Sjdp	is the number of bytes following upto the checksum. Note that
5333965Sjdp	this is not the number of chars following, since it takes two
5433965Sjdp	chars to represent a byte.
5533965Sjdp	o type
5633965Sjdp	is one of:
5733965Sjdp	0) header record
5833965Sjdp	1) two byte address data record
5933965Sjdp	2) three byte address data record
6033965Sjdp	3) four byte address data record
6133965Sjdp	7) four byte address termination record
6233965Sjdp	8) three byte address termination record
6333965Sjdp	9) two byte address termination record
6477298Sobrien
6533965Sjdp	o address
6633965Sjdp	is the start address of the data following, or in the case of
6733965Sjdp	a termination record, the start address of the image
6833965Sjdp	o data
6933965Sjdp	is the data.
7033965Sjdp	o checksum
7133965Sjdp	is the sum of all the raw byte data in the record, from the length
7233965Sjdp	upwards, modulo 256 and subtracted from 255.
7333965Sjdp
74218822Sdim   SUBSECTION
7533965Sjdp	Symbol S-Record handling
7633965Sjdp
77218822Sdim   DESCRIPTION
7833965Sjdp	Some ICE equipment understands an addition to the standard
7933965Sjdp	S-Record format; symbols and their addresses can be sent
8033965Sjdp	before the data.
8133965Sjdp
8233965Sjdp	The format of this is:
8333965Sjdp	($$ <modulename>
8433965Sjdp		(<space> <symbol> <address>)*)
8533965Sjdp	$$
8633965Sjdp
8733965Sjdp	so a short symbol table could look like:
8833965Sjdp
89218822Sdim   EXAMPLE
9033965Sjdp	$$ flash.x
9133965Sjdp	$$ flash.c
9233965Sjdp	  _port6 $0
9333965Sjdp	  _delay $4
9433965Sjdp	  _start $14
9533965Sjdp	  _etext $8036
9633965Sjdp	  _edata $8036
9733965Sjdp 	  _end $8036
9833965Sjdp	$$
9933965Sjdp
100218822Sdim   DESCRIPTION
10133965Sjdp	We allow symbols to be anywhere in the data stream - the module names
102218822Sdim	are always ignored.  */
10377298Sobrien
104218822Sdim#include "sysdep.h"
10533965Sjdp#include "bfd.h"
10633965Sjdp#include "libbfd.h"
10733965Sjdp#include "libiberty.h"
10889857Sobrien#include "safe-ctype.h"
10933965Sjdp
11033965Sjdp
11177298Sobrien/* Macros for converting between hex and binary.  */
11233965Sjdp
11389857Sobrienstatic const char digs[] = "0123456789ABCDEF";
11433965Sjdp
115218822Sdim#define NIBBLE(x)    hex_value(x)
116218822Sdim#define HEX(buffer) ((NIBBLE ((buffer)[0])<<4) + NIBBLE ((buffer)[1]))
11733965Sjdp#define TOHEX(d, x, ch) \
11833965Sjdp	d[1] = digs[(x) & 0xf]; \
11933965Sjdp	d[0] = digs[((x)>>4)&0xf]; \
12033965Sjdp	ch += ((x) & 0xff);
121218822Sdim#define	ISHEX(x)    hex_p(x)
12233965Sjdp
12394536Sobrien/* The maximum number of address+data+crc bytes on a line is FF.  */
12433965Sjdp#define MAXCHUNK 0xff
12533965Sjdp
12677298Sobrien/* Default size for a CHUNK.  */
12777298Sobrien#define DEFAULT_CHUNK 16
12877298Sobrien
12994536Sobrien/* The number of data bytes we actually fit onto a line on output.
13077298Sobrien   This variable can be modified by objcopy's --srec-len parameter.
13177298Sobrien   For a 0x75 byte record you should set --srec-len=0x70.  */
13277298Sobrienunsigned int Chunk = DEFAULT_CHUNK;
13377298Sobrien
13477298Sobrien/* The type of srec output (free or forced to S3).
13577298Sobrien   This variable can be modified by objcopy's --srec-forceS3
13677298Sobrien   parameter.  */
137130561Sobrienbfd_boolean S3Forced = FALSE;
13877298Sobrien
13933965Sjdp/* When writing an S-record file, the S-records can not be output as
14033965Sjdp   they are seen.  This structure is used to hold them in memory.  */
14133965Sjdp
14233965Sjdpstruct srec_data_list_struct
14333965Sjdp{
14433965Sjdp  struct srec_data_list_struct *next;
14533965Sjdp  bfd_byte *data;
14633965Sjdp  bfd_vma where;
14733965Sjdp  bfd_size_type size;
14833965Sjdp};
14933965Sjdp
15033965Sjdptypedef struct srec_data_list_struct srec_data_list_type;
15133965Sjdp
15233965Sjdp/* When scanning the S-record file, a linked list of srec_symbol
15333965Sjdp   structures is built to represent the symbol table (if there is
15433965Sjdp   one).  */
15533965Sjdp
15633965Sjdpstruct srec_symbol
15733965Sjdp{
15833965Sjdp  struct srec_symbol *next;
15933965Sjdp  const char *name;
16033965Sjdp  bfd_vma val;
16133965Sjdp};
16233965Sjdp
16333965Sjdp/* The S-record tdata information.  */
16433965Sjdp
16533965Sjdptypedef struct srec_data_struct
16633965Sjdp  {
16733965Sjdp    srec_data_list_type *head;
16833965Sjdp    srec_data_list_type *tail;
16933965Sjdp    unsigned int type;
17033965Sjdp    struct srec_symbol *symbols;
17133965Sjdp    struct srec_symbol *symtail;
17233965Sjdp    asymbol *csymbols;
17333965Sjdp  }
17433965Sjdptdata_type;
17533965Sjdp
176218822Sdim/* Initialize by filling in the hex conversion array.  */
17733965Sjdp
178218822Sdimstatic void
179218822Sdimsrec_init (void)
180218822Sdim{
181218822Sdim  static bfd_boolean inited = FALSE;
182218822Sdim
183218822Sdim  if (! inited)
184218822Sdim    {
185218822Sdim      inited = TRUE;
186218822Sdim      hex_init ();
187218822Sdim    }
188218822Sdim}
189218822Sdim
19033965Sjdp/* Set up the S-record tdata information.  */
19133965Sjdp
192130561Sobrienstatic bfd_boolean
193218822Sdimsrec_mkobject (bfd *abfd)
19433965Sjdp{
195104834Sobrien  tdata_type *tdata;
196104834Sobrien
19733965Sjdp  srec_init ();
19833965Sjdp
199218822Sdim  tdata = bfd_alloc (abfd, sizeof (tdata_type));
200104834Sobrien  if (tdata == NULL)
201130561Sobrien    return FALSE;
202130561Sobrien
203104834Sobrien  abfd->tdata.srec_data = tdata;
204104834Sobrien  tdata->type = 1;
205104834Sobrien  tdata->head = NULL;
206104834Sobrien  tdata->tail = NULL;
207104834Sobrien  tdata->symbols = NULL;
208104834Sobrien  tdata->symtail = NULL;
209104834Sobrien  tdata->csymbols = NULL;
21033965Sjdp
211130561Sobrien  return TRUE;
21233965Sjdp}
21333965Sjdp
21433965Sjdp/* Read a byte from an S record file.  Set *ERRORPTR if an error
21533965Sjdp   occurred.  Return EOF on error or end of file.  */
21633965Sjdp
21733965Sjdpstatic int
218218822Sdimsrec_get_byte (bfd *abfd, bfd_boolean *errorptr)
21933965Sjdp{
22033965Sjdp  bfd_byte c;
22133965Sjdp
22289857Sobrien  if (bfd_bread (&c, (bfd_size_type) 1, abfd) != 1)
22333965Sjdp    {
22433965Sjdp      if (bfd_get_error () != bfd_error_file_truncated)
225130561Sobrien	*errorptr = TRUE;
22633965Sjdp      return EOF;
22733965Sjdp    }
22833965Sjdp
22933965Sjdp  return (int) (c & 0xff);
23033965Sjdp}
23133965Sjdp
23233965Sjdp/* Report a problem in an S record file.  FIXME: This probably should
23333965Sjdp   not call fprintf, but we really do need some mechanism for printing
23433965Sjdp   error messages.  */
23533965Sjdp
23633965Sjdpstatic void
237218822Sdimsrec_bad_byte (bfd *abfd,
238218822Sdim	       unsigned int lineno,
239218822Sdim	       int c,
240218822Sdim	       bfd_boolean error)
24133965Sjdp{
24233965Sjdp  if (c == EOF)
24333965Sjdp    {
24433965Sjdp      if (! error)
24533965Sjdp	bfd_set_error (bfd_error_file_truncated);
24633965Sjdp    }
24733965Sjdp  else
24833965Sjdp    {
24933965Sjdp      char buf[10];
25033965Sjdp
25189857Sobrien      if (! ISPRINT (c))
25233965Sjdp	sprintf (buf, "\\%03o", (unsigned int) c);
25333965Sjdp      else
25433965Sjdp	{
25533965Sjdp	  buf[0] = c;
25633965Sjdp	  buf[1] = '\0';
25733965Sjdp	}
25833965Sjdp      (*_bfd_error_handler)
259218822Sdim	(_("%B:%d: Unexpected character `%s' in S-record file\n"),
260218822Sdim	 abfd, lineno, buf);
26133965Sjdp      bfd_set_error (bfd_error_bad_value);
26233965Sjdp    }
26333965Sjdp}
26433965Sjdp
26533965Sjdp/* Add a new symbol found in an S-record file.  */
26633965Sjdp
267130561Sobrienstatic bfd_boolean
268218822Sdimsrec_new_symbol (bfd *abfd, const char *name, bfd_vma val)
26933965Sjdp{
27033965Sjdp  struct srec_symbol *n;
27133965Sjdp
272218822Sdim  n = bfd_alloc (abfd, sizeof (* n));
27333965Sjdp  if (n == NULL)
274130561Sobrien    return FALSE;
27533965Sjdp
27633965Sjdp  n->name = name;
27733965Sjdp  n->val = val;
27833965Sjdp
27933965Sjdp  if (abfd->tdata.srec_data->symbols == NULL)
28033965Sjdp    abfd->tdata.srec_data->symbols = n;
28133965Sjdp  else
28233965Sjdp    abfd->tdata.srec_data->symtail->next = n;
28333965Sjdp  abfd->tdata.srec_data->symtail = n;
28433965Sjdp  n->next = NULL;
28533965Sjdp
28633965Sjdp  ++abfd->symcount;
28733965Sjdp
288130561Sobrien  return TRUE;
28933965Sjdp}
29033965Sjdp
29133965Sjdp/* Read the S record file and turn it into sections.  We create a new
29233965Sjdp   section for each contiguous set of bytes.  */
29333965Sjdp
294130561Sobrienstatic bfd_boolean
295218822Sdimsrec_scan (bfd *abfd)
29633965Sjdp{
29733965Sjdp  int c;
29833965Sjdp  unsigned int lineno = 1;
299130561Sobrien  bfd_boolean error = FALSE;
30033965Sjdp  bfd_byte *buf = NULL;
30133965Sjdp  size_t bufsize = 0;
30233965Sjdp  asection *sec = NULL;
30333965Sjdp  char *symbuf = NULL;
30433965Sjdp
30533965Sjdp  if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0)
30633965Sjdp    goto error_return;
30733965Sjdp
30833965Sjdp  while ((c = srec_get_byte (abfd, &error)) != EOF)
30933965Sjdp    {
31033965Sjdp      /* We only build sections from contiguous S-records, so if this
311130561Sobrien	 is not an S-record, then stop building a section.  */
31233965Sjdp      if (c != 'S' && c != '\r' && c != '\n')
31333965Sjdp	sec = NULL;
31433965Sjdp
31533965Sjdp      switch (c)
31633965Sjdp	{
31733965Sjdp	default:
31833965Sjdp	  srec_bad_byte (abfd, lineno, c, error);
31933965Sjdp	  goto error_return;
32033965Sjdp
32133965Sjdp	case '\n':
32233965Sjdp	  ++lineno;
32333965Sjdp	  break;
32433965Sjdp
32533965Sjdp	case '\r':
32633965Sjdp	  break;
32733965Sjdp
32833965Sjdp	case '$':
32933965Sjdp	  /* Starting a module name, which we ignore.  */
33033965Sjdp	  while ((c = srec_get_byte (abfd, &error)) != '\n'
33133965Sjdp		 && c != EOF)
33233965Sjdp	    ;
33333965Sjdp	  if (c == EOF)
33433965Sjdp	    {
33533965Sjdp	      srec_bad_byte (abfd, lineno, c, error);
33633965Sjdp	      goto error_return;
33733965Sjdp	    }
33833965Sjdp
33933965Sjdp	  ++lineno;
34033965Sjdp	  break;
34133965Sjdp
34233965Sjdp	case ' ':
34333965Sjdp	  do
34433965Sjdp	    {
34589857Sobrien	      bfd_size_type alc;
34633965Sjdp	      char *p, *symname;
34733965Sjdp	      bfd_vma symval;
34833965Sjdp
34933965Sjdp	      /* Starting a symbol definition.  */
35033965Sjdp	      while ((c = srec_get_byte (abfd, &error)) != EOF
35133965Sjdp		     && (c == ' ' || c == '\t'))
35233965Sjdp		;
35333965Sjdp
35460484Sobrien	      if (c == '\n' || c == '\r')
35533965Sjdp		break;
35633965Sjdp
35733965Sjdp	      if (c == EOF)
35833965Sjdp		{
35933965Sjdp		  srec_bad_byte (abfd, lineno, c, error);
36033965Sjdp		  goto error_return;
36133965Sjdp		}
36233965Sjdp
36333965Sjdp	      alc = 10;
364218822Sdim	      symbuf = bfd_malloc (alc + 1);
36533965Sjdp	      if (symbuf == NULL)
36633965Sjdp		goto error_return;
36733965Sjdp
36833965Sjdp	      p = symbuf;
36933965Sjdp
37033965Sjdp	      *p++ = c;
37133965Sjdp	      while ((c = srec_get_byte (abfd, &error)) != EOF
37289857Sobrien		     && ! ISSPACE (c))
37333965Sjdp		{
37489857Sobrien		  if ((bfd_size_type) (p - symbuf) >= alc)
37533965Sjdp		    {
37633965Sjdp		      char *n;
37733965Sjdp
37833965Sjdp		      alc *= 2;
379218822Sdim		      n = bfd_realloc (symbuf, alc + 1);
38033965Sjdp		      if (n == NULL)
38133965Sjdp			goto error_return;
38233965Sjdp		      p = n + (p - symbuf);
38333965Sjdp		      symbuf = n;
38433965Sjdp		    }
38533965Sjdp
38633965Sjdp		  *p++ = c;
38733965Sjdp		}
38833965Sjdp
38933965Sjdp	      if (c == EOF)
39033965Sjdp		{
39133965Sjdp		  srec_bad_byte (abfd, lineno, c, error);
39233965Sjdp		  goto error_return;
39333965Sjdp		}
39433965Sjdp
39533965Sjdp	      *p++ = '\0';
39689857Sobrien	      symname = bfd_alloc (abfd, (bfd_size_type) (p - symbuf));
39733965Sjdp	      if (symname == NULL)
39833965Sjdp		goto error_return;
39933965Sjdp	      strcpy (symname, symbuf);
40033965Sjdp	      free (symbuf);
40133965Sjdp	      symbuf = NULL;
40233965Sjdp
40333965Sjdp	      while ((c = srec_get_byte (abfd, &error)) != EOF
40433965Sjdp		     && (c == ' ' || c == '\t'))
40533965Sjdp		;
40633965Sjdp	      if (c == EOF)
40733965Sjdp		{
40833965Sjdp		  srec_bad_byte (abfd, lineno, c, error);
40933965Sjdp		  goto error_return;
41033965Sjdp		}
41133965Sjdp
41233965Sjdp	      /* Skip a dollar sign before the hex value.  */
41333965Sjdp	      if (c == '$')
41433965Sjdp		{
41533965Sjdp		  c = srec_get_byte (abfd, &error);
41633965Sjdp		  if (c == EOF)
41733965Sjdp		    {
41833965Sjdp		      srec_bad_byte (abfd, lineno, c, error);
41933965Sjdp		      goto error_return;
42033965Sjdp		    }
42133965Sjdp		}
42233965Sjdp
42333965Sjdp	      symval = 0;
42433965Sjdp	      while (ISHEX (c))
42533965Sjdp		{
42633965Sjdp		  symval <<= 4;
42733965Sjdp		  symval += NIBBLE (c);
42833965Sjdp		  c = srec_get_byte (abfd, &error);
42933965Sjdp		}
43033965Sjdp
43133965Sjdp	      if (! srec_new_symbol (abfd, symname, symval))
43233965Sjdp		goto error_return;
43333965Sjdp	    }
43477298Sobrien	  while (c == ' ' || c == '\t')
43577298Sobrien	    ;
43633965Sjdp
43760484Sobrien	  if (c == '\n')
43860484Sobrien	    ++lineno;
43960484Sobrien	  else if (c != '\r')
44033965Sjdp	    {
44133965Sjdp	      srec_bad_byte (abfd, lineno, c, error);
44233965Sjdp	      goto error_return;
44333965Sjdp	    }
44433965Sjdp
44533965Sjdp	  break;
44677298Sobrien
44733965Sjdp	case 'S':
44833965Sjdp	  {
44933965Sjdp	    file_ptr pos;
45033965Sjdp	    char hdr[3];
45133965Sjdp	    unsigned int bytes;
45233965Sjdp	    bfd_vma address;
45333965Sjdp	    bfd_byte *data;
45433965Sjdp
45533965Sjdp	    /* Starting an S-record.  */
45633965Sjdp
45733965Sjdp	    pos = bfd_tell (abfd) - 1;
45833965Sjdp
45989857Sobrien	    if (bfd_bread (hdr, (bfd_size_type) 3, abfd) != 3)
46033965Sjdp	      goto error_return;
46133965Sjdp
46233965Sjdp	    if (! ISHEX (hdr[1]) || ! ISHEX (hdr[2]))
46333965Sjdp	      {
46433965Sjdp		if (! ISHEX (hdr[1]))
46533965Sjdp		  c = hdr[1];
46633965Sjdp		else
46733965Sjdp		  c = hdr[2];
46833965Sjdp		srec_bad_byte (abfd, lineno, c, error);
46933965Sjdp		goto error_return;
47033965Sjdp	      }
47133965Sjdp
47233965Sjdp	    bytes = HEX (hdr + 1);
47333965Sjdp	    if (bytes * 2 > bufsize)
47433965Sjdp	      {
47533965Sjdp		if (buf != NULL)
47633965Sjdp		  free (buf);
477218822Sdim		buf = bfd_malloc ((bfd_size_type) bytes * 2);
47833965Sjdp		if (buf == NULL)
47933965Sjdp		  goto error_return;
48033965Sjdp		bufsize = bytes * 2;
48133965Sjdp	      }
48233965Sjdp
48389857Sobrien	    if (bfd_bread (buf, (bfd_size_type) bytes * 2, abfd) != bytes * 2)
48433965Sjdp	      goto error_return;
48533965Sjdp
48633965Sjdp	    /* Ignore the checksum byte.  */
48733965Sjdp	    --bytes;
48833965Sjdp
48933965Sjdp	    address = 0;
49033965Sjdp	    data = buf;
49133965Sjdp	    switch (hdr[0])
49233965Sjdp	      {
49333965Sjdp	      case '0':
49433965Sjdp	      case '5':
49533965Sjdp		/* Prologue--ignore the file name, but stop building a
496130561Sobrien		   section at this point.  */
49733965Sjdp		sec = NULL;
49833965Sjdp		break;
49933965Sjdp
50033965Sjdp	      case '3':
50133965Sjdp		address = HEX (data);
50233965Sjdp		data += 2;
50333965Sjdp		--bytes;
50433965Sjdp		/* Fall through.  */
50533965Sjdp	      case '2':
50633965Sjdp		address = (address << 8) | HEX (data);
50733965Sjdp		data += 2;
50833965Sjdp		--bytes;
50933965Sjdp		/* Fall through.  */
51033965Sjdp	      case '1':
51133965Sjdp		address = (address << 8) | HEX (data);
51233965Sjdp		data += 2;
51333965Sjdp		address = (address << 8) | HEX (data);
51433965Sjdp		data += 2;
51533965Sjdp		bytes -= 2;
51633965Sjdp
51733965Sjdp		if (sec != NULL
518218822Sdim		    && sec->vma + sec->size == address)
51933965Sjdp		  {
52033965Sjdp		    /* This data goes at the end of the section we are
521130561Sobrien		       currently building.  */
522218822Sdim		    sec->size += bytes;
52333965Sjdp		  }
52433965Sjdp		else
52533965Sjdp		  {
52633965Sjdp		    char secbuf[20];
52733965Sjdp		    char *secname;
52889857Sobrien		    bfd_size_type amt;
529218822Sdim		    flagword flags;
53033965Sjdp
53133965Sjdp		    sprintf (secbuf, ".sec%d", bfd_count_sections (abfd) + 1);
53289857Sobrien		    amt = strlen (secbuf) + 1;
533218822Sdim		    secname = bfd_alloc (abfd, amt);
53433965Sjdp		    strcpy (secname, secbuf);
535218822Sdim		    flags = SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC;
536218822Sdim		    sec = bfd_make_section_with_flags (abfd, secname, flags);
53733965Sjdp		    if (sec == NULL)
53833965Sjdp		      goto error_return;
53933965Sjdp		    sec->vma = address;
54033965Sjdp		    sec->lma = address;
541218822Sdim		    sec->size = bytes;
54233965Sjdp		    sec->filepos = pos;
54333965Sjdp		  }
54433965Sjdp		break;
54533965Sjdp
54633965Sjdp	      case '7':
54733965Sjdp		address = HEX (data);
54833965Sjdp		data += 2;
54933965Sjdp		/* Fall through.  */
55033965Sjdp	      case '8':
55133965Sjdp		address = (address << 8) | HEX (data);
55233965Sjdp		data += 2;
55333965Sjdp		/* Fall through.  */
55433965Sjdp	      case '9':
55533965Sjdp		address = (address << 8) | HEX (data);
55633965Sjdp		data += 2;
55733965Sjdp		address = (address << 8) | HEX (data);
55833965Sjdp		data += 2;
55933965Sjdp
56033965Sjdp		/* This is a termination record.  */
56133965Sjdp		abfd->start_address = address;
56233965Sjdp
56333965Sjdp		if (buf != NULL)
56433965Sjdp		  free (buf);
56533965Sjdp
566130561Sobrien		return TRUE;
56733965Sjdp	      }
56833965Sjdp	  }
56933965Sjdp	  break;
57033965Sjdp	}
57133965Sjdp    }
57233965Sjdp
57333965Sjdp  if (error)
57433965Sjdp    goto error_return;
57533965Sjdp
57633965Sjdp  if (buf != NULL)
57733965Sjdp    free (buf);
57833965Sjdp
579130561Sobrien  return TRUE;
58033965Sjdp
58133965Sjdp error_return:
58233965Sjdp  if (symbuf != NULL)
58333965Sjdp    free (symbuf);
58433965Sjdp  if (buf != NULL)
58533965Sjdp    free (buf);
586130561Sobrien  return FALSE;
58733965Sjdp}
58833965Sjdp
58933965Sjdp/* Check whether an existing file is an S-record file.  */
59033965Sjdp
59133965Sjdpstatic const bfd_target *
592218822Sdimsrec_object_p (bfd *abfd)
59333965Sjdp{
594218822Sdim  void * tdata_save;
59533965Sjdp  bfd_byte b[4];
59633965Sjdp
59733965Sjdp  srec_init ();
59833965Sjdp
59933965Sjdp  if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0
60089857Sobrien      || bfd_bread (b, (bfd_size_type) 4, abfd) != 4)
60133965Sjdp    return NULL;
60233965Sjdp
60333965Sjdp  if (b[0] != 'S' || !ISHEX (b[1]) || !ISHEX (b[2]) || !ISHEX (b[3]))
60433965Sjdp    {
60533965Sjdp      bfd_set_error (bfd_error_wrong_format);
60633965Sjdp      return NULL;
60733965Sjdp    }
60833965Sjdp
609104834Sobrien  tdata_save = abfd->tdata.any;
610104834Sobrien  if (! srec_mkobject (abfd) || ! srec_scan (abfd))
611104834Sobrien    {
612104834Sobrien      if (abfd->tdata.any != tdata_save && abfd->tdata.any != NULL)
613104834Sobrien	bfd_release (abfd, abfd->tdata.any);
614104834Sobrien      abfd->tdata.any = tdata_save;
615104834Sobrien      return NULL;
616104834Sobrien    }
61733965Sjdp
61860484Sobrien  if (abfd->symcount > 0)
61960484Sobrien    abfd->flags |= HAS_SYMS;
62060484Sobrien
62133965Sjdp  return abfd->xvec;
62233965Sjdp}
62333965Sjdp
62433965Sjdp/* Check whether an existing file is an S-record file with symbols.  */
62533965Sjdp
62633965Sjdpstatic const bfd_target *
627218822Sdimsymbolsrec_object_p (bfd *abfd)
62833965Sjdp{
629218822Sdim  void * tdata_save;
63033965Sjdp  char b[2];
63133965Sjdp
63233965Sjdp  srec_init ();
63333965Sjdp
63433965Sjdp  if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0
63589857Sobrien      || bfd_bread (b, (bfd_size_type) 2, abfd) != 2)
63633965Sjdp    return NULL;
63733965Sjdp
63833965Sjdp  if (b[0] != '$' || b[1] != '$')
63933965Sjdp    {
64033965Sjdp      bfd_set_error (bfd_error_wrong_format);
64133965Sjdp      return NULL;
64233965Sjdp    }
64333965Sjdp
644104834Sobrien  tdata_save = abfd->tdata.any;
645104834Sobrien  if (! srec_mkobject (abfd) || ! srec_scan (abfd))
646104834Sobrien    {
647104834Sobrien      if (abfd->tdata.any != tdata_save && abfd->tdata.any != NULL)
648104834Sobrien	bfd_release (abfd, abfd->tdata.any);
649104834Sobrien      abfd->tdata.any = tdata_save;
650104834Sobrien      return NULL;
651104834Sobrien    }
65233965Sjdp
65360484Sobrien  if (abfd->symcount > 0)
65460484Sobrien    abfd->flags |= HAS_SYMS;
65560484Sobrien
65633965Sjdp  return abfd->xvec;
65733965Sjdp}
65833965Sjdp
65933965Sjdp/* Read in the contents of a section in an S-record file.  */
66033965Sjdp
661130561Sobrienstatic bfd_boolean
662218822Sdimsrec_read_section (bfd *abfd, asection *section, bfd_byte *contents)
66333965Sjdp{
66433965Sjdp  int c;
66533965Sjdp  bfd_size_type sofar = 0;
666130561Sobrien  bfd_boolean error = FALSE;
66733965Sjdp  bfd_byte *buf = NULL;
66833965Sjdp  size_t bufsize = 0;
66933965Sjdp
67033965Sjdp  if (bfd_seek (abfd, section->filepos, SEEK_SET) != 0)
67133965Sjdp    goto error_return;
67233965Sjdp
67333965Sjdp  while ((c = srec_get_byte (abfd, &error)) != EOF)
67433965Sjdp    {
67533965Sjdp      bfd_byte hdr[3];
67633965Sjdp      unsigned int bytes;
67733965Sjdp      bfd_vma address;
67833965Sjdp      bfd_byte *data;
67933965Sjdp
68033965Sjdp      if (c == '\r' || c == '\n')
68133965Sjdp	continue;
68233965Sjdp
68333965Sjdp      /* This is called after srec_scan has already been called, so we
684130561Sobrien	 ought to know the exact format.  */
68533965Sjdp      BFD_ASSERT (c == 'S');
68633965Sjdp
68789857Sobrien      if (bfd_bread (hdr, (bfd_size_type) 3, abfd) != 3)
68833965Sjdp	goto error_return;
68933965Sjdp
69033965Sjdp      BFD_ASSERT (ISHEX (hdr[1]) && ISHEX (hdr[2]));
69133965Sjdp
69233965Sjdp      bytes = HEX (hdr + 1);
69333965Sjdp
69433965Sjdp      if (bytes * 2 > bufsize)
69533965Sjdp	{
69633965Sjdp	  if (buf != NULL)
69733965Sjdp	    free (buf);
698218822Sdim	  buf = bfd_malloc ((bfd_size_type) bytes * 2);
69933965Sjdp	  if (buf == NULL)
70033965Sjdp	    goto error_return;
70133965Sjdp	  bufsize = bytes * 2;
70233965Sjdp	}
70333965Sjdp
70489857Sobrien      if (bfd_bread (buf, (bfd_size_type) bytes * 2, abfd) != bytes * 2)
70533965Sjdp	goto error_return;
70633965Sjdp
70733965Sjdp      address = 0;
70833965Sjdp      data = buf;
70933965Sjdp      switch (hdr[0])
71033965Sjdp	{
71133965Sjdp	default:
712218822Sdim	  BFD_ASSERT (sofar == section->size);
71333965Sjdp	  if (buf != NULL)
71433965Sjdp	    free (buf);
715130561Sobrien	  return TRUE;
71633965Sjdp
71733965Sjdp	case '3':
71833965Sjdp	  address = HEX (data);
71933965Sjdp	  data += 2;
72033965Sjdp	  --bytes;
72133965Sjdp	  /* Fall through.  */
72233965Sjdp	case '2':
72333965Sjdp	  address = (address << 8) | HEX (data);
72433965Sjdp	  data += 2;
72533965Sjdp	  --bytes;
72633965Sjdp	  /* Fall through.  */
72733965Sjdp	case '1':
72833965Sjdp	  address = (address << 8) | HEX (data);
72933965Sjdp	  data += 2;
73033965Sjdp	  address = (address << 8) | HEX (data);
73133965Sjdp	  data += 2;
73233965Sjdp	  bytes -= 2;
73333965Sjdp
73433965Sjdp	  if (address != section->vma + sofar)
73533965Sjdp	    {
73633965Sjdp	      /* We've come to the end of this section.  */
737218822Sdim	      BFD_ASSERT (sofar == section->size);
73833965Sjdp	      if (buf != NULL)
73933965Sjdp		free (buf);
740130561Sobrien	      return TRUE;
74133965Sjdp	    }
74233965Sjdp
74333965Sjdp	  /* Don't consider checksum.  */
74433965Sjdp	  --bytes;
74533965Sjdp
74633965Sjdp	  while (bytes-- != 0)
74733965Sjdp	    {
74833965Sjdp	      contents[sofar] = HEX (data);
74933965Sjdp	      data += 2;
75033965Sjdp	      ++sofar;
75133965Sjdp	    }
75233965Sjdp
75333965Sjdp	  break;
75433965Sjdp	}
75533965Sjdp    }
75633965Sjdp
75733965Sjdp  if (error)
75833965Sjdp    goto error_return;
75933965Sjdp
760218822Sdim  BFD_ASSERT (sofar == section->size);
76133965Sjdp
76233965Sjdp  if (buf != NULL)
76333965Sjdp    free (buf);
76433965Sjdp
765130561Sobrien  return TRUE;
76633965Sjdp
76733965Sjdp error_return:
76833965Sjdp  if (buf != NULL)
76933965Sjdp    free (buf);
770130561Sobrien  return FALSE;
77133965Sjdp}
77233965Sjdp
77333965Sjdp/* Get the contents of a section in an S-record file.  */
77433965Sjdp
775130561Sobrienstatic bfd_boolean
776218822Sdimsrec_get_section_contents (bfd *abfd,
777218822Sdim			   asection *section,
778218822Sdim			   void * location,
779218822Sdim			   file_ptr offset,
780218822Sdim			   bfd_size_type count)
78133965Sjdp{
78233965Sjdp  if (section->used_by_bfd == NULL)
78333965Sjdp    {
784218822Sdim      section->used_by_bfd = bfd_alloc (abfd, section->size);
785218822Sdim      if (section->used_by_bfd == NULL && section->size != 0)
786130561Sobrien	return FALSE;
78733965Sjdp
78833965Sjdp      if (! srec_read_section (abfd, section, section->used_by_bfd))
789130561Sobrien	return FALSE;
79033965Sjdp    }
79133965Sjdp
79233965Sjdp  memcpy (location, (bfd_byte *) section->used_by_bfd + offset,
79333965Sjdp	  (size_t) count);
79433965Sjdp
795130561Sobrien  return TRUE;
79633965Sjdp}
79733965Sjdp
79833965Sjdp/* Set the architecture.  We accept an unknown architecture here.  */
79933965Sjdp
800130561Sobrienstatic bfd_boolean
801218822Sdimsrec_set_arch_mach (bfd *abfd, enum bfd_architecture arch, unsigned long mach)
80233965Sjdp{
803218822Sdim  if (arch != bfd_arch_unknown)
804218822Sdim    return bfd_default_set_arch_mach (abfd, arch, mach);
805218822Sdim
806218822Sdim  abfd->arch_info = & bfd_default_arch_struct;
807218822Sdim  return TRUE;
80833965Sjdp}
80933965Sjdp
81077298Sobrien/* We have to save up all the Srecords for a splurge before output.  */
81133965Sjdp
812130561Sobrienstatic bfd_boolean
813218822Sdimsrec_set_section_contents (bfd *abfd,
814218822Sdim			   sec_ptr section,
815218822Sdim			   const void * location,
816218822Sdim			   file_ptr offset,
817218822Sdim			   bfd_size_type bytes_to_do)
81833965Sjdp{
81933965Sjdp  tdata_type *tdata = abfd->tdata.srec_data;
820218822Sdim  srec_data_list_type *entry;
82133965Sjdp
822218822Sdim  entry = bfd_alloc (abfd, sizeof (* entry));
82333965Sjdp  if (entry == NULL)
824130561Sobrien    return FALSE;
82533965Sjdp
82633965Sjdp  if (bytes_to_do
82733965Sjdp      && (section->flags & SEC_ALLOC)
82833965Sjdp      && (section->flags & SEC_LOAD))
82933965Sjdp    {
83089857Sobrien      bfd_byte *data;
83189857Sobrien
832218822Sdim      data = bfd_alloc (abfd, bytes_to_do);
83333965Sjdp      if (data == NULL)
834130561Sobrien	return FALSE;
835218822Sdim      memcpy ((void *) data, location, (size_t) bytes_to_do);
83633965Sjdp
837130561Sobrien      /* Ff S3Forced is TRUE then always select S3 records,
83877298Sobrien	 regardless of the siez of the addresses.  */
83977298Sobrien      if (S3Forced)
84077298Sobrien	tdata->type = 3;
84177298Sobrien      else if ((section->lma + offset + bytes_to_do - 1) <= 0xffff)
84277298Sobrien	;  /* The default, S1, is OK.  */
84333965Sjdp      else if ((section->lma + offset + bytes_to_do - 1) <= 0xffffff
84460484Sobrien	       && tdata->type <= 2)
84577298Sobrien	tdata->type = 2;
84633965Sjdp      else
84777298Sobrien	tdata->type = 3;
84833965Sjdp
84933965Sjdp      entry->data = data;
85033965Sjdp      entry->where = section->lma + offset;
85133965Sjdp      entry->size = bytes_to_do;
85233965Sjdp
85333965Sjdp      /* Sort the records by address.  Optimize for the common case of
854130561Sobrien	 adding a record to the end of the list.  */
85533965Sjdp      if (tdata->tail != NULL
85633965Sjdp	  && entry->where >= tdata->tail->where)
85733965Sjdp	{
85833965Sjdp	  tdata->tail->next = entry;
85933965Sjdp	  entry->next = NULL;
86033965Sjdp	  tdata->tail = entry;
86133965Sjdp	}
86233965Sjdp      else
86333965Sjdp	{
864218822Sdim	  srec_data_list_type **look;
86533965Sjdp
86633965Sjdp	  for (look = &tdata->head;
86733965Sjdp	       *look != NULL && (*look)->where < entry->where;
86833965Sjdp	       look = &(*look)->next)
86933965Sjdp	    ;
87033965Sjdp	  entry->next = *look;
87133965Sjdp	  *look = entry;
87233965Sjdp	  if (entry->next == NULL)
87333965Sjdp	    tdata->tail = entry;
87433965Sjdp	}
87533965Sjdp    }
876130561Sobrien  return TRUE;
87733965Sjdp}
87833965Sjdp
87933965Sjdp/* Write a record of type, of the supplied number of bytes. The
88033965Sjdp   supplied bytes and length don't have a checksum. That's worked out
88177298Sobrien   here.  */
88277298Sobrien
883130561Sobrienstatic bfd_boolean
884218822Sdimsrec_write_record (bfd *abfd,
885218822Sdim		   unsigned int type,
886218822Sdim		   bfd_vma address,
887218822Sdim		   const bfd_byte *data,
888218822Sdim		   const bfd_byte *end)
88933965Sjdp{
89094536Sobrien  char buffer[2 * MAXCHUNK + 6];
89133965Sjdp  unsigned int check_sum = 0;
89289857Sobrien  const bfd_byte *src = data;
89333965Sjdp  char *dst = buffer;
89433965Sjdp  char *length;
89533965Sjdp  bfd_size_type wrlen;
89633965Sjdp
89733965Sjdp  *dst++ = 'S';
89833965Sjdp  *dst++ = '0' + type;
89933965Sjdp
90033965Sjdp  length = dst;
90177298Sobrien  dst += 2;			/* Leave room for dst.  */
90233965Sjdp
90333965Sjdp  switch (type)
90433965Sjdp    {
90533965Sjdp    case 3:
90633965Sjdp    case 7:
90733965Sjdp      TOHEX (dst, (address >> 24), check_sum);
90833965Sjdp      dst += 2;
90933965Sjdp    case 8:
91033965Sjdp    case 2:
91133965Sjdp      TOHEX (dst, (address >> 16), check_sum);
91233965Sjdp      dst += 2;
91333965Sjdp    case 9:
91433965Sjdp    case 1:
91533965Sjdp    case 0:
91633965Sjdp      TOHEX (dst, (address >> 8), check_sum);
91733965Sjdp      dst += 2;
91833965Sjdp      TOHEX (dst, (address), check_sum);
91933965Sjdp      dst += 2;
92033965Sjdp      break;
92133965Sjdp
92233965Sjdp    }
92333965Sjdp  for (src = data; src < end; src++)
92433965Sjdp    {
92533965Sjdp      TOHEX (dst, *src, check_sum);
92633965Sjdp      dst += 2;
92733965Sjdp    }
92833965Sjdp
92977298Sobrien  /* Fill in the length.  */
93033965Sjdp  TOHEX (length, (dst - length) / 2, check_sum);
93133965Sjdp  check_sum &= 0xff;
93233965Sjdp  check_sum = 255 - check_sum;
93333965Sjdp  TOHEX (dst, check_sum, check_sum);
93433965Sjdp  dst += 2;
93533965Sjdp
93633965Sjdp  *dst++ = '\r';
93733965Sjdp  *dst++ = '\n';
93833965Sjdp  wrlen = dst - buffer;
939218822Sdim
940218822Sdim  return bfd_bwrite ((void *) buffer, wrlen, abfd) == wrlen;
94133965Sjdp}
94233965Sjdp
943130561Sobrienstatic bfd_boolean
944218822Sdimsrec_write_header (bfd *abfd)
94533965Sjdp{
94694536Sobrien  unsigned int len = strlen (abfd->filename);
94733965Sjdp
948130561Sobrien  /* I'll put an arbitrary 40 char limit on header size.  */
94994536Sobrien  if (len > 40)
95094536Sobrien    len = 40;
95177298Sobrien
95294536Sobrien  return srec_write_record (abfd, 0, (bfd_vma) 0,
953218822Sdim			    (bfd_byte *) abfd->filename,
954218822Sdim			    (bfd_byte *) abfd->filename + len);
95533965Sjdp}
95633965Sjdp
957130561Sobrienstatic bfd_boolean
958218822Sdimsrec_write_section (bfd *abfd,
959218822Sdim		    tdata_type *tdata,
960218822Sdim		    srec_data_list_type *list)
96133965Sjdp{
96260484Sobrien  unsigned int octets_written = 0;
96333965Sjdp  bfd_byte *location = list->data;
96433965Sjdp
96594536Sobrien  /* Validate number of data bytes to write.  The srec length byte
96694536Sobrien     counts the address, data and crc bytes.  S1 (tdata->type == 1)
96794536Sobrien     records have two address bytes, S2 (tdata->type == 2) records
96894536Sobrien     have three, and S3 (tdata->type == 3) records have four.
96994536Sobrien     The total length can't exceed 255, and a zero data length will
97094536Sobrien     spin for a long time.  */
97194536Sobrien  if (Chunk == 0)
97294536Sobrien    Chunk = 1;
97394536Sobrien  else if (Chunk > MAXCHUNK - tdata->type - 2)
97494536Sobrien    Chunk = MAXCHUNK - tdata->type - 2;
97594536Sobrien
97660484Sobrien  while (octets_written < list->size)
97733965Sjdp    {
97833965Sjdp      bfd_vma address;
97960484Sobrien      unsigned int octets_this_chunk = list->size - octets_written;
98033965Sjdp
98177298Sobrien      if (octets_this_chunk > Chunk)
98277298Sobrien	octets_this_chunk = Chunk;
98333965Sjdp
98460484Sobrien      address = list->where + octets_written / bfd_octets_per_byte (abfd);
98533965Sjdp
98633965Sjdp      if (! srec_write_record (abfd,
98733965Sjdp			       tdata->type,
98833965Sjdp			       address,
98933965Sjdp			       location,
99060484Sobrien			       location + octets_this_chunk))
991130561Sobrien	return FALSE;
99233965Sjdp
99360484Sobrien      octets_written += octets_this_chunk;
99460484Sobrien      location += octets_this_chunk;
99533965Sjdp    }
99633965Sjdp
997130561Sobrien  return TRUE;
99833965Sjdp}
99933965Sjdp
1000130561Sobrienstatic bfd_boolean
1001218822Sdimsrec_write_terminator (bfd *abfd, tdata_type *tdata)
100233965Sjdp{
100333965Sjdp  return srec_write_record (abfd, 10 - tdata->type,
100494536Sobrien			    abfd->start_address, NULL, NULL);
100533965Sjdp}
100633965Sjdp
1007130561Sobrienstatic bfd_boolean
1008218822Sdimsrec_write_symbols (bfd *abfd)
100933965Sjdp{
101077298Sobrien  /* Dump out the symbols of a bfd.  */
101133965Sjdp  int i;
101233965Sjdp  int count = bfd_get_symcount (abfd);
101333965Sjdp
101433965Sjdp  if (count)
101533965Sjdp    {
101689857Sobrien      bfd_size_type len;
101733965Sjdp      asymbol **table = bfd_get_outsymbols (abfd);
1018218822Sdim
101994536Sobrien      len = strlen (abfd->filename);
102094536Sobrien      if (bfd_bwrite ("$$ ", (bfd_size_type) 3, abfd) != 3
102194536Sobrien	  || bfd_bwrite (abfd->filename, len, abfd) != len
102294536Sobrien	  || bfd_bwrite ("\r\n", (bfd_size_type) 2, abfd) != 2)
1023130561Sobrien	return FALSE;
102433965Sjdp
102533965Sjdp      for (i = 0; i < count; i++)
102633965Sjdp	{
102733965Sjdp	  asymbol *s = table[i];
102860484Sobrien	  if (! bfd_is_local_label (abfd, s)
102960484Sobrien	      && (s->flags & BSF_DEBUGGING) == 0)
103033965Sjdp	    {
103177298Sobrien	      /* Just dump out non debug symbols.  */
1032130561Sobrien	      char buf[43], *p;
103333965Sjdp
103494536Sobrien	      len = strlen (s->name);
103594536Sobrien	      if (bfd_bwrite ("  ", (bfd_size_type) 2, abfd) != 2
103694536Sobrien		  || bfd_bwrite (s->name, len, abfd) != len)
1037130561Sobrien		return FALSE;
103894536Sobrien
1039130561Sobrien	      sprintf_vma (buf + 2, (s->value
104094536Sobrien				     + s->section->output_section->lma
104194536Sobrien				     + s->section->output_offset));
1042130561Sobrien	      p = buf + 2;
104333965Sjdp	      while (p[0] == '0' && p[1] != 0)
104433965Sjdp		p++;
104594536Sobrien	      len = strlen (p);
104694536Sobrien	      p[len] = '\r';
104794536Sobrien	      p[len + 1] = '\n';
1048130561Sobrien	      *--p = '$';
104994536Sobrien	      *--p = ' ';
1050130561Sobrien	      len += 4;
105194536Sobrien	      if (bfd_bwrite (p, len, abfd) != len)
1052130561Sobrien		return FALSE;
105333965Sjdp	    }
105433965Sjdp	}
105594536Sobrien      if (bfd_bwrite ("$$ \r\n", (bfd_size_type) 5, abfd) != 5)
1056130561Sobrien	return FALSE;
105733965Sjdp    }
105833965Sjdp
1059130561Sobrien  return TRUE;
106033965Sjdp}
106133965Sjdp
1062130561Sobrienstatic bfd_boolean
1063218822Sdiminternal_srec_write_object_contents (bfd *abfd, int symbols)
106433965Sjdp{
106533965Sjdp  tdata_type *tdata = abfd->tdata.srec_data;
106633965Sjdp  srec_data_list_type *list;
106733965Sjdp
106833965Sjdp  if (symbols)
106933965Sjdp    {
107033965Sjdp      if (! srec_write_symbols (abfd))
1071130561Sobrien	return FALSE;
107233965Sjdp    }
107333965Sjdp
107433965Sjdp  if (! srec_write_header (abfd))
1075130561Sobrien    return FALSE;
107633965Sjdp
107777298Sobrien  /* Now wander though all the sections provided and output them.  */
107833965Sjdp  list = tdata->head;
107933965Sjdp
108033965Sjdp  while (list != (srec_data_list_type *) NULL)
108133965Sjdp    {
108233965Sjdp      if (! srec_write_section (abfd, tdata, list))
1083130561Sobrien	return FALSE;
108433965Sjdp      list = list->next;
108533965Sjdp    }
108633965Sjdp  return srec_write_terminator (abfd, tdata);
108733965Sjdp}
108833965Sjdp
1089130561Sobrienstatic bfd_boolean
1090218822Sdimsrec_write_object_contents (bfd *abfd)
109133965Sjdp{
109233965Sjdp  return internal_srec_write_object_contents (abfd, 0);
109333965Sjdp}
109433965Sjdp
1095130561Sobrienstatic bfd_boolean
1096218822Sdimsymbolsrec_write_object_contents (bfd *abfd)
109733965Sjdp{
109833965Sjdp  return internal_srec_write_object_contents (abfd, 1);
109933965Sjdp}
110033965Sjdp
110133965Sjdpstatic int
1102218822Sdimsrec_sizeof_headers (bfd *abfd ATTRIBUTE_UNUSED,
1103218822Sdim		     struct bfd_link_info *info ATTRIBUTE_UNUSED)
110433965Sjdp{
110533965Sjdp  return 0;
110633965Sjdp}
110733965Sjdp
110833965Sjdp/* Return the amount of memory needed to read the symbol table.  */
110933965Sjdp
111033965Sjdpstatic long
1111218822Sdimsrec_get_symtab_upper_bound (bfd *abfd)
111233965Sjdp{
111333965Sjdp  return (bfd_get_symcount (abfd) + 1) * sizeof (asymbol *);
111433965Sjdp}
111533965Sjdp
111633965Sjdp/* Return the symbol table.  */
111733965Sjdp
111833965Sjdpstatic long
1119218822Sdimsrec_canonicalize_symtab (bfd *abfd, asymbol **alocation)
112033965Sjdp{
112189857Sobrien  bfd_size_type symcount = bfd_get_symcount (abfd);
112233965Sjdp  asymbol *csymbols;
112333965Sjdp  unsigned int i;
112433965Sjdp
112533965Sjdp  csymbols = abfd->tdata.srec_data->csymbols;
112633965Sjdp  if (csymbols == NULL)
112733965Sjdp    {
112833965Sjdp      asymbol *c;
112933965Sjdp      struct srec_symbol *s;
113033965Sjdp
1131218822Sdim      csymbols = bfd_alloc (abfd, symcount * sizeof (asymbol));
113233965Sjdp      if (csymbols == NULL && symcount != 0)
1133130561Sobrien	return 0;
113433965Sjdp      abfd->tdata.srec_data->csymbols = csymbols;
113533965Sjdp
113633965Sjdp      for (s = abfd->tdata.srec_data->symbols, c = csymbols;
113733965Sjdp	   s != NULL;
113833965Sjdp	   s = s->next, ++c)
113933965Sjdp	{
114033965Sjdp	  c->the_bfd = abfd;
114133965Sjdp	  c->name = s->name;
114233965Sjdp	  c->value = s->val;
114333965Sjdp	  c->flags = BSF_GLOBAL;
114433965Sjdp	  c->section = bfd_abs_section_ptr;
114533965Sjdp	  c->udata.p = NULL;
114633965Sjdp	}
114733965Sjdp    }
114877298Sobrien
114933965Sjdp  for (i = 0; i < symcount; i++)
115033965Sjdp    *alocation++ = csymbols++;
115133965Sjdp  *alocation = NULL;
115233965Sjdp
115333965Sjdp  return symcount;
115433965Sjdp}
115533965Sjdp
115633965Sjdpstatic void
1157218822Sdimsrec_get_symbol_info (bfd *ignore_abfd ATTRIBUTE_UNUSED,
1158218822Sdim		      asymbol *symbol,
1159218822Sdim		      symbol_info *ret)
116033965Sjdp{
116133965Sjdp  bfd_symbol_info (symbol, ret);
116233965Sjdp}
116333965Sjdp
116433965Sjdpstatic void
1165218822Sdimsrec_print_symbol (bfd *abfd,
1166218822Sdim		   void * afile,
1167218822Sdim		   asymbol *symbol,
1168218822Sdim		   bfd_print_symbol_type how)
116933965Sjdp{
117033965Sjdp  FILE *file = (FILE *) afile;
1171218822Sdim
117233965Sjdp  switch (how)
117333965Sjdp    {
117433965Sjdp    case bfd_print_symbol_name:
117533965Sjdp      fprintf (file, "%s", symbol->name);
117633965Sjdp      break;
117733965Sjdp    default:
1178218822Sdim      bfd_print_symbol_vandf (abfd, (void *) file, symbol);
117933965Sjdp      fprintf (file, " %-5s %s",
118033965Sjdp	       symbol->section->name,
118133965Sjdp	       symbol->name);
118233965Sjdp    }
118333965Sjdp}
118433965Sjdp
1185218822Sdim#define	srec_close_and_cleanup                    _bfd_generic_close_and_cleanup
1186218822Sdim#define srec_bfd_free_cached_info                 _bfd_generic_bfd_free_cached_info
1187218822Sdim#define srec_new_section_hook                     _bfd_generic_new_section_hook
1188218822Sdim#define srec_bfd_is_target_special_symbol         ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false)
1189218822Sdim#define srec_bfd_is_local_label_name              bfd_generic_is_local_label_name
1190218822Sdim#define srec_get_lineno                           _bfd_nosymbols_get_lineno
1191218822Sdim#define srec_find_nearest_line                    _bfd_nosymbols_find_nearest_line
1192218822Sdim#define srec_find_inliner_info                    _bfd_nosymbols_find_inliner_info
1193218822Sdim#define srec_make_empty_symbol                    _bfd_generic_make_empty_symbol
1194218822Sdim#define srec_bfd_make_debug_symbol                _bfd_nosymbols_bfd_make_debug_symbol
1195218822Sdim#define srec_read_minisymbols                     _bfd_generic_read_minisymbols
1196218822Sdim#define srec_minisymbol_to_symbol                 _bfd_generic_minisymbol_to_symbol
1197218822Sdim#define srec_get_section_contents_in_window       _bfd_generic_get_section_contents_in_window
1198218822Sdim#define srec_bfd_get_relocated_section_contents   bfd_generic_get_relocated_section_contents
1199218822Sdim#define srec_bfd_relax_section                    bfd_generic_relax_section
1200218822Sdim#define srec_bfd_gc_sections                      bfd_generic_gc_sections
1201218822Sdim#define srec_bfd_merge_sections                   bfd_generic_merge_sections
1202218822Sdim#define srec_bfd_is_group_section                 bfd_generic_is_group_section
1203218822Sdim#define srec_bfd_discard_group                    bfd_generic_discard_group
1204218822Sdim#define srec_section_already_linked               _bfd_generic_section_already_linked
1205218822Sdim#define srec_bfd_link_hash_table_create           _bfd_generic_link_hash_table_create
1206218822Sdim#define srec_bfd_link_hash_table_free             _bfd_generic_link_hash_table_free
1207218822Sdim#define srec_bfd_link_add_symbols                 _bfd_generic_link_add_symbols
1208218822Sdim#define srec_bfd_link_just_syms                   _bfd_generic_link_just_syms
1209218822Sdim#define srec_bfd_final_link                       _bfd_generic_final_link
1210218822Sdim#define srec_bfd_link_split_section               _bfd_generic_link_split_section
121133965Sjdp
121233965Sjdpconst bfd_target srec_vec =
121333965Sjdp{
1214218822Sdim  "srec",			/* Name.  */
121533965Sjdp  bfd_target_srec_flavour,
1216218822Sdim  BFD_ENDIAN_UNKNOWN,		/* Target byte order.  */
1217218822Sdim  BFD_ENDIAN_UNKNOWN,		/* Target headers byte order.  */
1218218822Sdim  (HAS_RELOC | EXEC_P |		/* Object flags.  */
121933965Sjdp   HAS_LINENO | HAS_DEBUG |
122033965Sjdp   HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
122133965Sjdp  (SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS
1222218822Sdim   | SEC_ALLOC | SEC_LOAD | SEC_RELOC),	/* Section flags.  */
1223218822Sdim  0,				/* Leading underscore.  */
1224218822Sdim  ' ',				/* AR_pad_char.  */
1225218822Sdim  16,				/* AR_max_namelen.  */
122633965Sjdp  bfd_getb64, bfd_getb_signed_64, bfd_putb64,
122733965Sjdp  bfd_getb32, bfd_getb_signed_32, bfd_putb32,
1228218822Sdim  bfd_getb16, bfd_getb_signed_16, bfd_putb16,	/* Data.  */
122933965Sjdp  bfd_getb64, bfd_getb_signed_64, bfd_putb64,
123033965Sjdp  bfd_getb32, bfd_getb_signed_32, bfd_putb32,
1231218822Sdim  bfd_getb16, bfd_getb_signed_16, bfd_putb16,	/* Hdrs.  */
123233965Sjdp
123333965Sjdp  {
123433965Sjdp    _bfd_dummy_target,
1235218822Sdim    srec_object_p,		/* bfd_check_format.  */
123633965Sjdp    _bfd_dummy_target,
123733965Sjdp    _bfd_dummy_target,
123833965Sjdp  },
123933965Sjdp  {
124033965Sjdp    bfd_false,
124133965Sjdp    srec_mkobject,
124233965Sjdp    _bfd_generic_mkarchive,
124333965Sjdp    bfd_false,
124433965Sjdp  },
1245218822Sdim  {				/* bfd_write_contents.  */
124633965Sjdp    bfd_false,
124733965Sjdp    srec_write_object_contents,
124833965Sjdp    _bfd_write_archive_contents,
124933965Sjdp    bfd_false,
125033965Sjdp  },
125133965Sjdp
125233965Sjdp  BFD_JUMP_TABLE_GENERIC (srec),
125333965Sjdp  BFD_JUMP_TABLE_COPY (_bfd_generic),
125433965Sjdp  BFD_JUMP_TABLE_CORE (_bfd_nocore),
125533965Sjdp  BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
125633965Sjdp  BFD_JUMP_TABLE_SYMBOLS (srec),
1257218822Sdim  BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
125833965Sjdp  BFD_JUMP_TABLE_WRITE (srec),
125933965Sjdp  BFD_JUMP_TABLE_LINK (srec),
126033965Sjdp  BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
126133965Sjdp
126260484Sobrien  NULL,
126377298Sobrien
1264218822Sdim  NULL
126533965Sjdp};
126633965Sjdp
126733965Sjdpconst bfd_target symbolsrec_vec =
126833965Sjdp{
1269218822Sdim  "symbolsrec",			/* Name.  */
127033965Sjdp  bfd_target_srec_flavour,
1271218822Sdim  BFD_ENDIAN_UNKNOWN,		/* Target byte order.  */
1272218822Sdim  BFD_ENDIAN_UNKNOWN,		/* Target headers byte order.  */
1273218822Sdim  (HAS_RELOC | EXEC_P |		/* Object flags.  */
127433965Sjdp   HAS_LINENO | HAS_DEBUG |
127533965Sjdp   HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
127633965Sjdp  (SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS
1277218822Sdim   | SEC_ALLOC | SEC_LOAD | SEC_RELOC),	/* Section flags.  */
1278218822Sdim  0,				/* Leading underscore.  */
1279218822Sdim  ' ',				/* AR_pad_char.  */
1280218822Sdim  16,				/* AR_max_namelen.  */
128133965Sjdp  bfd_getb64, bfd_getb_signed_64, bfd_putb64,
128233965Sjdp  bfd_getb32, bfd_getb_signed_32, bfd_putb32,
1283218822Sdim  bfd_getb16, bfd_getb_signed_16, bfd_putb16,	/* Data.  */
128433965Sjdp  bfd_getb64, bfd_getb_signed_64, bfd_putb64,
128533965Sjdp  bfd_getb32, bfd_getb_signed_32, bfd_putb32,
1286218822Sdim  bfd_getb16, bfd_getb_signed_16, bfd_putb16,	/* Headers.  */
128733965Sjdp
128833965Sjdp  {
128933965Sjdp    _bfd_dummy_target,
1290218822Sdim    symbolsrec_object_p,	/* bfd_check_format.  */
129133965Sjdp    _bfd_dummy_target,
129233965Sjdp    _bfd_dummy_target,
129333965Sjdp  },
129433965Sjdp  {
129533965Sjdp    bfd_false,
129633965Sjdp    srec_mkobject,
129733965Sjdp    _bfd_generic_mkarchive,
129833965Sjdp    bfd_false,
129933965Sjdp  },
1300218822Sdim  {				/* bfd_write_contents.  */
130133965Sjdp    bfd_false,
130233965Sjdp    symbolsrec_write_object_contents,
130333965Sjdp    _bfd_write_archive_contents,
130433965Sjdp    bfd_false,
130533965Sjdp  },
130633965Sjdp
130733965Sjdp  BFD_JUMP_TABLE_GENERIC (srec),
130833965Sjdp  BFD_JUMP_TABLE_COPY (_bfd_generic),
130933965Sjdp  BFD_JUMP_TABLE_CORE (_bfd_nocore),
131033965Sjdp  BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
131133965Sjdp  BFD_JUMP_TABLE_SYMBOLS (srec),
1312218822Sdim  BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
131333965Sjdp  BFD_JUMP_TABLE_WRITE (srec),
131433965Sjdp  BFD_JUMP_TABLE_LINK (srec),
131533965Sjdp  BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
131633965Sjdp
131760484Sobrien  NULL,
131877298Sobrien
1319218822Sdim  NULL
132033965Sjdp};
1321