12159047fSniklas /* BFD back-end for s-record objects.
2b55d4692Sfgsch Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
3*007c2a45Smiod 2000, 2001, 2002, 2003
4b305b0f1Sespie Free Software Foundation, Inc.
52159047fSniklas Written by Steve Chamberlain of Cygnus Support <sac@cygnus.com>.
62159047fSniklas
72159047fSniklas This file is part of BFD, the Binary File Descriptor library.
82159047fSniklas
92159047fSniklas This program is free software; you can redistribute it and/or modify
102159047fSniklas it under the terms of the GNU General Public License as published by
112159047fSniklas the Free Software Foundation; either version 2 of the License, or
122159047fSniklas (at your option) any later version.
132159047fSniklas
142159047fSniklas This program is distributed in the hope that it will be useful,
152159047fSniklas but WITHOUT ANY WARRANTY; without even the implied warranty of
162159047fSniklas MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
172159047fSniklas GNU General Public License for more details.
182159047fSniklas
192159047fSniklas You should have received a copy of the GNU General Public License
202159047fSniklas along with this program; if not, write to the Free Software
212159047fSniklas Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
222159047fSniklas
232159047fSniklas /*
242159047fSniklas SUBSECTION
252159047fSniklas S-Record handling
262159047fSniklas
272159047fSniklas DESCRIPTION
282159047fSniklas
292159047fSniklas Ordinary S-Records cannot hold anything but addresses and
302159047fSniklas data, so that's all that we implement.
312159047fSniklas
322159047fSniklas The only interesting thing is that S-Records may come out of
332159047fSniklas order and there is no header, so an initial scan is required
342159047fSniklas to discover the minimum and maximum addresses used to create
352159047fSniklas the vma and size of the only section we create. We
362159047fSniklas arbitrarily call this section ".text".
372159047fSniklas
382159047fSniklas When bfd_get_section_contents is called the file is read
392159047fSniklas again, and this time the data is placed into a bfd_alloc'd
402159047fSniklas area.
412159047fSniklas
422159047fSniklas Any number of sections may be created for output, we save them
432159047fSniklas up and output them when it's time to close the bfd.
442159047fSniklas
452159047fSniklas An s record looks like:
462159047fSniklas
472159047fSniklas EXAMPLE
482159047fSniklas S<type><length><address><data><checksum>
492159047fSniklas
502159047fSniklas DESCRIPTION
512159047fSniklas Where
522159047fSniklas o length
532159047fSniklas is the number of bytes following upto the checksum. Note that
542159047fSniklas this is not the number of chars following, since it takes two
552159047fSniklas chars to represent a byte.
562159047fSniklas o type
572159047fSniklas is one of:
582159047fSniklas 0) header record
592159047fSniklas 1) two byte address data record
602159047fSniklas 2) three byte address data record
612159047fSniklas 3) four byte address data record
622159047fSniklas 7) four byte address termination record
632159047fSniklas 8) three byte address termination record
642159047fSniklas 9) two byte address termination record
652159047fSniklas
662159047fSniklas o address
672159047fSniklas is the start address of the data following, or in the case of
682159047fSniklas a termination record, the start address of the image
692159047fSniklas o data
702159047fSniklas is the data.
712159047fSniklas o checksum
722159047fSniklas is the sum of all the raw byte data in the record, from the length
732159047fSniklas upwards, modulo 256 and subtracted from 255.
742159047fSniklas
752159047fSniklas SUBSECTION
762159047fSniklas Symbol S-Record handling
772159047fSniklas
782159047fSniklas DESCRIPTION
792159047fSniklas Some ICE equipment understands an addition to the standard
802159047fSniklas S-Record format; symbols and their addresses can be sent
812159047fSniklas before the data.
822159047fSniklas
832159047fSniklas The format of this is:
842159047fSniklas ($$ <modulename>
852159047fSniklas (<space> <symbol> <address>)*)
862159047fSniklas $$
872159047fSniklas
882159047fSniklas so a short symbol table could look like:
892159047fSniklas
902159047fSniklas EXAMPLE
912159047fSniklas $$ flash.x
922159047fSniklas $$ flash.c
932159047fSniklas _port6 $0
942159047fSniklas _delay $4
952159047fSniklas _start $14
962159047fSniklas _etext $8036
972159047fSniklas _edata $8036
982159047fSniklas _end $8036
992159047fSniklas $$
1002159047fSniklas
1012159047fSniklas DESCRIPTION
1022159047fSniklas We allow symbols to be anywhere in the data stream - the module names
1032159047fSniklas are always ignored.
1042159047fSniklas
1052159047fSniklas */
1062159047fSniklas
1072159047fSniklas #include "bfd.h"
1082159047fSniklas #include "sysdep.h"
1092159047fSniklas #include "libbfd.h"
1102159047fSniklas #include "libiberty.h"
111c074d1c9Sdrahn #include "safe-ctype.h"
1122159047fSniklas
113b305b0f1Sespie static void srec_get_symbol_info PARAMS ((bfd *, asymbol *, symbol_info *));
114e93f7393Sniklas static void srec_print_symbol
115e93f7393Sniklas PARAMS ((bfd *, PTR, asymbol *, bfd_print_symbol_type));
1162159047fSniklas static void srec_init PARAMS ((void));
117c074d1c9Sdrahn static bfd_boolean srec_mkobject PARAMS ((bfd *));
118c074d1c9Sdrahn static int srec_get_byte PARAMS ((bfd *, bfd_boolean *));
119c074d1c9Sdrahn static void srec_bad_byte PARAMS ((bfd *, unsigned int, int, bfd_boolean));
120c074d1c9Sdrahn static bfd_boolean srec_scan PARAMS ((bfd *));
1212159047fSniklas static const bfd_target *srec_object_p PARAMS ((bfd *));
1222159047fSniklas static const bfd_target *symbolsrec_object_p PARAMS ((bfd *));
123c074d1c9Sdrahn static bfd_boolean srec_read_section PARAMS ((bfd *, asection *, bfd_byte *));
1242159047fSniklas
125c074d1c9Sdrahn static bfd_boolean srec_write_record
126c074d1c9Sdrahn PARAMS ((bfd *, unsigned int, bfd_vma, const bfd_byte *, const bfd_byte *));
127c074d1c9Sdrahn static bfd_boolean srec_write_header PARAMS ((bfd *));
128c074d1c9Sdrahn static bfd_boolean srec_write_symbols PARAMS ((bfd *));
129c074d1c9Sdrahn static bfd_boolean srec_new_symbol PARAMS ((bfd *, const char *, bfd_vma));
130c074d1c9Sdrahn static bfd_boolean srec_get_section_contents
131e93f7393Sniklas PARAMS ((bfd *, asection *, PTR, file_ptr, bfd_size_type));
132c074d1c9Sdrahn static bfd_boolean srec_set_arch_mach
133e93f7393Sniklas PARAMS ((bfd *, enum bfd_architecture, unsigned long));
134c074d1c9Sdrahn static bfd_boolean srec_set_section_contents
135*007c2a45Smiod PARAMS ((bfd *, sec_ptr, const PTR, file_ptr, bfd_size_type));
136c074d1c9Sdrahn static bfd_boolean internal_srec_write_object_contents PARAMS ((bfd *, int));
137c074d1c9Sdrahn static bfd_boolean srec_write_object_contents PARAMS ((bfd *));
138c074d1c9Sdrahn static bfd_boolean symbolsrec_write_object_contents PARAMS ((bfd *));
139c074d1c9Sdrahn static int srec_sizeof_headers PARAMS ((bfd *, bfd_boolean));
140e93f7393Sniklas static long srec_get_symtab_upper_bound PARAMS ((bfd *));
141*007c2a45Smiod static long srec_canonicalize_symtab PARAMS ((bfd *, asymbol **));
1422159047fSniklas
1432159047fSniklas /* Macros for converting between hex and binary. */
1442159047fSniklas
145c074d1c9Sdrahn static const char digs[] = "0123456789ABCDEF";
1462159047fSniklas
1472159047fSniklas #define NIBBLE(x) hex_value(x)
1482159047fSniklas #define HEX(buffer) ((NIBBLE((buffer)[0])<<4) + NIBBLE((buffer)[1]))
1492159047fSniklas #define TOHEX(d, x, ch) \
1502159047fSniklas d[1] = digs[(x) & 0xf]; \
1512159047fSniklas d[0] = digs[((x)>>4)&0xf]; \
1522159047fSniklas ch += ((x) & 0xff);
1532159047fSniklas #define ISHEX(x) hex_p(x)
1542159047fSniklas
1552159047fSniklas /* Initialize by filling in the hex conversion array. */
1562159047fSniklas
1572159047fSniklas static void
srec_init()1582159047fSniklas srec_init ()
1592159047fSniklas {
160c074d1c9Sdrahn static bfd_boolean inited = FALSE;
1612159047fSniklas
162c074d1c9Sdrahn if (! inited)
1632159047fSniklas {
164c074d1c9Sdrahn inited = TRUE;
1652159047fSniklas hex_init ();
1662159047fSniklas }
1672159047fSniklas }
1682159047fSniklas
169c074d1c9Sdrahn /* The maximum number of address+data+crc bytes on a line is FF. */
1702159047fSniklas #define MAXCHUNK 0xff
171b55d4692Sfgsch
172b55d4692Sfgsch /* Default size for a CHUNK. */
173b55d4692Sfgsch #define DEFAULT_CHUNK 16
174b55d4692Sfgsch
175c074d1c9Sdrahn /* The number of data bytes we actually fit onto a line on output.
176b55d4692Sfgsch This variable can be modified by objcopy's --srec-len parameter.
177b55d4692Sfgsch For a 0x75 byte record you should set --srec-len=0x70. */
178b55d4692Sfgsch unsigned int Chunk = DEFAULT_CHUNK;
179b55d4692Sfgsch
180b55d4692Sfgsch /* The type of srec output (free or forced to S3).
181b55d4692Sfgsch This variable can be modified by objcopy's --srec-forceS3
182b55d4692Sfgsch parameter. */
183c074d1c9Sdrahn bfd_boolean S3Forced = FALSE;
1842159047fSniklas
1852159047fSniklas /* When writing an S-record file, the S-records can not be output as
1862159047fSniklas they are seen. This structure is used to hold them in memory. */
1872159047fSniklas
1882159047fSniklas struct srec_data_list_struct
1892159047fSniklas {
1902159047fSniklas struct srec_data_list_struct *next;
1912159047fSniklas bfd_byte *data;
1922159047fSniklas bfd_vma where;
1932159047fSniklas bfd_size_type size;
1942159047fSniklas };
1952159047fSniklas
1962159047fSniklas typedef struct srec_data_list_struct srec_data_list_type;
1972159047fSniklas
1982159047fSniklas /* When scanning the S-record file, a linked list of srec_symbol
1992159047fSniklas structures is built to represent the symbol table (if there is
2002159047fSniklas one). */
2012159047fSniklas
2022159047fSniklas struct srec_symbol
2032159047fSniklas {
2042159047fSniklas struct srec_symbol *next;
2052159047fSniklas const char *name;
2062159047fSniklas bfd_vma val;
2072159047fSniklas };
2082159047fSniklas
2092159047fSniklas /* The S-record tdata information. */
2102159047fSniklas
2112159047fSniklas typedef struct srec_data_struct
2122159047fSniklas {
2132159047fSniklas srec_data_list_type *head;
2142159047fSniklas srec_data_list_type *tail;
2152159047fSniklas unsigned int type;
2162159047fSniklas struct srec_symbol *symbols;
2172159047fSniklas struct srec_symbol *symtail;
2182159047fSniklas asymbol *csymbols;
2192159047fSniklas }
2202159047fSniklas tdata_type;
2212159047fSniklas
222c074d1c9Sdrahn static bfd_boolean srec_write_section
223c074d1c9Sdrahn PARAMS ((bfd *, tdata_type *, srec_data_list_type *));
224c074d1c9Sdrahn static bfd_boolean srec_write_terminator
225c074d1c9Sdrahn PARAMS ((bfd *, tdata_type *));
2262159047fSniklas
2272159047fSniklas /* Set up the S-record tdata information. */
2282159047fSniklas
229c074d1c9Sdrahn static bfd_boolean
srec_mkobject(abfd)2302159047fSniklas srec_mkobject (abfd)
2312159047fSniklas bfd *abfd;
2322159047fSniklas {
233c074d1c9Sdrahn bfd_size_type amt;
234c074d1c9Sdrahn tdata_type *tdata;
235c074d1c9Sdrahn
2362159047fSniklas srec_init ();
2372159047fSniklas
238c074d1c9Sdrahn amt = sizeof (tdata_type);
239c074d1c9Sdrahn tdata = (tdata_type *) bfd_alloc (abfd, amt);
2402159047fSniklas if (tdata == NULL)
241c074d1c9Sdrahn return FALSE;
242c074d1c9Sdrahn
2432159047fSniklas abfd->tdata.srec_data = tdata;
2442159047fSniklas tdata->type = 1;
2452159047fSniklas tdata->head = NULL;
2462159047fSniklas tdata->tail = NULL;
2472159047fSniklas tdata->symbols = NULL;
2482159047fSniklas tdata->symtail = NULL;
2492159047fSniklas tdata->csymbols = NULL;
2502159047fSniklas
251c074d1c9Sdrahn return TRUE;
2522159047fSniklas }
2532159047fSniklas
2542159047fSniklas /* Read a byte from an S record file. Set *ERRORPTR if an error
2552159047fSniklas occurred. Return EOF on error or end of file. */
2562159047fSniklas
2572159047fSniklas static int
srec_get_byte(abfd,errorptr)2582159047fSniklas srec_get_byte (abfd, errorptr)
2592159047fSniklas bfd *abfd;
260c074d1c9Sdrahn bfd_boolean *errorptr;
2612159047fSniklas {
2622159047fSniklas bfd_byte c;
2632159047fSniklas
264c074d1c9Sdrahn if (bfd_bread (&c, (bfd_size_type) 1, abfd) != 1)
2652159047fSniklas {
2662159047fSniklas if (bfd_get_error () != bfd_error_file_truncated)
267c074d1c9Sdrahn *errorptr = TRUE;
2682159047fSniklas return EOF;
2692159047fSniklas }
2702159047fSniklas
2712159047fSniklas return (int) (c & 0xff);
2722159047fSniklas }
2732159047fSniklas
2742159047fSniklas /* Report a problem in an S record file. FIXME: This probably should
2752159047fSniklas not call fprintf, but we really do need some mechanism for printing
2762159047fSniklas error messages. */
2772159047fSniklas
2782159047fSniklas static void
srec_bad_byte(abfd,lineno,c,error)2792159047fSniklas srec_bad_byte (abfd, lineno, c, error)
2802159047fSniklas bfd *abfd;
2812159047fSniklas unsigned int lineno;
2822159047fSniklas int c;
283c074d1c9Sdrahn bfd_boolean error;
2842159047fSniklas {
2852159047fSniklas if (c == EOF)
2862159047fSniklas {
2872159047fSniklas if (! error)
2882159047fSniklas bfd_set_error (bfd_error_file_truncated);
2892159047fSniklas }
2902159047fSniklas else
2912159047fSniklas {
2922159047fSniklas char buf[10];
2932159047fSniklas
294c074d1c9Sdrahn if (! ISPRINT (c))
2952159047fSniklas sprintf (buf, "\\%03o", (unsigned int) c);
2962159047fSniklas else
2972159047fSniklas {
2982159047fSniklas buf[0] = c;
2992159047fSniklas buf[1] = '\0';
3002159047fSniklas }
3012159047fSniklas (*_bfd_error_handler)
302b305b0f1Sespie (_("%s:%d: Unexpected character `%s' in S-record file\n"),
303c074d1c9Sdrahn bfd_archive_filename (abfd), lineno, buf);
3042159047fSniklas bfd_set_error (bfd_error_bad_value);
3052159047fSniklas }
3062159047fSniklas }
3072159047fSniklas
3082159047fSniklas /* Add a new symbol found in an S-record file. */
3092159047fSniklas
310c074d1c9Sdrahn static bfd_boolean
srec_new_symbol(abfd,name,val)3112159047fSniklas srec_new_symbol (abfd, name, val)
3122159047fSniklas bfd *abfd;
3132159047fSniklas const char *name;
3142159047fSniklas bfd_vma val;
3152159047fSniklas {
3162159047fSniklas struct srec_symbol *n;
317c074d1c9Sdrahn bfd_size_type amt = sizeof (struct srec_symbol);
3182159047fSniklas
319c074d1c9Sdrahn n = (struct srec_symbol *) bfd_alloc (abfd, amt);
3202159047fSniklas if (n == NULL)
321c074d1c9Sdrahn return FALSE;
3222159047fSniklas
3232159047fSniklas n->name = name;
3242159047fSniklas n->val = val;
3252159047fSniklas
3262159047fSniklas if (abfd->tdata.srec_data->symbols == NULL)
3272159047fSniklas abfd->tdata.srec_data->symbols = n;
3282159047fSniklas else
3292159047fSniklas abfd->tdata.srec_data->symtail->next = n;
3302159047fSniklas abfd->tdata.srec_data->symtail = n;
3312159047fSniklas n->next = NULL;
3322159047fSniklas
3332159047fSniklas ++abfd->symcount;
3342159047fSniklas
335c074d1c9Sdrahn return TRUE;
3362159047fSniklas }
3372159047fSniklas
3382159047fSniklas /* Read the S record file and turn it into sections. We create a new
3392159047fSniklas section for each contiguous set of bytes. */
3402159047fSniklas
341c074d1c9Sdrahn static bfd_boolean
srec_scan(abfd)3422159047fSniklas srec_scan (abfd)
3432159047fSniklas bfd *abfd;
3442159047fSniklas {
3452159047fSniklas int c;
3462159047fSniklas unsigned int lineno = 1;
347c074d1c9Sdrahn bfd_boolean error = FALSE;
3482159047fSniklas bfd_byte *buf = NULL;
3492159047fSniklas size_t bufsize = 0;
3502159047fSniklas asection *sec = NULL;
351b305b0f1Sespie char *symbuf = NULL;
3522159047fSniklas
3532159047fSniklas if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0)
3542159047fSniklas goto error_return;
3552159047fSniklas
3562159047fSniklas while ((c = srec_get_byte (abfd, &error)) != EOF)
3572159047fSniklas {
3582159047fSniklas /* We only build sections from contiguous S-records, so if this
3592159047fSniklas is not an S-record, then stop building a section. */
3602159047fSniklas if (c != 'S' && c != '\r' && c != '\n')
3612159047fSniklas sec = NULL;
3622159047fSniklas
3632159047fSniklas switch (c)
3642159047fSniklas {
3652159047fSniklas default:
3662159047fSniklas srec_bad_byte (abfd, lineno, c, error);
3672159047fSniklas goto error_return;
3682159047fSniklas
3692159047fSniklas case '\n':
3702159047fSniklas ++lineno;
3712159047fSniklas break;
3722159047fSniklas
3732159047fSniklas case '\r':
3742159047fSniklas break;
3752159047fSniklas
3762159047fSniklas case '$':
3772159047fSniklas /* Starting a module name, which we ignore. */
3782159047fSniklas while ((c = srec_get_byte (abfd, &error)) != '\n'
3792159047fSniklas && c != EOF)
3802159047fSniklas ;
3812159047fSniklas if (c == EOF)
3822159047fSniklas {
3832159047fSniklas srec_bad_byte (abfd, lineno, c, error);
3842159047fSniklas goto error_return;
3852159047fSniklas }
3862159047fSniklas
3872159047fSniklas ++lineno;
3882159047fSniklas
3892159047fSniklas break;
3902159047fSniklas
3912159047fSniklas case ' ':
392e93f7393Sniklas do
3932159047fSniklas {
394c074d1c9Sdrahn bfd_size_type alc;
395b305b0f1Sespie char *p, *symname;
3962159047fSniklas bfd_vma symval;
3972159047fSniklas
3982159047fSniklas /* Starting a symbol definition. */
3992159047fSniklas while ((c = srec_get_byte (abfd, &error)) != EOF
4002159047fSniklas && (c == ' ' || c == '\t'))
4012159047fSniklas ;
402e93f7393Sniklas
403b305b0f1Sespie if (c == '\n' || c == '\r')
404e93f7393Sniklas break;
405e93f7393Sniklas
4062159047fSniklas if (c == EOF)
4072159047fSniklas {
4082159047fSniklas srec_bad_byte (abfd, lineno, c, error);
4092159047fSniklas goto error_return;
4102159047fSniklas }
4112159047fSniklas
412b305b0f1Sespie alc = 10;
413b305b0f1Sespie symbuf = (char *) bfd_malloc (alc + 1);
414b305b0f1Sespie if (symbuf == NULL)
415b305b0f1Sespie goto error_return;
416b305b0f1Sespie
417b305b0f1Sespie p = symbuf;
418b305b0f1Sespie
419b305b0f1Sespie *p++ = c;
4202159047fSniklas while ((c = srec_get_byte (abfd, &error)) != EOF
421c074d1c9Sdrahn && ! ISSPACE (c))
422b305b0f1Sespie {
423c074d1c9Sdrahn if ((bfd_size_type) (p - symbuf) >= alc)
424b305b0f1Sespie {
425b305b0f1Sespie char *n;
426b305b0f1Sespie
427b305b0f1Sespie alc *= 2;
428b305b0f1Sespie n = (char *) bfd_realloc (symbuf, alc + 1);
429b305b0f1Sespie if (n == NULL)
430b305b0f1Sespie goto error_return;
431b305b0f1Sespie p = n + (p - symbuf);
432b305b0f1Sespie symbuf = n;
433b305b0f1Sespie }
434b305b0f1Sespie
435b305b0f1Sespie *p++ = c;
436b305b0f1Sespie }
437b305b0f1Sespie
4382159047fSniklas if (c == EOF)
4392159047fSniklas {
4402159047fSniklas srec_bad_byte (abfd, lineno, c, error);
4412159047fSniklas goto error_return;
4422159047fSniklas }
4432159047fSniklas
444b305b0f1Sespie *p++ = '\0';
445c074d1c9Sdrahn symname = bfd_alloc (abfd, (bfd_size_type) (p - symbuf));
4462159047fSniklas if (symname == NULL)
4472159047fSniklas goto error_return;
448b305b0f1Sespie strcpy (symname, symbuf);
449b305b0f1Sespie free (symbuf);
450b305b0f1Sespie symbuf = NULL;
4512159047fSniklas
4522159047fSniklas while ((c = srec_get_byte (abfd, &error)) != EOF
4532159047fSniklas && (c == ' ' || c == '\t'))
4542159047fSniklas ;
4552159047fSniklas if (c == EOF)
4562159047fSniklas {
4572159047fSniklas srec_bad_byte (abfd, lineno, c, error);
4582159047fSniklas goto error_return;
4592159047fSniklas }
4602159047fSniklas
4612159047fSniklas /* Skip a dollar sign before the hex value. */
4622159047fSniklas if (c == '$')
4632159047fSniklas {
4642159047fSniklas c = srec_get_byte (abfd, &error);
4652159047fSniklas if (c == EOF)
4662159047fSniklas {
4672159047fSniklas srec_bad_byte (abfd, lineno, c, error);
4682159047fSniklas goto error_return;
4692159047fSniklas }
4702159047fSniklas }
4712159047fSniklas
4722159047fSniklas symval = 0;
4732159047fSniklas while (ISHEX (c))
4742159047fSniklas {
4752159047fSniklas symval <<= 4;
4762159047fSniklas symval += NIBBLE (c);
4772159047fSniklas c = srec_get_byte (abfd, &error);
4782159047fSniklas }
4792159047fSniklas
480e93f7393Sniklas if (! srec_new_symbol (abfd, symname, symval))
481e93f7393Sniklas goto error_return;
482e93f7393Sniklas }
483b55d4692Sfgsch while (c == ' ' || c == '\t')
484b55d4692Sfgsch ;
485e93f7393Sniklas
486b305b0f1Sespie if (c == '\n')
487b305b0f1Sespie ++lineno;
488b305b0f1Sespie else if (c != '\r')
4892159047fSniklas {
4902159047fSniklas srec_bad_byte (abfd, lineno, c, error);
4912159047fSniklas goto error_return;
4922159047fSniklas }
4932159047fSniklas
4942159047fSniklas break;
4952159047fSniklas
4962159047fSniklas case 'S':
4972159047fSniklas {
4982159047fSniklas file_ptr pos;
4992159047fSniklas char hdr[3];
5002159047fSniklas unsigned int bytes;
5012159047fSniklas bfd_vma address;
5022159047fSniklas bfd_byte *data;
5032159047fSniklas
5042159047fSniklas /* Starting an S-record. */
5052159047fSniklas
5062159047fSniklas pos = bfd_tell (abfd) - 1;
5072159047fSniklas
508c074d1c9Sdrahn if (bfd_bread (hdr, (bfd_size_type) 3, abfd) != 3)
5092159047fSniklas goto error_return;
5102159047fSniklas
5112159047fSniklas if (! ISHEX (hdr[1]) || ! ISHEX (hdr[2]))
5122159047fSniklas {
5132159047fSniklas if (! ISHEX (hdr[1]))
5142159047fSniklas c = hdr[1];
5152159047fSniklas else
5162159047fSniklas c = hdr[2];
5172159047fSniklas srec_bad_byte (abfd, lineno, c, error);
5182159047fSniklas goto error_return;
5192159047fSniklas }
5202159047fSniklas
5212159047fSniklas bytes = HEX (hdr + 1);
5222159047fSniklas if (bytes * 2 > bufsize)
5232159047fSniklas {
5242159047fSniklas if (buf != NULL)
5252159047fSniklas free (buf);
526c074d1c9Sdrahn buf = (bfd_byte *) bfd_malloc ((bfd_size_type) bytes * 2);
5272159047fSniklas if (buf == NULL)
5282159047fSniklas goto error_return;
5292159047fSniklas bufsize = bytes * 2;
5302159047fSniklas }
5312159047fSniklas
532c074d1c9Sdrahn if (bfd_bread (buf, (bfd_size_type) bytes * 2, abfd) != bytes * 2)
5332159047fSniklas goto error_return;
5342159047fSniklas
5352159047fSniklas /* Ignore the checksum byte. */
5362159047fSniklas --bytes;
5372159047fSniklas
5382159047fSniklas address = 0;
5392159047fSniklas data = buf;
5402159047fSniklas switch (hdr[0])
5412159047fSniklas {
5422159047fSniklas case '0':
5432159047fSniklas case '5':
5442159047fSniklas /* Prologue--ignore the file name, but stop building a
5452159047fSniklas section at this point. */
5462159047fSniklas sec = NULL;
5472159047fSniklas break;
5482159047fSniklas
5492159047fSniklas case '3':
5502159047fSniklas address = HEX (data);
5512159047fSniklas data += 2;
5522159047fSniklas --bytes;
5532159047fSniklas /* Fall through. */
5542159047fSniklas case '2':
5552159047fSniklas address = (address << 8) | HEX (data);
5562159047fSniklas data += 2;
5572159047fSniklas --bytes;
5582159047fSniklas /* Fall through. */
5592159047fSniklas case '1':
5602159047fSniklas address = (address << 8) | HEX (data);
5612159047fSniklas data += 2;
5622159047fSniklas address = (address << 8) | HEX (data);
5632159047fSniklas data += 2;
5642159047fSniklas bytes -= 2;
5652159047fSniklas
5662159047fSniklas if (sec != NULL
5672159047fSniklas && sec->vma + sec->_raw_size == address)
5682159047fSniklas {
5692159047fSniklas /* This data goes at the end of the section we are
5702159047fSniklas currently building. */
5712159047fSniklas sec->_raw_size += bytes;
5722159047fSniklas }
5732159047fSniklas else
5742159047fSniklas {
5752159047fSniklas char secbuf[20];
5762159047fSniklas char *secname;
577c074d1c9Sdrahn bfd_size_type amt;
5782159047fSniklas
5792159047fSniklas sprintf (secbuf, ".sec%d", bfd_count_sections (abfd) + 1);
580c074d1c9Sdrahn amt = strlen (secbuf) + 1;
581c074d1c9Sdrahn secname = (char *) bfd_alloc (abfd, amt);
5822159047fSniklas strcpy (secname, secbuf);
5832159047fSniklas sec = bfd_make_section (abfd, secname);
5842159047fSniklas if (sec == NULL)
5852159047fSniklas goto error_return;
5862159047fSniklas sec->flags = SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC;
5872159047fSniklas sec->vma = address;
588c88b1d6cSniklas sec->lma = address;
5892159047fSniklas sec->_raw_size = bytes;
5902159047fSniklas sec->filepos = pos;
5912159047fSniklas }
5922159047fSniklas
5932159047fSniklas break;
5942159047fSniklas
5952159047fSniklas case '7':
5962159047fSniklas address = HEX (data);
5972159047fSniklas data += 2;
5982159047fSniklas /* Fall through. */
5992159047fSniklas case '8':
6002159047fSniklas address = (address << 8) | HEX (data);
6012159047fSniklas data += 2;
6022159047fSniklas /* Fall through. */
6032159047fSniklas case '9':
6042159047fSniklas address = (address << 8) | HEX (data);
6052159047fSniklas data += 2;
6062159047fSniklas address = (address << 8) | HEX (data);
6072159047fSniklas data += 2;
6082159047fSniklas
6092159047fSniklas /* This is a termination record. */
6102159047fSniklas abfd->start_address = address;
6112159047fSniklas
6122159047fSniklas if (buf != NULL)
6132159047fSniklas free (buf);
6142159047fSniklas
615c074d1c9Sdrahn return TRUE;
6162159047fSniklas }
6172159047fSniklas }
6182159047fSniklas break;
6192159047fSniklas }
6202159047fSniklas }
6212159047fSniklas
6222159047fSniklas if (error)
6232159047fSniklas goto error_return;
6242159047fSniklas
6252159047fSniklas if (buf != NULL)
6262159047fSniklas free (buf);
6272159047fSniklas
628c074d1c9Sdrahn return TRUE;
6292159047fSniklas
6302159047fSniklas error_return:
631b305b0f1Sespie if (symbuf != NULL)
632b305b0f1Sespie free (symbuf);
6332159047fSniklas if (buf != NULL)
6342159047fSniklas free (buf);
635c074d1c9Sdrahn return FALSE;
6362159047fSniklas }
6372159047fSniklas
6382159047fSniklas /* Check whether an existing file is an S-record file. */
6392159047fSniklas
6402159047fSniklas static const bfd_target *
srec_object_p(abfd)6412159047fSniklas srec_object_p (abfd)
6422159047fSniklas bfd *abfd;
6432159047fSniklas {
644c074d1c9Sdrahn PTR tdata_save;
6452159047fSniklas bfd_byte b[4];
6462159047fSniklas
6472159047fSniklas srec_init ();
6482159047fSniklas
6492159047fSniklas if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0
650c074d1c9Sdrahn || bfd_bread (b, (bfd_size_type) 4, abfd) != 4)
6512159047fSniklas return NULL;
6522159047fSniklas
6532159047fSniklas if (b[0] != 'S' || !ISHEX (b[1]) || !ISHEX (b[2]) || !ISHEX (b[3]))
6542159047fSniklas {
6552159047fSniklas bfd_set_error (bfd_error_wrong_format);
6562159047fSniklas return NULL;
6572159047fSniklas }
6582159047fSniklas
659c074d1c9Sdrahn tdata_save = abfd->tdata.any;
660c074d1c9Sdrahn if (! srec_mkobject (abfd) || ! srec_scan (abfd))
661c074d1c9Sdrahn {
662c074d1c9Sdrahn if (abfd->tdata.any != tdata_save && abfd->tdata.any != NULL)
663c074d1c9Sdrahn bfd_release (abfd, abfd->tdata.any);
664c074d1c9Sdrahn abfd->tdata.any = tdata_save;
6652159047fSniklas return NULL;
666c074d1c9Sdrahn }
6672159047fSniklas
668b305b0f1Sespie if (abfd->symcount > 0)
669b305b0f1Sespie abfd->flags |= HAS_SYMS;
670b305b0f1Sespie
6712159047fSniklas return abfd->xvec;
6722159047fSniklas }
6732159047fSniklas
6742159047fSniklas /* Check whether an existing file is an S-record file with symbols. */
6752159047fSniklas
6762159047fSniklas static const bfd_target *
symbolsrec_object_p(abfd)6772159047fSniklas symbolsrec_object_p (abfd)
6782159047fSniklas bfd *abfd;
6792159047fSniklas {
680c074d1c9Sdrahn PTR tdata_save;
6812159047fSniklas char b[2];
6822159047fSniklas
6832159047fSniklas srec_init ();
6842159047fSniklas
6852159047fSniklas if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0
686c074d1c9Sdrahn || bfd_bread (b, (bfd_size_type) 2, abfd) != 2)
6872159047fSniklas return NULL;
6882159047fSniklas
6892159047fSniklas if (b[0] != '$' || b[1] != '$')
6902159047fSniklas {
6912159047fSniklas bfd_set_error (bfd_error_wrong_format);
6922159047fSniklas return NULL;
6932159047fSniklas }
6942159047fSniklas
695c074d1c9Sdrahn tdata_save = abfd->tdata.any;
696c074d1c9Sdrahn if (! srec_mkobject (abfd) || ! srec_scan (abfd))
697c074d1c9Sdrahn {
698c074d1c9Sdrahn if (abfd->tdata.any != tdata_save && abfd->tdata.any != NULL)
699c074d1c9Sdrahn bfd_release (abfd, abfd->tdata.any);
700c074d1c9Sdrahn abfd->tdata.any = tdata_save;
7012159047fSniklas return NULL;
702c074d1c9Sdrahn }
7032159047fSniklas
704b305b0f1Sespie if (abfd->symcount > 0)
705b305b0f1Sespie abfd->flags |= HAS_SYMS;
706b305b0f1Sespie
7072159047fSniklas return abfd->xvec;
7082159047fSniklas }
7092159047fSniklas
7102159047fSniklas /* Read in the contents of a section in an S-record file. */
7112159047fSniklas
712c074d1c9Sdrahn static bfd_boolean
srec_read_section(abfd,section,contents)7132159047fSniklas srec_read_section (abfd, section, contents)
7142159047fSniklas bfd *abfd;
7152159047fSniklas asection *section;
7162159047fSniklas bfd_byte *contents;
7172159047fSniklas {
7182159047fSniklas int c;
7192159047fSniklas bfd_size_type sofar = 0;
720c074d1c9Sdrahn bfd_boolean error = FALSE;
7212159047fSniklas bfd_byte *buf = NULL;
7222159047fSniklas size_t bufsize = 0;
7232159047fSniklas
7242159047fSniklas if (bfd_seek (abfd, section->filepos, SEEK_SET) != 0)
7252159047fSniklas goto error_return;
7262159047fSniklas
7272159047fSniklas while ((c = srec_get_byte (abfd, &error)) != EOF)
7282159047fSniklas {
7292159047fSniklas bfd_byte hdr[3];
7302159047fSniklas unsigned int bytes;
7312159047fSniklas bfd_vma address;
7322159047fSniklas bfd_byte *data;
7332159047fSniklas
7342159047fSniklas if (c == '\r' || c == '\n')
7352159047fSniklas continue;
7362159047fSniklas
7372159047fSniklas /* This is called after srec_scan has already been called, so we
7382159047fSniklas ought to know the exact format. */
7392159047fSniklas BFD_ASSERT (c == 'S');
7402159047fSniklas
741c074d1c9Sdrahn if (bfd_bread (hdr, (bfd_size_type) 3, abfd) != 3)
7422159047fSniklas goto error_return;
7432159047fSniklas
7442159047fSniklas BFD_ASSERT (ISHEX (hdr[1]) && ISHEX (hdr[2]));
7452159047fSniklas
7462159047fSniklas bytes = HEX (hdr + 1);
7472159047fSniklas
7482159047fSniklas if (bytes * 2 > bufsize)
7492159047fSniklas {
7502159047fSniklas if (buf != NULL)
7512159047fSniklas free (buf);
752c074d1c9Sdrahn buf = (bfd_byte *) bfd_malloc ((bfd_size_type) bytes * 2);
7532159047fSniklas if (buf == NULL)
7542159047fSniklas goto error_return;
7552159047fSniklas bufsize = bytes * 2;
7562159047fSniklas }
7572159047fSniklas
758c074d1c9Sdrahn if (bfd_bread (buf, (bfd_size_type) bytes * 2, abfd) != bytes * 2)
7592159047fSniklas goto error_return;
7602159047fSniklas
7612159047fSniklas address = 0;
7622159047fSniklas data = buf;
7632159047fSniklas switch (hdr[0])
7642159047fSniklas {
7652159047fSniklas default:
7662159047fSniklas BFD_ASSERT (sofar == section->_raw_size);
7672159047fSniklas if (buf != NULL)
7682159047fSniklas free (buf);
769c074d1c9Sdrahn return TRUE;
7702159047fSniklas
7712159047fSniklas case '3':
7722159047fSniklas address = HEX (data);
7732159047fSniklas data += 2;
7742159047fSniklas --bytes;
7752159047fSniklas /* Fall through. */
7762159047fSniklas case '2':
7772159047fSniklas address = (address << 8) | HEX (data);
7782159047fSniklas data += 2;
7792159047fSniklas --bytes;
7802159047fSniklas /* Fall through. */
7812159047fSniklas case '1':
7822159047fSniklas address = (address << 8) | HEX (data);
7832159047fSniklas data += 2;
7842159047fSniklas address = (address << 8) | HEX (data);
7852159047fSniklas data += 2;
7862159047fSniklas bytes -= 2;
7872159047fSniklas
7882159047fSniklas if (address != section->vma + sofar)
7892159047fSniklas {
7902159047fSniklas /* We've come to the end of this section. */
7912159047fSniklas BFD_ASSERT (sofar == section->_raw_size);
7922159047fSniklas if (buf != NULL)
7932159047fSniklas free (buf);
794c074d1c9Sdrahn return TRUE;
7952159047fSniklas }
7962159047fSniklas
7972159047fSniklas /* Don't consider checksum. */
7982159047fSniklas --bytes;
7992159047fSniklas
8002159047fSniklas while (bytes-- != 0)
8012159047fSniklas {
8022159047fSniklas contents[sofar] = HEX (data);
8032159047fSniklas data += 2;
8042159047fSniklas ++sofar;
8052159047fSniklas }
8062159047fSniklas
8072159047fSniklas break;
8082159047fSniklas }
8092159047fSniklas }
8102159047fSniklas
8112159047fSniklas if (error)
8122159047fSniklas goto error_return;
8132159047fSniklas
8142159047fSniklas BFD_ASSERT (sofar == section->_raw_size);
8152159047fSniklas
8162159047fSniklas if (buf != NULL)
8172159047fSniklas free (buf);
8182159047fSniklas
819c074d1c9Sdrahn return TRUE;
8202159047fSniklas
8212159047fSniklas error_return:
8222159047fSniklas if (buf != NULL)
8232159047fSniklas free (buf);
824c074d1c9Sdrahn return FALSE;
8252159047fSniklas }
8262159047fSniklas
8272159047fSniklas /* Get the contents of a section in an S-record file. */
8282159047fSniklas
829c074d1c9Sdrahn static bfd_boolean
srec_get_section_contents(abfd,section,location,offset,count)8302159047fSniklas srec_get_section_contents (abfd, section, location, offset, count)
8312159047fSniklas bfd *abfd;
8322159047fSniklas asection *section;
8332159047fSniklas PTR location;
8342159047fSniklas file_ptr offset;
8352159047fSniklas bfd_size_type count;
8362159047fSniklas {
8372159047fSniklas if (section->used_by_bfd == NULL)
8382159047fSniklas {
8392159047fSniklas section->used_by_bfd = bfd_alloc (abfd, section->_raw_size);
840c074d1c9Sdrahn if (section->used_by_bfd == NULL && section->_raw_size != 0)
841c074d1c9Sdrahn return FALSE;
8422159047fSniklas
8432159047fSniklas if (! srec_read_section (abfd, section, section->used_by_bfd))
844c074d1c9Sdrahn return FALSE;
8452159047fSniklas }
8462159047fSniklas
8472159047fSniklas memcpy (location, (bfd_byte *) section->used_by_bfd + offset,
8482159047fSniklas (size_t) count);
8492159047fSniklas
850c074d1c9Sdrahn return TRUE;
8512159047fSniklas }
8522159047fSniklas
853c88b1d6cSniklas /* Set the architecture. We accept an unknown architecture here. */
854c88b1d6cSniklas
855c074d1c9Sdrahn static bfd_boolean
srec_set_arch_mach(abfd,arch,mach)856c88b1d6cSniklas srec_set_arch_mach (abfd, arch, mach)
857c88b1d6cSniklas bfd *abfd;
858c88b1d6cSniklas enum bfd_architecture arch;
859c88b1d6cSniklas unsigned long mach;
860c88b1d6cSniklas {
861c88b1d6cSniklas if (arch == bfd_arch_unknown)
862c88b1d6cSniklas {
863c88b1d6cSniklas abfd->arch_info = &bfd_default_arch_struct;
864c074d1c9Sdrahn return TRUE;
865c88b1d6cSniklas }
866c88b1d6cSniklas return bfd_default_set_arch_mach (abfd, arch, mach);
867c88b1d6cSniklas }
868c88b1d6cSniklas
869b55d4692Sfgsch /* We have to save up all the Srecords for a splurge before output. */
8702159047fSniklas
871c074d1c9Sdrahn static bfd_boolean
srec_set_section_contents(abfd,section,location,offset,bytes_to_do)8722159047fSniklas srec_set_section_contents (abfd, section, location, offset, bytes_to_do)
8732159047fSniklas bfd *abfd;
8742159047fSniklas sec_ptr section;
875*007c2a45Smiod const PTR location;
8762159047fSniklas file_ptr offset;
8772159047fSniklas bfd_size_type bytes_to_do;
8782159047fSniklas {
8792159047fSniklas tdata_type *tdata = abfd->tdata.srec_data;
8802159047fSniklas register srec_data_list_type *entry;
8812159047fSniklas
8822159047fSniklas entry = ((srec_data_list_type *)
883c074d1c9Sdrahn bfd_alloc (abfd, (bfd_size_type) sizeof (srec_data_list_type)));
8842159047fSniklas if (entry == NULL)
885c074d1c9Sdrahn return FALSE;
8862159047fSniklas
8872159047fSniklas if (bytes_to_do
8882159047fSniklas && (section->flags & SEC_ALLOC)
8892159047fSniklas && (section->flags & SEC_LOAD))
8902159047fSniklas {
891c074d1c9Sdrahn bfd_byte *data;
892c074d1c9Sdrahn
893c074d1c9Sdrahn data = (bfd_byte *) bfd_alloc (abfd, bytes_to_do);
8942159047fSniklas if (data == NULL)
895c074d1c9Sdrahn return FALSE;
8962159047fSniklas memcpy ((PTR) data, location, (size_t) bytes_to_do);
8972159047fSniklas
898c074d1c9Sdrahn /* Ff S3Forced is TRUE then always select S3 records,
899b55d4692Sfgsch regardless of the siez of the addresses. */
900b55d4692Sfgsch if (S3Forced)
901b55d4692Sfgsch tdata->type = 3;
902b55d4692Sfgsch else if ((section->lma + offset + bytes_to_do - 1) <= 0xffff)
903b55d4692Sfgsch ; /* The default, S1, is OK. */
9042159047fSniklas else if ((section->lma + offset + bytes_to_do - 1) <= 0xffffff
905b305b0f1Sespie && tdata->type <= 2)
9062159047fSniklas tdata->type = 2;
9072159047fSniklas else
9082159047fSniklas tdata->type = 3;
9092159047fSniklas
9102159047fSniklas entry->data = data;
9112159047fSniklas entry->where = section->lma + offset;
9122159047fSniklas entry->size = bytes_to_do;
9132159047fSniklas
9142159047fSniklas /* Sort the records by address. Optimize for the common case of
9152159047fSniklas adding a record to the end of the list. */
9162159047fSniklas if (tdata->tail != NULL
9172159047fSniklas && entry->where >= tdata->tail->where)
9182159047fSniklas {
9192159047fSniklas tdata->tail->next = entry;
9202159047fSniklas entry->next = NULL;
9212159047fSniklas tdata->tail = entry;
9222159047fSniklas }
9232159047fSniklas else
9242159047fSniklas {
9252159047fSniklas register srec_data_list_type **look;
9262159047fSniklas
9272159047fSniklas for (look = &tdata->head;
9282159047fSniklas *look != NULL && (*look)->where < entry->where;
9292159047fSniklas look = &(*look)->next)
9302159047fSniklas ;
9312159047fSniklas entry->next = *look;
9322159047fSniklas *look = entry;
9332159047fSniklas if (entry->next == NULL)
9342159047fSniklas tdata->tail = entry;
9352159047fSniklas }
9362159047fSniklas }
937c074d1c9Sdrahn return TRUE;
9382159047fSniklas }
9392159047fSniklas
9402159047fSniklas /* Write a record of type, of the supplied number of bytes. The
9412159047fSniklas supplied bytes and length don't have a checksum. That's worked out
942b55d4692Sfgsch here. */
943b55d4692Sfgsch
944c074d1c9Sdrahn static bfd_boolean
srec_write_record(abfd,type,address,data,end)9452159047fSniklas srec_write_record (abfd, type, address, data, end)
9462159047fSniklas bfd *abfd;
947c074d1c9Sdrahn unsigned int type;
9482159047fSniklas bfd_vma address;
9492159047fSniklas const bfd_byte *data;
9502159047fSniklas const bfd_byte *end;
9512159047fSniklas {
952c074d1c9Sdrahn char buffer[2 * MAXCHUNK + 6];
9532159047fSniklas unsigned int check_sum = 0;
954c074d1c9Sdrahn const bfd_byte *src = data;
9552159047fSniklas char *dst = buffer;
9562159047fSniklas char *length;
9572159047fSniklas bfd_size_type wrlen;
9582159047fSniklas
9592159047fSniklas *dst++ = 'S';
9602159047fSniklas *dst++ = '0' + type;
9612159047fSniklas
9622159047fSniklas length = dst;
963b55d4692Sfgsch dst += 2; /* Leave room for dst. */
9642159047fSniklas
9652159047fSniklas switch (type)
9662159047fSniklas {
9672159047fSniklas case 3:
9682159047fSniklas case 7:
9692159047fSniklas TOHEX (dst, (address >> 24), check_sum);
9702159047fSniklas dst += 2;
9712159047fSniklas case 8:
9722159047fSniklas case 2:
9732159047fSniklas TOHEX (dst, (address >> 16), check_sum);
9742159047fSniklas dst += 2;
9752159047fSniklas case 9:
9762159047fSniklas case 1:
9772159047fSniklas case 0:
9782159047fSniklas TOHEX (dst, (address >> 8), check_sum);
9792159047fSniklas dst += 2;
9802159047fSniklas TOHEX (dst, (address), check_sum);
9812159047fSniklas dst += 2;
9822159047fSniklas break;
9832159047fSniklas
9842159047fSniklas }
9852159047fSniklas for (src = data; src < end; src++)
9862159047fSniklas {
9872159047fSniklas TOHEX (dst, *src, check_sum);
9882159047fSniklas dst += 2;
9892159047fSniklas }
9902159047fSniklas
991b55d4692Sfgsch /* Fill in the length. */
9922159047fSniklas TOHEX (length, (dst - length) / 2, check_sum);
9932159047fSniklas check_sum &= 0xff;
9942159047fSniklas check_sum = 255 - check_sum;
9952159047fSniklas TOHEX (dst, check_sum, check_sum);
9962159047fSniklas dst += 2;
9972159047fSniklas
9982159047fSniklas *dst++ = '\r';
9992159047fSniklas *dst++ = '\n';
10002159047fSniklas wrlen = dst - buffer;
1001c074d1c9Sdrahn if (bfd_bwrite ((PTR) buffer, wrlen, abfd) != wrlen)
1002c074d1c9Sdrahn return FALSE;
1003c074d1c9Sdrahn return TRUE;
10042159047fSniklas }
10052159047fSniklas
1006c074d1c9Sdrahn static bfd_boolean
srec_write_header(abfd)10072159047fSniklas srec_write_header (abfd)
10082159047fSniklas bfd *abfd;
10092159047fSniklas {
1010c074d1c9Sdrahn unsigned int len = strlen (abfd->filename);
10112159047fSniklas
1012*007c2a45Smiod /* I'll put an arbitrary 40 char limit on header size. */
1013c074d1c9Sdrahn if (len > 40)
1014c074d1c9Sdrahn len = 40;
1015b55d4692Sfgsch
1016c074d1c9Sdrahn return srec_write_record (abfd, 0, (bfd_vma) 0,
1017c074d1c9Sdrahn abfd->filename, abfd->filename + len);
10182159047fSniklas }
10192159047fSniklas
1020c074d1c9Sdrahn static bfd_boolean
srec_write_section(abfd,tdata,list)10212159047fSniklas srec_write_section (abfd, tdata, list)
10222159047fSniklas bfd *abfd;
10232159047fSniklas tdata_type *tdata;
10242159047fSniklas srec_data_list_type *list;
10252159047fSniklas {
1026b305b0f1Sespie unsigned int octets_written = 0;
10272159047fSniklas bfd_byte *location = list->data;
10282159047fSniklas
1029c074d1c9Sdrahn /* Validate number of data bytes to write. The srec length byte
1030c074d1c9Sdrahn counts the address, data and crc bytes. S1 (tdata->type == 1)
1031c074d1c9Sdrahn records have two address bytes, S2 (tdata->type == 2) records
1032c074d1c9Sdrahn have three, and S3 (tdata->type == 3) records have four.
1033c074d1c9Sdrahn The total length can't exceed 255, and a zero data length will
1034c074d1c9Sdrahn spin for a long time. */
1035c074d1c9Sdrahn if (Chunk == 0)
1036c074d1c9Sdrahn Chunk = 1;
1037c074d1c9Sdrahn else if (Chunk > MAXCHUNK - tdata->type - 2)
1038c074d1c9Sdrahn Chunk = MAXCHUNK - tdata->type - 2;
1039c074d1c9Sdrahn
1040b305b0f1Sespie while (octets_written < list->size)
10412159047fSniklas {
10422159047fSniklas bfd_vma address;
1043b305b0f1Sespie unsigned int octets_this_chunk = list->size - octets_written;
10442159047fSniklas
1045b55d4692Sfgsch if (octets_this_chunk > Chunk)
1046b55d4692Sfgsch octets_this_chunk = Chunk;
10472159047fSniklas
1048b305b0f1Sespie address = list->where + octets_written / bfd_octets_per_byte (abfd);
10492159047fSniklas
10502159047fSniklas if (! srec_write_record (abfd,
10512159047fSniklas tdata->type,
10522159047fSniklas address,
10532159047fSniklas location,
1054b305b0f1Sespie location + octets_this_chunk))
1055c074d1c9Sdrahn return FALSE;
10562159047fSniklas
1057b305b0f1Sespie octets_written += octets_this_chunk;
1058b305b0f1Sespie location += octets_this_chunk;
10592159047fSniklas }
10602159047fSniklas
1061c074d1c9Sdrahn return TRUE;
10622159047fSniklas }
10632159047fSniklas
1064c074d1c9Sdrahn static bfd_boolean
srec_write_terminator(abfd,tdata)10652159047fSniklas srec_write_terminator (abfd, tdata)
10662159047fSniklas bfd *abfd;
10672159047fSniklas tdata_type *tdata;
10682159047fSniklas {
10692159047fSniklas return srec_write_record (abfd, 10 - tdata->type,
1070c074d1c9Sdrahn abfd->start_address, NULL, NULL);
10712159047fSniklas }
10722159047fSniklas
1073c074d1c9Sdrahn static bfd_boolean
srec_write_symbols(abfd)10742159047fSniklas srec_write_symbols (abfd)
10752159047fSniklas bfd *abfd;
10762159047fSniklas {
1077b55d4692Sfgsch /* Dump out the symbols of a bfd. */
10782159047fSniklas int i;
10792159047fSniklas int count = bfd_get_symcount (abfd);
10802159047fSniklas
10812159047fSniklas if (count)
10822159047fSniklas {
1083c074d1c9Sdrahn bfd_size_type len;
10842159047fSniklas asymbol **table = bfd_get_outsymbols (abfd);
1085c074d1c9Sdrahn len = strlen (abfd->filename);
1086c074d1c9Sdrahn if (bfd_bwrite ("$$ ", (bfd_size_type) 3, abfd) != 3
1087c074d1c9Sdrahn || bfd_bwrite (abfd->filename, len, abfd) != len
1088c074d1c9Sdrahn || bfd_bwrite ("\r\n", (bfd_size_type) 2, abfd) != 2)
1089c074d1c9Sdrahn return FALSE;
10902159047fSniklas
10912159047fSniklas for (i = 0; i < count; i++)
10922159047fSniklas {
10932159047fSniklas asymbol *s = table[i];
1094b305b0f1Sespie if (! bfd_is_local_label (abfd, s)
1095b305b0f1Sespie && (s->flags & BSF_DEBUGGING) == 0)
10962159047fSniklas {
1097b55d4692Sfgsch /* Just dump out non debug symbols. */
1098c074d1c9Sdrahn char buf[43], *p;
10992159047fSniklas
1100c074d1c9Sdrahn len = strlen (s->name);
1101c074d1c9Sdrahn if (bfd_bwrite (" ", (bfd_size_type) 2, abfd) != 2
1102c074d1c9Sdrahn || bfd_bwrite (s->name, len, abfd) != len)
1103c074d1c9Sdrahn return FALSE;
1104c074d1c9Sdrahn
1105c074d1c9Sdrahn sprintf_vma (buf + 2, (s->value
1106c074d1c9Sdrahn + s->section->output_section->lma
1107c074d1c9Sdrahn + s->section->output_offset));
1108c074d1c9Sdrahn p = buf + 2;
11092159047fSniklas while (p[0] == '0' && p[1] != 0)
11102159047fSniklas p++;
1111c074d1c9Sdrahn len = strlen (p);
1112c074d1c9Sdrahn p[len] = '\r';
1113c074d1c9Sdrahn p[len + 1] = '\n';
1114c074d1c9Sdrahn *--p = '$';
1115c074d1c9Sdrahn *--p = ' ';
1116c074d1c9Sdrahn len += 4;
1117c074d1c9Sdrahn if (bfd_bwrite (p, len, abfd) != len)
1118c074d1c9Sdrahn return FALSE;
11192159047fSniklas }
11202159047fSniklas }
1121c074d1c9Sdrahn if (bfd_bwrite ("$$ \r\n", (bfd_size_type) 5, abfd) != 5)
1122c074d1c9Sdrahn return FALSE;
11232159047fSniklas }
11242159047fSniklas
1125c074d1c9Sdrahn return TRUE;
11262159047fSniklas }
11272159047fSniklas
1128c074d1c9Sdrahn static bfd_boolean
internal_srec_write_object_contents(abfd,symbols)11292159047fSniklas internal_srec_write_object_contents (abfd, symbols)
11302159047fSniklas bfd *abfd;
11312159047fSniklas int symbols;
11322159047fSniklas {
11332159047fSniklas tdata_type *tdata = abfd->tdata.srec_data;
11342159047fSniklas srec_data_list_type *list;
11352159047fSniklas
11362159047fSniklas if (symbols)
11372159047fSniklas {
11382159047fSniklas if (! srec_write_symbols (abfd))
1139c074d1c9Sdrahn return FALSE;
11402159047fSniklas }
11412159047fSniklas
11422159047fSniklas if (! srec_write_header (abfd))
1143c074d1c9Sdrahn return FALSE;
11442159047fSniklas
1145b55d4692Sfgsch /* Now wander though all the sections provided and output them. */
11462159047fSniklas list = tdata->head;
11472159047fSniklas
11482159047fSniklas while (list != (srec_data_list_type *) NULL)
11492159047fSniklas {
11502159047fSniklas if (! srec_write_section (abfd, tdata, list))
1151c074d1c9Sdrahn return FALSE;
11522159047fSniklas list = list->next;
11532159047fSniklas }
11542159047fSniklas return srec_write_terminator (abfd, tdata);
11552159047fSniklas }
11562159047fSniklas
1157c074d1c9Sdrahn static bfd_boolean
srec_write_object_contents(abfd)11582159047fSniklas srec_write_object_contents (abfd)
11592159047fSniklas bfd *abfd;
11602159047fSniklas {
11612159047fSniklas return internal_srec_write_object_contents (abfd, 0);
11622159047fSniklas }
11632159047fSniklas
1164c074d1c9Sdrahn static bfd_boolean
symbolsrec_write_object_contents(abfd)11652159047fSniklas symbolsrec_write_object_contents (abfd)
11662159047fSniklas bfd *abfd;
11672159047fSniklas {
11682159047fSniklas return internal_srec_write_object_contents (abfd, 1);
11692159047fSniklas }
11702159047fSniklas
11712159047fSniklas static int
srec_sizeof_headers(abfd,exec)11722159047fSniklas srec_sizeof_headers (abfd, exec)
1173b305b0f1Sespie bfd *abfd ATTRIBUTE_UNUSED;
1174c074d1c9Sdrahn bfd_boolean exec ATTRIBUTE_UNUSED;
11752159047fSniklas {
11762159047fSniklas return 0;
11772159047fSniklas }
11782159047fSniklas
11792159047fSniklas /* Return the amount of memory needed to read the symbol table. */
11802159047fSniklas
11812159047fSniklas static long
srec_get_symtab_upper_bound(abfd)11822159047fSniklas srec_get_symtab_upper_bound (abfd)
11832159047fSniklas bfd *abfd;
11842159047fSniklas {
11852159047fSniklas return (bfd_get_symcount (abfd) + 1) * sizeof (asymbol *);
11862159047fSniklas }
11872159047fSniklas
11882159047fSniklas /* Return the symbol table. */
11892159047fSniklas
11902159047fSniklas static long
srec_canonicalize_symtab(abfd,alocation)1191*007c2a45Smiod srec_canonicalize_symtab (abfd, alocation)
11922159047fSniklas bfd *abfd;
11932159047fSniklas asymbol **alocation;
11942159047fSniklas {
1195c074d1c9Sdrahn bfd_size_type symcount = bfd_get_symcount (abfd);
11962159047fSniklas asymbol *csymbols;
11972159047fSniklas unsigned int i;
11982159047fSniklas
11992159047fSniklas csymbols = abfd->tdata.srec_data->csymbols;
12002159047fSniklas if (csymbols == NULL)
12012159047fSniklas {
12022159047fSniklas asymbol *c;
12032159047fSniklas struct srec_symbol *s;
12042159047fSniklas
12052159047fSniklas csymbols = (asymbol *) bfd_alloc (abfd, symcount * sizeof (asymbol));
12062159047fSniklas if (csymbols == NULL && symcount != 0)
1207c074d1c9Sdrahn return 0;
12082159047fSniklas abfd->tdata.srec_data->csymbols = csymbols;
12092159047fSniklas
12102159047fSniklas for (s = abfd->tdata.srec_data->symbols, c = csymbols;
12112159047fSniklas s != NULL;
12122159047fSniklas s = s->next, ++c)
12132159047fSniklas {
12142159047fSniklas c->the_bfd = abfd;
12152159047fSniklas c->name = s->name;
12162159047fSniklas c->value = s->val;
12172159047fSniklas c->flags = BSF_GLOBAL;
12182159047fSniklas c->section = bfd_abs_section_ptr;
12192159047fSniklas c->udata.p = NULL;
12202159047fSniklas }
12212159047fSniklas }
12222159047fSniklas
12232159047fSniklas for (i = 0; i < symcount; i++)
12242159047fSniklas *alocation++ = csymbols++;
12252159047fSniklas *alocation = NULL;
12262159047fSniklas
12272159047fSniklas return symcount;
12282159047fSniklas }
12292159047fSniklas
1230b305b0f1Sespie static void
srec_get_symbol_info(ignore_abfd,symbol,ret)12312159047fSniklas srec_get_symbol_info (ignore_abfd, symbol, ret)
1232b305b0f1Sespie bfd *ignore_abfd ATTRIBUTE_UNUSED;
12332159047fSniklas asymbol *symbol;
12342159047fSniklas symbol_info *ret;
12352159047fSniklas {
12362159047fSniklas bfd_symbol_info (symbol, ret);
12372159047fSniklas }
12382159047fSniklas
1239e93f7393Sniklas static void
srec_print_symbol(abfd,afile,symbol,how)1240c074d1c9Sdrahn srec_print_symbol (abfd, afile, symbol, how)
1241c074d1c9Sdrahn bfd *abfd;
12422159047fSniklas PTR afile;
12432159047fSniklas asymbol *symbol;
12442159047fSniklas bfd_print_symbol_type how;
12452159047fSniklas {
12462159047fSniklas FILE *file = (FILE *) afile;
12472159047fSniklas switch (how)
12482159047fSniklas {
12492159047fSniklas case bfd_print_symbol_name:
12502159047fSniklas fprintf (file, "%s", symbol->name);
12512159047fSniklas break;
12522159047fSniklas default:
1253c074d1c9Sdrahn bfd_print_symbol_vandf (abfd, (PTR) file, symbol);
12542159047fSniklas fprintf (file, " %-5s %s",
12552159047fSniklas symbol->section->name,
12562159047fSniklas symbol->name);
12572159047fSniklas
12582159047fSniklas }
12592159047fSniklas }
12602159047fSniklas
12612159047fSniklas #define srec_close_and_cleanup _bfd_generic_close_and_cleanup
12622159047fSniklas #define srec_bfd_free_cached_info _bfd_generic_bfd_free_cached_info
12632159047fSniklas #define srec_new_section_hook _bfd_generic_new_section_hook
12642159047fSniklas
1265b305b0f1Sespie #define srec_bfd_is_local_label_name bfd_generic_is_local_label_name
12662159047fSniklas #define srec_get_lineno _bfd_nosymbols_get_lineno
12672159047fSniklas #define srec_find_nearest_line _bfd_nosymbols_find_nearest_line
1268c074d1c9Sdrahn #define srec_make_empty_symbol _bfd_generic_make_empty_symbol
12692159047fSniklas #define srec_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol
12702159047fSniklas #define srec_read_minisymbols _bfd_generic_read_minisymbols
12712159047fSniklas #define srec_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol
12722159047fSniklas
12732159047fSniklas #define srec_get_reloc_upper_bound \
12742159047fSniklas ((long (*) PARAMS ((bfd *, asection *))) bfd_0l)
12752159047fSniklas #define srec_canonicalize_reloc \
12762159047fSniklas ((long (*) PARAMS ((bfd *, asection *, arelent **, asymbol **))) bfd_0l)
12772159047fSniklas #define srec_bfd_reloc_type_lookup _bfd_norelocs_bfd_reloc_type_lookup
12782159047fSniklas
12792159047fSniklas #define srec_get_section_contents_in_window \
12802159047fSniklas _bfd_generic_get_section_contents_in_window
12812159047fSniklas
12822159047fSniklas #define srec_bfd_get_relocated_section_contents \
12832159047fSniklas bfd_generic_get_relocated_section_contents
12842159047fSniklas #define srec_bfd_relax_section bfd_generic_relax_section
1285b305b0f1Sespie #define srec_bfd_gc_sections bfd_generic_gc_sections
1286c074d1c9Sdrahn #define srec_bfd_merge_sections bfd_generic_merge_sections
1287c074d1c9Sdrahn #define srec_bfd_discard_group bfd_generic_discard_group
12882159047fSniklas #define srec_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
1289c074d1c9Sdrahn #define srec_bfd_link_hash_table_free _bfd_generic_link_hash_table_free
12902159047fSniklas #define srec_bfd_link_add_symbols _bfd_generic_link_add_symbols
1291c074d1c9Sdrahn #define srec_bfd_link_just_syms _bfd_generic_link_just_syms
12922159047fSniklas #define srec_bfd_final_link _bfd_generic_final_link
12932159047fSniklas #define srec_bfd_link_split_section _bfd_generic_link_split_section
12942159047fSniklas
12952159047fSniklas const bfd_target srec_vec =
12962159047fSniklas {
12972159047fSniklas "srec", /* name */
12982159047fSniklas bfd_target_srec_flavour,
1299c88b1d6cSniklas BFD_ENDIAN_UNKNOWN, /* target byte order */
1300c88b1d6cSniklas BFD_ENDIAN_UNKNOWN, /* target headers byte order */
13012159047fSniklas (HAS_RELOC | EXEC_P | /* object flags */
13022159047fSniklas HAS_LINENO | HAS_DEBUG |
13032159047fSniklas HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
13042159047fSniklas (SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS
13052159047fSniklas | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
13062159047fSniklas 0, /* leading underscore */
13072159047fSniklas ' ', /* ar_pad_char */
13082159047fSniklas 16, /* ar_max_namelen */
13092159047fSniklas bfd_getb64, bfd_getb_signed_64, bfd_putb64,
13102159047fSniklas bfd_getb32, bfd_getb_signed_32, bfd_putb32,
13112159047fSniklas bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */
13122159047fSniklas bfd_getb64, bfd_getb_signed_64, bfd_putb64,
13132159047fSniklas bfd_getb32, bfd_getb_signed_32, bfd_putb32,
13142159047fSniklas bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */
13152159047fSniklas
13162159047fSniklas {
13172159047fSniklas _bfd_dummy_target,
13182159047fSniklas srec_object_p, /* bfd_check_format */
13192159047fSniklas _bfd_dummy_target,
13202159047fSniklas _bfd_dummy_target,
13212159047fSniklas },
13222159047fSniklas {
13232159047fSniklas bfd_false,
13242159047fSniklas srec_mkobject,
13252159047fSniklas _bfd_generic_mkarchive,
13262159047fSniklas bfd_false,
13272159047fSniklas },
13282159047fSniklas { /* bfd_write_contents */
13292159047fSniklas bfd_false,
13302159047fSniklas srec_write_object_contents,
13312159047fSniklas _bfd_write_archive_contents,
13322159047fSniklas bfd_false,
13332159047fSniklas },
13342159047fSniklas
13352159047fSniklas BFD_JUMP_TABLE_GENERIC (srec),
13362159047fSniklas BFD_JUMP_TABLE_COPY (_bfd_generic),
13372159047fSniklas BFD_JUMP_TABLE_CORE (_bfd_nocore),
13382159047fSniklas BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
13392159047fSniklas BFD_JUMP_TABLE_SYMBOLS (srec),
13402159047fSniklas BFD_JUMP_TABLE_RELOCS (srec),
13412159047fSniklas BFD_JUMP_TABLE_WRITE (srec),
13422159047fSniklas BFD_JUMP_TABLE_LINK (srec),
13432159047fSniklas BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
13442159047fSniklas
1345b305b0f1Sespie NULL,
1346b305b0f1Sespie
13472159047fSniklas (PTR) 0
13482159047fSniklas };
13492159047fSniklas
13502159047fSniklas const bfd_target symbolsrec_vec =
13512159047fSniklas {
13522159047fSniklas "symbolsrec", /* name */
13532159047fSniklas bfd_target_srec_flavour,
1354c88b1d6cSniklas BFD_ENDIAN_UNKNOWN, /* target byte order */
1355c88b1d6cSniklas BFD_ENDIAN_UNKNOWN, /* target headers byte order */
13562159047fSniklas (HAS_RELOC | EXEC_P | /* object flags */
13572159047fSniklas HAS_LINENO | HAS_DEBUG |
13582159047fSniklas HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
13592159047fSniklas (SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS
13602159047fSniklas | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
13612159047fSniklas 0, /* leading underscore */
13622159047fSniklas ' ', /* ar_pad_char */
13632159047fSniklas 16, /* ar_max_namelen */
13642159047fSniklas bfd_getb64, bfd_getb_signed_64, bfd_putb64,
13652159047fSniklas bfd_getb32, bfd_getb_signed_32, bfd_putb32,
13662159047fSniklas bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */
13672159047fSniklas bfd_getb64, bfd_getb_signed_64, bfd_putb64,
13682159047fSniklas bfd_getb32, bfd_getb_signed_32, bfd_putb32,
13692159047fSniklas bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */
13702159047fSniklas
13712159047fSniklas {
13722159047fSniklas _bfd_dummy_target,
13732159047fSniklas symbolsrec_object_p, /* bfd_check_format */
13742159047fSniklas _bfd_dummy_target,
13752159047fSniklas _bfd_dummy_target,
13762159047fSniklas },
13772159047fSniklas {
13782159047fSniklas bfd_false,
13792159047fSniklas srec_mkobject,
13802159047fSniklas _bfd_generic_mkarchive,
13812159047fSniklas bfd_false,
13822159047fSniklas },
13832159047fSniklas { /* bfd_write_contents */
13842159047fSniklas bfd_false,
13852159047fSniklas symbolsrec_write_object_contents,
13862159047fSniklas _bfd_write_archive_contents,
13872159047fSniklas bfd_false,
13882159047fSniklas },
13892159047fSniklas
13902159047fSniklas BFD_JUMP_TABLE_GENERIC (srec),
13912159047fSniklas BFD_JUMP_TABLE_COPY (_bfd_generic),
13922159047fSniklas BFD_JUMP_TABLE_CORE (_bfd_nocore),
13932159047fSniklas BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
13942159047fSniklas BFD_JUMP_TABLE_SYMBOLS (srec),
13952159047fSniklas BFD_JUMP_TABLE_RELOCS (srec),
13962159047fSniklas BFD_JUMP_TABLE_WRITE (srec),
13972159047fSniklas BFD_JUMP_TABLE_LINK (srec),
13982159047fSniklas BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
13992159047fSniklas
1400b305b0f1Sespie NULL,
1401b305b0f1Sespie
14022159047fSniklas (PTR) 0
14032159047fSniklas };
1404