Back to index

cell-binutils  2.17cvs20070401
tekhex.c
Go to the documentation of this file.
00001 /* BFD backend for Extended Tektronix Hex Format  objects.
00002    Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002,
00003    2003, 2004 Free Software Foundation, Inc.
00004    Written by Steve Chamberlain of Cygnus Support <sac@cygnus.com>.
00005 
00006    This file is part of BFD, the Binary File Descriptor library.
00007 
00008    This program is free software; you can redistribute it and/or modify
00009    it under the terms of the GNU General Public License as published by
00010    the Free Software Foundation; either version 2 of the License, or
00011    (at your option) any later version.
00012 
00013    This program is distributed in the hope that it will be useful,
00014    but WITHOUT ANY WARRANTY; without even the implied warranty of
00015    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016    GNU General Public License for more details.
00017 
00018    You should have received a copy of the GNU General Public License
00019    along with this program; if not, write to the Free Software
00020    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
00021 
00022 /* SUBSECTION
00023        Tektronix Hex Format handling
00024 
00025    DESCRIPTION
00026 
00027        Tek Hex records can hold symbols and data, but not
00028        relocations. Their main application is communication with
00029        devices like PROM programmers and ICE equipment.
00030 
00031        It seems that the sections are described as being really big,
00032         the example I have says that the text section is 0..ffffffff.
00033        BFD would barf with this, many apps would try to alloc 4GB to
00034        read in the file.
00035 
00036        Tex Hex may contain many sections, but the data which comes in
00037        has no tag saying which section it belongs to, so we create
00038        one section for each block of data, called "blknnnn" which we
00039        stick all the data into.
00040 
00041        TekHex may come out of      order and there is no header, so an
00042        initial scan is required  to discover the minimum and maximum
00043        addresses used to create the vma and size of the sections we
00044        create.
00045        We read in the data into pages of CHUNK_MASK+1 size and read
00046        them out from that whenever we need to.
00047 
00048        Any number of sections may be created for output, we save them
00049        up and output them when it's time to close the bfd.
00050 
00051        A TekHex record looks like:
00052   EXAMPLE
00053        %<block length><type><checksum><stuff><cr>
00054 
00055   DESCRIPTION
00056        Where
00057        o length
00058        is the number of bytes in the record not including the % sign.
00059        o type
00060        is one of:
00061        3) symbol record
00062        6) data record
00063        8) termination record
00064 
00065   The data can come out of order, and may be discontigous. This is a
00066   serial protocol, so big files are unlikely, so we keep a list of 8k chunks.  */
00067 
00068 #include "bfd.h"
00069 #include "sysdep.h"
00070 #include "libbfd.h"
00071 #include "libiberty.h"
00072 
00073 typedef struct
00074 {
00075   bfd_vma low;
00076   bfd_vma high;
00077 } addr_range_type;
00078 
00079 typedef struct tekhex_symbol_struct
00080 {
00081   asymbol symbol;
00082   struct tekhex_symbol_struct *prev;
00083 } tekhex_symbol_type;
00084 
00085 static const char digs[] = "0123456789ABCDEF";
00086 
00087 static char sum_block[256];
00088 
00089 #define NOT_HEX      20
00090 #define NIBBLE(x)    hex_value(x)
00091 #define HEX(buffer) ((NIBBLE ((buffer)[0]) << 4) + NIBBLE ((buffer)[1]))
00092 #define       ISHEX(x)    hex_p(x)
00093 #define TOHEX(d, x) \
00094   (d)[1] = digs[(x) & 0xf]; \
00095   (d)[0] = digs[((x)>>4)&0xf];
00096 
00097 /* Here's an example
00098    %3A6C6480004E56FFFC4E717063B0AEFFFC6D0652AEFFFC60F24E5E4E75
00099    %1B3709T_SEGMENT1108FFFFFFFF
00100    %2B3AB9T_SEGMENT7Dgcc_compiled$1087hello$c10
00101    %373829T_SEGMENT80int$t1$r1$$214741080char$t2$r2$0$12710
00102    %373769T_SEGMENT80long$int$t3$r1$$1080unsigned$int$t4$10
00103    %373CA9T_SEGMENT80long$unsigned$in1080short$int$t6$r1$10
00104    %373049T_SEGMENT80long$long$int$t71080short$unsigned$i10
00105    %373A29T_SEGMENT80long$long$unsign1080signed$char$t10$10
00106    %373D69T_SEGMENT80unsigned$char$t11080float$t12$r1$4$010
00107    %373D19T_SEGMENT80double$t13$r1$8$1080long$double$t14$10
00108    %2734D9T_SEGMENT8Bvoid$t15$151035_main10
00109    %2F3CA9T_SEGMENT81$1081$1681$1E81$21487main$F110
00110    %2832F9T_SEGMENT83i$18FFFFFFFC81$1481$214
00111    %07 8 10 10
00112 
00113    explanation:
00114    %3A6C6480004E56FFFC4E717063B0AEFFFC6D0652AEFFFC60F24E5E4E75
00115     ^ ^^ ^     ^-data
00116     | || +------ 4 char integer 0x8000
00117     | |+-------- checksum
00118     | +--------- type 6 (data record)
00119     +----------- length 3a chars
00120    <---------------------- 3a (58 chars) ------------------->
00121 
00122    %1B3709T_SEGMENT1108FFFFFFFF
00123          ^         ^^ ^- 8 character integer 0xffffffff
00124          |         |+-   1 character integer 0
00125          |         +--   type 1 symbol (section definition)
00126          +------------   9 char symbol T_SEGMENT
00127 
00128    %2B3AB9T_SEGMENT7Dgcc_compiled$1087hello$c10
00129    %373829T_SEGMENT80int$t1$r1$$214741080char$t2$r2$0$12710
00130    %373769T_SEGMENT80long$int$t3$r1$$1080unsigned$int$t4$10
00131    %373CA9T_SEGMENT80long$unsigned$in1080short$int$t6$r1$10
00132    %373049T_SEGMENT80long$long$int$t71080short$unsigned$i10
00133    %373A29T_SEGMENT80long$long$unsign1080signed$char$t10$10
00134    %373D69T_SEGMENT80unsigned$char$t11080float$t12$r1$4$010
00135    %373D19T_SEGMENT80double$t13$r1$8$1080long$double$t14$10
00136    %2734D9T_SEGMENT8Bvoid$t15$151035_main10
00137    %2F3CA9T_SEGMENT81$1081$1681$1E81$21487main$F110
00138    %2832F9T_SEGMENT83i$18FFFFFFFC81$1481$214
00139    %0781010
00140 
00141    Turns into
00142    sac@thepub$ ./objdump -dx -m m68k f
00143 
00144    f:     file format tekhex
00145    -----x--- 9/55728 -134219416 Sep 29 15:13 1995 f
00146    architecture: UNKNOWN!, flags 0x00000010:
00147    HAS_SYMS
00148    start address 0x00000000
00149    SECTION 0 [D00000000]    : size 00020000 vma 00000000 align 2**0
00150    ALLOC, LOAD
00151    SECTION 1 [D00008000]    : size 00002001 vma 00008000 align 2**0
00152 
00153    SECTION 2 [T_SEGMENT]    : size ffffffff vma 00000000 align 2**0
00154 
00155    SYMBOL TABLE:
00156    00000000  g       T_SEGMENT gcc_compiled$
00157    00000000  g       T_SEGMENT hello$c
00158    00000000  g       T_SEGMENT int$t1$r1$$21474
00159    00000000  g       T_SEGMENT char$t2$r2$0$127
00160    00000000  g       T_SEGMENT long$int$t3$r1$$
00161    00000000  g       T_SEGMENT unsigned$int$t4$
00162    00000000  g       T_SEGMENT long$unsigned$in
00163    00000000  g       T_SEGMENT short$int$t6$r1$
00164    00000000  g       T_SEGMENT long$long$int$t7
00165    00000000  g       T_SEGMENT short$unsigned$i
00166    00000000  g       T_SEGMENT long$long$unsign
00167    00000000  g       T_SEGMENT signed$char$t10$
00168    00000000  g       T_SEGMENT unsigned$char$t1
00169    00000000  g       T_SEGMENT float$t12$r1$4$0
00170    00000000  g       T_SEGMENT double$t13$r1$8$
00171    00000000  g       T_SEGMENT long$double$t14$
00172    00000000  g       T_SEGMENT void$t15$15
00173    00000000  g       T_SEGMENT _main
00174    00000000  g       T_SEGMENT $
00175    00000000  g       T_SEGMENT $
00176    00000000  g       T_SEGMENT $
00177    00000010  g       T_SEGMENT $
00178    00000000  g       T_SEGMENT main$F1
00179    fcffffff  g       T_SEGMENT i$1
00180    00000000  g       T_SEGMENT $
00181    00000010  g       T_SEGMENT $
00182 
00183    RELOCATION RECORDS FOR [D00000000]: (none)
00184 
00185    RELOCATION RECORDS FOR [D00008000]: (none)
00186 
00187    RELOCATION RECORDS FOR [T_SEGMENT]: (none)
00188 
00189    Disassembly of section D00000000:
00190    ...
00191    00008000 ($+)7ff0 linkw fp,#-4
00192    00008004 ($+)7ff4 nop
00193    00008006 ($+)7ff6 movel #99,d0
00194    00008008 ($+)7ff8 cmpl fp@(-4),d0
00195    0000800c ($+)7ffc blts 00008014 ($+)8004
00196    0000800e ($+)7ffe addql #1,fp@(-4)
00197    00008012 ($+)8002 bras 00008006 ($+)7ff6
00198    00008014 ($+)8004 unlk fp
00199    00008016 ($+)8006 rts
00200    ...  */
00201 
00202 static void
00203 tekhex_init (void)
00204 {
00205   unsigned int i;
00206   static bfd_boolean inited = FALSE;
00207   int val;
00208 
00209   if (! inited)
00210     {
00211       inited = TRUE;
00212       hex_init ();
00213       val = 0;
00214       for (i = 0; i < 10; i++)
00215        sum_block[i + '0'] = val++;
00216 
00217       for (i = 'A'; i <= 'Z'; i++)
00218        sum_block[i] = val++;
00219 
00220       sum_block['$'] = val++;
00221       sum_block['%'] = val++;
00222       sum_block['.'] = val++;
00223       sum_block['_'] = val++;
00224       for (i = 'a'; i <= 'z'; i++)
00225        sum_block[i] = val++;
00226     }
00227 }
00228 
00229 /* The maximum number of bytes on a line is FF.  */
00230 #define MAXCHUNK 0xff
00231 /* The number of bytes we fit onto a line on output.  */
00232 #define CHUNK 21
00233 
00234 /* We cannot output our tekhexords as we see them, we have to glue them
00235    together, this is done in this structure : */
00236 
00237 struct tekhex_data_list_struct
00238 {
00239   unsigned char *data;
00240   bfd_vma where;
00241   bfd_size_type size;
00242   struct tekhex_data_list_struct *next;
00243 
00244 };
00245 typedef struct tekhex_data_list_struct tekhex_data_list_type;
00246 
00247 #define CHUNK_MASK 0x1fff
00248 
00249 struct data_struct
00250 {
00251   char chunk_data[CHUNK_MASK + 1];
00252   char chunk_init[CHUNK_MASK + 1];
00253   bfd_vma vma;
00254   struct data_struct *next;
00255 };
00256 
00257 typedef struct tekhex_data_struct
00258 {
00259   tekhex_data_list_type *head;
00260   unsigned int type;
00261   struct tekhex_symbol_struct *symbols;
00262   struct data_struct *data;
00263 } tdata_type;
00264 
00265 #define enda(x) (x->vma + x->size)
00266 
00267 static bfd_boolean
00268 getvalue (char **srcp, bfd_vma *valuep)
00269 {
00270   char *src = *srcp;
00271   bfd_vma value = 0;
00272   unsigned int len;
00273 
00274   if (!ISHEX (*src))
00275     return FALSE;
00276 
00277   len = hex_value (*src++);
00278   if (len == 0)
00279     len = 16;
00280   while (len--)
00281     {
00282       if (!ISHEX (*src))
00283        return FALSE;
00284       value = value << 4 | hex_value (*src++);
00285     }
00286 
00287   *srcp = src;
00288   *valuep = value;
00289   return TRUE;
00290 }
00291 
00292 static bfd_boolean
00293 getsym (char *dstp, char **srcp, unsigned int *lenp)
00294 {
00295   char *src = *srcp;
00296   unsigned int i;
00297   unsigned int len;
00298   
00299   if (!ISHEX (*src))
00300     return FALSE;
00301 
00302   len = hex_value (*src++);
00303   if (len == 0)
00304     len = 16;
00305   for (i = 0; i < len; i++)
00306     dstp[i] = src[i];
00307   dstp[i] = 0;
00308   *srcp = src + i;
00309   *lenp = len;
00310   return TRUE;
00311 }
00312 
00313 static struct data_struct *
00314 find_chunk (bfd *abfd, bfd_vma vma)
00315 {
00316   struct data_struct *d = abfd->tdata.tekhex_data->data;
00317 
00318   vma &= ~CHUNK_MASK;
00319   while (d && (d->vma) != vma)
00320     d = d->next;
00321 
00322   if (!d)
00323     {
00324       /* No chunk for this address, so make one up.  */
00325       d = bfd_zalloc (abfd, (bfd_size_type) sizeof (struct data_struct));
00326 
00327       if (!d)
00328        return NULL;
00329 
00330       d->next = abfd->tdata.tekhex_data->data;
00331       d->vma = vma;
00332       abfd->tdata.tekhex_data->data = d;
00333     }
00334   return d;
00335 }
00336 
00337 static void
00338 insert_byte (bfd *abfd, int value, bfd_vma addr)
00339 {
00340   /* Find the chunk that this byte needs and put it in.  */
00341   struct data_struct *d = find_chunk (abfd, addr);
00342 
00343   d->chunk_data[addr & CHUNK_MASK] = value;
00344   d->chunk_init[addr & CHUNK_MASK] = 1;
00345 }
00346 
00347 /* The first pass is to find the names of all the sections, and see
00348   how big the data is.  */
00349 
00350 static bfd_boolean
00351 first_phase (bfd *abfd, int type, char *src)
00352 {
00353   asection *section = bfd_abs_section_ptr;
00354   unsigned int len;
00355   bfd_vma val;
00356   char sym[17];                    /* A symbol can only be 16chars long.  */
00357 
00358   switch (type)
00359     {
00360     case '6':
00361       /* Data record - read it and store it.  */
00362       {
00363        bfd_vma addr;
00364 
00365        if (!getvalue (&src, &addr))
00366          return FALSE;
00367 
00368        while (*src)
00369          {
00370            insert_byte (abfd, HEX (src), addr);
00371            src += 2;
00372            addr++;
00373          }
00374       }
00375 
00376       return TRUE;
00377     case '3':
00378       /* Symbol record, read the segment.  */
00379       if (!getsym (sym, &src, &len))
00380        return FALSE;
00381       section = bfd_get_section_by_name (abfd, sym);
00382       if (section == NULL)
00383        {
00384          char *n = bfd_alloc (abfd, (bfd_size_type) len + 1);
00385 
00386          if (!n)
00387            return FALSE;
00388          memcpy (n, sym, len + 1);
00389          section = bfd_make_section (abfd, n);
00390        }
00391       while (*src)
00392        {
00393          switch (*src)
00394            {
00395            case '1':        /* Section range.  */
00396              src++;
00397              if (!getvalue (&src, &section->vma))
00398               return FALSE;
00399              if (!getvalue (&src, &val))
00400               return FALSE;
00401              section->size = val - section->vma;
00402              section->flags = SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC;
00403              break;
00404            case '0':
00405            case '2':
00406            case '3':
00407            case '4':
00408            case '6':
00409            case '7':
00410            case '8':
00411              /* Symbols, add to section.  */
00412              {
00413               bfd_size_type amt = sizeof (tekhex_symbol_type);
00414               tekhex_symbol_type *new = bfd_alloc (abfd, amt);
00415               char stype = (*src);
00416 
00417               if (!new)
00418                 return FALSE;
00419               new->symbol.the_bfd = abfd;
00420               src++;
00421               abfd->symcount++;
00422               abfd->flags |= HAS_SYMS;
00423               new->prev = abfd->tdata.tekhex_data->symbols;
00424               abfd->tdata.tekhex_data->symbols = new;
00425               if (!getsym (sym, &src, &len))
00426                 return FALSE;
00427               new->symbol.name = bfd_alloc (abfd, (bfd_size_type) len + 1);
00428               if (!new->symbol.name)
00429                 return FALSE;
00430               memcpy ((char *) (new->symbol.name), sym, len + 1);
00431               new->symbol.section = section;
00432               if (stype <= '4')
00433                 new->symbol.flags = (BSF_GLOBAL | BSF_EXPORT);
00434               else
00435                 new->symbol.flags = BSF_LOCAL;
00436               if (!getvalue (&src, &val))
00437                 return FALSE;
00438               new->symbol.value = val - section->vma;
00439               break;
00440              }
00441            default:
00442              return FALSE;
00443            }
00444        }
00445     }
00446 
00447   return TRUE;
00448 }
00449 
00450 /* Pass over a tekhex, calling one of the above functions on each
00451    record.  */
00452 
00453 static bfd_boolean
00454 pass_over (bfd *abfd, bfd_boolean (*func) (bfd *, int, char *))
00455 {
00456   unsigned int chars_on_line;
00457   bfd_boolean eof = FALSE;
00458 
00459   /* To the front of the file.  */
00460   if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0)
00461     return FALSE;
00462   while (! eof)
00463     {
00464       char src[MAXCHUNK];
00465       char type;
00466 
00467       /* Find first '%'.  */
00468       eof = (bfd_boolean) (bfd_bread (src, (bfd_size_type) 1, abfd) != 1);
00469       while (*src != '%' && !eof)
00470        eof = (bfd_boolean) (bfd_bread (src, (bfd_size_type) 1, abfd) != 1);
00471 
00472       if (eof)
00473        break;
00474 
00475       /* Fetch the type and the length and the checksum.  */
00476       if (bfd_bread (src, (bfd_size_type) 5, abfd) != 5)
00477        return FALSE;
00478 
00479       type = src[2];
00480 
00481       if (!ISHEX (src[0]) || !ISHEX (src[1]))
00482        break;
00483 
00484       /* Already read five chars.  */
00485       chars_on_line = HEX (src) - 5;
00486 
00487       if (chars_on_line >= MAXCHUNK)
00488        return FALSE;
00489 
00490       if (bfd_bread (src, (bfd_size_type) chars_on_line, abfd) != chars_on_line)
00491        return FALSE;
00492 
00493       /* Put a null at the end.  */
00494       src[chars_on_line] = 0;
00495 
00496       if (!func (abfd, type, src))
00497        return FALSE;
00498     }
00499 
00500   return TRUE;
00501 }
00502 
00503 static long
00504 tekhex_canonicalize_symtab (bfd *abfd, asymbol **table)
00505 {
00506   tekhex_symbol_type *p = abfd->tdata.tekhex_data->symbols;
00507   unsigned int c = bfd_get_symcount (abfd);
00508 
00509   table[c] = 0;
00510   while (p)
00511     {
00512       table[--c] = &(p->symbol);
00513       p = p->prev;
00514     }
00515 
00516   return bfd_get_symcount (abfd);
00517 }
00518 
00519 static long
00520 tekhex_get_symtab_upper_bound (bfd *abfd)
00521 {
00522   return (abfd->symcount + 1) * (sizeof (struct tekhex_asymbol_struct *));
00523 
00524 }
00525 
00526 static bfd_boolean
00527 tekhex_mkobject (bfd *abfd)
00528 {
00529   tdata_type *tdata;
00530 
00531   tdata = bfd_alloc (abfd, (bfd_size_type) sizeof (tdata_type));
00532   if (!tdata)
00533     return FALSE;
00534   abfd->tdata.tekhex_data = tdata;
00535   tdata->type = 1;
00536   tdata->head =  NULL;
00537   tdata->symbols = NULL;
00538   tdata->data = NULL;
00539   return TRUE;
00540 }
00541 
00542 /* Return TRUE if the file looks like it's in TekHex format. Just look
00543    for a percent sign and some hex digits.  */
00544 
00545 static const bfd_target *
00546 tekhex_object_p (bfd *abfd)
00547 {
00548   char b[4];
00549 
00550   tekhex_init ();
00551 
00552   if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0
00553       || bfd_bread (b, (bfd_size_type) 4, abfd) != 4)
00554     return NULL;
00555 
00556   if (b[0] != '%' || !ISHEX (b[1]) || !ISHEX (b[2]) || !ISHEX (b[3]))
00557     return NULL;
00558 
00559   tekhex_mkobject (abfd);
00560 
00561   if (!pass_over (abfd, first_phase))
00562     return NULL;
00563 
00564   return abfd->xvec;
00565 }
00566 
00567 static void
00568 move_section_contents (bfd *abfd,
00569                      asection *section,
00570                      const void * locationp,
00571                      file_ptr offset,
00572                      bfd_size_type count,
00573                      bfd_boolean get)
00574 {
00575   bfd_vma addr;
00576   char *location = (char *) locationp;
00577   bfd_vma prev_number = 1;  /* Nothing can have this as a high bit.  */
00578   struct data_struct *d = NULL;
00579 
00580   BFD_ASSERT (offset == 0);
00581   for (addr = section->vma; count != 0; count--, addr++)
00582     {
00583       /* Get high bits of address.  */
00584       bfd_vma chunk_number = addr & ~(bfd_vma) CHUNK_MASK;
00585       bfd_vma low_bits = addr & CHUNK_MASK;
00586 
00587       if (chunk_number != prev_number)
00588        /* Different chunk, so move pointer. */
00589        d = find_chunk (abfd, chunk_number);
00590 
00591       if (get)
00592        {
00593          if (d->chunk_init[low_bits])
00594            *location = d->chunk_data[low_bits];
00595          else
00596            *location = 0;
00597        }
00598       else
00599        {
00600          d->chunk_data[low_bits] = *location;
00601          d->chunk_init[low_bits] = (*location != 0);
00602        }
00603 
00604       location++;
00605     }
00606 }
00607 
00608 static bfd_boolean
00609 tekhex_get_section_contents (bfd *abfd,
00610                           asection *section,
00611                           void * locationp,
00612                           file_ptr offset,
00613                           bfd_size_type count)
00614 {
00615   if (section->flags & (SEC_LOAD | SEC_ALLOC))
00616     {
00617       move_section_contents (abfd, section, locationp, offset, count, TRUE);
00618       return TRUE;
00619     }
00620 
00621   return FALSE;
00622 }
00623 
00624 static bfd_boolean
00625 tekhex_set_arch_mach (bfd *abfd,
00626                     enum bfd_architecture arch,
00627                     unsigned long machine)
00628 {
00629   return bfd_default_set_arch_mach (abfd, arch, machine);
00630 }
00631 
00632 /* We have to save up all the Tekhexords for a splurge before output.  */
00633 
00634 static bfd_boolean
00635 tekhex_set_section_contents (bfd *abfd,
00636                           sec_ptr section,
00637                           const void * locationp,
00638                           file_ptr offset,
00639                           bfd_size_type bytes_to_do)
00640 {
00641   if (! abfd->output_has_begun)
00642     {
00643       /* The first time around, allocate enough sections to hold all the chunks.  */
00644       asection *s = abfd->sections;
00645       bfd_vma vma;
00646 
00647       for (s = abfd->sections; s; s = s->next)
00648        {
00649          if (s->flags & SEC_LOAD)
00650            {
00651              for (vma = s->vma & ~(bfd_vma) CHUNK_MASK;
00652                  vma < s->vma + s->size;
00653                  vma += CHUNK_MASK)
00654               find_chunk (abfd, vma);
00655            }
00656        }
00657     }
00658 
00659   if (section->flags & (SEC_LOAD | SEC_ALLOC))
00660     {
00661       move_section_contents (abfd, section, locationp, offset, bytes_to_do,
00662                           FALSE);
00663       return TRUE;
00664     }
00665 
00666   return FALSE;
00667 }
00668 
00669 static void
00670 writevalue (char **dst, bfd_vma value)
00671 {
00672   char *p = *dst;
00673   int len;
00674   int shift;
00675 
00676   for (len = 8, shift = 28; shift; shift -= 4, len--)
00677     {
00678       if ((value >> shift) & 0xf)
00679        {
00680          *p++ = len + '0';
00681          while (len)
00682            {
00683              *p++ = digs[(value >> shift) & 0xf];
00684              shift -= 4;
00685              len--;
00686            }
00687          *dst = p;
00688          return;
00689 
00690        }
00691     }
00692   *p++ = '1';
00693   *p++ = '0';
00694   *dst = p;
00695 }
00696 
00697 static void
00698 writesym (char **dst, const char *sym)
00699 {
00700   char *p = *dst;
00701   int len = (sym ? strlen (sym) : 0);
00702 
00703   if (len >= 16)
00704     {
00705       *p++ = '0';
00706       len = 16;
00707     }
00708   else
00709     {
00710       if (len == 0)
00711        {
00712          *p++ = '1';
00713          sym = "$";
00714          len = 1;
00715        }
00716       else
00717        *p++ = digs[len];
00718     }
00719 
00720   while (len--)
00721     *p++ = *sym++;
00722 
00723   *dst = p;
00724 }
00725 
00726 static void
00727 out (bfd *abfd, int type, char *start, char *end)
00728 {
00729   int sum = 0;
00730   char *s;
00731   char front[6];
00732   bfd_size_type wrlen;
00733 
00734   front[0] = '%';
00735   TOHEX (front + 1, end - start + 5);
00736   front[3] = type;
00737 
00738   for (s = start; s < end; s++)
00739     sum += sum_block[(unsigned char) *s];
00740 
00741   sum += sum_block[(unsigned char) front[1]];    /* Length.  */
00742   sum += sum_block[(unsigned char) front[2]];
00743   sum += sum_block[(unsigned char) front[3]];    /* Type.  */
00744   TOHEX (front + 4, sum);
00745   if (bfd_bwrite (front, (bfd_size_type) 6, abfd) != 6)
00746     abort ();
00747   end[0] = '\n';
00748   wrlen = end - start + 1;
00749   if (bfd_bwrite (start, wrlen, abfd) != wrlen)
00750     abort ();
00751 }
00752 
00753 static bfd_boolean
00754 tekhex_write_object_contents (bfd *abfd)
00755 {
00756   char buffer[100];
00757   asymbol **p;
00758   asection *s;
00759   struct data_struct *d;
00760 
00761   tekhex_init ();
00762 
00763   /* And the raw data.  */
00764   for (d = abfd->tdata.tekhex_data->data;
00765        d != NULL;
00766        d = d->next)
00767     {
00768       int low;
00769 
00770       const int span = 32;
00771       int addr;
00772 
00773       /* Write it in blocks of 32 bytes.  */
00774       for (addr = 0; addr < CHUNK_MASK + 1; addr += span)
00775        {
00776          int need = 0;
00777 
00778          /* Check to see if necessary.  */
00779          for (low = 0; !need && low < span; low++)
00780            if (d->chunk_init[addr + low])
00781              need = 1;
00782 
00783          if (need)
00784            {
00785              char *dst = buffer;
00786 
00787              writevalue (&dst, addr + d->vma);
00788              for (low = 0; low < span; low++)
00789               {
00790                 TOHEX (dst, d->chunk_data[addr + low]);
00791                 dst += 2;
00792               }
00793              out (abfd, '6', buffer, dst);
00794            }
00795        }
00796     }
00797 
00798   /* Write all the section headers for the sections.  */
00799   for (s = abfd->sections; s != NULL; s = s->next)
00800     {
00801       char *dst = buffer;
00802 
00803       writesym (&dst, s->name);
00804       *dst++ = '1';
00805       writevalue (&dst, s->vma);
00806       writevalue (&dst, s->vma + s->size);
00807       out (abfd, '3', buffer, dst);
00808     }
00809 
00810   /* And the symbols.  */
00811   if (abfd->outsymbols)
00812     {
00813       for (p = abfd->outsymbols; *p; p++)
00814        {
00815          int section_code = bfd_decode_symclass (*p);
00816 
00817          if (section_code != '?')
00818            {
00819              /* Do not include debug symbols.  */
00820              asymbol *sym = *p;
00821              char *dst = buffer;
00822 
00823              writesym (&dst, sym->section->name);
00824 
00825              switch (section_code)
00826               {
00827               case 'A':
00828                 *dst++ = '2';
00829                 break;
00830               case 'a':
00831                 *dst++ = '6';
00832                 break;
00833               case 'D':
00834               case 'B':
00835               case 'O':
00836                 *dst++ = '4';
00837                 break;
00838               case 'd':
00839               case 'b':
00840               case 'o':
00841                 *dst++ = '8';
00842                 break;
00843               case 'T':
00844                 *dst++ = '3';
00845                 break;
00846               case 't':
00847                 *dst++ = '7';
00848                 break;
00849               case 'C':
00850               case 'U':
00851                 bfd_set_error (bfd_error_wrong_format);
00852                 return FALSE;
00853               }
00854 
00855              writesym (&dst, sym->name);
00856              writevalue (&dst, sym->value + sym->section->vma);
00857              out (abfd, '3', buffer, dst);
00858            }
00859        }
00860     }
00861 
00862   /* And the terminator.  */
00863   if (bfd_bwrite ("%0781010\n", (bfd_size_type) 9, abfd) != 9)
00864     abort ();
00865   return TRUE;
00866 }
00867 
00868 static int
00869 tekhex_sizeof_headers (bfd *abfd ATTRIBUTE_UNUSED,
00870                      struct bfd_link_info *info ATTRIBUTE_UNUSED)
00871 {
00872   return 0;
00873 }
00874 
00875 static asymbol *
00876 tekhex_make_empty_symbol (bfd *abfd)
00877 {
00878   bfd_size_type amt = sizeof (struct tekhex_symbol_struct);
00879   tekhex_symbol_type *new = bfd_zalloc (abfd, amt);
00880 
00881   if (!new)
00882     return NULL;
00883   new->symbol.the_bfd = abfd;
00884   new->prev =  NULL;
00885   return &(new->symbol);
00886 }
00887 
00888 static void
00889 tekhex_get_symbol_info (bfd *abfd ATTRIBUTE_UNUSED,
00890                      asymbol *symbol,
00891                      symbol_info *ret)
00892 {
00893   bfd_symbol_info (symbol, ret);
00894 }
00895 
00896 static void
00897 tekhex_print_symbol (bfd *abfd,
00898                    void * filep,
00899                    asymbol *symbol,
00900                    bfd_print_symbol_type how)
00901 {
00902   FILE *file = (FILE *) filep;
00903 
00904   switch (how)
00905     {
00906     case bfd_print_symbol_name:
00907       fprintf (file, "%s", symbol->name);
00908       break;
00909     case bfd_print_symbol_more:
00910       break;
00911 
00912     case bfd_print_symbol_all:
00913       {
00914        const char *section_name = symbol->section->name;
00915 
00916        bfd_print_symbol_vandf (abfd, (void *) file, symbol);
00917 
00918        fprintf (file, " %-5s %s",
00919                section_name, symbol->name);
00920       }
00921     }
00922 }
00923 
00924 #define       tekhex_close_and_cleanup                    _bfd_generic_close_and_cleanup
00925 #define tekhex_bfd_free_cached_info                 _bfd_generic_bfd_free_cached_info
00926 #define tekhex_new_section_hook                     _bfd_generic_new_section_hook
00927 #define tekhex_bfd_is_target_special_symbol ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false)
00928 #define tekhex_bfd_is_local_label_name               bfd_generic_is_local_label_name
00929 #define tekhex_get_lineno                           _bfd_nosymbols_get_lineno
00930 #define tekhex_find_nearest_line                    _bfd_nosymbols_find_nearest_line
00931 #define tekhex_find_inliner_info                    _bfd_nosymbols_find_inliner_info
00932 #define tekhex_bfd_make_debug_symbol                _bfd_nosymbols_bfd_make_debug_symbol
00933 #define tekhex_read_minisymbols                     _bfd_generic_read_minisymbols
00934 #define tekhex_minisymbol_to_symbol                 _bfd_generic_minisymbol_to_symbol
00935 #define tekhex_bfd_get_relocated_section_contents   bfd_generic_get_relocated_section_contents
00936 #define tekhex_bfd_relax_section                    bfd_generic_relax_section
00937 #define tekhex_bfd_gc_sections                      bfd_generic_gc_sections
00938 #define tekhex_bfd_merge_sections                   bfd_generic_merge_sections
00939 #define tekhex_bfd_is_group_section                 bfd_generic_is_group_section
00940 #define tekhex_bfd_discard_group                    bfd_generic_discard_group
00941 #define tekhex_section_already_linked               _bfd_generic_section_already_linked
00942 #define tekhex_bfd_link_hash_table_create           _bfd_generic_link_hash_table_create
00943 #define tekhex_bfd_link_hash_table_free             _bfd_generic_link_hash_table_free
00944 #define tekhex_bfd_link_add_symbols                 _bfd_generic_link_add_symbols
00945 #define tekhex_bfd_link_just_syms                   _bfd_generic_link_just_syms
00946 #define tekhex_bfd_final_link                       _bfd_generic_final_link
00947 #define tekhex_bfd_link_split_section               _bfd_generic_link_split_section
00948 #define tekhex_get_section_contents_in_window       _bfd_generic_get_section_contents_in_window
00949 
00950 const bfd_target tekhex_vec =
00951 {
00952   "tekhex",                 /* Name.  */
00953   bfd_target_tekhex_flavour,
00954   BFD_ENDIAN_UNKNOWN,              /* Target byte order.  */
00955   BFD_ENDIAN_UNKNOWN,              /* Target headers byte order.  */
00956   (EXEC_P |                 /* Object flags.  */
00957    HAS_SYMS | HAS_LINENO | HAS_DEBUG |
00958    HAS_RELOC | HAS_LOCALS | WP_TEXT | D_PAGED),
00959   (SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS
00960    | SEC_ALLOC | SEC_LOAD | SEC_RELOC),   /* Section flags.  */
00961   0,                        /* Leading underscore.  */
00962   ' ',                      /* AR_pad_char.  */
00963   16,                       /* AR_max_namelen.  */
00964   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
00965   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
00966   bfd_getb16, bfd_getb_signed_16, bfd_putb16,    /* Data.  */
00967   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
00968   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
00969   bfd_getb16, bfd_getb_signed_16, bfd_putb16,    /* Headers.  */
00970 
00971   {
00972     _bfd_dummy_target,
00973     tekhex_object_p,        /* bfd_check_format.  */
00974     _bfd_dummy_target,
00975     _bfd_dummy_target,
00976   },
00977   {
00978     bfd_false,
00979     tekhex_mkobject,
00980     _bfd_generic_mkarchive,
00981     bfd_false,
00982   },
00983   {                         /* bfd_write_contents.  */
00984     bfd_false,
00985     tekhex_write_object_contents,
00986     _bfd_write_archive_contents,
00987     bfd_false,
00988   },
00989 
00990   BFD_JUMP_TABLE_GENERIC (tekhex),
00991   BFD_JUMP_TABLE_COPY (_bfd_generic),
00992   BFD_JUMP_TABLE_CORE (_bfd_nocore),
00993   BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
00994   BFD_JUMP_TABLE_SYMBOLS (tekhex),
00995   BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
00996   BFD_JUMP_TABLE_WRITE (tekhex),
00997   BFD_JUMP_TABLE_LINK (tekhex),
00998   BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
00999 
01000   NULL,
01001 
01002   NULL
01003 };