This commit was generated by cvs2svn to track changes on a CVS vendor
[external/binutils.git] / bfd / srec.c
1 /* Copyright (C) 1990, 1991 Free Software Foundation, Inc.
2
3 This file is part of BFD, the Binary File Diddler.
4
5 BFD is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 1, or (at your option)
8 any later version.
9
10 BFD is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with BFD; see the file COPYING.  If not, write to
17 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
18
19 /*
20
21  bfd backend for srecord objects.
22
23  Srecords cannot hold anything but addresses and data, so that's all
24  that we impliment.
25  
26  The only interesting thing is that srecords may come out of order and
27  there is no header, so an initial scan is required to discover the
28  minimum and maximum addresses used to create the vma and size of the
29  only section we create. We arbitarily call this section ".text".
30
31  When bfd_get_section_contents is called the file is read again, and
32  this time the data is placed into a malloced area.
33
34  Any number of sections may be created for output, we just output them
35  in the order provided to bfd_set_section_contents.
36
37
38  Steve Chamberlain steve@cygnus.com
39
40  */
41
42
43 /* $Id$
44  * $Log$
45  * Revision 1.2  1991/04/03 22:10:51  steve
46  * Fixed typo
47  *
48  * Revision 1.1.1.1  1991/03/21  21:11:22  gumby
49  * Back from Intel with Steve
50  *
51  * Revision 1.1  1991/03/21  21:11:20  gumby
52  * Initial revision
53  *
54  * Revision 1.1  1991/03/13  00:22:29  chrisb
55  * Initial revision
56  *
57  * Revision 1.3  1991/03/10  19:11:40  rich
58  *  Modified Files:
59  *      bfd.c coff-code.h libbfd.c libbfd.h srec.c sunos.c
60  *
61  * Working bugs out of coff support.
62  *
63  * Revision 1.2  1991/03/07  02:26:18  sac
64  * Tidied up xfer table
65  *
66  * Revision 1.1  1991/03/05  16:28:12  sac
67  * Initial revision
68  *
69  */
70 #include "sysdep.h"
71 #include "bfd.h"
72 #include "libbfd.h"
73
74
75 static char digs[] = "0123456789ABCDEF";
76
77 /* Macros for converting between hex and binary */
78
79 #define NIBBLE(x) ((x >= '0' && x <= '9') ? (x - '0') : (x - 'A' + 10))
80 #define HEX(buffer) ((NIBBLE((buffer)->high) <<4) + NIBBLE((buffer)->low))
81 #define TOHEX(d,x) \
82   ((d)->low = digs[(x) & 0xf], (d)->high = digs[((x)>>4)&0xf], x)
83
84 typedef struct {
85   char high;
86   char low;
87 } byte_as_two_char_type;
88
89 /* The maximum number of bytes on a line is FF */
90 #define MAXCHUNK 0xff 
91 /* The number of bytes we fit onto a line on output */
92 #define CHUNK 16 
93
94 /* The shape of an srecord .. */
95 typedef struct 
96 {
97   char S;
98   char type;
99   byte_as_two_char_type size;
100   union {
101     struct {
102       byte_as_two_char_type address[4];
103       byte_as_two_char_type data[MAXCHUNK];
104       /* If there isn't MAXCHUNK bytes of data then the checksum will 
105          appear earlier */
106       byte_as_two_char_type checksum;
107       char nl;
108     } type_3;
109     struct {
110       byte_as_two_char_type address[4];
111       byte_as_two_char_type data[MAXCHUNK];
112       byte_as_two_char_type checksum;
113       char nl;
114     } type_6;
115
116     struct {
117       byte_as_two_char_type address[3];
118       byte_as_two_char_type data[MAXCHUNK];
119       byte_as_two_char_type checksum;
120       char nl;
121     } type_2;
122
123     struct {
124       byte_as_two_char_type address[2];
125       byte_as_two_char_type data[MAXCHUNK];
126       byte_as_two_char_type checksum;
127       char nl;
128     } type_1;
129     byte_as_two_char_type data[MAXCHUNK];
130   } u;
131 } srec_type;
132
133
134 /* 
135    called once per input srecord, used to work out vma and size of data.
136  */
137
138 static void
139 size_srec(abfd, section, address, raw, length)
140 bfd *abfd;
141 asection *section;
142 bfd_vma address;
143 byte_as_two_char_type *raw;
144 unsigned int length;
145 {
146   if (address < section->vma)
147     section->vma = address;
148
149   if (address + length  > section->vma + section->size)
150     section->size = (address+length) -  section->vma;
151 }
152
153 /*
154  called once per input srecord, copies data from input into malloced area
155  */
156
157 static void
158 fillup(abfd, section, address, raw, length)
159 bfd *abfd;
160 asection *section;
161 bfd_vma address;
162 byte_as_two_char_type *raw;
163 unsigned int length;
164 {
165   unsigned int i;
166   bfd_byte *dst = (bfd_byte *)(section->used_by_bfd) +  address - section->vma;
167   for (i = 0; i < length; i++) {
168     *dst = HEX(raw);
169     dst++;
170     raw++;
171   }
172 }
173
174 /*
175  pass over an srecord file calling one of the above functions on each
176  record
177  */
178 static void
179 pass_over(abfd, func, section)
180 bfd *abfd;
181 void (*func)();
182 asection *section;
183 {
184   unsigned int bytes_on_line;
185   boolean eof = false;
186   bfd_vma address;
187   /* To the front of the file */
188   bfd_seek(abfd, (file_ptr)0, SEEK_SET);
189   while (eof == false)
190     {
191       srec_type buffer;
192
193       /* Find first 'S' */
194       eof =  bfd_read(&buffer.S, 1, 1, abfd) != 1;
195       while (buffer.S != 'S' && !eof) {
196         eof =  bfd_read(&buffer.S, 1, 1, abfd) != 1;
197       }
198       if (eof) break;
199
200       bfd_read(&buffer.type, 1, 3, abfd);
201
202       bytes_on_line = HEX(&buffer.size);
203     
204       bfd_read(buffer.u.data, 1 , bytes_on_line * 2, abfd);
205
206       switch (buffer.type) {
207       case '6':
208         /* Prologue - ignore */
209         break;
210       case '3':
211         address = (HEX(buffer.u.type_3.address+0) << 24)
212           + (HEX(buffer.u.type_3.address+1) << 16)
213             + (HEX(buffer.u.type_3.address+2) << 8) 
214               + (HEX(buffer.u.type_3.address+3));
215         func(abfd,section, address, buffer.u.type_2.data, bytes_on_line -1);
216
217         break;
218
219       case '2':
220         address = (HEX(buffer.u.type_2.address+0) << 16)+
221           (HEX(buffer.u.type_2.address+1) << 8) +
222         (HEX(buffer.u.type_2.address+2));
223         func(abfd,section, address, buffer.u.type_2.data, bytes_on_line -1);
224
225         break;
226       case '1':
227         address =
228           (HEX(buffer.u.type_1.address+0) << 8) 
229             + (HEX(buffer.u.type_1.address+1));
230         func(abfd, section, address, buffer.u.type_1.data, bytes_on_line -1);
231         break;
232
233       }
234     }
235 }
236
237
238 bfd_target *
239 srec_object_p (abfd)
240 bfd *abfd;
241 {
242   char b;
243   asection *section;
244   bfd_seek(abfd, (file_ptr)0, SEEK_SET);
245   bfd_read(&b, 1,1,abfd);
246   if (b != 'S') return (bfd_target*)NULL;
247
248   /* 
249      We create one section called data for all the contents, 
250      and allocate enough room for the entire file
251      */
252
253
254   section =  bfd_make_section(abfd, ".text");
255   section->size = 0;
256   section->vma = 0xffffffff;
257   pass_over(abfd, size_srec, section);
258
259   return abfd->xvec;
260 }
261
262
263
264
265
266
267
268
269 static boolean
270 srec_get_section_contents (abfd, section, location, offset, count)
271 bfd *abfd;
272 sec_ptr section;
273 void  *location;
274 file_ptr offset;
275 unsigned      int count;
276 {
277   if (section->used_by_bfd == (bfd_byte *)NULL) {
278     section->used_by_bfd = (bfd_byte *)malloc(section->size);
279     pass_over(abfd, fillup, section);
280   }
281   (void) memcpy(location, (bfd_byte *)(section->used_by_bfd) + offset, count);
282   return true;
283 }
284       
285
286
287 boolean
288 srec_set_arch_mach (abfd, arch, machine)
289 bfd *abfd;
290 enum bfd_architecture arch;
291 unsigned long machine;
292 {
293   abfd->obj_arch = arch;
294   abfd->obj_machine = machine;
295   return true;
296 }
297
298
299
300 boolean
301 srec_set_section_contents (abfd, section, location, offset, bytes_to_do)
302 bfd *abfd;
303 sec_ptr section;
304 unsigned char *location;
305 file_ptr offset;
306 int bytes_to_do;
307 {
308   bfd_vma address;
309   int bytes_written;
310
311   int type;
312   unsigned int i;
313   srec_type buffer;
314   bytes_written = 0;
315   if (section->size <= 0xffff) 
316     type = 1;
317   else if (section->size <= 0xffffff) 
318     type = 2;
319   else
320     type = 3;
321
322   buffer.S = 'S';
323   buffer.type = '0' + type;
324
325   while (bytes_written < bytes_to_do) {
326     unsigned int size;
327     unsigned int check_sum;
328     byte_as_two_char_type *data; 
329  unsigned   int bytes_this_chunk = bytes_to_do - bytes_written;
330
331     if (bytes_this_chunk > CHUNK) {
332       bytes_this_chunk = CHUNK;
333     }
334
335     address = section->vma + offset + bytes_written;
336
337     switch (type) {
338     case 3:
339       check_sum = TOHEX(buffer.u.type_3.address, address >> 24);
340       check_sum += TOHEX(buffer.u.type_3.address+1, address >> 16);
341       check_sum += TOHEX(buffer.u.type_3.address+2, address >> 8);
342       check_sum += TOHEX(buffer.u.type_3.address+3, address >> 0);
343       size = bytes_this_chunk + 5;
344       data = buffer.u.type_3.data;
345
346     case 2:
347       check_sum = TOHEX(buffer.u.type_3.address, address >> 16);
348       check_sum += TOHEX(buffer.u.type_3.address+1, address >> 8);
349       check_sum += TOHEX(buffer.u.type_3.address+2, address >> 0);
350       size = bytes_this_chunk + 4;
351       data = buffer.u.type_2.data;
352       break;
353
354     case 1:
355       check_sum = TOHEX(buffer.u.type_3.address+0, address >> 8);
356       check_sum += TOHEX(buffer.u.type_3.address+1, address >> 0);
357       size = bytes_this_chunk + 3;
358       data = buffer.u.type_1.data;
359     }
360
361     for (i = 0; i < bytes_this_chunk; i++) {
362       check_sum += TOHEX(data, (location[i]));
363       data++;
364     }
365
366     check_sum += TOHEX(&(buffer.size), size );
367     (void) TOHEX(data, ~check_sum);
368     data++;
369
370     * ( (char *)(data)) = '\n';
371     bfd_write(&buffer, 1, (char *)data - (char *)&buffer + 1 , abfd);
372
373     bytes_written += bytes_this_chunk;
374     location += bytes_this_chunk;
375   }
376
377
378   return true;
379 }
380
381
382 boolean
383 srec_close_and_cleanup (abfd)
384 bfd *abfd;
385 {
386   asection *s;
387   if (bfd_read_p (abfd) == false) {
388     switch (abfd->format) {
389     case bfd_archive:
390       if (!_bfd_write_archive_contents (abfd)) {
391         return false;
392       }
393       break;
394     case bfd_object:
395       bfd_write("S9030000FC\n", 1,11,abfd);
396       break;
397     default:
398       bfd_error = invalid_operation;
399       return false;
400     }
401   }
402   for (s = abfd->sections; s != (asection *)NULL;s = s->next) {
403     if (s->used_by_bfd != (void *)NULL) {
404       free(s->used_by_bfd);
405     }
406   }
407   return true;
408 }
409
410 /*SUPPRESS 460 */
411 bfd_target srec_vec =
412 {
413   "srec",                       /* name */
414   bfd_target_srec_flavour_enum,
415   true,                         /* target byte order */
416   true,                         /* target headers byte order */
417   (HAS_RELOC | EXEC_P |         /* object flags */
418    HAS_LINENO | HAS_DEBUG |
419    HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED),
420   (SEC_CODE|SEC_DATA|SEC_ROM
421    |SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
422   0,                            /* valid reloc types */
423   ' ',                          /* ar_pad_char */
424   16,                           /* ar_max_namelen */
425   srec_close_and_cleanup,       /* _close_and_cleanup */
426   srec_set_section_contents,    /* bfd_set_section_contents */
427   srec_get_section_contents,
428   bfd_true,                     /*   new_section_hook */
429   0,                            /* _core_file_failing_command */
430   0,                            /* _core_file_failing_signal */
431   0,                            /* _core_file_matches_ex...p */
432
433   bfd_false,                    /* bfd_slurp_armap */
434   bfd_false,                    /* bfd_slurp_extended_name_table */
435   bfd_void,                     /* bfd_truncate_arname */
436   bfd_0u,                       /* get_symtab_upper_bound */
437   bfd_0u,                       /* canonicalize_symtab */
438   bfd_void,                     /* bfd_reclaim_symbol_table */
439   bfd_0u,                       /* get_reloc_upper_bound */
440   bfd_0u,                       /* bfd_canonicalize_reloc */
441   bfd_void,                     /* bfd_reclaim_reloc */
442   bfd_0,                        /* bfd_get_symcount_upper_bound */
443   (symindex (*)())bfd_0,        /* bfd_get_first_symbol */
444   (symindex (*)())bfd_0,        /* bfd_get_next_symbol */
445   bfd_false,                    /* bfd_classify_symbol */
446   bfd_false,                    /* bfd_symbol_hasclass */
447   (char* (*)())bfd_0,           /* bfd_symbol_name */
448   bfd_0,                        /* bfd_symbol_value */
449
450   _do_getblong, _do_putblong, _do_getbshort, _do_putbshort, /* data */
451   _do_getblong, _do_putblong, _do_getbshort, _do_putbshort, /* hdrs */
452
453   {_bfd_dummy_target,
454      srec_object_p,             /* bfd_check_format */
455      (struct bfd_target *(*)()) bfd_nullvoidptr,
456      (struct bfd_target *(*)())     bfd_nullvoidptr,
457    },
458   {
459     bfd_false,
460     bfd_true,                   /* mkobject */
461     _bfd_generic_mkarchive,
462     bfd_false,
463   },
464   (asymbol * (*)())  bfd_nullvoidptr, /* bfd_make_empty_symbol */
465   bfd_void,                     /* bfd_prit_symbol */
466   (alent *(*)())bfd_nullvoidptr, /* srec_get_lineno,*/
467   srec_set_arch_mach,           /* bfd_set_arch_mach,*/
468   bfd_false,                    /* write_armap*/
469   (bfd *(*)())bfd_nullvoidptr,  /* openr_next_archived_file */
470   bfd_false,                    /* bfd_find_nearest_line */
471 };