2010-04-16 Tristan Gingold <gingold@adacore.com>
[binutils.git] / bfd / vms-lib.c
blobd05fab70818cc83c3c290ba0b236fd4f0de97cd6
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. */
23 #include "sysdep.h"
24 #include "bfd.h"
25 #include "libbfd.h"
26 #include "safe-ctype.h"
27 #include "bfdver.h"
28 #include "vms.h"
29 #include "vms/lbr.h"
30 #include "vms/dcx.h"
32 /* The standard VMS disk block size. */
33 #ifndef VMS_BLOCK_SIZE
34 #define VMS_BLOCK_SIZE 512
35 #endif
37 /* Maximum key length (which is also the maximum symbol length in archive). */
38 #define MAX_KEYLEN 129
40 /* DCX Submaps. */
42 struct dcxsbm_desc
44 unsigned char min_char;
45 unsigned char max_char;
46 unsigned char *flags;
47 unsigned char *nodes;
48 unsigned short *next;
51 /* Kind of library. Used to filter in archive_p. */
53 enum vms_lib_kind
55 vms_lib_vax,
56 vms_lib_alpha,
57 vms_lib_ia64,
58 vms_lib_txt
61 /* Back-end private data. */
63 struct lib_tdata
65 /* Major version. */
66 unsigned char ver;
68 /* Type of the archive. */
69 unsigned char type;
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;
80 bfd **cache;
82 /* Vector of symbols (archive map), already sorted. */
83 unsigned int nbr_syms;
84 struct carsym *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. */
100 static bfd_boolean
101 vms_traverse_index (bfd *abfd, unsigned int vbn, struct carsym **idx)
103 struct vms_indexdef indexdef;
104 unsigned int used;
105 file_ptr off;
106 unsigned int i;
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))
112 return FALSE;
114 /* Traverse it. */
115 used = bfd_getl16 (indexdef.used);
116 for (i = 0; i < used;)
118 unsigned int idx_vbn;
119 unsigned int idx_off;
120 unsigned int keylen;
121 unsigned char *keyname;
122 unsigned char *ridx = (unsigned char *)&indexdef.keys[i];
123 unsigned int len;
125 idx_vbn = bfd_getl32 (ridx);
126 idx_off = bfd_getl16 (ridx + 4);
128 /* Illegal value. */
129 if (idx_vbn == 0)
130 return FALSE;
132 /* Extract key length. */
133 if (bfd_libdata (abfd)->ver == 3)
135 keylen = ridx[6];
136 len = 7;
138 else if (bfd_libdata (abfd)->ver == 4)
140 keylen = bfd_getl16 (ridx + 6);
141 len = 9;
143 else
144 return FALSE;
146 keyname = ridx + len;
147 i += len + keylen;
149 if (idx_off == RFADEF__C_INDEX)
151 /* Indirect entry. Recurse. */
152 if (!vms_traverse_index (abfd, idx_vbn, idx))
153 return FALSE;
155 else
157 /* Add a new entry. */
158 char *name;
160 name = bfd_alloc (abfd, keylen + 1);
161 if (name == NULL)
162 return FALSE;
163 memcpy (name, keyname, keylen);
164 name[keylen] = 0;
165 (*idx)->file_offset = (idx_vbn - 1) * VMS_BLOCK_SIZE + idx_off;
166 (*idx)->name = name;
167 (*idx)++;
171 return TRUE;
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)
179 struct carsym *res;
180 struct carsym *el;
181 struct vms_idd idd;
182 unsigned int flags;
183 unsigned int vbn;
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))
188 return NULL;
190 /* Sanity checks. */
191 flags = bfd_getl16 (idd.flags);
192 if (!(flags & IDD__FLAGS_ASCII)
193 || !(flags & IDD__FLAGS_VARLENIDX))
194 return NULL;
196 res = bfd_alloc (abfd, nbrel * sizeof (struct carsym));
197 if (res == NULL)
198 return NULL;
200 el = res;
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);
207 return NULL;
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);
215 return NULL;
217 return res;
220 /* Standard function. */
222 static const bfd_target *
223 _bfd_vms_lib_archive_p (bfd *abfd, enum vms_lib_kind kind)
225 struct vms_lhd lhd;
226 unsigned int sanity;
227 struct lib_tdata *tdata_hold;
228 struct lib_tdata *tdata;
229 unsigned int dcxvbn;
231 /* Read header. */
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);
236 return NULL;
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);
246 return NULL;
249 /* Check archive kind. */
250 switch (kind)
252 case vms_lib_alpha:
253 if ((lhd.type != LBR__C_TYP_EOBJ && lhd.type != LBR__C_TYP_ESHSTB)
254 || bfd_getl32 (lhd.majorid) != 3
255 || lhd.nindex != 2)
257 bfd_set_error (bfd_error_wrong_format);
258 return NULL;
260 break;
261 case vms_lib_txt:
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
266 || lhd.nindex != 1)
268 bfd_set_error (bfd_error_wrong_format);
269 return NULL;
271 break;
272 default:
273 abort ();
276 /* Allocate and initialize private data. */
277 tdata_hold = bfd_libdata (abfd);
278 tdata = (struct lib_tdata *) bfd_zalloc (abfd, sizeof (struct lib_tdata));
279 if (tdata == NULL)
280 return NULL;
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;
285 tdata->kind = kind;
287 /* Read indexes. */
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)
292 goto err;
293 if (lhd.nindex == 2)
295 tdata->syms = vms_lib_read_index (abfd, 1, tdata->nbr_syms);
296 if (tdata->syms == NULL)
297 goto err;
299 tdata->cache = bfd_zalloc (abfd, sizeof (bfd *) * tdata->nbr_modules);
300 if (tdata->cache == NULL)
301 goto err;
303 /* Read DCX submaps. */
304 dcxvbn = bfd_getl32 (lhd.dcxmapvbn);
305 if (dcxvbn != 0)
307 unsigned char buf_reclen[4];
308 unsigned int reclen;
309 unsigned char *buf;
310 struct vms_dcxmap *map;
311 unsigned int sbm_off;
312 unsigned int i;
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))
317 goto err;
318 reclen = bfd_getl32 (buf_reclen);
319 buf = bfd_malloc (reclen);
320 if (buf == NULL)
321 goto err;
322 if (bfd_bread (buf, reclen, abfd) != reclen)
324 free (buf);
325 goto err;
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;
337 unsigned int sbm_sz;
338 unsigned char *data = (unsigned char *)sbm;
339 unsigned char *buf1;
340 unsigned int l, j;
342 sbm_sz = bfd_getl16 (sbm->size);
343 sbm_off += sbm_sz;
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);
362 free (buf);
364 else
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;
374 return abfd->xvec;
376 err:
377 bfd_release (abfd, tdata);
378 abfd->tdata.any = (void *)tdata_hold;;
379 return NULL;
382 /* Standard function for alpha libraries. */
384 const bfd_target *
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. */
400 bfd_boolean
401 _bfd_vms_lib_mkarchive (bfd *abfd)
403 struct lib_tdata *tdata;
405 tdata = (struct lib_tdata *) bfd_zalloc (abfd, sizeof (struct lib_tdata));
406 if (tdata == NULL)
407 return FALSE;
409 abfd->tdata.any = (void *)tdata;
410 tdata->ver = 3;
411 tdata->mhd_size = sizeof (struct vms_mhd);
412 tdata->type = LBR__C_TYP_EOBJ;
414 tdata->nbr_modules = 0;
415 tdata->nbr_syms = 0;
416 tdata->modules = NULL;
417 tdata->syms = NULL;
418 tdata->cache = NULL;
420 return TRUE;
423 /* Find NAME in the symbol index. Return the index. */
425 symindex
426 _bfd_vms_lib_find_symbol (bfd *abfd, const char *name)
428 struct lib_tdata *tdata = bfd_libdata (abfd);
429 int lo, hi;
431 /* Open-coded binary search for speed. */
432 lo = 0;
433 hi = tdata->nbr_syms - 1;
435 while (lo <= hi)
437 int mid = lo + (hi - lo) / 2;
438 int diff;
440 diff = (char)(name[0] - tdata->syms[mid].name[0]);
441 if (diff == 0)
442 diff = strcmp (name, tdata->syms[mid].name);
443 if (diff == 0)
444 return tdata->syms[mid].file_offset;
445 else if (diff < 0)
446 hi = mid - 1;
447 else
448 lo = mid + 1;
450 return 0;
453 /* IO vector for archive member. Need that because members are not linearly
454 stored in archives. */
456 struct vms_lib_iovec
458 /* Current offset. */
459 ufile_ptr where;
461 /* Length of the module, when known. */
462 ufile_ptr file_len;
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. */
467 int rec_pos;
468 #define REC_POS_NL -4
469 #define REC_POS_PAD -3
470 #define REC_POS_LEN0 -2
471 #define REC_POS_LEN1 -1
473 /* Record length. */
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. */
478 file_ptr 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];
493 /* DCX. */
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;
499 int dcx_pos;
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. */
511 static file_ptr
512 vms_lib_btell (struct bfd *abfd)
514 struct vms_lib_iovec *vec = (struct vms_lib_iovec *) abfd->iostream;
515 return vec->where;
518 /* Read the header of the next data block if all bytes of the current block
519 have been read. */
521 static bfd_boolean
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)
532 return FALSE;
533 if (bfd_bread (hdr, sizeof (hdr), abfd->my_archive) != sizeof (hdr))
534 return FALSE;
535 vec->next_block = (bfd_getl32 (hdr + 2) - 1) * VMS_BLOCK_SIZE;
536 vec->blk_off = sizeof (hdr);
538 return TRUE;
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. */
545 static file_ptr
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;
549 file_ptr res;
551 res = 0;
552 while (nbytes > 0)
554 unsigned int l;
556 /* Be sure the current data block is read. */
557 if (!vms_lib_read_block (abfd))
558 return -1;
560 /* Do not read past the data block, do not read more than requested. */
561 l = DATA__LENGTH - vec->blk_off;
562 if (l > nbytes)
563 l = nbytes;
564 if (l == 0)
565 return 0;
566 if (buf != NULL)
568 /* Really read into BUF. */
569 if (bfd_bread (buf, l, abfd->my_archive) != l)
570 return -1;
572 else
574 /* Make as if we are reading. */
575 if (bfd_seek (abfd->my_archive, l, SEEK_CUR) != 0)
576 return -1;
579 if (buf != NULL)
580 buf += l;
581 vec->blk_off += l;
582 nbytes -= l;
583 res += l;
585 return res;
588 /* Decompress NBYTES from VEC. Store the bytes into BUF if not NULL. */
590 static file_ptr
591 vms_lib_dcx (struct vms_lib_iovec *vec, unsigned char *buf, file_ptr nbytes)
593 struct dcxsbm_desc *sbm;
594 unsigned int i;
595 unsigned int offset;
596 unsigned int j;
597 file_ptr res = 0;
599 /* The loop below expect to deliver at least one byte. */
600 if (nbytes == 0)
601 return 0;
603 /* Get the current state. */
604 sbm = vec->dcx_sbm;
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];
612 for (; j < 8; j++)
614 if (b & (1 << j))
615 offset++;
616 if (!(sbm->flags[offset >> 3] & (1 << (offset & 7))))
618 unsigned int n_offset = sbm->nodes[offset];
619 if (n_offset == 0)
621 /* End of buffer. Stay where we are. */
622 vec->dcx_pos = (i << 3) + j;
623 if (b & (1 << j))
624 offset--;
625 vec->dcx_offset = offset;
626 vec->dcx_sbm = sbm;
627 return res;
629 offset = 2 * n_offset;
631 else
633 unsigned char v = sbm->nodes[offset];
635 sbm = vec->dcxsbms + sbm->next[v];
636 offset = 0;
637 res++;
639 if (buf)
641 *buf++ = v;
642 nbytes--;
644 if (nbytes == 0)
646 vec->dcx_pos = (i << 3) + j + 1;
647 vec->dcx_offset = offset;
648 vec->dcx_sbm = sbm;
650 return res;
655 j = 0;
657 return -1;
660 /* Standard IOVEC function. */
662 static file_ptr
663 vms_lib_bread (struct bfd *abfd, void *buf, file_ptr nbytes)
665 struct vms_lib_iovec *vec = (struct vms_lib_iovec *) abfd->iostream;
666 file_ptr res;
667 file_ptr chunk;
669 /* Do not read past the end. */
670 if (vec->where >= vec->file_len)
671 return 0;
673 res = 0;
674 while (nbytes > 0)
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))
682 return -1;
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. */
687 vec->rec_pos = 0;
688 vec->rec_rem = vec->rec_len;
690 else
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)
700 return -1;
701 if (!memcmp (vec->pattern, eotdesc + 2, 3))
703 /* This is really an EOF. */
704 vec->where += res;
705 vec->file_len = vec->where;
706 return res;
710 if (vec->dcxsbms != NULL)
712 /* This is a compressed member. */
713 unsigned int len;
714 file_ptr elen;
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)
721 vec->dcx_max *= 2;
722 vec->dcx_buf = bfd_alloc (abfd, vec->dcx_max);
723 if (vec->dcx_buf == NULL)
724 return -1;
727 /* Read the compressed record. */
728 vec->dcx_rlen = len;
729 if (vec->rec_len == 3)
731 /* Already read. */
732 memcpy (vec->dcx_buf, vec->pattern, 3);
734 else
736 elen = vms_lib_bread_raw (abfd, vec->dcx_buf, len);
737 if (elen != len)
738 return -1;
741 /* Dummy expansion to get the expanded length. */
742 vec->dcx_offset = 0;
743 vec->dcx_sbm = vec->dcxsbms;
744 vec->dcx_pos = 0;
745 elen = vms_lib_dcx (vec, NULL, 0x10000);
746 if (elen < 0)
747 return -1;
748 vec->rec_len = elen;
749 vec->rec_rem = elen;
751 /* Reset the state. */
752 vec->dcx_offset = 0;
753 vec->dcx_sbm = vec->dcxsbms;
754 vec->dcx_pos = 0;
757 if (vec->rec_pos < 0)
759 unsigned char c;
760 switch (vec->rec_pos)
762 case REC_POS_LEN0:
763 c = vec->rec_len & 0xff;
764 vec->rec_pos = REC_POS_LEN1;
765 break;
766 case REC_POS_LEN1:
767 c = (vec->rec_len >> 8) & 0xff;
768 vec->rec_pos = 0;
769 break;
770 case REC_POS_PAD:
771 c = 0;
772 vec->rec_rem = 0;
773 break;
774 case REC_POS_NL:
775 c = '\n';
776 vec->rec_rem = 0;
777 break;
778 default:
779 abort ();
781 if (buf != NULL)
783 *(unsigned char *)buf = c;
784 buf++;
786 nbytes--;
787 res++;
788 continue;
791 if (nbytes > vec->rec_rem)
792 chunk = vec->rec_rem;
793 else
794 chunk = nbytes;
796 if (vec->dcxsbms != NULL)
798 /* Optimize the stat() case: no need to decompress again as we
799 know the length. */
800 if (!(buf == NULL && chunk == vec->rec_rem))
801 chunk = vms_lib_dcx (vec, buf, chunk);
803 else
805 if (vec->rec_len == 3)
807 if (buf != NULL)
808 memcpy (buf, vec->pattern + vec->rec_pos, chunk);
810 else
811 chunk = vms_lib_bread_raw (abfd, buf, chunk);
813 if (chunk < 0)
814 return -1;
815 res += chunk;
816 if (buf != NULL)
817 buf += chunk;
818 nbytes -= 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
828 && vec->rec_len != 3
829 && vec->dcxsbms == NULL)
831 /* Eat the pad byte. */
832 unsigned char pad;
833 if (vms_lib_bread_raw (abfd, &pad, 1) != 1)
834 return -1;
836 vec->rec_pos = REC_POS_NL;
837 vec->rec_rem = 1;
839 else
841 if ((vec->rec_len & 1) == 1 && vec->dcxsbms != NULL)
843 vec->rec_pos = REC_POS_PAD;
844 vec->rec_rem = 1;
849 vec->where += res;
850 return res;
853 /* Standard function, but we currently only handle the rewind case. */
855 static int
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)
862 vec->where = 0;
863 vec->rec_rem = 0;
864 vec->dcx_pos = -1;
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)
869 return -1;
871 else
872 abort ();
873 return 0;
876 static file_ptr
877 vms_lib_bwrite (struct bfd *abfd ATTRIBUTE_UNUSED,
878 const void *where ATTRIBUTE_UNUSED,
879 file_ptr nbytes ATTRIBUTE_UNUSED)
881 return -1;
884 static int
885 vms_lib_bclose (struct bfd *abfd)
887 abfd->iostream = NULL;
888 return 0;
891 static int
892 vms_lib_bflush (struct bfd *abfd ATTRIBUTE_UNUSED)
894 return 0;
897 static int
898 vms_lib_bstat (struct bfd *abfd ATTRIBUTE_UNUSED,
899 struct stat *sb ATTRIBUTE_UNUSED)
901 /* Not supported. */
902 return 0;
905 static void *
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)
913 return (void *) -1;
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. */
923 static bfd_boolean
924 vms_lib_bopen (bfd *el, file_ptr filepos)
926 struct vms_lib_iovec *vec;
927 char buf[256];
928 struct vms_mhd *mhd;
929 struct lib_tdata *tdata = bfd_libdata (el->my_archive);
930 unsigned int len;
932 /* Allocate and initialized the iovec. */
933 vec = bfd_zalloc (el, sizeof (*vec));
934 if (vec == NULL)
935 return FALSE;
937 el->iostream = vec;
938 el->iovec = &vms_lib_iovec;
940 /* File length is not known. */
941 vec->file_len = -1;
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))
947 return FALSE;
949 /* Prepare to read the first record. */
950 vec->blk_off = filepos & (VMS_BLOCK_SIZE - 1);
951 vec->rec_rem = 0;
952 if (bfd_seek (el->my_archive, filepos, SEEK_SET) != 0)
953 return FALSE;
955 /* Read Record length + MHD + align byte. */
956 len = tdata->mhd_size;
957 if (vms_lib_bread_raw (el, buf, 2) != 2)
958 return -1;
959 if (bfd_getl16 (buf) != len)
960 return -1;
961 len = (len + 1) & ~1;
962 BFD_ASSERT (len <= sizeof (buf));
963 if (vms_lib_bread_raw (el, buf, len) != len)
964 return -1;
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
974 the mhd. */
975 vec->where = 0;
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)
983 /* Handle DCX. */
984 vec->dcx_max = 10 * 1024;
985 vec->dcx_buf = bfd_alloc (el, vec->dcx_max);
986 vec->dcx_pos = -1;
987 if (vec->dcx_buf == NULL)
988 return -1;
990 return TRUE;
993 /* Standard function: get member at IDX. */
995 bfd *
996 _bfd_vms_lib_get_elt_at_index (bfd *abfd, symindex idx)
998 struct lib_tdata *tdata = bfd_libdata (abfd);
999 bfd *res;
1000 unsigned int i;
1002 /* Linear-scan. */
1003 for (i = 0; i < tdata->nbr_modules; i++)
1005 if (tdata->modules[i].file_offset == (file_ptr)idx)
1006 break;
1009 /* Invalid index. */
1010 if (i >= tdata->nbr_modules)
1011 return NULL;
1013 /* Already loaded. */
1014 if (tdata->cache[i])
1015 return tdata->cache[i];
1017 /* Build it. */
1018 res = _bfd_create_empty_archive_element_shell (abfd);
1019 if (!vms_lib_bopen (res, idx))
1020 return NULL;
1021 res->filename = tdata->modules[i].name;
1023 tdata->cache[i] = res;
1025 return res;
1028 /* Elements of an imagelib are stubs. You can get the real image with this
1029 function. */
1031 bfd *
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);
1037 char *filename;
1038 int j;
1039 bfd *res;
1041 /* Convert module name to lower case and append '.exe'. */
1042 filename = bfd_alloc (el, modlen + 5);
1043 if (filename == NULL)
1044 return NULL;
1045 for (j = 0; j < modlen; j++)
1046 if (ISALPHA (modname[j]))
1047 filename[j] = TOLOWER (modname[j]);
1048 else
1049 filename[j] = modname[j];
1050 memcpy (filename + modlen, ".exe", 5);
1052 filename = _bfd_append_relative_path (archive, filename);
1053 if (filename == NULL)
1054 return NULL;
1055 res = bfd_openr (filename, NULL);
1057 if (res == NULL)
1059 (*_bfd_error_handler)(_("could not open shared image '%s' from '%s'"),
1060 filename, archive->filename);
1061 bfd_release (archive, filename);
1062 return NULL;
1065 /* FIXME: put it in a cache ? */
1066 return res;
1069 /* Standard function. */
1071 bfd *
1072 _bfd_vms_lib_openr_next_archived_file (bfd *archive,
1073 bfd *last_file)
1075 unsigned int idx;
1076 bfd *res;
1078 if (!last_file)
1079 idx = 0;
1080 else
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);
1086 return NULL;
1089 res = _bfd_vms_lib_get_elt_at_index
1090 (archive, bfd_libdata (archive)->modules[idx].file_offset);
1091 if (res == NULL)
1092 return res;
1093 res->proxy_origin = idx;
1094 return res;
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);
1107 return -1;
1110 if (vec->file_len == (ufile_ptr)-1)
1112 if (vms_lib_bseek (abfd, 0, SEEK_SET) != 0)
1113 return -1;
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;
1123 else
1124 st->st_mtime = 0;
1125 st->st_uid = 0;
1126 st->st_gid = 0;
1127 st->st_mode = 0644;
1129 return 0;
1132 /* Internal representation of an index entry. */
1134 struct vms_index
1136 /* Corresponding archive member. */
1137 bfd *abfd;
1139 /* Number of reference to this entry. */
1140 unsigned int ref;
1142 /* Length of the key. */
1143 unsigned short namlen;
1145 /* Key. */
1146 const char *name;
1149 /* Used to sort index entries. */
1151 static int
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. */
1166 static unsigned int
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. */
1176 static bfd_boolean
1177 vms_write_index (bfd *abfd,
1178 struct vms_index *idx, unsigned int nbr, unsigned int *vbn,
1179 unsigned int *topvbn)
1181 unsigned int i;
1182 int j;
1183 int level;
1184 struct vms_indexdef *rblk[MAX_LEVEL];
1185 struct idxblk
1187 unsigned int vbn;
1188 unsigned short len;
1189 unsigned short lastlen;
1190 } blk[MAX_LEVEL];
1192 if (nbr == 0)
1194 if (topvbn != NULL)
1195 *topvbn = 0;
1196 return TRUE;
1199 if (abfd == NULL)
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. */
1206 level = 1;
1207 if (abfd != NULL)
1208 rblk[0] = bfd_malloc (sizeof (struct vms_indexdef));
1209 blk[0].vbn = (*vbn)++;
1210 blk[0].len = 0;
1211 blk[0].lastlen = 0;
1213 for (i = 0; i < nbr; i++, idx++)
1215 unsigned int idxlen = get_idxlen (idx);
1216 struct vms_idxdef *en;
1217 int flush = 0;
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)
1223 flush = j + 1;
1225 for (j = 0; j < level; j++)
1227 if (j < flush)
1229 /* There is not enough room to write the new entry in this
1230 block or in a parent block. */
1232 if (j + 1 == level)
1234 BFD_ASSERT (level < MAX_LEVEL);
1236 /* Need to create a parent. */
1237 if (abfd != NULL)
1239 rblk[level] = bfd_malloc (sizeof (struct vms_indexdef));
1240 bfd_putl32 (*vbn, rblk[j]->parent);
1242 blk[level].vbn = (*vbn)++;
1243 blk[level].len = 0;
1244 blk[level].lastlen = 0;
1246 level++;
1249 /* Update parent block: write the new entry. */
1250 if (abfd != NULL)
1252 en = (struct vms_idxdef *)(rblk[j]->keys + blk[j].len);
1253 memcpy (rblk[j + 1]->keys + blk[j + 1].len, en,
1254 blk[j].lastlen);
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);
1261 if (j + 1 == flush)
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
1265 updated too). */
1266 blk[j + 1].len += blk[j].lastlen;
1267 blk[j + 1].lastlen = 0;
1270 /* Write this block on the disk. */
1271 if (abfd != NULL)
1273 bfd_putl16 (blk[j].len + blk[j].lastlen, rblk[j]->used);
1274 if (bfd_seek (abfd, (blk[j].vbn - 1) * VMS_BLOCK_SIZE,
1275 SEEK_SET) != 0)
1276 return FALSE;
1277 if (bfd_bwrite (rblk[j], sizeof (struct vms_indexdef), abfd)
1278 != sizeof (struct vms_indexdef))
1279 return FALSE;
1282 /* Reset this block. */
1283 blk[j].len = 0;
1284 blk[j].lastlen = 0;
1285 blk[j].vbn = (*vbn)++;
1288 /* Append it to the block. */
1289 if (j == 0)
1291 blk[j].len += blk[j].lastlen;
1293 if (abfd != NULL)
1295 en = (struct vms_idxdef *)(rblk[j]->keys + blk[j].len);
1296 bfd_putl32 ((idx->abfd->proxy_origin / VMS_BLOCK_SIZE) + 1,
1297 en->vbn);
1298 bfd_putl16
1299 ((idx->abfd->proxy_origin % VMS_BLOCK_SIZE) + DATA__DATA,
1300 en->offset);
1301 en->keylen = idx->namlen;
1302 memcpy (en->keyname, idx->name, idx->namlen);
1306 blk[j].lastlen = idxlen;
1310 if (topvbn != NULL)
1311 *topvbn = blk[level - 1].vbn;
1313 if (abfd == NULL)
1314 return TRUE;
1316 /* Flush. */
1317 for (j = 0; j < level; j++)
1319 if (j > 0)
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,
1335 SEEK_SET) != 0)
1336 return FALSE;
1337 if (bfd_bwrite (rblk[j], sizeof (struct vms_indexdef), abfd)
1338 != sizeof (struct vms_indexdef))
1339 return FALSE;
1341 free (rblk[j]);
1344 return TRUE;
1347 /* Append data to the data block DATA. Force write if PAD is true. */
1349 static bfd_boolean
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;
1357 unsigned int l;
1359 l = (len > remlen) ? remlen : len;
1360 memcpy (data->data + doff, buf, l);
1361 buf += l;
1362 len -= l;
1363 doff += l;
1364 *off += l;
1366 if (doff == (DATA__LENGTH - DATA__DATA) || (len == 0 && pad))
1368 data->recs = 0;
1369 data->fill_1 = 0;
1370 bfd_putl32 ((*off / VMS_BLOCK_SIZE) + 2, data->link);
1372 if (bfd_bwrite (data, sizeof (*data), arch) != sizeof (*data))
1373 return FALSE;
1375 *off += DATA__LENGTH - doff;
1377 if (len == 0)
1378 break;
1381 return TRUE;
1384 /* Build the symbols index. */
1386 static bfd_boolean
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)
1392 unsigned int i;
1393 asymbol **syms = NULL;
1394 long syms_max = 0;
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));
1400 if (map == NULL)
1401 goto error_return;
1403 /* Gather symbols. */
1404 for (i = 0; i < nbr_modules; i++)
1406 long storage;
1407 long symcount;
1408 long src_count;
1409 bfd *current = modules[i].abfd;
1411 if ((bfd_get_file_flags (current) & HAS_SYMS) == 0)
1412 continue;
1414 storage = bfd_get_symtab_upper_bound (current);
1415 if (storage < 0)
1416 goto error_return;
1418 if (storage != 0)
1420 if (storage > syms_max)
1422 if (syms_max > 0)
1423 free (syms);
1424 syms_max = storage;
1425 syms = (asymbol **) bfd_malloc (syms_max);
1426 if (syms == NULL)
1427 goto error_return;
1429 symcount = bfd_canonicalize_symtab (current, syms);
1430 if (symcount < 0)
1431 goto error_return;
1433 /* Now map over all the symbols, picking out the ones we
1434 want. */
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
1441 || flags & BSF_WEAK
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)
1451 map_max *= 2;
1452 new_map = (struct vms_index *)
1453 bfd_realloc (map, map_max * sizeof (struct vms_index));
1454 if (new_map == NULL)
1455 goto error_return;
1456 map = new_map;
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;
1463 map_count++;
1464 modules[i].ref++;
1470 *res_cnt = map_count;
1471 *res = map;
1472 return TRUE;
1474 error_return:
1475 if (syms_max > 0)
1476 free (syms);
1477 if (map != NULL)
1478 free (map);
1479 return FALSE;
1482 /* Do the hard work: write an archive on the disk. */
1484 bfd_boolean
1485 _bfd_vms_lib_write_archive_contents (bfd *arch)
1487 bfd *current;
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);
1493 unsigned int i;
1494 file_ptr off;
1495 unsigned int nbr_mod_iblk;
1496 unsigned int nbr_sym_iblk;
1497 unsigned int vbn;
1498 unsigned int mod_idx_vbn;
1499 unsigned int sym_idx_vbn;
1501 /* Count the number of modules (and do a first sanity check). */
1502 nbr_modules = 0;
1503 for (current = arch->archive_head;
1504 current != NULL;
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);
1515 goto input_err;
1518 nbr_modules++;
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)
1525 return FALSE;
1527 for (current = arch->archive_head, i = 0;
1528 current != NULL;
1529 current = current->archive_next, i++)
1531 int nl;
1533 modules[i].abfd = current;
1534 modules[i].name = vms_get_module_name (current->filename, FALSE);
1535 modules[i].ref = 1;
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. */
1543 vbn = 0;
1544 if (!vms_write_index (NULL, modules, nbr_modules, &vbn, NULL))
1545 return FALSE;
1546 nbr_mod_iblk = vbn;
1548 /* Create symbol index. */
1549 if (!_bfd_vms_lib_build_map (nbr_modules, modules, &nbr_symbols, &symbols))
1550 return FALSE;
1552 vbn = 0;
1553 if (!vms_write_index (NULL, symbols, nbr_symbols, &vbn, NULL))
1554 return FALSE;
1555 nbr_sym_iblk = vbn;
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)
1561 return FALSE;
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;
1568 unsigned int sz;
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));
1576 mhd->lbrflag = 0;
1577 mhd->id = MHD__C_MHDID;
1578 mhd->objidlng = 4;
1579 memcpy (mhd->objid, "V1.0", 4);
1580 bfd_putl32 (modules[i].ref, mhd->refcnt);
1581 /* FIXME: datim. */
1583 sz = (2 + sizeof (struct vms_mhd) + 1) & ~1;
1584 if (vms_write_data_block (arch, &data, &off, blk, sz, 0) < 0)
1585 goto input_err;
1587 if (bfd_seek (current, 0, SEEK_SET) != 0)
1588 goto input_err;
1590 while (1)
1592 sz = bfd_bread (blk, sizeof (blk), current);
1593 if (sz == 0)
1594 break;
1595 if (vms_write_data_block (arch, &data, &off, blk, sz, 0) < 0)
1596 goto input_err;
1598 if (vms_write_data_block (arch, &data, &off,
1599 eotdesc, sizeof (eotdesc), 1) < 0)
1600 goto input_err;
1603 /* Write the indexes. */
1604 vbn = 2;
1605 if (vms_write_index (arch, modules, nbr_modules, &vbn, &mod_idx_vbn) != TRUE)
1606 return FALSE;
1607 if (vms_write_index (arch, symbols, nbr_symbols, &vbn, &sym_idx_vbn) != TRUE)
1608 return FALSE;
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;
1620 lhd->nindex = 2;
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,
1625 "GNU ar %u.%u.%u",
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);
1632 /* FIXME. */
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);
1651 idd++;
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);
1657 idd++;
1659 if (bfd_seek (arch, 0, SEEK_SET) != 0)
1660 return FALSE;
1661 if (bfd_bwrite (blk, sizeof (blk), arch) != sizeof (blk))
1662 return FALSE;
1665 return TRUE;
1667 input_err:
1668 bfd_set_error (bfd_error_on_input, current, bfd_get_error ());
1669 return FALSE;
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),
1708 NULL,
1710 (PTR) 0