Some of these are guesses, if you know different, just yell.
[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<type><length><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   if ((section->flags & SEC_ALLOC)
353       && (section->flags & SEC_LOAD)) 
354   {
355     unsigned  char *data = (unsigned char *) bfd_alloc(abfd, bytes_to_do);
356     memcpy(data, location, bytes_to_do);
357
358     if ((section->vma + offset + bytes_to_do) <= 0xffff)  
359     {
360
361     }
362     else if ((section->vma + offset + bytes_to_do) <= 0xffffff 
363              && tdata->type < 2) 
364     {
365       tdata->type = 2;
366     }
367     else 
368     {
369       tdata->type = 3;
370     }
371
372     entry->data = data;
373     entry->where = section->vma + offset;
374     entry->size = bytes_to_do;
375     entry->next = tdata->head;
376     tdata->head = entry;
377   }
378   return true;    
379 }
380
381 /* Write a record of type, of the supplied number of bytes. The
382    supplied bytes and length don't have a checksum. That's worked out
383    here
384 */
385 static
386 void DEFUN(srec_write_record,(abfd, type, address, data, end),
387            bfd *abfd AND
388            char type AND
389            bfd_vma address AND
390            CONST unsigned char *data AND
391            CONST unsigned char *end)
392
393 {
394     char buffer[MAXCHUNK];
395     
396     unsigned int check_sum = 0;
397     unsigned CONST char *src = data;
398     char *dst =buffer;
399     char *length;
400     
401
402     *dst++ = 'S';
403     *dst++ = '0' + type;
404
405     length = dst;
406     dst+=2;                     /* leave room for dst*/
407     
408     switch (type) 
409     {
410       case 3:
411       case 7:
412         TOHEX(dst, (address >> 24), check_sum);
413         dst+=2;
414       case 8:
415       case 2:
416         TOHEX(dst, (address >> 16), check_sum);
417         dst+=2;
418       case 9:
419       case 1:
420       case 0:
421         TOHEX(dst, (address >> 8), check_sum);
422         dst+=2;
423         TOHEX(dst, (address), check_sum);
424         dst+=2;
425         break;
426
427     }
428     for (src = data; src < end; src++) 
429     {
430         TOHEX(dst, *src, check_sum);
431         dst+=2;
432
433     }
434
435     /* Fill in the length */
436     TOHEX(length, (dst - length)/2, check_sum);
437     check_sum &= 0xff;
438     check_sum = 255 - check_sum;
439     TOHEX(dst, check_sum, check_sum);
440     dst+=2;
441     
442     *dst ++ = '\n';
443     bfd_write((PTR)buffer, 1, dst - buffer , abfd);
444 }
445
446
447
448 static void
449 DEFUN(srec_write_header,(abfd),
450       bfd *abfd)
451 {
452     unsigned char buffer[MAXCHUNK];
453     unsigned char *dst = buffer;
454     unsigned int i;
455
456     /* I'll put an arbitary 40 char limit on header size */
457     for (i = 0; i < 40 && abfd->filename[i];  i++) 
458     {
459         *dst++ = abfd->filename[i];
460     }
461     srec_write_record(abfd,0, 0, buffer, dst);
462 }
463
464 static void
465 DEFUN(srec_write_section,(abfd, tdata, list),
466        bfd *abfd AND
467        tdata_type *tdata AND
468        srec_data_list_type *list)
469 {
470     unsigned int bytes_written = 0;
471     unsigned char *location = list->data;
472
473     while (bytes_written < list->size)
474     {
475         bfd_vma address;
476         
477         unsigned int bytes_this_chunk = list->size - bytes_written;
478
479         if (bytes_this_chunk > CHUNK) 
480         {
481             bytes_this_chunk = CHUNK;
482         }
483
484         address = list->where +  bytes_written;
485
486         srec_write_record(abfd,
487                           tdata->type,
488                           address,
489                           location,
490                           location + bytes_this_chunk);
491
492         bytes_written += bytes_this_chunk;
493         location += bytes_this_chunk;
494     }
495
496 }
497
498 static void
499 DEFUN(srec_write_terminator,(abfd, tdata),
500       bfd *abfd AND
501       tdata_type *tdata)
502 {
503     unsigned    char buffer[2];
504     
505     srec_write_record(abfd, 10 - tdata->type,
506                       abfd->start_address, buffer, buffer);
507
508
509 }
510 static boolean
511 DEFUN(srec_mkobject, (abfd), 
512       bfd *abfd)
513 {
514     tdata_type *tdata = (tdata_type *)bfd_alloc(abfd,  sizeof(tdata_type));
515     abfd->tdata.srec_data = tdata;
516     tdata->type = 1;
517     tdata->head = (srec_data_list_type *)NULL;
518     return true;
519     
520 }
521
522       
523 static boolean
524 DEFUN(srec_write_object_contents,(abfd),
525      bfd *abfd)
526 {
527     int bytes_written;
528     tdata_type *tdata = abfd->tdata.srec_data;
529     srec_data_list_type *list;
530
531     bytes_written = 0;
532
533
534     
535     srec_write_header(abfd);
536     
537     /* Now wander though all the sections provided and output them */
538     list = tdata->head;
539
540     while (list != (srec_data_list_type*)NULL) 
541     {
542         srec_write_section(abfd, tdata, list); 
543         list = list->next;
544     }
545     srec_write_terminator(abfd, tdata);
546     return true;
547 }
548
549 static int 
550 DEFUN(srec_sizeof_headers,(abfd, exec),
551       bfd *abfd AND
552       boolean exec)
553 {
554 return 0;
555 }
556
557 static asymbol *
558 DEFUN(srec_make_empty_symbol, (abfd),
559       bfd*abfd)
560 {
561   asymbol *new=  (asymbol *)bfd_zalloc (abfd, sizeof (asymbol));
562   new->the_bfd = abfd;
563   return new;
564 }
565 #define FOO PROTO
566 #define srec_new_section_hook (FOO(boolean, (*), (bfd *, asection *)))bfd_true
567 #define srec_get_symtab_upper_bound (PROTO(unsigned int, (*),(bfd *)))bfd_false
568 #define srec_get_symtab (FOO(unsigned int, (*), (bfd *, asymbol **)))bfd_0
569 #define srec_get_reloc_upper_bound (FOO(unsigned int, (*),(bfd*, asection *)))bfd_false
570 #define srec_canonicalize_reloc (FOO(unsigned int, (*),(bfd*,asection *, arelent **, asymbol **))) bfd_0
571
572 #define srec_print_symbol (FOO(void,(*),(bfd *, PTR, asymbol *, bfd_print_symbol_type))) bfd_void
573
574 #define srec_openr_next_archived_file (FOO(bfd *, (*), (bfd*,bfd*))) bfd_nullvoidptr
575 #define srec_find_nearest_line (FOO(boolean, (*),(bfd*,asection*,asymbol**,bfd_vma, CONST char**, CONST char**, unsigned int *))) bfd_false
576 #define srec_generic_stat_arch_elt  (FOO(int, (*), (bfd *,struct stat *))) bfd_0
577
578
579 #define srec_core_file_failing_command (char *(*)())(bfd_nullvoidptr)
580 #define srec_core_file_failing_signal (int (*)())bfd_0
581 #define srec_core_file_matches_executable_p (FOO(boolean, (*),(bfd*, bfd*)))bfd_false
582 #define srec_slurp_armap bfd_true
583 #define srec_slurp_extended_name_table bfd_true
584 #define srec_truncate_arname (void (*)())bfd_nullvoidptr
585 #define srec_write_armap  (FOO( boolean, (*),(bfd *, unsigned int, struct orl *, unsigned int, int))) bfd_nullvoidptr
586 #define srec_get_lineno (struct lineno_cache_entry *(*)())bfd_nullvoidptr
587 #define srec_close_and_cleanup  bfd_generic_close_and_cleanup
588 #define srec_bfd_debug_info_start bfd_void
589 #define srec_bfd_debug_info_end bfd_void
590 #define srec_bfd_debug_info_accumulate  (FOO(void, (*), (bfd *,  asection *))) bfd_void
591 #define srec_bfd_get_relocated_section_contents bfd_generic_get_relocated_section_contents
592 #define srec_bfd_relax_section bfd_generic_relax_section
593 bfd_target srec_vec =
594 {
595     "srec",                     /* name */
596     bfd_target_srec_flavour,
597     true,                       /* target byte order */
598     true,                       /* target headers byte order */
599     (HAS_RELOC | EXEC_P |       /* object flags */
600      HAS_LINENO | HAS_DEBUG |
601      HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED),
602     (SEC_CODE|SEC_DATA|SEC_ROM|SEC_HAS_CONTENTS
603      |SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
604      0,                         /* leading underscore */
605     ' ',                        /* ar_pad_char */
606     16,                         /* ar_max_namelen */
607     1,                          /* minimum alignment */
608     _do_getb64, _do_putb64,  _do_getb32,
609     _do_putb32, _do_getb16, _do_putb16, /* data */
610     _do_getb64, _do_putb64,  _do_getb32,
611     _do_putb32, _do_getb16, _do_putb16, /* hdrs */
612
613   {
614       _bfd_dummy_target,
615       srec_object_p,            /* bfd_check_format */
616       (struct bfd_target *(*)()) bfd_nullvoidptr,
617       (struct bfd_target *(*)())     bfd_nullvoidptr,
618   },
619   {
620       bfd_false,
621       srec_mkobject,
622       _bfd_generic_mkarchive,
623       bfd_false,
624   },
625   {                             /* bfd_write_contents */
626       bfd_false,
627       srec_write_object_contents,
628       _bfd_write_archive_contents,
629       bfd_false,
630   },
631     JUMP_TABLE(srec)
632  };
633