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.10 christos Copyright (C) 1996-2025 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.9 christos /* 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.9 christos 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.9 christos word first which must be explicitly output in UDF format. */ 293 1.1.1.9 christos /* 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.9 christos 301 1.1.1.9 christos /* Then the record. */ 302 1.1.1.9 christos 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.9 christos 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