]>
Commit | Line | Data |
---|---|---|
387cbb2b JG |
1 | /* BFD backend for s-record objects. |
2 | Copyright (C) 1990-1991 Free Software Foundation, Inc. | |
3 | Written by Steve Chamberlain of Cygnus Support <[email protected]>. | |
4a81b561 | 4 | |
387cbb2b | 5 | This file is part of BFD, the Binary File Descriptor library. |
4a81b561 | 6 | |
387cbb2b | 7 | This program is free software; you can redistribute it and/or modify |
4a81b561 | 8 | it under the terms of the GNU General Public License as published by |
387cbb2b JG |
9 | the Free Software Foundation; either version 2 of the License, or |
10 | (at your option) any later version. | |
4a81b561 | 11 | |
387cbb2b | 12 | This program is distributed in the hope that it will be useful, |
4a81b561 DHW |
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 | |
387cbb2b JG |
18 | along with this program; if not, write to the Free Software |
19 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
4a81b561 | 20 | |
387cbb2b JG |
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". | |
4a81b561 | 28 | |
387cbb2b JG |
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. | |
4a81b561 | 31 | |
387cbb2b JG |
32 | Any number of sections may be created for output, we just output them |
33 | in the order provided to bfd_set_section_contents. */ | |
7ed4093a SC |
34 | |
35 | #include <sysdep.h> | |
36773af5 | 36 | #include "bfd.h" |
4a81b561 DHW |
37 | #include "libbfd.h" |
38 | ||
39 | ||
40 | static char digs[] = "0123456789ABCDEF"; | |
41 | ||
42 | /* Macros for converting between hex and binary */ | |
43 | ||
387cbb2b | 44 | #define NIBBLE(x) (((x) >= '0' && (x) <= '9') ? ((x) - '0') : ((x) - 'A' + 10)) |
4a81b561 DHW |
45 | #define HEX(buffer) ((NIBBLE((buffer)->high) <<4) + NIBBLE((buffer)->low)) |
46 | #define TOHEX(d,x) \ | |
387cbb2b JG |
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')) | |
4a81b561 DHW |
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 | ||
387cbb2b | 60 | /* The shape of an s-record .. */ |
4a81b561 DHW |
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 | ||
357a1f38 | 99 | #define enda(x) (x->vma + x->size) |
4a81b561 | 100 | /* |
387cbb2b | 101 | called once per input s-record, used to work out vma and size of data. |
4a81b561 DHW |
102 | */ |
103 | ||
357a1f38 | 104 | static bfd_vma low,high; |
4a81b561 DHW |
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 | { | |
357a1f38 SC |
113 | if (address < low) |
114 | low = address; | |
115 | if (address + length > high) | |
116 | high = address + length; | |
4a81b561 DHW |
117 | } |
118 | ||
357a1f38 | 119 | |
4a81b561 | 120 | /* |
387cbb2b | 121 | called once per input s-record, copies data from input into bfd_alloc'd area |
4a81b561 DHW |
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 | ||
387cbb2b JG |
141 | /* Pass over an s-record file, calling one of the above functions on each |
142 | record. */ | |
143 | ||
4a81b561 DHW |
144 | static void |
145 | pass_over(abfd, func, section) | |
387cbb2b JG |
146 | bfd *abfd; |
147 | void (*func)(); | |
148 | asection *section; | |
4a81b561 DHW |
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 | ||
387cbb2b JG |
168 | if (!ISHEX (buffer.size.high) || !ISHEX (buffer.size.low)) |
169 | break; | |
4a81b561 | 170 | bytes_on_line = HEX(&buffer.size); |
387cbb2b JG |
171 | if (bytes_on_line > MAXCHUNK/2) |
172 | break; | |
4a81b561 | 173 | |
d0ec7a8e | 174 | bfd_read((PTR)buffer.u.data, 1 , bytes_on_line * 2, abfd); |
4a81b561 DHW |
175 | |
176 | switch (buffer.type) { | |
177 | case '6': | |
178 | /* Prologue - ignore */ | |
179 | break; | |
387cbb2b | 180 | |
4a81b561 DHW |
181 | case '3': |
182 | address = (HEX(buffer.u.type_3.address+0) << 24) | |
387cbb2b JG |
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)); | |
6f715d66 | 186 | func(abfd,section, address, buffer.u.type_3.data, bytes_on_line -1); |
4a81b561 DHW |
187 | break; |
188 | ||
189 | case '2': | |
387cbb2b JG |
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)); | |
4a81b561 | 193 | func(abfd,section, address, buffer.u.type_2.data, bytes_on_line -1); |
4a81b561 | 194 | break; |
387cbb2b | 195 | |
4a81b561 | 196 | case '1': |
387cbb2b JG |
197 | address = (HEX(buffer.u.type_1.address+0) << 8) |
198 | + (HEX(buffer.u.type_1.address+1)); | |
4a81b561 DHW |
199 | func(abfd, section, address, buffer.u.type_1.data, bytes_on_line -1); |
200 | break; | |
201 | ||
387cbb2b JG |
202 | default: |
203 | goto end_of_file; | |
4a81b561 DHW |
204 | } |
205 | } | |
387cbb2b | 206 | end_of_file: ; |
4a81b561 DHW |
207 | } |
208 | ||
209 | ||
210 | bfd_target * | |
211 | srec_object_p (abfd) | |
212 | bfd *abfd; | |
213 | { | |
387cbb2b | 214 | char b[4]; |
4a81b561 DHW |
215 | asection *section; |
216 | bfd_seek(abfd, (file_ptr)0, SEEK_SET); | |
387cbb2b JG |
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. */ | |
4a81b561 DHW |
223 | |
224 | section = bfd_make_section(abfd, ".text"); | |
225 | section->size = 0; | |
226 | section->vma = 0xffffffff; | |
357a1f38 SC |
227 | low = 0xffffffff; |
228 | high = 0; | |
4a81b561 | 229 | pass_over(abfd, size_srec, section); |
357a1f38 SC |
230 | section->size = high - low; |
231 | section->vma = low; | |
4a81b561 DHW |
232 | return abfd->xvec; |
233 | } | |
234 | ||
235 | ||
4a81b561 DHW |
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 | { | |
a6ac0c59 | 244 | if (section->used_by_bfd == (PTR)NULL) { |
2b1d8a50 | 245 | section->used_by_bfd = (PTR)bfd_alloc (abfd, section->size); |
4a81b561 DHW |
246 | pass_over(abfd, fillup, section); |
247 | } | |
387cbb2b | 248 | (void) memcpy((PTR)location, (PTR)((char *)(section->used_by_bfd) + offset), count); |
4a81b561 DHW |
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; | |
357a1f38 | 282 | if (section->vma <= 0xffff) |
4a81b561 | 283 | type = 1; |
357a1f38 | 284 | else if (section->vma <= 0xffffff) |
4a81b561 DHW |
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; | |
36773af5 | 296 | unsigned int bytes_this_chunk = bytes_to_do - bytes_written; |
4a81b561 DHW |
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; | |
6f715d66 | 312 | break; |
4a81b561 DHW |
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; | |
6f715d66 | 326 | break; |
4a81b561 DHW |
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'; | |
d0ec7a8e | 339 | bfd_write((PTR)&buffer, 1, (char *)data - (char *)&buffer + 1 , abfd); |
4a81b561 DHW |
340 | |
341 | bytes_written += bytes_this_chunk; | |
342 | location += bytes_this_chunk; | |
343 | } | |
344 | ||
345 | ||
346 | return true; | |
347 | } | |
348 | ||
4a81b561 | 349 | boolean |
2b1d8a50 JG |
350 | srec_write_object_contents (abfd) |
351 | bfd *abfd; | |
4a81b561 | 352 | { |
2b1d8a50 | 353 | bfd_write("S9030000FC\n", 1,11,abfd); |
7ed4093a | 354 | return true; |
4a81b561 DHW |
355 | } |
356 | ||
39a2ce33 | 357 | static int |
7ed4093a SC |
358 | DEFUN(srec_sizeof_headers,(abfd, exec), |
359 | bfd *abfd AND | |
360 | boolean exec) | |
39a2ce33 SC |
361 | { |
362 | return 0; | |
363 | } | |
364 | ||
357a1f38 SC |
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 | } | |
6f715d66 SC |
373 | #define FOO PROTO |
374 | #define srec_new_section_hook (FOO(boolean, (*), (bfd *, asection *)))bfd_true | |
387cbb2b | 375 | #define srec_get_symtab_upper_bound (PROTO(unsigned int, (*),(bfd *)))bfd_false |
6f715d66 SC |
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 | |
357a1f38 | 379 | |
6f715d66 | 380 | #define srec_print_symbol (FOO(void,(*),(bfd *, PTR, asymbol *, bfd_print_symbol_enum_type))) bfd_void |
d0ec7a8e | 381 | |
6f715d66 SC |
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 | |
9872a49c | 385 | |
d0ec7a8e SC |
386 | |
387 | #define srec_core_file_failing_command (char *(*)())(bfd_nullvoidptr) | |
388 | #define srec_core_file_failing_signal (int (*)())bfd_0 | |
6f715d66 | 389 | #define srec_core_file_matches_executable_p (FOO(boolean, (*),(bfd*, bfd*)))bfd_false |
d0ec7a8e SC |
390 | #define srec_slurp_armap bfd_true |
391 | #define srec_slurp_extended_name_table bfd_true | |
392 | #define srec_truncate_arname (void (*)())bfd_nullvoidptr | |
6f715d66 | 393 | #define srec_write_armap (FOO( boolean, (*),(bfd *, unsigned int, struct orl *, int, int))) bfd_nullvoidptr |
d0ec7a8e | 394 | #define srec_get_lineno (struct lineno_cache_entry *(*)())bfd_nullvoidptr |
2b1d8a50 | 395 | #define srec_close_and_cleanup bfd_generic_close_and_cleanup |
6f715d66 SC |
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 | |
2b1d8a50 | 399 | |
d0ec7a8e | 400 | |
4a81b561 DHW |
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), | |
9872a49c | 410 | (SEC_CODE|SEC_DATA|SEC_ROM|SEC_HAS_CONTENTS |
4a81b561 | 411 | |SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ |
4a81b561 DHW |
412 | ' ', /* ar_pad_char */ |
413 | 16, /* ar_max_namelen */ | |
6f715d66 | 414 | 1, /* minimum alignment */ |
7ed4093a SC |
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 | }, | |
2b1d8a50 | 435 | JUMP_TABLE(srec) |
7ed4093a | 436 | }; |