Don't use prototypes for vfprintf_filtered(). Someday we'll get prototypes of
[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 void
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  srec_data_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
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->_raw_size = 0;
295   section->vma = 0xffffffff;
296   low = 0xffffffff;
297   high = 0;
298   pass_over(abfd, size_srec, section);
299   section->_raw_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->_raw_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 = abfd->tdata.srec_data;
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     return true;    
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         
475         unsigned int bytes_this_chunk = list->size - bytes_written;
476
477         if (bytes_this_chunk > CHUNK) 
478         {
479             bytes_this_chunk = CHUNK;
480         }
481
482         address = list->where +  bytes_written;
483
484         srec_write_record(abfd,
485                           tdata->type,
486                           address,
487                           location,
488                           location + bytes_this_chunk);
489
490         bytes_written += bytes_this_chunk;
491         location += bytes_this_chunk;
492     }
493
494 }
495
496 static void
497 DEFUN(srec_write_terminator,(abfd, tdata),
498       bfd *abfd AND
499       tdata_type *tdata)
500 {
501     unsigned    char buffer[2];
502     
503     srec_write_record(abfd, 10 - tdata->type,
504                       abfd->start_address, buffer, buffer);
505
506
507 }
508 static boolean
509 DEFUN(srec_mkobject, (abfd), 
510       bfd *abfd)
511 {
512     tdata_type *tdata = (tdata_type *)bfd_alloc(abfd,  sizeof(tdata_type));
513     abfd->tdata.srec_data = tdata;
514     tdata->type = 1;
515     tdata->head = (srec_data_list_type *)NULL;
516     return true;
517     
518 }
519
520       
521 static boolean
522 DEFUN(srec_write_object_contents,(abfd),
523      bfd *abfd)
524 {
525     int bytes_written;
526     tdata_type *tdata = abfd->tdata.srec_data;
527     srec_data_list_type *list;
528
529     bytes_written = 0;
530
531
532     
533     srec_write_header(abfd);
534     
535     /* Now wander though all the sections provided and output them */
536     list = tdata->head;
537
538     while (list != (srec_data_list_type*)NULL) 
539     {
540         srec_write_section(abfd, tdata, list); 
541         list = list->next;
542     }
543     srec_write_terminator(abfd, tdata);
544     return true;
545 }
546
547 static int 
548 DEFUN(srec_sizeof_headers,(abfd, exec),
549       bfd *abfd AND
550       boolean exec)
551 {
552 return 0;
553 }
554
555 static asymbol *
556 DEFUN(srec_make_empty_symbol, (abfd),
557       bfd*abfd)
558 {
559   asymbol *new=  (asymbol *)bfd_zalloc (abfd, sizeof (asymbol));
560   new->the_bfd = abfd;
561   return new;
562 }
563 #define FOO PROTO
564 #define srec_new_section_hook (FOO(boolean, (*), (bfd *, asection *)))bfd_true
565 #define srec_get_symtab_upper_bound (PROTO(unsigned int, (*),(bfd *)))bfd_false
566 #define srec_get_symtab (FOO(unsigned int, (*), (bfd *, asymbol **)))bfd_0
567 #define srec_get_reloc_upper_bound (FOO(unsigned int, (*),(bfd*, asection *)))bfd_false
568 #define srec_canonicalize_reloc (FOO(unsigned int, (*),(bfd*,asection *, arelent **, asymbol **))) bfd_0
569
570 #define srec_print_symbol (FOO(void,(*),(bfd *, PTR, asymbol *, bfd_print_symbol_type))) bfd_void
571
572 #define srec_openr_next_archived_file (FOO(bfd *, (*), (bfd*,bfd*))) bfd_nullvoidptr
573 #define srec_find_nearest_line (FOO(boolean, (*),(bfd*,asection*,asymbol**,bfd_vma, CONST char**, CONST char**, unsigned int *))) bfd_false
574 #define srec_generic_stat_arch_elt  (FOO(int, (*), (bfd *,struct stat *))) bfd_0
575
576
577 #define srec_core_file_failing_command (char *(*)())(bfd_nullvoidptr)
578 #define srec_core_file_failing_signal (int (*)())bfd_0
579 #define srec_core_file_matches_executable_p (FOO(boolean, (*),(bfd*, bfd*)))bfd_false
580 #define srec_slurp_armap bfd_true
581 #define srec_slurp_extended_name_table bfd_true
582 #define srec_truncate_arname (void (*)())bfd_nullvoidptr
583 #define srec_write_armap  (FOO( boolean, (*),(bfd *, unsigned int, struct orl *, unsigned int, int))) bfd_nullvoidptr
584 #define srec_get_lineno (struct lineno_cache_entry *(*)())bfd_nullvoidptr
585 #define srec_close_and_cleanup  bfd_generic_close_and_cleanup
586 #define srec_bfd_debug_info_start bfd_void
587 #define srec_bfd_debug_info_end bfd_void
588 #define srec_bfd_debug_info_accumulate  (FOO(void, (*), (bfd *,  asection *))) bfd_void
589 #define srec_bfd_get_relocated_section_contents bfd_generic_get_relocated_section_contents
590
591 bfd_target srec_vec =
592 {
593     "srec",                     /* name */
594     bfd_target_srec_flavour,
595     true,                       /* target byte order */
596     true,                       /* target headers byte order */
597     (HAS_RELOC | EXEC_P |       /* object flags */
598      HAS_LINENO | HAS_DEBUG |
599      HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED),
600     (SEC_CODE|SEC_DATA|SEC_ROM|SEC_HAS_CONTENTS
601      |SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
602     ' ',                        /* ar_pad_char */
603     16,                         /* ar_max_namelen */
604     1,                          /* minimum alignment */
605     _do_getb64, _do_putb64,  _do_getb32,
606     _do_putb32, _do_getb16, _do_putb16, /* data */
607     _do_getb64, _do_putb64,  _do_getb32,
608     _do_putb32, _do_getb16, _do_putb16, /* hdrs */
609
610   {
611       _bfd_dummy_target,
612       srec_object_p,            /* bfd_check_format */
613       (struct bfd_target *(*)()) bfd_nullvoidptr,
614       (struct bfd_target *(*)())     bfd_nullvoidptr,
615   },
616   {
617       bfd_false,
618       srec_mkobject,
619       _bfd_generic_mkarchive,
620       bfd_false,
621   },
622   {                             /* bfd_write_contents */
623       bfd_false,
624       srec_write_object_contents,
625       _bfd_write_archive_contents,
626       bfd_false,
627   },
628     JUMP_TABLE(srec)
629  };
630