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