1 /* BFD back-end for VMS archive files.
3 Copyright 2010 Free Software Foundation, Inc.
4 Written by Tristan Gingold <gingold@adacore.com>, AdaCore.
6 This file is part of BFD, the Binary File Descriptor library.
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21 MA 02110-1301, USA. */
26 #include "safe-ctype.h"
32 /* The standard VMS disk block size. */
33 #ifndef VMS_BLOCK_SIZE
34 #define VMS_BLOCK_SIZE 512
37 /* Maximum key length (which is also the maximum symbol length in archive). */
38 #define MAX_KEYLEN 129
44 unsigned char min_char
;
45 unsigned char max_char
;
51 /* Kind of library. Used to filter in archive_p. */
61 /* Back-end private data. */
68 /* Type of the archive. */
71 /* Kind of archive. Summary of its type. */
72 enum vms_lib_kind kind
;
74 /* Total size of the mhd (element header). */
75 unsigned int mhd_size
;
77 /* Vector of modules (archive elements), already sorted. */
78 unsigned int nbr_modules
;
79 struct carsym
*modules
;
82 /* Vector of symbols (archive map), already sorted. */
83 unsigned int nbr_syms
;
86 /* DCX (decompression) data. */
87 unsigned int nbr_dcxsbm
;
88 struct dcxsbm_desc
*dcxsbm
;
91 #define bfd_libdata(bfd) ((struct lib_tdata *)((bfd)->tdata.any))
93 /* End-Of-Text pattern. This is a special record to mark the end of file. */
95 static const unsigned char eotdesc
[] = { 0x03, 0x00, 0x77, 0x00, 0x77, 0x00 };
97 /* Read index block VBN and put the entry in **IDX (which is updated).
98 If the entry is indirect, recurse. */
101 vms_traverse_index (bfd
*abfd
, unsigned int vbn
, struct carsym
**idx
)
103 struct vms_indexdef indexdef
;
108 /* Read the index block. */
109 off
= (vbn
- 1) * VMS_BLOCK_SIZE
;
110 if (bfd_seek (abfd
, off
, SEEK_SET
) != 0
111 || bfd_bread (&indexdef
, sizeof (indexdef
), abfd
) != sizeof (indexdef
))
115 used
= bfd_getl16 (indexdef
.used
);
116 for (i
= 0; i
< used
;)
118 unsigned int idx_vbn
;
119 unsigned int idx_off
;
121 unsigned char *keyname
;
122 unsigned char *ridx
= (unsigned char *)&indexdef
.keys
[i
];
125 idx_vbn
= bfd_getl32 (ridx
);
126 idx_off
= bfd_getl16 (ridx
+ 4);
132 /* Extract key length. */
133 if (bfd_libdata (abfd
)->ver
== 3)
138 else if (bfd_libdata (abfd
)->ver
== 4)
140 keylen
= bfd_getl16 (ridx
+ 6);
146 keyname
= ridx
+ len
;
149 if (idx_off
== RFADEF__C_INDEX
)
151 /* Indirect entry. Recurse. */
152 if (!vms_traverse_index (abfd
, idx_vbn
, idx
))
157 /* Add a new entry. */
160 name
= bfd_alloc (abfd
, keylen
+ 1);
163 memcpy (name
, keyname
, keylen
);
165 (*idx
)->file_offset
= (idx_vbn
- 1) * VMS_BLOCK_SIZE
+ idx_off
;
174 /* Read index #IDX, which must have NBREL entries. */
176 static struct carsym
*
177 vms_lib_read_index (bfd
*abfd
, int idx
, unsigned int nbrel
)
185 /* Read index desription. */
186 if (bfd_seek (abfd
, LHD_IDXDESC
+ idx
* IDD_LENGTH
, SEEK_SET
) != 0
187 || bfd_bread (&idd
, sizeof (idd
), abfd
) != sizeof (idd
))
191 flags
= bfd_getl16 (idd
.flags
);
192 if (!(flags
& IDD__FLAGS_ASCII
)
193 || !(flags
& IDD__FLAGS_VARLENIDX
))
196 res
= bfd_alloc (abfd
, nbrel
* sizeof (struct carsym
));
202 /* Note: if the index is empty, there is no block to traverse. */
203 vbn
= bfd_getl32 (idd
.vbn
);
204 if (vbn
!= 0 && !vms_traverse_index (abfd
, vbn
, &el
))
206 bfd_release (abfd
, res
);
210 if ((unsigned int)(el
- res
) != nbrel
)
212 /* Inconsistency between the number of modules declared and the number
213 of modules found in the index. */
214 bfd_release (abfd
, res
);
220 /* Standard function. */
222 static const bfd_target
*
223 _bfd_vms_lib_archive_p (bfd
*abfd
, enum vms_lib_kind kind
)
227 struct lib_tdata
*tdata_hold
;
228 struct lib_tdata
*tdata
;
232 if (bfd_bread (&lhd
, sizeof (lhd
), abfd
) != sizeof (lhd
))
234 if (bfd_get_error () != bfd_error_system_call
)
235 bfd_set_error (bfd_error_wrong_format
);
239 /* Check sanity (= magic) number. */
240 sanity
= bfd_getl32 (lhd
.sanity
);
241 if (!(sanity
== LHD_SANEID3
242 || sanity
== LHD_SANEID4
243 || sanity
== LHD_SANEID_DCX
))
245 bfd_set_error (bfd_error_wrong_format
);
249 /* Check archive kind. */
253 if ((lhd
.type
!= LBR__C_TYP_EOBJ
&& lhd
.type
!= LBR__C_TYP_ESHSTB
)
254 || bfd_getl32 (lhd
.majorid
) != 3
257 bfd_set_error (bfd_error_wrong_format
);
262 if ((lhd
.type
!= LBR__C_TYP_TXT
263 && lhd
.type
!= LBR__C_TYP_MLB
264 && lhd
.type
!= LBR__C_TYP_HLP
)
265 || bfd_getl32 (lhd
.majorid
) != 3
268 bfd_set_error (bfd_error_wrong_format
);
276 /* Allocate and initialize private data. */
277 tdata_hold
= bfd_libdata (abfd
);
278 tdata
= (struct lib_tdata
*) bfd_zalloc (abfd
, sizeof (struct lib_tdata
));
281 abfd
->tdata
.any
= (void *)tdata
;
282 tdata
->ver
= bfd_getl32 (lhd
.majorid
);
283 tdata
->mhd_size
= MHD__C_USRDAT
+ lhd
.mhdusz
;
284 tdata
->type
= lhd
.type
;
288 tdata
->nbr_modules
= bfd_getl32 (lhd
.modcnt
);
289 tdata
->nbr_syms
= bfd_getl32 (lhd
.idxcnt
) - tdata
->nbr_modules
;
290 tdata
->modules
= vms_lib_read_index (abfd
, 0, tdata
->nbr_modules
);
291 if (tdata
->modules
== NULL
)
295 tdata
->syms
= vms_lib_read_index (abfd
, 1, tdata
->nbr_syms
);
296 if (tdata
->syms
== NULL
)
299 tdata
->cache
= bfd_zalloc (abfd
, sizeof (bfd
*) * tdata
->nbr_modules
);
300 if (tdata
->cache
== NULL
)
303 /* Read DCX submaps. */
304 dcxvbn
= bfd_getl32 (lhd
.dcxmapvbn
);
307 unsigned char buf_reclen
[4];
310 struct vms_dcxmap
*map
;
311 unsigned int sbm_off
;
314 if (bfd_seek (abfd
, (dcxvbn
- 1) * VMS_BLOCK_SIZE
, SEEK_SET
) != 0
315 || bfd_bread (buf_reclen
, sizeof (buf_reclen
), abfd
)
316 != sizeof (buf_reclen
))
318 reclen
= bfd_getl32 (buf_reclen
);
319 buf
= bfd_malloc (reclen
);
322 if (bfd_bread (buf
, reclen
, abfd
) != reclen
)
327 map
= (struct vms_dcxmap
*)buf
;
328 tdata
->nbr_dcxsbm
= bfd_getl16 (map
->nsubs
);
329 sbm_off
= bfd_getl16 (map
->sub0
);
330 tdata
->dcxsbm
= (struct dcxsbm_desc
*)bfd_alloc
331 (abfd
, tdata
->nbr_dcxsbm
* sizeof (struct dcxsbm_desc
));
332 for (i
= 0; i
< tdata
->nbr_dcxsbm
; i
++)
334 struct vms_dcxsbm
*sbm
= (struct vms_dcxsbm
*) (buf
+ sbm_off
);
335 struct dcxsbm_desc
*sbmdesc
= &tdata
->dcxsbm
[i
];
336 unsigned int sbm_len
;
338 unsigned char *data
= (unsigned char *)sbm
;
342 sbm_sz
= bfd_getl16 (sbm
->size
);
344 BFD_ASSERT (sbm_off
<= reclen
);
346 sbmdesc
->min_char
= sbm
->min_char
;
347 BFD_ASSERT (sbmdesc
->min_char
== 0);
348 sbmdesc
->max_char
= sbm
->max_char
;
349 sbm_len
= sbmdesc
->max_char
- sbmdesc
->min_char
+ 1;
350 l
= (2 * sbm_len
+ 7) / 8;
351 BFD_ASSERT (sbm_sz
>= sizeof (struct vms_dcxsbm
) + l
+ 3 * sbm_len
);
352 sbmdesc
->flags
= (unsigned char *)bfd_alloc (abfd
, l
);
353 memcpy (sbmdesc
->flags
, data
+ bfd_getl16 (sbm
->flags
), l
);
354 sbmdesc
->nodes
= (unsigned char *)bfd_alloc (abfd
, 2 * sbm_len
);
355 memcpy (sbmdesc
->nodes
, data
+ bfd_getl16 (sbm
->nodes
), 2 * sbm_len
);
356 sbmdesc
->next
= (unsigned short *)bfd_alloc
357 (abfd
, sbm_len
* sizeof (unsigned short));
358 buf1
= data
+ bfd_getl16 (sbm
->next
);
359 for (j
= 0; j
< sbm_len
; j
++)
360 sbmdesc
->next
[j
] = bfd_getl16 (buf1
+ j
* 2);
366 tdata
->nbr_dcxsbm
= 0;
369 /* The map is always present. Also mark shared image library. */
370 abfd
->has_armap
= TRUE
;
371 if (tdata
->type
== LBR__C_TYP_ESHSTB
)
372 abfd
->is_thin_archive
= TRUE
;
377 bfd_release (abfd
, tdata
);
378 abfd
->tdata
.any
= (void *)tdata_hold
;;
382 /* Standard function for alpha libraries. */
385 _bfd_vms_lib_alpha_archive_p (bfd
*abfd
)
387 return _bfd_vms_lib_archive_p (abfd
, vms_lib_alpha
);
390 /* Standard function for text libraries. */
392 static const bfd_target
*
393 _bfd_vms_lib_txt_archive_p (bfd
*abfd
)
395 return _bfd_vms_lib_archive_p (abfd
, vms_lib_txt
);
398 /* Standard bfd function. */
401 _bfd_vms_lib_mkarchive (bfd
*abfd
)
403 struct lib_tdata
*tdata
;
405 tdata
= (struct lib_tdata
*) bfd_zalloc (abfd
, sizeof (struct lib_tdata
));
409 abfd
->tdata
.any
= (void *)tdata
;
411 tdata
->mhd_size
= sizeof (struct vms_mhd
);
412 tdata
->type
= LBR__C_TYP_EOBJ
;
414 tdata
->nbr_modules
= 0;
416 tdata
->modules
= NULL
;
423 /* Find NAME in the symbol index. Return the index. */
426 _bfd_vms_lib_find_symbol (bfd
*abfd
, const char *name
)
428 struct lib_tdata
*tdata
= bfd_libdata (abfd
);
431 /* Open-coded binary search for speed. */
433 hi
= tdata
->nbr_syms
- 1;
437 int mid
= lo
+ (hi
- lo
) / 2;
440 diff
= (char)(name
[0] - tdata
->syms
[mid
].name
[0]);
442 diff
= strcmp (name
, tdata
->syms
[mid
].name
);
444 return tdata
->syms
[mid
].file_offset
;
453 /* IO vector for archive member. Need that because members are not linearly
454 stored in archives. */
458 /* Current offset. */
461 /* Length of the module, when known. */
464 /* Current position in the record from bfd_bread point of view (ie, after
465 decompression). 0 means that no data byte have been read, -2 and -1
466 are reserved for the length word. */
468 #define REC_POS_NL -4
469 #define REC_POS_PAD -3
470 #define REC_POS_LEN0 -2
471 #define REC_POS_LEN1 -1
474 unsigned short rec_len
;
475 /* Number of bytes to read in the current record. */
476 unsigned short rec_rem
;
477 /* Offset of the next block. */
479 /* Current *data* offset in the data block. */
480 unsigned short blk_off
;
482 /* Offset of the first block. Extracted from the index. */
483 file_ptr first_block
;
485 /* Initial next_block. Extracted when the MHD is read. */
486 file_ptr init_next_block
;
487 /* Initial blk_off, once the MHD is read. */
488 unsigned short init_blk_off
;
490 /* Used to store any 3 byte record, which could be the EOF pattern. */
491 unsigned char pattern
[4];
494 struct dcxsbm_desc
*dcxsbms
;
495 /* Current submap. */
496 struct dcxsbm_desc
*dcx_sbm
;
497 /* Current offset in the submap. */
498 unsigned int dcx_offset
;
501 /* Compressed buffer. */
502 unsigned char *dcx_buf
;
503 /* Size of the buffer. Used to resize. */
504 unsigned int dcx_max
;
505 /* Number of valid bytes in the buffer. */
506 unsigned int dcx_rlen
;
509 /* Return the current position. */
512 vms_lib_btell (struct bfd
*abfd
)
514 struct vms_lib_iovec
*vec
= (struct vms_lib_iovec
*) abfd
->iostream
;
518 /* Read the header of the next data block if all bytes of the current block
522 vms_lib_read_block (struct bfd
*abfd
)
524 struct vms_lib_iovec
*vec
= (struct vms_lib_iovec
*) abfd
->iostream
;
526 if (vec
->blk_off
== DATA__LENGTH
)
528 unsigned char hdr
[DATA__DATA
];
530 /* Read next block. */
531 if (bfd_seek (abfd
->my_archive
, vec
->next_block
, SEEK_SET
) != 0)
533 if (bfd_bread (hdr
, sizeof (hdr
), abfd
->my_archive
) != sizeof (hdr
))
535 vec
->next_block
= (bfd_getl32 (hdr
+ 2) - 1) * VMS_BLOCK_SIZE
;
536 vec
->blk_off
= sizeof (hdr
);
541 /* Read NBYTES from ABFD into BUF if not NULL. If BUF is NULL, bytes are
542 not stored. Read linearly from the library, but handle blocks. This
543 function does not handle records nor EOF. */
546 vms_lib_bread_raw (struct bfd
*abfd
, void *buf
, file_ptr nbytes
)
548 struct vms_lib_iovec
*vec
= (struct vms_lib_iovec
*) abfd
->iostream
;
556 /* Be sure the current data block is read. */
557 if (!vms_lib_read_block (abfd
))
560 /* Do not read past the data block, do not read more than requested. */
561 l
= DATA__LENGTH
- vec
->blk_off
;
568 /* Really read into BUF. */
569 if (bfd_bread (buf
, l
, abfd
->my_archive
) != l
)
574 /* Make as if we are reading. */
575 if (bfd_seek (abfd
->my_archive
, l
, SEEK_CUR
) != 0)
588 /* Decompress NBYTES from VEC. Store the bytes into BUF if not NULL. */
591 vms_lib_dcx (struct vms_lib_iovec
*vec
, unsigned char *buf
, file_ptr nbytes
)
593 struct dcxsbm_desc
*sbm
;
599 /* The loop below expect to deliver at least one byte. */
603 /* Get the current state. */
605 offset
= vec
->dcx_offset
;
606 j
= vec
->dcx_pos
& 7;
608 for (i
= vec
->dcx_pos
>> 3; i
< vec
->dcx_rlen
; i
++)
610 unsigned char b
= vec
->dcx_buf
[i
];
616 if (!(sbm
->flags
[offset
>> 3] & (1 << (offset
& 7))))
618 unsigned int n_offset
= sbm
->nodes
[offset
];
621 /* End of buffer. Stay where we are. */
622 vec
->dcx_pos
= (i
<< 3) + j
;
625 vec
->dcx_offset
= offset
;
629 offset
= 2 * n_offset
;
633 unsigned char v
= sbm
->nodes
[offset
];
635 sbm
= vec
->dcxsbms
+ sbm
->next
[v
];
646 vec
->dcx_pos
= (i
<< 3) + j
+ 1;
647 vec
->dcx_offset
= offset
;
660 /* Standard IOVEC function. */
663 vms_lib_bread (struct bfd
*abfd
, void *buf
, file_ptr nbytes
)
665 struct vms_lib_iovec
*vec
= (struct vms_lib_iovec
*) abfd
->iostream
;
669 /* Do not read past the end. */
670 if (vec
->where
>= vec
->file_len
)
676 if (vec
->rec_rem
== 0)
678 unsigned char blen
[2];
680 /* Read record length. */
681 if (vms_lib_bread_raw (abfd
, &blen
, sizeof (blen
)) != sizeof (blen
))
683 vec
->rec_len
= bfd_getl16 (blen
);
684 if (bfd_libdata (abfd
->my_archive
)->kind
== vms_lib_txt
)
686 /* Discard record size and align byte. */
688 vec
->rec_rem
= vec
->rec_len
;
692 /* Prepend record size. */
693 vec
->rec_pos
= REC_POS_LEN0
;
694 vec
->rec_rem
= (vec
->rec_len
+ 1) & ~1; /* With align byte. */
696 if (vec
->rec_len
== 3)
698 /* Possibly end of file. Check the pattern. */
699 if (vms_lib_bread_raw (abfd
, vec
->pattern
, 4) != 4)
701 if (!memcmp (vec
->pattern
, eotdesc
+ 2, 3))
703 /* This is really an EOF. */
705 vec
->file_len
= vec
->where
;
710 if (vec
->dcxsbms
!= NULL
)
712 /* This is a compressed member. */
716 /* Be sure there is enough room for the expansion. */
717 len
= (vec
->rec_len
+ 1) & ~1;
718 if (len
> vec
->dcx_max
)
720 while (len
> vec
->dcx_max
)
722 vec
->dcx_buf
= bfd_alloc (abfd
, vec
->dcx_max
);
723 if (vec
->dcx_buf
== NULL
)
727 /* Read the compressed record. */
729 if (vec
->rec_len
== 3)
732 memcpy (vec
->dcx_buf
, vec
->pattern
, 3);
736 elen
= vms_lib_bread_raw (abfd
, vec
->dcx_buf
, len
);
741 /* Dummy expansion to get the expanded length. */
743 vec
->dcx_sbm
= vec
->dcxsbms
;
745 elen
= vms_lib_dcx (vec
, NULL
, 0x10000);
751 /* Reset the state. */
753 vec
->dcx_sbm
= vec
->dcxsbms
;
757 if (vec
->rec_pos
< 0)
760 switch (vec
->rec_pos
)
763 c
= vec
->rec_len
& 0xff;
764 vec
->rec_pos
= REC_POS_LEN1
;
767 c
= (vec
->rec_len
>> 8) & 0xff;
783 *(unsigned char *)buf
= c
;
791 if (nbytes
> vec
->rec_rem
)
792 chunk
= vec
->rec_rem
;
796 if (vec
->dcxsbms
!= NULL
)
798 /* Optimize the stat() case: no need to decompress again as we
800 if (!(buf
== NULL
&& chunk
== vec
->rec_rem
))
801 chunk
= vms_lib_dcx (vec
, buf
, chunk
);
805 if (vec
->rec_len
== 3)
808 memcpy (buf
, vec
->pattern
+ vec
->rec_pos
, chunk
);
811 chunk
= vms_lib_bread_raw (abfd
, buf
, chunk
);
819 vec
->rec_pos
+= chunk
;
820 vec
->rec_rem
-= chunk
;
822 if (vec
->rec_rem
== 0)
824 /* End of record reached. */
825 if (bfd_libdata (abfd
->my_archive
)->kind
== vms_lib_txt
)
827 if ((vec
->rec_len
& 1) == 1
829 && vec
->dcxsbms
== NULL
)
831 /* Eat the pad byte. */
833 if (vms_lib_bread_raw (abfd
, &pad
, 1) != 1)
836 vec
->rec_pos
= REC_POS_NL
;
841 if ((vec
->rec_len
& 1) == 1 && vec
->dcxsbms
!= NULL
)
843 vec
->rec_pos
= REC_POS_PAD
;
853 /* Standard function, but we currently only handle the rewind case. */
856 vms_lib_bseek (struct bfd
*abfd
, file_ptr offset
, int whence
)
858 struct vms_lib_iovec
*vec
= (struct vms_lib_iovec
*) abfd
->iostream
;
860 if (whence
== SEEK_SET
&& offset
== 0)
865 vec
->blk_off
= vec
->init_blk_off
;
866 vec
->next_block
= vec
->init_next_block
;
868 if (bfd_seek (abfd
->my_archive
, vec
->first_block
, SEEK_SET
) != 0)
877 vms_lib_bwrite (struct bfd
*abfd ATTRIBUTE_UNUSED
,
878 const void *where ATTRIBUTE_UNUSED
,
879 file_ptr nbytes ATTRIBUTE_UNUSED
)
885 vms_lib_bclose (struct bfd
*abfd
)
887 abfd
->iostream
= NULL
;
892 vms_lib_bflush (struct bfd
*abfd ATTRIBUTE_UNUSED
)
898 vms_lib_bstat (struct bfd
*abfd ATTRIBUTE_UNUSED
,
899 struct stat
*sb ATTRIBUTE_UNUSED
)
906 vms_lib_bmmap (struct bfd
*abfd ATTRIBUTE_UNUSED
,
907 void *addr ATTRIBUTE_UNUSED
,
908 bfd_size_type len ATTRIBUTE_UNUSED
,
909 int prot ATTRIBUTE_UNUSED
,
910 int flags ATTRIBUTE_UNUSED
,
911 file_ptr offset ATTRIBUTE_UNUSED
)
916 static const struct bfd_iovec vms_lib_iovec
= {
917 &vms_lib_bread
, &vms_lib_bwrite
, &vms_lib_btell
, &vms_lib_bseek
,
918 &vms_lib_bclose
, &vms_lib_bflush
, &vms_lib_bstat
, &vms_lib_bmmap
921 /* Open a library module. FILEPOS is the position of the module header. */
924 vms_lib_bopen (bfd
*el
, file_ptr filepos
)
926 struct vms_lib_iovec
*vec
;
929 struct lib_tdata
*tdata
= bfd_libdata (el
->my_archive
);
932 /* Allocate and initialized the iovec. */
933 vec
= bfd_zalloc (el
, sizeof (*vec
));
938 el
->iovec
= &vms_lib_iovec
;
940 /* File length is not known. */
943 /* Read the first data block. */
944 vec
->next_block
= filepos
& ~(VMS_BLOCK_SIZE
- 1);
945 vec
->blk_off
= DATA__LENGTH
;
946 if (!vms_lib_read_block (el
))
949 /* Prepare to read the first record. */
950 vec
->blk_off
= filepos
& (VMS_BLOCK_SIZE
- 1);
952 if (bfd_seek (el
->my_archive
, filepos
, SEEK_SET
) != 0)
955 /* Read Record length + MHD + align byte. */
956 len
= tdata
->mhd_size
;
957 if (vms_lib_bread_raw (el
, buf
, 2) != 2)
959 if (bfd_getl16 (buf
) != len
)
961 len
= (len
+ 1) & ~1;
962 BFD_ASSERT (len
<= sizeof (buf
));
963 if (vms_lib_bread_raw (el
, buf
, len
) != len
)
966 /* Get info from mhd. */
967 mhd
= (struct vms_mhd
*)buf
;
968 if (len
>= sizeof (struct vms_mhd
))
969 el
->selective_search
= (mhd
->objstat
& MHD__M_SELSRC
) ? 1 : 0;
970 el
->mtime
= vms_rawtime_to_time_t (mhd
->datim
);
971 el
->mtime_set
= TRUE
;
973 /* Reinit the iovec so that seek() will point to the first record after
976 vec
->init_blk_off
= vec
->blk_off
;
977 vec
->init_next_block
= vec
->next_block
;
978 vec
->first_block
= bfd_tell (el
->my_archive
);
979 vec
->dcxsbms
= bfd_libdata (el
->my_archive
)->dcxsbm
;
981 if (vec
->dcxsbms
!= NULL
)
984 vec
->dcx_max
= 10 * 1024;
985 vec
->dcx_buf
= bfd_alloc (el
, vec
->dcx_max
);
987 if (vec
->dcx_buf
== NULL
)
993 /* Standard function: get member at IDX. */
996 _bfd_vms_lib_get_elt_at_index (bfd
*abfd
, symindex idx
)
998 struct lib_tdata
*tdata
= bfd_libdata (abfd
);
1003 for (i
= 0; i
< tdata
->nbr_modules
; i
++)
1005 if (tdata
->modules
[i
].file_offset
== (file_ptr
)idx
)
1009 /* Invalid index. */
1010 if (i
>= tdata
->nbr_modules
)
1013 /* Already loaded. */
1014 if (tdata
->cache
[i
])
1015 return tdata
->cache
[i
];
1018 res
= _bfd_create_empty_archive_element_shell (abfd
);
1019 if (!vms_lib_bopen (res
, idx
))
1021 res
->filename
= tdata
->modules
[i
].name
;
1023 tdata
->cache
[i
] = res
;
1028 /* Elements of an imagelib are stubs. You can get the real image with this
1032 _bfd_vms_lib_get_imagelib_file (bfd
*el
)
1034 bfd
*archive
= el
->my_archive
;
1035 const char *modname
= el
->filename
;
1036 int modlen
= strlen (modname
);
1041 /* Convert module name to lower case and append '.exe'. */
1042 filename
= bfd_alloc (el
, modlen
+ 5);
1043 if (filename
== NULL
)
1045 for (j
= 0; j
< modlen
; j
++)
1046 if (ISALPHA (modname
[j
]))
1047 filename
[j
] = TOLOWER (modname
[j
]);
1049 filename
[j
] = modname
[j
];
1050 memcpy (filename
+ modlen
, ".exe", 5);
1052 filename
= _bfd_append_relative_path (archive
, filename
);
1053 if (filename
== NULL
)
1055 res
= bfd_openr (filename
, NULL
);
1059 (*_bfd_error_handler
)(_("could not open shared image '%s' from '%s'"),
1060 filename
, archive
->filename
);
1061 bfd_release (archive
, filename
);
1065 /* FIXME: put it in a cache ? */
1069 /* Standard function. */
1072 _bfd_vms_lib_openr_next_archived_file (bfd
*archive
,
1081 idx
= last_file
->proxy_origin
+ 1;
1083 if (idx
>= bfd_libdata (archive
)->nbr_modules
)
1085 bfd_set_error (bfd_error_no_more_archived_files
);
1089 res
= _bfd_vms_lib_get_elt_at_index
1090 (archive
, bfd_libdata (archive
)->modules
[idx
].file_offset
);
1093 res
->proxy_origin
= idx
;
1097 /* Standard function. Just compute the length. */
1100 _bfd_vms_lib_generic_stat_arch_elt (bfd
*abfd
, struct stat
*st
)
1102 struct vms_lib_iovec
*vec
= (struct vms_lib_iovec
*) abfd
->iostream
;
1104 if (abfd
->my_archive
== NULL
)
1106 bfd_set_error (bfd_error_invalid_operation
);
1110 if (vec
->file_len
== (ufile_ptr
)-1)
1112 if (vms_lib_bseek (abfd
, 0, SEEK_SET
) != 0)
1115 /* Compute length. */
1116 while (vms_lib_bread (abfd
, NULL
, 1 << 20) > 0)
1120 st
->st_size
= vec
->file_len
;
1121 if (abfd
->mtime_set
)
1122 st
->st_mtime
= abfd
->mtime
;
1132 /* Internal representation of an index entry. */
1136 /* Corresponding archive member. */
1139 /* Number of reference to this entry. */
1142 /* Length of the key. */
1143 unsigned short namlen
;
1149 /* Used to sort index entries. */
1152 vms_index_cmp (const void *lv
, const void *rv
)
1154 const struct vms_index
*l
= lv
;
1155 const struct vms_index
*r
= rv
;
1157 return strcmp (l
->name
, r
->name
);
1160 /* Maximum number of index blocks level. */
1162 #define MAX_LEVEL 10
1164 /* Get the size of an index entry. */
1167 get_idxlen (struct vms_index
*idx
)
1169 return 7 + idx
->namlen
;
1172 /* Write the index. VBN is the first vbn to be used, and will contain
1173 on return the last vbn.
1174 Return TRUE on success. */
1177 vms_write_index (bfd
*abfd
,
1178 struct vms_index
*idx
, unsigned int nbr
, unsigned int *vbn
,
1179 unsigned int *topvbn
)
1184 struct vms_indexdef
*rblk
[MAX_LEVEL
];
1189 unsigned short lastlen
;
1201 /* Sort the index the first time this function is called. */
1202 qsort (idx
, nbr
, sizeof (struct vms_index
), vms_index_cmp
);
1205 /* Allocate first index block. */
1208 rblk
[0] = bfd_malloc (sizeof (struct vms_indexdef
));
1209 blk
[0].vbn
= (*vbn
)++;
1213 for (i
= 0; i
< nbr
; i
++, idx
++)
1215 unsigned int idxlen
= get_idxlen (idx
);
1216 struct vms_idxdef
*en
;
1219 /* Check if a block might overflow. In this case we will flush this
1220 block and all the blocks below it. */
1221 for (j
= 0; j
< level
; j
++)
1222 if (blk
[j
].len
+ blk
[j
].lastlen
+ idxlen
> INDEXDEF__BLKSIZ
)
1225 for (j
= 0; j
< level
; j
++)
1229 /* There is not enough room to write the new entry in this
1230 block or in a parent block. */
1234 BFD_ASSERT (level
< MAX_LEVEL
);
1236 /* Need to create a parent. */
1239 rblk
[level
] = bfd_malloc (sizeof (struct vms_indexdef
));
1240 bfd_putl32 (*vbn
, rblk
[j
]->parent
);
1242 blk
[level
].vbn
= (*vbn
)++;
1244 blk
[level
].lastlen
= 0;
1249 /* Update parent block: write the new entry. */
1252 en
= (struct vms_idxdef
*)(rblk
[j
]->keys
+ blk
[j
].len
);
1253 memcpy (rblk
[j
+ 1]->keys
+ blk
[j
+ 1].len
, en
,
1255 en
= (struct vms_idxdef
*)
1256 (rblk
[j
+ 1]->keys
+ blk
[j
+ 1].len
);
1257 bfd_putl32 (blk
[j
].vbn
, en
->vbn
);
1258 bfd_putl16 (RFADEF__C_INDEX
, en
->offset
);
1263 /* And allocate it. Do it only on the block that won't be
1264 flushed (so that the parent of the parent can be
1266 blk
[j
+ 1].len
+= blk
[j
].lastlen
;
1267 blk
[j
+ 1].lastlen
= 0;
1270 /* Write this block on the disk. */
1273 bfd_putl16 (blk
[j
].len
+ blk
[j
].lastlen
, rblk
[j
]->used
);
1274 if (bfd_seek (abfd
, (blk
[j
].vbn
- 1) * VMS_BLOCK_SIZE
,
1277 if (bfd_bwrite (rblk
[j
], sizeof (struct vms_indexdef
), abfd
)
1278 != sizeof (struct vms_indexdef
))
1282 /* Reset this block. */
1285 blk
[j
].vbn
= (*vbn
)++;
1288 /* Append it to the block. */
1291 blk
[j
].len
+= blk
[j
].lastlen
;
1295 en
= (struct vms_idxdef
*)(rblk
[j
]->keys
+ blk
[j
].len
);
1296 bfd_putl32 ((idx
->abfd
->proxy_origin
/ VMS_BLOCK_SIZE
) + 1,
1299 ((idx
->abfd
->proxy_origin
% VMS_BLOCK_SIZE
) + DATA__DATA
,
1301 en
->keylen
= idx
->namlen
;
1302 memcpy (en
->keyname
, idx
->name
, idx
->namlen
);
1306 blk
[j
].lastlen
= idxlen
;
1311 *topvbn
= blk
[level
- 1].vbn
;
1317 for (j
= 0; j
< level
; j
++)
1321 /* Update parent block: write the new entry. */
1322 struct vms_idxdef
*en
;
1323 struct vms_idxdef
*par
;
1325 en
= (struct vms_idxdef
*)(rblk
[j
- 1]->keys
+ blk
[j
- 1].len
);
1326 par
= (struct vms_idxdef
*)(rblk
[j
]->keys
+ blk
[j
].len
);
1327 memcpy (par
, en
, blk
[j
- 1].lastlen
);
1328 bfd_putl32 (blk
[j
- 1].vbn
, par
->vbn
);
1329 bfd_putl16 (RFADEF__C_INDEX
, par
->offset
);
1332 /* Write this block on the disk. */
1333 bfd_putl16 (blk
[j
].len
+ blk
[j
].lastlen
, rblk
[j
]->used
);
1334 if (bfd_seek (abfd
, (blk
[j
].vbn
- 1) * VMS_BLOCK_SIZE
,
1337 if (bfd_bwrite (rblk
[j
], sizeof (struct vms_indexdef
), abfd
)
1338 != sizeof (struct vms_indexdef
))
1347 /* Append data to the data block DATA. Force write if PAD is true. */
1350 vms_write_data_block (bfd
*arch
, struct vms_datadef
*data
, file_ptr
*off
,
1351 const unsigned char *buf
, unsigned int len
, int pad
)
1353 while (len
> 0 || pad
)
1355 unsigned int doff
= *off
& (VMS_BLOCK_SIZE
- 1);
1356 unsigned int remlen
= (DATA__LENGTH
- DATA__DATA
) - doff
;
1359 l
= (len
> remlen
) ? remlen
: len
;
1360 memcpy (data
->data
+ doff
, buf
, l
);
1366 if (doff
== (DATA__LENGTH
- DATA__DATA
) || (len
== 0 && pad
))
1370 bfd_putl32 ((*off
/ VMS_BLOCK_SIZE
) + 2, data
->link
);
1372 if (bfd_bwrite (data
, sizeof (*data
), arch
) != sizeof (*data
))
1375 *off
+= DATA__LENGTH
- doff
;
1384 /* Build the symbols index. */
1387 _bfd_vms_lib_build_map (unsigned int nbr_modules
,
1388 struct vms_index
*modules
,
1389 unsigned int *res_cnt
,
1390 struct vms_index
**res
)
1393 asymbol
**syms
= NULL
;
1395 struct vms_index
*map
= NULL
;
1396 unsigned int map_max
= 1024; /* Fine initial default. */
1397 unsigned int map_count
= 0;
1399 map
= (struct vms_index
*) bfd_malloc (map_max
* sizeof (struct vms_index
));
1403 /* Gather symbols. */
1404 for (i
= 0; i
< nbr_modules
; i
++)
1409 bfd
*current
= modules
[i
].abfd
;
1411 if ((bfd_get_file_flags (current
) & HAS_SYMS
) == 0)
1414 storage
= bfd_get_symtab_upper_bound (current
);
1420 if (storage
> syms_max
)
1425 syms
= (asymbol
**) bfd_malloc (syms_max
);
1429 symcount
= bfd_canonicalize_symtab (current
, syms
);
1433 /* Now map over all the symbols, picking out the ones we
1435 for (src_count
= 0; src_count
< symcount
; src_count
++)
1437 flagword flags
= (syms
[src_count
])->flags
;
1438 asection
*sec
= syms
[src_count
]->section
;
1440 if ((flags
& BSF_GLOBAL
1442 || flags
& BSF_INDIRECT
1443 || bfd_is_com_section (sec
))
1444 && ! bfd_is_und_section (sec
))
1446 struct vms_index
*new_map
;
1448 /* This symbol will go into the archive header. */
1449 if (map_count
== map_max
)
1452 new_map
= (struct vms_index
*)
1453 bfd_realloc (map
, map_max
* sizeof (struct vms_index
));
1454 if (new_map
== NULL
)
1459 map
[map_count
].abfd
= current
;
1460 /* FIXME: check length. */
1461 map
[map_count
].namlen
= strlen (syms
[src_count
]->name
);
1462 map
[map_count
].name
= syms
[src_count
]->name
;
1470 *res_cnt
= map_count
;
1482 /* Do the hard work: write an archive on the disk. */
1485 _bfd_vms_lib_write_archive_contents (bfd
*arch
)
1488 unsigned int nbr_modules
;
1489 struct vms_index
*modules
;
1490 unsigned int nbr_symbols
;
1491 struct vms_index
*symbols
;
1492 struct lib_tdata
*tdata
= bfd_libdata (arch
);
1495 unsigned int nbr_mod_iblk
;
1496 unsigned int nbr_sym_iblk
;
1498 unsigned int mod_idx_vbn
;
1499 unsigned int sym_idx_vbn
;
1501 /* Count the number of modules (and do a first sanity check). */
1503 for (current
= arch
->archive_head
;
1505 current
= current
->archive_next
)
1507 /* This check is checking the bfds for the objects we're reading
1508 from (which are usually either an object file or archive on
1509 disk), not the archive entries we're writing to. We don't
1510 actually create bfds for the archive members, we just copy
1511 them byte-wise when we write out the archive. */
1512 if (bfd_write_p (current
) || !bfd_check_format (current
, bfd_object
))
1514 bfd_set_error (bfd_error_invalid_operation
);
1521 /* Build the modules list. */
1522 BFD_ASSERT (tdata
->modules
== NULL
);
1523 modules
= bfd_alloc (arch
, nbr_modules
* sizeof (struct vms_index
));
1524 if (modules
== NULL
)
1527 for (current
= arch
->archive_head
, i
= 0;
1529 current
= current
->archive_next
, i
++)
1533 modules
[i
].abfd
= current
;
1534 modules
[i
].name
= vms_get_module_name (current
->filename
, FALSE
);
1537 /* FIXME: silently truncate long names ? */
1538 nl
= strlen (modules
[i
].name
);
1539 modules
[i
].namlen
= (nl
> MAX_KEYLEN
? MAX_KEYLEN
: nl
);
1542 /* Create the module index. */
1544 if (!vms_write_index (NULL
, modules
, nbr_modules
, &vbn
, NULL
))
1548 /* Create symbol index. */
1549 if (!_bfd_vms_lib_build_map (nbr_modules
, modules
, &nbr_symbols
, &symbols
))
1553 if (!vms_write_index (NULL
, symbols
, nbr_symbols
, &vbn
, NULL
))
1557 /* Write modules and remember their position. */
1558 off
= (1 + nbr_mod_iblk
+ nbr_sym_iblk
) * VMS_BLOCK_SIZE
;
1560 if (bfd_seek (arch
, off
, SEEK_SET
) != 0)
1563 for (i
= 0; i
< nbr_modules
; i
++)
1565 struct vms_datadef data
;
1566 unsigned char blk
[VMS_BLOCK_SIZE
];
1567 struct vms_mhd
*mhd
;
1570 current
= modules
[i
].abfd
;
1571 current
->proxy_origin
= off
;
1573 bfd_putl16 (sizeof (struct vms_mhd
), blk
);
1574 mhd
= (struct vms_mhd
*)(blk
+ 2);
1575 memset (mhd
, 0, sizeof (struct vms_mhd
));
1577 mhd
->id
= MHD__C_MHDID
;
1579 memcpy (mhd
->objid
, "V1.0", 4);
1580 bfd_putl32 (modules
[i
].ref
, mhd
->refcnt
);
1583 sz
= (2 + sizeof (struct vms_mhd
) + 1) & ~1;
1584 if (vms_write_data_block (arch
, &data
, &off
, blk
, sz
, 0) < 0)
1587 if (bfd_seek (current
, 0, SEEK_SET
) != 0)
1592 sz
= bfd_bread (blk
, sizeof (blk
), current
);
1595 if (vms_write_data_block (arch
, &data
, &off
, blk
, sz
, 0) < 0)
1598 if (vms_write_data_block (arch
, &data
, &off
,
1599 eotdesc
, sizeof (eotdesc
), 1) < 0)
1603 /* Write the indexes. */
1605 if (vms_write_index (arch
, modules
, nbr_modules
, &vbn
, &mod_idx_vbn
) != TRUE
)
1607 if (vms_write_index (arch
, symbols
, nbr_symbols
, &vbn
, &sym_idx_vbn
) != TRUE
)
1610 /* Write libary header. */
1612 unsigned char blk
[VMS_BLOCK_SIZE
];
1613 struct vms_lhd
*lhd
= (struct vms_lhd
*)blk
;
1614 struct vms_idd
*idd
= (struct vms_idd
*)(blk
+ sizeof (*lhd
));
1615 unsigned int idd_flags
;
1617 memset (blk
, 0, sizeof (blk
));
1619 lhd
->type
= LBR__C_TYP_EOBJ
;
1621 bfd_putl32 (LHD_SANEID3
, lhd
->sanity
);
1622 bfd_putl16 (3, lhd
->majorid
);
1623 bfd_putl16 (0, lhd
->minorid
);
1624 snprintf ((char *)lhd
->lbrver
+ 1, sizeof (lhd
->lbrver
) - 1,
1626 (unsigned)(BFD_VERSION
/ 100000000UL),
1627 (unsigned)(BFD_VERSION
/ 1000000UL) % 100,
1628 (unsigned)(BFD_VERSION
/ 10000UL) % 100);
1629 lhd
->lbrver
[sizeof (lhd
->lbrver
) - 1] = 0;
1630 lhd
->lbrver
[0] = strlen ((char *)lhd
->lbrver
+ 1);
1633 bfd_putl64 (0, lhd
->credat
);
1634 bfd_putl64 (0, lhd
->updtim
);
1636 lhd
->mhdusz
= sizeof (struct vms_mhd
) - MHD__C_USRDAT
;
1638 bfd_putl32 (nbr_modules
+ nbr_symbols
, lhd
->idxcnt
);
1639 bfd_putl32 (nbr_modules
, lhd
->modcnt
);
1640 bfd_putl32 (nbr_modules
, lhd
->modhdrs
);
1642 bfd_putl32 (vbn
- 1, lhd
->hipreal
);
1643 bfd_putl32 (vbn
- 1, lhd
->hiprusd
);
1645 /* First index (modules name). */
1646 idd_flags
= IDD__FLAGS_ASCII
| IDD__FLAGS_VARLENIDX
1647 | IDD__FLAGS_NOCASECMP
| IDD__FLAGS_NOCASENTR
;
1648 bfd_putl16 (idd_flags
, idd
->flags
);
1649 bfd_putl16 (MAX_KEYLEN
, idd
->keylen
);
1650 bfd_putl16 (mod_idx_vbn
, idd
->vbn
);
1653 /* Second index (symbols name). */
1654 bfd_putl16 (idd_flags
, idd
->flags
);
1655 bfd_putl16 (MAX_KEYLEN
, idd
->keylen
);
1656 bfd_putl16 (sym_idx_vbn
, idd
->vbn
);
1659 if (bfd_seek (arch
, 0, SEEK_SET
) != 0)
1661 if (bfd_bwrite (blk
, sizeof (blk
), arch
) != sizeof (blk
))
1668 bfd_set_error (bfd_error_on_input
, current
, bfd_get_error ());
1672 /* Add a target for text library. This costs almost nothing and is useful to
1673 read VMS library on the host. */
1675 const bfd_target vms_lib_txt_vec
=
1677 "vms-libtxt", /* Name. */
1678 bfd_target_unknown_flavour
,
1679 BFD_ENDIAN_UNKNOWN
, /* byteorder */
1680 BFD_ENDIAN_UNKNOWN
, /* header_byteorder */
1681 0, /* Object flags. */
1682 0, /* Sect flags. */
1683 0, /* symbol_leading_char. */
1684 ' ', /* ar_pad_char. */
1685 15, /* ar_max_namelen. */
1686 bfd_getl64
, bfd_getl_signed_64
, bfd_putl64
,
1687 bfd_getl32
, bfd_getl_signed_32
, bfd_putl32
,
1688 bfd_getl16
, bfd_getl_signed_16
, bfd_putl16
,
1689 bfd_getl64
, bfd_getl_signed_64
, bfd_putl64
,
1690 bfd_getl32
, bfd_getl_signed_32
, bfd_putl32
,
1691 bfd_getl16
, bfd_getl_signed_16
, bfd_putl16
,
1693 {_bfd_dummy_target
, _bfd_dummy_target
, /* bfd_check_format. */
1694 _bfd_vms_lib_txt_archive_p
, _bfd_dummy_target
},
1695 {bfd_false
, bfd_false
, bfd_false
, bfd_false
}, /* bfd_set_format. */
1696 {bfd_false
, bfd_false
, bfd_false
, bfd_false
}, /* bfd_write_contents. */
1698 BFD_JUMP_TABLE_GENERIC (_bfd_generic
),
1699 BFD_JUMP_TABLE_COPY (_bfd_generic
),
1700 BFD_JUMP_TABLE_CORE (_bfd_nocore
),
1701 BFD_JUMP_TABLE_ARCHIVE (_bfd_vms_lib
),
1702 BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols
),
1703 BFD_JUMP_TABLE_RELOCS (_bfd_norelocs
),
1704 BFD_JUMP_TABLE_WRITE (_bfd_nowrite
),
1705 BFD_JUMP_TABLE_LINK (_bfd_nolink
),
1706 BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic
),