1/* BFD backend for Extended Tektronix Hex Format  objects.
2   Copyright (C) 1992-2024 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 bool 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 bool
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 (src >= endp)
277    return false;
278
279  if (!ISHEX (*src))
280    return false;
281
282  len = hex_value (*src++);
283  if (len == 0)
284    len = 16;
285  while (len-- && src < endp)
286    {
287      if (!ISHEX (*src))
288	return false;
289      value = value << 4 | hex_value (*src++);
290    }
291
292  *srcp = src;
293  *valuep = value;
294  return len == -1U;
295}
296
297static bool
298getsym (char *dstp, char **srcp, unsigned int *lenp, char * endp)
299{
300  char *src = *srcp;
301  unsigned int i;
302  unsigned int len;
303
304  if (!ISHEX (*src))
305    return false;
306
307  len = hex_value (*src++);
308  if (len == 0)
309    len = 16;
310  for (i = 0; i < len && (src + i) < endp; i++)
311    dstp[i] = src[i];
312  dstp[i] = 0;
313  *srcp = src + i;
314  *lenp = len;
315  return i == len;
316}
317
318static struct data_struct *
319find_chunk (bfd *abfd, bfd_vma vma, bool create)
320{
321  struct data_struct *d = abfd->tdata.tekhex_data->data;
322
323  vma &= ~CHUNK_MASK;
324  while (d && (d->vma) != vma)
325    d = d->next;
326
327  if (!d && create)
328    {
329      /* No chunk for this address, so make one up.  */
330      d = (struct data_struct *)
331	  bfd_zalloc (abfd, (bfd_size_type) sizeof (struct data_struct));
332
333      if (!d)
334	return NULL;
335
336      d->next = abfd->tdata.tekhex_data->data;
337      d->vma = vma;
338      abfd->tdata.tekhex_data->data = d;
339    }
340  return d;
341}
342
343static void
344insert_byte (bfd *abfd, int value, bfd_vma addr)
345{
346  if (value != 0)
347    {
348      /* Find the chunk that this byte needs and put it in.  */
349      struct data_struct *d = find_chunk (abfd, addr, true);
350
351      d->chunk_data[addr & CHUNK_MASK] = value;
352      d->chunk_init[(addr & CHUNK_MASK) / CHUNK_SPAN] = 1;
353    }
354}
355
356/* The first pass is to find the names of all the sections, and see
357  how big the data is.  */
358
359static bool
360first_phase (bfd *abfd, int type, char *src, char * src_end)
361{
362  asection *section, *alt_section;
363  unsigned int len;
364  bfd_vma val;
365  char sym[17];			/* A symbol can only be 16chars long.  */
366
367  switch (type)
368    {
369    case '6':
370      /* Data record - read it and store it.  */
371      {
372	bfd_vma addr;
373
374	if (!getvalue (&src, &addr, src_end))
375	  return false;
376
377	while (*src && src < src_end - 1)
378	  {
379	    insert_byte (abfd, HEX (src), addr);
380	    src += 2;
381	    addr++;
382	  }
383	return true;
384      }
385
386    case '3':
387      /* Symbol record, read the segment.  */
388      if (!getsym (sym, &src, &len, src_end))
389	return false;
390      section = bfd_get_section_by_name (abfd, sym);
391      if (section == NULL)
392	{
393	  char *n = (char *) bfd_alloc (abfd, (bfd_size_type) len + 1);
394
395	  if (!n)
396	    return false;
397	  memcpy (n, sym, len + 1);
398	  section = bfd_make_section (abfd, n);
399	  if (section == NULL)
400	    return false;
401	}
402      alt_section = NULL;
403      while (src < src_end && *src)
404	{
405	  switch (*src)
406	    {
407	    case '1':		/* Section range.  */
408	      src++;
409	      if (!getvalue (&src, &section->vma, src_end))
410		return false;
411	      if (!getvalue (&src, &val, src_end))
412		return false;
413	      if (val < section->vma)
414		val = section->vma;
415	      section->size = val - section->vma;
416	      /* PR 17512: file: objdump-s-endless-loop.tekhex.
417		 Check for overlarge section sizes.  */
418	      if (section->size & 0x80000000)
419		return false;
420	      section->flags = SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC;
421	      break;
422	    case '0':
423	    case '2':
424	    case '3':
425	    case '4':
426	    case '6':
427	    case '7':
428	    case '8':
429	      /* Symbols, add to section.  */
430	      {
431		size_t amt = sizeof (tekhex_symbol_type);
432		tekhex_symbol_type *new_symbol = (tekhex_symbol_type *)
433		    bfd_alloc (abfd, amt);
434		char stype = (*src);
435
436		if (!new_symbol)
437		  return false;
438		new_symbol->symbol.the_bfd = abfd;
439		src++;
440		abfd->symcount++;
441		abfd->flags |= HAS_SYMS;
442		new_symbol->prev = abfd->tdata.tekhex_data->symbols;
443		abfd->tdata.tekhex_data->symbols = new_symbol;
444		if (!getsym (sym, &src, &len, src_end))
445		  return false;
446		new_symbol->symbol.name = (const char *)
447		    bfd_alloc (abfd, (bfd_size_type) len + 1);
448		if (!new_symbol->symbol.name)
449		  return false;
450		memcpy ((char *) (new_symbol->symbol.name), sym, len + 1);
451		new_symbol->symbol.section = section;
452		if (stype <= '4')
453		  new_symbol->symbol.flags = (BSF_GLOBAL | BSF_EXPORT);
454		else
455		  new_symbol->symbol.flags = BSF_LOCAL;
456		if (stype == '2' || stype == '6')
457		  new_symbol->symbol.section = bfd_abs_section_ptr;
458		else if (stype == '3' || stype == '7')
459		  {
460		    if ((section->flags & SEC_DATA) == 0)
461		      section->flags |= SEC_CODE;
462		    else
463		      {
464			if (alt_section == NULL)
465			  alt_section
466			    = bfd_get_next_section_by_name (NULL, section);
467			if (alt_section == NULL)
468			  alt_section = bfd_make_section_anyway_with_flags
469			    (abfd, section->name,
470			     (section->flags & ~SEC_DATA) | SEC_CODE);
471			if (alt_section == NULL)
472			  return false;
473			new_symbol->symbol.section = alt_section;
474		      }
475		  }
476		else if (stype == '4' || stype == '8')
477		  {
478		    if ((section->flags & SEC_CODE) == 0)
479		      section->flags |= SEC_DATA;
480		    else
481		      {
482			if (alt_section == NULL)
483			  alt_section
484			    = bfd_get_next_section_by_name (NULL, section);
485			if (alt_section == NULL)
486			  alt_section = bfd_make_section_anyway_with_flags
487			    (abfd, section->name,
488			     (section->flags & ~SEC_CODE) | SEC_DATA);
489			if (alt_section == NULL)
490			  return false;
491			new_symbol->symbol.section = alt_section;
492		      }
493		  }
494		if (!getvalue (&src, &val, src_end))
495		  return false;
496		new_symbol->symbol.value = val - section->vma;
497		break;
498	      }
499	    default:
500	      return false;
501	    }
502	}
503    }
504
505  return true;
506}
507
508/* Pass over a tekhex, calling one of the above functions on each
509   record.  */
510
511static bool
512pass_over (bfd *abfd, bool (*func) (bfd *, int, char *, char *))
513{
514  unsigned int chars_on_line;
515  bool is_eof = false;
516
517  /* To the front of the file.  */
518  if (bfd_seek (abfd, 0, SEEK_SET) != 0)
519    return false;
520
521  while (! is_eof)
522    {
523      char src[MAXCHUNK];
524      char type;
525
526      /* Find first '%'.  */
527      is_eof = bfd_read (src, 1, abfd) != 1;
528      while (!is_eof && *src != '%')
529	is_eof = bfd_read (src, 1, abfd) != 1;
530
531      if (is_eof)
532	break;
533
534      /* Fetch the type and the length and the checksum.  */
535      if (bfd_read (src, 5, abfd) != 5)
536	return false;
537
538      type = src[2];
539
540      if (!ISHEX (src[0]) || !ISHEX (src[1]))
541	break;
542
543      /* Already read five chars.  */
544      chars_on_line = HEX (src) - 5;
545
546      if (chars_on_line >= MAXCHUNK)
547	return false;
548
549      if (bfd_read (src, chars_on_line, abfd) != chars_on_line)
550	return false;
551
552      /* Put a null at the end.  */
553      src[chars_on_line] = 0;
554      if (!func (abfd, type, src, src + chars_on_line))
555	return false;
556    }
557
558  return true;
559}
560
561static long
562tekhex_canonicalize_symtab (bfd *abfd, asymbol **table)
563{
564  tekhex_symbol_type *p = abfd->tdata.tekhex_data->symbols;
565  unsigned int c = bfd_get_symcount (abfd);
566
567  table[c] = 0;
568  while (p)
569    {
570      table[--c] = &(p->symbol);
571      p = p->prev;
572    }
573
574  return bfd_get_symcount (abfd);
575}
576
577static long
578tekhex_get_symtab_upper_bound (bfd *abfd)
579{
580  return (abfd->symcount + 1) * (sizeof (struct tekhex_asymbol_struct *));
581
582}
583
584static bool
585tekhex_mkobject (bfd *abfd)
586{
587  tdata_type *tdata;
588
589  tdata = (tdata_type *) bfd_alloc (abfd, (bfd_size_type) sizeof (tdata_type));
590  if (!tdata)
591    return false;
592  abfd->tdata.tekhex_data = tdata;
593  tdata->type = 1;
594  tdata->head =  NULL;
595  tdata->symbols = NULL;
596  tdata->data = NULL;
597  return true;
598}
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
603static bfd_cleanup
604tekhex_object_p (bfd *abfd)
605{
606  char b[4];
607
608  tekhex_init ();
609
610  if (bfd_seek (abfd, 0, SEEK_SET) != 0
611      || bfd_read (b, 4, abfd) != 4)
612    return NULL;
613
614  if (b[0] != '%' || !ISHEX (b[1]) || !ISHEX (b[2]) || !ISHEX (b[3]))
615    return NULL;
616
617  tekhex_mkobject (abfd);
618
619  if (!pass_over (abfd, first_phase))
620    return NULL;
621
622  return _bfd_no_cleanup;
623}
624
625static void
626move_section_contents (bfd *abfd,
627		       asection *section,
628		       const void * locationp,
629		       file_ptr offset,
630		       bfd_size_type count,
631		       bool get)
632{
633  bfd_vma addr;
634  char *location = (char *) locationp;
635  bfd_vma prev_number = 1;	/* Nothing can have this as a high bit.  */
636  struct data_struct *d = NULL;
637
638  BFD_ASSERT (offset == 0);
639  for (addr = section->vma; count != 0; count--, addr++)
640    {
641      /* Get high bits of address.  */
642      bfd_vma chunk_number = addr & ~(bfd_vma) CHUNK_MASK;
643      bfd_vma low_bits = addr & CHUNK_MASK;
644      bool must_write = !get && *location != 0;
645
646      if (chunk_number != prev_number || (!d && must_write))
647	{
648	  /* Different chunk, so move pointer. */
649	  d = find_chunk (abfd, chunk_number, must_write);
650	  prev_number = chunk_number;
651	}
652
653      if (get)
654	{
655	  if (d)
656	    *location = d->chunk_data[low_bits];
657	  else
658	    *location = 0;
659	}
660      else if (must_write)
661	{
662	  d->chunk_data[low_bits] = *location;
663	  d->chunk_init[low_bits / CHUNK_SPAN] = 1;
664	}
665
666      location++;
667    }
668}
669
670static bool
671tekhex_get_section_contents (bfd *abfd,
672			     asection *section,
673			     void * locationp,
674			     file_ptr offset,
675			     bfd_size_type count)
676{
677  if (section->flags & (SEC_LOAD | SEC_ALLOC))
678    {
679      move_section_contents (abfd, section, locationp, offset, count, true);
680      return true;
681    }
682
683  return false;
684}
685
686static bool
687tekhex_set_arch_mach (bfd *abfd,
688		      enum bfd_architecture arch,
689		      unsigned long machine)
690{
691  /* Ignore errors about unknown architecture.  */
692  return (bfd_default_set_arch_mach (abfd, arch, machine)
693	  || arch == bfd_arch_unknown);
694}
695
696/* We have to save up all the Tekhexords for a splurge before output.  */
697
698static bool
699tekhex_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{
705  if (section->flags & (SEC_LOAD | SEC_ALLOC))
706    {
707      move_section_contents (abfd, section, locationp, offset, bytes_to_do,
708			     false);
709      return true;
710    }
711
712  return false;
713}
714
715static void
716writevalue (char **dst, bfd_vma value)
717{
718  char *p = *dst;
719  int len;
720  int shift;
721
722  for (len = 8, shift = 28; shift; shift -= 4, len--)
723    {
724      if ((value >> shift) & 0xf)
725	{
726	  *p++ = len + '0';
727	  while (len)
728	    {
729	      *p++ = digs[(value >> shift) & 0xf];
730	      shift -= 4;
731	      len--;
732	    }
733	  *dst = p;
734	  return;
735
736	}
737    }
738  *p++ = '1';
739  *p++ = '0';
740  *dst = p;
741}
742
743static void
744writesym (char **dst, const char *sym)
745{
746  char *p = *dst;
747  int len = (sym ? strlen (sym) : 0);
748
749  if (len >= 16)
750    {
751      *p++ = '0';
752      len = 16;
753    }
754  else
755    {
756      if (len == 0)
757	{
758	  *p++ = '1';
759	  sym = "$";
760	  len = 1;
761	}
762      else
763	*p++ = digs[len];
764    }
765
766  while (len--)
767    *p++ = *sym++;
768
769  *dst = p;
770}
771
772static void
773out (bfd *abfd, int type, char *start, char *end)
774{
775  int sum = 0;
776  char *s;
777  char front[6];
778  bfd_size_type wrlen;
779
780  front[0] = '%';
781  TOHEX (front + 1, end - start + 5);
782  front[3] = type;
783
784  for (s = start; s < end; s++)
785    sum += sum_block[(unsigned char) *s];
786
787  sum += sum_block[(unsigned char) front[1]];	/* Length.  */
788  sum += sum_block[(unsigned char) front[2]];
789  sum += sum_block[(unsigned char) front[3]];	/* Type.  */
790  TOHEX (front + 4, sum);
791  if (bfd_write (front, 6, abfd) != 6)
792    abort ();
793  end[0] = '\n';
794  wrlen = end - start + 1;
795  if (bfd_write (start, wrlen, abfd) != wrlen)
796    abort ();
797}
798
799static bool
800tekhex_write_object_contents (bfd *abfd)
801{
802  char buffer[100];
803  asymbol **p;
804  asection *s;
805  struct data_struct *d;
806
807  tekhex_init ();
808
809  /* And the raw data.  */
810  for (d = abfd->tdata.tekhex_data->data;
811       d != NULL;
812       d = d->next)
813    {
814      int low;
815      int addr;
816
817      /* Write it in blocks of 32 bytes.  */
818      for (addr = 0; addr < CHUNK_MASK + 1; addr += CHUNK_SPAN)
819	{
820	  if (d->chunk_init[addr / CHUNK_SPAN])
821	    {
822	      char *dst = buffer;
823
824	      writevalue (&dst, addr + d->vma);
825	      for (low = 0; low < CHUNK_SPAN; low++)
826		{
827		  TOHEX (dst, d->chunk_data[addr + low]);
828		  dst += 2;
829		}
830	      out (abfd, '6', buffer, dst);
831	    }
832	}
833    }
834
835  /* Write all the section headers for the sections.  */
836  for (s = abfd->sections; s != NULL; s = s->next)
837    {
838      char *dst = buffer;
839
840      writesym (&dst, s->name);
841      *dst++ = '1';
842      writevalue (&dst, s->vma);
843      writevalue (&dst, s->vma + s->size);
844      out (abfd, '3', buffer, dst);
845    }
846
847  /* And the symbols.  */
848  if (abfd->outsymbols)
849    {
850      for (p = abfd->outsymbols; *p; p++)
851	{
852	  int section_code = bfd_decode_symclass (*p);
853
854	  if (section_code != '?')
855	    {
856	      /* Do not include debug symbols.  */
857	      asymbol *sym = *p;
858	      char *dst = buffer;
859
860	      writesym (&dst, sym->section->name);
861
862	      switch (section_code)
863		{
864		case 'A':
865		  *dst++ = '2';
866		  break;
867		case 'a':
868		  *dst++ = '6';
869		  break;
870		case 'D':
871		case 'B':
872		case 'O':
873		  *dst++ = '4';
874		  break;
875		case 'd':
876		case 'b':
877		case 'o':
878		  *dst++ = '8';
879		  break;
880		case 'T':
881		  *dst++ = '3';
882		  break;
883		case 't':
884		  *dst++ = '7';
885		  break;
886		case 'C':
887		case 'U':
888		  bfd_set_error (bfd_error_wrong_format);
889		  return false;
890		}
891
892	      writesym (&dst, sym->name);
893	      writevalue (&dst, sym->value + sym->section->vma);
894	      out (abfd, '3', buffer, dst);
895	    }
896	}
897    }
898
899  /* And the terminator.  */
900  if (bfd_write ("%0781010\n", 9, abfd) != 9)
901    abort ();
902  return true;
903}
904
905static int
906tekhex_sizeof_headers (bfd *abfd ATTRIBUTE_UNUSED,
907		       struct bfd_link_info *info ATTRIBUTE_UNUSED)
908{
909  return 0;
910}
911
912static asymbol *
913tekhex_make_empty_symbol (bfd *abfd)
914{
915  size_t amt = sizeof (struct tekhex_symbol_struct);
916  tekhex_symbol_type *new_symbol = (tekhex_symbol_type *) bfd_zalloc (abfd,
917								      amt);
918
919  if (!new_symbol)
920    return NULL;
921  new_symbol->symbol.the_bfd = abfd;
922  new_symbol->prev =  NULL;
923  return &(new_symbol->symbol);
924}
925
926static void
927tekhex_get_symbol_info (bfd *abfd ATTRIBUTE_UNUSED,
928			asymbol *symbol,
929			symbol_info *ret)
930{
931  bfd_symbol_info (symbol, ret);
932}
933
934static void
935tekhex_print_symbol (bfd *abfd,
936		     void * filep,
937		     asymbol *symbol,
938		     bfd_print_symbol_type how)
939{
940  FILE *file = (FILE *) filep;
941
942  switch (how)
943    {
944    case bfd_print_symbol_name:
945      fprintf (file, "%s", symbol->name);
946      break;
947    case bfd_print_symbol_more:
948      break;
949
950    case bfd_print_symbol_all:
951      {
952	const char *section_name = symbol->section->name;
953
954	bfd_print_symbol_vandf (abfd, (void *) file, symbol);
955
956	fprintf (file, " %-5s %s",
957		 section_name, symbol->name);
958      }
959    }
960}
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
997const 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};
1053