Home | History | Annotate | Line # | Download | only in bfd
vms-misc.c revision 1.1.1.8.2.1
      1          1.1  christos /* vms-misc.c -- BFD back-end for VMS/VAX (openVMS/VAX) and
      2          1.1  christos    EVAX (openVMS/Alpha) files.
      3  1.1.1.8.2.1  perseant    Copyright (C) 1996-2024 Free Software Foundation, Inc.
      4          1.1  christos 
      5          1.1  christos    Miscellaneous functions.
      6          1.1  christos 
      7          1.1  christos    Written by Klaus K"ampf (kkaempf (at) rmi.de)
      8          1.1  christos 
      9          1.1  christos    This program is free software; you can redistribute it and/or modify
     10          1.1  christos    it under the terms of the GNU General Public License as published by
     11          1.1  christos    the Free Software Foundation; either version 3 of the License, or
     12          1.1  christos    (at your option) any later version.
     13          1.1  christos 
     14          1.1  christos    This program is distributed in the hope that it will be useful,
     15          1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     16          1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17          1.1  christos    GNU General Public License for more details.
     18          1.1  christos 
     19          1.1  christos    You should have received a copy of the GNU General Public License
     20          1.1  christos    along with this program; if not, write to the Free Software
     21          1.1  christos    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
     22          1.1  christos    MA 02110-1301, USA.  */
     23          1.1  christos 
     24          1.1  christos #if __STDC__
     25          1.1  christos #include <stdarg.h>
     26          1.1  christos #endif
     27          1.1  christos 
     28          1.1  christos #include "sysdep.h"
     29          1.1  christos #include "bfd.h"
     30          1.1  christos #include "bfdlink.h"
     31          1.1  christos #include "libbfd.h"
     32          1.1  christos #include "safe-ctype.h"
     33          1.1  christos 
     34          1.1  christos #ifdef VMS
     35          1.1  christos #define __NEW_STARLET
     36          1.1  christos #include <rms.h>
     37          1.1  christos #include <unixlib.h>
     38          1.1  christos #include <gen64def.h>
     39          1.1  christos #include <starlet.h>
     40          1.1  christos #define RME$C_SETRFM 0x00000001
     41          1.1  christos #include <unistd.h>
     42          1.1  christos #endif
     43          1.1  christos #include <time.h>
     44          1.1  christos 
     45          1.1  christos #include "vms.h"
     46          1.1  christos #include "vms/emh.h"
     47          1.1  christos 
     48          1.1  christos #if VMS_DEBUG
     49          1.1  christos /* Debug functions.  */
     50          1.1  christos 
     51          1.1  christos /* Debug function for all vms extensions evaluates environment
     52          1.1  christos    variable VMS_DEBUG for a numerical value on the first call all
     53          1.1  christos    error levels below this value are printed:
     54          1.1  christos 
     55          1.1  christos    Levels:
     56          1.1  christos    1	toplevel bfd calls (functions from the bfd vector)
     57          1.1  christos    2	functions called by bfd calls
     58          1.1  christos    ...
     59          1.1  christos    9	almost everything
     60          1.1  christos 
     61          1.1  christos    Level is also indentation level. Indentation is performed
     62          1.1  christos    if level > 0.  */
     63          1.1  christos 
     64          1.1  christos void
     65          1.1  christos _bfd_vms_debug (int level, char *format, ...)
     66          1.1  christos {
     67          1.1  christos   static int min_level = -1;
     68          1.1  christos   static FILE *output = NULL;
     69          1.1  christos   char *eptr;
     70          1.1  christos   va_list args;
     71          1.1  christos   int abslvl = (level > 0) ? level : - level;
     72          1.1  christos 
     73          1.1  christos   if (min_level == -1)
     74          1.1  christos     {
     75          1.1  christos       if ((eptr = getenv ("VMS_DEBUG")) != NULL)
     76          1.1  christos 	{
     77          1.1  christos 	  min_level = atoi (eptr);
     78          1.1  christos 	  output = stderr;
     79          1.1  christos 	}
     80          1.1  christos       else
     81          1.1  christos 	min_level = 0;
     82          1.1  christos     }
     83          1.1  christos   if (output == NULL)
     84          1.1  christos     return;
     85          1.1  christos   if (abslvl > min_level)
     86          1.1  christos     return;
     87          1.1  christos 
     88          1.1  christos   while (--level > 0)
     89          1.1  christos     fprintf (output, " ");
     90          1.1  christos   va_start (args, format);
     91          1.1  christos   vfprintf (output, format, args);
     92          1.1  christos   fflush (output);
     93          1.1  christos   va_end (args);
     94          1.1  christos }
     95          1.1  christos 
     96          1.1  christos /* A debug function
     97          1.1  christos    hex dump 'size' bytes starting at 'ptr'.  */
     98          1.1  christos 
     99          1.1  christos void
    100          1.1  christos _bfd_hexdump (int level, unsigned char *ptr, int size, int offset)
    101          1.1  christos {
    102          1.1  christos   unsigned char *lptr = ptr;
    103          1.1  christos   int count = 0;
    104          1.1  christos   long start = offset;
    105          1.1  christos 
    106          1.1  christos   while (size-- > 0)
    107          1.1  christos     {
    108          1.1  christos       if ((count % 16) == 0)
    109          1.1  christos 	vms_debug (level, "%08lx:", start);
    110          1.1  christos       vms_debug (-level, " %02x", *ptr++);
    111          1.1  christos       count++;
    112          1.1  christos       start++;
    113          1.1  christos       if (size == 0)
    114          1.1  christos 	{
    115          1.1  christos 	  while ((count % 16) != 0)
    116          1.1  christos 	    {
    117          1.1  christos 	      vms_debug (-level, "   ");
    118          1.1  christos 	      count++;
    119          1.1  christos 	    }
    120          1.1  christos 	}
    121          1.1  christos       if ((count % 16) == 0)
    122          1.1  christos 	{
    123          1.1  christos 	  vms_debug (-level, " ");
    124          1.1  christos 	  while (lptr < ptr)
    125          1.1  christos 	    {
    126          1.1  christos 	      vms_debug (-level, "%c", (*lptr < 32) ? '.' : *lptr);
    127          1.1  christos 	      lptr++;
    128          1.1  christos 	    }
    129          1.1  christos 	  vms_debug (-level, "\n");
    130          1.1  christos 	}
    131          1.1  christos     }
    132          1.1  christos   if ((count % 16) != 0)
    133          1.1  christos     vms_debug (-level, "\n");
    134          1.1  christos }
    135          1.1  christos #endif
    136          1.1  christos 
    137          1.1  christos 
    139      1.1.1.6  christos /* Copy sized string (string with fixed size) to new allocated area.
    140          1.1  christos    Size is string size (size of record).  */
    141          1.1  christos 
    142      1.1.1.7  christos char *
    143          1.1  christos _bfd_vms_save_sized_string (bfd *abfd, unsigned char *str, size_t size)
    144      1.1.1.7  christos {
    145          1.1  christos   char *newstr;
    146      1.1.1.7  christos 
    147      1.1.1.7  christos   if (size == (size_t) -1)
    148      1.1.1.7  christos     {
    149      1.1.1.7  christos       bfd_set_error (bfd_error_no_memory);
    150      1.1.1.7  christos       return NULL;
    151      1.1.1.7  christos     }
    152          1.1  christos   newstr = bfd_alloc (abfd, size + 1);
    153          1.1  christos   if (newstr == NULL)
    154      1.1.1.7  christos     return NULL;
    155          1.1  christos   memcpy (newstr, str, size);
    156          1.1  christos   newstr[size] = 0;
    157          1.1  christos 
    158          1.1  christos   return newstr;
    159          1.1  christos }
    160      1.1.1.6  christos 
    161      1.1.1.6  christos /* Copy counted string (string with size at first byte) to new allocated area.
    162          1.1  christos    PTR points to size byte on entry.  */
    163          1.1  christos 
    164      1.1.1.7  christos char *
    165          1.1  christos _bfd_vms_save_counted_string (bfd *abfd, unsigned char *ptr, size_t maxlen)
    166      1.1.1.8  christos {
    167          1.1  christos   unsigned int len;
    168      1.1.1.8  christos 
    169      1.1.1.8  christos   if (maxlen == 0)
    170      1.1.1.8  christos     return NULL;
    171      1.1.1.8  christos   len = *ptr++;
    172      1.1.1.6  christos   if (len >  maxlen - 1)
    173      1.1.1.7  christos     return NULL;
    174          1.1  christos   return _bfd_vms_save_sized_string (abfd, ptr, len);
    175          1.1  christos }
    176          1.1  christos 
    177          1.1  christos /* Object output routines.   */
    179          1.1  christos 
    180          1.1  christos /* Begin new record.
    181          1.1  christos    Write 2 bytes rectype and 2 bytes record length.  */
    182          1.1  christos 
    183          1.1  christos void
    184          1.1  christos _bfd_vms_output_begin (struct vms_rec_wr *recwr, int rectype)
    185          1.1  christos {
    186          1.1  christos   vms_debug2 ((6, "_bfd_vms_output_begin (type %d)\n", rectype));
    187          1.1  christos 
    188          1.1  christos   /* Record must have been closed.  */
    189          1.1  christos   BFD_ASSERT (recwr->size == 0);
    190          1.1  christos 
    191          1.1  christos   _bfd_vms_output_short (recwr, (unsigned int) rectype);
    192          1.1  christos 
    193          1.1  christos   /* Placeholder for length.  */
    194          1.1  christos   _bfd_vms_output_short (recwr, 0);
    195          1.1  christos }
    196          1.1  christos 
    197          1.1  christos /* Begin new sub-record.
    198          1.1  christos    Write 2 bytes rectype, and 2 bytes record length.  */
    199          1.1  christos 
    200          1.1  christos void
    201          1.1  christos _bfd_vms_output_begin_subrec (struct vms_rec_wr *recwr, int rectype)
    202          1.1  christos {
    203          1.1  christos   vms_debug2 ((6, "_bfd_vms_output_begin_subrec (type %d)\n", rectype));
    204          1.1  christos 
    205          1.1  christos   /* Subrecord must have been closed.  */
    206          1.1  christos   BFD_ASSERT (recwr->subrec_offset == 0);
    207          1.1  christos 
    208          1.1  christos   /* Save start of subrecord offset.  */
    209          1.1  christos   recwr->subrec_offset = recwr->size;
    210          1.1  christos 
    211          1.1  christos   /* Subrecord type.  */
    212          1.1  christos   _bfd_vms_output_short (recwr, (unsigned int) rectype);
    213          1.1  christos 
    214          1.1  christos   /* Placeholder for length.  */
    215          1.1  christos   _bfd_vms_output_short (recwr, 0);
    216          1.1  christos }
    217          1.1  christos 
    218          1.1  christos /* Set record/subrecord alignment.   */
    219          1.1  christos 
    220          1.1  christos void
    221          1.1  christos _bfd_vms_output_alignment (struct vms_rec_wr *recwr, int alignto)
    222          1.1  christos {
    223          1.1  christos   vms_debug2 ((6, "_bfd_vms_output_alignment (%d)\n", alignto));
    224          1.1  christos   recwr->align = alignto;
    225          1.1  christos }
    226          1.1  christos 
    227          1.1  christos /* Align the size of the current record (whose length is LENGTH).
    228          1.1  christos    Warning: this obviously changes the record (and the possible subrecord)
    229          1.1  christos    length.  */
    230          1.1  christos 
    231          1.1  christos static void
    232          1.1  christos _bfd_vms_output_align (struct vms_rec_wr *recwr, unsigned int length)
    233          1.1  christos {
    234          1.1  christos   unsigned int real_size = recwr->size;
    235          1.1  christos   unsigned int aligncount;
    236          1.1  christos 
    237          1.1  christos   /* Pad with 0 if alignment is required.  */
    238          1.1  christos   aligncount = (recwr->align - (length % recwr->align)) % recwr->align;
    239          1.1  christos   vms_debug2 ((6, "align: adding %d bytes\n", aligncount));
    240          1.1  christos   while (aligncount-- > 0)
    241          1.1  christos     recwr->buf[real_size++] = 0;
    242          1.1  christos 
    243          1.1  christos   recwr->size = real_size;
    244          1.1  christos }
    245          1.1  christos 
    246          1.1  christos /* Ends current sub-record.  Set length field.  */
    247          1.1  christos 
    248          1.1  christos void
    249          1.1  christos _bfd_vms_output_end_subrec (struct vms_rec_wr *recwr)
    250          1.1  christos {
    251          1.1  christos   int real_size = recwr->size;
    252          1.1  christos   int length;
    253          1.1  christos 
    254          1.1  christos   /* Subrecord must be open.  */
    255          1.1  christos   BFD_ASSERT (recwr->subrec_offset != 0);
    256          1.1  christos 
    257          1.1  christos   length = real_size - recwr->subrec_offset;
    258          1.1  christos 
    259          1.1  christos   if (length == 0)
    260          1.1  christos     return;
    261          1.1  christos 
    262          1.1  christos   _bfd_vms_output_align (recwr, length);
    263          1.1  christos 
    264      1.1.1.6  christos   /* Put length to buffer.  */
    265          1.1  christos   bfd_putl16 ((bfd_vma) (recwr->size - recwr->subrec_offset),
    266          1.1  christos 	      recwr->buf + recwr->subrec_offset + 2);
    267          1.1  christos 
    268          1.1  christos   /* Close the subrecord.  */
    269          1.1  christos   recwr->subrec_offset = 0;
    270          1.1  christos }
    271          1.1  christos 
    272  1.1.1.8.2.1  perseant /* Ends current record (and write it).  */
    273          1.1  christos 
    274          1.1  christos bool
    275          1.1  christos _bfd_vms_output_end (bfd *abfd, struct vms_rec_wr *recwr)
    276          1.1  christos {
    277          1.1  christos   vms_debug2 ((6, "_bfd_vms_output_end (size %u)\n", recwr->size));
    278          1.1  christos 
    279          1.1  christos   /* Subrecord must have been closed.  */
    280          1.1  christos   BFD_ASSERT (recwr->subrec_offset == 0);
    281  1.1.1.8.2.1  perseant 
    282          1.1  christos   if (recwr->size == 0)
    283          1.1  christos     return true;
    284          1.1  christos 
    285          1.1  christos   _bfd_vms_output_align (recwr, recwr->size);
    286          1.1  christos 
    287          1.1  christos   /* Write the length word.  */
    288          1.1  christos   bfd_putl16 ((bfd_vma) recwr->size, recwr->buf + 2);
    289          1.1  christos 
    290          1.1  christos   /* File is open in undefined (UDF) format on VMS, but ultimately will be
    291          1.1  christos      converted to variable length (VAR) format.  VAR format has a length
    292  1.1.1.8.2.1  perseant      word first which must be explicitly output in UDF format.  */
    293  1.1.1.8.2.1  perseant   /* So, first the length word.  */
    294          1.1  christos   if (bfd_write (recwr->buf + 2, 2, abfd) != 2)
    295          1.1  christos     return false;
    296          1.1  christos 
    297          1.1  christos   /* Align.  */
    298          1.1  christos   if (recwr->size & 1)
    299          1.1  christos     recwr->buf[recwr->size++] = 0;
    300  1.1.1.8.2.1  perseant 
    301  1.1.1.8.2.1  perseant   /* Then the record.  */
    302  1.1.1.8.2.1  perseant   if (bfd_write (recwr->buf, (size_t) recwr->size, abfd)
    303          1.1  christos       != (size_t) recwr->size)
    304          1.1  christos     return false;
    305  1.1.1.8.2.1  perseant 
    306          1.1  christos   recwr->size = 0;
    307          1.1  christos   return true;
    308          1.1  christos }
    309          1.1  christos 
    310          1.1  christos /* Check remaining buffer size.  Return what's left.  */
    311          1.1  christos 
    312          1.1  christos int
    313          1.1  christos _bfd_vms_output_check (struct vms_rec_wr *recwr, int size)
    314          1.1  christos {
    315          1.1  christos   vms_debug2 ((6, "_bfd_vms_output_check (%d)\n", size));
    316          1.1  christos 
    317          1.1  christos   return (MAX_OUTREC_SIZE - (recwr->size + size + MIN_OUTREC_LUFT));
    318          1.1  christos }
    319          1.1  christos 
    320          1.1  christos /* Output byte (8 bit) value.  */
    321          1.1  christos 
    322          1.1  christos void
    323          1.1  christos _bfd_vms_output_byte (struct vms_rec_wr *recwr, unsigned int value)
    324          1.1  christos {
    325          1.1  christos   vms_debug2 ((6, "_bfd_vms_output_byte (%02x)\n", value));
    326          1.1  christos 
    327          1.1  christos   *(recwr->buf + recwr->size) = value;
    328          1.1  christos   recwr->size += 1;
    329          1.1  christos }
    330          1.1  christos 
    331          1.1  christos /* Output short (16 bit) value.  */
    332          1.1  christos 
    333          1.1  christos void
    334          1.1  christos _bfd_vms_output_short (struct vms_rec_wr *recwr, unsigned int value)
    335          1.1  christos {
    336          1.1  christos   vms_debug2 ((6, "_bfd_vms_output_short (%04x)\n", value));
    337          1.1  christos 
    338          1.1  christos   bfd_putl16 ((bfd_vma) value & 0xffff, recwr->buf + recwr->size);
    339          1.1  christos   recwr->size += 2;
    340          1.1  christos }
    341          1.1  christos 
    342          1.1  christos /* Output long (32 bit) value.  */
    343          1.1  christos 
    344          1.1  christos void
    345          1.1  christos _bfd_vms_output_long (struct vms_rec_wr *recwr, unsigned long value)
    346          1.1  christos {
    347          1.1  christos   vms_debug2 ((6, "_bfd_vms_output_long (%08lx)\n", value));
    348          1.1  christos 
    349          1.1  christos   bfd_putl32 ((bfd_vma) value, recwr->buf + recwr->size);
    350          1.1  christos   recwr->size += 4;
    351          1.1  christos }
    352          1.1  christos 
    353          1.1  christos /* Output quad (64 bit) value.  */
    354          1.1  christos 
    355          1.1  christos void
    356          1.1  christos _bfd_vms_output_quad (struct vms_rec_wr *recwr, bfd_vma value)
    357          1.1  christos {
    358          1.1  christos   vms_debug2 ((6, "_bfd_vms_output_quad (%08lx)\n", (unsigned long)value));
    359          1.1  christos 
    360          1.1  christos   bfd_putl64 (value, recwr->buf + recwr->size);
    361          1.1  christos   recwr->size += 8;
    362          1.1  christos }
    363          1.1  christos 
    364          1.1  christos /* Output c-string as counted string.  */
    365          1.1  christos 
    366          1.1  christos void
    367          1.1  christos _bfd_vms_output_counted (struct vms_rec_wr *recwr, const char *value)
    368          1.1  christos {
    369          1.1  christos   int len;
    370          1.1  christos 
    371          1.1  christos   vms_debug2 ((6, "_bfd_vms_output_counted (%s)\n", value));
    372          1.1  christos 
    373          1.1  christos   len = strlen (value);
    374      1.1.1.5  christos   if (len == 0)
    375          1.1  christos     {
    376          1.1  christos       _bfd_error_handler (_("_bfd_vms_output_counted called with zero bytes"));
    377          1.1  christos       return;
    378          1.1  christos     }
    379      1.1.1.5  christos   if (len > 255)
    380          1.1  christos     {
    381          1.1  christos       _bfd_error_handler (_("_bfd_vms_output_counted called with too many bytes"));
    382          1.1  christos       return;
    383          1.1  christos     }
    384          1.1  christos   _bfd_vms_output_byte (recwr, (unsigned int) len & 0xff);
    385          1.1  christos   _bfd_vms_output_dump (recwr, (const unsigned char *)value, len);
    386          1.1  christos }
    387          1.1  christos 
    388          1.1  christos /* Output character area.  */
    389          1.1  christos 
    390          1.1  christos void
    391          1.1  christos _bfd_vms_output_dump (struct vms_rec_wr *recwr, const unsigned char *data, int len)
    392          1.1  christos {
    393          1.1  christos   vms_debug2 ((6, "_bfd_vms_output_dump (%d)\n", len));
    394          1.1  christos 
    395          1.1  christos   if (len == 0)
    396          1.1  christos     return;
    397          1.1  christos 
    398          1.1  christos   memcpy (recwr->buf + recwr->size, data, (size_t) len);
    399          1.1  christos   recwr->size += len;
    400          1.1  christos }
    401          1.1  christos 
    402          1.1  christos /* Output count bytes of value.  */
    403          1.1  christos 
    404          1.1  christos void
    405          1.1  christos _bfd_vms_output_fill (struct vms_rec_wr *recwr, int value, int count)
    406          1.1  christos {
    407          1.1  christos   vms_debug2 ((6, "_bfd_vms_output_fill (val %02x times %d)\n", value, count));
    408          1.1  christos 
    409          1.1  christos   if (count == 0)
    410          1.1  christos     return;
    411          1.1  christos   memset (recwr->buf + recwr->size, value, (size_t) count);
    412          1.1  christos   recwr->size += count;
    413          1.1  christos }
    414          1.1  christos 
    415          1.1  christos #ifdef VMS
    416          1.1  christos /* Convert the file to variable record length format. This is done
    417          1.1  christos    using undocumented system call sys$modify().
    418          1.1  christos    Pure VMS version.  */
    419          1.1  christos 
    420          1.1  christos static void
    421          1.1  christos vms_convert_to_var (char * vms_filename)
    422          1.1  christos {
    423          1.1  christos   struct FAB fab = cc$rms_fab;
    424          1.1  christos 
    425          1.1  christos   fab.fab$l_fna = vms_filename;
    426          1.1  christos   fab.fab$b_fns = strlen (vms_filename);
    427          1.1  christos   fab.fab$b_fac = FAB$M_PUT;
    428          1.1  christos   fab.fab$l_fop = FAB$M_ESC;
    429          1.1  christos   fab.fab$l_ctx = RME$C_SETRFM;
    430          1.1  christos 
    431          1.1  christos   sys$open (&fab);
    432          1.1  christos 
    433          1.1  christos   fab.fab$b_rfm = FAB$C_VAR;
    434          1.1  christos 
    435          1.1  christos   sys$modify (&fab);
    436          1.1  christos   sys$close (&fab);
    437          1.1  christos }
    438          1.1  christos 
    439          1.1  christos static int
    440          1.1  christos vms_convert_to_var_1 (char *filename, int type)
    441      1.1.1.8  christos {
    442          1.1  christos   if (type != DECC$K_FILE)
    443      1.1.1.8  christos     return false;
    444          1.1  christos   vms_convert_to_var (filename);
    445          1.1  christos   return true;
    446          1.1  christos }
    447          1.1  christos 
    448          1.1  christos /* Convert the file to variable record length format. This is done
    449          1.1  christos    using undocumented system call sys$modify().
    450          1.1  christos    Unix filename version.  */
    451          1.1  christos 
    452          1.1  christos int
    453          1.1  christos _bfd_vms_convert_to_var_unix_filename (const char *unix_filename)
    454      1.1.1.8  christos {
    455      1.1.1.8  christos   if (decc$to_vms (unix_filename, &vms_convert_to_var_1, 0, 1) != 1)
    456          1.1  christos     return false;
    457          1.1  christos   return true;
    458          1.1  christos }
    459          1.1  christos #endif /* VMS */
    460          1.1  christos 
    461          1.1  christos /* Manufacture a VMS like time on a unix based system.
    462          1.1  christos    stolen from obj-vms.c.  */
    463      1.1.1.8  christos 
    464          1.1  christos unsigned char *
    465          1.1  christos get_vms_time_string (unsigned char *tbuf)
    466          1.1  christos {
    467          1.1  christos #ifndef VMS
    468          1.1  christos   char *pnt;
    469          1.1  christos   time_t timeb;
    470          1.1  christos 
    471          1.1  christos   time (& timeb);
    472          1.1  christos   pnt = ctime (&timeb);
    473          1.1  christos   pnt[3] = 0;
    474          1.1  christos   pnt[7] = 0;
    475          1.1  christos   pnt[10] = 0;
    476          1.1  christos   pnt[16] = 0;
    477          1.1  christos   pnt[24] = 0;
    478          1.1  christos   sprintf ((char *) tbuf, "%2s-%3s-%s %s",
    479          1.1  christos 	   pnt + 8, pnt + 4, pnt + 20, pnt + 11);
    480          1.1  christos #else
    481          1.1  christos   struct
    482          1.1  christos   {
    483          1.1  christos     int Size;
    484          1.1  christos     unsigned char *Ptr;
    485          1.1  christos   } Descriptor;
    486          1.1  christos   Descriptor.Size = 17;
    487          1.1  christos   Descriptor.Ptr = tbuf;
    488          1.1  christos   SYS$ASCTIM (0, &Descriptor, 0, 0);
    489          1.1  christos #endif /* not VMS */
    490          1.1  christos 
    491          1.1  christos   vms_debug2 ((6, "vmstimestring:'%s'\n", tbuf));
    492          1.1  christos 
    493          1.1  christos   return tbuf;
    494          1.1  christos }
    495          1.1  christos 
    496          1.1  christos /* Create module name from filename (ie, extract the basename and convert it
    497          1.1  christos    in upper cases).  Works on both VMS and UNIX pathes.
    498          1.1  christos    The result has to be free().  */
    499      1.1.1.8  christos 
    500          1.1  christos char *
    501          1.1  christos vms_get_module_name (const char *filename, bool upcase)
    502          1.1  christos {
    503          1.1  christos   char *fname, *fptr;
    504          1.1  christos   const char *fout;
    505          1.1  christos 
    506          1.1  christos   /* Strip VMS path.  */
    507          1.1  christos   fout = strrchr (filename, ']');
    508          1.1  christos   if (fout == NULL)
    509          1.1  christos     fout = strchr (filename, ':');
    510          1.1  christos   if (fout != NULL)
    511          1.1  christos     fout++;
    512          1.1  christos   else
    513          1.1  christos     fout = filename;
    514          1.1  christos 
    515          1.1  christos   /* Strip UNIX path.  */
    516          1.1  christos   fptr = strrchr (fout, '/');
    517          1.1  christos   if (fptr != NULL)
    518          1.1  christos     fout = fptr + 1;
    519          1.1  christos 
    520          1.1  christos   fname = strdup (fout);
    521          1.1  christos 
    522          1.1  christos   /* Strip suffix.  */
    523          1.1  christos   fptr = strrchr (fname, '.');
    524          1.1  christos   if (fptr != 0)
    525          1.1  christos     *fptr = 0;
    526          1.1  christos 
    527          1.1  christos   /* Convert to upper case and truncate at 31 characters.
    528          1.1  christos      (VMS object file format restricts module name length to 31).  */
    529          1.1  christos   fptr = fname;
    530          1.1  christos   for (fptr = fname; *fptr != 0; fptr++)
    531      1.1.1.6  christos     {
    532      1.1.1.6  christos       if (*fptr == ';' || (fptr - fname) >= 31)
    533      1.1.1.6  christos 	{
    534      1.1.1.6  christos 	  *fptr = 0;
    535          1.1  christos 	  break;
    536      1.1.1.6  christos 	}
    537          1.1  christos       if (upcase)
    538          1.1  christos 	*fptr = TOUPPER (*fptr);
    539          1.1  christos     }
    540          1.1  christos   return fname;
    541          1.1  christos }
    542          1.1  christos 
    543          1.1  christos /* Compared to usual UNIX time_t, VMS time has less limits:
    544          1.1  christos    -  64 bit (63 bits in fact as the MSB must be 0)
    545          1.1  christos    -  100ns granularity
    546      1.1.1.2  christos    -  epoch is Nov 17, 1858.
    547      1.1.1.2  christos    Here has the constants and the routines used to convert VMS from/to UNIX time.
    548      1.1.1.2  christos    The conversion routines don't assume 64 bits arithmetic.
    549      1.1.1.2  christos 
    550          1.1  christos    Here we assume that the definition of time_t is the UNIX one, ie integer
    551          1.1  christos    type, expressing seconds since the epoch.  */
    552          1.1  christos 
    553          1.1  christos /* UNIX time granularity for VMS, ie 1s / 100ns.  */
    554          1.1  christos #define VMS_TIME_FACTOR 10000000
    555          1.1  christos 
    556          1.1  christos /* Number of seconds since VMS epoch of the UNIX epoch.  */
    557          1.1  christos #define VMS_TIME_OFFSET 3506716800U
    558          1.1  christos 
    559          1.1  christos /* Convert a VMS time to a unix time.  */
    560          1.1  christos 
    561          1.1  christos time_t
    562          1.1  christos vms_time_to_time_t (unsigned int hi, unsigned int lo)
    563          1.1  christos {
    564          1.1  christos   unsigned int tmp;
    565      1.1.1.2  christos   unsigned int rlo;
    566          1.1  christos   int i;
    567          1.1  christos   time_t res;
    568          1.1  christos 
    569          1.1  christos   /* First convert to seconds.  */
    570          1.1  christos   tmp = hi % VMS_TIME_FACTOR;
    571          1.1  christos   hi = hi / VMS_TIME_FACTOR;
    572          1.1  christos   rlo = 0;
    573          1.1  christos   for (i = 0; i < 4; i++)
    574          1.1  christos     {
    575          1.1  christos       tmp = (tmp << 8) | (lo >> 24);
    576          1.1  christos       lo <<= 8;
    577          1.1  christos 
    578          1.1  christos       rlo = (rlo << 8) | (tmp / VMS_TIME_FACTOR);
    579          1.1  christos       tmp %= VMS_TIME_FACTOR;
    580          1.1  christos     }
    581          1.1  christos   lo = rlo;
    582      1.1.1.2  christos 
    583      1.1.1.2  christos   /* Return 0 in case of overflow.  */
    584          1.1  christos   if (hi > 1
    585          1.1  christos       || (hi == 1 && lo >= VMS_TIME_OFFSET))
    586          1.1  christos     return 0;
    587      1.1.1.2  christos 
    588          1.1  christos   /* Return 0 in case of underflow.  */
    589          1.1  christos   if (hi == 0 && lo < VMS_TIME_OFFSET)
    590      1.1.1.2  christos     return 0;
    591      1.1.1.2  christos 
    592      1.1.1.2  christos   res = lo - VMS_TIME_OFFSET;
    593      1.1.1.2  christos   if (res <= 0)
    594          1.1  christos     return 0;
    595          1.1  christos   return res;
    596          1.1  christos }
    597          1.1  christos 
    598          1.1  christos /* Convert a time_t to a VMS time.  */
    599          1.1  christos 
    600          1.1  christos void
    601      1.1.1.7  christos vms_time_t_to_vms_time (time_t ut, unsigned int *hi, unsigned int *lo)
    602      1.1.1.7  christos {
    603          1.1  christos   unsigned int val[4];
    604          1.1  christos   unsigned int tmp[4];
    605          1.1  christos   unsigned int carry;
    606          1.1  christos   int i;
    607          1.1  christos 
    608          1.1  christos   /* Put into val.  */
    609          1.1  christos   val[0] = ut & 0xffff;
    610          1.1  christos   val[1] = (ut >> 16) & 0xffff;
    611          1.1  christos   val[2] = sizeof (ut) > 4 ? (ut >> 32) & 0xffff : 0;
    612          1.1  christos   val[3] = sizeof (ut) > 4 ? (ut >> 48) & 0xffff : 0;
    613          1.1  christos 
    614          1.1  christos   /* Add offset.  */
    615          1.1  christos   tmp[0] = VMS_TIME_OFFSET & 0xffff;
    616          1.1  christos   tmp[1] = VMS_TIME_OFFSET >> 16;
    617          1.1  christos   tmp[2] = 0;
    618          1.1  christos   tmp[3] = 0;
    619          1.1  christos   carry = 0;
    620          1.1  christos   for (i = 0; i < 4; i++)
    621          1.1  christos     {
    622          1.1  christos       carry += tmp[i] + val[i];
    623          1.1  christos       val[i] = carry & 0xffff;
    624          1.1  christos       carry = carry >> 16;
    625          1.1  christos     }
    626          1.1  christos 
    627          1.1  christos   /* Multiply by factor, well first by 10000 and then by 1000.  */
    628          1.1  christos   carry = 0;
    629          1.1  christos   for (i = 0; i < 4; i++)
    630          1.1  christos     {
    631          1.1  christos       carry += val[i] * 10000;
    632          1.1  christos       val[i] = carry & 0xffff;
    633          1.1  christos       carry = carry >> 16;
    634          1.1  christos     }
    635          1.1  christos   carry = 0;
    636          1.1  christos   for (i = 0; i < 4; i++)
    637          1.1  christos     {
    638          1.1  christos       carry += val[i] * 1000;
    639          1.1  christos       val[i] = carry & 0xffff;
    640          1.1  christos       carry = carry >> 16;
    641          1.1  christos     }
    642          1.1  christos 
    643          1.1  christos   /* Write the result.  */
    644          1.1  christos   *lo = val[0] | (val[1] << 16);
    645          1.1  christos   *hi = val[2] | (val[3] << 16);
    646          1.1  christos }
    647          1.1  christos 
    648          1.1  christos /* Convert a raw (stored in a buffer) VMS time to a unix time.  */
    649          1.1  christos 
    650          1.1  christos time_t
    651          1.1  christos vms_rawtime_to_time_t (unsigned char *buf)
    652          1.1  christos {
    653          1.1  christos   unsigned int hi = bfd_getl32 (buf + 4);
    654          1.1  christos   unsigned int lo = bfd_getl32 (buf + 0);
    655          1.1  christos 
    656          1.1  christos   return vms_time_to_time_t (hi, lo);
    657          1.1  christos }
    658          1.1  christos 
    659          1.1  christos void
    660          1.1  christos vms_get_time (unsigned int *hi, unsigned int *lo)
    661          1.1  christos {
    662          1.1  christos #ifdef VMS
    663          1.1  christos   struct _generic_64 t;
    664          1.1  christos 
    665          1.1  christos   sys$gettim (&t);
    666          1.1  christos   *lo = t.gen64$q_quadword;
    667          1.1  christos   *hi = t.gen64$q_quadword >> 32;
    668          1.1  christos #else
    669          1.1  christos   time_t t;
    670          1.1  christos 
    671          1.1  christos   time (&t);
    672          1.1  christos   vms_time_t_to_vms_time (t, hi, lo);
    673          1.1  christos #endif
    674          1.1  christos }
    675          1.1  christos 
    676          1.1  christos /* Get the current time into a raw buffer BUF.  */
    677          1.1  christos 
    678          1.1  christos void
    679          1.1  christos vms_raw_get_time (unsigned char *buf)
    680          1.1  christos {
    681          1.1  christos   unsigned int hi, lo;
    682          1.1  christos 
    683          1.1  christos   vms_get_time (&hi, &lo);
    684          1.1  christos   bfd_putl32 (lo, buf + 0);
    685                          bfd_putl32 (hi, buf + 4);
    686                        }
    687