* NEWS: Mention gdbserver support for x86_64 Windows 64-bit.
[deliverable/binutils-gdb.git] / bfd / vms-lib.c
CommitLineData
a6163c10
TG
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
42struct 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
53enum 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
63struct 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
95static 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
100static bfd_boolean
101vms_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
176static struct carsym *
177vms_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
222static 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
384const 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
392static 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
400bfd_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
425symindex
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
456struct 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
511static file_ptr
512vms_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
521static bfd_boolean
522vms_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
545static file_ptr
546vms_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
ddfb684a 560 /* Do not read past the data block, do not read more than requested. */
a6163c10
TG
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)
567 {
ddfb684a 568 /* Really read into BUF. */
a6163c10
TG
569 if (bfd_bread (buf, l, abfd->my_archive) != l)
570 return -1;
571 }
572 else
573 {
ddfb684a 574 /* Make as if we are reading. */
a6163c10
TG
575 if (bfd_seek (abfd->my_archive, l, SEEK_CUR) != 0)
576 return -1;
577 }
578
579 if (buf != NULL)
580 buf += l;
581 vec->blk_off += l;
582 nbytes -= l;
583 res += l;
584 }
585 return res;
586}
587
588/* Decompress NBYTES from VEC. Store the bytes into BUF if not NULL. */
589
590static file_ptr
591vms_lib_dcx (struct vms_lib_iovec *vec, unsigned char *buf, file_ptr nbytes)
592{
593 struct dcxsbm_desc *sbm;
594 unsigned int i;
595 unsigned int offset;
596 unsigned int j;
597 file_ptr res = 0;
598
599 /* The loop below expect to deliver at least one byte. */
600 if (nbytes == 0)
601 return 0;
602
603 /* Get the current state. */
604 sbm = vec->dcx_sbm;
605 offset = vec->dcx_offset;
606 j = vec->dcx_pos & 7;
607
608 for (i = vec->dcx_pos >> 3; i < vec->dcx_rlen; i++)
609 {
610 unsigned char b = vec->dcx_buf[i];
611
612 for (; j < 8; j++)
613 {
614 if (b & (1 << j))
615 offset++;
616 if (!(sbm->flags[offset >> 3] & (1 << (offset & 7))))
617 {
618 unsigned int n_offset = sbm->nodes[offset];
619 if (n_offset == 0)
620 {
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;
628 }
629 offset = 2 * n_offset;
630 }
631 else
632 {
633 unsigned char v = sbm->nodes[offset];
634
635 sbm = vec->dcxsbms + sbm->next[v];
636 offset = 0;
637 res++;
638
639 if (buf)
640 {
641 *buf++ = v;
642 nbytes--;
643
644 if (nbytes == 0)
645 {
646 vec->dcx_pos = (i << 3) + j + 1;
647 vec->dcx_offset = offset;
648 vec->dcx_sbm = sbm;
649
650 return res;
651 }
652 }
653 }
654 }
655 j = 0;
656 }
657 return -1;
658}
659
660/* Standard IOVEC function. */
661
662static file_ptr
663vms_lib_bread (struct bfd *abfd, void *buf, file_ptr nbytes)
664{
665 struct vms_lib_iovec *vec = (struct vms_lib_iovec *) abfd->iostream;
666 file_ptr res;
667 file_ptr chunk;
668
669 /* Do not read past the end. */
670 if (vec->where >= vec->file_len)
671 return 0;
672
673 res = 0;
674 while (nbytes > 0)
675 {
676 if (vec->rec_rem == 0)
677 {
678 unsigned char blen[2];
679
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)
685 {
686 /* Discard record size and align byte. */
687 vec->rec_pos = 0;
688 vec->rec_rem = vec->rec_len;
689 }
690 else
691 {
692 /* Prepend record size. */
693 vec->rec_pos = REC_POS_LEN0;
694 vec->rec_rem = (vec->rec_len + 1) & ~1; /* With align byte. */
695 }
696 if (vec->rec_len == 3)
697 {
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))
702 {
703 /* This is really an EOF. */
704 vec->where += res;
705 vec->file_len = vec->where;
706 return res;
707 }
708 }
709
710 if (vec->dcxsbms != NULL)
711 {
712 /* This is a compressed member. */
713 unsigned int len;
714 file_ptr elen;
715
716 /* Be sure there is enough room for the expansion. */
717 len = (vec->rec_len + 1) & ~1;
718 if (len > vec->dcx_max)
719 {
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;
725 }
726
727 /* Read the compressed record. */
728 vec->dcx_rlen = len;
729 if (vec->rec_len == 3)
730 {
731 /* Already read. */
732 memcpy (vec->dcx_buf, vec->pattern, 3);
733 }
734 else
735 {
736 elen = vms_lib_bread_raw (abfd, vec->dcx_buf, len);
737 if (elen != len)
738 return -1;
739 }
740
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;
750
751 /* Reset the state. */
752 vec->dcx_offset = 0;
753 vec->dcx_sbm = vec->dcxsbms;
754 vec->dcx_pos = 0;
755 }
756 }
757 if (vec->rec_pos < 0)
758 {
759 unsigned char c;
760 switch (vec->rec_pos)
761 {
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 ();
780 }
781 if (buf != NULL)
782 {
783 *(unsigned char *)buf = c;
784 buf++;
785 }
786 nbytes--;
787 res++;
788 continue;
789 }
790
791 if (nbytes > vec->rec_rem)
792 chunk = vec->rec_rem;
793 else
794 chunk = nbytes;
795
796 if (vec->dcxsbms != NULL)
797 {
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);
802 }
803 else
804 {
805 if (vec->rec_len == 3)
806 {
807 if (buf != NULL)
808 memcpy (buf, vec->pattern + vec->rec_pos, chunk);
809 }
810 else
811 chunk = vms_lib_bread_raw (abfd, buf, chunk);
812 }
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;
821
822 if (vec->rec_rem == 0)
823 {
ddfb684a 824 /* End of record reached. */
a6163c10
TG
825 if (bfd_libdata (abfd->my_archive)->kind == vms_lib_txt)
826 {
827 if ((vec->rec_len & 1) == 1
828 && vec->rec_len != 3
829 && vec->dcxsbms == NULL)
830 {
831 /* Eat the pad byte. */
832 unsigned char pad;
833 if (vms_lib_bread_raw (abfd, &pad, 1) != 1)
834 return -1;
835 }
836 vec->rec_pos = REC_POS_NL;
837 vec->rec_rem = 1;
838 }
839 else
840 {
841 if ((vec->rec_len & 1) == 1 && vec->dcxsbms != NULL)
842 {
843 vec->rec_pos = REC_POS_PAD;
844 vec->rec_rem = 1;
845 }
846 }
847 }
848 }
849 vec->where += res;
850 return res;
851}
852
853/* Standard function, but we currently only handle the rewind case. */
854
855static int
856vms_lib_bseek (struct bfd *abfd, file_ptr offset, int whence)
857{
858 struct vms_lib_iovec *vec = (struct vms_lib_iovec *) abfd->iostream;
859
860 if (whence == SEEK_SET && offset == 0)
861 {
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;
867
868 if (bfd_seek (abfd->my_archive, vec->first_block, SEEK_SET) != 0)
869 return -1;
870 }
871 else
872 abort ();
873 return 0;
874}
875
876static file_ptr
877vms_lib_bwrite (struct bfd *abfd ATTRIBUTE_UNUSED,
878 const void *where ATTRIBUTE_UNUSED,
879 file_ptr nbytes ATTRIBUTE_UNUSED)
880{
881 return -1;
882}
883
884static int
885vms_lib_bclose (struct bfd *abfd)
886{
887 abfd->iostream = NULL;
888 return 0;
889}
890
891static int
892vms_lib_bflush (struct bfd *abfd ATTRIBUTE_UNUSED)
893{
894 return 0;
895}
896
897static int
898vms_lib_bstat (struct bfd *abfd ATTRIBUTE_UNUSED,
899 struct stat *sb ATTRIBUTE_UNUSED)
900{
901 /* Not supported. */
902 return 0;
903}
904
905static void *
906vms_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)
912{
913 return (void *) -1;
914}
915
916static 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
919};
920
921/* Open a library module. FILEPOS is the position of the module header. */
922
923static bfd_boolean
924vms_lib_bopen (bfd *el, file_ptr filepos)
925{
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;
931
932 /* Allocate and initialized the iovec. */
933 vec = bfd_zalloc (el, sizeof (*vec));
934 if (vec == NULL)
935 return FALSE;
936
937 el->iostream = vec;
938 el->iovec = &vms_lib_iovec;
939
940 /* File length is not known. */
941 vec->file_len = -1;
942
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;
948
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;
954
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;
965
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;
972
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;
980
981 if (vec->dcxsbms != NULL)
982 {
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;
989 }
990 return TRUE;
991}
992
993/* Standard function: get member at IDX. */
994
995bfd *
996_bfd_vms_lib_get_elt_at_index (bfd *abfd, symindex idx)
997{
998 struct lib_tdata *tdata = bfd_libdata (abfd);
999 bfd *res;
1000 unsigned int i;
1001
1002 /* Linear-scan. */
1003 for (i = 0; i < tdata->nbr_modules; i++)
1004 {
1005 if (tdata->modules[i].file_offset == (file_ptr)idx)
1006 break;
1007 }
1008
1009 /* Invalid index. */
1010 if (i >= tdata->nbr_modules)
1011 return NULL;
1012
1013 /* Already loaded. */
1014 if (tdata->cache[i])
1015 return tdata->cache[i];
1016
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;
1022
1023 tdata->cache[i] = res;
1024
1025 return res;
1026}
1027
1028/* Elements of an imagelib are stubs. You can get the real image with this
1029 function. */
1030
1031bfd *
1032_bfd_vms_lib_get_imagelib_file (bfd *el)
1033{
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;
1040
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);
1051
1052 filename = _bfd_append_relative_path (archive, filename);
1053 if (filename == NULL)
1054 return NULL;
1055 res = bfd_openr (filename, NULL);
1056
1057 if (res == NULL)
1058 {
1059 (*_bfd_error_handler)(_("could not open shared image '%s' from '%s'"),
1060 filename, archive->filename);
1061 bfd_release (archive, filename);
1062 return NULL;
1063 }
1064
1065 /* FIXME: put it in a cache ? */
1066 return res;
1067}
1068
1069/* Standard function. */
1070
1071bfd *
1072_bfd_vms_lib_openr_next_archived_file (bfd *archive,
1073 bfd *last_file)
1074{
1075 unsigned int idx;
1076 bfd *res;
1077
1078 if (!last_file)
1079 idx = 0;
1080 else
1081 idx = last_file->proxy_origin + 1;
1082
1083 if (idx >= bfd_libdata (archive)->nbr_modules)
1084 {
1085 bfd_set_error (bfd_error_no_more_archived_files);
1086 return NULL;
1087 }
1088
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;
1095}
1096
1097/* Standard function. Just compute the length. */
1098
1099int
1100_bfd_vms_lib_generic_stat_arch_elt (bfd *abfd, struct stat *st)
1101{
1102 struct vms_lib_iovec *vec = (struct vms_lib_iovec *) abfd->iostream;
1103
1104 if (abfd->my_archive == NULL)
1105 {
1106 bfd_set_error (bfd_error_invalid_operation);
1107 return -1;
1108 }
1109
1110 if (vec->file_len == (ufile_ptr)-1)
1111 {
1112 if (vms_lib_bseek (abfd, 0, SEEK_SET) != 0)
1113 return -1;
1114
1115 /* Compute length. */
1116 while (vms_lib_bread (abfd, NULL, 1 << 20) > 0)
1117 ;
1118 }
1119
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;
1128
1129 return 0;
1130}
1131
1132/* Internal representation of an index entry. */
1133
1134struct vms_index
1135{
1136 /* Corresponding archive member. */
1137 bfd *abfd;
1138
1139 /* Number of reference to this entry. */
1140 unsigned int ref;
1141
1142 /* Length of the key. */
1143 unsigned short namlen;
1144
1145 /* Key. */
1146 const char *name;
1147};
1148
1149/* Used to sort index entries. */
1150
1151static int
1152vms_index_cmp (const void *lv, const void *rv)
1153{
1154 const struct vms_index *l = lv;
1155 const struct vms_index *r = rv;
1156
1157 return strcmp (l->name, r->name);
1158}
1159
1160/* Maximum number of index blocks level. */
1161
1162#define MAX_LEVEL 10
1163
1164/* Get the size of an index entry. */
1165
1166static unsigned int
1167get_idxlen (struct vms_index *idx)
1168{
1169 return 7 + idx->namlen;
1170}
1171
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. */
1175
1176static bfd_boolean
1177vms_write_index (bfd *abfd,
1178 struct vms_index *idx, unsigned int nbr, unsigned int *vbn,
1179 unsigned int *topvbn)
1180{
1181 unsigned int i;
1182 int j;
1183 int level;
1184 struct vms_indexdef *rblk[MAX_LEVEL];
1185 struct idxblk
1186 {
1187 unsigned int vbn;
1188 unsigned short len;
1189 unsigned short lastlen;
1190 } blk[MAX_LEVEL];
1191
1192 if (nbr == 0)
1193 {
1194 if (topvbn != NULL)
1195 *topvbn = 0;
1196 return TRUE;
1197 }
1198
1199 if (abfd == NULL)
1200 {
1201 /* Sort the index the first time this function is called. */
1202 qsort (idx, nbr, sizeof (struct vms_index), vms_index_cmp);
1203 }
1204
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;
1212
1213 for (i = 0; i < nbr; i++, idx++)
1214 {
1215 unsigned int idxlen = get_idxlen (idx);
1216 struct vms_idxdef *en;
1217 int flush = 0;
1218
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;
1224
1225 for (j = 0; j < level; j++)
1226 {
1227 if (j < flush)
1228 {
1229 /* There is not enough room to write the new entry in this
1230 block or in a parent block. */
1231
1232 if (j + 1 == level)
1233 {
1234 BFD_ASSERT (level < MAX_LEVEL);
1235
1236 /* Need to create a parent. */
1237 if (abfd != NULL)
1238 {
1239 rblk[level] = bfd_malloc (sizeof (struct vms_indexdef));
1240 bfd_putl32 (*vbn, rblk[j]->parent);
1241 }
1242 blk[level].vbn = (*vbn)++;
1243 blk[level].len = 0;
1244 blk[level].lastlen = 0;
1245
1246 level++;
1247 }
1248
1249 /* Update parent block: write the new entry. */
1250 if (abfd != NULL)
1251 {
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);
1259 }
1260
1261 if (j + 1 == flush)
1262 {
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;
1268 }
1269
1270 /* Write this block on the disk. */
1271 if (abfd != NULL)
1272 {
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;
1280 }
1281
1282 /* Reset this block. */
1283 blk[j].len = 0;
1284 blk[j].lastlen = 0;
1285 blk[j].vbn = (*vbn)++;
1286 }
1287
1288 /* Append it to the block. */
1289 if (j == 0)
1290 {
1291 blk[j].len += blk[j].lastlen;
1292
1293 if (abfd != NULL)
1294 {
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);
1303 }
1304 }
1305
1306 blk[j].lastlen = idxlen;
1307 }
1308 }
1309
1310 if (topvbn != NULL)
1311 *topvbn = blk[level - 1].vbn;
1312
1313 if (abfd == NULL)
1314 return TRUE;
1315
1316 /* Flush. */
1317 for (j = 0; j < level; j++)
1318 {
1319 if (j > 0)
1320 {
1321 /* Update parent block: write the new entry. */
1322 struct vms_idxdef *en;
1323 struct vms_idxdef *par;
1324
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);
1330 }
1331
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;
1340
1341 free (rblk[j]);
1342 }
1343
1344 return TRUE;
1345}
1346
1347/* Append data to the data block DATA. Force write if PAD is true. */
1348
1349static bfd_boolean
1350vms_write_data_block (bfd *arch, struct vms_datadef *data, file_ptr *off,
1351 const unsigned char *buf, unsigned int len, int pad)
1352{
1353 while (len > 0 || pad)
1354 {
1355 unsigned int doff = *off & (VMS_BLOCK_SIZE - 1);
1356 unsigned int remlen = (DATA__LENGTH - DATA__DATA) - doff;
1357 unsigned int l;
1358
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;
1365
1366 if (doff == (DATA__LENGTH - DATA__DATA) || (len == 0 && pad))
1367 {
1368 data->recs = 0;
1369 data->fill_1 = 0;
1370 bfd_putl32 ((*off / VMS_BLOCK_SIZE) + 2, data->link);
1371
1372 if (bfd_bwrite (data, sizeof (*data), arch) != sizeof (*data))
1373 return FALSE;
1374
1375 *off += DATA__LENGTH - doff;
1376
1377 if (len == 0)
1378 break;
1379 }
1380 }
1381 return TRUE;
1382}
1383
1384/* Build the symbols index. */
1385
1386static 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)
1391{
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;
1398
1399 map = (struct vms_index *) bfd_malloc (map_max * sizeof (struct vms_index));
1400 if (map == NULL)
1401 goto error_return;
1402
1403 /* Gather symbols. */
1404 for (i = 0; i < nbr_modules; i++)
1405 {
1406 long storage;
1407 long symcount;
1408 long src_count;
1409 bfd *current = modules[i].abfd;
1410
1411 if ((bfd_get_file_flags (current) & HAS_SYMS) == 0)
1412 continue;
1413
1414 storage = bfd_get_symtab_upper_bound (current);
1415 if (storage < 0)
1416 goto error_return;
1417
1418 if (storage != 0)
1419 {
1420 if (storage > syms_max)
1421 {
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;
1428 }
1429 symcount = bfd_canonicalize_symtab (current, syms);
1430 if (symcount < 0)
1431 goto error_return;
1432
1433 /* Now map over all the symbols, picking out the ones we
1434 want. */
1435 for (src_count = 0; src_count < symcount; src_count++)
1436 {
1437 flagword flags = (syms[src_count])->flags;
1438 asection *sec = syms[src_count]->section;
1439
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))
1445 {
1446 struct vms_index *new_map;
1447
1448 /* This symbol will go into the archive header. */
1449 if (map_count == map_max)
1450 {
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;
1457 }
1458
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++;
1465 }
1466 }
1467 }
1468 }
1469
1470 *res_cnt = map_count;
1471 *res = map;
1472 return TRUE;
1473
1474 error_return:
1475 if (syms_max > 0)
1476 free (syms);
1477 if (map != NULL)
1478 free (map);
1479 return FALSE;
1480}
1481
1482/* Do the hard work: write an archive on the disk. */
1483
1484bfd_boolean
1485_bfd_vms_lib_write_archive_contents (bfd *arch)
1486{
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;
1500
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)
1506 {
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))
1513 {
1514 bfd_set_error (bfd_error_invalid_operation);
1515 goto input_err;
1516 }
1517
1518 nbr_modules++;
1519 }
1520
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;
1526
1527 for (current = arch->archive_head, i = 0;
1528 current != NULL;
1529 current = current->archive_next, i++)
1530 {
1531 int nl;
1532
1533 modules[i].abfd = current;
1534 modules[i].name = vms_get_module_name (current->filename, FALSE);
1535 modules[i].ref = 1;
1536
1537 /* FIXME: silently truncate long names ? */
1538 nl = strlen (modules[i].name);
1539 modules[i].namlen = (nl > MAX_KEYLEN ? MAX_KEYLEN : nl);
1540 }
1541
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;
1547
1548 /* Create symbol index. */
1549 if (!_bfd_vms_lib_build_map (nbr_modules, modules, &nbr_symbols, &symbols))
1550 return FALSE;
1551
1552 vbn = 0;
1553 if (!vms_write_index (NULL, symbols, nbr_symbols, &vbn, NULL))
1554 return FALSE;
1555 nbr_sym_iblk = vbn;
1556
1557 /* Write modules and remember their position. */
1558 off = (1 + nbr_mod_iblk + nbr_sym_iblk) * VMS_BLOCK_SIZE;
1559
1560 if (bfd_seek (arch, off, SEEK_SET) != 0)
1561 return FALSE;
1562
1563 for (i = 0; i < nbr_modules; i++)
1564 {
1565 struct vms_datadef data;
1566 unsigned char blk[VMS_BLOCK_SIZE];
1567 struct vms_mhd *mhd;
1568 unsigned int sz;
1569
1570 current = modules[i].abfd;
1571 current->proxy_origin = off;
1572
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. */
1582
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;
1586
1587 if (bfd_seek (current, 0, SEEK_SET) != 0)
1588 goto input_err;
1589
1590 while (1)
1591 {
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;
1597 }
1598 if (vms_write_data_block (arch, &data, &off,
1599 eotdesc, sizeof (eotdesc), 1) < 0)
1600 goto input_err;
1601 }
1602
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;
1609
1610 /* Write libary header. */
1611 {
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));
0e9b2e9a 1615 unsigned int idd_flags;
a6163c10
TG
1616
1617 memset (blk, 0, sizeof (blk));
1618
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);
1631
1632 /* FIXME. */
1633 bfd_putl64 (0, lhd->credat);
1634 bfd_putl64 (0, lhd->updtim);
1635
1636 lhd->mhdusz = sizeof (struct vms_mhd) - MHD__C_USRDAT;
1637
1638 bfd_putl32 (nbr_modules + nbr_symbols, lhd->idxcnt);
1639 bfd_putl32 (nbr_modules, lhd->modcnt);
1640 bfd_putl32 (nbr_modules, lhd->modhdrs);
1641
1642 bfd_putl32 (vbn - 1, lhd->hipreal);
1643 bfd_putl32 (vbn - 1, lhd->hiprusd);
1644
1645 /* First index (modules name). */
0e9b2e9a
TG
1646 idd_flags = IDD__FLAGS_ASCII | IDD__FLAGS_VARLENIDX
1647 | IDD__FLAGS_NOCASECMP | IDD__FLAGS_NOCASENTR;
1648 bfd_putl16 (idd_flags, idd->flags);
a6163c10
TG
1649 bfd_putl16 (MAX_KEYLEN, idd->keylen);
1650 bfd_putl16 (mod_idx_vbn, idd->vbn);
1651 idd++;
1652
1653 /* Second index (symbols name). */
0e9b2e9a 1654 bfd_putl16 (idd_flags, idd->flags);
a6163c10
TG
1655 bfd_putl16 (MAX_KEYLEN, idd->keylen);
1656 bfd_putl16 (sym_idx_vbn, idd->vbn);
1657 idd++;
1658
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;
1663 }
1664
1665 return TRUE;
1666
1667 input_err:
1668 bfd_set_error (bfd_error_on_input, current, bfd_get_error ());
1669 return FALSE;
1670}
1671
1672/* Add a target for text library. This costs almost nothing and is useful to
1673 read VMS library on the host. */
1674
1675const bfd_target vms_lib_txt_vec =
1676{
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,
1692
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. */
1697
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),
1707
1708 NULL,
1709
1710 (PTR) 0
1711};
This page took 0.086434 seconds and 4 git commands to generate.