* srec.c: Better error checking, partly from Peter Schauer.
[external/binutils.git] / bfd / srec.c
1 /* BFD backend for s-record objects.
2    Copyright (C) 1990-1991 Free Software Foundation, Inc.
3    Written by Steve Chamberlain of Cygnus Support <steve@cygnus.com>.
4
5 This file is part of BFD, the Binary File Descriptor library.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
20
21 /* S-records cannot hold anything but addresses and data, so that's all
22    that we implement.
23    
24    The only interesting thing is that s-records may come out of order and
25    there is no header, so an initial scan is required to discover the
26    minimum and maximum addresses used to create the vma and size of the
27    only section we create.  We arbitrarily call this section ".text".
28
29    When bfd_get_section_contents is called the file is read again, and
30    this time the data is placed into a bfd_alloc'd area.
31
32    Any number of sections may be created for output, we just output them
33    in the order provided to bfd_set_section_contents.  */
34
35 #include <sysdep.h>
36 #include "bfd.h"
37 #include "libbfd.h"
38
39
40 static char digs[] = "0123456789ABCDEF";
41
42 /* Macros for converting between hex and binary */
43
44 #define NIBBLE(x) (((x) >= '0' && (x) <= '9') ? ((x) - '0') : ((x) - 'A' + 10))
45 #define HEX(buffer) ((NIBBLE((buffer)->high) <<4) + NIBBLE((buffer)->low))
46 #define TOHEX(d,x) \
47   ((d)->low = digs[(x) & 0xf], (d)->high = digs[((x)>>4)&0xf], (x))
48 #define ISHEX(x)  (((x) >= '0' && (x) <= '9') || ((x) >= 'A' && (x) <= 'F'))
49
50 typedef struct {
51   char high;
52   char low;
53 } byte_as_two_char_type;
54
55 /* The maximum number of bytes on a line is FF */
56 #define MAXCHUNK 0xff 
57 /* The number of bytes we fit onto a line on output */
58 #define CHUNK 16 
59
60 /* The shape of an s-record .. */
61 typedef struct 
62 {
63   char S;
64   char type;
65   byte_as_two_char_type size;
66   union {
67     struct {
68       byte_as_two_char_type address[4];
69       byte_as_two_char_type data[MAXCHUNK];
70       /* If there isn't MAXCHUNK bytes of data then the checksum will 
71          appear earlier */
72       byte_as_two_char_type checksum;
73       char nl;
74     } type_3;
75     struct {
76       byte_as_two_char_type address[4];
77       byte_as_two_char_type data[MAXCHUNK];
78       byte_as_two_char_type checksum;
79       char nl;
80     } type_6;
81
82     struct {
83       byte_as_two_char_type address[3];
84       byte_as_two_char_type data[MAXCHUNK];
85       byte_as_two_char_type checksum;
86       char nl;
87     } type_2;
88
89     struct {
90       byte_as_two_char_type address[2];
91       byte_as_two_char_type data[MAXCHUNK];
92       byte_as_two_char_type checksum;
93       char nl;
94     } type_1;
95     byte_as_two_char_type data[MAXCHUNK];
96   } u;
97 } srec_type;
98
99 #define enda(x) (x->vma + x->size)
100 /* 
101    called once per input s-record, used to work out vma and size of data.
102  */
103
104 static bfd_vma low,high;
105 static void
106 size_srec(abfd, section, address, raw, length)
107 bfd *abfd;
108 asection *section;
109 bfd_vma address;
110 byte_as_two_char_type *raw;
111 unsigned int length;
112 {
113   if (address < low)
114     low = address;
115   if (address + length > high) 
116     high = address + length;
117 }
118
119
120 /*
121  called once per input s-record, copies data from input into bfd_alloc'd area
122  */
123
124 static void
125 fillup(abfd, section, address, raw, length)
126 bfd *abfd;
127 asection *section;
128 bfd_vma address;
129 byte_as_two_char_type *raw;
130 unsigned int length;
131 {
132   unsigned int i;
133   bfd_byte *dst = (bfd_byte *)(section->used_by_bfd) +  address - section->vma;
134   for (i = 0; i < length; i++) {
135     *dst = HEX(raw);
136     dst++;
137     raw++;
138   }
139 }
140
141 /* Pass over an s-record file, calling one of the above functions on each
142    record.  */
143
144 static void
145 pass_over(abfd, func, section)
146      bfd *abfd;
147      void (*func)();
148      asection *section;
149 {
150   unsigned int bytes_on_line;
151   boolean eof = false;
152   bfd_vma address;
153   /* To the front of the file */
154   bfd_seek(abfd, (file_ptr)0, SEEK_SET);
155   while (eof == false)
156     {
157       srec_type buffer;
158
159       /* Find first 'S' */
160       eof =  bfd_read(&buffer.S, 1, 1, abfd) != 1;
161       while (buffer.S != 'S' && !eof) {
162         eof =  bfd_read(&buffer.S, 1, 1, abfd) != 1;
163       }
164       if (eof) break;
165
166       bfd_read(&buffer.type, 1, 3, abfd);
167
168       if (!ISHEX (buffer.size.high) || !ISHEX (buffer.size.low))
169         break;
170       bytes_on_line = HEX(&buffer.size);
171       if (bytes_on_line > MAXCHUNK/2)
172         break;
173     
174       bfd_read((PTR)buffer.u.data, 1 , bytes_on_line * 2, abfd);
175
176       switch (buffer.type) {
177       case '6':
178         /* Prologue - ignore */
179         break;
180
181       case '3':
182         address = (HEX(buffer.u.type_3.address+0) << 24)
183                 + (HEX(buffer.u.type_3.address+1) << 16)
184                 + (HEX(buffer.u.type_3.address+2) << 8) 
185                 + (HEX(buffer.u.type_3.address+3));
186         func(abfd,section, address, buffer.u.type_3.data, bytes_on_line -1);
187         break;
188
189       case '2':
190         address = (HEX(buffer.u.type_2.address+0) << 16)
191                 + (HEX(buffer.u.type_2.address+1) << 8)
192                 + (HEX(buffer.u.type_2.address+2));
193         func(abfd,section, address, buffer.u.type_2.data, bytes_on_line -1);
194         break;
195
196       case '1':
197         address = (HEX(buffer.u.type_1.address+0) << 8) 
198                 + (HEX(buffer.u.type_1.address+1));
199         func(abfd, section, address, buffer.u.type_1.data, bytes_on_line -1);
200         break;
201
202       default:
203         goto end_of_file;
204       }
205     }
206   end_of_file: ;
207 }
208
209
210 bfd_target *
211 srec_object_p (abfd)
212 bfd *abfd;
213 {
214   char b[4];
215   asection *section;
216   bfd_seek(abfd, (file_ptr)0, SEEK_SET);
217   bfd_read(b, 1, 4, abfd);
218   if (b[0] != 'S' || !ISHEX(b[1]) || !ISHEX(b[2]) || !ISHEX(b[3]))
219     return (bfd_target*) NULL;
220   
221   /* We create one section called .text for all the contents, 
222      and allocate enough room for the entire file.  */
223
224   section =  bfd_make_section(abfd, ".text");
225   section->size = 0;
226   section->vma = 0xffffffff;
227   low = 0xffffffff;
228   high = 0;
229   pass_over(abfd, size_srec, section);
230   section->size = high - low;
231   section->vma = low;
232   return abfd->xvec;
233 }
234
235
236 static boolean
237 srec_get_section_contents (abfd, section, location, offset, count)
238 bfd *abfd;
239 sec_ptr section;
240 void  *location;
241 file_ptr offset;
242 unsigned      int count;
243 {
244   if (section->used_by_bfd == (PTR)NULL) {
245     section->used_by_bfd = (PTR)bfd_alloc (abfd, section->size);
246     pass_over(abfd, fillup, section);
247   }
248   (void) memcpy((PTR)location, (PTR)((char *)(section->used_by_bfd) + offset), count);
249   return true;
250 }
251       
252
253
254 boolean
255 srec_set_arch_mach (abfd, arch, machine)
256 bfd *abfd;
257 enum bfd_architecture arch;
258 unsigned long machine;
259 {
260   abfd->obj_arch = arch;
261   abfd->obj_machine = machine;
262   return true;
263 }
264
265
266
267 boolean
268 srec_set_section_contents (abfd, section, location, offset, bytes_to_do)
269 bfd *abfd;
270 sec_ptr section;
271 unsigned char *location;
272 file_ptr offset;
273 int bytes_to_do;
274 {
275   bfd_vma address;
276   int bytes_written;
277
278   int type;
279   unsigned int i;
280   srec_type buffer;
281   bytes_written = 0;
282   if (section->vma <= 0xffff) 
283     type = 1;
284   else if (section->vma <= 0xffffff) 
285     type = 2;
286   else
287     type = 3;
288
289   buffer.S = 'S';
290   buffer.type = '0' + type;
291
292   while (bytes_written < bytes_to_do) {
293     unsigned int size;
294     unsigned int check_sum;
295     byte_as_two_char_type *data; 
296  unsigned   int bytes_this_chunk = bytes_to_do - bytes_written;
297
298     if (bytes_this_chunk > CHUNK) {
299       bytes_this_chunk = CHUNK;
300     }
301
302     address = section->vma + offset + bytes_written;
303
304     switch (type) {
305     case 3:
306       check_sum = TOHEX(buffer.u.type_3.address, address >> 24);
307       check_sum += TOHEX(buffer.u.type_3.address+1, address >> 16);
308       check_sum += TOHEX(buffer.u.type_3.address+2, address >> 8);
309       check_sum += TOHEX(buffer.u.type_3.address+3, address >> 0);
310       size = bytes_this_chunk + 5;
311       data = buffer.u.type_3.data;
312       break;
313     case 2:
314       check_sum = TOHEX(buffer.u.type_3.address, address >> 16);
315       check_sum += TOHEX(buffer.u.type_3.address+1, address >> 8);
316       check_sum += TOHEX(buffer.u.type_3.address+2, address >> 0);
317       size = bytes_this_chunk + 4;
318       data = buffer.u.type_2.data;
319       break;
320
321     case 1:
322       check_sum = TOHEX(buffer.u.type_3.address+0, address >> 8);
323       check_sum += TOHEX(buffer.u.type_3.address+1, address >> 0);
324       size = bytes_this_chunk + 3;
325       data = buffer.u.type_1.data;
326       break;
327     }
328
329     for (i = 0; i < bytes_this_chunk; i++) {
330       check_sum += TOHEX(data, (location[i]));
331       data++;
332     }
333
334     check_sum += TOHEX(&(buffer.size), size );
335     (void) TOHEX(data, ~check_sum);
336     data++;
337
338     * ( (char *)(data)) = '\n';
339     bfd_write((PTR)&buffer, 1, (char *)data - (char *)&buffer + 1 , abfd);
340
341     bytes_written += bytes_this_chunk;
342     location += bytes_this_chunk;
343   }
344
345
346   return true;
347 }
348
349 boolean
350 srec_write_object_contents (abfd)
351      bfd *abfd;
352 {
353   bfd_write("S9030000FC\n", 1,11,abfd);
354   return true;
355 }
356
357 static int 
358 DEFUN(srec_sizeof_headers,(abfd, exec),
359       bfd *abfd AND
360       boolean exec)
361 {
362 return 0;
363 }
364
365 static asymbol *
366 DEFUN(srec_make_empty_symbol, (abfd),
367       bfd*abfd)
368 {
369   asymbol *new=  (asymbol *)bfd_zalloc (abfd, sizeof (asymbol));
370   new->the_bfd = abfd;
371   return new;
372 }
373 #define FOO PROTO
374 #define srec_new_section_hook (FOO(boolean, (*), (bfd *, asection *)))bfd_true
375 #define srec_get_symtab_upper_bound (PROTO(unsigned int, (*),(bfd *)))bfd_false
376 #define srec_get_symtab (FOO(unsigned int, (*), (bfd *, asymbol **)))bfd_0
377 #define srec_get_reloc_upper_bound (FOO(unsigned int, (*),(bfd*, asection *)))bfd_false
378 #define srec_canonicalize_reloc (FOO(unsigned int, (*),(bfd*,asection *, arelent **, asymbol **))) bfd_0
379
380 #define srec_print_symbol (FOO(void,(*),(bfd *, PTR, asymbol *, bfd_print_symbol_enum_type))) bfd_void
381
382 #define srec_openr_next_archived_file (FOO(bfd *, (*), (bfd*,bfd*))) bfd_nullvoidptr
383 #define srec_find_nearest_line (FOO(boolean, (*),(bfd*,asection*,asymbol**,bfd_vma, CONST char**, CONST char**, unsigned int *))) bfd_false
384 #define srec_generic_stat_arch_elt  (FOO(int, (*), (bfd *,struct stat *))) bfd_0
385
386
387 #define srec_core_file_failing_command (char *(*)())(bfd_nullvoidptr)
388 #define srec_core_file_failing_signal (int (*)())bfd_0
389 #define srec_core_file_matches_executable_p (FOO(boolean, (*),(bfd*, bfd*)))bfd_false
390 #define srec_slurp_armap bfd_true
391 #define srec_slurp_extended_name_table bfd_true
392 #define srec_truncate_arname (void (*)())bfd_nullvoidptr
393 #define srec_write_armap  (FOO( boolean, (*),(bfd *, unsigned int, struct orl *, int, int))) bfd_nullvoidptr
394 #define srec_get_lineno (struct lineno_cache_entry *(*)())bfd_nullvoidptr
395 #define srec_close_and_cleanup  bfd_generic_close_and_cleanup
396 #define srec_bfd_debug_info_start bfd_void
397 #define srec_bfd_debug_info_end bfd_void
398 #define srec_bfd_debug_info_accumulate  (FOO(void, (*), (bfd *,  asection *))) bfd_void
399
400
401 bfd_target srec_vec =
402 {
403   "srec",                       /* name */
404   bfd_target_srec_flavour_enum,
405   true,                         /* target byte order */
406   true,                         /* target headers byte order */
407   (HAS_RELOC | EXEC_P |         /* object flags */
408    HAS_LINENO | HAS_DEBUG |
409    HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED),
410   (SEC_CODE|SEC_DATA|SEC_ROM|SEC_HAS_CONTENTS
411    |SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
412   ' ',                          /* ar_pad_char */
413   16,                           /* ar_max_namelen */
414     1,                          /* minimum alignment */
415   _do_getb64, _do_putb64,  _do_getb32, _do_putb32, _do_getb16, _do_putb16, /* data */
416   _do_getb64, _do_putb64,  _do_getb32, _do_putb32, _do_getb16, _do_putb16, /* hdrs */
417
418     {_bfd_dummy_target,
419        srec_object_p,           /* bfd_check_format */
420        (struct bfd_target *(*)()) bfd_nullvoidptr,
421        (struct bfd_target *(*)())     bfd_nullvoidptr,
422      },
423     {
424       bfd_false,
425       bfd_true,                 /* mkobject */
426       _bfd_generic_mkarchive,
427       bfd_false,
428     },
429     {                           /* bfd_write_contents */
430       bfd_false,
431       srec_write_object_contents,
432       _bfd_write_archive_contents,
433       bfd_false,
434     },
435   JUMP_TABLE(srec)
436   };