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