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