* srec.c: Better error checking, partly from Peter Schauer.
[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 <steve@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 /* S-records cannot hold anything but addresses and data, so that's all
22 that we implement.
23
24 The only interesting thing is that s-records may come out of order and
25 there is no header, so an initial scan is required to discover the
26 minimum and maximum addresses used to create the vma and size of the
27 only section we create. We arbitrarily call this section ".text".
28
29 When bfd_get_section_contents is called the file is read again, and
30 this time the data is placed into a bfd_alloc'd area.
31
32 Any number of sections may be created for output, we just output them
33 in the order provided to bfd_set_section_contents. */
34
35 #include <sysdep.h>
36 #include "bfd.h"
37 #include "libbfd.h"
38
39
40 static char digs[] = "0123456789ABCDEF";
41
42 /* Macros for converting between hex and binary */
43
44 #define NIBBLE(x) (((x) >= '0' && (x) <= '9') ? ((x) - '0') : ((x) - 'A' + 10))
45 #define HEX(buffer) ((NIBBLE((buffer)->high) <<4) + NIBBLE((buffer)->low))
46 #define TOHEX(d,x) \
47 ((d)->low = digs[(x) & 0xf], (d)->high = digs[((x)>>4)&0xf], (x))
48 #define ISHEX(x) (((x) >= '0' && (x) <= '9') || ((x) >= 'A' && (x) <= 'F'))
49
50 typedef struct {
51 char high;
52 char low;
53 } byte_as_two_char_type;
54
55 /* The maximum number of bytes on a line is FF */
56 #define MAXCHUNK 0xff
57 /* The number of bytes we fit onto a line on output */
58 #define CHUNK 16
59
60 /* The shape of an s-record .. */
61 typedef struct
62 {
63 char S;
64 char type;
65 byte_as_two_char_type size;
66 union {
67 struct {
68 byte_as_two_char_type address[4];
69 byte_as_two_char_type data[MAXCHUNK];
70 /* If there isn't MAXCHUNK bytes of data then the checksum will
71 appear earlier */
72 byte_as_two_char_type checksum;
73 char nl;
74 } type_3;
75 struct {
76 byte_as_two_char_type address[4];
77 byte_as_two_char_type data[MAXCHUNK];
78 byte_as_two_char_type checksum;
79 char nl;
80 } type_6;
81
82 struct {
83 byte_as_two_char_type address[3];
84 byte_as_two_char_type data[MAXCHUNK];
85 byte_as_two_char_type checksum;
86 char nl;
87 } type_2;
88
89 struct {
90 byte_as_two_char_type address[2];
91 byte_as_two_char_type data[MAXCHUNK];
92 byte_as_two_char_type checksum;
93 char nl;
94 } type_1;
95 byte_as_two_char_type data[MAXCHUNK];
96 } u;
97 } srec_type;
98
99 #define enda(x) (x->vma + x->size)
100 /*
101 called once per input s-record, used to work out vma and size of data.
102 */
103
104 static bfd_vma low,high;
105 static void
106 size_srec(abfd, section, address, raw, length)
107 bfd *abfd;
108 asection *section;
109 bfd_vma address;
110 byte_as_two_char_type *raw;
111 unsigned int length;
112 {
113 if (address < low)
114 low = address;
115 if (address + length > high)
116 high = address + length;
117 }
118
119
120 /*
121 called once per input s-record, copies data from input into bfd_alloc'd area
122 */
123
124 static void
125 fillup(abfd, section, address, raw, length)
126 bfd *abfd;
127 asection *section;
128 bfd_vma address;
129 byte_as_two_char_type *raw;
130 unsigned int length;
131 {
132 unsigned int i;
133 bfd_byte *dst = (bfd_byte *)(section->used_by_bfd) + address - section->vma;
134 for (i = 0; i < length; i++) {
135 *dst = HEX(raw);
136 dst++;
137 raw++;
138 }
139 }
140
141 /* Pass over an s-record file, calling one of the above functions on each
142 record. */
143
144 static void
145 pass_over(abfd, func, section)
146 bfd *abfd;
147 void (*func)();
148 asection *section;
149 {
150 unsigned int bytes_on_line;
151 boolean eof = false;
152 bfd_vma address;
153 /* To the front of the file */
154 bfd_seek(abfd, (file_ptr)0, SEEK_SET);
155 while (eof == false)
156 {
157 srec_type buffer;
158
159 /* Find first 'S' */
160 eof = bfd_read(&buffer.S, 1, 1, abfd) != 1;
161 while (buffer.S != 'S' && !eof) {
162 eof = bfd_read(&buffer.S, 1, 1, abfd) != 1;
163 }
164 if (eof) break;
165
166 bfd_read(&buffer.type, 1, 3, abfd);
167
168 if (!ISHEX (buffer.size.high) || !ISHEX (buffer.size.low))
169 break;
170 bytes_on_line = HEX(&buffer.size);
171 if (bytes_on_line > MAXCHUNK/2)
172 break;
173
174 bfd_read((PTR)buffer.u.data, 1 , bytes_on_line * 2, abfd);
175
176 switch (buffer.type) {
177 case '6':
178 /* Prologue - ignore */
179 break;
180
181 case '3':
182 address = (HEX(buffer.u.type_3.address+0) << 24)
183 + (HEX(buffer.u.type_3.address+1) << 16)
184 + (HEX(buffer.u.type_3.address+2) << 8)
185 + (HEX(buffer.u.type_3.address+3));
186 func(abfd,section, address, buffer.u.type_3.data, bytes_on_line -1);
187 break;
188
189 case '2':
190 address = (HEX(buffer.u.type_2.address+0) << 16)
191 + (HEX(buffer.u.type_2.address+1) << 8)
192 + (HEX(buffer.u.type_2.address+2));
193 func(abfd,section, address, buffer.u.type_2.data, bytes_on_line -1);
194 break;
195
196 case '1':
197 address = (HEX(buffer.u.type_1.address+0) << 8)
198 + (HEX(buffer.u.type_1.address+1));
199 func(abfd, section, address, buffer.u.type_1.data, bytes_on_line -1);
200 break;
201
202 default:
203 goto end_of_file;
204 }
205 }
206 end_of_file: ;
207 }
208
209
210 bfd_target *
211 srec_object_p (abfd)
212 bfd *abfd;
213 {
214 char b[4];
215 asection *section;
216 bfd_seek(abfd, (file_ptr)0, SEEK_SET);
217 bfd_read(b, 1, 4, abfd);
218 if (b[0] != 'S' || !ISHEX(b[1]) || !ISHEX(b[2]) || !ISHEX(b[3]))
219 return (bfd_target*) NULL;
220
221 /* We create one section called .text for all the contents,
222 and allocate enough room for the entire file. */
223
224 section = bfd_make_section(abfd, ".text");
225 section->size = 0;
226 section->vma = 0xffffffff;
227 low = 0xffffffff;
228 high = 0;
229 pass_over(abfd, size_srec, section);
230 section->size = high - low;
231 section->vma = low;
232 return abfd->xvec;
233 }
234
235
236 static boolean
237 srec_get_section_contents (abfd, section, location, offset, count)
238 bfd *abfd;
239 sec_ptr section;
240 void *location;
241 file_ptr offset;
242 unsigned int count;
243 {
244 if (section->used_by_bfd == (PTR)NULL) {
245 section->used_by_bfd = (PTR)bfd_alloc (abfd, section->size);
246 pass_over(abfd, fillup, section);
247 }
248 (void) memcpy((PTR)location, (PTR)((char *)(section->used_by_bfd) + offset), count);
249 return true;
250 }
251
252
253
254 boolean
255 srec_set_arch_mach (abfd, arch, machine)
256 bfd *abfd;
257 enum bfd_architecture arch;
258 unsigned long machine;
259 {
260 abfd->obj_arch = arch;
261 abfd->obj_machine = machine;
262 return true;
263 }
264
265
266
267 boolean
268 srec_set_section_contents (abfd, section, location, offset, bytes_to_do)
269 bfd *abfd;
270 sec_ptr section;
271 unsigned char *location;
272 file_ptr offset;
273 int bytes_to_do;
274 {
275 bfd_vma address;
276 int bytes_written;
277
278 int type;
279 unsigned int i;
280 srec_type buffer;
281 bytes_written = 0;
282 if (section->vma <= 0xffff)
283 type = 1;
284 else if (section->vma <= 0xffffff)
285 type = 2;
286 else
287 type = 3;
288
289 buffer.S = 'S';
290 buffer.type = '0' + type;
291
292 while (bytes_written < bytes_to_do) {
293 unsigned int size;
294 unsigned int check_sum;
295 byte_as_two_char_type *data;
296 unsigned int bytes_this_chunk = bytes_to_do - bytes_written;
297
298 if (bytes_this_chunk > CHUNK) {
299 bytes_this_chunk = CHUNK;
300 }
301
302 address = section->vma + offset + bytes_written;
303
304 switch (type) {
305 case 3:
306 check_sum = TOHEX(buffer.u.type_3.address, address >> 24);
307 check_sum += TOHEX(buffer.u.type_3.address+1, address >> 16);
308 check_sum += TOHEX(buffer.u.type_3.address+2, address >> 8);
309 check_sum += TOHEX(buffer.u.type_3.address+3, address >> 0);
310 size = bytes_this_chunk + 5;
311 data = buffer.u.type_3.data;
312 break;
313 case 2:
314 check_sum = TOHEX(buffer.u.type_3.address, address >> 16);
315 check_sum += TOHEX(buffer.u.type_3.address+1, address >> 8);
316 check_sum += TOHEX(buffer.u.type_3.address+2, address >> 0);
317 size = bytes_this_chunk + 4;
318 data = buffer.u.type_2.data;
319 break;
320
321 case 1:
322 check_sum = TOHEX(buffer.u.type_3.address+0, address >> 8);
323 check_sum += TOHEX(buffer.u.type_3.address+1, address >> 0);
324 size = bytes_this_chunk + 3;
325 data = buffer.u.type_1.data;
326 break;
327 }
328
329 for (i = 0; i < bytes_this_chunk; i++) {
330 check_sum += TOHEX(data, (location[i]));
331 data++;
332 }
333
334 check_sum += TOHEX(&(buffer.size), size );
335 (void) TOHEX(data, ~check_sum);
336 data++;
337
338 * ( (char *)(data)) = '\n';
339 bfd_write((PTR)&buffer, 1, (char *)data - (char *)&buffer + 1 , abfd);
340
341 bytes_written += bytes_this_chunk;
342 location += bytes_this_chunk;
343 }
344
345
346 return true;
347 }
348
349 boolean
350 srec_write_object_contents (abfd)
351 bfd *abfd;
352 {
353 bfd_write("S9030000FC\n", 1,11,abfd);
354 return true;
355 }
356
357 static int
358 DEFUN(srec_sizeof_headers,(abfd, exec),
359 bfd *abfd AND
360 boolean exec)
361 {
362 return 0;
363 }
364
365 static asymbol *
366 DEFUN(srec_make_empty_symbol, (abfd),
367 bfd*abfd)
368 {
369 asymbol *new= (asymbol *)bfd_zalloc (abfd, sizeof (asymbol));
370 new->the_bfd = abfd;
371 return new;
372 }
373 #define FOO PROTO
374 #define srec_new_section_hook (FOO(boolean, (*), (bfd *, asection *)))bfd_true
375 #define srec_get_symtab_upper_bound (PROTO(unsigned int, (*),(bfd *)))bfd_false
376 #define srec_get_symtab (FOO(unsigned int, (*), (bfd *, asymbol **)))bfd_0
377 #define srec_get_reloc_upper_bound (FOO(unsigned int, (*),(bfd*, asection *)))bfd_false
378 #define srec_canonicalize_reloc (FOO(unsigned int, (*),(bfd*,asection *, arelent **, asymbol **))) bfd_0
379
380 #define srec_print_symbol (FOO(void,(*),(bfd *, PTR, asymbol *, bfd_print_symbol_enum_type))) bfd_void
381
382 #define srec_openr_next_archived_file (FOO(bfd *, (*), (bfd*,bfd*))) bfd_nullvoidptr
383 #define srec_find_nearest_line (FOO(boolean, (*),(bfd*,asection*,asymbol**,bfd_vma, CONST char**, CONST char**, unsigned int *))) bfd_false
384 #define srec_generic_stat_arch_elt (FOO(int, (*), (bfd *,struct stat *))) bfd_0
385
386
387 #define srec_core_file_failing_command (char *(*)())(bfd_nullvoidptr)
388 #define srec_core_file_failing_signal (int (*)())bfd_0
389 #define srec_core_file_matches_executable_p (FOO(boolean, (*),(bfd*, bfd*)))bfd_false
390 #define srec_slurp_armap bfd_true
391 #define srec_slurp_extended_name_table bfd_true
392 #define srec_truncate_arname (void (*)())bfd_nullvoidptr
393 #define srec_write_armap (FOO( boolean, (*),(bfd *, unsigned int, struct orl *, int, int))) bfd_nullvoidptr
394 #define srec_get_lineno (struct lineno_cache_entry *(*)())bfd_nullvoidptr
395 #define srec_close_and_cleanup bfd_generic_close_and_cleanup
396 #define srec_bfd_debug_info_start bfd_void
397 #define srec_bfd_debug_info_end bfd_void
398 #define srec_bfd_debug_info_accumulate (FOO(void, (*), (bfd *, asection *))) bfd_void
399
400
401 bfd_target srec_vec =
402 {
403 "srec", /* name */
404 bfd_target_srec_flavour_enum,
405 true, /* target byte order */
406 true, /* target headers byte order */
407 (HAS_RELOC | EXEC_P | /* object flags */
408 HAS_LINENO | HAS_DEBUG |
409 HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED),
410 (SEC_CODE|SEC_DATA|SEC_ROM|SEC_HAS_CONTENTS
411 |SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
412 ' ', /* ar_pad_char */
413 16, /* ar_max_namelen */
414 1, /* minimum alignment */
415 _do_getb64, _do_putb64, _do_getb32, _do_putb32, _do_getb16, _do_putb16, /* data */
416 _do_getb64, _do_putb64, _do_getb32, _do_putb32, _do_getb16, _do_putb16, /* hdrs */
417
418 {_bfd_dummy_target,
419 srec_object_p, /* bfd_check_format */
420 (struct bfd_target *(*)()) bfd_nullvoidptr,
421 (struct bfd_target *(*)()) bfd_nullvoidptr,
422 },
423 {
424 bfd_false,
425 bfd_true, /* mkobject */
426 _bfd_generic_mkarchive,
427 bfd_false,
428 },
429 { /* bfd_write_contents */
430 bfd_false,
431 srec_write_object_contents,
432 _bfd_write_archive_contents,
433 bfd_false,
434 },
435 JUMP_TABLE(srec)
436 };
This page took 0.056623 seconds and 5 git commands to generate.