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