bfd/ChangeLog
[binutils.git] / bfd / vms-lib.c
blob4f7da81d7924fb8877a939216451c298541adf48
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 l = DATA__LENGTH - vec->blk_off;
561 if (l > nbytes)
562 l = nbytes;
563 if (l == 0)
564 return 0;
565 if (buf != NULL)
567 if (bfd_bread (buf, l, abfd->my_archive) != l)
568 return -1;
570 else
572 if (bfd_seek (abfd->my_archive, l, SEEK_CUR) != 0)
573 return -1;
576 if (buf != NULL)
577 buf += l;
578 vec->blk_off += l;
579 nbytes -= l;
580 res += l;
582 return res;
585 /* Decompress NBYTES from VEC. Store the bytes into BUF if not NULL. */
587 static file_ptr
588 vms_lib_dcx (struct vms_lib_iovec *vec, unsigned char *buf, file_ptr nbytes)
590 struct dcxsbm_desc *sbm;
591 unsigned int i;
592 unsigned int offset;
593 unsigned int j;
594 file_ptr res = 0;
596 /* The loop below expect to deliver at least one byte. */
597 if (nbytes == 0)
598 return 0;
600 /* Get the current state. */
601 sbm = vec->dcx_sbm;
602 offset = vec->dcx_offset;
603 j = vec->dcx_pos & 7;
605 for (i = vec->dcx_pos >> 3; i < vec->dcx_rlen; i++)
607 unsigned char b = vec->dcx_buf[i];
609 for (; j < 8; j++)
611 if (b & (1 << j))
612 offset++;
613 if (!(sbm->flags[offset >> 3] & (1 << (offset & 7))))
615 unsigned int n_offset = sbm->nodes[offset];
616 if (n_offset == 0)
618 /* End of buffer. Stay where we are. */
619 vec->dcx_pos = (i << 3) + j;
620 if (b & (1 << j))
621 offset--;
622 vec->dcx_offset = offset;
623 vec->dcx_sbm = sbm;
624 return res;
626 offset = 2 * n_offset;
628 else
630 unsigned char v = sbm->nodes[offset];
632 sbm = vec->dcxsbms + sbm->next[v];
633 offset = 0;
634 res++;
636 if (buf)
638 *buf++ = v;
639 nbytes--;
641 if (nbytes == 0)
643 vec->dcx_pos = (i << 3) + j + 1;
644 vec->dcx_offset = offset;
645 vec->dcx_sbm = sbm;
647 return res;
652 j = 0;
654 return -1;
657 /* Standard IOVEC function. */
659 static file_ptr
660 vms_lib_bread (struct bfd *abfd, void *buf, file_ptr nbytes)
662 struct vms_lib_iovec *vec = (struct vms_lib_iovec *) abfd->iostream;
663 file_ptr res;
664 file_ptr chunk;
666 /* Do not read past the end. */
667 if (vec->where >= vec->file_len)
668 return 0;
670 res = 0;
671 while (nbytes > 0)
673 if (vec->rec_rem == 0)
675 unsigned char blen[2];
677 /* Read record length. */
678 if (vms_lib_bread_raw (abfd, &blen, sizeof (blen)) != sizeof (blen))
679 return -1;
680 vec->rec_len = bfd_getl16 (blen);
681 if (bfd_libdata (abfd->my_archive)->kind == vms_lib_txt)
683 /* Discard record size and align byte. */
684 vec->rec_pos = 0;
685 vec->rec_rem = vec->rec_len;
687 else
689 /* Prepend record size. */
690 vec->rec_pos = REC_POS_LEN0;
691 vec->rec_rem = (vec->rec_len + 1) & ~1; /* With align byte. */
693 if (vec->rec_len == 3)
695 /* Possibly end of file. Check the pattern. */
696 if (vms_lib_bread_raw (abfd, vec->pattern, 4) != 4)
697 return -1;
698 if (!memcmp (vec->pattern, eotdesc + 2, 3))
700 /* This is really an EOF. */
701 vec->where += res;
702 vec->file_len = vec->where;
703 return res;
707 if (vec->dcxsbms != NULL)
709 /* This is a compressed member. */
710 unsigned int len;
711 file_ptr elen;
713 /* Be sure there is enough room for the expansion. */
714 len = (vec->rec_len + 1) & ~1;
715 if (len > vec->dcx_max)
717 while (len > vec->dcx_max)
718 vec->dcx_max *= 2;
719 vec->dcx_buf = bfd_alloc (abfd, vec->dcx_max);
720 if (vec->dcx_buf == NULL)
721 return -1;
724 /* Read the compressed record. */
725 vec->dcx_rlen = len;
726 if (vec->rec_len == 3)
728 /* Already read. */
729 memcpy (vec->dcx_buf, vec->pattern, 3);
731 else
733 elen = vms_lib_bread_raw (abfd, vec->dcx_buf, len);
734 if (elen != len)
735 return -1;
738 /* Dummy expansion to get the expanded length. */
739 vec->dcx_offset = 0;
740 vec->dcx_sbm = vec->dcxsbms;
741 vec->dcx_pos = 0;
742 elen = vms_lib_dcx (vec, NULL, 0x10000);
743 if (elen < 0)
744 return -1;
745 vec->rec_len = elen;
746 vec->rec_rem = elen;
748 /* Reset the state. */
749 vec->dcx_offset = 0;
750 vec->dcx_sbm = vec->dcxsbms;
751 vec->dcx_pos = 0;
754 if (vec->rec_pos < 0)
756 unsigned char c;
757 switch (vec->rec_pos)
759 case REC_POS_LEN0:
760 c = vec->rec_len & 0xff;
761 vec->rec_pos = REC_POS_LEN1;
762 break;
763 case REC_POS_LEN1:
764 c = (vec->rec_len >> 8) & 0xff;
765 vec->rec_pos = 0;
766 break;
767 case REC_POS_PAD:
768 c = 0;
769 vec->rec_rem = 0;
770 break;
771 case REC_POS_NL:
772 c = '\n';
773 vec->rec_rem = 0;
774 break;
775 default:
776 abort ();
778 if (buf != NULL)
780 *(unsigned char *)buf = c;
781 buf++;
783 nbytes--;
784 res++;
785 continue;
788 if (nbytes > vec->rec_rem)
789 chunk = vec->rec_rem;
790 else
791 chunk = nbytes;
793 if (vec->dcxsbms != NULL)
795 /* Optimize the stat() case: no need to decompress again as we
796 know the length. */
797 if (!(buf == NULL && chunk == vec->rec_rem))
798 chunk = vms_lib_dcx (vec, buf, chunk);
800 else
802 if (vec->rec_len == 3)
804 if (buf != NULL)
805 memcpy (buf, vec->pattern + vec->rec_pos, chunk);
807 else
808 chunk = vms_lib_bread_raw (abfd, buf, chunk);
810 if (chunk < 0)
811 return -1;
812 res += chunk;
813 if (buf != NULL)
814 buf += chunk;
815 nbytes -= chunk;
816 vec->rec_pos += chunk;
817 vec->rec_rem -= chunk;
819 if (vec->rec_rem == 0)
821 if (bfd_libdata (abfd->my_archive)->kind == vms_lib_txt)
823 if ((vec->rec_len & 1) == 1
824 && vec->rec_len != 3
825 && vec->dcxsbms == NULL)
827 /* Eat the pad byte. */
828 unsigned char pad;
829 if (vms_lib_bread_raw (abfd, &pad, 1) != 1)
830 return -1;
832 vec->rec_pos = REC_POS_NL;
833 vec->rec_rem = 1;
835 else
837 if ((vec->rec_len & 1) == 1 && vec->dcxsbms != NULL)
839 vec->rec_pos = REC_POS_PAD;
840 vec->rec_rem = 1;
845 vec->where += res;
846 return res;
849 /* Standard function, but we currently only handle the rewind case. */
851 static int
852 vms_lib_bseek (struct bfd *abfd, file_ptr offset, int whence)
854 struct vms_lib_iovec *vec = (struct vms_lib_iovec *) abfd->iostream;
856 if (whence == SEEK_SET && offset == 0)
858 vec->where = 0;
859 vec->rec_rem = 0;
860 vec->dcx_pos = -1;
861 vec->blk_off = vec->init_blk_off;
862 vec->next_block = vec->init_next_block;
864 if (bfd_seek (abfd->my_archive, vec->first_block, SEEK_SET) != 0)
865 return -1;
867 else
868 abort ();
869 return 0;
872 static file_ptr
873 vms_lib_bwrite (struct bfd *abfd ATTRIBUTE_UNUSED,
874 const void *where ATTRIBUTE_UNUSED,
875 file_ptr nbytes ATTRIBUTE_UNUSED)
877 return -1;
880 static int
881 vms_lib_bclose (struct bfd *abfd)
883 abfd->iostream = NULL;
884 return 0;
887 static int
888 vms_lib_bflush (struct bfd *abfd ATTRIBUTE_UNUSED)
890 return 0;
893 static int
894 vms_lib_bstat (struct bfd *abfd ATTRIBUTE_UNUSED,
895 struct stat *sb ATTRIBUTE_UNUSED)
897 /* Not supported. */
898 return 0;
901 static void *
902 vms_lib_bmmap (struct bfd *abfd ATTRIBUTE_UNUSED,
903 void *addr ATTRIBUTE_UNUSED,
904 bfd_size_type len ATTRIBUTE_UNUSED,
905 int prot ATTRIBUTE_UNUSED,
906 int flags ATTRIBUTE_UNUSED,
907 file_ptr offset ATTRIBUTE_UNUSED)
909 return (void *) -1;
912 static const struct bfd_iovec vms_lib_iovec = {
913 &vms_lib_bread, &vms_lib_bwrite, &vms_lib_btell, &vms_lib_bseek,
914 &vms_lib_bclose, &vms_lib_bflush, &vms_lib_bstat, &vms_lib_bmmap
917 /* Open a library module. FILEPOS is the position of the module header. */
919 static bfd_boolean
920 vms_lib_bopen (bfd *el, file_ptr filepos)
922 struct vms_lib_iovec *vec;
923 char buf[256];
924 struct vms_mhd *mhd;
925 struct lib_tdata *tdata = bfd_libdata (el->my_archive);
926 unsigned int len;
928 /* Allocate and initialized the iovec. */
929 vec = bfd_zalloc (el, sizeof (*vec));
930 if (vec == NULL)
931 return FALSE;
933 el->iostream = vec;
934 el->iovec = &vms_lib_iovec;
936 /* File length is not known. */
937 vec->file_len = -1;
939 /* Read the first data block. */
940 vec->next_block = filepos & ~(VMS_BLOCK_SIZE - 1);
941 vec->blk_off = DATA__LENGTH;
942 if (!vms_lib_read_block (el))
943 return FALSE;
945 /* Prepare to read the first record. */
946 vec->blk_off = filepos & (VMS_BLOCK_SIZE - 1);
947 vec->rec_rem = 0;
948 if (bfd_seek (el->my_archive, filepos, SEEK_SET) != 0)
949 return FALSE;
951 /* Read Record length + MHD + align byte. */
952 len = tdata->mhd_size;
953 if (vms_lib_bread_raw (el, buf, 2) != 2)
954 return -1;
955 if (bfd_getl16 (buf) != len)
956 return -1;
957 len = (len + 1) & ~1;
958 BFD_ASSERT (len <= sizeof (buf));
959 if (vms_lib_bread_raw (el, buf, len) != len)
960 return -1;
962 /* Get info from mhd. */
963 mhd = (struct vms_mhd *)buf;
964 if (len >= sizeof (struct vms_mhd))
965 el->selective_search = (mhd->objstat & MHD__M_SELSRC) ? 1 : 0;
966 el->mtime = vms_rawtime_to_time_t (mhd->datim);
967 el->mtime_set = TRUE;
969 /* Reinit the iovec so that seek() will point to the first record after
970 the mhd. */
971 vec->where = 0;
972 vec->init_blk_off = vec->blk_off;
973 vec->init_next_block = vec->next_block;
974 vec->first_block = bfd_tell (el->my_archive);
975 vec->dcxsbms = bfd_libdata (el->my_archive)->dcxsbm;
977 if (vec->dcxsbms != NULL)
979 /* Handle DCX. */
980 vec->dcx_max = 10 * 1024;
981 vec->dcx_buf = bfd_alloc (el, vec->dcx_max);
982 vec->dcx_pos = -1;
983 if (vec->dcx_buf == NULL)
984 return -1;
986 return TRUE;
989 /* Standard function: get member at IDX. */
991 bfd *
992 _bfd_vms_lib_get_elt_at_index (bfd *abfd, symindex idx)
994 struct lib_tdata *tdata = bfd_libdata (abfd);
995 bfd *res;
996 unsigned int i;
998 /* Linear-scan. */
999 for (i = 0; i < tdata->nbr_modules; i++)
1001 if (tdata->modules[i].file_offset == (file_ptr)idx)
1002 break;
1005 /* Invalid index. */
1006 if (i >= tdata->nbr_modules)
1007 return NULL;
1009 /* Already loaded. */
1010 if (tdata->cache[i])
1011 return tdata->cache[i];
1013 /* Build it. */
1014 res = _bfd_create_empty_archive_element_shell (abfd);
1015 if (!vms_lib_bopen (res, idx))
1016 return NULL;
1017 res->filename = tdata->modules[i].name;
1019 tdata->cache[i] = res;
1021 return res;
1024 /* Elements of an imagelib are stubs. You can get the real image with this
1025 function. */
1027 bfd *
1028 _bfd_vms_lib_get_imagelib_file (bfd *el)
1030 bfd *archive = el->my_archive;
1031 const char *modname = el->filename;
1032 int modlen = strlen (modname);
1033 char *filename;
1034 int j;
1035 bfd *res;
1037 /* Convert module name to lower case and append '.exe'. */
1038 filename = bfd_alloc (el, modlen + 5);
1039 if (filename == NULL)
1040 return NULL;
1041 for (j = 0; j < modlen; j++)
1042 if (ISALPHA (modname[j]))
1043 filename[j] = TOLOWER (modname[j]);
1044 else
1045 filename[j] = modname[j];
1046 memcpy (filename + modlen, ".exe", 5);
1048 filename = _bfd_append_relative_path (archive, filename);
1049 if (filename == NULL)
1050 return NULL;
1051 res = bfd_openr (filename, NULL);
1053 if (res == NULL)
1055 (*_bfd_error_handler)(_("could not open shared image '%s' from '%s'"),
1056 filename, archive->filename);
1057 bfd_release (archive, filename);
1058 return NULL;
1061 /* FIXME: put it in a cache ? */
1062 return res;
1065 /* Standard function. */
1067 bfd *
1068 _bfd_vms_lib_openr_next_archived_file (bfd *archive,
1069 bfd *last_file)
1071 unsigned int idx;
1072 bfd *res;
1074 if (!last_file)
1075 idx = 0;
1076 else
1077 idx = last_file->proxy_origin + 1;
1079 if (idx >= bfd_libdata (archive)->nbr_modules)
1081 bfd_set_error (bfd_error_no_more_archived_files);
1082 return NULL;
1085 res = _bfd_vms_lib_get_elt_at_index
1086 (archive, bfd_libdata (archive)->modules[idx].file_offset);
1087 if (res == NULL)
1088 return res;
1089 res->proxy_origin = idx;
1090 return res;
1093 /* Standard function. Just compute the length. */
1096 _bfd_vms_lib_generic_stat_arch_elt (bfd *abfd, struct stat *st)
1098 struct vms_lib_iovec *vec = (struct vms_lib_iovec *) abfd->iostream;
1100 if (abfd->my_archive == NULL)
1102 bfd_set_error (bfd_error_invalid_operation);
1103 return -1;
1106 if (vec->file_len == (ufile_ptr)-1)
1108 if (vms_lib_bseek (abfd, 0, SEEK_SET) != 0)
1109 return -1;
1111 /* Compute length. */
1112 while (vms_lib_bread (abfd, NULL, 1 << 20) > 0)
1116 st->st_size = vec->file_len;
1117 if (abfd->mtime_set)
1118 st->st_mtime = abfd->mtime;
1119 else
1120 st->st_mtime = 0;
1121 st->st_uid = 0;
1122 st->st_gid = 0;
1123 st->st_mode = 0644;
1125 return 0;
1128 /* Internal representation of an index entry. */
1130 struct vms_index
1132 /* Corresponding archive member. */
1133 bfd *abfd;
1135 /* Number of reference to this entry. */
1136 unsigned int ref;
1138 /* Length of the key. */
1139 unsigned short namlen;
1141 /* Key. */
1142 const char *name;
1145 /* Used to sort index entries. */
1147 static int
1148 vms_index_cmp (const void *lv, const void *rv)
1150 const struct vms_index *l = lv;
1151 const struct vms_index *r = rv;
1153 return strcmp (l->name, r->name);
1156 /* Maximum number of index blocks level. */
1158 #define MAX_LEVEL 10
1160 /* Get the size of an index entry. */
1162 static unsigned int
1163 get_idxlen (struct vms_index *idx)
1165 return 7 + idx->namlen;
1168 /* Write the index. VBN is the first vbn to be used, and will contain
1169 on return the last vbn.
1170 Return TRUE on success. */
1172 static bfd_boolean
1173 vms_write_index (bfd *abfd,
1174 struct vms_index *idx, unsigned int nbr, unsigned int *vbn,
1175 unsigned int *topvbn)
1177 unsigned int i;
1178 int j;
1179 int level;
1180 struct vms_indexdef *rblk[MAX_LEVEL];
1181 struct idxblk
1183 unsigned int vbn;
1184 unsigned short len;
1185 unsigned short lastlen;
1186 } blk[MAX_LEVEL];
1188 if (nbr == 0)
1190 if (topvbn != NULL)
1191 *topvbn = 0;
1192 return TRUE;
1195 if (abfd == NULL)
1197 /* Sort the index the first time this function is called. */
1198 qsort (idx, nbr, sizeof (struct vms_index), vms_index_cmp);
1201 /* Allocate first index block. */
1202 level = 1;
1203 if (abfd != NULL)
1204 rblk[0] = bfd_malloc (sizeof (struct vms_indexdef));
1205 blk[0].vbn = (*vbn)++;
1206 blk[0].len = 0;
1207 blk[0].lastlen = 0;
1209 for (i = 0; i < nbr; i++, idx++)
1211 unsigned int idxlen = get_idxlen (idx);
1212 struct vms_idxdef *en;
1213 int flush = 0;
1215 /* Check if a block might overflow. In this case we will flush this
1216 block and all the blocks below it. */
1217 for (j = 0; j < level; j++)
1218 if (blk[j].len + blk[j].lastlen + idxlen > INDEXDEF__BLKSIZ)
1219 flush = j + 1;
1221 for (j = 0; j < level; j++)
1223 if (j < flush)
1225 /* There is not enough room to write the new entry in this
1226 block or in a parent block. */
1228 if (j + 1 == level)
1230 BFD_ASSERT (level < MAX_LEVEL);
1232 /* Need to create a parent. */
1233 if (abfd != NULL)
1235 rblk[level] = bfd_malloc (sizeof (struct vms_indexdef));
1236 bfd_putl32 (*vbn, rblk[j]->parent);
1238 blk[level].vbn = (*vbn)++;
1239 blk[level].len = 0;
1240 blk[level].lastlen = 0;
1242 level++;
1245 /* Update parent block: write the new entry. */
1246 if (abfd != NULL)
1248 en = (struct vms_idxdef *)(rblk[j]->keys + blk[j].len);
1249 memcpy (rblk[j + 1]->keys + blk[j + 1].len, en,
1250 blk[j].lastlen);
1251 en = (struct vms_idxdef *)
1252 (rblk[j + 1]->keys + blk[j + 1].len);
1253 bfd_putl32 (blk[j].vbn, en->vbn);
1254 bfd_putl16 (RFADEF__C_INDEX, en->offset);
1257 if (j + 1 == flush)
1259 /* And allocate it. Do it only on the block that won't be
1260 flushed (so that the parent of the parent can be
1261 updated too). */
1262 blk[j + 1].len += blk[j].lastlen;
1263 blk[j + 1].lastlen = 0;
1266 /* Write this block on the disk. */
1267 if (abfd != NULL)
1269 bfd_putl16 (blk[j].len + blk[j].lastlen, rblk[j]->used);
1270 if (bfd_seek (abfd, (blk[j].vbn - 1) * VMS_BLOCK_SIZE,
1271 SEEK_SET) != 0)
1272 return FALSE;
1273 if (bfd_bwrite (rblk[j], sizeof (struct vms_indexdef), abfd)
1274 != sizeof (struct vms_indexdef))
1275 return FALSE;
1278 /* Reset this block. */
1279 blk[j].len = 0;
1280 blk[j].lastlen = 0;
1281 blk[j].vbn = (*vbn)++;
1284 /* Append it to the block. */
1285 if (j == 0)
1287 blk[j].len += blk[j].lastlen;
1289 if (abfd != NULL)
1291 en = (struct vms_idxdef *)(rblk[j]->keys + blk[j].len);
1292 bfd_putl32 ((idx->abfd->proxy_origin / VMS_BLOCK_SIZE) + 1,
1293 en->vbn);
1294 bfd_putl16
1295 ((idx->abfd->proxy_origin % VMS_BLOCK_SIZE) + DATA__DATA,
1296 en->offset);
1297 en->keylen = idx->namlen;
1298 memcpy (en->keyname, idx->name, idx->namlen);
1302 blk[j].lastlen = idxlen;
1306 if (topvbn != NULL)
1307 *topvbn = blk[level - 1].vbn;
1309 if (abfd == NULL)
1310 return TRUE;
1312 /* Flush. */
1313 for (j = 0; j < level; j++)
1315 if (j > 0)
1317 /* Update parent block: write the new entry. */
1318 struct vms_idxdef *en;
1319 struct vms_idxdef *par;
1321 en = (struct vms_idxdef *)(rblk[j - 1]->keys + blk[j - 1].len);
1322 par = (struct vms_idxdef *)(rblk[j]->keys + blk[j].len);
1323 memcpy (par, en, blk[j - 1].lastlen);
1324 bfd_putl32 (blk[j - 1].vbn, par->vbn);
1325 bfd_putl16 (RFADEF__C_INDEX, par->offset);
1328 /* Write this block on the disk. */
1329 bfd_putl16 (blk[j].len + blk[j].lastlen, rblk[j]->used);
1330 if (bfd_seek (abfd, (blk[j].vbn - 1) * VMS_BLOCK_SIZE,
1331 SEEK_SET) != 0)
1332 return FALSE;
1333 if (bfd_bwrite (rblk[j], sizeof (struct vms_indexdef), abfd)
1334 != sizeof (struct vms_indexdef))
1335 return FALSE;
1337 free (rblk[j]);
1340 return TRUE;
1343 /* Append data to the data block DATA. Force write if PAD is true. */
1345 static bfd_boolean
1346 vms_write_data_block (bfd *arch, struct vms_datadef *data, file_ptr *off,
1347 const unsigned char *buf, unsigned int len, int pad)
1349 while (len > 0 || pad)
1351 unsigned int doff = *off & (VMS_BLOCK_SIZE - 1);
1352 unsigned int remlen = (DATA__LENGTH - DATA__DATA) - doff;
1353 unsigned int l;
1355 l = (len > remlen) ? remlen : len;
1356 memcpy (data->data + doff, buf, l);
1357 buf += l;
1358 len -= l;
1359 doff += l;
1360 *off += l;
1362 if (doff == (DATA__LENGTH - DATA__DATA) || (len == 0 && pad))
1364 data->recs = 0;
1365 data->fill_1 = 0;
1366 bfd_putl32 ((*off / VMS_BLOCK_SIZE) + 2, data->link);
1368 if (bfd_bwrite (data, sizeof (*data), arch) != sizeof (*data))
1369 return FALSE;
1371 *off += DATA__LENGTH - doff;
1373 if (len == 0)
1374 break;
1377 return TRUE;
1380 /* Build the symbols index. */
1382 static bfd_boolean
1383 _bfd_vms_lib_build_map (unsigned int nbr_modules,
1384 struct vms_index *modules,
1385 unsigned int *res_cnt,
1386 struct vms_index **res)
1388 unsigned int i;
1389 asymbol **syms = NULL;
1390 long syms_max = 0;
1391 struct vms_index *map = NULL;
1392 unsigned int map_max = 1024; /* Fine initial default. */
1393 unsigned int map_count = 0;
1395 map = (struct vms_index *) bfd_malloc (map_max * sizeof (struct vms_index));
1396 if (map == NULL)
1397 goto error_return;
1399 /* Gather symbols. */
1400 for (i = 0; i < nbr_modules; i++)
1402 long storage;
1403 long symcount;
1404 long src_count;
1405 bfd *current = modules[i].abfd;
1407 if ((bfd_get_file_flags (current) & HAS_SYMS) == 0)
1408 continue;
1410 storage = bfd_get_symtab_upper_bound (current);
1411 if (storage < 0)
1412 goto error_return;
1414 if (storage != 0)
1416 if (storage > syms_max)
1418 if (syms_max > 0)
1419 free (syms);
1420 syms_max = storage;
1421 syms = (asymbol **) bfd_malloc (syms_max);
1422 if (syms == NULL)
1423 goto error_return;
1425 symcount = bfd_canonicalize_symtab (current, syms);
1426 if (symcount < 0)
1427 goto error_return;
1429 /* Now map over all the symbols, picking out the ones we
1430 want. */
1431 for (src_count = 0; src_count < symcount; src_count++)
1433 flagword flags = (syms[src_count])->flags;
1434 asection *sec = syms[src_count]->section;
1436 if ((flags & BSF_GLOBAL
1437 || flags & BSF_WEAK
1438 || flags & BSF_INDIRECT
1439 || bfd_is_com_section (sec))
1440 && ! bfd_is_und_section (sec))
1442 struct vms_index *new_map;
1444 /* This symbol will go into the archive header. */
1445 if (map_count == map_max)
1447 map_max *= 2;
1448 new_map = (struct vms_index *)
1449 bfd_realloc (map, map_max * sizeof (struct vms_index));
1450 if (new_map == NULL)
1451 goto error_return;
1452 map = new_map;
1455 map[map_count].abfd = current;
1456 /* FIXME: check length. */
1457 map[map_count].namlen = strlen (syms[src_count]->name);
1458 map[map_count].name = syms[src_count]->name;
1459 map_count++;
1460 modules[i].ref++;
1466 *res_cnt = map_count;
1467 *res = map;
1468 return TRUE;
1470 error_return:
1471 if (syms_max > 0)
1472 free (syms);
1473 if (map != NULL)
1474 free (map);
1475 return FALSE;
1478 /* Do the hard work: write an archive on the disk. */
1480 bfd_boolean
1481 _bfd_vms_lib_write_archive_contents (bfd *arch)
1483 bfd *current;
1484 unsigned int nbr_modules;
1485 struct vms_index *modules;
1486 unsigned int nbr_symbols;
1487 struct vms_index *symbols;
1488 struct lib_tdata *tdata = bfd_libdata (arch);
1489 unsigned int i;
1490 file_ptr off;
1491 unsigned int nbr_mod_iblk;
1492 unsigned int nbr_sym_iblk;
1493 unsigned int vbn;
1494 unsigned int mod_idx_vbn;
1495 unsigned int sym_idx_vbn;
1497 /* Count the number of modules (and do a first sanity check). */
1498 nbr_modules = 0;
1499 for (current = arch->archive_head;
1500 current != NULL;
1501 current = current->archive_next)
1503 /* This check is checking the bfds for the objects we're reading
1504 from (which are usually either an object file or archive on
1505 disk), not the archive entries we're writing to. We don't
1506 actually create bfds for the archive members, we just copy
1507 them byte-wise when we write out the archive. */
1508 if (bfd_write_p (current) || !bfd_check_format (current, bfd_object))
1510 bfd_set_error (bfd_error_invalid_operation);
1511 goto input_err;
1514 nbr_modules++;
1517 /* Build the modules list. */
1518 BFD_ASSERT (tdata->modules == NULL);
1519 modules = bfd_alloc (arch, nbr_modules * sizeof (struct vms_index));
1520 if (modules == NULL)
1521 return FALSE;
1523 for (current = arch->archive_head, i = 0;
1524 current != NULL;
1525 current = current->archive_next, i++)
1527 int nl;
1529 modules[i].abfd = current;
1530 modules[i].name = vms_get_module_name (current->filename, FALSE);
1531 modules[i].ref = 1;
1533 /* FIXME: silently truncate long names ? */
1534 nl = strlen (modules[i].name);
1535 modules[i].namlen = (nl > MAX_KEYLEN ? MAX_KEYLEN : nl);
1538 /* Create the module index. */
1539 vbn = 0;
1540 if (!vms_write_index (NULL, modules, nbr_modules, &vbn, NULL))
1541 return FALSE;
1542 nbr_mod_iblk = vbn;
1544 /* Create symbol index. */
1545 if (!_bfd_vms_lib_build_map (nbr_modules, modules, &nbr_symbols, &symbols))
1546 return FALSE;
1548 vbn = 0;
1549 if (!vms_write_index (NULL, symbols, nbr_symbols, &vbn, NULL))
1550 return FALSE;
1551 nbr_sym_iblk = vbn;
1553 /* Write modules and remember their position. */
1554 off = (1 + nbr_mod_iblk + nbr_sym_iblk) * VMS_BLOCK_SIZE;
1556 if (bfd_seek (arch, off, SEEK_SET) != 0)
1557 return FALSE;
1559 for (i = 0; i < nbr_modules; i++)
1561 struct vms_datadef data;
1562 unsigned char blk[VMS_BLOCK_SIZE];
1563 struct vms_mhd *mhd;
1564 unsigned int sz;
1566 current = modules[i].abfd;
1567 current->proxy_origin = off;
1569 bfd_putl16 (sizeof (struct vms_mhd), blk);
1570 mhd = (struct vms_mhd *)(blk + 2);
1571 memset (mhd, 0, sizeof (struct vms_mhd));
1572 mhd->lbrflag = 0;
1573 mhd->id = MHD__C_MHDID;
1574 mhd->objidlng = 4;
1575 memcpy (mhd->objid, "V1.0", 4);
1576 bfd_putl32 (modules[i].ref, mhd->refcnt);
1577 /* FIXME: datim. */
1579 sz = (2 + sizeof (struct vms_mhd) + 1) & ~1;
1580 if (vms_write_data_block (arch, &data, &off, blk, sz, 0) < 0)
1581 goto input_err;
1583 if (bfd_seek (current, 0, SEEK_SET) != 0)
1584 goto input_err;
1586 while (1)
1588 sz = bfd_bread (blk, sizeof (blk), current);
1589 if (sz == 0)
1590 break;
1591 if (vms_write_data_block (arch, &data, &off, blk, sz, 0) < 0)
1592 goto input_err;
1594 if (vms_write_data_block (arch, &data, &off,
1595 eotdesc, sizeof (eotdesc), 1) < 0)
1596 goto input_err;
1599 /* Write the indexes. */
1600 vbn = 2;
1601 if (vms_write_index (arch, modules, nbr_modules, &vbn, &mod_idx_vbn) != TRUE)
1602 return FALSE;
1603 if (vms_write_index (arch, symbols, nbr_symbols, &vbn, &sym_idx_vbn) != TRUE)
1604 return FALSE;
1606 /* Write libary header. */
1608 unsigned char blk[VMS_BLOCK_SIZE];
1609 struct vms_lhd *lhd = (struct vms_lhd *)blk;
1610 struct vms_idd *idd = (struct vms_idd *)(blk + sizeof (*lhd));
1611 unsigned int idd_flags;
1613 memset (blk, 0, sizeof (blk));
1615 lhd->type = LBR__C_TYP_EOBJ;
1616 lhd->nindex = 2;
1617 bfd_putl32 (LHD_SANEID3, lhd->sanity);
1618 bfd_putl16 (3, lhd->majorid);
1619 bfd_putl16 (0, lhd->minorid);
1620 snprintf ((char *)lhd->lbrver + 1, sizeof (lhd->lbrver) - 1,
1621 "GNU ar %u.%u.%u",
1622 (unsigned)(BFD_VERSION / 100000000UL),
1623 (unsigned)(BFD_VERSION / 1000000UL) % 100,
1624 (unsigned)(BFD_VERSION / 10000UL) % 100);
1625 lhd->lbrver[sizeof (lhd->lbrver) - 1] = 0;
1626 lhd->lbrver[0] = strlen ((char *)lhd->lbrver + 1);
1628 /* FIXME. */
1629 bfd_putl64 (0, lhd->credat);
1630 bfd_putl64 (0, lhd->updtim);
1632 lhd->mhdusz = sizeof (struct vms_mhd) - MHD__C_USRDAT;
1634 bfd_putl32 (nbr_modules + nbr_symbols, lhd->idxcnt);
1635 bfd_putl32 (nbr_modules, lhd->modcnt);
1636 bfd_putl32 (nbr_modules, lhd->modhdrs);
1638 bfd_putl32 (vbn - 1, lhd->hipreal);
1639 bfd_putl32 (vbn - 1, lhd->hiprusd);
1641 /* First index (modules name). */
1642 idd_flags = IDD__FLAGS_ASCII | IDD__FLAGS_VARLENIDX
1643 | IDD__FLAGS_NOCASECMP | IDD__FLAGS_NOCASENTR;
1644 bfd_putl16 (idd_flags, idd->flags);
1645 bfd_putl16 (MAX_KEYLEN, idd->keylen);
1646 bfd_putl16 (mod_idx_vbn, idd->vbn);
1647 idd++;
1649 /* Second index (symbols name). */
1650 bfd_putl16 (idd_flags, idd->flags);
1651 bfd_putl16 (MAX_KEYLEN, idd->keylen);
1652 bfd_putl16 (sym_idx_vbn, idd->vbn);
1653 idd++;
1655 if (bfd_seek (arch, 0, SEEK_SET) != 0)
1656 return FALSE;
1657 if (bfd_bwrite (blk, sizeof (blk), arch) != sizeof (blk))
1658 return FALSE;
1661 return TRUE;
1663 input_err:
1664 bfd_set_error (bfd_error_on_input, current, bfd_get_error ());
1665 return FALSE;
1668 /* Add a target for text library. This costs almost nothing and is useful to
1669 read VMS library on the host. */
1671 const bfd_target vms_lib_txt_vec =
1673 "vms-libtxt", /* Name. */
1674 bfd_target_unknown_flavour,
1675 BFD_ENDIAN_UNKNOWN, /* byteorder */
1676 BFD_ENDIAN_UNKNOWN, /* header_byteorder */
1677 0, /* Object flags. */
1678 0, /* Sect flags. */
1679 0, /* symbol_leading_char. */
1680 ' ', /* ar_pad_char. */
1681 15, /* ar_max_namelen. */
1682 bfd_getl64, bfd_getl_signed_64, bfd_putl64,
1683 bfd_getl32, bfd_getl_signed_32, bfd_putl32,
1684 bfd_getl16, bfd_getl_signed_16, bfd_putl16,
1685 bfd_getl64, bfd_getl_signed_64, bfd_putl64,
1686 bfd_getl32, bfd_getl_signed_32, bfd_putl32,
1687 bfd_getl16, bfd_getl_signed_16, bfd_putl16,
1689 {_bfd_dummy_target, _bfd_dummy_target, /* bfd_check_format. */
1690 _bfd_vms_lib_txt_archive_p, _bfd_dummy_target},
1691 {bfd_false, bfd_false, bfd_false, bfd_false}, /* bfd_set_format. */
1692 {bfd_false, bfd_false, bfd_false, bfd_false}, /* bfd_write_contents. */
1694 BFD_JUMP_TABLE_GENERIC (_bfd_generic),
1695 BFD_JUMP_TABLE_COPY (_bfd_generic),
1696 BFD_JUMP_TABLE_CORE (_bfd_nocore),
1697 BFD_JUMP_TABLE_ARCHIVE (_bfd_vms_lib),
1698 BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols),
1699 BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
1700 BFD_JUMP_TABLE_WRITE (_bfd_nowrite),
1701 BFD_JUMP_TABLE_LINK (_bfd_nolink),
1702 BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
1704 NULL,
1706 (PTR) 0