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