/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-2023 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 | 0 | #define NIBBLE(x) hex_value(x) |
92 | 0 | #define HEX(buffer) ((NIBBLE ((buffer)[0]) << 4) + NIBBLE ((buffer)[1])) |
93 | 0 | #define ISHEX(x) hex_p(x) |
94 | | #define TOHEX(d, x) \ |
95 | 0 | (d)[1] = digs[(x) & 0xf]; \ |
96 | 0 | (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 | 0 | { |
206 | 0 | unsigned int i; |
207 | 0 | static bool inited = false; |
208 | 0 | int val; |
209 | |
|
210 | 0 | if (! inited) |
211 | 0 | { |
212 | 0 | inited = true; |
213 | 0 | hex_init (); |
214 | 0 | val = 0; |
215 | 0 | for (i = 0; i < 10; i++) |
216 | 0 | sum_block[i + '0'] = val++; |
217 | |
|
218 | 0 | for (i = 'A'; i <= 'Z'; i++) |
219 | 0 | sum_block[i] = val++; |
220 | |
|
221 | 0 | sum_block['$'] = val++; |
222 | 0 | sum_block['%'] = val++; |
223 | 0 | sum_block['.'] = val++; |
224 | 0 | sum_block['_'] = val++; |
225 | 0 | for (i = 'a'; i <= 'z'; i++) |
226 | 0 | sum_block[i] = val++; |
227 | 0 | } |
228 | 0 | } |
229 | | |
230 | | /* The maximum number of bytes on a line is FF. */ |
231 | 0 | #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 | 0 | #define CHUNK_MASK 0x1fff |
249 | 0 | #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 | 0 | { |
272 | 0 | char *src = *srcp; |
273 | 0 | bfd_vma value = 0; |
274 | 0 | unsigned int len; |
275 | |
|
276 | 0 | if (src >= endp) |
277 | 0 | return false; |
278 | | |
279 | 0 | if (!ISHEX (*src)) |
280 | 0 | return false; |
281 | | |
282 | 0 | len = hex_value (*src++); |
283 | 0 | if (len == 0) |
284 | 0 | len = 16; |
285 | 0 | while (len-- && src < endp) |
286 | 0 | { |
287 | 0 | if (!ISHEX (*src)) |
288 | 0 | return false; |
289 | 0 | value = value << 4 | hex_value (*src++); |
290 | 0 | } |
291 | | |
292 | 0 | *srcp = src; |
293 | 0 | *valuep = value; |
294 | 0 | return len == -1U; |
295 | 0 | } |
296 | | |
297 | | static bool |
298 | | getsym (char *dstp, char **srcp, unsigned int *lenp, char * endp) |
299 | 0 | { |
300 | 0 | char *src = *srcp; |
301 | 0 | unsigned int i; |
302 | 0 | unsigned int len; |
303 | |
|
304 | 0 | if (!ISHEX (*src)) |
305 | 0 | return false; |
306 | | |
307 | 0 | len = hex_value (*src++); |
308 | 0 | if (len == 0) |
309 | 0 | len = 16; |
310 | 0 | for (i = 0; i < len && (src + i) < endp; i++) |
311 | 0 | dstp[i] = src[i]; |
312 | 0 | dstp[i] = 0; |
313 | 0 | *srcp = src + i; |
314 | 0 | *lenp = len; |
315 | 0 | return i == len; |
316 | 0 | } |
317 | | |
318 | | static struct data_struct * |
319 | | find_chunk (bfd *abfd, bfd_vma vma, bool create) |
320 | 0 | { |
321 | 0 | struct data_struct *d = abfd->tdata.tekhex_data->data; |
322 | |
|
323 | 0 | vma &= ~CHUNK_MASK; |
324 | 0 | while (d && (d->vma) != vma) |
325 | 0 | d = d->next; |
326 | |
|
327 | 0 | if (!d && create) |
328 | 0 | { |
329 | | /* No chunk for this address, so make one up. */ |
330 | 0 | d = (struct data_struct *) |
331 | 0 | bfd_zalloc (abfd, (bfd_size_type) sizeof (struct data_struct)); |
332 | |
|
333 | 0 | if (!d) |
334 | 0 | return NULL; |
335 | | |
336 | 0 | d->next = abfd->tdata.tekhex_data->data; |
337 | 0 | d->vma = vma; |
338 | 0 | abfd->tdata.tekhex_data->data = d; |
339 | 0 | } |
340 | 0 | return d; |
341 | 0 | } |
342 | | |
343 | | static void |
344 | | insert_byte (bfd *abfd, int value, bfd_vma addr) |
345 | 0 | { |
346 | 0 | if (value != 0) |
347 | 0 | { |
348 | | /* Find the chunk that this byte needs and put it in. */ |
349 | 0 | struct data_struct *d = find_chunk (abfd, addr, true); |
350 | |
|
351 | 0 | d->chunk_data[addr & CHUNK_MASK] = value; |
352 | 0 | d->chunk_init[(addr & CHUNK_MASK) / CHUNK_SPAN] = 1; |
353 | 0 | } |
354 | 0 | } |
355 | | |
356 | | /* The first pass is to find the names of all the sections, and see |
357 | | how big the data is. */ |
358 | | |
359 | | static bool |
360 | | first_phase (bfd *abfd, int type, char *src, char * src_end) |
361 | 0 | { |
362 | 0 | asection *section, *alt_section; |
363 | 0 | unsigned int len; |
364 | 0 | bfd_vma val; |
365 | 0 | char sym[17]; /* A symbol can only be 16chars long. */ |
366 | |
|
367 | 0 | switch (type) |
368 | 0 | { |
369 | 0 | case '6': |
370 | | /* Data record - read it and store it. */ |
371 | 0 | { |
372 | 0 | bfd_vma addr; |
373 | |
|
374 | 0 | if (!getvalue (&src, &addr, src_end)) |
375 | 0 | return false; |
376 | | |
377 | 0 | while (*src && src < src_end - 1) |
378 | 0 | { |
379 | 0 | insert_byte (abfd, HEX (src), addr); |
380 | 0 | src += 2; |
381 | 0 | addr++; |
382 | 0 | } |
383 | 0 | return true; |
384 | 0 | } |
385 | | |
386 | 0 | case '3': |
387 | | /* Symbol record, read the segment. */ |
388 | 0 | if (!getsym (sym, &src, &len, src_end)) |
389 | 0 | return false; |
390 | 0 | section = bfd_get_section_by_name (abfd, sym); |
391 | 0 | if (section == NULL) |
392 | 0 | { |
393 | 0 | char *n = (char *) bfd_alloc (abfd, (bfd_size_type) len + 1); |
394 | |
|
395 | 0 | if (!n) |
396 | 0 | return false; |
397 | 0 | memcpy (n, sym, len + 1); |
398 | 0 | section = bfd_make_section (abfd, n); |
399 | 0 | if (section == NULL) |
400 | 0 | return false; |
401 | 0 | } |
402 | 0 | alt_section = NULL; |
403 | 0 | while (src < src_end && *src) |
404 | 0 | { |
405 | 0 | switch (*src) |
406 | 0 | { |
407 | 0 | case '1': /* Section range. */ |
408 | 0 | src++; |
409 | 0 | if (!getvalue (&src, §ion->vma, src_end)) |
410 | 0 | return false; |
411 | 0 | if (!getvalue (&src, &val, src_end)) |
412 | 0 | return false; |
413 | 0 | if (val < section->vma) |
414 | 0 | val = section->vma; |
415 | 0 | section->size = val - section->vma; |
416 | | /* PR 17512: file: objdump-s-endless-loop.tekhex. |
417 | | Check for overlarge section sizes. */ |
418 | 0 | if (section->size & 0x80000000) |
419 | 0 | return false; |
420 | 0 | section->flags = SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC; |
421 | 0 | break; |
422 | 0 | case '0': |
423 | 0 | case '2': |
424 | 0 | case '3': |
425 | 0 | case '4': |
426 | 0 | case '6': |
427 | 0 | case '7': |
428 | 0 | case '8': |
429 | | /* Symbols, add to section. */ |
430 | 0 | { |
431 | 0 | size_t amt = sizeof (tekhex_symbol_type); |
432 | 0 | tekhex_symbol_type *new_symbol = (tekhex_symbol_type *) |
433 | 0 | bfd_alloc (abfd, amt); |
434 | 0 | char stype = (*src); |
435 | |
|
436 | 0 | if (!new_symbol) |
437 | 0 | return false; |
438 | 0 | new_symbol->symbol.the_bfd = abfd; |
439 | 0 | src++; |
440 | 0 | abfd->symcount++; |
441 | 0 | abfd->flags |= HAS_SYMS; |
442 | 0 | new_symbol->prev = abfd->tdata.tekhex_data->symbols; |
443 | 0 | abfd->tdata.tekhex_data->symbols = new_symbol; |
444 | 0 | if (!getsym (sym, &src, &len, src_end)) |
445 | 0 | return false; |
446 | 0 | new_symbol->symbol.name = (const char *) |
447 | 0 | bfd_alloc (abfd, (bfd_size_type) len + 1); |
448 | 0 | if (!new_symbol->symbol.name) |
449 | 0 | return false; |
450 | 0 | memcpy ((char *) (new_symbol->symbol.name), sym, len + 1); |
451 | 0 | new_symbol->symbol.section = section; |
452 | 0 | if (stype <= '4') |
453 | 0 | new_symbol->symbol.flags = (BSF_GLOBAL | BSF_EXPORT); |
454 | 0 | else |
455 | 0 | new_symbol->symbol.flags = BSF_LOCAL; |
456 | 0 | if (stype == '2' || stype == '6') |
457 | 0 | new_symbol->symbol.section = bfd_abs_section_ptr; |
458 | 0 | else if (stype == '3' || stype == '7') |
459 | 0 | { |
460 | 0 | if ((section->flags & SEC_DATA) == 0) |
461 | 0 | section->flags |= SEC_CODE; |
462 | 0 | else |
463 | 0 | { |
464 | 0 | if (alt_section == NULL) |
465 | 0 | alt_section |
466 | 0 | = bfd_get_next_section_by_name (NULL, section); |
467 | 0 | if (alt_section == NULL) |
468 | 0 | alt_section = bfd_make_section_anyway_with_flags |
469 | 0 | (abfd, section->name, |
470 | 0 | (section->flags & ~SEC_DATA) | SEC_CODE); |
471 | 0 | if (alt_section == NULL) |
472 | 0 | return false; |
473 | 0 | new_symbol->symbol.section = alt_section; |
474 | 0 | } |
475 | 0 | } |
476 | 0 | else if (stype == '4' || stype == '8') |
477 | 0 | { |
478 | 0 | if ((section->flags & SEC_CODE) == 0) |
479 | 0 | section->flags |= SEC_DATA; |
480 | 0 | else |
481 | 0 | { |
482 | 0 | if (alt_section == NULL) |
483 | 0 | alt_section |
484 | 0 | = bfd_get_next_section_by_name (NULL, section); |
485 | 0 | if (alt_section == NULL) |
486 | 0 | alt_section = bfd_make_section_anyway_with_flags |
487 | 0 | (abfd, section->name, |
488 | 0 | (section->flags & ~SEC_CODE) | SEC_DATA); |
489 | 0 | if (alt_section == NULL) |
490 | 0 | return false; |
491 | 0 | new_symbol->symbol.section = alt_section; |
492 | 0 | } |
493 | 0 | } |
494 | 0 | if (!getvalue (&src, &val, src_end)) |
495 | 0 | return false; |
496 | 0 | new_symbol->symbol.value = val - section->vma; |
497 | 0 | break; |
498 | 0 | } |
499 | 0 | default: |
500 | 0 | return false; |
501 | 0 | } |
502 | 0 | } |
503 | 0 | } |
504 | | |
505 | 0 | return true; |
506 | 0 | } |
507 | | |
508 | | /* Pass over a tekhex, calling one of the above functions on each |
509 | | record. */ |
510 | | |
511 | | static bool |
512 | | pass_over (bfd *abfd, bool (*func) (bfd *, int, char *, char *)) |
513 | 0 | { |
514 | 0 | unsigned int chars_on_line; |
515 | 0 | bool is_eof = false; |
516 | | |
517 | | /* To the front of the file. */ |
518 | 0 | if (bfd_seek (abfd, 0, SEEK_SET) != 0) |
519 | 0 | return false; |
520 | | |
521 | 0 | while (! is_eof) |
522 | 0 | { |
523 | 0 | char src[MAXCHUNK]; |
524 | 0 | char type; |
525 | | |
526 | | /* Find first '%'. */ |
527 | 0 | is_eof = bfd_read (src, 1, abfd) != 1; |
528 | 0 | while (!is_eof && *src != '%') |
529 | 0 | is_eof = bfd_read (src, 1, abfd) != 1; |
530 | |
|
531 | 0 | if (is_eof) |
532 | 0 | break; |
533 | | |
534 | | /* Fetch the type and the length and the checksum. */ |
535 | 0 | if (bfd_read (src, 5, abfd) != 5) |
536 | 0 | return false; |
537 | | |
538 | 0 | type = src[2]; |
539 | |
|
540 | 0 | if (!ISHEX (src[0]) || !ISHEX (src[1])) |
541 | 0 | break; |
542 | | |
543 | | /* Already read five chars. */ |
544 | 0 | chars_on_line = HEX (src) - 5; |
545 | |
|
546 | 0 | if (chars_on_line >= MAXCHUNK) |
547 | 0 | return false; |
548 | | |
549 | 0 | if (bfd_read (src, chars_on_line, abfd) != chars_on_line) |
550 | 0 | return false; |
551 | | |
552 | | /* Put a null at the end. */ |
553 | 0 | src[chars_on_line] = 0; |
554 | 0 | if (!func (abfd, type, src, src + chars_on_line)) |
555 | 0 | return false; |
556 | 0 | } |
557 | | |
558 | 0 | return true; |
559 | 0 | } |
560 | | |
561 | | static long |
562 | | tekhex_canonicalize_symtab (bfd *abfd, asymbol **table) |
563 | 0 | { |
564 | 0 | tekhex_symbol_type *p = abfd->tdata.tekhex_data->symbols; |
565 | 0 | unsigned int c = bfd_get_symcount (abfd); |
566 | |
|
567 | 0 | table[c] = 0; |
568 | 0 | while (p) |
569 | 0 | { |
570 | 0 | table[--c] = &(p->symbol); |
571 | 0 | p = p->prev; |
572 | 0 | } |
573 | |
|
574 | 0 | return bfd_get_symcount (abfd); |
575 | 0 | } |
576 | | |
577 | | static long |
578 | | tekhex_get_symtab_upper_bound (bfd *abfd) |
579 | 0 | { |
580 | 0 | return (abfd->symcount + 1) * (sizeof (struct tekhex_asymbol_struct *)); |
581 | |
|
582 | 0 | } |
583 | | |
584 | | static bool |
585 | | tekhex_mkobject (bfd *abfd) |
586 | 0 | { |
587 | 0 | tdata_type *tdata; |
588 | |
|
589 | 0 | tdata = (tdata_type *) bfd_alloc (abfd, (bfd_size_type) sizeof (tdata_type)); |
590 | 0 | if (!tdata) |
591 | 0 | return false; |
592 | 0 | abfd->tdata.tekhex_data = tdata; |
593 | 0 | tdata->type = 1; |
594 | 0 | tdata->head = NULL; |
595 | 0 | tdata->symbols = NULL; |
596 | 0 | tdata->data = NULL; |
597 | 0 | return true; |
598 | 0 | } |
599 | | |
600 | | /* Return TRUE if the file looks like it's in TekHex format. Just look |
601 | | for a percent sign and some hex digits. */ |
602 | | |
603 | | static bfd_cleanup |
604 | | tekhex_object_p (bfd *abfd) |
605 | 0 | { |
606 | 0 | char b[4]; |
607 | |
|
608 | 0 | tekhex_init (); |
609 | |
|
610 | 0 | if (bfd_seek (abfd, 0, SEEK_SET) != 0 |
611 | 0 | || bfd_read (b, 4, abfd) != 4) |
612 | 0 | return NULL; |
613 | | |
614 | 0 | if (b[0] != '%' || !ISHEX (b[1]) || !ISHEX (b[2]) || !ISHEX (b[3])) |
615 | 0 | return NULL; |
616 | | |
617 | 0 | tekhex_mkobject (abfd); |
618 | |
|
619 | 0 | if (!pass_over (abfd, first_phase)) |
620 | 0 | return NULL; |
621 | | |
622 | 0 | return _bfd_no_cleanup; |
623 | 0 | } |
624 | | |
625 | | static void |
626 | | move_section_contents (bfd *abfd, |
627 | | asection *section, |
628 | | const void * locationp, |
629 | | file_ptr offset, |
630 | | bfd_size_type count, |
631 | | bool get) |
632 | 0 | { |
633 | 0 | bfd_vma addr; |
634 | 0 | char *location = (char *) locationp; |
635 | 0 | bfd_vma prev_number = 1; /* Nothing can have this as a high bit. */ |
636 | 0 | struct data_struct *d = NULL; |
637 | |
|
638 | 0 | BFD_ASSERT (offset == 0); |
639 | 0 | for (addr = section->vma; count != 0; count--, addr++) |
640 | 0 | { |
641 | | /* Get high bits of address. */ |
642 | 0 | bfd_vma chunk_number = addr & ~(bfd_vma) CHUNK_MASK; |
643 | 0 | bfd_vma low_bits = addr & CHUNK_MASK; |
644 | 0 | bool must_write = !get && *location != 0; |
645 | |
|
646 | 0 | if (chunk_number != prev_number || (!d && must_write)) |
647 | 0 | { |
648 | | /* Different chunk, so move pointer. */ |
649 | 0 | d = find_chunk (abfd, chunk_number, must_write); |
650 | 0 | prev_number = chunk_number; |
651 | 0 | } |
652 | |
|
653 | 0 | if (get) |
654 | 0 | { |
655 | 0 | if (d) |
656 | 0 | *location = d->chunk_data[low_bits]; |
657 | 0 | else |
658 | 0 | *location = 0; |
659 | 0 | } |
660 | 0 | else if (must_write) |
661 | 0 | { |
662 | 0 | d->chunk_data[low_bits] = *location; |
663 | 0 | d->chunk_init[low_bits / CHUNK_SPAN] = 1; |
664 | 0 | } |
665 | |
|
666 | 0 | location++; |
667 | 0 | } |
668 | 0 | } |
669 | | |
670 | | static bool |
671 | | tekhex_get_section_contents (bfd *abfd, |
672 | | asection *section, |
673 | | void * locationp, |
674 | | file_ptr offset, |
675 | | bfd_size_type count) |
676 | 0 | { |
677 | 0 | if (section->flags & (SEC_LOAD | SEC_ALLOC)) |
678 | 0 | { |
679 | 0 | move_section_contents (abfd, section, locationp, offset, count, true); |
680 | 0 | return true; |
681 | 0 | } |
682 | | |
683 | 0 | return false; |
684 | 0 | } |
685 | | |
686 | | static bool |
687 | | tekhex_set_arch_mach (bfd *abfd, |
688 | | enum bfd_architecture arch, |
689 | | unsigned long machine) |
690 | 0 | { |
691 | | /* Ignore errors about unknown architecture. */ |
692 | 0 | return (bfd_default_set_arch_mach (abfd, arch, machine) |
693 | 0 | || arch == bfd_arch_unknown); |
694 | 0 | } |
695 | | |
696 | | /* We have to save up all the Tekhexords for a splurge before output. */ |
697 | | |
698 | | static bool |
699 | | tekhex_set_section_contents (bfd *abfd, |
700 | | sec_ptr section, |
701 | | const void * locationp, |
702 | | file_ptr offset, |
703 | | bfd_size_type bytes_to_do) |
704 | 0 | { |
705 | 0 | if (section->flags & (SEC_LOAD | SEC_ALLOC)) |
706 | 0 | { |
707 | 0 | move_section_contents (abfd, section, locationp, offset, bytes_to_do, |
708 | 0 | false); |
709 | 0 | return true; |
710 | 0 | } |
711 | | |
712 | 0 | return false; |
713 | 0 | } |
714 | | |
715 | | static void |
716 | | writevalue (char **dst, bfd_vma value) |
717 | 0 | { |
718 | 0 | char *p = *dst; |
719 | 0 | int len; |
720 | 0 | int shift; |
721 | |
|
722 | 0 | for (len = 8, shift = 28; shift; shift -= 4, len--) |
723 | 0 | { |
724 | 0 | if ((value >> shift) & 0xf) |
725 | 0 | { |
726 | 0 | *p++ = len + '0'; |
727 | 0 | while (len) |
728 | 0 | { |
729 | 0 | *p++ = digs[(value >> shift) & 0xf]; |
730 | 0 | shift -= 4; |
731 | 0 | len--; |
732 | 0 | } |
733 | 0 | *dst = p; |
734 | 0 | return; |
735 | |
|
736 | 0 | } |
737 | 0 | } |
738 | 0 | *p++ = '1'; |
739 | 0 | *p++ = '0'; |
740 | 0 | *dst = p; |
741 | 0 | } |
742 | | |
743 | | static void |
744 | | writesym (char **dst, const char *sym) |
745 | 0 | { |
746 | 0 | char *p = *dst; |
747 | 0 | int len = (sym ? strlen (sym) : 0); |
748 | |
|
749 | 0 | if (len >= 16) |
750 | 0 | { |
751 | 0 | *p++ = '0'; |
752 | 0 | len = 16; |
753 | 0 | } |
754 | 0 | else |
755 | 0 | { |
756 | 0 | if (len == 0) |
757 | 0 | { |
758 | 0 | *p++ = '1'; |
759 | 0 | sym = "$"; |
760 | 0 | len = 1; |
761 | 0 | } |
762 | 0 | else |
763 | 0 | *p++ = digs[len]; |
764 | 0 | } |
765 | |
|
766 | 0 | while (len--) |
767 | 0 | *p++ = *sym++; |
768 | |
|
769 | 0 | *dst = p; |
770 | 0 | } |
771 | | |
772 | | static void |
773 | | out (bfd *abfd, int type, char *start, char *end) |
774 | 0 | { |
775 | 0 | int sum = 0; |
776 | 0 | char *s; |
777 | 0 | char front[6]; |
778 | 0 | bfd_size_type wrlen; |
779 | |
|
780 | 0 | front[0] = '%'; |
781 | 0 | TOHEX (front + 1, end - start + 5); |
782 | 0 | front[3] = type; |
783 | |
|
784 | 0 | for (s = start; s < end; s++) |
785 | 0 | sum += sum_block[(unsigned char) *s]; |
786 | |
|
787 | 0 | sum += sum_block[(unsigned char) front[1]]; /* Length. */ |
788 | 0 | sum += sum_block[(unsigned char) front[2]]; |
789 | 0 | sum += sum_block[(unsigned char) front[3]]; /* Type. */ |
790 | 0 | TOHEX (front + 4, sum); |
791 | 0 | if (bfd_write (front, 6, abfd) != 6) |
792 | 0 | abort (); |
793 | 0 | end[0] = '\n'; |
794 | 0 | wrlen = end - start + 1; |
795 | 0 | if (bfd_write (start, wrlen, abfd) != wrlen) |
796 | 0 | abort (); |
797 | 0 | } |
798 | | |
799 | | static bool |
800 | | tekhex_write_object_contents (bfd *abfd) |
801 | 0 | { |
802 | 0 | char buffer[100]; |
803 | 0 | asymbol **p; |
804 | 0 | asection *s; |
805 | 0 | struct data_struct *d; |
806 | |
|
807 | 0 | tekhex_init (); |
808 | | |
809 | | /* And the raw data. */ |
810 | 0 | for (d = abfd->tdata.tekhex_data->data; |
811 | 0 | d != NULL; |
812 | 0 | d = d->next) |
813 | 0 | { |
814 | 0 | int low; |
815 | 0 | int addr; |
816 | | |
817 | | /* Write it in blocks of 32 bytes. */ |
818 | 0 | for (addr = 0; addr < CHUNK_MASK + 1; addr += CHUNK_SPAN) |
819 | 0 | { |
820 | 0 | if (d->chunk_init[addr / CHUNK_SPAN]) |
821 | 0 | { |
822 | 0 | char *dst = buffer; |
823 | |
|
824 | 0 | writevalue (&dst, addr + d->vma); |
825 | 0 | for (low = 0; low < CHUNK_SPAN; low++) |
826 | 0 | { |
827 | 0 | TOHEX (dst, d->chunk_data[addr + low]); |
828 | 0 | dst += 2; |
829 | 0 | } |
830 | 0 | out (abfd, '6', buffer, dst); |
831 | 0 | } |
832 | 0 | } |
833 | 0 | } |
834 | | |
835 | | /* Write all the section headers for the sections. */ |
836 | 0 | for (s = abfd->sections; s != NULL; s = s->next) |
837 | 0 | { |
838 | 0 | char *dst = buffer; |
839 | |
|
840 | 0 | writesym (&dst, s->name); |
841 | 0 | *dst++ = '1'; |
842 | 0 | writevalue (&dst, s->vma); |
843 | 0 | writevalue (&dst, s->vma + s->size); |
844 | 0 | out (abfd, '3', buffer, dst); |
845 | 0 | } |
846 | | |
847 | | /* And the symbols. */ |
848 | 0 | if (abfd->outsymbols) |
849 | 0 | { |
850 | 0 | for (p = abfd->outsymbols; *p; p++) |
851 | 0 | { |
852 | 0 | int section_code = bfd_decode_symclass (*p); |
853 | |
|
854 | 0 | if (section_code != '?') |
855 | 0 | { |
856 | | /* Do not include debug symbols. */ |
857 | 0 | asymbol *sym = *p; |
858 | 0 | char *dst = buffer; |
859 | |
|
860 | 0 | writesym (&dst, sym->section->name); |
861 | |
|
862 | 0 | switch (section_code) |
863 | 0 | { |
864 | 0 | case 'A': |
865 | 0 | *dst++ = '2'; |
866 | 0 | break; |
867 | 0 | case 'a': |
868 | 0 | *dst++ = '6'; |
869 | 0 | break; |
870 | 0 | case 'D': |
871 | 0 | case 'B': |
872 | 0 | case 'O': |
873 | 0 | *dst++ = '4'; |
874 | 0 | break; |
875 | 0 | case 'd': |
876 | 0 | case 'b': |
877 | 0 | case 'o': |
878 | 0 | *dst++ = '8'; |
879 | 0 | break; |
880 | 0 | case 'T': |
881 | 0 | *dst++ = '3'; |
882 | 0 | break; |
883 | 0 | case 't': |
884 | 0 | *dst++ = '7'; |
885 | 0 | break; |
886 | 0 | case 'C': |
887 | 0 | case 'U': |
888 | 0 | bfd_set_error (bfd_error_wrong_format); |
889 | 0 | return false; |
890 | 0 | } |
891 | | |
892 | 0 | writesym (&dst, sym->name); |
893 | 0 | writevalue (&dst, sym->value + sym->section->vma); |
894 | 0 | out (abfd, '3', buffer, dst); |
895 | 0 | } |
896 | 0 | } |
897 | 0 | } |
898 | | |
899 | | /* And the terminator. */ |
900 | 0 | if (bfd_write ("%0781010\n", 9, abfd) != 9) |
901 | 0 | abort (); |
902 | 0 | return true; |
903 | 0 | } |
904 | | |
905 | | static int |
906 | | tekhex_sizeof_headers (bfd *abfd ATTRIBUTE_UNUSED, |
907 | | struct bfd_link_info *info ATTRIBUTE_UNUSED) |
908 | 0 | { |
909 | 0 | return 0; |
910 | 0 | } |
911 | | |
912 | | static asymbol * |
913 | | tekhex_make_empty_symbol (bfd *abfd) |
914 | 0 | { |
915 | 0 | size_t amt = sizeof (struct tekhex_symbol_struct); |
916 | 0 | tekhex_symbol_type *new_symbol = (tekhex_symbol_type *) bfd_zalloc (abfd, |
917 | 0 | amt); |
918 | |
|
919 | 0 | if (!new_symbol) |
920 | 0 | return NULL; |
921 | 0 | new_symbol->symbol.the_bfd = abfd; |
922 | 0 | new_symbol->prev = NULL; |
923 | 0 | return &(new_symbol->symbol); |
924 | 0 | } |
925 | | |
926 | | static void |
927 | | tekhex_get_symbol_info (bfd *abfd ATTRIBUTE_UNUSED, |
928 | | asymbol *symbol, |
929 | | symbol_info *ret) |
930 | 0 | { |
931 | 0 | bfd_symbol_info (symbol, ret); |
932 | 0 | } |
933 | | |
934 | | static void |
935 | | tekhex_print_symbol (bfd *abfd, |
936 | | void * filep, |
937 | | asymbol *symbol, |
938 | | bfd_print_symbol_type how) |
939 | 0 | { |
940 | 0 | FILE *file = (FILE *) filep; |
941 | |
|
942 | 0 | switch (how) |
943 | 0 | { |
944 | 0 | case bfd_print_symbol_name: |
945 | 0 | fprintf (file, "%s", symbol->name); |
946 | 0 | break; |
947 | 0 | case bfd_print_symbol_more: |
948 | 0 | break; |
949 | | |
950 | 0 | case bfd_print_symbol_all: |
951 | 0 | { |
952 | 0 | const char *section_name = symbol->section->name; |
953 | |
|
954 | 0 | bfd_print_symbol_vandf (abfd, (void *) file, symbol); |
955 | |
|
956 | 0 | fprintf (file, " %-5s %s", |
957 | 0 | section_name, symbol->name); |
958 | 0 | } |
959 | 0 | } |
960 | 0 | } |
961 | | |
962 | | #define tekhex_close_and_cleanup _bfd_generic_close_and_cleanup |
963 | | #define tekhex_bfd_free_cached_info _bfd_generic_bfd_free_cached_info |
964 | | #define tekhex_new_section_hook _bfd_generic_new_section_hook |
965 | | #define tekhex_bfd_is_target_special_symbol _bfd_bool_bfd_asymbol_false |
966 | | #define tekhex_bfd_is_local_label_name bfd_generic_is_local_label_name |
967 | | #define tekhex_get_lineno _bfd_nosymbols_get_lineno |
968 | | #define tekhex_find_nearest_line _bfd_nosymbols_find_nearest_line |
969 | | #define tekhex_find_nearest_line_with_alt _bfd_nosymbols_find_nearest_line_with_alt |
970 | | #define tekhex_find_line _bfd_nosymbols_find_line |
971 | | #define tekhex_find_inliner_info _bfd_nosymbols_find_inliner_info |
972 | | #define tekhex_get_symbol_version_string _bfd_nosymbols_get_symbol_version_string |
973 | | #define tekhex_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol |
974 | | #define tekhex_read_minisymbols _bfd_generic_read_minisymbols |
975 | | #define tekhex_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol |
976 | | #define tekhex_bfd_get_relocated_section_contents bfd_generic_get_relocated_section_contents |
977 | | #define tekhex_bfd_relax_section bfd_generic_relax_section |
978 | | #define tekhex_bfd_gc_sections bfd_generic_gc_sections |
979 | | #define tekhex_bfd_lookup_section_flags bfd_generic_lookup_section_flags |
980 | | #define tekhex_bfd_merge_sections bfd_generic_merge_sections |
981 | | #define tekhex_bfd_is_group_section bfd_generic_is_group_section |
982 | | #define tekhex_bfd_group_name bfd_generic_group_name |
983 | | #define tekhex_bfd_discard_group bfd_generic_discard_group |
984 | | #define tekhex_section_already_linked _bfd_generic_section_already_linked |
985 | | #define tekhex_bfd_define_common_symbol bfd_generic_define_common_symbol |
986 | | #define tekhex_bfd_link_hide_symbol _bfd_generic_link_hide_symbol |
987 | | #define tekhex_bfd_define_start_stop bfd_generic_define_start_stop |
988 | | #define tekhex_bfd_link_hash_table_create _bfd_generic_link_hash_table_create |
989 | | #define tekhex_bfd_link_add_symbols _bfd_generic_link_add_symbols |
990 | | #define tekhex_bfd_link_just_syms _bfd_generic_link_just_syms |
991 | | #define tekhex_bfd_copy_link_hash_symbol_type _bfd_generic_copy_link_hash_symbol_type |
992 | | #define tekhex_bfd_final_link _bfd_generic_final_link |
993 | | #define tekhex_bfd_link_split_section _bfd_generic_link_split_section |
994 | | #define tekhex_get_section_contents_in_window _bfd_generic_get_section_contents_in_window |
995 | | #define tekhex_bfd_link_check_relocs _bfd_generic_link_check_relocs |
996 | | |
997 | | const bfd_target tekhex_vec = |
998 | | { |
999 | | "tekhex", /* Name. */ |
1000 | | bfd_target_tekhex_flavour, |
1001 | | BFD_ENDIAN_UNKNOWN, /* Target byte order. */ |
1002 | | BFD_ENDIAN_UNKNOWN, /* Target headers byte order. */ |
1003 | | (EXEC_P | /* Object flags. */ |
1004 | | HAS_SYMS | HAS_LINENO | HAS_DEBUG | |
1005 | | HAS_RELOC | HAS_LOCALS | WP_TEXT | D_PAGED), |
1006 | | (SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS |
1007 | | | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* Section flags. */ |
1008 | | 0, /* Leading underscore. */ |
1009 | | ' ', /* AR_pad_char. */ |
1010 | | 16, /* AR_max_namelen. */ |
1011 | | 0, /* match priority. */ |
1012 | | TARGET_KEEP_UNUSED_SECTION_SYMBOLS, /* keep unused section symbols. */ |
1013 | | bfd_getb64, bfd_getb_signed_64, bfd_putb64, |
1014 | | bfd_getb32, bfd_getb_signed_32, bfd_putb32, |
1015 | | bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* Data. */ |
1016 | | bfd_getb64, bfd_getb_signed_64, bfd_putb64, |
1017 | | bfd_getb32, bfd_getb_signed_32, bfd_putb32, |
1018 | | bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* Headers. */ |
1019 | | |
1020 | | { |
1021 | | _bfd_dummy_target, |
1022 | | tekhex_object_p, /* bfd_check_format. */ |
1023 | | _bfd_dummy_target, |
1024 | | _bfd_dummy_target, |
1025 | | }, |
1026 | | { |
1027 | | _bfd_bool_bfd_false_error, |
1028 | | tekhex_mkobject, |
1029 | | _bfd_generic_mkarchive, |
1030 | | _bfd_bool_bfd_false_error, |
1031 | | }, |
1032 | | { /* bfd_write_contents. */ |
1033 | | _bfd_bool_bfd_false_error, |
1034 | | tekhex_write_object_contents, |
1035 | | _bfd_write_archive_contents, |
1036 | | _bfd_bool_bfd_false_error, |
1037 | | }, |
1038 | | |
1039 | | BFD_JUMP_TABLE_GENERIC (tekhex), |
1040 | | BFD_JUMP_TABLE_COPY (_bfd_generic), |
1041 | | BFD_JUMP_TABLE_CORE (_bfd_nocore), |
1042 | | BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), |
1043 | | BFD_JUMP_TABLE_SYMBOLS (tekhex), |
1044 | | BFD_JUMP_TABLE_RELOCS (_bfd_norelocs), |
1045 | | BFD_JUMP_TABLE_WRITE (tekhex), |
1046 | | BFD_JUMP_TABLE_LINK (tekhex), |
1047 | | BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), |
1048 | | |
1049 | | NULL, |
1050 | | |
1051 | | NULL |
1052 | | }; |