(root)/
binutils-2.41/
gas/
config/
te-vms.c
       1  /* te-vms.c -- Utilities for VMS.
       2     Copyright (C) 2009-2023 Free Software Foundation, Inc.
       3  
       4     Written by Douglas B Rupp <rupp@gnat.com>
       5  
       6     This program is free software; you can redistribute it and/or modify
       7     it under the terms of the GNU General Public License as published by
       8     the Free Software Foundation; either version 3 of the License, or
       9     (at your option) any later version.
      10  
      11     This program is distributed in the hope that it will be useful,
      12     but WITHOUT ANY WARRANTY; without even the implied warranty of
      13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14     GNU General Public License for more details.
      15  
      16     You should have received a copy of the GNU General Public License
      17     along with this program; if not, write to the Free Software
      18     Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
      19  
      20  #include "as.h"
      21  #include "te-vms.h"
      22  
      23  /* The purpose of the two alternate versions below is to have one that
      24     works for native VMS and one that works on an NFS mounted filesystem
      25     (Unix Server/VMS client).  The main issue being to generate the special
      26     VMS file timestamps for the debug info.  */
      27  
      28  #ifdef VMS
      29  #define __NEW_STARLET 1
      30  #include <vms/starlet.h>
      31  #include <vms/rms.h>
      32  #include <vms/atrdef.h>
      33  #include <vms/fibdef.h>
      34  #include <vms/stsdef.h>
      35  #include <vms/iodef.h>
      36  #include <vms/fatdef.h>
      37  #include <errno.h>
      38  #include <vms/descrip.h>
      39  #include <string.h>
      40  #include <unixlib.h>
      41  
      42  #define MAXPATH 256
      43  
      44  /* Descrip.h doesn't have everything...  */
      45  typedef struct fibdef * __fibdef_ptr32 __attribute__ (( mode (SI) ));
      46  
      47  struct dsc$descriptor_fib
      48  {
      49    unsigned int   fib$l_len;
      50    __fibdef_ptr32 fib$l_addr;
      51  };
      52  
      53  /* I/O Status Block.  */
      54  struct IOSB
      55  {
      56    unsigned short status, count;
      57    unsigned int devdep;
      58  };
      59  
      60  static char *tryfile;
      61  
      62  /* Variable length string.  */
      63  struct vstring
      64  {
      65    short length;
      66    char string[NAM$C_MAXRSS+1];
      67  };
      68  
      69  static char filename_buff [MAXPATH];
      70  static char vms_filespec [MAXPATH];
      71  
      72  /* Callback function for filespec style conversion.  */
      73  
      74  static int
      75  translate_unix (char *name, int type ATTRIBUTE_UNUSED)
      76  {
      77    strncpy (filename_buff, name, MAXPATH);
      78    filename_buff [MAXPATH - 1] = (char) 0;
      79    return 0;
      80  }
      81  
      82  /* Wrapper for DECC function that converts a Unix filespec
      83     to VMS style filespec.  */
      84  
      85  static char *
      86  to_vms_file_spec (char *filespec)
      87  {
      88    strncpy (vms_filespec, "", MAXPATH);
      89    decc$to_vms (filespec, translate_unix, 1, 1);
      90    strncpy (vms_filespec, filename_buff, MAXPATH);
      91  
      92    vms_filespec [MAXPATH - 1] = (char) 0;
      93  
      94    return vms_filespec;
      95  }
      96  
      97  #else /* not VMS */
      98  
      99  #define _BSD_SOURCE 1
     100  #include <sys/stat.h>
     101  #include <time.h>
     102  
     103  #define VMS_EPOCH_OFFSET        35067168000000000LL
     104  #define VMS_GRANULARITY_FACTOR  10000000
     105  
     106  #endif /* VMS */
     107  
     108  /* Return VMS file date, size, format, version given a name.  */
     109  
     110  static int
     111  vms_file_stats_name (const char *dirname,
     112                       const char *filename,
     113  		     long long *cdt,
     114  		     long *siz,
     115  		     char *rfo,
     116  		     int *ver)
     117  {
     118    char * fullname;
     119  
     120  #ifdef VMS
     121    struct FAB fab;
     122    struct NAM nam;
     123  
     124    unsigned long long create;
     125    FAT recattr;
     126    char ascnamebuff [256];
     127  
     128    ATRDEF atrlst[]
     129      = {
     130        { ATR$S_CREDATE,  ATR$C_CREDATE,  &create },
     131        { ATR$S_RECATTR,  ATR$C_RECATTR,  &recattr },
     132        { ATR$S_ASCNAME,  ATR$C_ASCNAME,  &ascnamebuff },
     133        { 0, 0, 0}
     134      };
     135  
     136    FIBDEF fib;
     137    struct dsc$descriptor_fib fibdsc = {sizeof (fib), (void *) &fib};
     138  
     139    struct IOSB iosb;
     140  
     141    long status;
     142    unsigned short chan;
     143  
     144    struct vstring file;
     145    struct dsc$descriptor_s filedsc
     146      = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) file.string};
     147    struct vstring device;
     148    struct dsc$descriptor_s devicedsc
     149      = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) device.string};
     150    struct vstring result;
     151    struct dsc$descriptor_s resultdsc
     152      = {NAM$C_MAXRSS, DSC$K_DTYPE_VT, DSC$K_CLASS_VS, (void *) result.string};
     153  
     154    if (strcmp (filename, "<internal>") == 0
     155        || strcmp (filename, "<built-in>") == 0)
     156      {
     157        if (cdt)
     158  	*cdt = 0;
     159  
     160        if (siz)
     161  	*siz = 0;
     162  
     163        if (rfo)
     164  	*rfo = 0;
     165  
     166        if (ver)
     167          *ver = 0;
     168  
     169        return 0;
     170      }
     171  
     172    fullname = concat (dirname, filename, NULL);
     173    tryfile = to_vms_file_spec (fullname);
     174  
     175    /* Allocate and initialize a FAB and NAM structures.  */
     176    fab = cc$rms_fab;
     177    nam = cc$rms_nam;
     178  
     179    nam.nam$l_esa = file.string;
     180    nam.nam$b_ess = NAM$C_MAXRSS;
     181    nam.nam$l_rsa = result.string;
     182    nam.nam$b_rss = NAM$C_MAXRSS;
     183    fab.fab$l_fna = tryfile;
     184    fab.fab$b_fns = strlen (tryfile);
     185    fab.fab$l_nam = &nam;
     186  
     187    /* Validate filespec syntax and device existence.  */
     188    status = SYS$PARSE (&fab, 0, 0);
     189    if ((status & 1) != 1)
     190      {
     191        free (fullname);
     192        return 1;
     193      }
     194  
     195    file.string[nam.nam$b_esl] = 0;
     196  
     197    /* Find matching filespec.  */
     198    status = SYS$SEARCH (&fab, 0, 0);
     199    if ((status & 1) != 1)
     200      {
     201        free (fullname);
     202        return 1;
     203      }
     204  
     205    file.string[nam.nam$b_esl] = 0;
     206    result.string[result.length=nam.nam$b_rsl] = 0;
     207  
     208    /* Get the device name and assign an IO channel.  */
     209    strncpy (device.string, nam.nam$l_dev, nam.nam$b_dev);
     210    devicedsc.dsc$w_length  = nam.nam$b_dev;
     211    chan = 0;
     212    status = SYS$ASSIGN (&devicedsc, &chan, 0, 0, 0);
     213    if ((status & 1) != 1)
     214      {
     215        free (fullname);
     216        return 1;
     217      }
     218  
     219    /* Initialize the FIB and fill in the directory id field.  */
     220    memset (&fib, 0, sizeof (fib));
     221    fib.fib$w_did[0]  = nam.nam$w_did[0];
     222    fib.fib$w_did[1]  = nam.nam$w_did[1];
     223    fib.fib$w_did[2]  = nam.nam$w_did[2];
     224    fib.fib$l_acctl = 0;
     225    fib.fib$l_wcc = 0;
     226    strcpy (file.string, (strrchr (result.string, ']') + 1));
     227    filedsc.dsc$w_length = strlen (file.string);
     228    result.string[result.length = 0] = 0;
     229  
     230    /* Open and close the file to fill in the attributes.  */
     231    status
     232      = SYS$QIOW (0, chan, IO$_ACCESS|IO$M_ACCESS, &iosb, 0, 0,
     233  		&fibdsc, &filedsc, &result.length, &resultdsc, &atrlst, 0);
     234    if ((status & 1) != 1)
     235      {
     236        free (fullname);
     237        return 1;
     238      }
     239  
     240    if ((iosb.status & 1) != 1)
     241      {
     242        free (fullname);
     243        return 1;
     244      }
     245  
     246    result.string[result.length] = 0;
     247    status = SYS$QIOW (0, chan, IO$_DEACCESS, &iosb, 0, 0, &fibdsc, 0, 0, 0,
     248  		     &atrlst, 0);
     249    if ((status & 1) != 1)
     250      {
     251        free (fullname);
     252        return 1;
     253      }
     254  
     255    if ((iosb.status & 1) != 1)
     256      {
     257        free (fullname);
     258        return 1;
     259      }
     260  
     261    /* Deassign the channel and exit.  */
     262    status = SYS$DASSGN (chan);
     263    if ((status & 1) != 1)
     264      {
     265        free (fullname);
     266        return 1;
     267      }
     268  
     269    if (cdt) *cdt = create;
     270    if (siz) *siz = (512 * 65536 * recattr.fat$w_efblkh) +
     271                    (512 * (recattr.fat$w_efblkl - 1)) +
     272                    recattr.fat$w_ffbyte;
     273    if (rfo) *rfo = recattr.fat$v_rtype;
     274    if (ver) *ver = strtol (strrchr (ascnamebuff, ';') + 1, 0, 10);
     275  #else /* not VMS */
     276  
     277    struct stat buff;
     278    struct tm *ts;
     279    long long gmtoff, secs, nsecs;
     280  
     281    fullname = concat (dirname, filename, NULL);
     282  
     283    if ((stat (fullname, &buff)) != 0)
     284      {
     285        free (fullname);
     286        return 1;
     287      }
     288  
     289    if (cdt)
     290      {
     291        ts = localtime (& buff.st_mtime);
     292  
     293  #ifdef HAVE_TM_GMTOFF
     294  	gmtoff = ts->tm_gmtoff;
     295  #else
     296  	{
     297  	  extern long timezone;
     298  
     299  	  if (ts->tm_isdst == 1)
     300  	    gmtoff = - (timezone - 3600);
     301  	  else
     302  	    gmtoff = - timezone;
     303  	}
     304  #endif
     305  
     306  #ifdef HAVE_ST_MTIM_TV_SEC
     307        secs = buff.st_mtim.tv_sec;
     308  #else
     309        secs = buff.st_mtime;
     310  #endif
     311  
     312  #ifdef HAVE_ST_MTIM_TV_NSEC
     313        nsecs = buff.st_mtim.tv_nsec;
     314  #else
     315        nsecs = 0;
     316  #endif
     317  
     318        /* VMS timestamps are stored in local time to 100 nsec accuracy, but by
     319  	 experiment I found timestamps truncated to (at least) microseconds
     320  	 on an NFS mounted filesystem, hence the adjustment below. DBR. */
     321        *cdt = ((secs + gmtoff) * VMS_GRANULARITY_FACTOR)
     322  	+ (nsecs / 1000 * 10) + VMS_EPOCH_OFFSET;
     323      }
     324  
     325    if (siz)
     326      *siz = buff.st_size;
     327  
     328    if (rfo)
     329      *rfo = 2; /* Stream LF format.  */
     330  
     331    /* Returning a file version of 0 is never correct for debug info, version 1
     332       will be correct if file editing is done only on the Unix side.  If editing
     333       is done on the VMS side, then its TBD.  */
     334    if (ver)
     335      *ver = 1;
     336  #endif /* VMS */
     337  
     338    free (fullname);
     339    return 0;
     340  }
     341  
     342  uint64_t
     343  vms_dwarf2_file_time_name (const char *filename, const char *dirname)
     344  {
     345    long long cdt;
     346  
     347    if (vms_file_stats_name (dirname, filename, &cdt, 0, 0, 0) == 0)
     348      return cdt;
     349    else
     350      return 0;
     351  }
     352  
     353  long
     354  vms_dwarf2_file_size_name (const char *filename, const char *dirname)
     355  {
     356    long siz;
     357  
     358    if (vms_file_stats_name (dirname, filename, 0, &siz, 0, 0) == 0)
     359      return siz;
     360    else
     361      return 0;
     362  }
     363  
     364  /* VMS debugger needs the filename with version appended.  */
     365  /* Longest filename on VMS is 255 characters. Largest version is 32768.  */
     366  char *
     367  vms_dwarf2_file_name (const char *filename, const char *dirname)
     368  {
     369    int ver;
     370    static char buff [255 + 7];
     371  
     372    vms_file_stats_name (dirname, filename, 0, 0, 0, &ver);
     373    snprintf (buff, 255 + 7, "%s;%d", filename, ver);
     374    return buff;
     375  }