Change svr4 references to sysv4.
[deliverable/binutils-gdb.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
This page took 0.041836 seconds and 4 git commands to generate.