/* vms-misc.c -- BFD back-end for VMS/VAX (openVMS/VAX) and
EVAX (openVMS/Alpha) files.
- Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
- 2007, 2008, 2009 Free Software Foundation, Inc.
+ Copyright (C) 1996-2020 Free Software Foundation, Inc.
Miscellaneous functions.
#include "safe-ctype.h"
#ifdef VMS
+#define __NEW_STARLET
#include <rms.h>
#include <unixlib.h>
+#include <gen64def.h>
#include <starlet.h>
#define RME$C_SETRFM 0x00000001
#include <unistd.h>
#endif
\f
-/* Copy sized string (string with fixed size) to new allocated area
- size is string size (size of record) */
+/* Copy sized string (string with fixed size) to new allocated area.
+ Size is string size (size of record). */
char *
-_bfd_vms_save_sized_string (unsigned char *str, int size)
+_bfd_vms_save_sized_string (bfd *abfd, unsigned char *str, size_t size)
{
- char *newstr = bfd_malloc ((bfd_size_type) size + 1);
+ char *newstr;
+ if (size == (size_t) -1)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
+ newstr = bfd_alloc (abfd, size + 1);
if (newstr == NULL)
return NULL;
- memcpy (newstr, (char *) str, (size_t) size);
+ memcpy (newstr, str, size);
newstr[size] = 0;
return newstr;
}
-/* Copy counted string (string with size at first byte) to new allocated area
- ptr points to size byte on entry */
+/* Copy counted string (string with size at first byte) to new allocated area.
+ PTR points to size byte on entry. */
char *
-_bfd_vms_save_counted_string (unsigned char *ptr)
+_bfd_vms_save_counted_string (bfd *abfd, unsigned char *ptr, size_t maxlen)
{
- int len = *ptr++;
+ unsigned int len = *ptr++;
- return _bfd_vms_save_sized_string (ptr, len);
+ if (len > maxlen)
+ return NULL;
+ return _bfd_vms_save_sized_string (abfd, ptr, len);
}
\f
/* Object output routines. */
/* Put length to buffer. */
bfd_putl16 ((bfd_vma) (recwr->size - recwr->subrec_offset),
- recwr->buf + recwr->subrec_offset + 2);
+ recwr->buf + recwr->subrec_offset + 2);
/* Close the subrecord. */
recwr->subrec_offset = 0;
/* Output c-string as counted string. */
void
-_bfd_vms_output_counted (struct vms_rec_wr *recwr, char *value)
+_bfd_vms_output_counted (struct vms_rec_wr *recwr, const char *value)
{
int len;
len = strlen (value);
if (len == 0)
{
- (*_bfd_error_handler) (_("_bfd_vms_output_counted called with zero bytes"));
+ _bfd_error_handler (_("_bfd_vms_output_counted called with zero bytes"));
return;
}
if (len > 255)
{
- (*_bfd_error_handler) (_("_bfd_vms_output_counted called with too many bytes"));
+ _bfd_error_handler (_("_bfd_vms_output_counted called with too many bytes"));
return;
}
_bfd_vms_output_byte (recwr, (unsigned int) len & 0xff);
- _bfd_vms_output_dump (recwr, (unsigned char *) value, len);
+ _bfd_vms_output_dump (recwr, (const unsigned char *)value, len);
}
/* Output character area. */
void
-_bfd_vms_output_dump (struct vms_rec_wr *recwr, unsigned char *data, int len)
+_bfd_vms_output_dump (struct vms_rec_wr *recwr, const unsigned char *data, int len)
{
vms_debug2 ((6, "_bfd_vms_output_dump (%d)\n", len));
Pure VMS version. */
static void
-vms_convert_to_var (char *vms_filename)
+vms_convert_to_var (char * vms_filename)
{
struct FAB fab = cc$rms_fab;
using undocumented system call sys$modify().
Unix filename version. */
-static int
-vms_convert_to_var_unix_filename (const char *unix_filename)
+int
+_bfd_vms_convert_to_var_unix_filename (const char *unix_filename)
{
if (decc$to_vms (unix_filename, &vms_convert_to_var_1, 0, 1) != 1)
return FALSE;
fout++;
else
fout = filename;
-
+
/* Strip UNIX path. */
fptr = strrchr (fout, '/');
if (fptr != NULL)
fout = fptr + 1;
-
+
fname = strdup (fout);
/* Strip suffix. */
fptr = strrchr (fname, '.');
if (fptr != 0)
*fptr = 0;
-
+
/* Convert to upper case and truncate at 31 characters.
(VMS object file format restricts module name length to 31). */
fptr = fname;
for (fptr = fname; *fptr != 0; fptr++)
{
if (*fptr == ';' || (fptr - fname) >= 31)
- {
- *fptr = 0;
- break;
- }
+ {
+ *fptr = 0;
+ break;
+ }
if (upcase)
- *fptr = TOUPPER (*fptr);
+ *fptr = TOUPPER (*fptr);
}
return fname;
}
-/* Convert a raw VMS time to a unix time. */
+/* Compared to usual UNIX time_t, VMS time has less limits:
+ - 64 bit (63 bits in fact as the MSB must be 0)
+ - 100ns granularity
+ - epoch is Nov 17, 1858.
+ Here has the constants and the routines used to convert VMS from/to UNIX time.
+ The conversion routines don't assume 64 bits arithmetic.
+
+ Here we assume that the definition of time_t is the UNIX one, ie integer
+ type, expressing seconds since the epoch. */
+
+/* UNIX time granularity for VMS, ie 1s / 100ns. */
+#define VMS_TIME_FACTOR 10000000
+
+/* Number of seconds since VMS epoch of the UNIX epoch. */
+#define VMS_TIME_OFFSET 3506716800U
+
+/* Convert a VMS time to a unix time. */
time_t
vms_time_to_time_t (unsigned int hi, unsigned int lo)
{
- const unsigned int off = 3506716800U;
- const unsigned int factor = 10000000;
unsigned int tmp;
unsigned int rlo;
int i;
+ time_t res;
/* First convert to seconds. */
- tmp = hi % factor;
- hi = hi / factor;
+ tmp = hi % VMS_TIME_FACTOR;
+ hi = hi / VMS_TIME_FACTOR;
rlo = 0;
for (i = 0; i < 4; i++)
{
tmp = (tmp << 8) | (lo >> 24);
lo <<= 8;
- rlo = (rlo << 8) | (tmp / factor);
- tmp %= factor;
+ rlo = (rlo << 8) | (tmp / VMS_TIME_FACTOR);
+ tmp %= VMS_TIME_FACTOR;
}
lo = rlo;
/* Return 0 in case of overflow. */
- if (lo > off && hi > 1)
+ if (hi > 1
+ || (hi == 1 && lo >= VMS_TIME_OFFSET))
+ return 0;
+
+ /* Return 0 in case of underflow. */
+ if (hi == 0 && lo < VMS_TIME_OFFSET)
return 0;
- return lo - off;
+ res = lo - VMS_TIME_OFFSET;
+ if (res <= 0)
+ return 0;
+ return res;
+}
+
+/* Convert a time_t to a VMS time. */
+
+void
+vms_time_t_to_vms_time (time_t ut, unsigned int *hi, unsigned int *lo)
+{
+ unsigned short val[4];
+ unsigned short tmp[4];
+ unsigned int carry;
+ int i;
+
+ /* Put into val. */
+ val[0] = ut & 0xffff;
+ val[1] = (ut >> 16) & 0xffff;
+ val[2] = sizeof (ut) > 4 ? (ut >> 32) & 0xffff : 0;
+ val[3] = sizeof (ut) > 4 ? (ut >> 48) & 0xffff : 0;
+
+ /* Add offset. */
+ tmp[0] = VMS_TIME_OFFSET & 0xffff;
+ tmp[1] = VMS_TIME_OFFSET >> 16;
+ tmp[2] = 0;
+ tmp[3] = 0;
+ carry = 0;
+ for (i = 0; i < 4; i++)
+ {
+ carry += tmp[i] + val[i];
+ val[i] = carry & 0xffff;
+ carry = carry >> 16;
+ }
+
+ /* Multiply by factor, well first by 10000 and then by 1000. */
+ carry = 0;
+ for (i = 0; i < 4; i++)
+ {
+ carry += val[i] * 10000;
+ val[i] = carry & 0xffff;
+ carry = carry >> 16;
+ }
+ carry = 0;
+ for (i = 0; i < 4; i++)
+ {
+ carry += val[i] * 1000;
+ val[i] = carry & 0xffff;
+ carry = carry >> 16;
+ }
+
+ /* Write the result. */
+ *lo = val[0] | (val[1] << 16);
+ *hi = val[2] | (val[3] << 16);
}
/* Convert a raw (stored in a buffer) VMS time to a unix time. */
return vms_time_to_time_t (hi, lo);
}
+
+void
+vms_get_time (unsigned int *hi, unsigned int *lo)
+{
+#ifdef VMS
+ struct _generic_64 t;
+
+ sys$gettim (&t);
+ *lo = t.gen64$q_quadword;
+ *hi = t.gen64$q_quadword >> 32;
+#else
+ time_t t;
+
+ time (&t);
+ vms_time_t_to_vms_time (t, hi, lo);
+#endif
+}
+
+/* Get the current time into a raw buffer BUF. */
+
+void
+vms_raw_get_time (unsigned char *buf)
+{
+ unsigned int hi, lo;
+
+ vms_get_time (&hi, &lo);
+ bfd_putl32 (lo, buf + 0);
+ bfd_putl32 (hi, buf + 4);
+}