tekhex.c revision 1.1
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
75typedef struct
76{
77  bfd_vma low;
78  bfd_vma high;
79} addr_range_type;
80
81typedef struct tekhex_symbol_struct
82{
83  asymbol symbol;
84  struct tekhex_symbol_struct *prev;
85} tekhex_symbol_type;
86
87static const char digs[] = "0123456789ABCDEF";
88
89static 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
204static void
205tekhex_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
239struct 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};
247typedef struct tekhex_data_list_struct tekhex_data_list_type;
248
249#define CHUNK_MASK 0x1fff
250
251struct 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
259typedef 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
269static bfd_boolean
270getvalue (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
294static bfd_boolean
295getsym (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
315static struct data_struct *
316find_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
340static void
341insert_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
353static bfd_boolean
354first_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
460static bfd_boolean
461pass_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
510static long
511tekhex_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
526static long
527tekhex_get_symtab_upper_bound (bfd *abfd)
528{
529  return (abfd->symcount + 1) * (sizeof (struct tekhex_asymbol_struct *));
530
531}
532
533static bfd_boolean
534tekhex_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
552static const bfd_target *
553tekhex_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
574static void
575move_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
615static bfd_boolean
616tekhex_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
631static bfd_boolean
632tekhex_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
641static bfd_boolean
642tekhex_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
676static void
677writevalue (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
704static void
705writesym (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
733static void
734out (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
760static bfd_boolean
761tekhex_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
875static int
876tekhex_sizeof_headers (bfd *abfd ATTRIBUTE_UNUSED,
877		       struct bfd_link_info *info ATTRIBUTE_UNUSED)
878{
879  return 0;
880}
881
882static asymbol *
883tekhex_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
896static void
897tekhex_get_symbol_info (bfd *abfd ATTRIBUTE_UNUSED,
898			asymbol *symbol,
899			symbol_info *ret)
900{
901  bfd_symbol_info (symbol, ret);
902}
903
904static void
905tekhex_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
962const 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