/src/binutils-gdb/bfd/tekhex.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* BFD backend for Extended Tektronix Hex Format objects. |
2 | | Copyright (C) 1992-2025 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 3 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., 51 Franklin Street - Fifth Floor, Boston, |
20 | | MA 02110-1301, USA. */ |
21 | | |
22 | | |
23 | | /* SUBSECTION |
24 | | Tektronix Hex Format handling |
25 | | |
26 | | DESCRIPTION |
27 | | |
28 | | Tek Hex records can hold symbols and data, but not |
29 | | relocations. Their main application is communication with |
30 | | devices like PROM programmers and ICE equipment. |
31 | | |
32 | | It seems that the sections are described as being really big, |
33 | | the example I have says that the text section is 0..ffffffff. |
34 | | BFD would barf with this, many apps would try to alloc 4GB to |
35 | | read in the file. |
36 | | |
37 | | Tex Hex may contain many sections, but the data which comes in |
38 | | has no tag saying which section it belongs to, so we create |
39 | | one section for each block of data, called "blknnnn" which we |
40 | | stick all the data into. |
41 | | |
42 | | TekHex may come out of order and there is no header, so an |
43 | | initial scan is required to discover the minimum and maximum |
44 | | addresses used to create the vma and size of the sections we |
45 | | create. |
46 | | We read in the data into pages of CHUNK_MASK+1 size and read |
47 | | them out from that whenever we need to. |
48 | | |
49 | | Any number of sections may be created for output, we save them |
50 | | up and output them when it's time to close the bfd. |
51 | | |
52 | | A TekHex record looks like: |
53 | | EXAMPLE |
54 | | %<block length><type><checksum><stuff><cr> |
55 | | |
56 | | DESCRIPTION |
57 | | Where |
58 | | o length |
59 | | is the number of bytes in the record not including the % sign. |
60 | | o type |
61 | | is one of: |
62 | | 3) symbol record |
63 | | 6) data record |
64 | | 8) termination record |
65 | | |
66 | | The data can come out of order, and may be discontigous. This is a |
67 | | serial protocol, so big files are unlikely, so we keep a list of 8k chunks. */ |
68 | | |
69 | | #include "sysdep.h" |
70 | | #include "bfd.h" |
71 | | #include "libbfd.h" |
72 | | #include "libiberty.h" |
73 | | |
74 | | typedef struct |
75 | | { |
76 | | bfd_vma low; |
77 | | bfd_vma high; |
78 | | } addr_range_type; |
79 | | |
80 | | typedef struct tekhex_symbol_struct |
81 | | { |
82 | | asymbol symbol; |
83 | | struct tekhex_symbol_struct *prev; |
84 | | } tekhex_symbol_type; |
85 | | |
86 | | static const char digs[] = "0123456789ABCDEF"; |
87 | | |
88 | | static char sum_block[256]; |
89 | | |
90 | | #define NOT_HEX 20 |
91 | 977k | #define NIBBLE(x) hex_value(x) |
92 | 488k | #define HEX(buffer) ((NIBBLE ((buffer)[0]) << 4) + NIBBLE ((buffer)[1])) |
93 | 4.52M | #define ISHEX(x) hex_p(x) |
94 | | #define TOHEX(d, x) \ |
95 | 5.51k | (d)[1] = digs[(x) & 0xf]; \ |
96 | 5.51k | (d)[0] = digs[((x)>>4)&0xf]; |
97 | | |
98 | | /* Here's an example |
99 | | %3A6C6480004E56FFFC4E717063B0AEFFFC6D0652AEFFFC60F24E5E4E75 |
100 | | %1B3709T_SEGMENT1108FFFFFFFF |
101 | | %2B3AB9T_SEGMENT7Dgcc_compiled$1087hello$c10 |
102 | | %373829T_SEGMENT80int$t1$r1$$214741080char$t2$r2$0$12710 |
103 | | %373769T_SEGMENT80long$int$t3$r1$$1080unsigned$int$t4$10 |
104 | | %373CA9T_SEGMENT80long$unsigned$in1080short$int$t6$r1$10 |
105 | | %373049T_SEGMENT80long$long$int$t71080short$unsigned$i10 |
106 | | %373A29T_SEGMENT80long$long$unsign1080signed$char$t10$10 |
107 | | %373D69T_SEGMENT80unsigned$char$t11080float$t12$r1$4$010 |
108 | | %373D19T_SEGMENT80double$t13$r1$8$1080long$double$t14$10 |
109 | | %2734D9T_SEGMENT8Bvoid$t15$151035_main10 |
110 | | %2F3CA9T_SEGMENT81$1081$1681$1E81$21487main$F110 |
111 | | %2832F9T_SEGMENT83i$18FFFFFFFC81$1481$214 |
112 | | %07 8 10 10 |
113 | | |
114 | | explanation: |
115 | | %3A6C6480004E56FFFC4E717063B0AEFFFC6D0652AEFFFC60F24E5E4E75 |
116 | | ^ ^^ ^ ^-data |
117 | | | || +------ 4 char integer 0x8000 |
118 | | | |+-------- checksum |
119 | | | +--------- type 6 (data record) |
120 | | +----------- length 3a chars |
121 | | <---------------------- 3a (58 chars) -------------------> |
122 | | |
123 | | %1B3709T_SEGMENT1108FFFFFFFF |
124 | | ^ ^^ ^- 8 character integer 0xffffffff |
125 | | | |+- 1 character integer 0 |
126 | | | +-- type 1 symbol (section definition) |
127 | | +------------ 9 char symbol T_SEGMENT |
128 | | |
129 | | %2B3AB9T_SEGMENT7Dgcc_compiled$1087hello$c10 |
130 | | %373829T_SEGMENT80int$t1$r1$$214741080char$t2$r2$0$12710 |
131 | | %373769T_SEGMENT80long$int$t3$r1$$1080unsigned$int$t4$10 |
132 | | %373CA9T_SEGMENT80long$unsigned$in1080short$int$t6$r1$10 |
133 | | %373049T_SEGMENT80long$long$int$t71080short$unsigned$i10 |
134 | | %373A29T_SEGMENT80long$long$unsign1080signed$char$t10$10 |
135 | | %373D69T_SEGMENT80unsigned$char$t11080float$t12$r1$4$010 |
136 | | %373D19T_SEGMENT80double$t13$r1$8$1080long$double$t14$10 |
137 | | %2734D9T_SEGMENT8Bvoid$t15$151035_main10 |
138 | | %2F3CA9T_SEGMENT81$1081$1681$1E81$21487main$F110 |
139 | | %2832F9T_SEGMENT83i$18FFFFFFFC81$1481$214 |
140 | | %0781010 |
141 | | |
142 | | Turns into |
143 | | sac@thepub$ ./objdump -dx -m m68k f |
144 | | |
145 | | f: file format tekhex |
146 | | -----x--- 9/55728 -134219416 Sep 29 15:13 1995 f |
147 | | architecture: UNKNOWN!, flags 0x00000010: |
148 | | HAS_SYMS |
149 | | start address 0x00000000 |
150 | | SECTION 0 [D00000000] : size 00020000 vma 00000000 align 2**0 |
151 | | ALLOC, LOAD |
152 | | SECTION 1 [D00008000] : size 00002001 vma 00008000 align 2**0 |
153 | | |
154 | | SECTION 2 [T_SEGMENT] : size ffffffff vma 00000000 align 2**0 |
155 | | |
156 | | SYMBOL TABLE: |
157 | | 00000000 g T_SEGMENT gcc_compiled$ |
158 | | 00000000 g T_SEGMENT hello$c |
159 | | 00000000 g T_SEGMENT int$t1$r1$$21474 |
160 | | 00000000 g T_SEGMENT char$t2$r2$0$127 |
161 | | 00000000 g T_SEGMENT long$int$t3$r1$$ |
162 | | 00000000 g T_SEGMENT unsigned$int$t4$ |
163 | | 00000000 g T_SEGMENT long$unsigned$in |
164 | | 00000000 g T_SEGMENT short$int$t6$r1$ |
165 | | 00000000 g T_SEGMENT long$long$int$t7 |
166 | | 00000000 g T_SEGMENT short$unsigned$i |
167 | | 00000000 g T_SEGMENT long$long$unsign |
168 | | 00000000 g T_SEGMENT signed$char$t10$ |
169 | | 00000000 g T_SEGMENT unsigned$char$t1 |
170 | | 00000000 g T_SEGMENT float$t12$r1$4$0 |
171 | | 00000000 g T_SEGMENT double$t13$r1$8$ |
172 | | 00000000 g T_SEGMENT long$double$t14$ |
173 | | 00000000 g T_SEGMENT void$t15$15 |
174 | | 00000000 g T_SEGMENT _main |
175 | | 00000000 g T_SEGMENT $ |
176 | | 00000000 g T_SEGMENT $ |
177 | | 00000000 g T_SEGMENT $ |
178 | | 00000010 g T_SEGMENT $ |
179 | | 00000000 g T_SEGMENT main$F1 |
180 | | fcffffff g T_SEGMENT i$1 |
181 | | 00000000 g T_SEGMENT $ |
182 | | 00000010 g T_SEGMENT $ |
183 | | |
184 | | RELOCATION RECORDS FOR [D00000000]: (none) |
185 | | |
186 | | RELOCATION RECORDS FOR [D00008000]: (none) |
187 | | |
188 | | RELOCATION RECORDS FOR [T_SEGMENT]: (none) |
189 | | |
190 | | Disassembly of section D00000000: |
191 | | ... |
192 | | 00008000 ($+)7ff0 linkw fp,#-4 |
193 | | 00008004 ($+)7ff4 nop |
194 | | 00008006 ($+)7ff6 movel #99,d0 |
195 | | 00008008 ($+)7ff8 cmpl fp@(-4),d0 |
196 | | 0000800c ($+)7ffc blts 00008014 ($+)8004 |
197 | | 0000800e ($+)7ffe addql #1,fp@(-4) |
198 | | 00008012 ($+)8002 bras 00008006 ($+)7ff6 |
199 | | 00008014 ($+)8004 unlk fp |
200 | | 00008016 ($+)8006 rts |
201 | | ... */ |
202 | | |
203 | | static void |
204 | | tekhex_init (void) |
205 | 3.41M | { |
206 | 3.41M | unsigned int i; |
207 | 3.41M | static bool inited = false; |
208 | 3.41M | int val; |
209 | | |
210 | 3.41M | if (! inited) |
211 | 11 | { |
212 | 11 | inited = true; |
213 | 11 | hex_init (); |
214 | 11 | val = 0; |
215 | 121 | for (i = 0; i < 10; i++) |
216 | 110 | sum_block[i + '0'] = val++; |
217 | | |
218 | 297 | for (i = 'A'; i <= 'Z'; i++) |
219 | 286 | sum_block[i] = val++; |
220 | | |
221 | 11 | sum_block['$'] = val++; |
222 | 11 | sum_block['%'] = val++; |
223 | 11 | sum_block['.'] = val++; |
224 | 11 | sum_block['_'] = val++; |
225 | 297 | for (i = 'a'; i <= 'z'; i++) |
226 | 286 | sum_block[i] = val++; |
227 | 11 | } |
228 | 3.41M | } |
229 | | |
230 | | /* The maximum number of bytes on a line is FF. */ |
231 | 286k | #define MAXCHUNK 0xff |
232 | | /* The number of bytes we fit onto a line on output. */ |
233 | | #define CHUNK 21 |
234 | | |
235 | | /* We cannot output our tekhexords as we see them, we have to glue them |
236 | | together, this is done in this structure : */ |
237 | | |
238 | | struct tekhex_data_list_struct |
239 | | { |
240 | | unsigned char *data; |
241 | | bfd_vma where; |
242 | | bfd_size_type size; |
243 | | struct tekhex_data_list_struct *next; |
244 | | |
245 | | }; |
246 | | typedef struct tekhex_data_list_struct tekhex_data_list_type; |
247 | | |
248 | 561k | #define CHUNK_MASK 0x1fff |
249 | 184k | #define CHUNK_SPAN 32 |
250 | | |
251 | | struct data_struct |
252 | | { |
253 | | unsigned char chunk_data[CHUNK_MASK + 1]; |
254 | | unsigned char chunk_init[(CHUNK_MASK + 1 + CHUNK_SPAN - 1) / CHUNK_SPAN]; |
255 | | bfd_vma vma; |
256 | | struct data_struct *next; |
257 | | }; |
258 | | |
259 | | typedef struct tekhex_data_struct |
260 | | { |
261 | | tekhex_data_list_type *head; |
262 | | unsigned int type; |
263 | | struct tekhex_symbol_struct *symbols; |
264 | | struct data_struct *data; |
265 | | } tdata_type; |
266 | | |
267 | | #define enda(x) (x->vma + x->size) |
268 | | |
269 | | static bool |
270 | | getvalue (char **srcp, bfd_vma *valuep, char * endp) |
271 | 660k | { |
272 | 660k | char *src = *srcp; |
273 | 660k | bfd_vma value = 0; |
274 | 660k | unsigned int len; |
275 | | |
276 | 660k | if (src >= endp) |
277 | 775 | return false; |
278 | | |
279 | 659k | if (!ISHEX (*src)) |
280 | 3.40k | return false; |
281 | | |
282 | 655k | len = hex_value (*src++); |
283 | 655k | if (len == 0) |
284 | 35.7k | len = 16; |
285 | 3.05M | while (len-- && src < endp) |
286 | 2.40M | { |
287 | 2.40M | if (!ISHEX (*src)) |
288 | 4.51k | return false; |
289 | 2.39M | value = value << 4 | hex_value (*src++); |
290 | 2.39M | } |
291 | | |
292 | 651k | *srcp = src; |
293 | 651k | *valuep = value; |
294 | 651k | return len == -1U; |
295 | 655k | } |
296 | | |
297 | | static bool |
298 | | getsym (char *dstp, char **srcp, unsigned int *lenp, char * endp) |
299 | 652k | { |
300 | 652k | char *src = *srcp; |
301 | 652k | unsigned int i; |
302 | 652k | unsigned int len; |
303 | | |
304 | 652k | if (!ISHEX (*src)) |
305 | 1.40k | return false; |
306 | | |
307 | 650k | len = hex_value (*src++); |
308 | 650k | if (len == 0) |
309 | 111k | len = 16; |
310 | 4.68M | for (i = 0; i < len && (src + i) < endp; i++) |
311 | 4.03M | dstp[i] = src[i]; |
312 | 650k | dstp[i] = 0; |
313 | 650k | *srcp = src + i; |
314 | 650k | *lenp = len; |
315 | 650k | return i == len; |
316 | 652k | } |
317 | | |
318 | | static struct data_struct * |
319 | | find_chunk (bfd *abfd, bfd_vma vma, bool create) |
320 | 186k | { |
321 | 186k | struct data_struct *d = abfd->tdata.tekhex_data->data; |
322 | | |
323 | 186k | vma &= ~CHUNK_MASK; |
324 | 248k | while (d && (d->vma) != vma) |
325 | 62.4k | d = d->next; |
326 | | |
327 | 186k | if (!d && create) |
328 | 20.8k | { |
329 | | /* No chunk for this address, so make one up. */ |
330 | 20.8k | d = bfd_zalloc (abfd, sizeof (struct data_struct)); |
331 | 20.8k | if (!d) |
332 | 0 | return NULL; |
333 | | |
334 | 20.8k | d->next = abfd->tdata.tekhex_data->data; |
335 | 20.8k | d->vma = vma; |
336 | 20.8k | abfd->tdata.tekhex_data->data = d; |
337 | 20.8k | } |
338 | 186k | return d; |
339 | 186k | } |
340 | | |
341 | | static bool |
342 | | insert_byte (bfd *abfd, int value, bfd_vma addr) |
343 | 202k | { |
344 | 202k | if (value != 0) |
345 | 184k | { |
346 | | /* Find the chunk that this byte needs and put it in. */ |
347 | 184k | struct data_struct *d = find_chunk (abfd, addr, true); |
348 | 184k | if (!d) |
349 | 0 | return false; |
350 | | |
351 | 184k | d->chunk_data[addr & CHUNK_MASK] = value; |
352 | 184k | d->chunk_init[(addr & CHUNK_MASK) / CHUNK_SPAN] = 1; |
353 | 184k | } |
354 | 202k | return true; |
355 | 202k | } |
356 | | |
357 | | /* The first pass is to find the names of all the sections, and see |
358 | | how big the data is. */ |
359 | | |
360 | | static bool |
361 | | first_phase (bfd *abfd, int type, char *src, char * src_end) |
362 | 285k | { |
363 | 285k | asection *section, *alt_section; |
364 | 285k | unsigned int len; |
365 | 285k | bfd_vma addr; |
366 | 285k | bfd_vma val; |
367 | 285k | char sym[17]; /* A symbol can only be 16chars long. */ |
368 | | |
369 | 285k | switch (type) |
370 | 285k | { |
371 | 32.1k | case '6': |
372 | | /* Data record - read it and store it. */ |
373 | 32.1k | if (!getvalue (&src, &addr, src_end)) |
374 | 1.19k | return false; |
375 | | |
376 | 233k | while (*src && src < src_end - 1) |
377 | 202k | { |
378 | 202k | if (!insert_byte (abfd, HEX (src), addr)) |
379 | 0 | return false; |
380 | 202k | src += 2; |
381 | 202k | addr++; |
382 | 202k | } |
383 | 31.0k | return true; |
384 | | |
385 | 174k | case '3': |
386 | | /* Symbol record, read the segment. */ |
387 | 174k | if (!getsym (sym, &src, &len, src_end)) |
388 | 433 | return false; |
389 | 174k | section = bfd_get_section_by_name (abfd, sym); |
390 | 174k | if (section == NULL) |
391 | 93.6k | { |
392 | 93.6k | char *n = (char *) bfd_alloc (abfd, (bfd_size_type) len + 1); |
393 | | |
394 | 93.6k | if (!n) |
395 | 0 | return false; |
396 | 93.6k | memcpy (n, sym, len + 1); |
397 | 93.6k | section = bfd_make_section_old_way (abfd, n); |
398 | 93.6k | if (section == NULL) |
399 | 0 | return false; |
400 | 93.6k | } |
401 | 174k | alt_section = NULL; |
402 | 718k | while (src < src_end && *src) |
403 | 555k | { |
404 | 555k | switch (*src) |
405 | 555k | { |
406 | 76.6k | case '1': /* Section range. */ |
407 | 76.6k | src++; |
408 | 76.6k | if (!getvalue (&src, &addr, src_end)) |
409 | 1.41k | return false; |
410 | 75.2k | if (!getvalue (&src, &val, src_end)) |
411 | 1.79k | return false; |
412 | 73.4k | if (bfd_is_const_section (section)) |
413 | 4.43k | break; |
414 | 68.9k | section->vma = addr; |
415 | 68.9k | if (val < addr) |
416 | 28.8k | val = addr; |
417 | 68.9k | section->size = val - addr; |
418 | | /* PR 17512: file: objdump-s-endless-loop.tekhex. |
419 | | Check for overlarge section sizes. */ |
420 | 68.9k | if (section->size & 0x80000000) |
421 | 628 | return false; |
422 | 68.3k | section->flags = SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC; |
423 | 68.3k | break; |
424 | 42.4k | case '0': |
425 | 50.4k | case '2': |
426 | 239k | case '3': |
427 | 261k | case '4': |
428 | 303k | case '6': |
429 | 348k | case '7': |
430 | 477k | case '8': |
431 | | /* Symbols, add to section. */ |
432 | 477k | { |
433 | 477k | size_t amt = sizeof (tekhex_symbol_type); |
434 | 477k | tekhex_symbol_type *new_symbol = (tekhex_symbol_type *) |
435 | 477k | bfd_alloc (abfd, amt); |
436 | 477k | char stype = (*src); |
437 | | |
438 | 477k | if (!new_symbol) |
439 | 0 | return false; |
440 | 477k | new_symbol->symbol.the_bfd = abfd; |
441 | 477k | src++; |
442 | 477k | abfd->symcount++; |
443 | 477k | abfd->flags |= HAS_SYMS; |
444 | 477k | new_symbol->prev = abfd->tdata.tekhex_data->symbols; |
445 | 477k | abfd->tdata.tekhex_data->symbols = new_symbol; |
446 | 477k | if (!getsym (sym, &src, &len, src_end)) |
447 | 1.37k | return false; |
448 | 475k | new_symbol->symbol.name = (const char *) |
449 | 475k | bfd_alloc (abfd, (bfd_size_type) len + 1); |
450 | 475k | if (!new_symbol->symbol.name) |
451 | 0 | return false; |
452 | 475k | memcpy ((char *) (new_symbol->symbol.name), sym, len + 1); |
453 | 475k | new_symbol->symbol.section = section; |
454 | 475k | if (stype <= '4') |
455 | 260k | new_symbol->symbol.flags = (BSF_GLOBAL | BSF_EXPORT); |
456 | 215k | else |
457 | 215k | new_symbol->symbol.flags = BSF_LOCAL; |
458 | 475k | if (stype == '2' || stype == '6') |
459 | 49.0k | new_symbol->symbol.section = bfd_abs_section_ptr; |
460 | 426k | else if (bfd_is_const_section (section)) |
461 | 12.0k | ; |
462 | 414k | else if (stype == '3' || stype == '7') |
463 | 228k | { |
464 | 228k | if ((section->flags & SEC_DATA) == 0) |
465 | 190k | section->flags |= SEC_CODE; |
466 | 37.8k | else |
467 | 37.8k | { |
468 | 37.8k | if (alt_section == NULL) |
469 | 22.9k | alt_section |
470 | 22.9k | = bfd_get_next_section_by_name (NULL, section); |
471 | 37.8k | if (alt_section == NULL) |
472 | 13.6k | alt_section = bfd_make_section_anyway_with_flags |
473 | 13.6k | (abfd, section->name, |
474 | 13.6k | (section->flags & ~SEC_DATA) | SEC_CODE); |
475 | 37.8k | if (alt_section == NULL) |
476 | 0 | return false; |
477 | 37.8k | new_symbol->symbol.section = alt_section; |
478 | 37.8k | } |
479 | 228k | } |
480 | 186k | else if (stype == '4' || stype == '8') |
481 | 147k | { |
482 | 147k | if ((section->flags & SEC_CODE) == 0) |
483 | 48.1k | section->flags |= SEC_DATA; |
484 | 99.4k | else |
485 | 99.4k | { |
486 | 99.4k | if (alt_section == NULL) |
487 | 75.5k | alt_section |
488 | 75.5k | = bfd_get_next_section_by_name (NULL, section); |
489 | 99.4k | if (alt_section == NULL) |
490 | 26.2k | alt_section = bfd_make_section_anyway_with_flags |
491 | 26.2k | (abfd, section->name, |
492 | 26.2k | (section->flags & ~SEC_CODE) | SEC_DATA); |
493 | 99.4k | if (alt_section == NULL) |
494 | 0 | return false; |
495 | 99.4k | new_symbol->symbol.section = alt_section; |
496 | 99.4k | } |
497 | 147k | } |
498 | 475k | if (!getvalue (&src, &val, src_end)) |
499 | 4.39k | return false; |
500 | 471k | new_symbol->symbol.value = val - section->vma; |
501 | 471k | break; |
502 | 475k | } |
503 | 1.62k | default: |
504 | 1.62k | return false; |
505 | 555k | } |
506 | 555k | } |
507 | 285k | } |
508 | | |
509 | 241k | return true; |
510 | 285k | } |
511 | | |
512 | | /* Pass over a tekhex, calling one of the above functions on each |
513 | | record. */ |
514 | | |
515 | | static bool |
516 | | pass_over (bfd *abfd, bool (*func) (bfd *, int, char *, char *)) |
517 | 75.5k | { |
518 | 75.5k | unsigned int chars_on_line; |
519 | 75.5k | bool is_eof = false; |
520 | | |
521 | | /* To the front of the file. */ |
522 | 75.5k | if (bfd_seek (abfd, 0, SEEK_SET) != 0) |
523 | 0 | return false; |
524 | | |
525 | 348k | while (! is_eof) |
526 | 348k | { |
527 | 348k | char src[MAXCHUNK]; |
528 | 348k | char type; |
529 | | |
530 | | /* Find first '%'. */ |
531 | 348k | is_eof = bfd_read (src, 1, abfd) != 1; |
532 | 20.4M | while (!is_eof && *src != '%') |
533 | 20.1M | is_eof = bfd_read (src, 1, abfd) != 1; |
534 | | |
535 | 348k | if (is_eof) |
536 | 54.3k | break; |
537 | | |
538 | | /* Fetch the type and the length and the checksum. */ |
539 | 293k | if (bfd_read (src, 5, abfd) != 5) |
540 | 781 | return false; |
541 | | |
542 | 292k | type = src[2]; |
543 | | |
544 | 292k | if (!ISHEX (src[0]) || !ISHEX (src[1])) |
545 | 6.17k | break; |
546 | | |
547 | | /* Already read five chars. */ |
548 | 286k | chars_on_line = HEX (src) - 5; |
549 | | |
550 | 286k | if (chars_on_line >= MAXCHUNK) |
551 | 429 | return false; |
552 | | |
553 | 286k | if (bfd_read (src, chars_on_line, abfd) != chars_on_line) |
554 | 928 | return false; |
555 | | |
556 | | /* Put a null at the end. */ |
557 | 285k | src[chars_on_line] = 0; |
558 | 285k | if (!func (abfd, type, src, src + chars_on_line)) |
559 | 12.8k | return false; |
560 | 285k | } |
561 | | |
562 | 60.5k | return true; |
563 | 75.5k | } |
564 | | |
565 | | static long |
566 | | tekhex_canonicalize_symtab (bfd *abfd, asymbol **table) |
567 | 269 | { |
568 | 269 | tekhex_symbol_type *p = abfd->tdata.tekhex_data->symbols; |
569 | 269 | unsigned int c = bfd_get_symcount (abfd); |
570 | | |
571 | 269 | table[c] = 0; |
572 | 20.1k | while (p) |
573 | 19.8k | { |
574 | 19.8k | table[--c] = &(p->symbol); |
575 | 19.8k | p = p->prev; |
576 | 19.8k | } |
577 | | |
578 | 269 | return bfd_get_symcount (abfd); |
579 | 269 | } |
580 | | |
581 | | static long |
582 | | tekhex_get_symtab_upper_bound (bfd *abfd) |
583 | 269 | { |
584 | 269 | return (abfd->symcount + 1) * (sizeof (struct tekhex_asymbol_struct *)); |
585 | | |
586 | 269 | } |
587 | | |
588 | | static bool |
589 | | tekhex_mkobject (bfd *abfd) |
590 | 75.5k | { |
591 | 75.5k | tdata_type *tdata; |
592 | | |
593 | 75.5k | tdata = (tdata_type *) bfd_alloc (abfd, (bfd_size_type) sizeof (tdata_type)); |
594 | 75.5k | if (!tdata) |
595 | 0 | return false; |
596 | 75.5k | abfd->tdata.tekhex_data = tdata; |
597 | 75.5k | tdata->type = 1; |
598 | 75.5k | tdata->head = NULL; |
599 | 75.5k | tdata->symbols = NULL; |
600 | 75.5k | tdata->data = NULL; |
601 | 75.5k | return true; |
602 | 75.5k | } |
603 | | |
604 | | /* Return TRUE if the file looks like it's in TekHex format. Just look |
605 | | for a percent sign and some hex digits. */ |
606 | | |
607 | | static bfd_cleanup |
608 | | tekhex_object_p (bfd *abfd) |
609 | 3.41M | { |
610 | 3.41M | char b[4]; |
611 | | |
612 | 3.41M | tekhex_init (); |
613 | | |
614 | 3.41M | if (bfd_seek (abfd, 0, SEEK_SET) != 0 |
615 | 3.41M | || bfd_read (b, 4, abfd) != 4) |
616 | 3.74k | return NULL; |
617 | | |
618 | 3.40M | if (b[0] != '%' || !ISHEX (b[1]) || !ISHEX (b[2]) || !ISHEX (b[3])) |
619 | 3.33M | return NULL; |
620 | | |
621 | 75.5k | if (!tekhex_mkobject (abfd)) |
622 | 0 | return NULL; |
623 | | |
624 | 75.5k | if (!pass_over (abfd, first_phase)) |
625 | 14.9k | { |
626 | 14.9k | bfd_release (abfd, abfd->tdata.tekhex_data); |
627 | 14.9k | return NULL; |
628 | 14.9k | } |
629 | | |
630 | 60.5k | return _bfd_no_cleanup; |
631 | 75.5k | } |
632 | | |
633 | | static bool |
634 | | move_section_contents (bfd *abfd, |
635 | | asection *section, |
636 | | const void * locationp, |
637 | | file_ptr offset, |
638 | | bfd_size_type count, |
639 | | bool get) |
640 | 1.95k | { |
641 | 1.95k | bfd_vma addr; |
642 | 1.95k | char *location = (char *) locationp; |
643 | 1.95k | bfd_vma prev_number = 1; /* Nothing can have this as a high bit. */ |
644 | 1.95k | struct data_struct *d = NULL; |
645 | | |
646 | 1.95k | BFD_ASSERT (offset == 0); |
647 | 3.14k | for (addr = section->vma; count != 0; count--, addr++) |
648 | 2.98k | { |
649 | | /* Get high bits of address. */ |
650 | 2.98k | bfd_vma chunk_number = addr & ~(bfd_vma) CHUNK_MASK; |
651 | 2.98k | bfd_vma low_bits = addr & CHUNK_MASK; |
652 | 2.98k | bool must_write = !get && *location != 0; |
653 | | |
654 | 2.98k | if (chunk_number != prev_number || (!d && must_write)) |
655 | 1.95k | { |
656 | | /* Different chunk, so move pointer. */ |
657 | 1.95k | d = find_chunk (abfd, chunk_number, must_write); |
658 | 1.95k | if (!d) |
659 | 1.80k | return false; |
660 | 153 | prev_number = chunk_number; |
661 | 153 | } |
662 | | |
663 | 1.18k | if (get) |
664 | 1.18k | { |
665 | 1.18k | if (d) |
666 | 1.18k | *location = d->chunk_data[low_bits]; |
667 | 0 | else |
668 | 0 | *location = 0; |
669 | 1.18k | } |
670 | 0 | else if (must_write) |
671 | 0 | { |
672 | 0 | d->chunk_data[low_bits] = *location; |
673 | 0 | d->chunk_init[low_bits / CHUNK_SPAN] = 1; |
674 | 0 | } |
675 | | |
676 | 1.18k | location++; |
677 | 1.18k | } |
678 | 153 | return true; |
679 | 1.95k | } |
680 | | |
681 | | static bool |
682 | | tekhex_get_section_contents (bfd *abfd, |
683 | | asection *section, |
684 | | void *location, |
685 | | file_ptr offset, |
686 | | bfd_size_type count) |
687 | 1.95k | { |
688 | 1.95k | if ((section->flags & (SEC_LOAD | SEC_ALLOC)) == 0) |
689 | 0 | return false; |
690 | 1.95k | return move_section_contents (abfd, section, location, offset, count, true); |
691 | 1.95k | } |
692 | | |
693 | | static bool |
694 | | tekhex_set_arch_mach (bfd *abfd, |
695 | | enum bfd_architecture arch, |
696 | | unsigned long machine) |
697 | 8 | { |
698 | | /* Ignore errors about unknown architecture. */ |
699 | 8 | return (bfd_default_set_arch_mach (abfd, arch, machine) |
700 | 8 | || arch == bfd_arch_unknown); |
701 | 8 | } |
702 | | |
703 | | /* We have to save up all the Tekhexords for a splurge before output. */ |
704 | | |
705 | | static bool |
706 | | tekhex_set_section_contents (bfd *abfd, |
707 | | sec_ptr section, |
708 | | const void *location, |
709 | | file_ptr offset, |
710 | | bfd_size_type count) |
711 | 0 | { |
712 | 0 | if ((section->flags & (SEC_LOAD | SEC_ALLOC)) == 0) |
713 | 0 | return false; |
714 | 0 | return move_section_contents (abfd, section, location, offset, count, false); |
715 | 0 | } |
716 | | |
717 | | static void |
718 | | writevalue (char **dst, bfd_vma value) |
719 | 2.80k | { |
720 | 2.80k | char *p = *dst; |
721 | 2.80k | int len; |
722 | 2.80k | int shift; |
723 | | |
724 | 37.8k | for (len = BFD_ARCH_SIZE / 4, shift = len * 4 - 4; len > 1; shift -= 4, len--) |
725 | 37.7k | if ((value >> shift) & 0xf) |
726 | 2.70k | break; |
727 | | |
728 | 2.80k | *p++ = digs[len & 0xf]; |
729 | 12.5k | for (; len; shift -= 4, len--) |
730 | 9.79k | *p++ = digs[(value >> shift) & 0xf]; |
731 | 2.80k | *dst = p; |
732 | 2.80k | } |
733 | | |
734 | | static void |
735 | | writesym (char **dst, const char *sym) |
736 | 5.47k | { |
737 | 5.47k | char *p = *dst; |
738 | 5.47k | int len = (sym ? strlen (sym) : 0); |
739 | | |
740 | 5.47k | if (len >= 16) |
741 | 0 | len = 16; |
742 | 5.47k | else if (len == 0) |
743 | 672 | { |
744 | 672 | len = 1; |
745 | 672 | sym = "$"; |
746 | 672 | } |
747 | | |
748 | 5.47k | *p++ = digs[len & 0xf]; |
749 | 36.3k | while (len--) |
750 | 30.8k | *p++ = *sym++; |
751 | | |
752 | 5.47k | *dst = p; |
753 | 5.47k | } |
754 | | |
755 | | static void |
756 | | out (bfd *abfd, int type, char *start, char *end) |
757 | 2.75k | { |
758 | 2.75k | int sum = 0; |
759 | 2.75k | char *s; |
760 | 2.75k | char front[6]; |
761 | 2.75k | bfd_size_type wrlen; |
762 | | |
763 | 2.75k | front[0] = '%'; |
764 | 2.75k | TOHEX (front + 1, end - start + 5); |
765 | 2.75k | front[3] = type; |
766 | | |
767 | 54.2k | for (s = start; s < end; s++) |
768 | 51.4k | sum += sum_block[(unsigned char) *s]; |
769 | | |
770 | 2.75k | sum += sum_block[(unsigned char) front[1]]; /* Length. */ |
771 | 2.75k | sum += sum_block[(unsigned char) front[2]]; |
772 | 2.75k | sum += sum_block[(unsigned char) front[3]]; /* Type. */ |
773 | 2.75k | TOHEX (front + 4, sum); |
774 | 2.75k | if (bfd_write (front, 6, abfd) != 6) |
775 | 0 | abort (); |
776 | 2.75k | end[0] = '\n'; |
777 | 2.75k | wrlen = end - start + 1; |
778 | 2.75k | if (bfd_write (start, wrlen, abfd) != wrlen) |
779 | 0 | abort (); |
780 | 2.75k | } |
781 | | |
782 | | static bool |
783 | | tekhex_write_object_contents (bfd *abfd) |
784 | 8 | { |
785 | 8 | char buffer[100]; |
786 | 8 | asymbol **p; |
787 | 8 | asection *s; |
788 | 8 | struct data_struct *d; |
789 | | |
790 | 8 | tekhex_init (); |
791 | | |
792 | | /* And the raw data. */ |
793 | 8 | for (d = abfd->tdata.tekhex_data->data; |
794 | 8 | d != NULL; |
795 | 8 | d = d->next) |
796 | 0 | { |
797 | 0 | int low; |
798 | 0 | int addr; |
799 | | |
800 | | /* Write it in blocks of 32 bytes. */ |
801 | 0 | for (addr = 0; addr < CHUNK_MASK + 1; addr += CHUNK_SPAN) |
802 | 0 | { |
803 | 0 | if (d->chunk_init[addr / CHUNK_SPAN]) |
804 | 0 | { |
805 | 0 | char *dst = buffer; |
806 | |
|
807 | 0 | writevalue (&dst, addr + d->vma); |
808 | 0 | for (low = 0; low < CHUNK_SPAN; low++) |
809 | 0 | { |
810 | 0 | TOHEX (dst, d->chunk_data[addr + low]); |
811 | 0 | dst += 2; |
812 | 0 | } |
813 | 0 | out (abfd, '6', buffer, dst); |
814 | 0 | } |
815 | 0 | } |
816 | 0 | } |
817 | | |
818 | | /* Write all the section headers for the sections. */ |
819 | 51 | for (s = abfd->sections; s != NULL; s = s->next) |
820 | 43 | { |
821 | 43 | char *dst = buffer; |
822 | | |
823 | 43 | writesym (&dst, s->name); |
824 | 43 | *dst++ = '1'; |
825 | 43 | writevalue (&dst, s->vma); |
826 | 43 | writevalue (&dst, s->vma + s->size); |
827 | 43 | out (abfd, '3', buffer, dst); |
828 | 43 | } |
829 | | |
830 | | /* And the symbols. */ |
831 | 8 | if (abfd->outsymbols) |
832 | 8 | { |
833 | 2.72k | for (p = abfd->outsymbols; *p; p++) |
834 | 2.71k | { |
835 | 2.71k | int section_code = bfd_decode_symclass (*p); |
836 | | |
837 | 2.71k | if (section_code != '?') |
838 | 2.71k | { |
839 | | /* Do not include debug symbols. */ |
840 | 2.71k | asymbol *sym = *p; |
841 | 2.71k | char *dst = buffer; |
842 | | |
843 | 2.71k | writesym (&dst, sym->section->name); |
844 | | |
845 | 2.71k | switch (section_code) |
846 | 2.71k | { |
847 | 7 | case 'A': |
848 | 7 | *dst++ = '2'; |
849 | 7 | break; |
850 | 20 | case 'a': |
851 | 20 | *dst++ = '6'; |
852 | 20 | break; |
853 | 389 | case 'D': |
854 | 389 | case 'B': |
855 | 389 | case 'O': |
856 | 389 | *dst++ = '4'; |
857 | 389 | break; |
858 | 486 | case 'd': |
859 | 486 | case 'b': |
860 | 486 | case 'o': |
861 | 486 | *dst++ = '8'; |
862 | 486 | break; |
863 | 1.42k | case 'T': |
864 | 1.42k | *dst++ = '3'; |
865 | 1.42k | break; |
866 | 220 | case 't': |
867 | 220 | *dst++ = '7'; |
868 | 220 | break; |
869 | 0 | case 'C': |
870 | 0 | case 'U': |
871 | 0 | bfd_set_error (bfd_error_wrong_format); |
872 | 0 | goto fail; |
873 | 2.71k | } |
874 | | |
875 | 2.71k | writesym (&dst, sym->name); |
876 | 2.71k | writevalue (&dst, sym->value + sym->section->vma); |
877 | 2.71k | out (abfd, '3', buffer, dst); |
878 | 2.71k | } |
879 | 2.71k | } |
880 | 8 | } |
881 | | |
882 | | /* And the terminator. */ |
883 | 8 | if (bfd_write ("%0781010\n", 9, abfd) != 9) |
884 | 0 | goto fail; |
885 | 8 | return true; |
886 | | |
887 | 0 | fail: |
888 | 0 | return false; |
889 | 8 | } |
890 | | |
891 | | static int |
892 | | tekhex_sizeof_headers (bfd *abfd ATTRIBUTE_UNUSED, |
893 | | struct bfd_link_info *info ATTRIBUTE_UNUSED) |
894 | 0 | { |
895 | 0 | return 0; |
896 | 0 | } |
897 | | |
898 | | static asymbol * |
899 | | tekhex_make_empty_symbol (bfd *abfd) |
900 | 114k | { |
901 | 114k | size_t amt = sizeof (struct tekhex_symbol_struct); |
902 | 114k | tekhex_symbol_type *new_symbol = (tekhex_symbol_type *) bfd_zalloc (abfd, |
903 | 114k | amt); |
904 | | |
905 | 114k | if (!new_symbol) |
906 | 0 | return NULL; |
907 | 114k | new_symbol->symbol.the_bfd = abfd; |
908 | 114k | new_symbol->prev = NULL; |
909 | 114k | return &(new_symbol->symbol); |
910 | 114k | } |
911 | | |
912 | | static void |
913 | | tekhex_get_symbol_info (bfd *abfd ATTRIBUTE_UNUSED, |
914 | | asymbol *symbol, |
915 | | symbol_info *ret) |
916 | 7.08k | { |
917 | 7.08k | bfd_symbol_info (symbol, ret); |
918 | 7.08k | } |
919 | | |
920 | | static void |
921 | | tekhex_print_symbol (bfd *abfd, |
922 | | void * filep, |
923 | | asymbol *symbol, |
924 | | bfd_print_symbol_type how) |
925 | 0 | { |
926 | 0 | FILE *file = (FILE *) filep; |
927 | |
|
928 | 0 | switch (how) |
929 | 0 | { |
930 | 0 | case bfd_print_symbol_name: |
931 | 0 | fprintf (file, "%s", symbol->name); |
932 | 0 | break; |
933 | 0 | case bfd_print_symbol_more: |
934 | 0 | break; |
935 | | |
936 | 0 | case bfd_print_symbol_all: |
937 | 0 | { |
938 | 0 | const char *section_name = symbol->section->name; |
939 | |
|
940 | 0 | bfd_print_symbol_vandf (abfd, (void *) file, symbol); |
941 | |
|
942 | 0 | fprintf (file, " %-5s %s", |
943 | 0 | section_name, symbol->name); |
944 | 0 | } |
945 | 0 | } |
946 | 0 | } |
947 | | |
948 | | #define tekhex_close_and_cleanup _bfd_generic_close_and_cleanup |
949 | | #define tekhex_bfd_free_cached_info _bfd_generic_bfd_free_cached_info |
950 | | #define tekhex_new_section_hook _bfd_generic_new_section_hook |
951 | | #define tekhex_bfd_is_target_special_symbol _bfd_bool_bfd_asymbol_false |
952 | | #define tekhex_bfd_is_local_label_name bfd_generic_is_local_label_name |
953 | | #define tekhex_get_lineno _bfd_nosymbols_get_lineno |
954 | | #define tekhex_find_nearest_line _bfd_nosymbols_find_nearest_line |
955 | | #define tekhex_find_nearest_line_with_alt _bfd_nosymbols_find_nearest_line_with_alt |
956 | | #define tekhex_find_line _bfd_nosymbols_find_line |
957 | | #define tekhex_find_inliner_info _bfd_nosymbols_find_inliner_info |
958 | | #define tekhex_get_symbol_version_string _bfd_nosymbols_get_symbol_version_string |
959 | | #define tekhex_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol |
960 | | #define tekhex_read_minisymbols _bfd_generic_read_minisymbols |
961 | | #define tekhex_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol |
962 | | #define tekhex_bfd_get_relocated_section_contents bfd_generic_get_relocated_section_contents |
963 | | #define tekhex_bfd_relax_section bfd_generic_relax_section |
964 | | #define tekhex_bfd_gc_sections bfd_generic_gc_sections |
965 | | #define tekhex_bfd_lookup_section_flags bfd_generic_lookup_section_flags |
966 | | #define tekhex_bfd_merge_sections bfd_generic_merge_sections |
967 | | #define tekhex_bfd_is_group_section bfd_generic_is_group_section |
968 | | #define tekhex_bfd_group_name bfd_generic_group_name |
969 | | #define tekhex_bfd_discard_group bfd_generic_discard_group |
970 | | #define tekhex_section_already_linked _bfd_generic_section_already_linked |
971 | | #define tekhex_bfd_define_common_symbol bfd_generic_define_common_symbol |
972 | | #define tekhex_bfd_link_hide_symbol _bfd_generic_link_hide_symbol |
973 | | #define tekhex_bfd_define_start_stop bfd_generic_define_start_stop |
974 | | #define tekhex_bfd_link_hash_table_create _bfd_generic_link_hash_table_create |
975 | | #define tekhex_bfd_link_add_symbols _bfd_generic_link_add_symbols |
976 | | #define tekhex_bfd_link_just_syms _bfd_generic_link_just_syms |
977 | | #define tekhex_bfd_copy_link_hash_symbol_type _bfd_generic_copy_link_hash_symbol_type |
978 | | #define tekhex_bfd_final_link _bfd_generic_final_link |
979 | | #define tekhex_bfd_link_split_section _bfd_generic_link_split_section |
980 | | #define tekhex_bfd_link_check_relocs _bfd_generic_link_check_relocs |
981 | | |
982 | | const bfd_target tekhex_vec = |
983 | | { |
984 | | "tekhex", /* Name. */ |
985 | | bfd_target_tekhex_flavour, |
986 | | BFD_ENDIAN_UNKNOWN, /* Target byte order. */ |
987 | | BFD_ENDIAN_UNKNOWN, /* Target headers byte order. */ |
988 | | EXEC_P | HAS_SYMS, /* Object flags. */ |
989 | | (SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS |
990 | | | SEC_ALLOC | SEC_LOAD), /* Section flags. */ |
991 | | 0, /* Leading underscore. */ |
992 | | ' ', /* AR_pad_char. */ |
993 | | 16, /* AR_max_namelen. */ |
994 | | 0, /* match priority. */ |
995 | | TARGET_KEEP_UNUSED_SECTION_SYMBOLS, /* keep unused section symbols. */ |
996 | | bfd_getb64, bfd_getb_signed_64, bfd_putb64, |
997 | | bfd_getb32, bfd_getb_signed_32, bfd_putb32, |
998 | | bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* Data. */ |
999 | | bfd_getb64, bfd_getb_signed_64, bfd_putb64, |
1000 | | bfd_getb32, bfd_getb_signed_32, bfd_putb32, |
1001 | | bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* Headers. */ |
1002 | | |
1003 | | { |
1004 | | _bfd_dummy_target, |
1005 | | tekhex_object_p, /* bfd_check_format. */ |
1006 | | _bfd_dummy_target, |
1007 | | _bfd_dummy_target, |
1008 | | }, |
1009 | | { |
1010 | | _bfd_bool_bfd_false_error, |
1011 | | tekhex_mkobject, |
1012 | | _bfd_bool_bfd_false_error, |
1013 | | _bfd_bool_bfd_false_error, |
1014 | | }, |
1015 | | { /* bfd_write_contents. */ |
1016 | | _bfd_bool_bfd_false_error, |
1017 | | tekhex_write_object_contents, |
1018 | | _bfd_bool_bfd_false_error, |
1019 | | _bfd_bool_bfd_false_error, |
1020 | | }, |
1021 | | |
1022 | | BFD_JUMP_TABLE_GENERIC (tekhex), |
1023 | | BFD_JUMP_TABLE_COPY (_bfd_generic), |
1024 | | BFD_JUMP_TABLE_CORE (_bfd_nocore), |
1025 | | BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), |
1026 | | BFD_JUMP_TABLE_SYMBOLS (tekhex), |
1027 | | BFD_JUMP_TABLE_RELOCS (_bfd_norelocs), |
1028 | | BFD_JUMP_TABLE_WRITE (tekhex), |
1029 | | BFD_JUMP_TABLE_LINK (tekhex), |
1030 | | BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), |
1031 | | |
1032 | | NULL, |
1033 | | |
1034 | | NULL |
1035 | | }; |