srec.c revision 38889
133965Sjdp/* BFD back-end for s-record objects.
238889Sjdp   Copyright 1990, 91, 92, 93, 94, 95, 96, 97, 1998
338889Sjdp   Free Software Foundation, Inc.
433965Sjdp   Written by Steve Chamberlain of Cygnus Support <sac@cygnus.com>.
533965Sjdp
633965SjdpThis file is part of BFD, the Binary File Descriptor library.
733965Sjdp
833965SjdpThis program is free software; you can redistribute it and/or modify
933965Sjdpit under the terms of the GNU General Public License as published by
1033965Sjdpthe Free Software Foundation; either version 2 of the License, or
1133965Sjdp(at your option) any later version.
1233965Sjdp
1333965SjdpThis program is distributed in the hope that it will be useful,
1433965Sjdpbut WITHOUT ANY WARRANTY; without even the implied warranty of
1533965SjdpMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1633965SjdpGNU General Public License for more details.
1733965Sjdp
1833965SjdpYou should have received a copy of the GNU General Public License
1933965Sjdpalong with this program; if not, write to the Free Software
2033965SjdpFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
2133965Sjdp
2233965Sjdp/*
2333965SjdpSUBSECTION
2433965Sjdp	S-Record handling
2533965Sjdp
2633965SjdpDESCRIPTION
2733965Sjdp
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:
4533965Sjdp
4633965SjdpEXAMPLE
4733965Sjdp	S<type><length><address><data><checksum>
4833965Sjdp
4933965SjdpDESCRIPTION
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
6433965Sjdp
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
7433965Sjdp
7533965SjdpSUBSECTION
7633965Sjdp	Symbol S-Record handling
7733965Sjdp
7833965SjdpDESCRIPTION
7933965Sjdp	Some ICE equipment understands an addition to the standard
8033965Sjdp	S-Record format; symbols and their addresses can be sent
8133965Sjdp	before the data.
8233965Sjdp
8333965Sjdp	The format of this is:
8433965Sjdp	($$ <modulename>
8533965Sjdp		(<space> <symbol> <address>)*)
8633965Sjdp	$$
8733965Sjdp
8833965Sjdp	so a short symbol table could look like:
8933965Sjdp
9033965SjdpEXAMPLE
9133965Sjdp	$$ flash.x
9233965Sjdp	$$ flash.c
9333965Sjdp	  _port6 $0
9433965Sjdp	  _delay $4
9533965Sjdp	  _start $14
9633965Sjdp	  _etext $8036
9733965Sjdp	  _edata $8036
9833965Sjdp 	  _end $8036
9933965Sjdp	$$
10033965Sjdp
10133965SjdpDESCRIPTION
10233965Sjdp	We allow symbols to be anywhere in the data stream - the module names
10333965Sjdp	are always ignored.
10433965Sjdp
10533965Sjdp*/
10633965Sjdp
10733965Sjdp#include "bfd.h"
10833965Sjdp#include "sysdep.h"
10933965Sjdp#include "libbfd.h"
11033965Sjdp#include "libiberty.h"
11133965Sjdp#include <ctype.h>
11233965Sjdp
11333965Sjdpstatic void srec_get_symbol_info PARAMS ((bfd *, asymbol *, symbol_info *));
11433965Sjdpstatic void srec_print_symbol
11533965Sjdp PARAMS ((bfd *, PTR, asymbol *, bfd_print_symbol_type));
11633965Sjdpstatic void srec_init PARAMS ((void));
11733965Sjdpstatic boolean srec_mkobject PARAMS ((bfd *));
11833965Sjdpstatic int srec_get_byte PARAMS ((bfd *, boolean *));
11933965Sjdpstatic void srec_bad_byte PARAMS ((bfd *, unsigned int, int, boolean));
12033965Sjdpstatic boolean srec_scan PARAMS ((bfd *));
12133965Sjdpstatic const bfd_target *srec_object_p PARAMS ((bfd *));
12233965Sjdpstatic const bfd_target *symbolsrec_object_p PARAMS ((bfd *));
12333965Sjdpstatic boolean srec_read_section PARAMS ((bfd *, asection *, bfd_byte *));
12433965Sjdp
12533965Sjdpstatic boolean srec_write_record PARAMS ((bfd *, int, bfd_vma,
12633965Sjdp					  const bfd_byte *,
12733965Sjdp					  const bfd_byte *));
12833965Sjdpstatic boolean srec_write_header PARAMS ((bfd *));
12933965Sjdpstatic boolean srec_write_symbols PARAMS ((bfd *));
13033965Sjdpstatic boolean srec_new_symbol PARAMS ((bfd *, const char *, bfd_vma));
13133965Sjdpstatic boolean srec_get_section_contents
13233965Sjdp  PARAMS ((bfd *, asection *, PTR, file_ptr, bfd_size_type));
13333965Sjdpstatic boolean srec_set_arch_mach
13433965Sjdp  PARAMS ((bfd *, enum bfd_architecture, unsigned long));
13533965Sjdpstatic boolean srec_set_section_contents
13633965Sjdp  PARAMS ((bfd *, sec_ptr, PTR, file_ptr, bfd_size_type));
13733965Sjdpstatic boolean internal_srec_write_object_contents PARAMS ((bfd *, int));
13833965Sjdpstatic boolean srec_write_object_contents PARAMS ((bfd *));
13933965Sjdpstatic boolean symbolsrec_write_object_contents PARAMS ((bfd *));
14033965Sjdpstatic int srec_sizeof_headers PARAMS ((bfd *, boolean));
14133965Sjdpstatic asymbol *srec_make_empty_symbol PARAMS ((bfd *));
14233965Sjdpstatic long srec_get_symtab_upper_bound PARAMS ((bfd *));
14333965Sjdpstatic long srec_get_symtab PARAMS ((bfd *, asymbol **));
14433965Sjdp
14533965Sjdp/* Macros for converting between hex and binary. */
14633965Sjdp
14733965Sjdpstatic CONST char digs[] = "0123456789ABCDEF";
14833965Sjdp
14933965Sjdp#define NIBBLE(x) hex_value(x)
15033965Sjdp#define HEX(buffer) ((NIBBLE((buffer)[0])<<4) + NIBBLE((buffer)[1]))
15133965Sjdp#define TOHEX(d, x, ch) \
15233965Sjdp	d[1] = digs[(x) & 0xf]; \
15333965Sjdp	d[0] = digs[((x)>>4)&0xf]; \
15433965Sjdp	ch += ((x) & 0xff);
15533965Sjdp#define	ISHEX(x)  hex_p(x)
15633965Sjdp
15733965Sjdp/* Initialize by filling in the hex conversion array. */
15833965Sjdp
15933965Sjdpstatic void
16033965Sjdpsrec_init ()
16133965Sjdp{
16233965Sjdp  static boolean inited = false;
16333965Sjdp
16433965Sjdp  if (inited == false)
16533965Sjdp    {
16633965Sjdp      inited = true;
16733965Sjdp      hex_init ();
16833965Sjdp    }
16933965Sjdp}
17033965Sjdp
17133965Sjdp/* The maximum number of bytes on a line is FF */
17233965Sjdp#define MAXCHUNK 0xff
17333965Sjdp/* The number of bytes we fit onto a line on output */
17433965Sjdp#define CHUNK 21
17533965Sjdp
17633965Sjdp/* When writing an S-record file, the S-records can not be output as
17733965Sjdp   they are seen.  This structure is used to hold them in memory.  */
17833965Sjdp
17933965Sjdpstruct srec_data_list_struct
18033965Sjdp{
18133965Sjdp  struct srec_data_list_struct *next;
18233965Sjdp  bfd_byte *data;
18333965Sjdp  bfd_vma where;
18433965Sjdp  bfd_size_type size;
18533965Sjdp};
18633965Sjdp
18733965Sjdptypedef struct srec_data_list_struct srec_data_list_type;
18833965Sjdp
18933965Sjdp/* When scanning the S-record file, a linked list of srec_symbol
19033965Sjdp   structures is built to represent the symbol table (if there is
19133965Sjdp   one).  */
19233965Sjdp
19333965Sjdpstruct srec_symbol
19433965Sjdp{
19533965Sjdp  struct srec_symbol *next;
19633965Sjdp  const char *name;
19733965Sjdp  bfd_vma val;
19833965Sjdp};
19933965Sjdp
20033965Sjdp/* The S-record tdata information.  */
20133965Sjdp
20233965Sjdptypedef struct srec_data_struct
20333965Sjdp  {
20433965Sjdp    srec_data_list_type *head;
20533965Sjdp    srec_data_list_type *tail;
20633965Sjdp    unsigned int type;
20733965Sjdp    struct srec_symbol *symbols;
20833965Sjdp    struct srec_symbol *symtail;
20933965Sjdp    asymbol *csymbols;
21033965Sjdp  }
21133965Sjdptdata_type;
21233965Sjdp
21333965Sjdpstatic boolean srec_write_section PARAMS ((bfd *, tdata_type *,
21433965Sjdp					   srec_data_list_type *));
21533965Sjdpstatic boolean srec_write_terminator PARAMS ((bfd *, tdata_type *));
21633965Sjdp
21733965Sjdp/* Set up the S-record tdata information.  */
21833965Sjdp
21933965Sjdpstatic boolean
22033965Sjdpsrec_mkobject (abfd)
22133965Sjdp     bfd *abfd;
22233965Sjdp{
22333965Sjdp  srec_init ();
22433965Sjdp
22533965Sjdp  if (abfd->tdata.srec_data == NULL)
22633965Sjdp    {
22733965Sjdp      tdata_type *tdata = (tdata_type *) bfd_alloc (abfd, sizeof (tdata_type));
22833965Sjdp      if (tdata == NULL)
22933965Sjdp	return false;
23033965Sjdp      abfd->tdata.srec_data = tdata;
23133965Sjdp      tdata->type = 1;
23233965Sjdp      tdata->head = NULL;
23333965Sjdp      tdata->tail = NULL;
23433965Sjdp      tdata->symbols = NULL;
23533965Sjdp      tdata->symtail = NULL;
23633965Sjdp      tdata->csymbols = NULL;
23733965Sjdp    }
23833965Sjdp
23933965Sjdp  return true;
24033965Sjdp}
24133965Sjdp
24233965Sjdp/* Read a byte from an S record file.  Set *ERRORPTR if an error
24333965Sjdp   occurred.  Return EOF on error or end of file.  */
24433965Sjdp
24533965Sjdpstatic int
24633965Sjdpsrec_get_byte (abfd, errorptr)
24733965Sjdp     bfd *abfd;
24833965Sjdp     boolean *errorptr;
24933965Sjdp{
25033965Sjdp  bfd_byte c;
25133965Sjdp
25233965Sjdp  if (bfd_read (&c, 1, 1, abfd) != 1)
25333965Sjdp    {
25433965Sjdp      if (bfd_get_error () != bfd_error_file_truncated)
25533965Sjdp	*errorptr = true;
25633965Sjdp      return EOF;
25733965Sjdp    }
25833965Sjdp
25933965Sjdp  return (int) (c & 0xff);
26033965Sjdp}
26133965Sjdp
26233965Sjdp/* Report a problem in an S record file.  FIXME: This probably should
26333965Sjdp   not call fprintf, but we really do need some mechanism for printing
26433965Sjdp   error messages.  */
26533965Sjdp
26633965Sjdpstatic void
26733965Sjdpsrec_bad_byte (abfd, lineno, c, error)
26833965Sjdp     bfd *abfd;
26933965Sjdp     unsigned int lineno;
27033965Sjdp     int c;
27133965Sjdp     boolean error;
27233965Sjdp{
27333965Sjdp  if (c == EOF)
27433965Sjdp    {
27533965Sjdp      if (! error)
27633965Sjdp	bfd_set_error (bfd_error_file_truncated);
27733965Sjdp    }
27833965Sjdp  else
27933965Sjdp    {
28033965Sjdp      char buf[10];
28133965Sjdp
28233965Sjdp      if (! isprint (c))
28333965Sjdp	sprintf (buf, "\\%03o", (unsigned int) c);
28433965Sjdp      else
28533965Sjdp	{
28633965Sjdp	  buf[0] = c;
28733965Sjdp	  buf[1] = '\0';
28833965Sjdp	}
28933965Sjdp      (*_bfd_error_handler)
29033965Sjdp	("%s:%d: Unexpected character `%s' in S-record file\n",
29133965Sjdp	 bfd_get_filename (abfd), lineno, buf);
29233965Sjdp      bfd_set_error (bfd_error_bad_value);
29333965Sjdp    }
29433965Sjdp}
29533965Sjdp
29633965Sjdp/* Add a new symbol found in an S-record file.  */
29733965Sjdp
29833965Sjdpstatic boolean
29933965Sjdpsrec_new_symbol (abfd, name, val)
30033965Sjdp     bfd *abfd;
30133965Sjdp     const char *name;
30233965Sjdp     bfd_vma val;
30333965Sjdp{
30433965Sjdp  struct srec_symbol *n;
30533965Sjdp
30633965Sjdp  n = (struct srec_symbol *) bfd_alloc (abfd, sizeof (struct srec_symbol));
30733965Sjdp  if (n == NULL)
30833965Sjdp    return false;
30933965Sjdp
31033965Sjdp  n->name = name;
31133965Sjdp  n->val = val;
31233965Sjdp
31333965Sjdp  if (abfd->tdata.srec_data->symbols == NULL)
31433965Sjdp    abfd->tdata.srec_data->symbols = n;
31533965Sjdp  else
31633965Sjdp    abfd->tdata.srec_data->symtail->next = n;
31733965Sjdp  abfd->tdata.srec_data->symtail = n;
31833965Sjdp  n->next = NULL;
31933965Sjdp
32033965Sjdp  ++abfd->symcount;
32133965Sjdp
32233965Sjdp  return true;
32333965Sjdp}
32433965Sjdp
32533965Sjdp/* Read the S record file and turn it into sections.  We create a new
32633965Sjdp   section for each contiguous set of bytes.  */
32733965Sjdp
32833965Sjdpstatic boolean
32933965Sjdpsrec_scan (abfd)
33033965Sjdp     bfd *abfd;
33133965Sjdp{
33233965Sjdp  int c;
33333965Sjdp  unsigned int lineno = 1;
33433965Sjdp  boolean error = false;
33533965Sjdp  bfd_byte *buf = NULL;
33633965Sjdp  size_t bufsize = 0;
33733965Sjdp  asection *sec = NULL;
33833965Sjdp  char *symbuf = NULL;
33933965Sjdp
34033965Sjdp  if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0)
34133965Sjdp    goto error_return;
34233965Sjdp
34333965Sjdp  while ((c = srec_get_byte (abfd, &error)) != EOF)
34433965Sjdp    {
34533965Sjdp      /* We only build sections from contiguous S-records, so if this
34633965Sjdp         is not an S-record, then stop building a section.  */
34733965Sjdp      if (c != 'S' && c != '\r' && c != '\n')
34833965Sjdp	sec = NULL;
34933965Sjdp
35033965Sjdp      switch (c)
35133965Sjdp	{
35233965Sjdp	default:
35333965Sjdp	  srec_bad_byte (abfd, lineno, c, error);
35433965Sjdp	  goto error_return;
35533965Sjdp
35633965Sjdp	case '\n':
35733965Sjdp	  ++lineno;
35833965Sjdp	  break;
35933965Sjdp
36033965Sjdp	case '\r':
36133965Sjdp	  break;
36233965Sjdp
36333965Sjdp	case '$':
36433965Sjdp	  /* Starting a module name, which we ignore.  */
36533965Sjdp	  while ((c = srec_get_byte (abfd, &error)) != '\n'
36633965Sjdp		 && c != EOF)
36733965Sjdp	    ;
36833965Sjdp	  if (c == EOF)
36933965Sjdp	    {
37033965Sjdp	      srec_bad_byte (abfd, lineno, c, error);
37133965Sjdp	      goto error_return;
37233965Sjdp	    }
37333965Sjdp
37433965Sjdp	  ++lineno;
37533965Sjdp
37633965Sjdp	  break;
37733965Sjdp
37833965Sjdp	case ' ':
37933965Sjdp	  do
38033965Sjdp	    {
38133965Sjdp	      unsigned int alc;
38233965Sjdp	      char *p, *symname;
38333965Sjdp	      bfd_vma symval;
38433965Sjdp
38533965Sjdp	      /* Starting a symbol definition.  */
38633965Sjdp	      while ((c = srec_get_byte (abfd, &error)) != EOF
38733965Sjdp		     && (c == ' ' || c == '\t'))
38833965Sjdp		;
38933965Sjdp
39033965Sjdp	      if (c == '\n')
39133965Sjdp		break;
39233965Sjdp
39333965Sjdp	      if (c == EOF)
39433965Sjdp		{
39533965Sjdp		  srec_bad_byte (abfd, lineno, c, error);
39633965Sjdp		  goto error_return;
39733965Sjdp		}
39833965Sjdp
39933965Sjdp	      alc = 10;
40033965Sjdp	      symbuf = (char *) bfd_malloc (alc + 1);
40133965Sjdp	      if (symbuf == NULL)
40233965Sjdp		goto error_return;
40333965Sjdp
40433965Sjdp	      p = symbuf;
40533965Sjdp
40633965Sjdp	      *p++ = c;
40733965Sjdp	      while ((c = srec_get_byte (abfd, &error)) != EOF
40833965Sjdp		     && ! isspace (c))
40933965Sjdp		{
41038889Sjdp		  if ((unsigned int) (p - symbuf) >= alc)
41133965Sjdp		    {
41233965Sjdp		      char *n;
41333965Sjdp
41433965Sjdp		      alc *= 2;
41533965Sjdp		      n = (char *) bfd_realloc (symbuf, alc + 1);
41633965Sjdp		      if (n == NULL)
41733965Sjdp			goto error_return;
41833965Sjdp		      p = n + (p - symbuf);
41933965Sjdp		      symbuf = n;
42033965Sjdp		    }
42133965Sjdp
42233965Sjdp		  *p++ = c;
42333965Sjdp		}
42433965Sjdp
42533965Sjdp	      if (c == EOF)
42633965Sjdp		{
42733965Sjdp		  srec_bad_byte (abfd, lineno, c, error);
42833965Sjdp		  goto error_return;
42933965Sjdp		}
43033965Sjdp
43133965Sjdp	      *p++ = '\0';
43233965Sjdp	      symname = bfd_alloc (abfd, p - symbuf);
43333965Sjdp	      if (symname == NULL)
43433965Sjdp		goto error_return;
43533965Sjdp	      strcpy (symname, symbuf);
43633965Sjdp	      free (symbuf);
43733965Sjdp	      symbuf = NULL;
43833965Sjdp
43933965Sjdp	      while ((c = srec_get_byte (abfd, &error)) != EOF
44033965Sjdp		     && (c == ' ' || c == '\t'))
44133965Sjdp		;
44233965Sjdp	      if (c == EOF)
44333965Sjdp		{
44433965Sjdp		  srec_bad_byte (abfd, lineno, c, error);
44533965Sjdp		  goto error_return;
44633965Sjdp		}
44733965Sjdp
44833965Sjdp	      /* Skip a dollar sign before the hex value.  */
44933965Sjdp	      if (c == '$')
45033965Sjdp		{
45133965Sjdp		  c = srec_get_byte (abfd, &error);
45233965Sjdp		  if (c == EOF)
45333965Sjdp		    {
45433965Sjdp		      srec_bad_byte (abfd, lineno, c, error);
45533965Sjdp		      goto error_return;
45633965Sjdp		    }
45733965Sjdp		}
45833965Sjdp
45933965Sjdp	      symval = 0;
46033965Sjdp	      while (ISHEX (c))
46133965Sjdp		{
46233965Sjdp		  symval <<= 4;
46333965Sjdp		  symval += NIBBLE (c);
46433965Sjdp		  c = srec_get_byte (abfd, &error);
46533965Sjdp		}
46633965Sjdp
46733965Sjdp	      if (! srec_new_symbol (abfd, symname, symval))
46833965Sjdp		goto error_return;
46933965Sjdp	    }
47033965Sjdp	  while (c == ' ' || c == '\t');
47133965Sjdp
47233965Sjdp	  if (c != '\n')
47333965Sjdp	    {
47433965Sjdp	      srec_bad_byte (abfd, lineno, c, error);
47533965Sjdp	      goto error_return;
47633965Sjdp	    }
47733965Sjdp
47833965Sjdp	  ++lineno;
47933965Sjdp
48033965Sjdp	  break;
48133965Sjdp
48233965Sjdp	case 'S':
48333965Sjdp	  {
48433965Sjdp	    file_ptr pos;
48533965Sjdp	    char hdr[3];
48633965Sjdp	    unsigned int bytes;
48733965Sjdp	    bfd_vma address;
48833965Sjdp	    bfd_byte *data;
48933965Sjdp
49033965Sjdp	    /* Starting an S-record.  */
49133965Sjdp
49233965Sjdp	    pos = bfd_tell (abfd) - 1;
49333965Sjdp
49433965Sjdp	    if (bfd_read (hdr, 1, 3, abfd) != 3)
49533965Sjdp	      goto error_return;
49633965Sjdp
49733965Sjdp	    if (! ISHEX (hdr[1]) || ! ISHEX (hdr[2]))
49833965Sjdp	      {
49933965Sjdp		if (! ISHEX (hdr[1]))
50033965Sjdp		  c = hdr[1];
50133965Sjdp		else
50233965Sjdp		  c = hdr[2];
50333965Sjdp		srec_bad_byte (abfd, lineno, c, error);
50433965Sjdp		goto error_return;
50533965Sjdp	      }
50633965Sjdp
50733965Sjdp	    bytes = HEX (hdr + 1);
50833965Sjdp	    if (bytes * 2 > bufsize)
50933965Sjdp	      {
51033965Sjdp		if (buf != NULL)
51133965Sjdp		  free (buf);
51233965Sjdp		buf = (bfd_byte *) bfd_malloc (bytes * 2);
51333965Sjdp		if (buf == NULL)
51433965Sjdp		  goto error_return;
51533965Sjdp		bufsize = bytes * 2;
51633965Sjdp	      }
51733965Sjdp
51833965Sjdp	    if (bfd_read (buf, 1, bytes * 2, abfd) != bytes * 2)
51933965Sjdp	      goto error_return;
52033965Sjdp
52133965Sjdp	    /* Ignore the checksum byte.  */
52233965Sjdp	    --bytes;
52333965Sjdp
52433965Sjdp	    address = 0;
52533965Sjdp	    data = buf;
52633965Sjdp	    switch (hdr[0])
52733965Sjdp	      {
52833965Sjdp	      case '0':
52933965Sjdp	      case '5':
53033965Sjdp		/* Prologue--ignore the file name, but stop building a
53133965Sjdp                   section at this point.  */
53233965Sjdp		sec = NULL;
53333965Sjdp		break;
53433965Sjdp
53533965Sjdp	      case '3':
53633965Sjdp		address = HEX (data);
53733965Sjdp		data += 2;
53833965Sjdp		--bytes;
53933965Sjdp		/* Fall through.  */
54033965Sjdp	      case '2':
54133965Sjdp		address = (address << 8) | HEX (data);
54233965Sjdp		data += 2;
54333965Sjdp		--bytes;
54433965Sjdp		/* Fall through.  */
54533965Sjdp	      case '1':
54633965Sjdp		address = (address << 8) | HEX (data);
54733965Sjdp		data += 2;
54833965Sjdp		address = (address << 8) | HEX (data);
54933965Sjdp		data += 2;
55033965Sjdp		bytes -= 2;
55133965Sjdp
55233965Sjdp		if (sec != NULL
55333965Sjdp		    && sec->vma + sec->_raw_size == address)
55433965Sjdp		  {
55533965Sjdp		    /* This data goes at the end of the section we are
55633965Sjdp                       currently building.  */
55733965Sjdp		    sec->_raw_size += bytes;
55833965Sjdp		  }
55933965Sjdp		else
56033965Sjdp		  {
56133965Sjdp		    char secbuf[20];
56233965Sjdp		    char *secname;
56333965Sjdp
56433965Sjdp		    sprintf (secbuf, ".sec%d", bfd_count_sections (abfd) + 1);
56533965Sjdp		    secname = (char *) bfd_alloc (abfd, strlen (secbuf) + 1);
56633965Sjdp		    strcpy (secname, secbuf);
56733965Sjdp		    sec = bfd_make_section (abfd, secname);
56833965Sjdp		    if (sec == NULL)
56933965Sjdp		      goto error_return;
57033965Sjdp		    sec->flags = SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC;
57133965Sjdp		    sec->vma = address;
57233965Sjdp		    sec->lma = address;
57333965Sjdp		    sec->_raw_size = bytes;
57433965Sjdp		    sec->filepos = pos;
57533965Sjdp		  }
57633965Sjdp
57733965Sjdp		break;
57833965Sjdp
57933965Sjdp	      case '7':
58033965Sjdp		address = HEX (data);
58133965Sjdp		data += 2;
58233965Sjdp		/* Fall through.  */
58333965Sjdp	      case '8':
58433965Sjdp		address = (address << 8) | HEX (data);
58533965Sjdp		data += 2;
58633965Sjdp		/* Fall through.  */
58733965Sjdp	      case '9':
58833965Sjdp		address = (address << 8) | HEX (data);
58933965Sjdp		data += 2;
59033965Sjdp		address = (address << 8) | HEX (data);
59133965Sjdp		data += 2;
59233965Sjdp
59333965Sjdp		/* This is a termination record.  */
59433965Sjdp		abfd->start_address = address;
59533965Sjdp
59633965Sjdp		if (buf != NULL)
59733965Sjdp		  free (buf);
59833965Sjdp
59933965Sjdp		return true;
60033965Sjdp	      }
60133965Sjdp	  }
60233965Sjdp	  break;
60333965Sjdp	}
60433965Sjdp    }
60533965Sjdp
60633965Sjdp  if (error)
60733965Sjdp    goto error_return;
60833965Sjdp
60933965Sjdp  if (buf != NULL)
61033965Sjdp    free (buf);
61133965Sjdp
61233965Sjdp  return true;
61333965Sjdp
61433965Sjdp error_return:
61533965Sjdp  if (symbuf != NULL)
61633965Sjdp    free (symbuf);
61733965Sjdp  if (buf != NULL)
61833965Sjdp    free (buf);
61933965Sjdp  return false;
62033965Sjdp}
62133965Sjdp
62233965Sjdp/* Check whether an existing file is an S-record file.  */
62333965Sjdp
62433965Sjdpstatic const bfd_target *
62533965Sjdpsrec_object_p (abfd)
62633965Sjdp     bfd *abfd;
62733965Sjdp{
62833965Sjdp  bfd_byte b[4];
62933965Sjdp
63033965Sjdp  srec_init ();
63133965Sjdp
63233965Sjdp  if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0
63333965Sjdp      || bfd_read (b, 1, 4, abfd) != 4)
63433965Sjdp    return NULL;
63533965Sjdp
63633965Sjdp  if (b[0] != 'S' || !ISHEX (b[1]) || !ISHEX (b[2]) || !ISHEX (b[3]))
63733965Sjdp    {
63833965Sjdp      bfd_set_error (bfd_error_wrong_format);
63933965Sjdp      return NULL;
64033965Sjdp    }
64133965Sjdp
64233965Sjdp  if (! srec_mkobject (abfd)
64333965Sjdp      || ! srec_scan (abfd))
64433965Sjdp    return NULL;
64533965Sjdp
64633965Sjdp  return abfd->xvec;
64733965Sjdp}
64833965Sjdp
64933965Sjdp/* Check whether an existing file is an S-record file with symbols.  */
65033965Sjdp
65133965Sjdpstatic const bfd_target *
65233965Sjdpsymbolsrec_object_p (abfd)
65333965Sjdp     bfd *abfd;
65433965Sjdp{
65533965Sjdp  char b[2];
65633965Sjdp
65733965Sjdp  srec_init ();
65833965Sjdp
65933965Sjdp  if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0
66033965Sjdp      || bfd_read (b, 1, 2, abfd) != 2)
66133965Sjdp    return NULL;
66233965Sjdp
66333965Sjdp  if (b[0] != '$' || b[1] != '$')
66433965Sjdp    {
66533965Sjdp      bfd_set_error (bfd_error_wrong_format);
66633965Sjdp      return NULL;
66733965Sjdp    }
66833965Sjdp
66933965Sjdp  if (! srec_mkobject (abfd)
67033965Sjdp      || ! srec_scan (abfd))
67133965Sjdp    return NULL;
67233965Sjdp
67333965Sjdp  return abfd->xvec;
67433965Sjdp}
67533965Sjdp
67633965Sjdp/* Read in the contents of a section in an S-record file.  */
67733965Sjdp
67833965Sjdpstatic boolean
67933965Sjdpsrec_read_section (abfd, section, contents)
68033965Sjdp     bfd *abfd;
68133965Sjdp     asection *section;
68233965Sjdp     bfd_byte *contents;
68333965Sjdp{
68433965Sjdp  int c;
68533965Sjdp  bfd_size_type sofar = 0;
68633965Sjdp  boolean error = false;
68733965Sjdp  bfd_byte *buf = NULL;
68833965Sjdp  size_t bufsize = 0;
68933965Sjdp
69033965Sjdp  if (bfd_seek (abfd, section->filepos, SEEK_SET) != 0)
69133965Sjdp    goto error_return;
69233965Sjdp
69333965Sjdp  while ((c = srec_get_byte (abfd, &error)) != EOF)
69433965Sjdp    {
69533965Sjdp      bfd_byte hdr[3];
69633965Sjdp      unsigned int bytes;
69733965Sjdp      bfd_vma address;
69833965Sjdp      bfd_byte *data;
69933965Sjdp
70033965Sjdp      if (c == '\r' || c == '\n')
70133965Sjdp	continue;
70233965Sjdp
70333965Sjdp      /* This is called after srec_scan has already been called, so we
70433965Sjdp         ought to know the exact format.  */
70533965Sjdp      BFD_ASSERT (c == 'S');
70633965Sjdp
70733965Sjdp      if (bfd_read (hdr, 1, 3, abfd) != 3)
70833965Sjdp	goto error_return;
70933965Sjdp
71033965Sjdp      BFD_ASSERT (ISHEX (hdr[1]) && ISHEX (hdr[2]));
71133965Sjdp
71233965Sjdp      bytes = HEX (hdr + 1);
71333965Sjdp
71433965Sjdp      if (bytes * 2 > bufsize)
71533965Sjdp	{
71633965Sjdp	  if (buf != NULL)
71733965Sjdp	    free (buf);
71833965Sjdp	  buf = (bfd_byte *) bfd_malloc (bytes * 2);
71933965Sjdp	  if (buf == NULL)
72033965Sjdp	    goto error_return;
72133965Sjdp	  bufsize = bytes * 2;
72233965Sjdp	}
72333965Sjdp
72433965Sjdp      if (bfd_read (buf, 1, bytes * 2, abfd) != bytes * 2)
72533965Sjdp	goto error_return;
72633965Sjdp
72733965Sjdp      address = 0;
72833965Sjdp      data = buf;
72933965Sjdp      switch (hdr[0])
73033965Sjdp	{
73133965Sjdp	default:
73233965Sjdp	  BFD_ASSERT (sofar == section->_raw_size);
73333965Sjdp	  if (buf != NULL)
73433965Sjdp	    free (buf);
73533965Sjdp	  return true;
73633965Sjdp
73733965Sjdp	case '3':
73833965Sjdp	  address = HEX (data);
73933965Sjdp	  data += 2;
74033965Sjdp	  --bytes;
74133965Sjdp	  /* Fall through.  */
74233965Sjdp	case '2':
74333965Sjdp	  address = (address << 8) | HEX (data);
74433965Sjdp	  data += 2;
74533965Sjdp	  --bytes;
74633965Sjdp	  /* Fall through.  */
74733965Sjdp	case '1':
74833965Sjdp	  address = (address << 8) | HEX (data);
74933965Sjdp	  data += 2;
75033965Sjdp	  address = (address << 8) | HEX (data);
75133965Sjdp	  data += 2;
75233965Sjdp	  bytes -= 2;
75333965Sjdp
75433965Sjdp	  if (address != section->vma + sofar)
75533965Sjdp	    {
75633965Sjdp	      /* We've come to the end of this section.  */
75733965Sjdp	      BFD_ASSERT (sofar == section->_raw_size);
75833965Sjdp	      if (buf != NULL)
75933965Sjdp		free (buf);
76033965Sjdp	      return true;
76133965Sjdp	    }
76233965Sjdp
76333965Sjdp	  /* Don't consider checksum.  */
76433965Sjdp	  --bytes;
76533965Sjdp
76633965Sjdp	  while (bytes-- != 0)
76733965Sjdp	    {
76833965Sjdp	      contents[sofar] = HEX (data);
76933965Sjdp	      data += 2;
77033965Sjdp	      ++sofar;
77133965Sjdp	    }
77233965Sjdp
77333965Sjdp	  break;
77433965Sjdp	}
77533965Sjdp    }
77633965Sjdp
77733965Sjdp  if (error)
77833965Sjdp    goto error_return;
77933965Sjdp
78033965Sjdp  BFD_ASSERT (sofar == section->_raw_size);
78133965Sjdp
78233965Sjdp  if (buf != NULL)
78333965Sjdp    free (buf);
78433965Sjdp
78533965Sjdp  return true;
78633965Sjdp
78733965Sjdp error_return:
78833965Sjdp  if (buf != NULL)
78933965Sjdp    free (buf);
79033965Sjdp  return false;
79133965Sjdp}
79233965Sjdp
79333965Sjdp/* Get the contents of a section in an S-record file.  */
79433965Sjdp
79533965Sjdpstatic boolean
79633965Sjdpsrec_get_section_contents (abfd, section, location, offset, count)
79733965Sjdp     bfd *abfd;
79833965Sjdp     asection *section;
79933965Sjdp     PTR location;
80033965Sjdp     file_ptr offset;
80133965Sjdp     bfd_size_type count;
80233965Sjdp{
80333965Sjdp  if (section->used_by_bfd == NULL)
80433965Sjdp    {
80533965Sjdp      section->used_by_bfd = bfd_alloc (abfd, section->_raw_size);
80633965Sjdp      if (section->used_by_bfd == NULL
80733965Sjdp	  && section->_raw_size != 0)
80833965Sjdp	return false;
80933965Sjdp
81033965Sjdp      if (! srec_read_section (abfd, section, section->used_by_bfd))
81133965Sjdp	return false;
81233965Sjdp    }
81333965Sjdp
81433965Sjdp  memcpy (location, (bfd_byte *) section->used_by_bfd + offset,
81533965Sjdp	  (size_t) count);
81633965Sjdp
81733965Sjdp  return true;
81833965Sjdp}
81933965Sjdp
82033965Sjdp/* Set the architecture.  We accept an unknown architecture here.  */
82133965Sjdp
82233965Sjdpstatic boolean
82333965Sjdpsrec_set_arch_mach (abfd, arch, mach)
82433965Sjdp     bfd *abfd;
82533965Sjdp     enum bfd_architecture arch;
82633965Sjdp     unsigned long mach;
82733965Sjdp{
82833965Sjdp  if (arch == bfd_arch_unknown)
82933965Sjdp    {
83033965Sjdp      abfd->arch_info = &bfd_default_arch_struct;
83133965Sjdp      return true;
83233965Sjdp    }
83333965Sjdp  return bfd_default_set_arch_mach (abfd, arch, mach);
83433965Sjdp}
83533965Sjdp
83633965Sjdp/* we have to save up all the Srecords for a splurge before output */
83733965Sjdp
83833965Sjdpstatic boolean
83933965Sjdpsrec_set_section_contents (abfd, section, location, offset, bytes_to_do)
84033965Sjdp     bfd *abfd;
84133965Sjdp     sec_ptr section;
84233965Sjdp     PTR location;
84333965Sjdp     file_ptr offset;
84433965Sjdp     bfd_size_type bytes_to_do;
84533965Sjdp{
84633965Sjdp  tdata_type *tdata = abfd->tdata.srec_data;
84733965Sjdp  register srec_data_list_type *entry;
84833965Sjdp
84933965Sjdp  entry = ((srec_data_list_type *)
85033965Sjdp	   bfd_alloc (abfd, sizeof (srec_data_list_type)));
85133965Sjdp  if (entry == NULL)
85233965Sjdp    return false;
85333965Sjdp
85433965Sjdp  if (bytes_to_do
85533965Sjdp      && (section->flags & SEC_ALLOC)
85633965Sjdp      && (section->flags & SEC_LOAD))
85733965Sjdp    {
85833965Sjdp      bfd_byte *data = (bfd_byte *) bfd_alloc (abfd, bytes_to_do);
85933965Sjdp      if (data == NULL)
86033965Sjdp	return false;
86133965Sjdp      memcpy ((PTR) data, location, (size_t) bytes_to_do);
86233965Sjdp
86333965Sjdp      if ((section->lma + offset + bytes_to_do - 1) <= 0xffff)
86433965Sjdp	{
86533965Sjdp
86633965Sjdp	}
86733965Sjdp      else if ((section->lma + offset + bytes_to_do - 1) <= 0xffffff
86833965Sjdp	       && tdata->type < 2)
86933965Sjdp	{
87033965Sjdp	  tdata->type = 2;
87133965Sjdp	}
87233965Sjdp      else
87333965Sjdp	{
87433965Sjdp	  tdata->type = 3;
87533965Sjdp	}
87633965Sjdp
87733965Sjdp      entry->data = data;
87833965Sjdp      entry->where = section->lma + offset;
87933965Sjdp      entry->size = bytes_to_do;
88033965Sjdp
88133965Sjdp      /* Sort the records by address.  Optimize for the common case of
88233965Sjdp         adding a record to the end of the list.  */
88333965Sjdp      if (tdata->tail != NULL
88433965Sjdp	  && entry->where >= tdata->tail->where)
88533965Sjdp	{
88633965Sjdp	  tdata->tail->next = entry;
88733965Sjdp	  entry->next = NULL;
88833965Sjdp	  tdata->tail = entry;
88933965Sjdp	}
89033965Sjdp      else
89133965Sjdp	{
89233965Sjdp	  register srec_data_list_type **look;
89333965Sjdp
89433965Sjdp	  for (look = &tdata->head;
89533965Sjdp	       *look != NULL && (*look)->where < entry->where;
89633965Sjdp	       look = &(*look)->next)
89733965Sjdp	    ;
89833965Sjdp	  entry->next = *look;
89933965Sjdp	  *look = entry;
90033965Sjdp	  if (entry->next == NULL)
90133965Sjdp	    tdata->tail = entry;
90233965Sjdp	}
90333965Sjdp    }
90433965Sjdp  return true;
90533965Sjdp}
90633965Sjdp
90733965Sjdp/* Write a record of type, of the supplied number of bytes. The
90833965Sjdp   supplied bytes and length don't have a checksum. That's worked out
90933965Sjdp   here
91033965Sjdp*/
91133965Sjdpstatic boolean
91233965Sjdpsrec_write_record (abfd, type, address, data, end)
91333965Sjdp     bfd *abfd;
91433965Sjdp     int type;
91533965Sjdp     bfd_vma address;
91633965Sjdp     const bfd_byte *data;
91733965Sjdp     const bfd_byte *end;
91833965Sjdp{
91933965Sjdp  char buffer[MAXCHUNK];
92033965Sjdp  unsigned int check_sum = 0;
92133965Sjdp  CONST bfd_byte *src = data;
92233965Sjdp  char *dst = buffer;
92333965Sjdp  char *length;
92433965Sjdp  bfd_size_type wrlen;
92533965Sjdp
92633965Sjdp  *dst++ = 'S';
92733965Sjdp  *dst++ = '0' + type;
92833965Sjdp
92933965Sjdp  length = dst;
93033965Sjdp  dst += 2;			/* leave room for dst*/
93133965Sjdp
93233965Sjdp  switch (type)
93333965Sjdp    {
93433965Sjdp    case 3:
93533965Sjdp    case 7:
93633965Sjdp      TOHEX (dst, (address >> 24), check_sum);
93733965Sjdp      dst += 2;
93833965Sjdp    case 8:
93933965Sjdp    case 2:
94033965Sjdp      TOHEX (dst, (address >> 16), check_sum);
94133965Sjdp      dst += 2;
94233965Sjdp    case 9:
94333965Sjdp    case 1:
94433965Sjdp    case 0:
94533965Sjdp      TOHEX (dst, (address >> 8), check_sum);
94633965Sjdp      dst += 2;
94733965Sjdp      TOHEX (dst, (address), check_sum);
94833965Sjdp      dst += 2;
94933965Sjdp      break;
95033965Sjdp
95133965Sjdp    }
95233965Sjdp  for (src = data; src < end; src++)
95333965Sjdp    {
95433965Sjdp      TOHEX (dst, *src, check_sum);
95533965Sjdp      dst += 2;
95633965Sjdp    }
95733965Sjdp
95833965Sjdp  /* Fill in the length */
95933965Sjdp  TOHEX (length, (dst - length) / 2, check_sum);
96033965Sjdp  check_sum &= 0xff;
96133965Sjdp  check_sum = 255 - check_sum;
96233965Sjdp  TOHEX (dst, check_sum, check_sum);
96333965Sjdp  dst += 2;
96433965Sjdp
96533965Sjdp  *dst++ = '\r';
96633965Sjdp  *dst++ = '\n';
96733965Sjdp  wrlen = dst - buffer;
96833965Sjdp  if (bfd_write ((PTR) buffer, 1, wrlen, abfd) != wrlen)
96933965Sjdp    return false;
97033965Sjdp  return true;
97133965Sjdp}
97233965Sjdp
97333965Sjdp
97433965Sjdp
97533965Sjdpstatic boolean
97633965Sjdpsrec_write_header (abfd)
97733965Sjdp     bfd *abfd;
97833965Sjdp{
97933965Sjdp  bfd_byte buffer[MAXCHUNK];
98033965Sjdp  bfd_byte *dst = buffer;
98133965Sjdp  unsigned int i;
98233965Sjdp
98333965Sjdp  /* I'll put an arbitary 40 char limit on header size */
98433965Sjdp  for (i = 0; i < 40 && abfd->filename[i]; i++)
98533965Sjdp    {
98633965Sjdp      *dst++ = abfd->filename[i];
98733965Sjdp    }
98833965Sjdp  return srec_write_record (abfd, 0, 0, buffer, dst);
98933965Sjdp}
99033965Sjdp
99133965Sjdpstatic boolean
99233965Sjdpsrec_write_section (abfd, tdata, list)
99333965Sjdp     bfd *abfd;
99433965Sjdp     tdata_type *tdata;
99533965Sjdp     srec_data_list_type *list;
99633965Sjdp{
99733965Sjdp  unsigned int bytes_written = 0;
99833965Sjdp  bfd_byte *location = list->data;
99933965Sjdp
100033965Sjdp  while (bytes_written < list->size)
100133965Sjdp    {
100233965Sjdp      bfd_vma address;
100333965Sjdp
100433965Sjdp      unsigned int bytes_this_chunk = list->size - bytes_written;
100533965Sjdp
100633965Sjdp      if (bytes_this_chunk > CHUNK)
100733965Sjdp	{
100833965Sjdp	  bytes_this_chunk = CHUNK;
100933965Sjdp	}
101033965Sjdp
101133965Sjdp      address = list->where + bytes_written;
101233965Sjdp
101333965Sjdp      if (! srec_write_record (abfd,
101433965Sjdp			       tdata->type,
101533965Sjdp			       address,
101633965Sjdp			       location,
101733965Sjdp			       location + bytes_this_chunk))
101833965Sjdp	return false;
101933965Sjdp
102033965Sjdp      bytes_written += bytes_this_chunk;
102133965Sjdp      location += bytes_this_chunk;
102233965Sjdp    }
102333965Sjdp
102433965Sjdp  return true;
102533965Sjdp}
102633965Sjdp
102733965Sjdpstatic boolean
102833965Sjdpsrec_write_terminator (abfd, tdata)
102933965Sjdp     bfd *abfd;
103033965Sjdp     tdata_type *tdata;
103133965Sjdp{
103233965Sjdp  bfd_byte buffer[2];
103333965Sjdp
103433965Sjdp  return srec_write_record (abfd, 10 - tdata->type,
103533965Sjdp			    abfd->start_address, buffer, buffer);
103633965Sjdp}
103733965Sjdp
103833965Sjdp
103933965Sjdp
104033965Sjdpstatic boolean
104133965Sjdpsrec_write_symbols (abfd)
104233965Sjdp     bfd *abfd;
104333965Sjdp{
104433965Sjdp  char buffer[MAXCHUNK];
104533965Sjdp  /* Dump out the symbols of a bfd */
104633965Sjdp  int i;
104733965Sjdp  int count = bfd_get_symcount (abfd);
104833965Sjdp
104933965Sjdp  if (count)
105033965Sjdp    {
105133965Sjdp      size_t len;
105233965Sjdp      asymbol **table = bfd_get_outsymbols (abfd);
105333965Sjdp      sprintf (buffer, "$$ %s\r\n", abfd->filename);
105433965Sjdp
105533965Sjdp      len = strlen (buffer);
105633965Sjdp      if (bfd_write (buffer, len, 1, abfd) != len)
105733965Sjdp	return false;
105833965Sjdp
105933965Sjdp      for (i = 0; i < count; i++)
106033965Sjdp	{
106133965Sjdp	  asymbol *s = table[i];
106233965Sjdp#if 0
106333965Sjdp	  int len = strlen (s->name);
106433965Sjdp
106533965Sjdp	  /* If this symbol has a .[ocs] in it, it's probably a file name
106633965Sjdp	 and we'll output that as the module name */
106733965Sjdp
106833965Sjdp	  if (len > 3 && s->name[len - 2] == '.')
106933965Sjdp	    {
107033965Sjdp	      int l;
107133965Sjdp	      sprintf (buffer, "$$ %s\r\n", s->name);
107233965Sjdp	      l = strlen (buffer);
107333965Sjdp	      if (bfd_write (buffer, l, 1, abfd) != l)
107433965Sjdp		return false;
107533965Sjdp	    }
107633965Sjdp	  else
107733965Sjdp#endif
107833965Sjdp	    if (s->flags & (BSF_GLOBAL | BSF_LOCAL)
107933965Sjdp		&& (s->flags & BSF_DEBUGGING) == 0
108033965Sjdp		&& s->name[0] != '.'
108133965Sjdp		&& s->name[0] != 't')
108233965Sjdp	    {
108333965Sjdp	      /* Just dump out non debug symbols */
108433965Sjdp	      bfd_size_type l;
108533965Sjdp	      char buf2[40], *p;
108633965Sjdp
108733965Sjdp	      sprintf_vma (buf2,
108833965Sjdp			   s->value + s->section->output_section->lma
108933965Sjdp			   + s->section->output_offset);
109033965Sjdp	      p = buf2;
109133965Sjdp	      while (p[0] == '0' && p[1] != 0)
109233965Sjdp		p++;
109333965Sjdp	      sprintf (buffer, "  %s $%s\r\n", s->name, p);
109433965Sjdp	      l = strlen (buffer);
109533965Sjdp	      if (bfd_write (buffer, l, 1, abfd) != l)
109633965Sjdp		return false;
109733965Sjdp	    }
109833965Sjdp	}
109933965Sjdp      sprintf (buffer, "$$ \r\n");
110033965Sjdp      len = strlen (buffer);
110133965Sjdp      if (bfd_write (buffer, len, 1, abfd) != len)
110233965Sjdp	return false;
110333965Sjdp    }
110433965Sjdp
110533965Sjdp  return true;
110633965Sjdp}
110733965Sjdp
110833965Sjdpstatic boolean
110933965Sjdpinternal_srec_write_object_contents (abfd, symbols)
111033965Sjdp     bfd *abfd;
111133965Sjdp     int symbols;
111233965Sjdp{
111333965Sjdp  tdata_type *tdata = abfd->tdata.srec_data;
111433965Sjdp  srec_data_list_type *list;
111533965Sjdp
111633965Sjdp  if (symbols)
111733965Sjdp    {
111833965Sjdp      if (! srec_write_symbols (abfd))
111933965Sjdp	return false;
112033965Sjdp    }
112133965Sjdp
112233965Sjdp  if (! srec_write_header (abfd))
112333965Sjdp    return false;
112433965Sjdp
112533965Sjdp  /* Now wander though all the sections provided and output them */
112633965Sjdp  list = tdata->head;
112733965Sjdp
112833965Sjdp  while (list != (srec_data_list_type *) NULL)
112933965Sjdp    {
113033965Sjdp      if (! srec_write_section (abfd, tdata, list))
113133965Sjdp	return false;
113233965Sjdp      list = list->next;
113333965Sjdp    }
113433965Sjdp  return srec_write_terminator (abfd, tdata);
113533965Sjdp}
113633965Sjdp
113733965Sjdpstatic boolean
113833965Sjdpsrec_write_object_contents (abfd)
113933965Sjdp     bfd *abfd;
114033965Sjdp{
114133965Sjdp  return internal_srec_write_object_contents (abfd, 0);
114233965Sjdp}
114333965Sjdp
114433965Sjdpstatic boolean
114533965Sjdpsymbolsrec_write_object_contents (abfd)
114633965Sjdp     bfd *abfd;
114733965Sjdp{
114833965Sjdp  return internal_srec_write_object_contents (abfd, 1);
114933965Sjdp}
115033965Sjdp
115133965Sjdp/*ARGSUSED*/
115233965Sjdpstatic int
115333965Sjdpsrec_sizeof_headers (abfd, exec)
115433965Sjdp     bfd *abfd;
115533965Sjdp     boolean exec;
115633965Sjdp{
115733965Sjdp  return 0;
115833965Sjdp}
115933965Sjdp
116033965Sjdpstatic asymbol *
116133965Sjdpsrec_make_empty_symbol (abfd)
116233965Sjdp     bfd *abfd;
116333965Sjdp{
116433965Sjdp  asymbol *new = (asymbol *) bfd_zalloc (abfd, sizeof (asymbol));
116533965Sjdp  if (new)
116633965Sjdp    new->the_bfd = abfd;
116733965Sjdp  return new;
116833965Sjdp}
116933965Sjdp
117033965Sjdp/* Return the amount of memory needed to read the symbol table.  */
117133965Sjdp
117233965Sjdpstatic long
117333965Sjdpsrec_get_symtab_upper_bound (abfd)
117433965Sjdp     bfd *abfd;
117533965Sjdp{
117633965Sjdp  return (bfd_get_symcount (abfd) + 1) * sizeof (asymbol *);
117733965Sjdp}
117833965Sjdp
117933965Sjdp/* Return the symbol table.  */
118033965Sjdp
118133965Sjdpstatic long
118233965Sjdpsrec_get_symtab (abfd, alocation)
118333965Sjdp     bfd *abfd;
118433965Sjdp     asymbol **alocation;
118533965Sjdp{
118633965Sjdp  unsigned int symcount = bfd_get_symcount (abfd);
118733965Sjdp  asymbol *csymbols;
118833965Sjdp  unsigned int i;
118933965Sjdp
119033965Sjdp  csymbols = abfd->tdata.srec_data->csymbols;
119133965Sjdp  if (csymbols == NULL)
119233965Sjdp    {
119333965Sjdp      asymbol *c;
119433965Sjdp      struct srec_symbol *s;
119533965Sjdp
119633965Sjdp      csymbols = (asymbol *) bfd_alloc (abfd, symcount * sizeof (asymbol));
119733965Sjdp      if (csymbols == NULL && symcount != 0)
119833965Sjdp	return false;
119933965Sjdp      abfd->tdata.srec_data->csymbols = csymbols;
120033965Sjdp
120133965Sjdp      for (s = abfd->tdata.srec_data->symbols, c = csymbols;
120233965Sjdp	   s != NULL;
120333965Sjdp	   s = s->next, ++c)
120433965Sjdp	{
120533965Sjdp	  c->the_bfd = abfd;
120633965Sjdp	  c->name = s->name;
120733965Sjdp	  c->value = s->val;
120833965Sjdp	  c->flags = BSF_GLOBAL;
120933965Sjdp	  c->section = bfd_abs_section_ptr;
121033965Sjdp	  c->udata.p = NULL;
121133965Sjdp	}
121233965Sjdp    }
121333965Sjdp
121433965Sjdp  for (i = 0; i < symcount; i++)
121533965Sjdp    *alocation++ = csymbols++;
121633965Sjdp  *alocation = NULL;
121733965Sjdp
121833965Sjdp  return symcount;
121933965Sjdp}
122033965Sjdp
122133965Sjdp/*ARGSUSED*/
122233965Sjdpstatic void
122333965Sjdpsrec_get_symbol_info (ignore_abfd, symbol, ret)
122433965Sjdp     bfd *ignore_abfd;
122533965Sjdp     asymbol *symbol;
122633965Sjdp     symbol_info *ret;
122733965Sjdp{
122833965Sjdp  bfd_symbol_info (symbol, ret);
122933965Sjdp}
123033965Sjdp
123133965Sjdp/*ARGSUSED*/
123233965Sjdpstatic void
123333965Sjdpsrec_print_symbol (ignore_abfd, afile, symbol, how)
123433965Sjdp     bfd *ignore_abfd;
123533965Sjdp     PTR afile;
123633965Sjdp     asymbol *symbol;
123733965Sjdp     bfd_print_symbol_type how;
123833965Sjdp{
123933965Sjdp  FILE *file = (FILE *) afile;
124033965Sjdp  switch (how)
124133965Sjdp    {
124233965Sjdp    case bfd_print_symbol_name:
124333965Sjdp      fprintf (file, "%s", symbol->name);
124433965Sjdp      break;
124533965Sjdp    default:
124633965Sjdp      bfd_print_symbol_vandf ((PTR) file, symbol);
124733965Sjdp      fprintf (file, " %-5s %s",
124833965Sjdp	       symbol->section->name,
124933965Sjdp	       symbol->name);
125033965Sjdp
125133965Sjdp    }
125233965Sjdp}
125333965Sjdp
125433965Sjdp#define	srec_close_and_cleanup _bfd_generic_close_and_cleanup
125533965Sjdp#define srec_bfd_free_cached_info _bfd_generic_bfd_free_cached_info
125633965Sjdp#define srec_new_section_hook _bfd_generic_new_section_hook
125733965Sjdp
125833965Sjdp#define srec_bfd_is_local_label_name bfd_generic_is_local_label_name
125933965Sjdp#define srec_get_lineno _bfd_nosymbols_get_lineno
126033965Sjdp#define srec_find_nearest_line _bfd_nosymbols_find_nearest_line
126133965Sjdp#define srec_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol
126233965Sjdp#define srec_read_minisymbols _bfd_generic_read_minisymbols
126333965Sjdp#define srec_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol
126433965Sjdp
126533965Sjdp#define srec_get_reloc_upper_bound \
126633965Sjdp  ((long (*) PARAMS ((bfd *, asection *))) bfd_0l)
126733965Sjdp#define srec_canonicalize_reloc \
126833965Sjdp  ((long (*) PARAMS ((bfd *, asection *, arelent **, asymbol **))) bfd_0l)
126933965Sjdp#define srec_bfd_reloc_type_lookup _bfd_norelocs_bfd_reloc_type_lookup
127033965Sjdp
127133965Sjdp#define srec_get_section_contents_in_window \
127233965Sjdp  _bfd_generic_get_section_contents_in_window
127333965Sjdp
127433965Sjdp#define srec_bfd_get_relocated_section_contents \
127533965Sjdp  bfd_generic_get_relocated_section_contents
127633965Sjdp#define srec_bfd_relax_section bfd_generic_relax_section
127733965Sjdp#define srec_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
127833965Sjdp#define srec_bfd_link_add_symbols _bfd_generic_link_add_symbols
127933965Sjdp#define srec_bfd_final_link _bfd_generic_final_link
128033965Sjdp#define srec_bfd_link_split_section _bfd_generic_link_split_section
128133965Sjdp
128233965Sjdpconst bfd_target srec_vec =
128333965Sjdp{
128433965Sjdp  "srec",			/* name */
128533965Sjdp  bfd_target_srec_flavour,
128633965Sjdp  BFD_ENDIAN_UNKNOWN,		/* target byte order */
128733965Sjdp  BFD_ENDIAN_UNKNOWN,		/* target headers byte order */
128833965Sjdp  (HAS_RELOC | EXEC_P |		/* object flags */
128933965Sjdp   HAS_LINENO | HAS_DEBUG |
129033965Sjdp   HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
129133965Sjdp  (SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS
129233965Sjdp   | SEC_ALLOC | SEC_LOAD | SEC_RELOC),	/* section flags */
129333965Sjdp  0,				/* leading underscore */
129433965Sjdp  ' ',				/* ar_pad_char */
129533965Sjdp  16,				/* ar_max_namelen */
129633965Sjdp  bfd_getb64, bfd_getb_signed_64, bfd_putb64,
129733965Sjdp  bfd_getb32, bfd_getb_signed_32, bfd_putb32,
129833965Sjdp  bfd_getb16, bfd_getb_signed_16, bfd_putb16,	/* data */
129933965Sjdp  bfd_getb64, bfd_getb_signed_64, bfd_putb64,
130033965Sjdp  bfd_getb32, bfd_getb_signed_32, bfd_putb32,
130133965Sjdp  bfd_getb16, bfd_getb_signed_16, bfd_putb16,	/* hdrs */
130233965Sjdp
130333965Sjdp  {
130433965Sjdp    _bfd_dummy_target,
130533965Sjdp    srec_object_p,		/* bfd_check_format */
130633965Sjdp    _bfd_dummy_target,
130733965Sjdp    _bfd_dummy_target,
130833965Sjdp  },
130933965Sjdp  {
131033965Sjdp    bfd_false,
131133965Sjdp    srec_mkobject,
131233965Sjdp    _bfd_generic_mkarchive,
131333965Sjdp    bfd_false,
131433965Sjdp  },
131533965Sjdp  {				/* bfd_write_contents */
131633965Sjdp    bfd_false,
131733965Sjdp    srec_write_object_contents,
131833965Sjdp    _bfd_write_archive_contents,
131933965Sjdp    bfd_false,
132033965Sjdp  },
132133965Sjdp
132233965Sjdp  BFD_JUMP_TABLE_GENERIC (srec),
132333965Sjdp  BFD_JUMP_TABLE_COPY (_bfd_generic),
132433965Sjdp  BFD_JUMP_TABLE_CORE (_bfd_nocore),
132533965Sjdp  BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
132633965Sjdp  BFD_JUMP_TABLE_SYMBOLS (srec),
132733965Sjdp  BFD_JUMP_TABLE_RELOCS (srec),
132833965Sjdp  BFD_JUMP_TABLE_WRITE (srec),
132933965Sjdp  BFD_JUMP_TABLE_LINK (srec),
133033965Sjdp  BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
133133965Sjdp
133233965Sjdp  (PTR) 0
133333965Sjdp};
133433965Sjdp
133533965Sjdp
133633965Sjdp
133733965Sjdpconst bfd_target symbolsrec_vec =
133833965Sjdp{
133933965Sjdp  "symbolsrec",			/* name */
134033965Sjdp  bfd_target_srec_flavour,
134133965Sjdp  BFD_ENDIAN_UNKNOWN,		/* target byte order */
134233965Sjdp  BFD_ENDIAN_UNKNOWN,		/* target headers byte order */
134333965Sjdp  (HAS_RELOC | EXEC_P |		/* object flags */
134433965Sjdp   HAS_LINENO | HAS_DEBUG |
134533965Sjdp   HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
134633965Sjdp  (SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS
134733965Sjdp   | SEC_ALLOC | SEC_LOAD | SEC_RELOC),	/* section flags */
134833965Sjdp  0,				/* leading underscore */
134933965Sjdp  ' ',				/* ar_pad_char */
135033965Sjdp  16,				/* ar_max_namelen */
135133965Sjdp  bfd_getb64, bfd_getb_signed_64, bfd_putb64,
135233965Sjdp  bfd_getb32, bfd_getb_signed_32, bfd_putb32,
135333965Sjdp  bfd_getb16, bfd_getb_signed_16, bfd_putb16,	/* data */
135433965Sjdp  bfd_getb64, bfd_getb_signed_64, bfd_putb64,
135533965Sjdp  bfd_getb32, bfd_getb_signed_32, bfd_putb32,
135633965Sjdp  bfd_getb16, bfd_getb_signed_16, bfd_putb16,	/* hdrs */
135733965Sjdp
135833965Sjdp  {
135933965Sjdp    _bfd_dummy_target,
136033965Sjdp    symbolsrec_object_p,	/* bfd_check_format */
136133965Sjdp    _bfd_dummy_target,
136233965Sjdp    _bfd_dummy_target,
136333965Sjdp  },
136433965Sjdp  {
136533965Sjdp    bfd_false,
136633965Sjdp    srec_mkobject,
136733965Sjdp    _bfd_generic_mkarchive,
136833965Sjdp    bfd_false,
136933965Sjdp  },
137033965Sjdp  {				/* bfd_write_contents */
137133965Sjdp    bfd_false,
137233965Sjdp    symbolsrec_write_object_contents,
137333965Sjdp    _bfd_write_archive_contents,
137433965Sjdp    bfd_false,
137533965Sjdp  },
137633965Sjdp
137733965Sjdp  BFD_JUMP_TABLE_GENERIC (srec),
137833965Sjdp  BFD_JUMP_TABLE_COPY (_bfd_generic),
137933965Sjdp  BFD_JUMP_TABLE_CORE (_bfd_nocore),
138033965Sjdp  BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
138133965Sjdp  BFD_JUMP_TABLE_SYMBOLS (srec),
138233965Sjdp  BFD_JUMP_TABLE_RELOCS (srec),
138333965Sjdp  BFD_JUMP_TABLE_WRITE (srec),
138433965Sjdp  BFD_JUMP_TABLE_LINK (srec),
138533965Sjdp  BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
138633965Sjdp
138733965Sjdp  (PTR) 0
138833965Sjdp};
1389