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