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