vms-misc.c revision 1.10 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.10 christos Copyright (C) 1996-2022 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.8 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.9 christos char *
143 1.1 christos _bfd_vms_save_sized_string (bfd *abfd, unsigned char *str, size_t size)
144 1.9 christos {
145 1.1 christos char *newstr;
146 1.9 christos
147 1.9 christos if (size == (size_t) -1)
148 1.9 christos {
149 1.9 christos bfd_set_error (bfd_error_no_memory);
150 1.9 christos return NULL;
151 1.9 christos }
152 1.1 christos newstr = bfd_alloc (abfd, size + 1);
153 1.1 christos if (newstr == NULL)
154 1.9 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.8 christos
161 1.8 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.9 christos char *
165 1.1 christos _bfd_vms_save_counted_string (bfd *abfd, unsigned char *ptr, size_t maxlen)
166 1.10 christos {
167 1.1 christos unsigned int len;
168 1.10 christos
169 1.10 christos if (maxlen == 0)
170 1.10 christos return NULL;
171 1.10 christos len = *ptr++;
172 1.8 christos if (len > maxlen - 1)
173 1.9 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.8 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 christos /* Ends current record (and write it). */
273 1.1 christos
274 1.1 christos void
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 christos
282 1.1 christos if (recwr->size == 0)
283 1.1 christos return;
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 christos word first which must be explicitly output in UDF format. */
293 1.1 christos /* So, first the length word. */
294 1.1 christos bfd_bwrite (recwr->buf + 2, 2, abfd);
295 1.1 christos
296 1.1 christos /* Align. */
297 1.1 christos if (recwr->size & 1)
298 1.1 christos recwr->buf[recwr->size++] = 0;
299 1.1 christos
300 1.1 christos /* Then the record. */
301 1.1 christos bfd_bwrite (recwr->buf, (size_t) recwr->size, abfd);
302 1.1 christos
303 1.1 christos recwr->size = 0;
304 1.1 christos }
305 1.1 christos
306 1.1 christos /* Check remaining buffer size. Return what's left. */
307 1.1 christos
308 1.1 christos int
309 1.1 christos _bfd_vms_output_check (struct vms_rec_wr *recwr, int size)
310 1.1 christos {
311 1.1 christos vms_debug2 ((6, "_bfd_vms_output_check (%d)\n", size));
312 1.1 christos
313 1.1 christos return (MAX_OUTREC_SIZE - (recwr->size + size + MIN_OUTREC_LUFT));
314 1.1 christos }
315 1.1 christos
316 1.1 christos /* Output byte (8 bit) value. */
317 1.1 christos
318 1.1 christos void
319 1.1 christos _bfd_vms_output_byte (struct vms_rec_wr *recwr, unsigned int value)
320 1.1 christos {
321 1.1 christos vms_debug2 ((6, "_bfd_vms_output_byte (%02x)\n", value));
322 1.1 christos
323 1.1 christos *(recwr->buf + recwr->size) = value;
324 1.1 christos recwr->size += 1;
325 1.1 christos }
326 1.1 christos
327 1.1 christos /* Output short (16 bit) value. */
328 1.1 christos
329 1.1 christos void
330 1.1 christos _bfd_vms_output_short (struct vms_rec_wr *recwr, unsigned int value)
331 1.1 christos {
332 1.1 christos vms_debug2 ((6, "_bfd_vms_output_short (%04x)\n", value));
333 1.1 christos
334 1.1 christos bfd_putl16 ((bfd_vma) value & 0xffff, recwr->buf + recwr->size);
335 1.1 christos recwr->size += 2;
336 1.1 christos }
337 1.1 christos
338 1.1 christos /* Output long (32 bit) value. */
339 1.1 christos
340 1.1 christos void
341 1.1 christos _bfd_vms_output_long (struct vms_rec_wr *recwr, unsigned long value)
342 1.1 christos {
343 1.1 christos vms_debug2 ((6, "_bfd_vms_output_long (%08lx)\n", value));
344 1.1 christos
345 1.1 christos bfd_putl32 ((bfd_vma) value, recwr->buf + recwr->size);
346 1.1 christos recwr->size += 4;
347 1.1 christos }
348 1.1 christos
349 1.1 christos /* Output quad (64 bit) value. */
350 1.1 christos
351 1.1 christos void
352 1.1 christos _bfd_vms_output_quad (struct vms_rec_wr *recwr, bfd_vma value)
353 1.1 christos {
354 1.1 christos vms_debug2 ((6, "_bfd_vms_output_quad (%08lx)\n", (unsigned long)value));
355 1.1 christos
356 1.1 christos bfd_putl64 (value, recwr->buf + recwr->size);
357 1.1 christos recwr->size += 8;
358 1.1 christos }
359 1.1 christos
360 1.1 christos /* Output c-string as counted string. */
361 1.1 christos
362 1.1 christos void
363 1.1 christos _bfd_vms_output_counted (struct vms_rec_wr *recwr, const char *value)
364 1.1 christos {
365 1.1 christos int len;
366 1.1 christos
367 1.1 christos vms_debug2 ((6, "_bfd_vms_output_counted (%s)\n", value));
368 1.1 christos
369 1.1 christos len = strlen (value);
370 1.7 christos if (len == 0)
371 1.1 christos {
372 1.1 christos _bfd_error_handler (_("_bfd_vms_output_counted called with zero bytes"));
373 1.1 christos return;
374 1.1 christos }
375 1.7 christos if (len > 255)
376 1.1 christos {
377 1.1 christos _bfd_error_handler (_("_bfd_vms_output_counted called with too many bytes"));
378 1.1 christos return;
379 1.1 christos }
380 1.1 christos _bfd_vms_output_byte (recwr, (unsigned int) len & 0xff);
381 1.1 christos _bfd_vms_output_dump (recwr, (const unsigned char *)value, len);
382 1.1 christos }
383 1.1 christos
384 1.1 christos /* Output character area. */
385 1.1 christos
386 1.1 christos void
387 1.1 christos _bfd_vms_output_dump (struct vms_rec_wr *recwr, const unsigned char *data, int len)
388 1.1 christos {
389 1.1 christos vms_debug2 ((6, "_bfd_vms_output_dump (%d)\n", len));
390 1.1 christos
391 1.1 christos if (len == 0)
392 1.1 christos return;
393 1.1 christos
394 1.1 christos memcpy (recwr->buf + recwr->size, data, (size_t) len);
395 1.1 christos recwr->size += len;
396 1.1 christos }
397 1.1 christos
398 1.1 christos /* Output count bytes of value. */
399 1.1 christos
400 1.1 christos void
401 1.1 christos _bfd_vms_output_fill (struct vms_rec_wr *recwr, int value, int count)
402 1.1 christos {
403 1.1 christos vms_debug2 ((6, "_bfd_vms_output_fill (val %02x times %d)\n", value, count));
404 1.1 christos
405 1.1 christos if (count == 0)
406 1.1 christos return;
407 1.1 christos memset (recwr->buf + recwr->size, value, (size_t) count);
408 1.1 christos recwr->size += count;
409 1.1 christos }
410 1.1 christos
411 1.1 christos #ifdef VMS
412 1.1 christos /* Convert the file to variable record length format. This is done
413 1.1 christos using undocumented system call sys$modify().
414 1.1 christos Pure VMS version. */
415 1.1 christos
416 1.1 christos static void
417 1.1 christos vms_convert_to_var (char * vms_filename)
418 1.1 christos {
419 1.1 christos struct FAB fab = cc$rms_fab;
420 1.1 christos
421 1.1 christos fab.fab$l_fna = vms_filename;
422 1.1 christos fab.fab$b_fns = strlen (vms_filename);
423 1.1 christos fab.fab$b_fac = FAB$M_PUT;
424 1.1 christos fab.fab$l_fop = FAB$M_ESC;
425 1.1 christos fab.fab$l_ctx = RME$C_SETRFM;
426 1.1 christos
427 1.1 christos sys$open (&fab);
428 1.1 christos
429 1.1 christos fab.fab$b_rfm = FAB$C_VAR;
430 1.1 christos
431 1.1 christos sys$modify (&fab);
432 1.1 christos sys$close (&fab);
433 1.1 christos }
434 1.1 christos
435 1.1 christos static int
436 1.1 christos vms_convert_to_var_1 (char *filename, int type)
437 1.10 christos {
438 1.1 christos if (type != DECC$K_FILE)
439 1.10 christos return false;
440 1.1 christos vms_convert_to_var (filename);
441 1.1 christos return true;
442 1.1 christos }
443 1.1 christos
444 1.1 christos /* Convert the file to variable record length format. This is done
445 1.1 christos using undocumented system call sys$modify().
446 1.1 christos Unix filename version. */
447 1.1 christos
448 1.1 christos int
449 1.1 christos _bfd_vms_convert_to_var_unix_filename (const char *unix_filename)
450 1.10 christos {
451 1.10 christos if (decc$to_vms (unix_filename, &vms_convert_to_var_1, 0, 1) != 1)
452 1.1 christos return false;
453 1.1 christos return true;
454 1.1 christos }
455 1.1 christos #endif /* VMS */
456 1.1 christos
457 1.1 christos /* Manufacture a VMS like time on a unix based system.
458 1.1 christos stolen from obj-vms.c. */
459 1.10 christos
460 1.1 christos unsigned char *
461 1.1 christos get_vms_time_string (unsigned char *tbuf)
462 1.1 christos {
463 1.1 christos #ifndef VMS
464 1.1 christos char *pnt;
465 1.1 christos time_t timeb;
466 1.1 christos
467 1.1 christos time (& timeb);
468 1.1 christos pnt = ctime (&timeb);
469 1.1 christos pnt[3] = 0;
470 1.1 christos pnt[7] = 0;
471 1.1 christos pnt[10] = 0;
472 1.1 christos pnt[16] = 0;
473 1.1 christos pnt[24] = 0;
474 1.1 christos sprintf ((char *) tbuf, "%2s-%3s-%s %s",
475 1.1 christos pnt + 8, pnt + 4, pnt + 20, pnt + 11);
476 1.1 christos #else
477 1.1 christos struct
478 1.1 christos {
479 1.1 christos int Size;
480 1.1 christos unsigned char *Ptr;
481 1.1 christos } Descriptor;
482 1.1 christos Descriptor.Size = 17;
483 1.1 christos Descriptor.Ptr = tbuf;
484 1.1 christos SYS$ASCTIM (0, &Descriptor, 0, 0);
485 1.1 christos #endif /* not VMS */
486 1.1 christos
487 1.1 christos vms_debug2 ((6, "vmstimestring:'%s'\n", tbuf));
488 1.1 christos
489 1.1 christos return tbuf;
490 1.1 christos }
491 1.1 christos
492 1.1 christos /* Create module name from filename (ie, extract the basename and convert it
493 1.1 christos in upper cases). Works on both VMS and UNIX pathes.
494 1.1 christos The result has to be free(). */
495 1.10 christos
496 1.1 christos char *
497 1.1 christos vms_get_module_name (const char *filename, bool upcase)
498 1.1 christos {
499 1.1 christos char *fname, *fptr;
500 1.1 christos const char *fout;
501 1.1 christos
502 1.1 christos /* Strip VMS path. */
503 1.1 christos fout = strrchr (filename, ']');
504 1.1 christos if (fout == NULL)
505 1.1 christos fout = strchr (filename, ':');
506 1.1 christos if (fout != NULL)
507 1.1 christos fout++;
508 1.1 christos else
509 1.1 christos fout = filename;
510 1.1 christos
511 1.1 christos /* Strip UNIX path. */
512 1.1 christos fptr = strrchr (fout, '/');
513 1.1 christos if (fptr != NULL)
514 1.1 christos fout = fptr + 1;
515 1.1 christos
516 1.1 christos fname = strdup (fout);
517 1.1 christos
518 1.1 christos /* Strip suffix. */
519 1.1 christos fptr = strrchr (fname, '.');
520 1.1 christos if (fptr != 0)
521 1.1 christos *fptr = 0;
522 1.1 christos
523 1.1 christos /* Convert to upper case and truncate at 31 characters.
524 1.1 christos (VMS object file format restricts module name length to 31). */
525 1.1 christos fptr = fname;
526 1.1 christos for (fptr = fname; *fptr != 0; fptr++)
527 1.8 christos {
528 1.8 christos if (*fptr == ';' || (fptr - fname) >= 31)
529 1.8 christos {
530 1.8 christos *fptr = 0;
531 1.1 christos break;
532 1.8 christos }
533 1.1 christos if (upcase)
534 1.1 christos *fptr = TOUPPER (*fptr);
535 1.1 christos }
536 1.1 christos return fname;
537 1.1 christos }
538 1.1 christos
539 1.1 christos /* Compared to usual UNIX time_t, VMS time has less limits:
540 1.1 christos - 64 bit (63 bits in fact as the MSB must be 0)
541 1.1 christos - 100ns granularity
542 1.1 christos - epoch is Nov 17, 1858.
543 1.1 christos Here has the constants and the routines used to convert VMS from/to UNIX time.
544 1.1 christos The conversion routines don't assume 64 bits arithmetic.
545 1.1 christos
546 1.1 christos Here we assume that the definition of time_t is the UNIX one, ie integer
547 1.1 christos type, expressing seconds since the epoch. */
548 1.1 christos
549 1.1 christos /* UNIX time granularity for VMS, ie 1s / 100ns. */
550 1.1 christos #define VMS_TIME_FACTOR 10000000
551 1.1 christos
552 1.1 christos /* Number of seconds since VMS epoch of the UNIX epoch. */
553 1.1 christos #define VMS_TIME_OFFSET 3506716800U
554 1.1 christos
555 1.1 christos /* Convert a VMS time to a unix time. */
556 1.1 christos
557 1.1 christos time_t
558 1.1 christos vms_time_to_time_t (unsigned int hi, unsigned int lo)
559 1.1 christos {
560 1.1 christos unsigned int tmp;
561 1.1 christos unsigned int rlo;
562 1.1 christos int i;
563 1.1 christos time_t res;
564 1.1 christos
565 1.1 christos /* First convert to seconds. */
566 1.1 christos tmp = hi % VMS_TIME_FACTOR;
567 1.1 christos hi = hi / VMS_TIME_FACTOR;
568 1.1 christos rlo = 0;
569 1.1 christos for (i = 0; i < 4; i++)
570 1.1 christos {
571 1.1 christos tmp = (tmp << 8) | (lo >> 24);
572 1.1 christos lo <<= 8;
573 1.1 christos
574 1.1 christos rlo = (rlo << 8) | (tmp / VMS_TIME_FACTOR);
575 1.1 christos tmp %= VMS_TIME_FACTOR;
576 1.1 christos }
577 1.1 christos lo = rlo;
578 1.1 christos
579 1.1 christos /* Return 0 in case of overflow. */
580 1.1 christos if (hi > 1
581 1.1 christos || (hi == 1 && lo >= VMS_TIME_OFFSET))
582 1.1 christos return 0;
583 1.1 christos
584 1.1 christos /* Return 0 in case of underflow. */
585 1.1 christos if (hi == 0 && lo < VMS_TIME_OFFSET)
586 1.1 christos return 0;
587 1.1 christos
588 1.1 christos res = lo - VMS_TIME_OFFSET;
589 1.1 christos if (res <= 0)
590 1.1 christos return 0;
591 1.1 christos return res;
592 1.1 christos }
593 1.1 christos
594 1.1 christos /* Convert a time_t to a VMS time. */
595 1.1 christos
596 1.1 christos void
597 1.9 christos vms_time_t_to_vms_time (time_t ut, unsigned int *hi, unsigned int *lo)
598 1.9 christos {
599 1.1 christos unsigned int val[4];
600 1.1 christos unsigned int tmp[4];
601 1.1 christos unsigned int carry;
602 1.1 christos int i;
603 1.1 christos
604 1.1 christos /* Put into val. */
605 1.1 christos val[0] = ut & 0xffff;
606 1.1 christos val[1] = (ut >> 16) & 0xffff;
607 1.1 christos val[2] = sizeof (ut) > 4 ? (ut >> 32) & 0xffff : 0;
608 1.1 christos val[3] = sizeof (ut) > 4 ? (ut >> 48) & 0xffff : 0;
609 1.1 christos
610 1.1 christos /* Add offset. */
611 1.1 christos tmp[0] = VMS_TIME_OFFSET & 0xffff;
612 1.1 christos tmp[1] = VMS_TIME_OFFSET >> 16;
613 1.1 christos tmp[2] = 0;
614 1.1 christos tmp[3] = 0;
615 1.1 christos carry = 0;
616 1.1 christos for (i = 0; i < 4; i++)
617 1.1 christos {
618 1.1 christos carry += tmp[i] + val[i];
619 1.1 christos val[i] = carry & 0xffff;
620 1.1 christos carry = carry >> 16;
621 1.1 christos }
622 1.1 christos
623 1.1 christos /* Multiply by factor, well first by 10000 and then by 1000. */
624 1.1 christos carry = 0;
625 1.1 christos for (i = 0; i < 4; i++)
626 1.1 christos {
627 1.1 christos carry += val[i] * 10000;
628 1.1 christos val[i] = carry & 0xffff;
629 1.1 christos carry = carry >> 16;
630 1.1 christos }
631 1.1 christos carry = 0;
632 1.1 christos for (i = 0; i < 4; i++)
633 1.1 christos {
634 1.1 christos carry += val[i] * 1000;
635 1.1 christos val[i] = carry & 0xffff;
636 1.1 christos carry = carry >> 16;
637 1.1 christos }
638 1.1 christos
639 1.1 christos /* Write the result. */
640 1.1 christos *lo = val[0] | (val[1] << 16);
641 1.1 christos *hi = val[2] | (val[3] << 16);
642 1.1 christos }
643 1.1 christos
644 1.1 christos /* Convert a raw (stored in a buffer) VMS time to a unix time. */
645 1.1 christos
646 1.1 christos time_t
647 1.1 christos vms_rawtime_to_time_t (unsigned char *buf)
648 1.1 christos {
649 1.1 christos unsigned int hi = bfd_getl32 (buf + 4);
650 1.1 christos unsigned int lo = bfd_getl32 (buf + 0);
651 1.1 christos
652 1.1 christos return vms_time_to_time_t (hi, lo);
653 1.1 christos }
654 1.1 christos
655 1.1 christos void
656 1.1 christos vms_get_time (unsigned int *hi, unsigned int *lo)
657 1.1 christos {
658 1.1 christos #ifdef VMS
659 1.1 christos struct _generic_64 t;
660 1.1 christos
661 1.1 christos sys$gettim (&t);
662 1.1 christos *lo = t.gen64$q_quadword;
663 1.1 christos *hi = t.gen64$q_quadword >> 32;
664 1.1 christos #else
665 1.1 christos time_t t;
666 1.1 christos
667 1.1 christos time (&t);
668 1.1 christos vms_time_t_to_vms_time (t, hi, lo);
669 1.1 christos #endif
670 1.1 christos }
671 1.1 christos
672 1.1 christos /* Get the current time into a raw buffer BUF. */
673 1.1 christos
674 1.1 christos void
675 1.1 christos vms_raw_get_time (unsigned char *buf)
676 1.1 christos {
677 1.1 christos unsigned int hi, lo;
678 1.1 christos
679 1.1 christos vms_get_time (&hi, &lo);
680 1.1 christos bfd_putl32 (lo, buf + 0);
681 bfd_putl32 (hi, buf + 4);
682 }
683