*** empty log message ***
[binutils-gdb.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.5 1991/04/23 22:44:14 steve
46 * *** empty log message ***
47 *
48 * Revision 1.4 1991/04/23 16:01:02 steve
49 * *** empty log message ***
50 *
51 * Revision 1.3 1991/04/08 23:22:31 steve
52 * *** empty log message ***
53 *
54 * Revision 1.2 1991/04/03 22:10:51 steve
55 * Fixed typo
56 *
57 * Revision 1.1.1.1 1991/03/21 21:11:22 gumby
58 * Back from Intel with Steve
59 *
60 * Revision 1.1 1991/03/21 21:11:20 gumby
61 * Initial revision
62 *
63 * Revision 1.1 1991/03/13 00:22:29 chrisb
64 * Initial revision
65 *
66 * Revision 1.3 1991/03/10 19:11:40 rich
67 * Modified Files:
68 * bfd.c coff-code.h libbfd.c libbfd.h srec.c sunos.c
69 *
70 * Working bugs out of coff support.
71 *
72 * Revision 1.2 1991/03/07 02:26:18 sac
73 * Tidied up xfer table
74 *
75 * Revision 1.1 1991/03/05 16:28:12 sac
76 * Initial revision
77 *
78 */
79 #include "sysdep.h"
80 #include "bfd.h"
81 #include "libbfd.h"
82
83
84 static char digs[] = "0123456789ABCDEF";
85
86 /* Macros for converting between hex and binary */
87
88 #define NIBBLE(x) ((x >= '0' && x <= '9') ? (x - '0') : (x - 'A' + 10))
89 #define HEX(buffer) ((NIBBLE((buffer)->high) <<4) + NIBBLE((buffer)->low))
90 #define TOHEX(d,x) \
91 ((d)->low = digs[(x) & 0xf], (d)->high = digs[((x)>>4)&0xf], x)
92
93 typedef struct {
94 char high;
95 char low;
96 } byte_as_two_char_type;
97
98 /* The maximum number of bytes on a line is FF */
99 #define MAXCHUNK 0xff
100 /* The number of bytes we fit onto a line on output */
101 #define CHUNK 16
102
103 /* The shape of an srecord .. */
104 typedef struct
105 {
106 char S;
107 char type;
108 byte_as_two_char_type size;
109 union {
110 struct {
111 byte_as_two_char_type address[4];
112 byte_as_two_char_type data[MAXCHUNK];
113 /* If there isn't MAXCHUNK bytes of data then the checksum will
114 appear earlier */
115 byte_as_two_char_type checksum;
116 char nl;
117 } type_3;
118 struct {
119 byte_as_two_char_type address[4];
120 byte_as_two_char_type data[MAXCHUNK];
121 byte_as_two_char_type checksum;
122 char nl;
123 } type_6;
124
125 struct {
126 byte_as_two_char_type address[3];
127 byte_as_two_char_type data[MAXCHUNK];
128 byte_as_two_char_type checksum;
129 char nl;
130 } type_2;
131
132 struct {
133 byte_as_two_char_type address[2];
134 byte_as_two_char_type data[MAXCHUNK];
135 byte_as_two_char_type checksum;
136 char nl;
137 } type_1;
138 byte_as_two_char_type data[MAXCHUNK];
139 } u;
140 } srec_type;
141
142
143 /*
144 called once per input srecord, used to work out vma and size of data.
145 */
146
147 static void
148 size_srec(abfd, section, address, raw, length)
149 bfd *abfd;
150 asection *section;
151 bfd_vma address;
152 byte_as_two_char_type *raw;
153 unsigned int length;
154 {
155 if (address < section->vma)
156 section->vma = address;
157
158 if (address + length > section->vma + section->size)
159 section->size = (address+length) - section->vma;
160 }
161
162 /*
163 called once per input srecord, copies data from input into malloced area
164 */
165
166 static void
167 fillup(abfd, section, address, raw, length)
168 bfd *abfd;
169 asection *section;
170 bfd_vma address;
171 byte_as_two_char_type *raw;
172 unsigned int length;
173 {
174 unsigned int i;
175 bfd_byte *dst = (bfd_byte *)(section->used_by_bfd) + address - section->vma;
176 for (i = 0; i < length; i++) {
177 *dst = HEX(raw);
178 dst++;
179 raw++;
180 }
181 }
182
183 /*
184 pass over an srecord file calling one of the above functions on each
185 record
186 */
187 static void
188 pass_over(abfd, func, section)
189 bfd *abfd;
190 void (*func)();
191 asection *section;
192 {
193 unsigned int bytes_on_line;
194 boolean eof = false;
195 bfd_vma address;
196 /* To the front of the file */
197 bfd_seek(abfd, (file_ptr)0, SEEK_SET);
198 while (eof == false)
199 {
200 srec_type buffer;
201
202 /* Find first 'S' */
203 eof = bfd_read(&buffer.S, 1, 1, abfd) != 1;
204 while (buffer.S != 'S' && !eof) {
205 eof = bfd_read(&buffer.S, 1, 1, abfd) != 1;
206 }
207 if (eof) break;
208
209 bfd_read(&buffer.type, 1, 3, abfd);
210
211 bytes_on_line = HEX(&buffer.size);
212
213 bfd_read(buffer.u.data, 1 , bytes_on_line * 2, abfd);
214
215 switch (buffer.type) {
216 case '6':
217 /* Prologue - ignore */
218 break;
219 case '3':
220 address = (HEX(buffer.u.type_3.address+0) << 24)
221 + (HEX(buffer.u.type_3.address+1) << 16)
222 + (HEX(buffer.u.type_3.address+2) << 8)
223 + (HEX(buffer.u.type_3.address+3));
224 func(abfd,section, address, buffer.u.type_2.data, bytes_on_line -1);
225
226 break;
227
228 case '2':
229 address = (HEX(buffer.u.type_2.address+0) << 16)+
230 (HEX(buffer.u.type_2.address+1) << 8) +
231 (HEX(buffer.u.type_2.address+2));
232 func(abfd,section, address, buffer.u.type_2.data, bytes_on_line -1);
233
234 break;
235 case '1':
236 address =
237 (HEX(buffer.u.type_1.address+0) << 8)
238 + (HEX(buffer.u.type_1.address+1));
239 func(abfd, section, address, buffer.u.type_1.data, bytes_on_line -1);
240 break;
241
242 }
243 }
244 }
245
246
247 bfd_target *
248 srec_object_p (abfd)
249 bfd *abfd;
250 {
251 char b;
252 asection *section;
253 bfd_seek(abfd, (file_ptr)0, SEEK_SET);
254 bfd_read(&b, 1,1,abfd);
255 if (b != 'S') return (bfd_target*)NULL;
256
257 /*
258 We create one section called data for all the contents,
259 and allocate enough room for the entire file
260 */
261
262
263 section = bfd_make_section(abfd, ".text");
264 section->size = 0;
265 section->vma = 0xffffffff;
266 pass_over(abfd, size_srec, section);
267
268 return abfd->xvec;
269 }
270
271
272
273
274
275
276
277
278 static boolean
279 srec_get_section_contents (abfd, section, location, offset, count)
280 bfd *abfd;
281 sec_ptr section;
282 void *location;
283 file_ptr offset;
284 unsigned int count;
285 {
286 if (section->used_by_bfd == (bfd_byte *)NULL) {
287 section->used_by_bfd = (bfd_byte *)malloc(section->size);
288 pass_over(abfd, fillup, section);
289 }
290 (void) memcpy(location, (bfd_byte *)(section->used_by_bfd) + offset, count);
291 return true;
292 }
293
294
295
296 boolean
297 srec_set_arch_mach (abfd, arch, machine)
298 bfd *abfd;
299 enum bfd_architecture arch;
300 unsigned long machine;
301 {
302 abfd->obj_arch = arch;
303 abfd->obj_machine = machine;
304 return true;
305 }
306
307
308
309 boolean
310 srec_set_section_contents (abfd, section, location, offset, bytes_to_do)
311 bfd *abfd;
312 sec_ptr section;
313 unsigned char *location;
314 file_ptr offset;
315 int bytes_to_do;
316 {
317 bfd_vma address;
318 int bytes_written;
319
320 int type;
321 unsigned int i;
322 srec_type buffer;
323 bytes_written = 0;
324 if (section->size <= 0xffff)
325 type = 1;
326 else if (section->size <= 0xffffff)
327 type = 2;
328 else
329 type = 3;
330
331 buffer.S = 'S';
332 buffer.type = '0' + type;
333
334 while (bytes_written < bytes_to_do) {
335 unsigned int size;
336 unsigned int check_sum;
337 byte_as_two_char_type *data;
338 unsigned int bytes_this_chunk = bytes_to_do - bytes_written;
339
340 if (bytes_this_chunk > CHUNK) {
341 bytes_this_chunk = CHUNK;
342 }
343
344 address = section->vma + offset + bytes_written;
345
346 switch (type) {
347 case 3:
348 check_sum = TOHEX(buffer.u.type_3.address, address >> 24);
349 check_sum += TOHEX(buffer.u.type_3.address+1, address >> 16);
350 check_sum += TOHEX(buffer.u.type_3.address+2, address >> 8);
351 check_sum += TOHEX(buffer.u.type_3.address+3, address >> 0);
352 size = bytes_this_chunk + 5;
353 data = buffer.u.type_3.data;
354
355 case 2:
356 check_sum = TOHEX(buffer.u.type_3.address, address >> 16);
357 check_sum += TOHEX(buffer.u.type_3.address+1, address >> 8);
358 check_sum += TOHEX(buffer.u.type_3.address+2, address >> 0);
359 size = bytes_this_chunk + 4;
360 data = buffer.u.type_2.data;
361 break;
362
363 case 1:
364 check_sum = TOHEX(buffer.u.type_3.address+0, address >> 8);
365 check_sum += TOHEX(buffer.u.type_3.address+1, address >> 0);
366 size = bytes_this_chunk + 3;
367 data = buffer.u.type_1.data;
368 }
369
370 for (i = 0; i < bytes_this_chunk; i++) {
371 check_sum += TOHEX(data, (location[i]));
372 data++;
373 }
374
375 check_sum += TOHEX(&(buffer.size), size );
376 (void) TOHEX(data, ~check_sum);
377 data++;
378
379 * ( (char *)(data)) = '\n';
380 bfd_write(&buffer, 1, (char *)data - (char *)&buffer + 1 , abfd);
381
382 bytes_written += bytes_this_chunk;
383 location += bytes_this_chunk;
384 }
385
386
387 return true;
388 }
389
390
391 boolean
392 srec_close_and_cleanup (abfd)
393 bfd *abfd;
394 {
395 asection *s;
396 if (bfd_read_p (abfd) == false) {
397 switch (abfd->format) {
398 case bfd_archive:
399 if (!_bfd_write_archive_contents (abfd)) {
400 return false;
401 }
402 break;
403 case bfd_object:
404 bfd_write("S9030000FC\n", 1,11,abfd);
405 break;
406 default:
407 bfd_error = invalid_operation;
408 return false;
409 }
410 }
411 for (s = abfd->sections; s != (asection *)NULL;s = s->next) {
412 if (s->used_by_bfd != (void *)NULL) {
413 free(s->used_by_bfd);
414 }
415 }
416 return true;
417 }
418
419 static int
420 DEFUN(srec_sizeof_headers,(abfd),
421 bfd *abfd)
422 {
423 return 0;
424 }
425
426 /*SUPPRESS 460 */
427 #define srec_core_file_failing_command bfd_false
428 #define srec_core_file_failing_signal bfd_false
429 #define srec_core_file_matches_executable_p bfd_false
430 #define srec_slurp_armap bfd_false
431 #define srec_slurp_extended_name_table bfd_false
432 #define srec_truncate_arname bfd_false
433 #define srec_write_armap bfd_false
434 #define srec_new_section_hook bfd_false
435 #define srec_get_symtab_upper_bound bfd_false
436 #define srec_get_symtab bfd_false
437 #define srec_get_reloc_upper_bound bfd_false
438 #define srec_canonicalize_reloc bfd_false
439 #define srec_make_empty_symbol bfd_false
440 #define srec_print_symbol bfd_false
441 #define srec_get_lineno bfd_false
442 #define srec_openr_next_archived_file bfd_false
443 #define srec_find_nearest_line bfd_false
444 #define srec_generic_stat_arch_elt bfd_false
445
446 bfd_target srec_vec =
447 {
448 "srec", /* name */
449 bfd_target_srec_flavour_enum,
450 true, /* target byte order */
451 true, /* target headers byte order */
452 (HAS_RELOC | EXEC_P | /* object flags */
453 HAS_LINENO | HAS_DEBUG |
454 HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED),
455 (SEC_CODE|SEC_DATA|SEC_ROM|SEC_HAS_CONTENTS
456 |SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
457 ' ', /* ar_pad_char */
458 16, /* ar_max_namelen */
459 _do_getblong, _do_putblong, _do_getbshort, _do_putbshort, /* data */
460 _do_getblong, _do_putblong, _do_getbshort, _do_putbshort, /* hdrs */
461
462 {_bfd_dummy_target,
463 srec_object_p, /* bfd_check_format */
464 (struct bfd_target *(*)()) bfd_nullvoidptr,
465 (struct bfd_target *(*)()) bfd_nullvoidptr,
466 },
467 {
468 bfd_false,
469 bfd_true, /* mkobject */
470 _bfd_generic_mkarchive,
471 bfd_false,
472 },
473 JUMP_TABLE(srec)
474 };