Back to index

cell-binutils  2.17cvs20070401
vms-misc.c
Go to the documentation of this file.
00001 /* vms-misc.c -- Miscellaneous functions for VAX (openVMS/VAX) and
00002    EVAX (openVMS/Alpha) files.
00003    Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
00004    Free Software Foundation, Inc.
00005 
00006    Written by Klaus K"ampf (kkaempf@rmi.de)
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 #if __STDC__
00023 #include <stdarg.h>
00024 #endif
00025 
00026 #include "bfd.h"
00027 #include "sysdep.h"
00028 #include "bfdlink.h"
00029 #include "libbfd.h"
00030 
00031 #include "vms.h"
00032 
00033 #if VMS_DEBUG
00034 /* Debug functions.  */
00035 
00036 /* Debug function for all vms extensions
00037    evaluates environment variable VMS_DEBUG for a
00038    numerical value on the first call
00039    all error levels below this value are printed
00040 
00041    levels:
00042    1   toplevel bfd calls (functions from the bfd vector)
00043    2   functions called by bfd calls
00044    ...
00045    9   almost everything
00046 
00047    level is also indentation level. Indentation is performed
00048    if level > 0.  */
00049 
00050 void
00051 _bfd_vms_debug (int level, char *format, ...)
00052 {
00053   static int min_level = -1;
00054   static FILE *output = NULL;
00055   char *eptr;
00056   va_list args;
00057   int abslvl = (level > 0) ? level : - level;
00058 
00059   if (min_level == -1)
00060     {
00061       if ((eptr = getenv ("VMS_DEBUG")) != NULL)
00062        {
00063          min_level = atoi (eptr);
00064          output = stderr;
00065        }
00066       else
00067        min_level = 0;
00068     }
00069   if (output == NULL)
00070     return;
00071   if (abslvl > min_level)
00072     return;
00073 
00074   while (--level>0)
00075     fprintf (output, " ");
00076   va_start (args, format);
00077   vfprintf (output, format, args);
00078   fflush (output);
00079   va_end (args);
00080 }
00081 
00082 /* A debug function
00083    hex dump 'size' bytes starting at 'ptr'.  */
00084 
00085 void
00086 _bfd_hexdump (int level,
00087              unsigned char *ptr,
00088              int size,
00089              int offset)
00090 {
00091   unsigned char *lptr = ptr;
00092   int count = 0;
00093   long start = offset;
00094 
00095   while (size-- > 0)
00096     {
00097       if ((count%16) == 0)
00098        vms_debug (level, "%08lx:", start);
00099       vms_debug (-level, " %02x", *ptr++);
00100       count++;
00101       start++;
00102       if (size == 0)
00103        {
00104          while ((count%16) != 0)
00105            {
00106              vms_debug (-level, "   ");
00107              count++;
00108            }
00109        }
00110       if ((count%16) == 0)
00111        {
00112          vms_debug (-level, " ");
00113          while (lptr < ptr)
00114            {
00115              vms_debug (-level, "%c", (*lptr < 32)?'.':*lptr);
00116              lptr++;
00117            }
00118          vms_debug (-level, "\n");
00119        }
00120     }
00121   if ((count%16) != 0)
00122     vms_debug (-level, "\n");
00123 }
00124 #endif
00125 
00126 /* Hash functions
00127 
00128    These are needed when reading an object file.  */
00129 
00130 /* Allocate new vms_hash_entry
00131    keep the symbol name and a pointer to the bfd symbol in the table.  */
00132 
00133 struct bfd_hash_entry *
00134 _bfd_vms_hash_newfunc (struct bfd_hash_entry *entry,
00135                      struct bfd_hash_table *table,
00136                      const char *string)
00137 {
00138   vms_symbol_entry *ret;
00139 
00140 #if VMS_DEBUG
00141   vms_debug (5, "_bfd_vms_hash_newfunc (%p, %p, %s)\n", entry, table, string);
00142 #endif
00143 
00144   if (entry == NULL)
00145     {
00146       ret = (vms_symbol_entry *)
00147              bfd_hash_allocate (table, sizeof (vms_symbol_entry));
00148       if (ret ==  NULL)
00149        {
00150          bfd_set_error (bfd_error_no_memory);
00151          return NULL;
00152        }
00153       entry = (struct bfd_hash_entry *) ret;
00154     }
00155 
00156   /* Call the allocation method of the base class.  */
00157   ret = (vms_symbol_entry *) bfd_hash_newfunc (entry, table, string);
00158 #if VMS_DEBUG
00159   vms_debug (6, "_bfd_vms_hash_newfunc ret %p\n", ret);
00160 #endif
00161 
00162   ret->symbol = NULL;
00163 
00164   return (struct bfd_hash_entry *)ret;
00165 }
00166 
00167 /* Object file input functions.  */
00168 
00169 /* Return type and length from record header (buf) on Alpha.  */
00170 
00171 void
00172 _bfd_vms_get_header_values (bfd * abfd ATTRIBUTE_UNUSED,
00173                          unsigned char *buf,
00174                          int *type,
00175                          int *length)
00176 {
00177   if (type != 0)
00178     *type = bfd_getl16 (buf);
00179   buf += 2;
00180   if (length != 0)
00181     *length = bfd_getl16 (buf);
00182 
00183 #if VMS_DEBUG
00184   vms_debug (10, "_bfd_vms_get_header_values type %x, length %x\n", (type?*type:0), (length?*length:0));
00185 #endif
00186 }
00187 
00188 /* Get next record from object file to vms_buf.
00189    Set PRIV(buf_size) and return it
00190 
00191    This is a little tricky since it should be portable.
00192 
00193    The openVMS object file has 'variable length' which means that
00194    read() returns data in chunks of (hopefully) correct and expected
00195    size. The linker (and other tools on vms) depend on that. Unix doesn't
00196    know about 'formatted' files, so reading and writing such an object
00197    file in a unix environment is not trivial.
00198 
00199    With the tool 'file' (available on all vms ftp sites), one
00200    can view and change the attributes of a file. Changing from
00201    'variable length' to 'fixed length, 512 bytes' reveals the
00202    record length at the first 2 bytes of every record. The same
00203    happens during the transfer of object files from vms to unix,
00204    at least with ucx, dec's implementation of tcp/ip.
00205 
00206    The vms format repeats the length at bytes 2 & 3 of every record.
00207 
00208    On the first call (file_format == FF_UNKNOWN) we check if
00209    the first and the third byte pair (!) of the record match.
00210    If they do it's an object file in an unix environment or with
00211    wrong attributes (FF_FOREIGN), else we should be in a vms
00212    environment where read() returns the record size (FF_NATIVE).
00213 
00214    Reading is always done in 2 steps.
00215    First just the record header is read and the length extracted
00216    by get_header_values,
00217    then the read buffer is adjusted and the remaining bytes are
00218    read in.
00219 
00220    All file i/o is always done on even file positions.  */
00221 
00222 int
00223 _bfd_vms_get_record (bfd * abfd)
00224 {
00225   int test_len, test_start, remaining;
00226   unsigned char *vms_buf;
00227 
00228 #if VMS_DEBUG
00229   vms_debug (8, "_bfd_vms_get_record\n");
00230 #endif
00231 
00232   /* Minimum is 6 bytes on Alpha
00233      (2 bytes length, 2 bytes record id, 2 bytes length repeated)
00234 
00235      On the VAX there's no length information in the record
00236      so start with OBJ_S_C_MAXRECSIZ.   */
00237 
00238   if (PRIV (buf_size) == 0)
00239     {
00240       bfd_size_type amt;
00241 
00242       if (PRIV (is_vax))
00243        {
00244          amt = OBJ_S_C_MAXRECSIZ;
00245          PRIV (file_format) = FF_VAX;
00246        }
00247       else
00248        amt = 6;
00249       PRIV (vms_buf) = bfd_malloc (amt);
00250       PRIV (buf_size) = amt;
00251     }
00252 
00253   vms_buf = PRIV (vms_buf);
00254 
00255   if (vms_buf == 0)
00256     return -1;
00257 
00258   switch (PRIV (file_format))
00259     {
00260     case FF_UNKNOWN:
00261     case FF_FOREIGN:
00262       test_len = 6;                /* Probe 6 bytes.  */
00263       test_start = 2;                     /* Where the record starts.  */
00264       break;
00265 
00266     case FF_NATIVE:
00267       test_len = 4;
00268       test_start = 0;
00269       break;
00270 
00271     default:
00272     case FF_VAX:
00273       test_len = 0;
00274       test_start = 0;
00275       break;
00276     }
00277 
00278   /* Skip odd alignment byte.  */
00279 
00280   if (bfd_tell (abfd) & 1)
00281     {
00282       if (bfd_bread (PRIV (vms_buf), (bfd_size_type) 1, abfd) != 1)
00283        {
00284          bfd_set_error (bfd_error_file_truncated);
00285          return 0;
00286        }
00287     }
00288 
00289   /* Read the record header on Alpha.  */
00290   if ((test_len != 0)
00291       && (bfd_bread (PRIV (vms_buf), (bfd_size_type) test_len, abfd)
00292          != (bfd_size_type) test_len))
00293     {
00294       bfd_set_error (bfd_error_file_truncated);
00295       return 0;
00296     }
00297 
00298   /* Check file format on first call.  */
00299   if (PRIV (file_format) == FF_UNKNOWN)
00300     {                                     /* Record length repeats ?  */
00301       if (vms_buf[0] == vms_buf[4]
00302          && vms_buf[1] == vms_buf[5])
00303        {
00304          PRIV (file_format) = FF_FOREIGN; /* Y: foreign environment.  */
00305          test_start = 2;
00306        }
00307       else
00308        {
00309          PRIV (file_format) = FF_NATIVE;  /* N: native environment.  */
00310          test_start = 0;
00311        }
00312     }
00313 
00314   if (PRIV (is_vax))
00315     {
00316       PRIV (rec_length) = bfd_bread (vms_buf, (bfd_size_type) PRIV (buf_size),
00317                                  abfd);
00318       if (PRIV (rec_length) <= 0)
00319        {
00320          bfd_set_error (bfd_error_file_truncated);
00321          return 0;
00322        }
00323       PRIV (vms_rec) = vms_buf;
00324     }
00325   else
00326     {
00327       /* Alpha.   */
00328       /* Extract vms record length.  */
00329 
00330       _bfd_vms_get_header_values (abfd, vms_buf + test_start, NULL,
00331                               & PRIV (rec_length));
00332 
00333       if (PRIV (rec_length) <= 0)
00334        {
00335          bfd_set_error (bfd_error_file_truncated);
00336          return 0;
00337        }
00338 
00339       /* That's what the linker manual says.  */
00340 
00341       if (PRIV (rec_length) > EOBJ_S_C_MAXRECSIZ)
00342        {
00343          bfd_set_error (bfd_error_file_truncated);
00344          return 0;
00345        }
00346 
00347       /* Adjust the buffer.  */
00348 
00349       if (PRIV (rec_length) > PRIV (buf_size))
00350        {
00351          PRIV (vms_buf) = bfd_realloc (vms_buf,
00352                                    (bfd_size_type) PRIV (rec_length));
00353          vms_buf = PRIV (vms_buf);
00354          if (vms_buf == 0)
00355            return -1;
00356          PRIV (buf_size) = PRIV (rec_length);
00357        }
00358 
00359       /* Read the remaining record.  */
00360       remaining = PRIV (rec_length) - test_len + test_start;
00361 
00362 #if VMS_DEBUG
00363       vms_debug (10, "bfd_bread remaining %d\n", remaining);
00364 #endif
00365       if (bfd_bread (vms_buf + test_len, (bfd_size_type) remaining, abfd) !=
00366          (bfd_size_type) remaining)
00367        {
00368          bfd_set_error (bfd_error_file_truncated);
00369          return 0;
00370        }
00371       PRIV (vms_rec) = vms_buf + test_start;
00372     }
00373 
00374 #if VMS_DEBUG
00375   vms_debug (11, "bfd_bread rec_length %d\n", PRIV (rec_length));
00376 #endif
00377 
00378   return PRIV (rec_length);
00379 }
00380 
00381 /* Get next vms record from file
00382    update vms_rec and rec_length to new (remaining) values.  */
00383 
00384 int
00385 _bfd_vms_next_record (bfd * abfd)
00386 {
00387 #if VMS_DEBUG
00388   vms_debug (8, "_bfd_vms_next_record (len %d, size %d)\n",
00389              PRIV (rec_length), PRIV (rec_size));
00390 #endif
00391 
00392   if (PRIV (rec_length) > 0)
00393     PRIV (vms_rec) += PRIV (rec_size);
00394   else
00395     {
00396       if (_bfd_vms_get_record (abfd) <= 0)
00397        return -1;
00398     }
00399 
00400   if (!PRIV (vms_rec) || !PRIV (vms_buf)
00401       || PRIV (vms_rec) >= (PRIV (vms_buf) + PRIV (buf_size)))
00402     return -1;
00403 
00404   if (PRIV (is_vax))
00405     {
00406       PRIV (rec_type) = *(PRIV (vms_rec));
00407       PRIV (rec_size) = PRIV (rec_length);
00408     }
00409   else
00410     _bfd_vms_get_header_values (abfd, PRIV (vms_rec), &PRIV (rec_type),
00411                             &PRIV (rec_size));
00412 
00413   PRIV (rec_length) -= PRIV (rec_size);
00414 
00415 #if VMS_DEBUG
00416   vms_debug (8, "_bfd_vms_next_record: rec %p, size %d, length %d, type %d\n",
00417              PRIV (vms_rec), PRIV (rec_size), PRIV (rec_length),
00418              PRIV (rec_type));
00419 #endif
00420 
00421   return PRIV (rec_type);
00422 }
00423 
00424 /* Copy sized string (string with fixed length) to new allocated area
00425    size is string length (size of record)  */
00426 
00427 char *
00428 _bfd_vms_save_sized_string (unsigned char *str, int size)
00429 {
00430   char *newstr = bfd_malloc ((bfd_size_type) size + 1);
00431 
00432   if (newstr == NULL)
00433     return NULL;
00434   strncpy (newstr, (char *) str, (size_t) size);
00435   newstr[size] = 0;
00436 
00437   return newstr;
00438 }
00439 
00440 /* Copy counted string (string with length at first byte) to new allocated area
00441    ptr points to length byte on entry  */
00442 
00443 char *
00444 _bfd_vms_save_counted_string (unsigned char *ptr)
00445 {
00446   int len = *ptr++;
00447 
00448   return _bfd_vms_save_sized_string (ptr, len);
00449 }
00450 
00451 /* Stack routines for vms ETIR commands.  */
00452 
00453 /* Push value and section index.  */
00454 
00455 void
00456 _bfd_vms_push (bfd * abfd, uquad val, int psect)
00457 {
00458   static int last_psect;
00459 
00460 #if VMS_DEBUG
00461   vms_debug (4, "<push %016lx (%d) at %d>\n", val, psect, PRIV (stackptr));
00462 #endif
00463 
00464   if (psect >= 0)
00465     last_psect = psect;
00466 
00467   PRIV (stack[PRIV (stackptr)]).value = val;
00468   PRIV (stack[PRIV (stackptr)]).psect = last_psect;
00469   PRIV (stackptr)++;
00470   if (PRIV (stackptr) >= STACKSIZE)
00471     {
00472       bfd_set_error (bfd_error_bad_value);
00473       (*_bfd_error_handler) (_("Stack overflow (%d) in _bfd_vms_push"), PRIV (stackptr));
00474       exit (1);
00475     }
00476 }
00477 
00478 /* Pop value and section index.  */
00479 
00480 uquad
00481 _bfd_vms_pop (bfd * abfd, int *psect)
00482 {
00483   uquad value;
00484 
00485   if (PRIV (stackptr) == 0)
00486     {
00487       bfd_set_error (bfd_error_bad_value);
00488       (*_bfd_error_handler) (_("Stack underflow in _bfd_vms_pop"));
00489       exit (1);
00490     }
00491   PRIV (stackptr)--;
00492   value = PRIV (stack[PRIV (stackptr)]).value;
00493   if ((psect != NULL) && (PRIV (stack[PRIV (stackptr)]).psect >= 0))
00494     *psect = PRIV (stack[PRIV (stackptr)]).psect;
00495 
00496 #if VMS_DEBUG
00497   vms_debug (4, "<pop %016lx(%d)>\n", value, PRIV (stack[PRIV (stackptr)]).psect);
00498 #endif
00499 
00500   return value;
00501 }
00502 
00503 /* Object file output functions.  */
00504 
00505 /* GAS tends to write sections in little chunks (bfd_set_section_contents)
00506    which we can't use directly. So we save the little chunks in linked
00507    lists (one per section) and write them later.  */
00508 
00509 /* Add a new vms_section structure to vms_section_table
00510    - forward chaining -.  */
00511 
00512 static vms_section *
00513 add_new_contents (bfd * abfd, sec_ptr section)
00514 {
00515   vms_section *sptr, *newptr;
00516 
00517   sptr = PRIV (vms_section_table)[section->index];
00518   if (sptr != NULL)
00519     return sptr;
00520 
00521   newptr = bfd_alloc (abfd, (bfd_size_type) sizeof (vms_section));
00522   if (newptr == NULL)
00523     return NULL;
00524   newptr->contents = bfd_alloc (abfd, section->size);
00525   if (newptr->contents == NULL)
00526     return NULL;
00527   newptr->offset = 0;
00528   newptr->size = section->size;
00529   newptr->next = 0;
00530   PRIV (vms_section_table)[section->index] = newptr;
00531   return newptr;
00532 }
00533 
00534 /* Save section data & offset to a vms_section structure
00535    vms_section_table[] holds the vms_section chain.  */
00536 
00537 bfd_boolean
00538 _bfd_save_vms_section (bfd * abfd,
00539                      sec_ptr section,
00540                      const void * data,
00541                      file_ptr offset,
00542                      bfd_size_type count)
00543 {
00544   vms_section *sptr;
00545 
00546   if (section->index >= VMS_SECTION_COUNT)
00547     {
00548       bfd_set_error (bfd_error_nonrepresentable_section);
00549       return FALSE;
00550     }
00551   if (count == (bfd_size_type)0)
00552     return TRUE;
00553   sptr = add_new_contents (abfd, section);
00554   if (sptr == NULL)
00555     return FALSE;
00556   memcpy (sptr->contents + offset, data, (size_t) count);
00557 
00558   return TRUE;
00559 }
00560 
00561 /* Get vms_section pointer to saved contents for section # index  */
00562 
00563 vms_section *
00564 _bfd_get_vms_section (bfd * abfd, int index)
00565 {
00566   if (index >=  VMS_SECTION_COUNT)
00567     {
00568       bfd_set_error (bfd_error_nonrepresentable_section);
00569       return NULL;
00570     }
00571   return PRIV (vms_section_table)[index];
00572 }
00573 
00574 /* Object output routines.   */
00575 
00576 /* Begin new record or record header
00577    write 2 bytes rectype
00578    write 2 bytes record length (filled in at flush)
00579    write 2 bytes header type (ommitted if rechead == -1).   */
00580 
00581 void
00582 _bfd_vms_output_begin (bfd * abfd, int rectype, int rechead)
00583 {
00584 #if VMS_DEBUG
00585   vms_debug (6, "_bfd_vms_output_begin (type %d, head %d)\n", rectype,
00586              rechead);
00587 #endif
00588 
00589   _bfd_vms_output_short (abfd, (unsigned int) rectype);
00590 
00591   /* Save current output position to fill in length later.   */
00592 
00593   if (PRIV (push_level) > 0)
00594     PRIV (length_pos) = PRIV (output_size);
00595 
00596 #if VMS_DEBUG
00597   vms_debug (6, "_bfd_vms_output_begin: length_pos = %d\n",
00598              PRIV (length_pos));
00599 #endif
00600 
00601   /* Placeholder for length.  */
00602   _bfd_vms_output_short (abfd, 0);
00603 
00604   if (rechead != -1)
00605     _bfd_vms_output_short (abfd, (unsigned int) rechead);
00606 }
00607 
00608 /* Set record/subrecord alignment.   */
00609 
00610 void
00611 _bfd_vms_output_alignment (bfd * abfd, int alignto)
00612 {
00613 #if VMS_DEBUG
00614   vms_debug (6, "_bfd_vms_output_alignment (%d)\n", alignto);
00615 #endif
00616 
00617   PRIV (output_alignment) = alignto;
00618 }
00619 
00620 /* Prepare for subrecord fields.  */
00621 
00622 void
00623 _bfd_vms_output_push (bfd * abfd)
00624 {
00625 #if VMS_DEBUG
00626   vms_debug (6, "vms_output_push (pushed_size = %d)\n", PRIV (output_size));
00627 #endif
00628 
00629   PRIV (push_level)++;
00630   PRIV (pushed_size) = PRIV (output_size);
00631 }
00632 
00633 /* End of subrecord fields.   */
00634 
00635 void
00636 _bfd_vms_output_pop (bfd * abfd)
00637 {
00638 #if VMS_DEBUG
00639   vms_debug (6, "vms_output_pop (pushed_size = %d)\n", PRIV (pushed_size));
00640 #endif
00641 
00642   _bfd_vms_output_flush (abfd);
00643   PRIV (length_pos) = 2;
00644 
00645 #if VMS_DEBUG
00646   vms_debug (6, "vms_output_pop: length_pos = %d\n", PRIV (length_pos));
00647 #endif
00648 
00649   PRIV (pushed_size) = 0;
00650   PRIV (push_level)--;
00651 }
00652 
00653 /* Flush unwritten output, ends current record.  */
00654 
00655 void
00656 _bfd_vms_output_flush (bfd * abfd)
00657 {
00658   int real_size = PRIV (output_size);
00659   int aligncount;
00660   int length;
00661 
00662 #if VMS_DEBUG
00663   vms_debug (6, "_bfd_vms_output_flush (real_size = %d, pushed_size %d at lenpos %d)\n",
00664              real_size, PRIV (pushed_size), PRIV (length_pos));
00665 #endif
00666 
00667   if (PRIV (push_level) > 0)
00668     length = real_size - PRIV (pushed_size);
00669   else
00670     length = real_size;
00671 
00672   if (length == 0)
00673     return;
00674   aligncount = (PRIV (output_alignment)
00675               - (length % PRIV (output_alignment))) % PRIV (output_alignment);
00676 
00677 #if VMS_DEBUG
00678   vms_debug (6, "align: adding %d bytes\n", aligncount);
00679 #endif
00680 
00681   while (aligncount-- > 0)
00682     {
00683       PRIV (output_buf)[real_size++] = 0;
00684       length++;
00685     }
00686 
00687   /* Put length to buffer.  */
00688   PRIV (output_size) = PRIV (length_pos);
00689   _bfd_vms_output_short (abfd, (unsigned int) length);
00690 
00691   if (PRIV (push_level) == 0)
00692     {
00693 #ifndef VMS
00694        /* Write length first, see FF_FOREIGN in the input routines.  */
00695       fwrite (PRIV (output_buf) + 2, 2, 1, (FILE *) abfd->iostream);
00696 #endif
00697       fwrite (PRIV (output_buf), (size_t) real_size, 1,
00698              (FILE *) abfd->iostream);
00699 
00700       PRIV (output_size) = 0;
00701     }
00702   else
00703     {
00704       PRIV (output_size) = real_size;
00705       PRIV (pushed_size) = PRIV (output_size);
00706     }
00707 }
00708 
00709 /* End record output.   */
00710 
00711 void
00712 _bfd_vms_output_end (bfd * abfd)
00713 {
00714 #if VMS_DEBUG
00715   vms_debug (6, "_bfd_vms_output_end\n");
00716 #endif
00717 
00718   _bfd_vms_output_flush (abfd);
00719 }
00720 
00721 /* Check remaining buffer size
00722 
00723    Return what's left.  */
00724 
00725 int
00726 _bfd_vms_output_check (bfd * abfd, int size)
00727 {
00728 #if VMS_DEBUG
00729   vms_debug (6, "_bfd_vms_output_check (%d)\n", size);
00730 #endif
00731 
00732   return (MAX_OUTREC_SIZE - (PRIV (output_size) + size + MIN_OUTREC_LUFT));
00733 }
00734 
00735 /* Output byte (8 bit) value.  */
00736 
00737 void
00738 _bfd_vms_output_byte (bfd * abfd, unsigned int value)
00739 {
00740 #if VMS_DEBUG
00741   vms_debug (6, "_bfd_vms_output_byte (%02x)\n", value);
00742 #endif
00743 
00744   bfd_put_8 (abfd, value & 0xff, PRIV (output_buf) + PRIV (output_size));
00745   PRIV (output_size) += 1;
00746 }
00747 
00748 /* Output short (16 bit) value.  */
00749 
00750 void
00751 _bfd_vms_output_short (bfd * abfd, unsigned int value)
00752 {
00753 #if VMS_DEBUG
00754   vms_debug (6, "_bfd_vms_output_short (%04x)\n", value);
00755 #endif
00756 
00757   bfd_put_16 (abfd, (bfd_vma) value & 0xffff,
00758              PRIV (output_buf) + PRIV (output_size));
00759   PRIV (output_size) += 2;
00760 }
00761 
00762 /* Output long (32 bit) value.  */
00763 
00764 void
00765 _bfd_vms_output_long (bfd * abfd, unsigned long value)
00766 {
00767 #if VMS_DEBUG
00768   vms_debug (6, "_bfd_vms_output_long (%08lx)\n", value);
00769 #endif
00770 
00771   bfd_put_32 (abfd, (bfd_vma) value, PRIV (output_buf) + PRIV (output_size));
00772   PRIV (output_size) += 4;
00773 }
00774 
00775 /* Output quad (64 bit) value.  */
00776 
00777 void
00778 _bfd_vms_output_quad (bfd * abfd, uquad value)
00779 {
00780 #if VMS_DEBUG
00781   vms_debug (6, "_bfd_vms_output_quad (%016lx)\n", value);
00782 #endif
00783 
00784   bfd_put_64(abfd, value, PRIV (output_buf) + PRIV (output_size));
00785   PRIV (output_size) += 8;
00786 }
00787 
00788 /* Output c-string as counted string.  */
00789 
00790 void
00791 _bfd_vms_output_counted (bfd * abfd, char *value)
00792 {
00793   int len;
00794 
00795 #if VMS_DEBUG
00796   vms_debug (6, "_bfd_vms_output_counted (%s)\n", value);
00797 #endif
00798 
00799   len = strlen (value);
00800   if (len == 0)
00801     {
00802       (*_bfd_error_handler) (_("_bfd_vms_output_counted called with zero bytes"));
00803       return;
00804     }
00805   if (len > 255)
00806     {
00807       (*_bfd_error_handler) (_("_bfd_vms_output_counted called with too many bytes"));
00808       return;
00809     }
00810   _bfd_vms_output_byte (abfd, (unsigned int) len & 0xff);
00811   _bfd_vms_output_dump (abfd, (unsigned char *) value, len);
00812 }
00813 
00814 /* Output character area.  */
00815 
00816 void
00817 _bfd_vms_output_dump (bfd * abfd,
00818                     unsigned char *data,
00819                     int length)
00820 {
00821 #if VMS_DEBUG
00822   vms_debug (6, "_bfd_vms_output_dump (%d)\n", length);
00823 #endif
00824 
00825   if (length == 0)
00826     return;
00827 
00828   memcpy (PRIV (output_buf) + PRIV (output_size), data, (size_t) length);
00829   PRIV (output_size) += length;
00830 }
00831 
00832 /* Output count bytes of value.  */
00833 
00834 void
00835 _bfd_vms_output_fill (bfd * abfd,
00836                     int value,
00837                     int count)
00838 {
00839 #if VMS_DEBUG
00840   vms_debug (6, "_bfd_vms_output_fill (val %02x times %d)\n", value, count);
00841 #endif
00842 
00843   if (count == 0)
00844     return;
00845   memset (PRIV (output_buf) + PRIV (output_size), value, (size_t) count);
00846   PRIV (output_size) += count;
00847 }
00848 
00849 /* This hash routine borrowed from GNU-EMACS, and strengthened slightly.  ERY.  */
00850 
00851 static int
00852 hash_string (const char *ptr)
00853 {
00854   const unsigned char *p = (unsigned char *) ptr;
00855   const unsigned char *end = p + strlen (ptr);
00856   unsigned char c;
00857   int hash = 0;
00858 
00859   while (p != end)
00860     {
00861       c = *p++;
00862       hash = ((hash << 3) + (hash << 15) + (hash >> 28) + c);
00863     }
00864   return hash;
00865 }
00866 
00867 /* Generate a length-hashed VMS symbol name (limited to maxlen chars).  */
00868 
00869 char *
00870 _bfd_vms_length_hash_symbol (bfd * abfd, const char *in, int maxlen)
00871 {
00872   long int result;
00873   int in_len;
00874   char *new_name;
00875   const char *old_name;
00876   int i;
00877   static char outbuf[EOBJ_S_C_SYMSIZ+1];
00878   char *out = outbuf;
00879 
00880 #if VMS_DEBUG
00881   vms_debug (4, "_bfd_vms_length_hash_symbol \"%s\"\n", in);
00882 #endif
00883 
00884   if (maxlen > EOBJ_S_C_SYMSIZ)
00885     maxlen = EOBJ_S_C_SYMSIZ;
00886 
00887   /* Save this for later.  */
00888   new_name = out;
00889 
00890   /* We may need to truncate the symbol, save the hash for later.  */
00891   in_len = strlen (in);
00892 
00893   result = (in_len > maxlen) ? hash_string (in) : 0;
00894 
00895   old_name = in;
00896 
00897   /* Do the length checking.  */
00898   if (in_len <= maxlen)
00899     i = in_len;
00900   else
00901     {
00902       if (PRIV (flag_hash_long_names))
00903        i = maxlen-9;
00904       else
00905        i = maxlen;
00906     }
00907 
00908   strncpy (out, in, (size_t) i);
00909   in += i;
00910   out += i;
00911 
00912   if ((in_len > maxlen)
00913       && PRIV (flag_hash_long_names))
00914     sprintf (out, "_%08lx", result);
00915   else
00916     *out = 0;
00917 
00918 #if VMS_DEBUG
00919   vms_debug (4, "--> [%d]\"%s\"\n", strlen (outbuf), outbuf);
00920 #endif
00921 
00922   if (in_len > maxlen
00923        && PRIV (flag_hash_long_names)
00924        && PRIV (flag_show_after_trunc))
00925     printf (_("Symbol %s replaced by %s\n"), old_name, new_name);
00926 
00927   return outbuf;
00928 }
00929 
00930 /* Allocate and initialize a new symbol.  */
00931 
00932 static asymbol *
00933 new_symbol (bfd * abfd, char *name)
00934 {
00935   asymbol *symbol;
00936 
00937 #if VMS_DEBUG
00938   _bfd_vms_debug (7,  "new_symbol %s\n", name);
00939 #endif
00940 
00941   symbol = bfd_make_empty_symbol (abfd);
00942   if (symbol == 0)
00943     return symbol;
00944   symbol->name = name;
00945   symbol->section = bfd_make_section (abfd, BFD_UND_SECTION_NAME);
00946 
00947   return symbol;
00948 }
00949 
00950 /* Allocate and enter a new private symbol.  */
00951 
00952 vms_symbol_entry *
00953 _bfd_vms_enter_symbol (bfd * abfd, char *name)
00954 {
00955   vms_symbol_entry *entry;
00956 
00957 #if VMS_DEBUG
00958   _bfd_vms_debug (6,  "_bfd_vms_enter_symbol %s\n", name);
00959 #endif
00960 
00961   entry = (vms_symbol_entry *)
00962          bfd_hash_lookup (PRIV (vms_symbol_table), name, FALSE, FALSE);
00963   if (entry == 0)
00964     {
00965 #if VMS_DEBUG
00966       _bfd_vms_debug (8,  "creating hash entry for %s\n", name);
00967 #endif
00968       entry = (vms_symbol_entry *) bfd_hash_lookup (PRIV (vms_symbol_table),
00969                                               name, TRUE, FALSE);
00970       if (entry != 0)
00971        {
00972          asymbol *symbol;
00973          symbol = new_symbol (abfd, name);
00974          if (symbol != 0)
00975            {
00976              entry->symbol = symbol;
00977              PRIV (gsd_sym_count)++;
00978              abfd->symcount++;
00979            }
00980          else
00981            entry = 0;
00982        }
00983       else
00984        (*_bfd_error_handler) (_("failed to enter %s"), name);
00985     }
00986   else
00987     {
00988 #if VMS_DEBUG
00989       _bfd_vms_debug (8,  "found hash entry for %s\n", name);
00990 #endif
00991     }
00992 
00993 #if VMS_DEBUG
00994   _bfd_vms_debug (7, "-> entry %p, entry->symbol %p\n", entry, entry->symbol);
00995 #endif
00996   return entry;
00997 }