bfd/
[deliverable/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 /* Standard tdata for an archive. But we don't use many fields. */
66 struct artdata artdata;
67
68 /* Major version. */
69 unsigned char ver;
70
71 /* Type of the archive. */
72 unsigned char type;
73
74 /* Kind of archive. Summary of its type. */
75 enum vms_lib_kind kind;
76
77 /* Total size of the mhd (element header). */
78 unsigned int mhd_size;
79
80 /* Vector of modules (archive elements), already sorted. */
81 unsigned int nbr_modules;
82 struct carsym *modules;
83 bfd **cache;
84
85 /* DCX (decompression) data. */
86 unsigned int nbr_dcxsbm;
87 struct dcxsbm_desc *dcxsbm;
88 };
89
90 #define bfd_libdata(bfd) ((struct lib_tdata *)((bfd)->tdata.any))
91
92 /* End-Of-Text pattern. This is a special record to mark the end of file. */
93
94 static const unsigned char eotdesc[] = { 0x03, 0x00, 0x77, 0x00, 0x77, 0x00 };
95
96 /* Describe the current state of carsym entries while building the archive
97 table of content. Things are simple with Alpha archives as the number
98 of entries is known, but with IA64 archives a entry can make a reference
99 to severals members. Therefore we must be able to extend the table on the
100 fly, but it should be allocated on the bfd - which doesn't support realloc.
101 To reduce the overhead, the table is initially allocated in the BFD's
102 objalloc and extended if necessary on the heap. In the later case, it
103 is finally copied to the BFD's objalloc so that it will automatically be
104 freed. */
105
106 struct carsym_mem
107 {
108 /* The table of content. */
109 struct carsym *idx;
110
111 /* Number of entries used in the table. */
112 unsigned int nbr;
113
114 /* Maximum number of entries. */
115 unsigned int max;
116
117 /* If true, the table was reallocated on the heap. If false, it is still
118 in the BFD's objalloc. */
119 bfd_boolean realloced;
120 };
121
122 /* Simply add a name to the index. */
123
124 static bfd_boolean
125 vms_add_index (struct carsym_mem *cs, char *name,
126 unsigned int idx_vbn, unsigned int idx_off)
127 {
128 if (cs->nbr == cs->max)
129 {
130 struct carsym *n;
131
132 cs->max = 2 * cs->max + 32;
133
134 if (!cs->realloced)
135 {
136 n = bfd_malloc2 (cs->max, sizeof (struct carsym));
137 if (n == NULL)
138 return FALSE;
139 memcpy (n, cs->idx, cs->nbr * sizeof (struct carsym));
140 /* And unfortunately we can't free cs->idx. */
141 }
142 else
143 {
144 n = bfd_realloc_or_free (cs->idx, cs->nbr * sizeof (struct carsym));
145 if (n == NULL)
146 return FALSE;
147 }
148 cs->idx = n;
149 cs->realloced = TRUE;
150 }
151 cs->idx[cs->nbr].file_offset = (idx_vbn - 1) * VMS_BLOCK_SIZE + idx_off;
152 cs->idx[cs->nbr].name = name;
153 cs->nbr++;
154 return TRUE;
155 }
156
157 /* Follow all member of a lns list (pointed by RFA) and add indexes for
158 NAME. Return FALSE in case of error. */
159
160 static bfd_boolean
161 vms_add_indexes_from_list (bfd *abfd, struct carsym_mem *cs, char *name,
162 struct vms_rfa *rfa)
163 {
164 struct vms_lns lns;
165 unsigned int vbn;
166 file_ptr off;
167
168 while (1)
169 {
170 vbn = bfd_getl32 (rfa->vbn);
171 if (vbn == 0)
172 return TRUE;
173
174 /* Read the LHS. */
175 off = (vbn - 1) * VMS_BLOCK_SIZE + bfd_getl16 (rfa->offset);
176 if (bfd_seek (abfd, off, SEEK_SET) != 0
177 || bfd_bread (&lns, sizeof (lns), abfd) != sizeof (lns))
178 return FALSE;
179
180 if (!vms_add_index (cs, name,
181 bfd_getl32 (lns.modrfa.vbn),
182 bfd_getl16 (lns.modrfa.offset)))
183 return FALSE;
184
185 rfa = &lns.nxtrfa;
186 }
187 }
188
189 /* Read block VBN from ABFD and store it into BLK. */
190
191 static bfd_boolean
192 vms_read_block (bfd *abfd, unsigned int vbn, void *blk)
193 {
194 file_ptr off;
195
196 /* Read the index block. */
197 off = (vbn - 1) * VMS_BLOCK_SIZE;
198 if (bfd_seek (abfd, off, SEEK_SET) != 0
199 || bfd_bread (blk, VMS_BLOCK_SIZE, abfd) != VMS_BLOCK_SIZE)
200 return FALSE;
201
202 return TRUE;
203 }
204
205 /* Read index block VBN and put the entry in **IDX (which is updated).
206 If the entry is indirect, recurse. */
207
208 static bfd_boolean
209 vms_traverse_index (bfd *abfd, unsigned int vbn, struct carsym_mem *cs)
210 {
211 struct vms_indexdef indexdef;
212 file_ptr off;
213 unsigned char *p;
214 unsigned char *endp;
215
216 /* Read the index block. */
217 BFD_ASSERT (sizeof (indexdef) == VMS_BLOCK_SIZE);
218 if (!vms_read_block (abfd, vbn, &indexdef))
219 return FALSE;
220
221 /* Traverse it. */
222 p = &indexdef.keys[0];
223 endp = p + bfd_getl16 (indexdef.used);
224 while (p < endp)
225 {
226 unsigned int idx_vbn;
227 unsigned int idx_off;
228 unsigned int keylen;
229 unsigned char *keyname;
230 unsigned int flags;
231
232 /* Extract key length. */
233 if (bfd_libdata (abfd)->ver == LBR_MAJORID)
234 {
235 struct vms_idx *ridx = (struct vms_idx *)p;
236
237 idx_vbn = bfd_getl32 (ridx->rfa.vbn);
238 idx_off = bfd_getl16 (ridx->rfa.offset);
239
240 keylen = ridx->keylen;
241 flags = 0;
242 keyname = ridx->keyname;
243 }
244 else if (bfd_libdata (abfd)->ver == LBR_ELFMAJORID)
245 {
246 struct vms_elfidx *ridx = (struct vms_elfidx *)p;
247
248 idx_vbn = bfd_getl32 (ridx->rfa.vbn);
249 idx_off = bfd_getl16 (ridx->rfa.offset);
250
251 keylen = bfd_getl16 (ridx->keylen);
252 flags = ridx->flags;
253 keyname = ridx->keyname;
254 }
255 else
256 return FALSE;
257
258 /* Illegal value. */
259 if (idx_vbn == 0)
260 return FALSE;
261
262 if (idx_off == RFADEF__C_INDEX)
263 {
264 /* Indirect entry. Recurse. */
265 if (!vms_traverse_index (abfd, idx_vbn, cs))
266 return FALSE;
267 }
268 else
269 {
270 /* Add a new entry. */
271 char *name;
272
273 if (flags & ELFIDX__SYMESC)
274 {
275 /* Extended key name. */
276 unsigned int noff = 0;
277 unsigned int koff;
278 unsigned int kvbn;
279 struct vms_kbn *kbn;
280 unsigned char kblk[VMS_BLOCK_SIZE];
281
282 /* Sanity check. */
283 if (keylen != sizeof (struct vms_kbn))
284 return FALSE;
285
286 kbn = (struct vms_kbn *)keyname;
287 keylen = bfd_getl16 (kbn->keylen);
288
289 name = bfd_alloc (abfd, keylen + 1);
290 if (name == NULL)
291 return FALSE;
292 kvbn = bfd_getl32 (kbn->rfa.vbn);
293 koff = bfd_getl16 (kbn->rfa.offset);
294
295 /* Read the key, chunk by chunk. */
296 do
297 {
298 unsigned int klen;
299
300 if (!vms_read_block (abfd, kvbn, kblk))
301 return FALSE;
302 kbn = (struct vms_kbn *)(kblk + koff);
303 klen = bfd_getl16 (kbn->keylen);
304 kvbn = bfd_getl32 (kbn->rfa.vbn);
305 koff = bfd_getl16 (kbn->rfa.offset);
306
307 memcpy (name + noff, kbn + 1, klen);
308 noff += klen;
309 }
310 while (kvbn != 0);
311
312 /* Sanity check. */
313 if (noff != keylen)
314 return FALSE;
315 }
316 else
317 {
318 /* Usual key name. */
319 name = bfd_alloc (abfd, keylen + 1);
320 if (name == NULL)
321 return FALSE;
322
323 memcpy (name, keyname, keylen);
324 }
325 name[keylen] = 0;
326
327 if (flags & ELFIDX__LISTRFA)
328 {
329 struct vms_lhs lhs;
330
331 /* Read the LHS. */
332 off = (idx_vbn - 1) * VMS_BLOCK_SIZE + idx_off;
333 if (bfd_seek (abfd, off, SEEK_SET) != 0
334 || bfd_bread (&lhs, sizeof (lhs), abfd) != sizeof (lhs))
335 return FALSE;
336
337 /* FIXME: this adds extra entries that were not accounted. */
338 if (!vms_add_indexes_from_list (abfd, cs, name, &lhs.ng_g_rfa))
339 return FALSE;
340 if (!vms_add_indexes_from_list (abfd, cs, name, &lhs.ng_wk_rfa))
341 return FALSE;
342 if (!vms_add_indexes_from_list (abfd, cs, name, &lhs.g_g_rfa))
343 return FALSE;
344 if (!vms_add_indexes_from_list (abfd, cs, name, &lhs.g_wk_rfa))
345 return FALSE;
346 }
347 else
348 {
349 if (!vms_add_index (cs, name, idx_vbn, idx_off))
350 return FALSE;
351 }
352 }
353
354 /* Point to the next index entry. */
355 p = keyname + keylen;
356 }
357
358 return TRUE;
359 }
360
361 /* Read index #IDX, which must have NBREL entries. */
362
363 static struct carsym *
364 vms_lib_read_index (bfd *abfd, int idx, unsigned int *nbrel)
365 {
366 struct vms_idd idd;
367 unsigned int flags;
368 unsigned int vbn;
369 struct carsym *csbuf;
370 struct carsym_mem csm;
371
372 /* Read index desription. */
373 if (bfd_seek (abfd, LHD_IDXDESC + idx * IDD_LENGTH, SEEK_SET) != 0
374 || bfd_bread (&idd, sizeof (idd), abfd) != sizeof (idd))
375 return NULL;
376
377 /* Sanity checks. */
378 flags = bfd_getl16 (idd.flags);
379 if (!(flags & IDD__FLAGS_ASCII)
380 || !(flags & IDD__FLAGS_VARLENIDX))
381 return NULL;
382
383 csbuf = bfd_alloc (abfd, *nbrel * sizeof (struct carsym));
384 if (csbuf == NULL)
385 return NULL;
386
387 csm.max = *nbrel;
388 csm.nbr = 0;
389 csm.realloced = FALSE;
390 csm.idx = csbuf;
391
392 /* Note: if the index is empty, there is no block to traverse. */
393 vbn = bfd_getl32 (idd.vbn);
394 if (vbn != 0 && !vms_traverse_index (abfd, vbn, &csm))
395 {
396 if (csm.realloced && csm.idx != NULL)
397 free (csm.idx);
398
399 /* Note: in case of error, we can free what was allocated on the
400 BFD's objalloc. */
401 bfd_release (abfd, csbuf);
402 return NULL;
403 }
404
405 if (csm.realloced)
406 {
407 /* There are more entries than the first estimate. Allocate on
408 the BFD's objalloc. */
409 csbuf = bfd_alloc (abfd, csm.nbr * sizeof (struct carsym));
410 if (csbuf == NULL)
411 return NULL;
412 memcpy (csbuf, csm.idx, csm.nbr * sizeof (struct carsym));
413 free (csm.idx);
414 *nbrel = csm.nbr;
415 }
416 return csbuf;
417 }
418
419 /* Standard function. */
420
421 static const bfd_target *
422 _bfd_vms_lib_archive_p (bfd *abfd, enum vms_lib_kind kind)
423 {
424 struct vms_lhd lhd;
425 unsigned int sanity;
426 struct lib_tdata *tdata_hold;
427 struct lib_tdata *tdata;
428 unsigned int dcxvbn;
429 unsigned int nbr_ent;
430
431 /* Read header. */
432 if (bfd_bread (&lhd, sizeof (lhd), abfd) != sizeof (lhd))
433 {
434 if (bfd_get_error () != bfd_error_system_call)
435 bfd_set_error (bfd_error_wrong_format);
436 return NULL;
437 }
438
439 /* Check sanity (= magic) number. */
440 sanity = bfd_getl32 (lhd.sanity);
441 if (!(sanity == LHD_SANEID3
442 || sanity == LHD_SANEID6
443 || sanity == LHD_SANEID_DCX))
444 {
445 bfd_set_error (bfd_error_wrong_format);
446 return NULL;
447 }
448
449 /* Check archive kind. */
450 switch (kind)
451 {
452 case vms_lib_alpha:
453 if ((lhd.type != LBR__C_TYP_EOBJ && lhd.type != LBR__C_TYP_ESHSTB)
454 || bfd_getl32 (lhd.majorid) != 3
455 || lhd.nindex != 2)
456 {
457 bfd_set_error (bfd_error_wrong_format);
458 return NULL;
459 }
460 break;
461 case vms_lib_ia64:
462 if ((lhd.type != LBR__C_TYP_IOBJ && lhd.type != LBR__C_TYP_ISHSTB)
463 || bfd_getl32 (lhd.majorid) != 6
464 || lhd.nindex != 2)
465 {
466 bfd_set_error (bfd_error_wrong_format);
467 return NULL;
468 }
469 break;
470 case vms_lib_txt:
471 if ((lhd.type != LBR__C_TYP_TXT
472 && lhd.type != LBR__C_TYP_MLB
473 && lhd.type != LBR__C_TYP_HLP)
474 || bfd_getl32 (lhd.majorid) != 3
475 || lhd.nindex != 1)
476 {
477 bfd_set_error (bfd_error_wrong_format);
478 return NULL;
479 }
480 break;
481 default:
482 abort ();
483 }
484
485 /* Allocate and initialize private data. */
486 tdata_hold = bfd_libdata (abfd);
487 tdata = (struct lib_tdata *) bfd_zalloc (abfd, sizeof (struct lib_tdata));
488 if (tdata == NULL)
489 return NULL;
490 abfd->tdata.any = (void *)tdata;
491 tdata->ver = bfd_getl32 (lhd.majorid);
492 tdata->mhd_size = MHD__C_USRDAT + lhd.mhdusz;
493 tdata->type = lhd.type;
494 tdata->kind = kind;
495
496 /* Read indexes. */
497 tdata->nbr_modules = bfd_getl32 (lhd.modcnt);
498 tdata->artdata.symdef_count = bfd_getl32 (lhd.idxcnt) - tdata->nbr_modules;
499 nbr_ent = tdata->nbr_modules;
500 tdata->modules = vms_lib_read_index (abfd, 0, &nbr_ent);
501 if (tdata->modules == NULL || nbr_ent != tdata->nbr_modules)
502 goto err;
503 if (lhd.nindex == 2)
504 {
505 nbr_ent = tdata->artdata.symdef_count;
506 tdata->artdata.symdefs = vms_lib_read_index (abfd, 1, &nbr_ent);
507 if (tdata->artdata.symdefs == NULL)
508 goto err;
509 /* Only IA64 archives may have more entries in the index that what
510 was declared. */
511 if (nbr_ent != tdata->artdata.symdef_count
512 && kind != vms_lib_ia64)
513 goto err;
514 tdata->artdata.symdef_count = nbr_ent;
515 }
516 tdata->cache = bfd_zalloc (abfd, sizeof (bfd *) * tdata->nbr_modules);
517 if (tdata->cache == NULL)
518 goto err;
519
520 /* Read DCX submaps. */
521 dcxvbn = bfd_getl32 (lhd.dcxmapvbn);
522 if (dcxvbn != 0)
523 {
524 unsigned char buf_reclen[4];
525 unsigned int reclen;
526 unsigned char *buf;
527 struct vms_dcxmap *map;
528 unsigned int sbm_off;
529 unsigned int i;
530
531 if (bfd_seek (abfd, (dcxvbn - 1) * VMS_BLOCK_SIZE, SEEK_SET) != 0
532 || bfd_bread (buf_reclen, sizeof (buf_reclen), abfd)
533 != sizeof (buf_reclen))
534 goto err;
535 reclen = bfd_getl32 (buf_reclen);
536 buf = bfd_malloc (reclen);
537 if (buf == NULL)
538 goto err;
539 if (bfd_bread (buf, reclen, abfd) != reclen)
540 {
541 free (buf);
542 goto err;
543 }
544 map = (struct vms_dcxmap *)buf;
545 tdata->nbr_dcxsbm = bfd_getl16 (map->nsubs);
546 sbm_off = bfd_getl16 (map->sub0);
547 tdata->dcxsbm = (struct dcxsbm_desc *)bfd_alloc
548 (abfd, tdata->nbr_dcxsbm * sizeof (struct dcxsbm_desc));
549 for (i = 0; i < tdata->nbr_dcxsbm; i++)
550 {
551 struct vms_dcxsbm *sbm = (struct vms_dcxsbm *) (buf + sbm_off);
552 struct dcxsbm_desc *sbmdesc = &tdata->dcxsbm[i];
553 unsigned int sbm_len;
554 unsigned int sbm_sz;
555 unsigned char *data = (unsigned char *)sbm;
556 unsigned char *buf1;
557 unsigned int l, j;
558
559 sbm_sz = bfd_getl16 (sbm->size);
560 sbm_off += sbm_sz;
561 BFD_ASSERT (sbm_off <= reclen);
562
563 sbmdesc->min_char = sbm->min_char;
564 BFD_ASSERT (sbmdesc->min_char == 0);
565 sbmdesc->max_char = sbm->max_char;
566 sbm_len = sbmdesc->max_char - sbmdesc->min_char + 1;
567 l = (2 * sbm_len + 7) / 8;
568 BFD_ASSERT (sbm_sz >= sizeof (struct vms_dcxsbm) + l + 3 * sbm_len);
569 sbmdesc->flags = (unsigned char *)bfd_alloc (abfd, l);
570 memcpy (sbmdesc->flags, data + bfd_getl16 (sbm->flags), l);
571 sbmdesc->nodes = (unsigned char *)bfd_alloc (abfd, 2 * sbm_len);
572 memcpy (sbmdesc->nodes, data + bfd_getl16 (sbm->nodes), 2 * sbm_len);
573 sbmdesc->next = (unsigned short *)bfd_alloc
574 (abfd, sbm_len * sizeof (unsigned short));
575 buf1 = data + bfd_getl16 (sbm->next);
576 for (j = 0; j < sbm_len; j++)
577 sbmdesc->next[j] = bfd_getl16 (buf1 + j * 2);
578 }
579 free (buf);
580 }
581 else
582 {
583 tdata->nbr_dcxsbm = 0;
584 }
585
586 /* The map is always present. Also mark shared image library. */
587 abfd->has_armap = TRUE;
588 if (tdata->type == LBR__C_TYP_ESHSTB || tdata->type == LBR__C_TYP_ISHSTB)
589 abfd->is_thin_archive = TRUE;
590
591 return abfd->xvec;
592
593 err:
594 bfd_release (abfd, tdata);
595 abfd->tdata.any = (void *)tdata_hold;;
596 return NULL;
597 }
598
599 /* Standard function for alpha libraries. */
600
601 const bfd_target *
602 _bfd_vms_lib_alpha_archive_p (bfd *abfd)
603 {
604 return _bfd_vms_lib_archive_p (abfd, vms_lib_alpha);
605 }
606
607 /* Standard function for text libraries. */
608
609 static const bfd_target *
610 _bfd_vms_lib_txt_archive_p (bfd *abfd)
611 {
612 return _bfd_vms_lib_archive_p (abfd, vms_lib_txt);
613 }
614
615 /* Standard bfd function. */
616
617 bfd_boolean
618 _bfd_vms_lib_mkarchive (bfd *abfd)
619 {
620 struct lib_tdata *tdata;
621
622 tdata = (struct lib_tdata *) bfd_zalloc (abfd, sizeof (struct lib_tdata));
623 if (tdata == NULL)
624 return FALSE;
625
626 abfd->tdata.any = (void *)tdata;
627 tdata->ver = 3;
628 tdata->mhd_size = sizeof (struct vms_mhd);
629 tdata->type = LBR__C_TYP_EOBJ;
630
631 tdata->nbr_modules = 0;
632 tdata->artdata.symdef_count = 0;
633 tdata->modules = NULL;
634 tdata->artdata.symdefs = NULL;
635 tdata->cache = NULL;
636
637 return TRUE;
638 }
639
640 /* Find NAME in the symbol index. Return the index. */
641
642 symindex
643 _bfd_vms_lib_find_symbol (bfd *abfd, const char *name)
644 {
645 struct lib_tdata *tdata = bfd_libdata (abfd);
646 carsym *syms = tdata->artdata.symdefs;
647 int lo, hi;
648
649 /* Open-coded binary search for speed. */
650 lo = 0;
651 hi = tdata->artdata.symdef_count - 1;
652
653 while (lo <= hi)
654 {
655 int mid = lo + (hi - lo) / 2;
656 int diff;
657
658 diff = (char)(name[0] - syms[mid].name[0]);
659 if (diff == 0)
660 diff = strcmp (name, syms[mid].name);
661 if (diff == 0)
662 return mid;
663 else if (diff < 0)
664 hi = mid - 1;
665 else
666 lo = mid + 1;
667 }
668 return BFD_NO_MORE_SYMBOLS;
669 }
670
671 /* IO vector for archive member. Need that because members are not linearly
672 stored in archives. */
673
674 struct vms_lib_iovec
675 {
676 /* Current offset. */
677 ufile_ptr where;
678
679 /* Length of the module, when known. */
680 ufile_ptr file_len;
681
682 /* Current position in the record from bfd_bread point of view (ie, after
683 decompression). 0 means that no data byte have been read, -2 and -1
684 are reserved for the length word. */
685 int rec_pos;
686 #define REC_POS_NL -4
687 #define REC_POS_PAD -3
688 #define REC_POS_LEN0 -2
689 #define REC_POS_LEN1 -1
690
691 /* Record length. */
692 unsigned short rec_len;
693 /* Number of bytes to read in the current record. */
694 unsigned short rec_rem;
695 /* Offset of the next block. */
696 file_ptr next_block;
697 /* Current *data* offset in the data block. */
698 unsigned short blk_off;
699
700 /* Offset of the first block. Extracted from the index. */
701 file_ptr first_block;
702
703 /* Initial next_block. Extracted when the MHD is read. */
704 file_ptr init_next_block;
705 /* Initial blk_off, once the MHD is read. */
706 unsigned short init_blk_off;
707
708 /* Used to store any 3 byte record, which could be the EOF pattern. */
709 unsigned char pattern[4];
710
711 /* DCX. */
712 struct dcxsbm_desc *dcxsbms;
713 /* Current submap. */
714 struct dcxsbm_desc *dcx_sbm;
715 /* Current offset in the submap. */
716 unsigned int dcx_offset;
717 int dcx_pos;
718
719 /* Compressed buffer. */
720 unsigned char *dcx_buf;
721 /* Size of the buffer. Used to resize. */
722 unsigned int dcx_max;
723 /* Number of valid bytes in the buffer. */
724 unsigned int dcx_rlen;
725 };
726
727 /* Return the current position. */
728
729 static file_ptr
730 vms_lib_btell (struct bfd *abfd)
731 {
732 struct vms_lib_iovec *vec = (struct vms_lib_iovec *) abfd->iostream;
733 return vec->where;
734 }
735
736 /* Read the header of the next data block if all bytes of the current block
737 have been read. */
738
739 static bfd_boolean
740 vms_lib_read_block (struct bfd *abfd)
741 {
742 struct vms_lib_iovec *vec = (struct vms_lib_iovec *) abfd->iostream;
743
744 if (vec->blk_off == DATA__LENGTH)
745 {
746 unsigned char hdr[DATA__DATA];
747
748 /* Read next block. */
749 if (bfd_seek (abfd->my_archive, vec->next_block, SEEK_SET) != 0)
750 return FALSE;
751 if (bfd_bread (hdr, sizeof (hdr), abfd->my_archive) != sizeof (hdr))
752 return FALSE;
753 vec->next_block = (bfd_getl32 (hdr + 2) - 1) * VMS_BLOCK_SIZE;
754 vec->blk_off = sizeof (hdr);
755 }
756 return TRUE;
757 }
758
759 /* Read NBYTES from ABFD into BUF if not NULL. If BUF is NULL, bytes are
760 not stored. Read linearly from the library, but handle blocks. This
761 function does not handle records nor EOF. */
762
763 static file_ptr
764 vms_lib_bread_raw (struct bfd *abfd, void *buf, file_ptr nbytes)
765 {
766 struct vms_lib_iovec *vec = (struct vms_lib_iovec *) abfd->iostream;
767 file_ptr res;
768
769 res = 0;
770 while (nbytes > 0)
771 {
772 unsigned int l;
773
774 /* Be sure the current data block is read. */
775 if (!vms_lib_read_block (abfd))
776 return -1;
777
778 /* Do not read past the data block, do not read more than requested. */
779 l = DATA__LENGTH - vec->blk_off;
780 if (l > nbytes)
781 l = nbytes;
782 if (l == 0)
783 return 0;
784 if (buf != NULL)
785 {
786 /* Really read into BUF. */
787 if (bfd_bread (buf, l, abfd->my_archive) != l)
788 return -1;
789 }
790 else
791 {
792 /* Make as if we are reading. */
793 if (bfd_seek (abfd->my_archive, l, SEEK_CUR) != 0)
794 return -1;
795 }
796
797 if (buf != NULL)
798 buf += l;
799 vec->blk_off += l;
800 nbytes -= l;
801 res += l;
802 }
803 return res;
804 }
805
806 /* Decompress NBYTES from VEC. Store the bytes into BUF if not NULL. */
807
808 static file_ptr
809 vms_lib_dcx (struct vms_lib_iovec *vec, unsigned char *buf, file_ptr nbytes)
810 {
811 struct dcxsbm_desc *sbm;
812 unsigned int i;
813 unsigned int offset;
814 unsigned int j;
815 file_ptr res = 0;
816
817 /* The loop below expect to deliver at least one byte. */
818 if (nbytes == 0)
819 return 0;
820
821 /* Get the current state. */
822 sbm = vec->dcx_sbm;
823 offset = vec->dcx_offset;
824 j = vec->dcx_pos & 7;
825
826 for (i = vec->dcx_pos >> 3; i < vec->dcx_rlen; i++)
827 {
828 unsigned char b = vec->dcx_buf[i];
829
830 for (; j < 8; j++)
831 {
832 if (b & (1 << j))
833 offset++;
834 if (!(sbm->flags[offset >> 3] & (1 << (offset & 7))))
835 {
836 unsigned int n_offset = sbm->nodes[offset];
837 if (n_offset == 0)
838 {
839 /* End of buffer. Stay where we are. */
840 vec->dcx_pos = (i << 3) + j;
841 if (b & (1 << j))
842 offset--;
843 vec->dcx_offset = offset;
844 vec->dcx_sbm = sbm;
845 return res;
846 }
847 offset = 2 * n_offset;
848 }
849 else
850 {
851 unsigned char v = sbm->nodes[offset];
852
853 sbm = vec->dcxsbms + sbm->next[v];
854 offset = 0;
855 res++;
856
857 if (buf)
858 {
859 *buf++ = v;
860 nbytes--;
861
862 if (nbytes == 0)
863 {
864 vec->dcx_pos = (i << 3) + j + 1;
865 vec->dcx_offset = offset;
866 vec->dcx_sbm = sbm;
867
868 return res;
869 }
870 }
871 }
872 }
873 j = 0;
874 }
875 return -1;
876 }
877
878 /* Standard IOVEC function. */
879
880 static file_ptr
881 vms_lib_bread (struct bfd *abfd, void *buf, file_ptr nbytes)
882 {
883 struct vms_lib_iovec *vec = (struct vms_lib_iovec *) abfd->iostream;
884 file_ptr res;
885 file_ptr chunk;
886
887 /* Do not read past the end. */
888 if (vec->where >= vec->file_len)
889 return 0;
890
891 res = 0;
892 while (nbytes > 0)
893 {
894 if (vec->rec_rem == 0)
895 {
896 unsigned char blen[2];
897
898 /* Read record length. */
899 if (vms_lib_bread_raw (abfd, &blen, sizeof (blen)) != sizeof (blen))
900 return -1;
901 vec->rec_len = bfd_getl16 (blen);
902 if (bfd_libdata (abfd->my_archive)->kind == vms_lib_txt)
903 {
904 /* Discard record size and align byte. */
905 vec->rec_pos = 0;
906 vec->rec_rem = vec->rec_len;
907 }
908 else
909 {
910 /* Prepend record size. */
911 vec->rec_pos = REC_POS_LEN0;
912 vec->rec_rem = (vec->rec_len + 1) & ~1; /* With align byte. */
913 }
914 if (vec->rec_len == 3)
915 {
916 /* Possibly end of file. Check the pattern. */
917 if (vms_lib_bread_raw (abfd, vec->pattern, 4) != 4)
918 return -1;
919 if (!memcmp (vec->pattern, eotdesc + 2, 3))
920 {
921 /* This is really an EOF. */
922 vec->where += res;
923 vec->file_len = vec->where;
924 return res;
925 }
926 }
927
928 if (vec->dcxsbms != NULL)
929 {
930 /* This is a compressed member. */
931 unsigned int len;
932 file_ptr elen;
933
934 /* Be sure there is enough room for the expansion. */
935 len = (vec->rec_len + 1) & ~1;
936 if (len > vec->dcx_max)
937 {
938 while (len > vec->dcx_max)
939 vec->dcx_max *= 2;
940 vec->dcx_buf = bfd_alloc (abfd, vec->dcx_max);
941 if (vec->dcx_buf == NULL)
942 return -1;
943 }
944
945 /* Read the compressed record. */
946 vec->dcx_rlen = len;
947 if (vec->rec_len == 3)
948 {
949 /* Already read. */
950 memcpy (vec->dcx_buf, vec->pattern, 3);
951 }
952 else
953 {
954 elen = vms_lib_bread_raw (abfd, vec->dcx_buf, len);
955 if (elen != len)
956 return -1;
957 }
958
959 /* Dummy expansion to get the expanded length. */
960 vec->dcx_offset = 0;
961 vec->dcx_sbm = vec->dcxsbms;
962 vec->dcx_pos = 0;
963 elen = vms_lib_dcx (vec, NULL, 0x10000);
964 if (elen < 0)
965 return -1;
966 vec->rec_len = elen;
967 vec->rec_rem = elen;
968
969 /* Reset the state. */
970 vec->dcx_offset = 0;
971 vec->dcx_sbm = vec->dcxsbms;
972 vec->dcx_pos = 0;
973 }
974 }
975 if (vec->rec_pos < 0)
976 {
977 unsigned char c;
978 switch (vec->rec_pos)
979 {
980 case REC_POS_LEN0:
981 c = vec->rec_len & 0xff;
982 vec->rec_pos = REC_POS_LEN1;
983 break;
984 case REC_POS_LEN1:
985 c = (vec->rec_len >> 8) & 0xff;
986 vec->rec_pos = 0;
987 break;
988 case REC_POS_PAD:
989 c = 0;
990 vec->rec_rem = 0;
991 break;
992 case REC_POS_NL:
993 c = '\n';
994 vec->rec_rem = 0;
995 break;
996 default:
997 abort ();
998 }
999 if (buf != NULL)
1000 {
1001 *(unsigned char *)buf = c;
1002 buf++;
1003 }
1004 nbytes--;
1005 res++;
1006 continue;
1007 }
1008
1009 if (nbytes > vec->rec_rem)
1010 chunk = vec->rec_rem;
1011 else
1012 chunk = nbytes;
1013
1014 if (vec->dcxsbms != NULL)
1015 {
1016 /* Optimize the stat() case: no need to decompress again as we
1017 know the length. */
1018 if (!(buf == NULL && chunk == vec->rec_rem))
1019 chunk = vms_lib_dcx (vec, buf, chunk);
1020 }
1021 else
1022 {
1023 if (vec->rec_len == 3)
1024 {
1025 if (buf != NULL)
1026 memcpy (buf, vec->pattern + vec->rec_pos, chunk);
1027 }
1028 else
1029 chunk = vms_lib_bread_raw (abfd, buf, chunk);
1030 }
1031 if (chunk < 0)
1032 return -1;
1033 res += chunk;
1034 if (buf != NULL)
1035 buf += chunk;
1036 nbytes -= chunk;
1037 vec->rec_pos += chunk;
1038 vec->rec_rem -= chunk;
1039
1040 if (vec->rec_rem == 0)
1041 {
1042 /* End of record reached. */
1043 if (bfd_libdata (abfd->my_archive)->kind == vms_lib_txt)
1044 {
1045 if ((vec->rec_len & 1) == 1
1046 && vec->rec_len != 3
1047 && vec->dcxsbms == NULL)
1048 {
1049 /* Eat the pad byte. */
1050 unsigned char pad;
1051 if (vms_lib_bread_raw (abfd, &pad, 1) != 1)
1052 return -1;
1053 }
1054 vec->rec_pos = REC_POS_NL;
1055 vec->rec_rem = 1;
1056 }
1057 else
1058 {
1059 if ((vec->rec_len & 1) == 1 && vec->dcxsbms != NULL)
1060 {
1061 vec->rec_pos = REC_POS_PAD;
1062 vec->rec_rem = 1;
1063 }
1064 }
1065 }
1066 }
1067 vec->where += res;
1068 return res;
1069 }
1070
1071 /* Standard function, but we currently only handle the rewind case. */
1072
1073 static int
1074 vms_lib_bseek (struct bfd *abfd, file_ptr offset, int whence)
1075 {
1076 struct vms_lib_iovec *vec = (struct vms_lib_iovec *) abfd->iostream;
1077
1078 if (whence == SEEK_SET && offset == 0)
1079 {
1080 vec->where = 0;
1081 vec->rec_rem = 0;
1082 vec->dcx_pos = -1;
1083 vec->blk_off = vec->init_blk_off;
1084 vec->next_block = vec->init_next_block;
1085
1086 if (bfd_seek (abfd->my_archive, vec->first_block, SEEK_SET) != 0)
1087 return -1;
1088 }
1089 else
1090 abort ();
1091 return 0;
1092 }
1093
1094 static file_ptr
1095 vms_lib_bwrite (struct bfd *abfd ATTRIBUTE_UNUSED,
1096 const void *where ATTRIBUTE_UNUSED,
1097 file_ptr nbytes ATTRIBUTE_UNUSED)
1098 {
1099 return -1;
1100 }
1101
1102 static int
1103 vms_lib_bclose (struct bfd *abfd)
1104 {
1105 abfd->iostream = NULL;
1106 return 0;
1107 }
1108
1109 static int
1110 vms_lib_bflush (struct bfd *abfd ATTRIBUTE_UNUSED)
1111 {
1112 return 0;
1113 }
1114
1115 static int
1116 vms_lib_bstat (struct bfd *abfd ATTRIBUTE_UNUSED,
1117 struct stat *sb ATTRIBUTE_UNUSED)
1118 {
1119 /* Not supported. */
1120 return 0;
1121 }
1122
1123 static void *
1124 vms_lib_bmmap (struct bfd *abfd ATTRIBUTE_UNUSED,
1125 void *addr ATTRIBUTE_UNUSED,
1126 bfd_size_type len ATTRIBUTE_UNUSED,
1127 int prot ATTRIBUTE_UNUSED,
1128 int flags ATTRIBUTE_UNUSED,
1129 file_ptr offset ATTRIBUTE_UNUSED)
1130 {
1131 return (void *) -1;
1132 }
1133
1134 static const struct bfd_iovec vms_lib_iovec = {
1135 &vms_lib_bread, &vms_lib_bwrite, &vms_lib_btell, &vms_lib_bseek,
1136 &vms_lib_bclose, &vms_lib_bflush, &vms_lib_bstat, &vms_lib_bmmap
1137 };
1138
1139 /* Open a library module. FILEPOS is the position of the module header. */
1140
1141 static bfd_boolean
1142 vms_lib_bopen (bfd *el, file_ptr filepos)
1143 {
1144 struct vms_lib_iovec *vec;
1145 char buf[256];
1146 struct vms_mhd *mhd;
1147 struct lib_tdata *tdata = bfd_libdata (el->my_archive);
1148 unsigned int len;
1149
1150 /* Allocate and initialized the iovec. */
1151 vec = bfd_zalloc (el, sizeof (*vec));
1152 if (vec == NULL)
1153 return FALSE;
1154
1155 el->iostream = vec;
1156 el->iovec = &vms_lib_iovec;
1157
1158 /* File length is not known. */
1159 vec->file_len = -1;
1160
1161 /* Read the first data block. */
1162 vec->next_block = filepos & ~(VMS_BLOCK_SIZE - 1);
1163 vec->blk_off = DATA__LENGTH;
1164 if (!vms_lib_read_block (el))
1165 return FALSE;
1166
1167 /* Prepare to read the first record. */
1168 vec->blk_off = filepos & (VMS_BLOCK_SIZE - 1);
1169 vec->rec_rem = 0;
1170 if (bfd_seek (el->my_archive, filepos, SEEK_SET) != 0)
1171 return FALSE;
1172
1173 /* Read Record length + MHD + align byte. */
1174 len = tdata->mhd_size;
1175 if (vms_lib_bread_raw (el, buf, 2) != 2)
1176 return FALSE;
1177 if (bfd_getl16 (buf) != len)
1178 return FALSE;
1179 len = (len + 1) & ~1;
1180 BFD_ASSERT (len <= sizeof (buf));
1181 if (vms_lib_bread_raw (el, buf, len) != len)
1182 return FALSE;
1183
1184 /* Get info from mhd. */
1185 mhd = (struct vms_mhd *)buf;
1186 /* Check id. */
1187 if (mhd->id != MHD__C_MHDID)
1188 return FALSE;
1189 if (len >= sizeof (struct vms_mhd))
1190 el->selective_search = (mhd->objstat & MHD__M_SELSRC) ? 1 : 0;
1191 el->mtime = vms_rawtime_to_time_t (mhd->datim);
1192 el->mtime_set = TRUE;
1193
1194 /* Reinit the iovec so that seek() will point to the first record after
1195 the mhd. */
1196 vec->where = 0;
1197 vec->init_blk_off = vec->blk_off;
1198 vec->init_next_block = vec->next_block;
1199 vec->first_block = bfd_tell (el->my_archive);
1200 vec->dcxsbms = bfd_libdata (el->my_archive)->dcxsbm;
1201
1202 if (vec->dcxsbms != NULL)
1203 {
1204 /* Handle DCX. */
1205 vec->dcx_max = 10 * 1024;
1206 vec->dcx_buf = bfd_alloc (el, vec->dcx_max);
1207 vec->dcx_pos = -1;
1208 if (vec->dcx_buf == NULL)
1209 return -1;
1210 }
1211 return TRUE;
1212 }
1213
1214 /* Get member MODIDX. Return NULL in case of error. */
1215
1216 static bfd *
1217 _bfd_vms_lib_get_module (bfd *abfd, unsigned int modidx)
1218 {
1219 struct lib_tdata *tdata = bfd_libdata (abfd);
1220 bfd *res;
1221 file_ptr file_off;
1222
1223 /* Sanity check. */
1224 if (modidx >= tdata->nbr_modules)
1225 return NULL;
1226
1227 /* Already loaded. */
1228 if (tdata->cache[modidx])
1229 return tdata->cache[modidx];
1230
1231 /* Build it. */
1232 file_off = tdata->modules[modidx].file_offset;
1233 if (tdata->type != LBR__C_TYP_IOBJ)
1234 {
1235 res = _bfd_create_empty_archive_element_shell (abfd);
1236 if (res == NULL)
1237 return NULL;
1238
1239 /* Special reader to deal with data blocks. */
1240 if (!vms_lib_bopen (res, file_off))
1241 return NULL;
1242 }
1243 else
1244 {
1245 char buf[256];
1246 struct vms_mhd *mhd;
1247 struct areltdata *arelt;
1248
1249 /* Sanity check. The MHD must be big enough to contain module size. */
1250 if (tdata->mhd_size < offsetof (struct vms_mhd, modsize) + 4)
1251 return NULL;
1252
1253 /* Read the MHD now. */
1254 if (bfd_seek (abfd, file_off, SEEK_SET) != 0)
1255 return NULL;
1256 if (bfd_bread (buf, tdata->mhd_size, abfd) != tdata->mhd_size)
1257 return NULL;
1258
1259 res = _bfd_create_empty_archive_element_shell (abfd);
1260 if (res == NULL)
1261 return NULL;
1262 arelt = bfd_zalloc (res, sizeof (*arelt));
1263 if (arelt == NULL)
1264 return NULL;
1265 res->arelt_data = arelt;
1266
1267 /* Get info from mhd. */
1268 mhd = (struct vms_mhd *)buf;
1269 if (mhd->id != MHD__C_MHDID)
1270 return NULL;
1271 if (tdata->mhd_size >= offsetof (struct vms_mhd, objstat) + 1)
1272 res->selective_search = (mhd->objstat & MHD__M_SELSRC) ? 1 : 0;
1273 res->mtime = vms_rawtime_to_time_t (mhd->datim);
1274 res->mtime_set = TRUE;
1275
1276 arelt->parsed_size = bfd_getl32 (mhd->modsize);
1277
1278 /* No need for a special reader as members are stored linearly.
1279 Just skip the MHD. */
1280 res->origin = file_off + tdata->mhd_size;
1281 }
1282
1283 res->filename = tdata->modules[modidx].name;
1284
1285 tdata->cache[modidx] = res;
1286
1287 return res;
1288 }
1289
1290 /* Standard function: get member at IDX. */
1291
1292 bfd *
1293 _bfd_vms_lib_get_elt_at_index (bfd *abfd, symindex symidx)
1294 {
1295 struct lib_tdata *tdata = bfd_libdata (abfd);
1296 file_ptr file_off;
1297 unsigned int modidx;
1298
1299 /* Check symidx. */
1300 if (symidx > tdata->artdata.symdef_count)
1301 return NULL;
1302 file_off = tdata->artdata.symdefs[symidx].file_offset;
1303
1304 /* Linear-scan. */
1305 for (modidx = 0; modidx < tdata->nbr_modules; modidx++)
1306 {
1307 if (tdata->modules[modidx].file_offset == file_off)
1308 break;
1309 }
1310 if (modidx >= tdata->nbr_modules)
1311 return NULL;
1312
1313 return _bfd_vms_lib_get_module (abfd, modidx);
1314 }
1315
1316 /* Elements of an imagelib are stubs. You can get the real image with this
1317 function. */
1318
1319 bfd *
1320 _bfd_vms_lib_get_imagelib_file (bfd *el)
1321 {
1322 bfd *archive = el->my_archive;
1323 const char *modname = el->filename;
1324 int modlen = strlen (modname);
1325 char *filename;
1326 int j;
1327 bfd *res;
1328
1329 /* Convert module name to lower case and append '.exe'. */
1330 filename = bfd_alloc (el, modlen + 5);
1331 if (filename == NULL)
1332 return NULL;
1333 for (j = 0; j < modlen; j++)
1334 if (ISALPHA (modname[j]))
1335 filename[j] = TOLOWER (modname[j]);
1336 else
1337 filename[j] = modname[j];
1338 memcpy (filename + modlen, ".exe", 5);
1339
1340 filename = _bfd_append_relative_path (archive, filename);
1341 if (filename == NULL)
1342 return NULL;
1343 res = bfd_openr (filename, NULL);
1344
1345 if (res == NULL)
1346 {
1347 (*_bfd_error_handler)(_("could not open shared image '%s' from '%s'"),
1348 filename, archive->filename);
1349 bfd_release (archive, filename);
1350 return NULL;
1351 }
1352
1353 /* FIXME: put it in a cache ? */
1354 return res;
1355 }
1356
1357 /* Standard function. */
1358
1359 bfd *
1360 _bfd_vms_lib_openr_next_archived_file (bfd *archive,
1361 bfd *last_file)
1362 {
1363 unsigned int idx;
1364 bfd *res;
1365
1366 if (!last_file)
1367 idx = 0;
1368 else
1369 idx = last_file->proxy_origin + 1;
1370
1371 if (idx >= bfd_libdata (archive)->nbr_modules)
1372 {
1373 bfd_set_error (bfd_error_no_more_archived_files);
1374 return NULL;
1375 }
1376
1377 res = _bfd_vms_lib_get_module (archive, idx);
1378 if (res == NULL)
1379 return res;
1380 res->proxy_origin = idx;
1381 return res;
1382 }
1383
1384 /* Standard function. Just compute the length. */
1385
1386 int
1387 _bfd_vms_lib_generic_stat_arch_elt (bfd *abfd, struct stat *st)
1388 {
1389 struct lib_tdata *tdata;
1390
1391 /* Sanity check. */
1392 if (abfd->my_archive == NULL)
1393 {
1394 bfd_set_error (bfd_error_invalid_operation);
1395 return -1;
1396 }
1397
1398 tdata = bfd_libdata (abfd->my_archive);
1399 if (tdata->type != LBR__C_TYP_IOBJ)
1400 {
1401 struct vms_lib_iovec *vec = (struct vms_lib_iovec *) abfd->iostream;
1402
1403 if (vec->file_len == (ufile_ptr)-1)
1404 {
1405 if (vms_lib_bseek (abfd, 0, SEEK_SET) != 0)
1406 return -1;
1407
1408 /* Compute length. */
1409 while (vms_lib_bread (abfd, NULL, 1 << 20) > 0)
1410 ;
1411 }
1412 st->st_size = vec->file_len;
1413 }
1414 else
1415 {
1416 st->st_size = ((struct areltdata *)abfd->arelt_data)->parsed_size;
1417 }
1418
1419 if (abfd->mtime_set)
1420 st->st_mtime = abfd->mtime;
1421 else
1422 st->st_mtime = 0;
1423 st->st_uid = 0;
1424 st->st_gid = 0;
1425 st->st_mode = 0644;
1426
1427 return 0;
1428 }
1429
1430 /* Internal representation of an index entry. */
1431
1432 struct vms_index
1433 {
1434 /* Corresponding archive member. */
1435 bfd *abfd;
1436
1437 /* Number of reference to this entry. */
1438 unsigned int ref;
1439
1440 /* Length of the key. */
1441 unsigned short namlen;
1442
1443 /* Key. */
1444 const char *name;
1445 };
1446
1447 /* Used to sort index entries. */
1448
1449 static int
1450 vms_index_cmp (const void *lv, const void *rv)
1451 {
1452 const struct vms_index *l = lv;
1453 const struct vms_index *r = rv;
1454
1455 return strcmp (l->name, r->name);
1456 }
1457
1458 /* Maximum number of index blocks level. */
1459
1460 #define MAX_LEVEL 10
1461
1462 /* Get the size of an index entry. */
1463
1464 static unsigned int
1465 get_idxlen (struct vms_index *idx)
1466 {
1467 return 7 + idx->namlen;
1468 }
1469
1470 /* Write the index. VBN is the first vbn to be used, and will contain
1471 on return the last vbn.
1472 Return TRUE on success. */
1473
1474 static bfd_boolean
1475 vms_write_index (bfd *abfd,
1476 struct vms_index *idx, unsigned int nbr, unsigned int *vbn,
1477 unsigned int *topvbn)
1478 {
1479 unsigned int i;
1480 int j;
1481 int level;
1482 struct vms_indexdef *rblk[MAX_LEVEL];
1483 struct idxblk
1484 {
1485 unsigned int vbn;
1486 unsigned short len;
1487 unsigned short lastlen;
1488 } blk[MAX_LEVEL];
1489
1490 if (nbr == 0)
1491 {
1492 if (topvbn != NULL)
1493 *topvbn = 0;
1494 return TRUE;
1495 }
1496
1497 if (abfd == NULL)
1498 {
1499 /* Sort the index the first time this function is called. */
1500 qsort (idx, nbr, sizeof (struct vms_index), vms_index_cmp);
1501 }
1502
1503 /* Allocate first index block. */
1504 level = 1;
1505 if (abfd != NULL)
1506 rblk[0] = bfd_malloc (sizeof (struct vms_indexdef));
1507 blk[0].vbn = (*vbn)++;
1508 blk[0].len = 0;
1509 blk[0].lastlen = 0;
1510
1511 for (i = 0; i < nbr; i++, idx++)
1512 {
1513 unsigned int idxlen = get_idxlen (idx);
1514 struct vms_idx *en;
1515 int flush = 0;
1516
1517 /* Check if a block might overflow. In this case we will flush this
1518 block and all the blocks below it. */
1519 for (j = 0; j < level; j++)
1520 if (blk[j].len + blk[j].lastlen + idxlen > INDEXDEF__BLKSIZ)
1521 flush = j + 1;
1522
1523 for (j = 0; j < level; j++)
1524 {
1525 if (j < flush)
1526 {
1527 /* There is not enough room to write the new entry in this
1528 block or in a parent block. */
1529
1530 if (j + 1 == level)
1531 {
1532 BFD_ASSERT (level < MAX_LEVEL);
1533
1534 /* Need to create a parent. */
1535 if (abfd != NULL)
1536 {
1537 rblk[level] = bfd_malloc (sizeof (struct vms_indexdef));
1538 bfd_putl32 (*vbn, rblk[j]->parent);
1539 }
1540 blk[level].vbn = (*vbn)++;
1541 blk[level].len = 0;
1542 blk[level].lastlen = 0;
1543
1544 level++;
1545 }
1546
1547 /* Update parent block: write the new entry. */
1548 if (abfd != NULL)
1549 {
1550 en = (struct vms_idx *)(rblk[j]->keys + blk[j].len);
1551 memcpy (rblk[j + 1]->keys + blk[j + 1].len, en,
1552 blk[j].lastlen);
1553 en = (struct vms_idx *)(rblk[j + 1]->keys + blk[j + 1].len);
1554 bfd_putl32 (blk[j].vbn, en->rfa.vbn);
1555 bfd_putl16 (RFADEF__C_INDEX, en->rfa.offset);
1556 }
1557
1558 if (j + 1 == flush)
1559 {
1560 /* And allocate it. Do it only on the block that won't be
1561 flushed (so that the parent of the parent can be
1562 updated too). */
1563 blk[j + 1].len += blk[j].lastlen;
1564 blk[j + 1].lastlen = 0;
1565 }
1566
1567 /* Write this block on the disk. */
1568 if (abfd != NULL)
1569 {
1570 bfd_putl16 (blk[j].len + blk[j].lastlen, rblk[j]->used);
1571 if (bfd_seek (abfd, (blk[j].vbn - 1) * VMS_BLOCK_SIZE,
1572 SEEK_SET) != 0)
1573 return FALSE;
1574 if (bfd_bwrite (rblk[j], sizeof (struct vms_indexdef), abfd)
1575 != sizeof (struct vms_indexdef))
1576 return FALSE;
1577 }
1578
1579 /* Reset this block. */
1580 blk[j].len = 0;
1581 blk[j].lastlen = 0;
1582 blk[j].vbn = (*vbn)++;
1583 }
1584
1585 /* Append it to the block. */
1586 if (j == 0)
1587 {
1588 blk[j].len += blk[j].lastlen;
1589
1590 if (abfd != NULL)
1591 {
1592 en = (struct vms_idx *)(rblk[j]->keys + blk[j].len);
1593 bfd_putl32 ((idx->abfd->proxy_origin / VMS_BLOCK_SIZE) + 1,
1594 en->rfa.vbn);
1595 bfd_putl16
1596 ((idx->abfd->proxy_origin % VMS_BLOCK_SIZE) + DATA__DATA,
1597 en->rfa.offset);
1598 en->keylen = idx->namlen;
1599 memcpy (en->keyname, idx->name, idx->namlen);
1600 }
1601 }
1602
1603 blk[j].lastlen = idxlen;
1604 }
1605 }
1606
1607 if (topvbn != NULL)
1608 *topvbn = blk[level - 1].vbn;
1609
1610 if (abfd == NULL)
1611 return TRUE;
1612
1613 /* Flush. */
1614 for (j = 0; j < level; j++)
1615 {
1616 if (j > 0)
1617 {
1618 /* Update parent block: write the new entry. */
1619 struct vms_idx *en;
1620 struct vms_idx *par;
1621
1622 en = (struct vms_idx *)(rblk[j - 1]->keys + blk[j - 1].len);
1623 par = (struct vms_idx *)(rblk[j]->keys + blk[j].len);
1624 memcpy (par, en, blk[j - 1].lastlen);
1625 bfd_putl32 (blk[j - 1].vbn, par->rfa.vbn);
1626 bfd_putl16 (RFADEF__C_INDEX, par->rfa.offset);
1627 }
1628
1629 /* Write this block on the disk. */
1630 bfd_putl16 (blk[j].len + blk[j].lastlen, rblk[j]->used);
1631 if (bfd_seek (abfd, (blk[j].vbn - 1) * VMS_BLOCK_SIZE,
1632 SEEK_SET) != 0)
1633 return FALSE;
1634 if (bfd_bwrite (rblk[j], sizeof (struct vms_indexdef), abfd)
1635 != sizeof (struct vms_indexdef))
1636 return FALSE;
1637
1638 free (rblk[j]);
1639 }
1640
1641 return TRUE;
1642 }
1643
1644 /* Append data to the data block DATA. Force write if PAD is true. */
1645
1646 static bfd_boolean
1647 vms_write_data_block (bfd *arch, struct vms_datadef *data, file_ptr *off,
1648 const unsigned char *buf, unsigned int len, int pad)
1649 {
1650 while (len > 0 || pad)
1651 {
1652 unsigned int doff = *off & (VMS_BLOCK_SIZE - 1);
1653 unsigned int remlen = (DATA__LENGTH - DATA__DATA) - doff;
1654 unsigned int l;
1655
1656 l = (len > remlen) ? remlen : len;
1657 memcpy (data->data + doff, buf, l);
1658 buf += l;
1659 len -= l;
1660 doff += l;
1661 *off += l;
1662
1663 if (doff == (DATA__LENGTH - DATA__DATA) || (len == 0 && pad))
1664 {
1665 data->recs = 0;
1666 data->fill_1 = 0;
1667 bfd_putl32 ((*off / VMS_BLOCK_SIZE) + 2, data->link);
1668
1669 if (bfd_bwrite (data, sizeof (*data), arch) != sizeof (*data))
1670 return FALSE;
1671
1672 *off += DATA__LENGTH - doff;
1673
1674 if (len == 0)
1675 break;
1676 }
1677 }
1678 return TRUE;
1679 }
1680
1681 /* Build the symbols index. */
1682
1683 static bfd_boolean
1684 _bfd_vms_lib_build_map (unsigned int nbr_modules,
1685 struct vms_index *modules,
1686 unsigned int *res_cnt,
1687 struct vms_index **res)
1688 {
1689 unsigned int i;
1690 asymbol **syms = NULL;
1691 long syms_max = 0;
1692 struct vms_index *map = NULL;
1693 unsigned int map_max = 1024; /* Fine initial default. */
1694 unsigned int map_count = 0;
1695
1696 map = (struct vms_index *) bfd_malloc (map_max * sizeof (struct vms_index));
1697 if (map == NULL)
1698 goto error_return;
1699
1700 /* Gather symbols. */
1701 for (i = 0; i < nbr_modules; i++)
1702 {
1703 long storage;
1704 long symcount;
1705 long src_count;
1706 bfd *current = modules[i].abfd;
1707
1708 if ((bfd_get_file_flags (current) & HAS_SYMS) == 0)
1709 continue;
1710
1711 storage = bfd_get_symtab_upper_bound (current);
1712 if (storage < 0)
1713 goto error_return;
1714
1715 if (storage != 0)
1716 {
1717 if (storage > syms_max)
1718 {
1719 if (syms_max > 0)
1720 free (syms);
1721 syms_max = storage;
1722 syms = (asymbol **) bfd_malloc (syms_max);
1723 if (syms == NULL)
1724 goto error_return;
1725 }
1726 symcount = bfd_canonicalize_symtab (current, syms);
1727 if (symcount < 0)
1728 goto error_return;
1729
1730 /* Now map over all the symbols, picking out the ones we
1731 want. */
1732 for (src_count = 0; src_count < symcount; src_count++)
1733 {
1734 flagword flags = (syms[src_count])->flags;
1735 asection *sec = syms[src_count]->section;
1736
1737 if ((flags & BSF_GLOBAL
1738 || flags & BSF_WEAK
1739 || flags & BSF_INDIRECT
1740 || bfd_is_com_section (sec))
1741 && ! bfd_is_und_section (sec))
1742 {
1743 struct vms_index *new_map;
1744
1745 /* This symbol will go into the archive header. */
1746 if (map_count == map_max)
1747 {
1748 map_max *= 2;
1749 new_map = (struct vms_index *)
1750 bfd_realloc (map, map_max * sizeof (struct vms_index));
1751 if (new_map == NULL)
1752 goto error_return;
1753 map = new_map;
1754 }
1755
1756 map[map_count].abfd = current;
1757 /* FIXME: check length. */
1758 map[map_count].namlen = strlen (syms[src_count]->name);
1759 map[map_count].name = syms[src_count]->name;
1760 map_count++;
1761 modules[i].ref++;
1762 }
1763 }
1764 }
1765 }
1766
1767 *res_cnt = map_count;
1768 *res = map;
1769 return TRUE;
1770
1771 error_return:
1772 if (syms_max > 0)
1773 free (syms);
1774 if (map != NULL)
1775 free (map);
1776 return FALSE;
1777 }
1778
1779 /* Do the hard work: write an archive on the disk. */
1780
1781 bfd_boolean
1782 _bfd_vms_lib_write_archive_contents (bfd *arch)
1783 {
1784 bfd *current;
1785 unsigned int nbr_modules;
1786 struct vms_index *modules;
1787 unsigned int nbr_symbols;
1788 struct vms_index *symbols;
1789 struct lib_tdata *tdata = bfd_libdata (arch);
1790 unsigned int i;
1791 file_ptr off;
1792 unsigned int nbr_mod_iblk;
1793 unsigned int nbr_sym_iblk;
1794 unsigned int vbn;
1795 unsigned int mod_idx_vbn;
1796 unsigned int sym_idx_vbn;
1797
1798 /* Count the number of modules (and do a first sanity check). */
1799 nbr_modules = 0;
1800 for (current = arch->archive_head;
1801 current != NULL;
1802 current = current->archive_next)
1803 {
1804 /* This check is checking the bfds for the objects we're reading
1805 from (which are usually either an object file or archive on
1806 disk), not the archive entries we're writing to. We don't
1807 actually create bfds for the archive members, we just copy
1808 them byte-wise when we write out the archive. */
1809 if (bfd_write_p (current) || !bfd_check_format (current, bfd_object))
1810 {
1811 bfd_set_error (bfd_error_invalid_operation);
1812 goto input_err;
1813 }
1814
1815 nbr_modules++;
1816 }
1817
1818 /* Build the modules list. */
1819 BFD_ASSERT (tdata->modules == NULL);
1820 modules = bfd_alloc (arch, nbr_modules * sizeof (struct vms_index));
1821 if (modules == NULL)
1822 return FALSE;
1823
1824 for (current = arch->archive_head, i = 0;
1825 current != NULL;
1826 current = current->archive_next, i++)
1827 {
1828 int nl;
1829
1830 modules[i].abfd = current;
1831 modules[i].name = vms_get_module_name (current->filename, FALSE);
1832 modules[i].ref = 1;
1833
1834 /* FIXME: silently truncate long names ? */
1835 nl = strlen (modules[i].name);
1836 modules[i].namlen = (nl > MAX_KEYLEN ? MAX_KEYLEN : nl);
1837 }
1838
1839 /* Create the module index. */
1840 vbn = 0;
1841 if (!vms_write_index (NULL, modules, nbr_modules, &vbn, NULL))
1842 return FALSE;
1843 nbr_mod_iblk = vbn;
1844
1845 /* Create symbol index. */
1846 if (!_bfd_vms_lib_build_map (nbr_modules, modules, &nbr_symbols, &symbols))
1847 return FALSE;
1848
1849 vbn = 0;
1850 if (!vms_write_index (NULL, symbols, nbr_symbols, &vbn, NULL))
1851 return FALSE;
1852 nbr_sym_iblk = vbn;
1853
1854 /* Write modules and remember their position. */
1855 off = (1 + nbr_mod_iblk + nbr_sym_iblk) * VMS_BLOCK_SIZE;
1856
1857 if (bfd_seek (arch, off, SEEK_SET) != 0)
1858 return FALSE;
1859
1860 for (i = 0; i < nbr_modules; i++)
1861 {
1862 struct vms_datadef data;
1863 unsigned char blk[VMS_BLOCK_SIZE];
1864 struct vms_mhd *mhd;
1865 unsigned int sz;
1866
1867 current = modules[i].abfd;
1868 current->proxy_origin = off;
1869
1870 bfd_putl16 (sizeof (struct vms_mhd), blk);
1871 mhd = (struct vms_mhd *)(blk + 2);
1872 memset (mhd, 0, sizeof (struct vms_mhd));
1873 mhd->lbrflag = 0;
1874 mhd->id = MHD__C_MHDID;
1875 mhd->objidlng = 4;
1876 memcpy (mhd->objid, "V1.0", 4);
1877 bfd_putl32 (modules[i].ref, mhd->refcnt);
1878 /* FIXME: datim. */
1879
1880 sz = (2 + sizeof (struct vms_mhd) + 1) & ~1;
1881 if (vms_write_data_block (arch, &data, &off, blk, sz, 0) < 0)
1882 goto input_err;
1883
1884 if (bfd_seek (current, 0, SEEK_SET) != 0)
1885 goto input_err;
1886
1887 while (1)
1888 {
1889 sz = bfd_bread (blk, sizeof (blk), current);
1890 if (sz == 0)
1891 break;
1892 if (vms_write_data_block (arch, &data, &off, blk, sz, 0) < 0)
1893 goto input_err;
1894 }
1895 if (vms_write_data_block (arch, &data, &off,
1896 eotdesc, sizeof (eotdesc), 1) < 0)
1897 goto input_err;
1898 }
1899
1900 /* Write the indexes. */
1901 vbn = 2;
1902 if (vms_write_index (arch, modules, nbr_modules, &vbn, &mod_idx_vbn) != TRUE)
1903 return FALSE;
1904 if (vms_write_index (arch, symbols, nbr_symbols, &vbn, &sym_idx_vbn) != TRUE)
1905 return FALSE;
1906
1907 /* Write libary header. */
1908 {
1909 unsigned char blk[VMS_BLOCK_SIZE];
1910 struct vms_lhd *lhd = (struct vms_lhd *)blk;
1911 struct vms_idd *idd = (struct vms_idd *)(blk + sizeof (*lhd));
1912 unsigned int idd_flags;
1913
1914 memset (blk, 0, sizeof (blk));
1915
1916 lhd->type = LBR__C_TYP_EOBJ;
1917 lhd->nindex = 2;
1918 bfd_putl32 (LHD_SANEID3, lhd->sanity);
1919 bfd_putl16 (3, lhd->majorid);
1920 bfd_putl16 (0, lhd->minorid);
1921 snprintf ((char *)lhd->lbrver + 1, sizeof (lhd->lbrver) - 1,
1922 "GNU ar %u.%u.%u",
1923 (unsigned)(BFD_VERSION / 100000000UL),
1924 (unsigned)(BFD_VERSION / 1000000UL) % 100,
1925 (unsigned)(BFD_VERSION / 10000UL) % 100);
1926 lhd->lbrver[sizeof (lhd->lbrver) - 1] = 0;
1927 lhd->lbrver[0] = strlen ((char *)lhd->lbrver + 1);
1928
1929 /* FIXME. */
1930 bfd_putl64 (0, lhd->credat);
1931 bfd_putl64 (0, lhd->updtim);
1932
1933 lhd->mhdusz = sizeof (struct vms_mhd) - MHD__C_USRDAT;
1934
1935 bfd_putl32 (nbr_modules + nbr_symbols, lhd->idxcnt);
1936 bfd_putl32 (nbr_modules, lhd->modcnt);
1937 bfd_putl32 (nbr_modules, lhd->modhdrs);
1938
1939 bfd_putl32 (vbn - 1, lhd->hipreal);
1940 bfd_putl32 (vbn - 1, lhd->hiprusd);
1941
1942 /* First index (modules name). */
1943 idd_flags = IDD__FLAGS_ASCII | IDD__FLAGS_VARLENIDX
1944 | IDD__FLAGS_NOCASECMP | IDD__FLAGS_NOCASENTR;
1945 bfd_putl16 (idd_flags, idd->flags);
1946 bfd_putl16 (MAX_KEYLEN, idd->keylen);
1947 bfd_putl16 (mod_idx_vbn, idd->vbn);
1948 idd++;
1949
1950 /* Second index (symbols name). */
1951 bfd_putl16 (idd_flags, idd->flags);
1952 bfd_putl16 (MAX_KEYLEN, idd->keylen);
1953 bfd_putl16 (sym_idx_vbn, idd->vbn);
1954 idd++;
1955
1956 if (bfd_seek (arch, 0, SEEK_SET) != 0)
1957 return FALSE;
1958 if (bfd_bwrite (blk, sizeof (blk), arch) != sizeof (blk))
1959 return FALSE;
1960 }
1961
1962 return TRUE;
1963
1964 input_err:
1965 bfd_set_error (bfd_error_on_input, current, bfd_get_error ());
1966 return FALSE;
1967 }
1968
1969 /* Add a target for text library. This costs almost nothing and is useful to
1970 read VMS library on the host. */
1971
1972 const bfd_target vms_lib_txt_vec =
1973 {
1974 "vms-libtxt", /* Name. */
1975 bfd_target_unknown_flavour,
1976 BFD_ENDIAN_UNKNOWN, /* byteorder */
1977 BFD_ENDIAN_UNKNOWN, /* header_byteorder */
1978 0, /* Object flags. */
1979 0, /* Sect flags. */
1980 0, /* symbol_leading_char. */
1981 ' ', /* ar_pad_char. */
1982 15, /* ar_max_namelen. */
1983 bfd_getl64, bfd_getl_signed_64, bfd_putl64,
1984 bfd_getl32, bfd_getl_signed_32, bfd_putl32,
1985 bfd_getl16, bfd_getl_signed_16, bfd_putl16,
1986 bfd_getl64, bfd_getl_signed_64, bfd_putl64,
1987 bfd_getl32, bfd_getl_signed_32, bfd_putl32,
1988 bfd_getl16, bfd_getl_signed_16, bfd_putl16,
1989
1990 {_bfd_dummy_target, _bfd_dummy_target, /* bfd_check_format. */
1991 _bfd_vms_lib_txt_archive_p, _bfd_dummy_target},
1992 {bfd_false, bfd_false, bfd_false, bfd_false}, /* bfd_set_format. */
1993 {bfd_false, bfd_false, bfd_false, bfd_false}, /* bfd_write_contents. */
1994
1995 BFD_JUMP_TABLE_GENERIC (_bfd_generic),
1996 BFD_JUMP_TABLE_COPY (_bfd_generic),
1997 BFD_JUMP_TABLE_CORE (_bfd_nocore),
1998 BFD_JUMP_TABLE_ARCHIVE (_bfd_vms_lib),
1999 BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols),
2000 BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
2001 BFD_JUMP_TABLE_WRITE (_bfd_nowrite),
2002 BFD_JUMP_TABLE_LINK (_bfd_nolink),
2003 BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
2004
2005 NULL,
2006
2007 (PTR) 0
2008 };
This page took 0.112024 seconds and 5 git commands to generate.