]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - bfd/vms-lib.c
2010-04-06 Tristan Gingold <gingold@adacore.com>
[thirdparty/binutils-gdb.git] / bfd / vms-lib.c
1 /* BFD back-end for VMS archive files.
2
3 Copyright 2010 Free Software Foundation, Inc.
4 Written by Tristan Gingold <gingold@adacore.com>, AdaCore.
5
6 This file is part of BFD, the Binary File Descriptor library.
7
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.
12
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.
17
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. */
22
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"
31
32 /* The standard VMS disk block size. */
33 #ifndef VMS_BLOCK_SIZE
34 #define VMS_BLOCK_SIZE 512
35 #endif
36
37 /* Maximum key length (which is also the maximum symbol length in archive). */
38 #define MAX_KEYLEN 129
39
40 /* DCX Submaps. */
41
42 struct dcxsbm_desc
43 {
44 unsigned char min_char;
45 unsigned char max_char;
46 unsigned char *flags;
47 unsigned char *nodes;
48 unsigned short *next;
49 };
50
51 /* Kind of library. Used to filter in archive_p. */
52
53 enum vms_lib_kind
54 {
55 vms_lib_vax,
56 vms_lib_alpha,
57 vms_lib_ia64,
58 vms_lib_txt
59 };
60
61 /* Back-end private data. */
62
63 struct lib_tdata
64 {
65 /* Major version. */
66 unsigned char ver;
67
68 /* Type of the archive. */
69 unsigned char type;
70
71 /* Kind of archive. Summary of its type. */
72 enum vms_lib_kind kind;
73
74 /* Total size of the mhd (element header). */
75 unsigned int mhd_size;
76
77 /* Vector of modules (archive elements), already sorted. */
78 unsigned int nbr_modules;
79 struct carsym *modules;
80 bfd **cache;
81
82 /* Vector of symbols (archive map), already sorted. */
83 unsigned int nbr_syms;
84 struct carsym *syms;
85
86 /* DCX (decompression) data. */
87 unsigned int nbr_dcxsbm;
88 struct dcxsbm_desc *dcxsbm;
89 };
90
91 #define bfd_libdata(bfd) ((struct lib_tdata *)((bfd)->tdata.any))
92
93 /* End-Of-Text pattern. This is a special record to mark the end of file. */
94
95 static const unsigned char eotdesc[] = { 0x03, 0x00, 0x77, 0x00, 0x77, 0x00 };
96
97 /* Read index block VBN and put the entry in **IDX (which is updated).
98 If the entry is indirect, recurse. */
99
100 static bfd_boolean
101 vms_traverse_index (bfd *abfd, unsigned int vbn, struct carsym **idx)
102 {
103 struct vms_indexdef indexdef;
104 unsigned int used;
105 file_ptr off;
106 unsigned int i;
107
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;
113
114 /* Traverse it. */
115 used = bfd_getl16 (indexdef.used);
116 for (i = 0; i < used;)
117 {
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;
124
125 idx_vbn = bfd_getl32 (ridx);
126 idx_off = bfd_getl16 (ridx + 4);
127
128 /* Illegal value. */
129 if (idx_vbn == 0)
130 return FALSE;
131
132 /* Extract key length. */
133 if (bfd_libdata (abfd)->ver == 3)
134 {
135 keylen = ridx[6];
136 len = 7;
137 }
138 else if (bfd_libdata (abfd)->ver == 4)
139 {
140 keylen = bfd_getl16 (ridx + 6);
141 len = 9;
142 }
143 else
144 return FALSE;
145
146 keyname = ridx + len;
147 i += len + keylen;
148
149 if (idx_off == RFADEF__C_INDEX)
150 {
151 /* Indirect entry. Recurse. */
152 if (!vms_traverse_index (abfd, idx_vbn, idx))
153 return FALSE;
154 }
155 else
156 {
157 /* Add a new entry. */
158 char *name;
159
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)++;
168 }
169 }
170
171 return TRUE;
172 }
173
174 /* Read index #IDX, which must have NBREL entries. */
175
176 static struct carsym *
177 vms_lib_read_index (bfd *abfd, int idx, unsigned int nbrel)
178 {
179 struct carsym *res;
180 struct carsym *el;
181 struct vms_idd idd;
182 unsigned int flags;
183 unsigned int vbn;
184
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;
189
190 /* Sanity checks. */
191 flags = bfd_getl16 (idd.flags);
192 if (!(flags & IDD__FLAGS_ASCII)
193 || !(flags & IDD__FLAGS_VARLENIDX))
194 return NULL;
195
196 res = bfd_alloc (abfd, nbrel * sizeof (struct carsym));
197 if (res == NULL)
198 return NULL;
199
200 el = res;
201
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))
205 {
206 bfd_release (abfd, res);
207 return NULL;
208 }
209
210 if ((unsigned int)(el - res) != nbrel)
211 {
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;
216 }
217 return res;
218 }
219
220 /* Standard function. */
221
222 static const bfd_target *
223 _bfd_vms_lib_archive_p (bfd *abfd, enum vms_lib_kind kind)
224 {
225 struct vms_lhd lhd;
226 unsigned int sanity;
227 struct lib_tdata *tdata_hold;
228 struct lib_tdata *tdata;
229 unsigned int dcxvbn;
230
231 /* Read header. */
232 if (bfd_bread (&lhd, sizeof (lhd), abfd) != sizeof (lhd))
233 {
234 if (bfd_get_error () != bfd_error_system_call)
235 bfd_set_error (bfd_error_wrong_format);
236 return NULL;
237 }
238
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))
244 {
245 bfd_set_error (bfd_error_wrong_format);
246 return NULL;
247 }
248
249 /* Check archive kind. */
250 switch (kind)
251 {
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)
256 {
257 bfd_set_error (bfd_error_wrong_format);
258 return NULL;
259 }
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)
267 {
268 bfd_set_error (bfd_error_wrong_format);
269 return NULL;
270 }
271 break;
272 default:
273 abort ();
274 }
275
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;
286
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)
294 {
295 tdata->syms = vms_lib_read_index (abfd, 1, tdata->nbr_syms);
296 if (tdata->syms == NULL)
297 goto err;
298 }
299 tdata->cache = bfd_zalloc (abfd, sizeof (bfd *) * tdata->nbr_modules);
300 if (tdata->cache == NULL)
301 goto err;
302
303 /* Read DCX submaps. */
304 dcxvbn = bfd_getl32 (lhd.dcxmapvbn);
305 if (dcxvbn != 0)
306 {
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;
313
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)
323 {
324 free (buf);
325 goto err;
326 }
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++)
333 {
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;
341
342 sbm_sz = bfd_getl16 (sbm->size);
343 sbm_off += sbm_sz;
344 BFD_ASSERT (sbm_off <= reclen);
345
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);
361 }
362 free (buf);
363 }
364 else
365 {
366 tdata->nbr_dcxsbm = 0;
367 }
368
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;
373
374 return abfd->xvec;
375
376 err:
377 bfd_release (abfd, tdata);
378 abfd->tdata.any = (void *)tdata_hold;;
379 return NULL;
380 }
381
382 /* Standard function for alpha libraries. */
383
384 const bfd_target *
385 _bfd_vms_lib_alpha_archive_p (bfd *abfd)
386 {
387 return _bfd_vms_lib_archive_p (abfd, vms_lib_alpha);
388 }
389
390 /* Standard function for text libraries. */
391
392 static const bfd_target *
393 _bfd_vms_lib_txt_archive_p (bfd *abfd)
394 {
395 return _bfd_vms_lib_archive_p (abfd, vms_lib_txt);
396 }
397
398 /* Standard bfd function. */
399
400 bfd_boolean
401 _bfd_vms_lib_mkarchive (bfd *abfd)
402 {
403 struct lib_tdata *tdata;
404
405 tdata = (struct lib_tdata *) bfd_zalloc (abfd, sizeof (struct lib_tdata));
406 if (tdata == NULL)
407 return FALSE;
408
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;
413
414 tdata->nbr_modules = 0;
415 tdata->nbr_syms = 0;
416 tdata->modules = NULL;
417 tdata->syms = NULL;
418 tdata->cache = NULL;
419
420 return TRUE;
421 }
422
423 /* Find NAME in the symbol index. Return the index. */
424
425 symindex
426 _bfd_vms_lib_find_symbol (bfd *abfd, const char *name)
427 {
428 struct lib_tdata *tdata = bfd_libdata (abfd);
429 int lo, hi;
430
431 /* Open-coded binary search for speed. */
432 lo = 0;
433 hi = tdata->nbr_syms - 1;
434
435 while (lo <= hi)
436 {
437 int mid = lo + (hi - lo) / 2;
438 int diff;
439
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;
449 }
450 return 0;
451 }
452
453 /* IO vector for archive member. Need that because members are not linearly
454 stored in archives. */
455
456 struct vms_lib_iovec
457 {
458 /* Current offset. */
459 ufile_ptr where;
460
461 /* Length of the module, when known. */
462 ufile_ptr file_len;
463
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
472
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;
481
482 /* Offset of the first block. Extracted from the index. */
483 file_ptr first_block;
484
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;
489
490 /* Used to store any 3 byte record, which could be the EOF pattern. */
491 unsigned char pattern[4];
492
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;
500
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;
507 };
508
509 /* Return the current position. */
510
511 static file_ptr
512 vms_lib_btell (struct bfd *abfd)
513 {
514 struct vms_lib_iovec *vec = (struct vms_lib_iovec *) abfd->iostream;
515 return vec->where;
516 }
517
518 /* Read the header of the next data block if all bytes of the current block
519 have been read. */
520
521 static bfd_boolean
522 vms_lib_read_block (struct bfd *abfd)
523 {
524 struct vms_lib_iovec *vec = (struct vms_lib_iovec *) abfd->iostream;
525
526 if (vec->blk_off == DATA__LENGTH)
527 {
528 unsigned char hdr[DATA__DATA];
529
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);
537 }
538 return TRUE;
539 }
540
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. */
544
545 static file_ptr
546 vms_lib_bread_raw (struct bfd *abfd, void *buf, file_ptr nbytes)
547 {
548 struct vms_lib_iovec *vec = (struct vms_lib_iovec *) abfd->iostream;
549 file_ptr res;
550
551 res = 0;
552 while (nbytes > 0)
553 {
554 unsigned int l;
555
556 /* Be sure the current data block is read. */
557 if (!vms_lib_read_block (abfd))
558 return -1;
559
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)
566 {
567 if (bfd_bread (buf, l, abfd->my_archive) != l)
568 return -1;
569 }
570 else
571 {
572 if (bfd_seek (abfd->my_archive, l, SEEK_CUR) != 0)
573 return -1;
574 }
575
576 if (buf != NULL)
577 buf += l;
578 vec->blk_off += l;
579 nbytes -= l;
580 res += l;
581 }
582 return res;
583 }
584
585 /* Decompress NBYTES from VEC. Store the bytes into BUF if not NULL. */
586
587 static file_ptr
588 vms_lib_dcx (struct vms_lib_iovec *vec, unsigned char *buf, file_ptr nbytes)
589 {
590 struct dcxsbm_desc *sbm;
591 unsigned int i;
592 unsigned int offset;
593 unsigned int j;
594 file_ptr res = 0;
595
596 /* The loop below expect to deliver at least one byte. */
597 if (nbytes == 0)
598 return 0;
599
600 /* Get the current state. */
601 sbm = vec->dcx_sbm;
602 offset = vec->dcx_offset;
603 j = vec->dcx_pos & 7;
604
605 for (i = vec->dcx_pos >> 3; i < vec->dcx_rlen; i++)
606 {
607 unsigned char b = vec->dcx_buf[i];
608
609 for (; j < 8; j++)
610 {
611 if (b & (1 << j))
612 offset++;
613 if (!(sbm->flags[offset >> 3] & (1 << (offset & 7))))
614 {
615 unsigned int n_offset = sbm->nodes[offset];
616 if (n_offset == 0)
617 {
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;
625 }
626 offset = 2 * n_offset;
627 }
628 else
629 {
630 unsigned char v = sbm->nodes[offset];
631
632 sbm = vec->dcxsbms + sbm->next[v];
633 offset = 0;
634 res++;
635
636 if (buf)
637 {
638 *buf++ = v;
639 nbytes--;
640
641 if (nbytes == 0)
642 {
643 vec->dcx_pos = (i << 3) + j + 1;
644 vec->dcx_offset = offset;
645 vec->dcx_sbm = sbm;
646
647 return res;
648 }
649 }
650 }
651 }
652 j = 0;
653 }
654 return -1;
655 }
656
657 /* Standard IOVEC function. */
658
659 static file_ptr
660 vms_lib_bread (struct bfd *abfd, void *buf, file_ptr nbytes)
661 {
662 struct vms_lib_iovec *vec = (struct vms_lib_iovec *) abfd->iostream;
663 file_ptr res;
664 file_ptr chunk;
665
666 /* Do not read past the end. */
667 if (vec->where >= vec->file_len)
668 return 0;
669
670 res = 0;
671 while (nbytes > 0)
672 {
673 if (vec->rec_rem == 0)
674 {
675 unsigned char blen[2];
676
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)
682 {
683 /* Discard record size and align byte. */
684 vec->rec_pos = 0;
685 vec->rec_rem = vec->rec_len;
686 }
687 else
688 {
689 /* Prepend record size. */
690 vec->rec_pos = REC_POS_LEN0;
691 vec->rec_rem = (vec->rec_len + 1) & ~1; /* With align byte. */
692 }
693 if (vec->rec_len == 3)
694 {
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))
699 {
700 /* This is really an EOF. */
701 vec->where += res;
702 vec->file_len = vec->where;
703 return res;
704 }
705 }
706
707 if (vec->dcxsbms != NULL)
708 {
709 /* This is a compressed member. */
710 unsigned int len;
711 file_ptr elen;
712
713 /* Be sure there is enough room for the expansion. */
714 len = (vec->rec_len + 1) & ~1;
715 if (len > vec->dcx_max)
716 {
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;
722 }
723
724 /* Read the compressed record. */
725 vec->dcx_rlen = len;
726 if (vec->rec_len == 3)
727 {
728 /* Already read. */
729 memcpy (vec->dcx_buf, vec->pattern, 3);
730 }
731 else
732 {
733 elen = vms_lib_bread_raw (abfd, vec->dcx_buf, len);
734 if (elen != len)
735 return -1;
736 }
737
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;
747
748 /* Reset the state. */
749 vec->dcx_offset = 0;
750 vec->dcx_sbm = vec->dcxsbms;
751 vec->dcx_pos = 0;
752 }
753 }
754 if (vec->rec_pos < 0)
755 {
756 unsigned char c;
757 switch (vec->rec_pos)
758 {
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 ();
777 }
778 if (buf != NULL)
779 {
780 *(unsigned char *)buf = c;
781 buf++;
782 }
783 nbytes--;
784 res++;
785 continue;
786 }
787
788 if (nbytes > vec->rec_rem)
789 chunk = vec->rec_rem;
790 else
791 chunk = nbytes;
792
793 if (vec->dcxsbms != NULL)
794 {
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);
799 }
800 else
801 {
802 if (vec->rec_len == 3)
803 {
804 if (buf != NULL)
805 memcpy (buf, vec->pattern + vec->rec_pos, chunk);
806 }
807 else
808 chunk = vms_lib_bread_raw (abfd, buf, chunk);
809 }
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;
818
819 if (vec->rec_rem == 0)
820 {
821 if (bfd_libdata (abfd->my_archive)->kind == vms_lib_txt)
822 {
823 if ((vec->rec_len & 1) == 1
824 && vec->rec_len != 3
825 && vec->dcxsbms == NULL)
826 {
827 /* Eat the pad byte. */
828 unsigned char pad;
829 if (vms_lib_bread_raw (abfd, &pad, 1) != 1)
830 return -1;
831 }
832 vec->rec_pos = REC_POS_NL;
833 vec->rec_rem = 1;
834 }
835 else
836 {
837 if ((vec->rec_len & 1) == 1 && vec->dcxsbms != NULL)
838 {
839 vec->rec_pos = REC_POS_PAD;
840 vec->rec_rem = 1;
841 }
842 }
843 }
844 }
845 vec->where += res;
846 return res;
847 }
848
849 /* Standard function, but we currently only handle the rewind case. */
850
851 static int
852 vms_lib_bseek (struct bfd *abfd, file_ptr offset, int whence)
853 {
854 struct vms_lib_iovec *vec = (struct vms_lib_iovec *) abfd->iostream;
855
856 if (whence == SEEK_SET && offset == 0)
857 {
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;
863
864 if (bfd_seek (abfd->my_archive, vec->first_block, SEEK_SET) != 0)
865 return -1;
866 }
867 else
868 abort ();
869 return 0;
870 }
871
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)
876 {
877 return -1;
878 }
879
880 static int
881 vms_lib_bclose (struct bfd *abfd)
882 {
883 abfd->iostream = NULL;
884 return 0;
885 }
886
887 static int
888 vms_lib_bflush (struct bfd *abfd ATTRIBUTE_UNUSED)
889 {
890 return 0;
891 }
892
893 static int
894 vms_lib_bstat (struct bfd *abfd ATTRIBUTE_UNUSED,
895 struct stat *sb ATTRIBUTE_UNUSED)
896 {
897 /* Not supported. */
898 return 0;
899 }
900
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)
908 {
909 return (void *) -1;
910 }
911
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
915 };
916
917 /* Open a library module. FILEPOS is the position of the module header. */
918
919 static bfd_boolean
920 vms_lib_bopen (bfd *el, file_ptr filepos)
921 {
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;
927
928 /* Allocate and initialized the iovec. */
929 vec = bfd_zalloc (el, sizeof (*vec));
930 if (vec == NULL)
931 return FALSE;
932
933 el->iostream = vec;
934 el->iovec = &vms_lib_iovec;
935
936 /* File length is not known. */
937 vec->file_len = -1;
938
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;
944
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;
950
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;
961
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;
968
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;
976
977 if (vec->dcxsbms != NULL)
978 {
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;
985 }
986 return TRUE;
987 }
988
989 /* Standard function: get member at IDX. */
990
991 bfd *
992 _bfd_vms_lib_get_elt_at_index (bfd *abfd, symindex idx)
993 {
994 struct lib_tdata *tdata = bfd_libdata (abfd);
995 bfd *res;
996 unsigned int i;
997
998 /* Linear-scan. */
999 for (i = 0; i < tdata->nbr_modules; i++)
1000 {
1001 if (tdata->modules[i].file_offset == (file_ptr)idx)
1002 break;
1003 }
1004
1005 /* Invalid index. */
1006 if (i >= tdata->nbr_modules)
1007 return NULL;
1008
1009 /* Already loaded. */
1010 if (tdata->cache[i])
1011 return tdata->cache[i];
1012
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;
1018
1019 tdata->cache[i] = res;
1020
1021 return res;
1022 }
1023
1024 /* Elements of an imagelib are stubs. You can get the real image with this
1025 function. */
1026
1027 bfd *
1028 _bfd_vms_lib_get_imagelib_file (bfd *el)
1029 {
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;
1036
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);
1047
1048 filename = _bfd_append_relative_path (archive, filename);
1049 if (filename == NULL)
1050 return NULL;
1051 res = bfd_openr (filename, NULL);
1052
1053 if (res == NULL)
1054 {
1055 (*_bfd_error_handler)(_("could not open shared image '%s' from '%s'"),
1056 filename, archive->filename);
1057 bfd_release (archive, filename);
1058 return NULL;
1059 }
1060
1061 /* FIXME: put it in a cache ? */
1062 return res;
1063 }
1064
1065 /* Standard function. */
1066
1067 bfd *
1068 _bfd_vms_lib_openr_next_archived_file (bfd *archive,
1069 bfd *last_file)
1070 {
1071 unsigned int idx;
1072 bfd *res;
1073
1074 if (!last_file)
1075 idx = 0;
1076 else
1077 idx = last_file->proxy_origin + 1;
1078
1079 if (idx >= bfd_libdata (archive)->nbr_modules)
1080 {
1081 bfd_set_error (bfd_error_no_more_archived_files);
1082 return NULL;
1083 }
1084
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;
1091 }
1092
1093 /* Standard function. Just compute the length. */
1094
1095 int
1096 _bfd_vms_lib_generic_stat_arch_elt (bfd *abfd, struct stat *st)
1097 {
1098 struct vms_lib_iovec *vec = (struct vms_lib_iovec *) abfd->iostream;
1099
1100 if (abfd->my_archive == NULL)
1101 {
1102 bfd_set_error (bfd_error_invalid_operation);
1103 return -1;
1104 }
1105
1106 if (vec->file_len == (ufile_ptr)-1)
1107 {
1108 if (vms_lib_bseek (abfd, 0, SEEK_SET) != 0)
1109 return -1;
1110
1111 /* Compute length. */
1112 while (vms_lib_bread (abfd, NULL, 1 << 20) > 0)
1113 ;
1114 }
1115
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;
1124
1125 return 0;
1126 }
1127
1128 /* Internal representation of an index entry. */
1129
1130 struct vms_index
1131 {
1132 /* Corresponding archive member. */
1133 bfd *abfd;
1134
1135 /* Number of reference to this entry. */
1136 unsigned int ref;
1137
1138 /* Length of the key. */
1139 unsigned short namlen;
1140
1141 /* Key. */
1142 const char *name;
1143 };
1144
1145 /* Used to sort index entries. */
1146
1147 static int
1148 vms_index_cmp (const void *lv, const void *rv)
1149 {
1150 const struct vms_index *l = lv;
1151 const struct vms_index *r = rv;
1152
1153 return strcmp (l->name, r->name);
1154 }
1155
1156 /* Maximum number of index blocks level. */
1157
1158 #define MAX_LEVEL 10
1159
1160 /* Get the size of an index entry. */
1161
1162 static unsigned int
1163 get_idxlen (struct vms_index *idx)
1164 {
1165 return 7 + idx->namlen;
1166 }
1167
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. */
1171
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)
1176 {
1177 unsigned int i;
1178 int j;
1179 int level;
1180 struct vms_indexdef *rblk[MAX_LEVEL];
1181 struct idxblk
1182 {
1183 unsigned int vbn;
1184 unsigned short len;
1185 unsigned short lastlen;
1186 } blk[MAX_LEVEL];
1187
1188 if (nbr == 0)
1189 {
1190 if (topvbn != NULL)
1191 *topvbn = 0;
1192 return TRUE;
1193 }
1194
1195 if (abfd == NULL)
1196 {
1197 /* Sort the index the first time this function is called. */
1198 qsort (idx, nbr, sizeof (struct vms_index), vms_index_cmp);
1199 }
1200
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;
1208
1209 for (i = 0; i < nbr; i++, idx++)
1210 {
1211 unsigned int idxlen = get_idxlen (idx);
1212 struct vms_idxdef *en;
1213 int flush = 0;
1214
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;
1220
1221 for (j = 0; j < level; j++)
1222 {
1223 if (j < flush)
1224 {
1225 /* There is not enough room to write the new entry in this
1226 block or in a parent block. */
1227
1228 if (j + 1 == level)
1229 {
1230 BFD_ASSERT (level < MAX_LEVEL);
1231
1232 /* Need to create a parent. */
1233 if (abfd != NULL)
1234 {
1235 rblk[level] = bfd_malloc (sizeof (struct vms_indexdef));
1236 bfd_putl32 (*vbn, rblk[j]->parent);
1237 }
1238 blk[level].vbn = (*vbn)++;
1239 blk[level].len = 0;
1240 blk[level].lastlen = 0;
1241
1242 level++;
1243 }
1244
1245 /* Update parent block: write the new entry. */
1246 if (abfd != NULL)
1247 {
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);
1255 }
1256
1257 if (j + 1 == flush)
1258 {
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;
1264 }
1265
1266 /* Write this block on the disk. */
1267 if (abfd != NULL)
1268 {
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;
1276 }
1277
1278 /* Reset this block. */
1279 blk[j].len = 0;
1280 blk[j].lastlen = 0;
1281 blk[j].vbn = (*vbn)++;
1282 }
1283
1284 /* Append it to the block. */
1285 if (j == 0)
1286 {
1287 blk[j].len += blk[j].lastlen;
1288
1289 if (abfd != NULL)
1290 {
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);
1299 }
1300 }
1301
1302 blk[j].lastlen = idxlen;
1303 }
1304 }
1305
1306 if (topvbn != NULL)
1307 *topvbn = blk[level - 1].vbn;
1308
1309 if (abfd == NULL)
1310 return TRUE;
1311
1312 /* Flush. */
1313 for (j = 0; j < level; j++)
1314 {
1315 if (j > 0)
1316 {
1317 /* Update parent block: write the new entry. */
1318 struct vms_idxdef *en;
1319 struct vms_idxdef *par;
1320
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);
1326 }
1327
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;
1336
1337 free (rblk[j]);
1338 }
1339
1340 return TRUE;
1341 }
1342
1343 /* Append data to the data block DATA. Force write if PAD is true. */
1344
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)
1348 {
1349 while (len > 0 || pad)
1350 {
1351 unsigned int doff = *off & (VMS_BLOCK_SIZE - 1);
1352 unsigned int remlen = (DATA__LENGTH - DATA__DATA) - doff;
1353 unsigned int l;
1354
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;
1361
1362 if (doff == (DATA__LENGTH - DATA__DATA) || (len == 0 && pad))
1363 {
1364 data->recs = 0;
1365 data->fill_1 = 0;
1366 bfd_putl32 ((*off / VMS_BLOCK_SIZE) + 2, data->link);
1367
1368 if (bfd_bwrite (data, sizeof (*data), arch) != sizeof (*data))
1369 return FALSE;
1370
1371 *off += DATA__LENGTH - doff;
1372
1373 if (len == 0)
1374 break;
1375 }
1376 }
1377 return TRUE;
1378 }
1379
1380 /* Build the symbols index. */
1381
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)
1387 {
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;
1394
1395 map = (struct vms_index *) bfd_malloc (map_max * sizeof (struct vms_index));
1396 if (map == NULL)
1397 goto error_return;
1398
1399 /* Gather symbols. */
1400 for (i = 0; i < nbr_modules; i++)
1401 {
1402 long storage;
1403 long symcount;
1404 long src_count;
1405 bfd *current = modules[i].abfd;
1406
1407 if ((bfd_get_file_flags (current) & HAS_SYMS) == 0)
1408 continue;
1409
1410 storage = bfd_get_symtab_upper_bound (current);
1411 if (storage < 0)
1412 goto error_return;
1413
1414 if (storage != 0)
1415 {
1416 if (storage > syms_max)
1417 {
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;
1424 }
1425 symcount = bfd_canonicalize_symtab (current, syms);
1426 if (symcount < 0)
1427 goto error_return;
1428
1429 /* Now map over all the symbols, picking out the ones we
1430 want. */
1431 for (src_count = 0; src_count < symcount; src_count++)
1432 {
1433 flagword flags = (syms[src_count])->flags;
1434 asection *sec = syms[src_count]->section;
1435
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))
1441 {
1442 struct vms_index *new_map;
1443
1444 /* This symbol will go into the archive header. */
1445 if (map_count == map_max)
1446 {
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;
1453 }
1454
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++;
1461 }
1462 }
1463 }
1464 }
1465
1466 *res_cnt = map_count;
1467 *res = map;
1468 return TRUE;
1469
1470 error_return:
1471 if (syms_max > 0)
1472 free (syms);
1473 if (map != NULL)
1474 free (map);
1475 return FALSE;
1476 }
1477
1478 /* Do the hard work: write an archive on the disk. */
1479
1480 bfd_boolean
1481 _bfd_vms_lib_write_archive_contents (bfd *arch)
1482 {
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;
1496
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)
1502 {
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))
1509 {
1510 bfd_set_error (bfd_error_invalid_operation);
1511 goto input_err;
1512 }
1513
1514 nbr_modules++;
1515 }
1516
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;
1522
1523 for (current = arch->archive_head, i = 0;
1524 current != NULL;
1525 current = current->archive_next, i++)
1526 {
1527 int nl;
1528
1529 modules[i].abfd = current;
1530 modules[i].name = vms_get_module_name (current->filename, FALSE);
1531 modules[i].ref = 1;
1532
1533 /* FIXME: silently truncate long names ? */
1534 nl = strlen (modules[i].name);
1535 modules[i].namlen = (nl > MAX_KEYLEN ? MAX_KEYLEN : nl);
1536 }
1537
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;
1543
1544 /* Create symbol index. */
1545 if (!_bfd_vms_lib_build_map (nbr_modules, modules, &nbr_symbols, &symbols))
1546 return FALSE;
1547
1548 vbn = 0;
1549 if (!vms_write_index (NULL, symbols, nbr_symbols, &vbn, NULL))
1550 return FALSE;
1551 nbr_sym_iblk = vbn;
1552
1553 /* Write modules and remember their position. */
1554 off = (1 + nbr_mod_iblk + nbr_sym_iblk) * VMS_BLOCK_SIZE;
1555
1556 if (bfd_seek (arch, off, SEEK_SET) != 0)
1557 return FALSE;
1558
1559 for (i = 0; i < nbr_modules; i++)
1560 {
1561 struct vms_datadef data;
1562 unsigned char blk[VMS_BLOCK_SIZE];
1563 struct vms_mhd *mhd;
1564 unsigned int sz;
1565
1566 current = modules[i].abfd;
1567 current->proxy_origin = off;
1568
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. */
1578
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;
1582
1583 if (bfd_seek (current, 0, SEEK_SET) != 0)
1584 goto input_err;
1585
1586 while (1)
1587 {
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;
1593 }
1594 if (vms_write_data_block (arch, &data, &off,
1595 eotdesc, sizeof (eotdesc), 1) < 0)
1596 goto input_err;
1597 }
1598
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;
1605
1606 /* Write libary header. */
1607 {
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;
1612
1613 memset (blk, 0, sizeof (blk));
1614
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);
1627
1628 /* FIXME. */
1629 bfd_putl64 (0, lhd->credat);
1630 bfd_putl64 (0, lhd->updtim);
1631
1632 lhd->mhdusz = sizeof (struct vms_mhd) - MHD__C_USRDAT;
1633
1634 bfd_putl32 (nbr_modules + nbr_symbols, lhd->idxcnt);
1635 bfd_putl32 (nbr_modules, lhd->modcnt);
1636 bfd_putl32 (nbr_modules, lhd->modhdrs);
1637
1638 bfd_putl32 (vbn - 1, lhd->hipreal);
1639 bfd_putl32 (vbn - 1, lhd->hiprusd);
1640
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++;
1648
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++;
1654
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;
1659 }
1660
1661 return TRUE;
1662
1663 input_err:
1664 bfd_set_error (bfd_error_on_input, current, bfd_get_error ());
1665 return FALSE;
1666 }
1667
1668 /* Add a target for text library. This costs almost nothing and is useful to
1669 read VMS library on the host. */
1670
1671 const bfd_target vms_lib_txt_vec =
1672 {
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,
1688
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. */
1693
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),
1703
1704 NULL,
1705
1706 (PTR) 0
1707 };