Lint (detected on hp300bsd & sconix)
[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 <sac@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 /*
22 SUBSECTION
23         S-record handling
24
25 DESCRIPTION
26         
27         S-records cannot hold anything but addresses and data, so
28         that's all that we implement.
29    
30         The only interesting thing is that s-records may come out of
31         order and there is no header, so an initial scan is required
32         to discover the minimum and maximum addresses used to create
33         the vma and size of the only section we create.  We
34         arbitrarily call this section ".text". 
35
36         When bfd_get_section_contents is called the file is read
37         again, and this time the data is placed into a bfd_alloc'd
38         area.
39
40         Any number of sections may be created for output, we save them
41         up and output them when it's time to close the bfd.
42
43         An s record looks like:
44         
45 EXAMPLE
46         S<length><type><address><data><checksum>
47         
48 DESCRIPTION
49         Where
50         o length
51         is the number of bytes following upto the checksum. Note that
52         this is not the number of chars following, since it takes two
53         chars to represent a byte.
54         o type
55         is one of:
56         0) header record
57         1) two byte address data record
58         2) three byte address data record
59         3) four byte address data record
60         7) four byte address termination record
61         8) three byte address termination record
62         9) two byte address termination record
63         
64         o address
65         is the start address of the data following, or in the case of
66         a termination record, the start address of the image
67         o data
68         is the data.
69         o checksum
70         is the sum of all the raw byte data in the record, from the length
71         upwards, modulo 256 and subtracted from 255.
72         
73 */
74
75 #include "bfd.h"
76 #include "sysdep.h"
77 #include "libbfd.h"
78
79 static char digs[] = "0123456789ABCDEF";
80
81 /* Horrible ascii dependent macros for converting between hex and
82    binary */
83
84 #define CHARS_IN_SET 256
85 static char hex_value[CHARS_IN_SET];
86 #define NOT_HEX 20
87 #define NIBBLE(x) hex_value[x]
88 #define HEX(buffer) ((NIBBLE((buffer)[0])<<4) + NIBBLE((buffer)[1]))
89 #define TOHEX(d,x, ch) \
90 d[1] = digs[(x) & 0xf]; \
91 d[0] = digs[((x)>>4)&0xf]; ch += (x & 0xff);
92 #define ISHEX(x)  (hex_value[x] != NOT_HEX)
93
94
95
96 static 
97 DEFUN_VOID(srec_init) 
98 {
99     unsigned int i;
100     static boolean inited = false;
101     
102     if (inited == false) 
103     {
104         
105         inited = true;
106         
107         for (i = 0; i < CHARS_IN_SET; i++) 
108         {
109             hex_value[i] = NOT_HEX;
110         }
111     
112         for (i = 0; i < 10; i++) 
113         {
114             hex_value[i + '0'] = i;
115         
116         }
117         for (i = 0; i < 6; i++) 
118         {
119             hex_value[i + 'a'] = i+10;
120             hex_value[i + 'A'] = i+10;
121         }
122     }    
123 }
124
125
126 /* The maximum number of bytes on a line is FF */
127 #define MAXCHUNK 0xff 
128 /* The number of bytes we fit onto a line on output */
129 #define CHUNK 21
130
131 /* We cannot output our srecords as we see them, we have to glue them
132    together, this is done in this structure : */
133
134 struct srec_data_list_struct
135 {
136     unsigned    char *data;
137     bfd_vma where;
138     bfd_size_type size;
139     struct srec_data_list_struct *next;
140     
141 } ;
142 typedef struct srec_data_list_struct srec_data_list_type;
143
144
145 typedef struct 
146 {
147     srec_data_list_type *head;    
148     unsigned int type;
149
150 } tdata_type;
151
152
153
154 #define enda(x) (x->vma + x->size)
155 /* 
156    called once per input s-record, used to work out vma and size of data.
157  */
158
159 static bfd_vma low,high;
160
161 static void
162 DEFUN(size_srec,(abfd, section, address, raw, length),
163       bfd *abfd AND
164       asection *section AND
165       bfd_vma address AND
166       bfd_byte *raw AND
167       unsigned int length)
168 {
169   if (address < low)
170     low = address;
171   if (address + length > high) 
172     high = address + length -1;
173 }
174
175
176 /*
177  called once per input s-record, copies data from input into bfd_alloc'd area
178  */
179
180 static void
181 DEFUN(fillup,(abfd, section, address, raw, length),
182 bfd *abfd AND
183 asection *section AND
184 bfd_vma address AND
185 bfd_byte *raw AND
186 unsigned int length)
187 {
188     unsigned int i;
189     bfd_byte *dst =
190      (bfd_byte *)(section->used_by_bfd) +
191      address - section->vma;
192     /* length -1 because we don't read in the checksum */
193     for (i = 0; i < length -1 ; i++) {
194             *dst = HEX(raw);
195             dst++;
196             raw+=2;
197         }
198 }
199
200 /* Pass over an s-record file, calling one of the above functions on each
201    record.  */
202
203 static void
204 DEFUN(pass_over,(abfd, func, section),
205       bfd *abfd AND
206       void (*func)() AND
207       asection *section)
208 {
209     unsigned int bytes_on_line;
210     boolean eof = false;
211     bfd_vma address;
212     /* To the front of the file */
213     bfd_seek(abfd, (file_ptr)0, SEEK_SET);
214     while (eof == false)
215     {
216         char buffer[MAXCHUNK];
217         char *src = buffer;
218         char type;
219         bfd_vma address = 0;
220
221         /* Find first 'S' */
222         eof =  (boolean)(bfd_read(src, 1, 1, abfd) != 1);
223         while (*src!= 'S' && !eof) {
224                 eof = (boolean)(bfd_read(src, 1, 1, abfd) != 1);
225             }
226         if (eof) break;
227         src++;
228
229         /* Fetch the type and the length */
230         bfd_read(src, 1, 3, abfd);
231
232         type = *src++;
233
234         if (!ISHEX (src[0]) || !ISHEX (src[1]))
235          break;
236
237         bytes_on_line = HEX(src);
238
239         if (bytes_on_line > MAXCHUNK/2)
240          break;
241         src+=2 ;
242
243         bfd_read(src, 1 , bytes_on_line * 2, abfd);
244
245         switch (type) {
246               case '0':
247               case '5':
248                 /* Prologue - ignore */
249                 break;
250              case '3':
251                 address = HEX(src);
252                 src+=2;
253                 bytes_on_line--;
254                 
255               case '2':
256                 address = HEX(src) | (address<<8) ;
257                 src+=2;
258                 bytes_on_line--;
259               case '1':
260                 address = HEX(src) | (address<<8) ;
261                 src+=2;
262                 address = HEX(src) | (address<<8) ;
263                 src+=2;
264                 bytes_on_line-=2;
265                 func(abfd,section, address, src, bytes_on_line);
266                 break;
267               default:
268                 return;
269             }
270     }
271
272 }
273
274
275
276 static bfd_target *
277 DEFUN(srec_object_p, (abfd),
278       bfd *abfd)
279 {
280   char b[4];
281   asection *section;
282   srec_init();
283   
284   bfd_seek(abfd, (file_ptr)0, SEEK_SET);
285   bfd_read(b, 1, 4, abfd);
286
287   if (b[0] != 'S' || !ISHEX(b[1]) || !ISHEX(b[2]) || !ISHEX(b[3]))
288     return (bfd_target*) NULL;
289   
290   /* We create one section called .text for all the contents, 
291      and allocate enough room for the entire file.  */
292
293   section =  bfd_make_section(abfd, ".text");
294   section->size = 0;
295   section->vma = 0xffffffff;
296   low = 0xffffffff;
297   high = 0;
298   pass_over(abfd, size_srec, section);
299   section->size = high - low;
300   section->vma = low;
301   section->flags = SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC;
302   
303   return abfd->xvec;
304 }
305
306
307 static boolean
308 DEFUN(srec_get_section_contents,(abfd, section, location, offset, count),
309       bfd *abfd AND
310       asection *section AND
311       PTR location AND
312       file_ptr offset AND
313       bfd_size_type count)
314 {
315     if (section->used_by_bfd == (PTR)NULL) 
316     {
317         section->used_by_bfd = (PTR)bfd_alloc (abfd, section->size);
318         pass_over(abfd, fillup, section);
319     }
320     (void) memcpy((PTR)location,
321                   (PTR)((char *)(section->used_by_bfd) + offset),
322                   count);
323     return true;
324 }
325       
326
327
328 boolean
329 DEFUN(srec_set_arch_mach,(abfd, arch, machine),
330       bfd *abfd AND
331       enum bfd_architecture arch AND
332       unsigned long machine)
333 {
334   return bfd_default_set_arch_mach(abfd, arch, machine);
335 }
336
337
338 /* we have to save up all the Srecords for a splurge before output,
339    also remember   */
340
341 static boolean
342 DEFUN(srec_set_section_contents,(abfd, section, location, offset, bytes_to_do),
343       bfd *abfd AND
344       sec_ptr section AND
345       PTR location AND
346       file_ptr offset AND
347       bfd_size_type bytes_to_do)
348 {
349     tdata_type  *tdata = (tdata_type *)(abfd->tdata);
350     srec_data_list_type *entry = (srec_data_list_type *)
351      bfd_alloc(abfd, sizeof(srec_data_list_type));
352     unsigned  char *data = (unsigned char *) bfd_alloc(abfd, bytes_to_do);
353     memcpy(data, location, bytes_to_do);
354
355     if ((section->vma + offset + bytes_to_do) <= 0xffff)  
356     {
357
358     }
359     else if ((section->vma + offset + bytes_to_do) <= 0xffffff 
360              && tdata->type < 2) 
361     {
362         tdata->type = 2;
363     }
364     else 
365     {
366         tdata->type = 3;
367     }
368
369     entry->data = data;
370     entry->where = section->vma + offset;
371     entry->size = bytes_to_do;
372     entry->next = tdata->head;
373     tdata->head = entry;
374     
375 }
376
377 /* Write a record of type, of the supplied number of bytes. The
378    supplied bytes and length don't have a checksum. That's worked out
379    here
380 */
381 static
382 void DEFUN(srec_write_record,(abfd, type, address, data, end),
383            bfd *abfd AND
384            char type AND
385            bfd_vma address AND
386            CONST unsigned char *data AND
387            CONST unsigned char *end)
388
389 {
390     char buffer[MAXCHUNK];
391     
392     unsigned int check_sum = 0;
393     unsigned CONST char *src = data;
394     char *dst =buffer;
395     char *length;
396     
397
398     *dst++ = 'S';
399     *dst++ = '0' + type;
400
401     length = dst;
402     dst+=2;                     /* leave room for dst*/
403     
404     switch (type) 
405     {
406       case 3:
407       case 7:
408         TOHEX(dst, (address >> 24), check_sum);
409         dst+=2;
410       case 8:
411       case 2:
412         TOHEX(dst, (address >> 16), check_sum);
413         dst+=2;
414       case 9:
415       case 1:
416       case 0:
417         TOHEX(dst, (address >> 8), check_sum);
418         dst+=2;
419         TOHEX(dst, (address), check_sum);
420         dst+=2;
421         break;
422
423     }
424     for (src = data; src < end; src++) 
425     {
426         TOHEX(dst, *src, check_sum);
427         dst+=2;
428
429     }
430
431     /* Fill in the length */
432     TOHEX(length, (dst - length)/2, check_sum);
433     check_sum &= 0xff;
434     check_sum = 255 - check_sum;
435     TOHEX(dst, check_sum, check_sum);
436     dst+=2;
437     
438     *dst ++ = '\n';
439     bfd_write((PTR)buffer, 1, dst - buffer , abfd);
440 }
441
442
443
444 static void
445 DEFUN(srec_write_header,(abfd),
446       bfd *abfd)
447 {
448     unsigned char buffer[MAXCHUNK];
449     unsigned char *dst = buffer;
450     unsigned int i;
451
452     /* I'll put an arbitary 40 char limit on header size */
453     for (i = 0; i < 40 && abfd->filename[i];  i++) 
454     {
455         *dst++ = abfd->filename[i];
456     }
457     srec_write_record(abfd,0, 0, buffer, dst);
458 }
459
460 static void
461 DEFUN(srec_write_section,(abfd, tdata, list),
462        bfd *abfd AND
463        tdata_type *tdata AND
464        srec_data_list_type *list)
465 {
466     unsigned int bytes_written = 0;
467     unsigned char *location = list->data;
468
469     while (bytes_written < list->size)
470     {
471         char buffer[MAXCHUNK];
472         char *dst = buffer;
473         bfd_vma address;
474         unsigned int i;
475         
476         unsigned int bytes_this_chunk = list->size - bytes_written;
477
478         if (bytes_this_chunk > CHUNK) 
479         {
480             bytes_this_chunk = CHUNK;
481         }
482
483         address = list->where +  bytes_written;
484
485         srec_write_record(abfd,
486                           tdata->type,
487                           address,
488                           location,
489                           location + bytes_this_chunk);
490
491         bytes_written += bytes_this_chunk;
492         location += bytes_this_chunk;
493     }
494
495 }
496
497 static void
498 DEFUN(srec_write_terminator,(abfd, tdata),
499       bfd *abfd AND
500       tdata_type *tdata)
501 {
502     unsigned    char buffer[2];
503     
504     srec_write_record(abfd, 10 - tdata->type,
505                       abfd->start_address, buffer, buffer);
506
507
508 }
509 static boolean
510 DEFUN(srec_mkobject, (abfd), 
511       bfd *abfd)
512 {
513     tdata_type *tdata = (tdata_type *)bfd_alloc(abfd,  sizeof(tdata_type));
514     abfd->tdata = (PTR)tdata;
515     tdata->type = 1;
516     tdata->head = (srec_data_list_type *)NULL;
517     return true;
518     
519 }
520
521       
522 static boolean
523 DEFUN(srec_write_object_contents,(abfd),
524      bfd *abfd)
525 {
526     bfd_vma address;
527     int bytes_written;
528     
529     int type;
530     unsigned int i;
531     tdata_type *tdata = (tdata_type *)(abfd->tdata);
532     srec_data_list_type *list;
533
534     bytes_written = 0;
535
536
537     
538     srec_write_header(abfd);
539     
540     /* Now wander though all the sections provided and output them */
541     list = tdata->head;
542
543     while (list != (srec_data_list_type*)NULL) 
544     {
545         srec_write_section(abfd, tdata, list); 
546         list = list->next;
547     }
548     srec_write_terminator(abfd, tdata);
549     return true;
550 }
551
552 static int 
553 DEFUN(srec_sizeof_headers,(abfd, exec),
554       bfd *abfd AND
555       boolean exec)
556 {
557 return 0;
558 }
559
560 static asymbol *
561 DEFUN(srec_make_empty_symbol, (abfd),
562       bfd*abfd)
563 {
564   asymbol *new=  (asymbol *)bfd_zalloc (abfd, sizeof (asymbol));
565   new->the_bfd = abfd;
566   return new;
567 }
568 #define FOO PROTO
569 #define srec_new_section_hook (FOO(boolean, (*), (bfd *, asection *)))bfd_true
570 #define srec_get_symtab_upper_bound (PROTO(unsigned int, (*),(bfd *)))bfd_false
571 #define srec_get_symtab (FOO(unsigned int, (*), (bfd *, asymbol **)))bfd_0
572 #define srec_get_reloc_upper_bound (FOO(unsigned int, (*),(bfd*, asection *)))bfd_false
573 #define srec_canonicalize_reloc (FOO(unsigned int, (*),(bfd*,asection *, arelent **, asymbol **))) bfd_0
574
575 #define srec_print_symbol (FOO(void,(*),(bfd *, PTR, asymbol *, bfd_print_symbol_type))) bfd_void
576
577 #define srec_openr_next_archived_file (FOO(bfd *, (*), (bfd*,bfd*))) bfd_nullvoidptr
578 #define srec_find_nearest_line (FOO(boolean, (*),(bfd*,asection*,asymbol**,bfd_vma, CONST char**, CONST char**, unsigned int *))) bfd_false
579 #define srec_generic_stat_arch_elt  (FOO(int, (*), (bfd *,struct stat *))) bfd_0
580
581
582 #define srec_core_file_failing_command (char *(*)())(bfd_nullvoidptr)
583 #define srec_core_file_failing_signal (int (*)())bfd_0
584 #define srec_core_file_matches_executable_p (FOO(boolean, (*),(bfd*, bfd*)))bfd_false
585 #define srec_slurp_armap bfd_true
586 #define srec_slurp_extended_name_table bfd_true
587 #define srec_truncate_arname (void (*)())bfd_nullvoidptr
588 #define srec_write_armap  (FOO( boolean, (*),(bfd *, unsigned int, struct orl *, unsigned int, int))) bfd_nullvoidptr
589 #define srec_get_lineno (struct lineno_cache_entry *(*)())bfd_nullvoidptr
590 #define srec_close_and_cleanup  bfd_generic_close_and_cleanup
591 #define srec_bfd_debug_info_start bfd_void
592 #define srec_bfd_debug_info_end bfd_void
593 #define srec_bfd_debug_info_accumulate  (FOO(void, (*), (bfd *,  asection *))) bfd_void
594
595
596 bfd_target srec_vec =
597 {
598     "srec",                     /* name */
599     bfd_target_srec_flavour,
600     true,                       /* target byte order */
601     true,                       /* target headers byte order */
602     (HAS_RELOC | EXEC_P |       /* object flags */
603      HAS_LINENO | HAS_DEBUG |
604      HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED),
605     (SEC_CODE|SEC_DATA|SEC_ROM|SEC_HAS_CONTENTS
606      |SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
607     ' ',                        /* ar_pad_char */
608     16,                         /* ar_max_namelen */
609     1,                          /* minimum alignment */
610     _do_getb64, _do_putb64,  _do_getb32,
611     _do_putb32, _do_getb16, _do_putb16, /* data */
612     _do_getb64, _do_putb64,  _do_getb32,
613     _do_putb32, _do_getb16, _do_putb16, /* hdrs */
614
615   {
616       _bfd_dummy_target,
617       srec_object_p,            /* bfd_check_format */
618       (struct bfd_target *(*)()) bfd_nullvoidptr,
619       (struct bfd_target *(*)())     bfd_nullvoidptr,
620   },
621   {
622       bfd_false,
623       srec_mkobject,
624       _bfd_generic_mkarchive,
625       bfd_false,
626   },
627   {                             /* bfd_write_contents */
628       bfd_false,
629       srec_write_object_contents,
630       _bfd_write_archive_contents,
631       bfd_false,
632   },
633     JUMP_TABLE(srec)
634  };
635