bfd/
[platform/upstream/binutils.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 int off;
556           unsigned char *data = (unsigned char *)sbm;
557           unsigned char *buf1;
558           unsigned int l, j;
559
560           sbm_sz = bfd_getl16 (sbm->size);
561           sbm_off += sbm_sz;
562           BFD_ASSERT (sbm_off <= reclen);
563
564           sbmdesc->min_char = sbm->min_char;
565           BFD_ASSERT (sbmdesc->min_char == 0);
566           sbmdesc->max_char = sbm->max_char;
567           sbm_len = sbmdesc->max_char - sbmdesc->min_char + 1;
568           l = (2 * sbm_len + 7) / 8;
569           BFD_ASSERT
570             (sbm_sz >= sizeof (struct vms_dcxsbm) + l + 3 * sbm_len
571              || (tdata->nbr_dcxsbm == 1
572                  && sbm_sz >= sizeof (struct vms_dcxsbm) + l + sbm_len));
573           sbmdesc->flags = (unsigned char *)bfd_alloc (abfd, l);
574           memcpy (sbmdesc->flags, data + bfd_getl16 (sbm->flags), l);
575           sbmdesc->nodes = (unsigned char *)bfd_alloc (abfd, 2 * sbm_len);
576           memcpy (sbmdesc->nodes, data + bfd_getl16 (sbm->nodes), 2 * sbm_len);
577           off = bfd_getl16 (sbm->next);
578           if (off != 0)
579             {
580               sbmdesc->next = (unsigned short *)bfd_alloc
581                 (abfd, sbm_len * sizeof (unsigned short));
582               buf1 = data + off;
583               for (j = 0; j < sbm_len; j++)
584                 sbmdesc->next[j] = bfd_getl16 (buf1 + j * 2);
585             }
586           else
587             {
588               BFD_ASSERT (tdata->nbr_dcxsbm == 1);
589               sbmdesc->next = NULL;
590             }
591         }
592       free (buf);
593     }
594   else
595     {
596       tdata->nbr_dcxsbm = 0;
597     }
598
599   /* The map is always present.  Also mark shared image library.  */
600   abfd->has_armap = TRUE;
601   if (tdata->type == LBR__C_TYP_ESHSTB || tdata->type == LBR__C_TYP_ISHSTB)
602     abfd->is_thin_archive = TRUE;
603
604   return abfd->xvec;
605
606  err:
607   bfd_release (abfd, tdata);
608   abfd->tdata.any = (void *)tdata_hold;;
609   return NULL;
610 }
611
612 /* Standard function for alpha libraries.  */
613
614 const bfd_target *
615 _bfd_vms_lib_alpha_archive_p (bfd *abfd)
616 {
617   return _bfd_vms_lib_archive_p (abfd, vms_lib_alpha);
618 }
619
620 /* Standard function for text libraries.  */
621
622 static const bfd_target *
623 _bfd_vms_lib_txt_archive_p (bfd *abfd)
624 {
625   return _bfd_vms_lib_archive_p (abfd, vms_lib_txt);
626 }
627
628 /* Standard bfd function.  */
629
630 bfd_boolean
631 _bfd_vms_lib_mkarchive (bfd *abfd)
632 {
633   struct lib_tdata *tdata;
634
635   tdata = (struct lib_tdata *) bfd_zalloc (abfd, sizeof (struct lib_tdata));
636   if (tdata == NULL)
637     return FALSE;
638
639   abfd->tdata.any = (void *)tdata;
640   tdata->ver = 3;
641   tdata->mhd_size = sizeof (struct vms_mhd);
642   tdata->type = LBR__C_TYP_EOBJ;
643
644   tdata->nbr_modules = 0;
645   tdata->artdata.symdef_count = 0;
646   tdata->modules = NULL;
647   tdata->artdata.symdefs = NULL;
648   tdata->cache = NULL;
649
650   return TRUE;
651 }
652
653 /* Find NAME in the symbol index.  Return the index.  */
654
655 symindex
656 _bfd_vms_lib_find_symbol (bfd *abfd, const char *name)
657 {
658   struct lib_tdata *tdata = bfd_libdata (abfd);
659   carsym *syms = tdata->artdata.symdefs;
660   int lo, hi;
661
662   /* Open-coded binary search for speed.  */
663   lo = 0;
664   hi = tdata->artdata.symdef_count - 1;
665
666   while (lo <= hi)
667     {
668       int mid = lo + (hi - lo) / 2;
669       int diff;
670
671       diff = (char)(name[0] - syms[mid].name[0]);
672       if (diff == 0)
673         diff = strcmp (name, syms[mid].name);
674       if (diff == 0)
675         return mid;
676       else if (diff < 0)
677         hi = mid - 1;
678       else
679         lo = mid + 1;
680     }
681   return BFD_NO_MORE_SYMBOLS;
682 }
683
684 /* IO vector for archive member.  Need that because members are not linearly
685    stored in archives.  */
686
687 struct vms_lib_iovec
688 {
689   /* Current offset.  */
690   ufile_ptr where;
691
692   /* Length of the module, when known.  */
693   ufile_ptr file_len;
694
695   /* Current position in the record from bfd_bread point of view (ie, after
696      decompression).  0 means that no data byte have been read, -2 and -1
697      are reserved for the length word.  */
698   int rec_pos;
699 #define REC_POS_NL   -4
700 #define REC_POS_PAD  -3
701 #define REC_POS_LEN0 -2
702 #define REC_POS_LEN1 -1
703
704   /* Record length.  */
705   unsigned short rec_len;
706   /* Number of bytes to read in the current record.  */
707   unsigned short rec_rem;
708   /* Offset of the next block.  */
709   file_ptr next_block;
710   /* Current *data* offset in the data block.  */
711   unsigned short blk_off;
712
713   /* Offset of the first block.  Extracted from the index.  */
714   file_ptr first_block;
715
716   /* Initial next_block.  Extracted when the MHD is read.  */
717   file_ptr init_next_block;
718   /* Initial blk_off, once the MHD is read.  */
719   unsigned short init_blk_off;
720
721   /* Used to store any 3 byte record, which could be the EOF pattern.  */
722   unsigned char pattern[4];
723
724   /* DCX.  */
725   struct dcxsbm_desc *dcxsbms;
726   /* Current submap.  */
727   struct dcxsbm_desc *dcx_sbm;
728   /* Current offset in the submap.  */
729   unsigned int dcx_offset;
730   int dcx_pos;
731
732   /* Compressed buffer.  */
733   unsigned char *dcx_buf;
734   /* Size of the buffer.  Used to resize.  */
735   unsigned int dcx_max;
736   /* Number of valid bytes in the buffer.  */
737   unsigned int dcx_rlen;
738 };
739
740 /* Return the current position.  */
741
742 static file_ptr
743 vms_lib_btell (struct bfd *abfd)
744 {
745   struct vms_lib_iovec *vec = (struct vms_lib_iovec *) abfd->iostream;
746   return vec->where;
747 }
748
749 /* Read the header of the next data block if all bytes of the current block
750    have been read.  */
751
752 static bfd_boolean
753 vms_lib_read_block (struct bfd *abfd)
754 {
755   struct vms_lib_iovec *vec = (struct vms_lib_iovec *) abfd->iostream;
756
757   if (vec->blk_off == DATA__LENGTH)
758     {
759       unsigned char hdr[DATA__DATA];
760
761       /* Read next block.  */
762       if (bfd_seek (abfd->my_archive, vec->next_block, SEEK_SET) != 0)
763         return FALSE;
764       if (bfd_bread (hdr, sizeof (hdr), abfd->my_archive) != sizeof (hdr))
765         return FALSE;
766       vec->next_block = (bfd_getl32 (hdr + 2) - 1) * VMS_BLOCK_SIZE;
767       vec->blk_off = sizeof (hdr);
768     }
769   return TRUE;
770 }
771
772 /* Read NBYTES from ABFD into BUF if not NULL.  If BUF is NULL, bytes are
773    not stored.  Read linearly from the library, but handle blocks.  This
774    function does not handle records nor EOF.  */
775
776 static file_ptr
777 vms_lib_bread_raw (struct bfd *abfd, void *buf, file_ptr nbytes)
778 {
779   struct vms_lib_iovec *vec = (struct vms_lib_iovec *) abfd->iostream;
780   file_ptr res;
781
782   res = 0;
783   while (nbytes > 0)
784     {
785       unsigned int l;
786
787       /* Be sure the current data block is read.  */
788       if (!vms_lib_read_block (abfd))
789         return -1;
790
791       /* Do not read past the data block, do not read more than requested.  */
792       l = DATA__LENGTH - vec->blk_off;
793       if (l > nbytes)
794         l = nbytes;
795       if (l == 0)
796         return 0;
797       if (buf != NULL)
798         {
799           /* Really read into BUF.  */
800           if (bfd_bread (buf, l, abfd->my_archive) != l)
801             return -1;
802         }
803       else
804         {
805           /* Make as if we are reading.  */
806           if (bfd_seek (abfd->my_archive, l, SEEK_CUR) != 0)
807             return -1;
808         }
809
810       if (buf != NULL)
811         buf += l;
812       vec->blk_off += l;
813       nbytes -= l;
814       res += l;
815     }
816   return res;
817 }
818
819 /* Decompress NBYTES from VEC.  Store the bytes into BUF if not NULL.  */
820
821 static file_ptr
822 vms_lib_dcx (struct vms_lib_iovec *vec, unsigned char *buf, file_ptr nbytes)
823 {
824   struct dcxsbm_desc *sbm;
825   unsigned int i;
826   unsigned int offset;
827   unsigned int j;
828   file_ptr res = 0;
829
830   /* The loop below expect to deliver at least one byte.  */
831   if (nbytes == 0)
832     return 0;
833
834   /* Get the current state.  */
835   sbm = vec->dcx_sbm;
836   offset = vec->dcx_offset;
837   j = vec->dcx_pos & 7;
838
839   for (i = vec->dcx_pos >> 3; i < vec->dcx_rlen; i++)
840     {
841       unsigned char b = vec->dcx_buf[i];
842
843       for (; j < 8; j++)
844         {
845           if (b & (1 << j))
846             offset++;
847           if (!(sbm->flags[offset >> 3] & (1 << (offset & 7))))
848             {
849               unsigned int n_offset = sbm->nodes[offset];
850               if (n_offset == 0)
851                 {
852                   /* End of buffer.  Stay where we are.  */
853                   vec->dcx_pos = (i << 3) + j;
854                   if (b & (1 << j))
855                     offset--;
856                   vec->dcx_offset = offset;
857                   vec->dcx_sbm = sbm;
858                   return res;
859                 }
860               offset = 2 * n_offset;
861             }
862           else
863             {
864               unsigned char v = sbm->nodes[offset];
865
866               if (sbm->next != NULL)
867                 sbm = vec->dcxsbms + sbm->next[v];
868               offset = 0;
869               res++;
870
871               if (buf)
872                 {
873                   *buf++ = v;
874                   nbytes--;
875
876                   if (nbytes == 0)
877                     {
878                       vec->dcx_pos = (i << 3) + j + 1;
879                       vec->dcx_offset = offset;
880                       vec->dcx_sbm = sbm;
881
882                       return res;
883                     }
884                 }
885             }
886         }
887       j = 0;
888     }
889   return -1;
890 }
891
892 /* Standard IOVEC function.  */
893
894 static file_ptr
895 vms_lib_bread (struct bfd *abfd, void *buf, file_ptr nbytes)
896 {
897   struct vms_lib_iovec *vec = (struct vms_lib_iovec *) abfd->iostream;
898   file_ptr res;
899   file_ptr chunk;
900
901   /* Do not read past the end.  */
902   if (vec->where >= vec->file_len)
903     return 0;
904
905   res = 0;
906   while (nbytes > 0)
907     {
908       if (vec->rec_rem == 0)
909         {
910           unsigned char blen[2];
911
912           /* Read record length.  */
913           if (vms_lib_bread_raw (abfd, &blen, sizeof (blen)) != sizeof (blen))
914             return -1;
915           vec->rec_len = bfd_getl16 (blen);
916           if (bfd_libdata (abfd->my_archive)->kind == vms_lib_txt)
917             {
918               /* Discard record size and align byte.  */
919               vec->rec_pos = 0;
920               vec->rec_rem = vec->rec_len;
921             }
922           else
923             {
924               /* Prepend record size.  */
925               vec->rec_pos = REC_POS_LEN0;
926               vec->rec_rem = (vec->rec_len + 1) & ~1;   /* With align byte.  */
927             }
928           if (vec->rec_len == 3)
929             {
930               /* Possibly end of file.  Check the pattern.  */
931               if (vms_lib_bread_raw (abfd, vec->pattern, 4) != 4)
932                 return -1;
933               if (!memcmp (vec->pattern, eotdesc + 2, 3))
934                 {
935                   /* This is really an EOF.  */
936                   vec->where += res;
937                   vec->file_len = vec->where;
938                   return res;
939                 }
940             }
941
942           if (vec->dcxsbms != NULL)
943             {
944               /* This is a compressed member.  */
945               unsigned int len;
946               file_ptr elen;
947
948               /* Be sure there is enough room for the expansion.  */
949               len = (vec->rec_len + 1) & ~1;
950               if (len > vec->dcx_max)
951                 {
952                   while (len > vec->dcx_max)
953                     vec->dcx_max *= 2;
954                   vec->dcx_buf = bfd_alloc (abfd, vec->dcx_max);
955                   if (vec->dcx_buf == NULL)
956                     return -1;
957                 }
958
959               /* Read the compressed record.  */
960               vec->dcx_rlen = len;
961               if (vec->rec_len == 3)
962                 {
963                   /* Already read.  */
964                   memcpy (vec->dcx_buf, vec->pattern, 3);
965                 }
966               else
967                 {
968                   elen = vms_lib_bread_raw (abfd, vec->dcx_buf, len);
969                   if (elen != len)
970                     return -1;
971                 }
972
973               /* Dummy expansion to get the expanded length.  */
974               vec->dcx_offset = 0;
975               vec->dcx_sbm = vec->dcxsbms;
976               vec->dcx_pos = 0;
977               elen = vms_lib_dcx (vec, NULL, 0x10000);
978               if (elen < 0)
979                 return -1;
980               vec->rec_len = elen;
981               vec->rec_rem = elen;
982
983               /* Reset the state.  */
984               vec->dcx_offset = 0;
985               vec->dcx_sbm = vec->dcxsbms;
986               vec->dcx_pos = 0;
987             }
988         }
989       if (vec->rec_pos < 0)
990         {
991           unsigned char c;
992           switch (vec->rec_pos)
993             {
994             case REC_POS_LEN0:
995               c = vec->rec_len & 0xff;
996               vec->rec_pos = REC_POS_LEN1;
997               break;
998             case REC_POS_LEN1:
999               c = (vec->rec_len >> 8) & 0xff;
1000               vec->rec_pos = 0;
1001               break;
1002             case REC_POS_PAD:
1003               c = 0;
1004               vec->rec_rem = 0;
1005               break;
1006             case REC_POS_NL:
1007               c = '\n';
1008               vec->rec_rem = 0;
1009               break;
1010             default:
1011               abort ();
1012             }
1013           if (buf != NULL)
1014             {
1015               *(unsigned char *)buf = c;
1016               buf++;
1017             }
1018           nbytes--;
1019           res++;
1020           continue;
1021         }
1022
1023       if (nbytes > vec->rec_rem)
1024         chunk = vec->rec_rem;
1025       else
1026         chunk = nbytes;
1027
1028       if (vec->dcxsbms != NULL)
1029         {
1030           /* Optimize the stat() case: no need to decompress again as we
1031              know the length.  */
1032           if (!(buf == NULL && chunk == vec->rec_rem))
1033             chunk = vms_lib_dcx (vec, buf, chunk);
1034         }
1035       else
1036         {
1037           if (vec->rec_len == 3)
1038             {
1039               if (buf != NULL)
1040                 memcpy (buf, vec->pattern + vec->rec_pos, chunk);
1041             }
1042           else
1043             chunk = vms_lib_bread_raw (abfd, buf, chunk);
1044         }
1045       if (chunk < 0)
1046         return -1;
1047       res += chunk;
1048       if (buf != NULL)
1049         buf += chunk;
1050       nbytes -= chunk;
1051       vec->rec_pos += chunk;
1052       vec->rec_rem -= chunk;
1053
1054       if (vec->rec_rem == 0)
1055         {
1056           /* End of record reached.  */
1057           if (bfd_libdata (abfd->my_archive)->kind == vms_lib_txt)
1058             {
1059               if ((vec->rec_len & 1) == 1
1060                   && vec->rec_len != 3
1061                   && vec->dcxsbms == NULL)
1062                 {
1063                   /* Eat the pad byte.  */
1064                   unsigned char pad;
1065                   if (vms_lib_bread_raw (abfd, &pad, 1) != 1)
1066                     return -1;
1067                 }
1068               vec->rec_pos = REC_POS_NL;
1069               vec->rec_rem = 1;
1070             }
1071           else
1072             {
1073               if ((vec->rec_len & 1) == 1 && vec->dcxsbms != NULL)
1074                 {
1075                   vec->rec_pos = REC_POS_PAD;
1076                   vec->rec_rem = 1;
1077                 }
1078             }
1079         }
1080     }
1081   vec->where += res;
1082   return res;
1083 }
1084
1085 /* Standard function, but we currently only handle the rewind case.  */
1086
1087 static int
1088 vms_lib_bseek (struct bfd *abfd, file_ptr offset, int whence)
1089 {
1090   struct vms_lib_iovec *vec = (struct vms_lib_iovec *) abfd->iostream;
1091
1092   if (whence == SEEK_SET && offset == 0)
1093     {
1094       vec->where = 0;
1095       vec->rec_rem = 0;
1096       vec->dcx_pos = -1;
1097       vec->blk_off = vec->init_blk_off;
1098       vec->next_block = vec->init_next_block;
1099
1100       if (bfd_seek (abfd->my_archive, vec->first_block, SEEK_SET) != 0)
1101         return -1;
1102     }
1103   else
1104     abort ();
1105   return 0;
1106 }
1107
1108 static file_ptr
1109 vms_lib_bwrite (struct bfd *abfd ATTRIBUTE_UNUSED,
1110               const void *where ATTRIBUTE_UNUSED,
1111               file_ptr nbytes ATTRIBUTE_UNUSED)
1112 {
1113   return -1;
1114 }
1115
1116 static int
1117 vms_lib_bclose (struct bfd *abfd)
1118 {
1119   abfd->iostream = NULL;
1120   return 0;
1121 }
1122
1123 static int
1124 vms_lib_bflush (struct bfd *abfd ATTRIBUTE_UNUSED)
1125 {
1126   return 0;
1127 }
1128
1129 static int
1130 vms_lib_bstat (struct bfd *abfd ATTRIBUTE_UNUSED,
1131                struct stat *sb ATTRIBUTE_UNUSED)
1132 {
1133   /* Not supported.  */
1134   return 0;
1135 }
1136
1137 static void *
1138 vms_lib_bmmap (struct bfd *abfd ATTRIBUTE_UNUSED,
1139               void *addr ATTRIBUTE_UNUSED,
1140               bfd_size_type len ATTRIBUTE_UNUSED,
1141               int prot ATTRIBUTE_UNUSED,
1142               int flags ATTRIBUTE_UNUSED,
1143               file_ptr offset ATTRIBUTE_UNUSED)
1144 {
1145   return (void *) -1;
1146 }
1147
1148 static const struct bfd_iovec vms_lib_iovec = {
1149   &vms_lib_bread, &vms_lib_bwrite, &vms_lib_btell, &vms_lib_bseek,
1150   &vms_lib_bclose, &vms_lib_bflush, &vms_lib_bstat, &vms_lib_bmmap
1151 };
1152
1153 /* Open a library module.  FILEPOS is the position of the module header.  */
1154
1155 static bfd_boolean
1156 vms_lib_bopen (bfd *el, file_ptr filepos)
1157 {
1158   struct vms_lib_iovec *vec;
1159   char buf[256];
1160   struct vms_mhd *mhd;
1161   struct lib_tdata *tdata = bfd_libdata (el->my_archive);
1162   unsigned int len;
1163
1164   /* Allocate and initialized the iovec.  */
1165   vec = bfd_zalloc (el, sizeof (*vec));
1166   if (vec == NULL)
1167     return FALSE;
1168
1169   el->iostream = vec;
1170   el->iovec = &vms_lib_iovec;
1171
1172   /* File length is not known.  */
1173   vec->file_len = -1;
1174
1175   /* Read the first data block.  */
1176   vec->next_block = filepos & ~(VMS_BLOCK_SIZE - 1);
1177   vec->blk_off = DATA__LENGTH;
1178   if (!vms_lib_read_block (el))
1179     return FALSE;
1180
1181   /* Prepare to read the first record.  */
1182   vec->blk_off = filepos & (VMS_BLOCK_SIZE - 1);
1183   vec->rec_rem = 0;
1184   if (bfd_seek (el->my_archive, filepos, SEEK_SET) != 0)
1185     return FALSE;
1186
1187   /* Read Record length + MHD + align byte.  */
1188   len = tdata->mhd_size;
1189   if (vms_lib_bread_raw (el, buf, 2) != 2)
1190     return FALSE;
1191   if (bfd_getl16 (buf) != len)
1192     return FALSE;
1193   len = (len + 1) & ~1;
1194   BFD_ASSERT (len <= sizeof (buf));
1195   if (vms_lib_bread_raw (el, buf, len) != len)
1196     return FALSE;
1197
1198   /* Get info from mhd.  */
1199   mhd = (struct vms_mhd *)buf;
1200   /* Check id.  */
1201   if (mhd->id != MHD__C_MHDID)
1202     return FALSE;
1203   if (len >= sizeof (struct vms_mhd))
1204     el->selective_search = (mhd->objstat & MHD__M_SELSRC) ? 1 : 0;
1205   el->mtime = vms_rawtime_to_time_t (mhd->datim);
1206   el->mtime_set = TRUE;
1207
1208   /* Reinit the iovec so that seek() will point to the first record after
1209      the mhd.  */
1210   vec->where = 0;
1211   vec->init_blk_off = vec->blk_off;
1212   vec->init_next_block = vec->next_block;
1213   vec->first_block = bfd_tell (el->my_archive);
1214   vec->dcxsbms = bfd_libdata (el->my_archive)->dcxsbm;
1215
1216   if (vec->dcxsbms != NULL)
1217     {
1218       /* Handle DCX.  */
1219       vec->dcx_max = 10 * 1024;
1220       vec->dcx_buf = bfd_alloc (el, vec->dcx_max);
1221       vec->dcx_pos = -1;
1222       if (vec->dcx_buf == NULL)
1223         return -1;
1224     }
1225   return TRUE;
1226 }
1227
1228 /* Get member MODIDX.  Return NULL in case of error.  */
1229
1230 static bfd *
1231 _bfd_vms_lib_get_module (bfd *abfd, unsigned int modidx)
1232 {
1233   struct lib_tdata *tdata = bfd_libdata (abfd);
1234   bfd *res;
1235   file_ptr file_off;
1236
1237   /* Sanity check.  */
1238   if (modidx >= tdata->nbr_modules)
1239     return NULL;
1240
1241   /* Already loaded.  */
1242   if (tdata->cache[modidx])
1243     return tdata->cache[modidx];
1244
1245   /* Build it.  */
1246   file_off = tdata->modules[modidx].file_offset;
1247   if (tdata->type != LBR__C_TYP_IOBJ)
1248     {
1249       res = _bfd_create_empty_archive_element_shell (abfd);
1250       if (res == NULL)
1251         return NULL;
1252
1253       /* Special reader to deal with data blocks.  */
1254       if (!vms_lib_bopen (res, file_off))
1255         return NULL;
1256     }
1257   else
1258     {
1259       char buf[256];
1260       struct vms_mhd *mhd;
1261       struct areltdata *arelt;
1262
1263       /* Sanity check.  The MHD must be big enough to contain module size.  */
1264       if (tdata->mhd_size < offsetof (struct vms_mhd, modsize) + 4)
1265         return NULL;
1266
1267       /* Read the MHD now.  */
1268       if (bfd_seek (abfd, file_off, SEEK_SET) != 0)
1269         return NULL;
1270       if (bfd_bread (buf, tdata->mhd_size, abfd) != tdata->mhd_size)
1271         return NULL;
1272
1273       res = _bfd_create_empty_archive_element_shell (abfd);
1274       if (res == NULL)
1275         return NULL;
1276       arelt = bfd_zalloc (res, sizeof (*arelt));
1277       if (arelt == NULL)
1278         return NULL;
1279       res->arelt_data = arelt;
1280
1281       /* Get info from mhd.  */
1282       mhd = (struct vms_mhd *)buf;
1283       if (mhd->id != MHD__C_MHDID)
1284         return NULL;
1285       if (tdata->mhd_size >= offsetof (struct vms_mhd, objstat) + 1)
1286         res->selective_search = (mhd->objstat & MHD__M_SELSRC) ? 1 : 0;
1287       res->mtime = vms_rawtime_to_time_t (mhd->datim);
1288       res->mtime_set = TRUE;
1289
1290       arelt->parsed_size = bfd_getl32 (mhd->modsize);
1291
1292       /* No need for a special reader as members are stored linearly.
1293          Just skip the MHD.  */
1294       res->origin = file_off + tdata->mhd_size;
1295     }
1296
1297   res->filename = tdata->modules[modidx].name;
1298
1299   tdata->cache[modidx] = res;
1300
1301   return res;
1302 }
1303
1304 /* Standard function: get member at IDX.  */
1305
1306 bfd *
1307 _bfd_vms_lib_get_elt_at_index (bfd *abfd, symindex symidx)
1308 {
1309   struct lib_tdata *tdata = bfd_libdata (abfd);
1310   file_ptr file_off;
1311   unsigned int modidx;
1312
1313   /* Check symidx.  */
1314   if (symidx > tdata->artdata.symdef_count)
1315     return NULL;
1316   file_off = tdata->artdata.symdefs[symidx].file_offset;
1317
1318   /* Linear-scan.  */
1319   for (modidx = 0; modidx < tdata->nbr_modules; modidx++)
1320     {
1321       if (tdata->modules[modidx].file_offset == file_off)
1322         break;
1323     }
1324   if (modidx >= tdata->nbr_modules)
1325     return NULL;
1326
1327   return _bfd_vms_lib_get_module (abfd, modidx);
1328 }
1329
1330 /* Elements of an imagelib are stubs.  You can get the real image with this
1331    function.  */
1332
1333 bfd *
1334 _bfd_vms_lib_get_imagelib_file (bfd *el)
1335 {
1336   bfd *archive = el->my_archive;
1337   const char *modname = el->filename;
1338   int modlen = strlen (modname);
1339   char *filename;
1340   int j;
1341   bfd *res;
1342
1343   /* Convert module name to lower case and append '.exe'.  */
1344   filename = bfd_alloc (el, modlen + 5);
1345   if (filename == NULL)
1346     return NULL;
1347   for (j = 0; j < modlen; j++)
1348     if (ISALPHA (modname[j]))
1349       filename[j] = TOLOWER (modname[j]);
1350     else
1351       filename[j] = modname[j];
1352   memcpy (filename + modlen, ".exe", 5);
1353
1354   filename = _bfd_append_relative_path (archive, filename);
1355   if (filename == NULL)
1356     return NULL;
1357   res = bfd_openr (filename, NULL);
1358
1359   if (res == NULL)
1360     {
1361       (*_bfd_error_handler)(_("could not open shared image '%s' from '%s'"),
1362                             filename, archive->filename);
1363       bfd_release (archive, filename);
1364       return NULL;
1365     }
1366
1367   /* FIXME: put it in a cache ?  */
1368   return res;
1369 }
1370
1371 /* Standard function.  */
1372
1373 bfd *
1374 _bfd_vms_lib_openr_next_archived_file (bfd *archive,
1375                                        bfd *last_file)
1376 {
1377   unsigned int idx;
1378   bfd *res;
1379
1380   if (!last_file)
1381     idx = 0;
1382   else
1383     idx = last_file->proxy_origin + 1;
1384
1385   if (idx >= bfd_libdata (archive)->nbr_modules)
1386     {
1387       bfd_set_error (bfd_error_no_more_archived_files);
1388       return NULL;
1389     }
1390
1391   res = _bfd_vms_lib_get_module (archive, idx);
1392   if (res == NULL)
1393     return res;
1394   res->proxy_origin = idx;
1395   return res;
1396 }
1397
1398 /* Standard function.  Just compute the length.  */
1399
1400 int
1401 _bfd_vms_lib_generic_stat_arch_elt (bfd *abfd, struct stat *st)
1402 {
1403   struct lib_tdata *tdata;
1404
1405   /* Sanity check.  */
1406   if (abfd->my_archive == NULL)
1407     {
1408       bfd_set_error (bfd_error_invalid_operation);
1409       return -1;
1410     }
1411
1412   tdata = bfd_libdata (abfd->my_archive);
1413   if (tdata->type != LBR__C_TYP_IOBJ)
1414     {
1415       struct vms_lib_iovec *vec = (struct vms_lib_iovec *) abfd->iostream;
1416
1417       if (vec->file_len == (ufile_ptr)-1)
1418         {
1419           if (vms_lib_bseek (abfd, 0, SEEK_SET) != 0)
1420             return -1;
1421
1422           /* Compute length.  */
1423           while (vms_lib_bread (abfd, NULL, 1 << 20) > 0)
1424             ;
1425         }
1426       st->st_size = vec->file_len;
1427     }
1428   else
1429     {
1430       st->st_size = ((struct areltdata *)abfd->arelt_data)->parsed_size;
1431     }
1432
1433   if (abfd->mtime_set)
1434     st->st_mtime = abfd->mtime;
1435   else
1436     st->st_mtime = 0;
1437   st->st_uid = 0;
1438   st->st_gid = 0;
1439   st->st_mode = 0644;
1440
1441   return 0;
1442 }
1443
1444 /* Internal representation of an index entry.  */
1445
1446 struct vms_index
1447 {
1448   /* Corresponding archive member.  */
1449   bfd *abfd;
1450
1451   /* Number of reference to this entry.  */
1452   unsigned int ref;
1453
1454   /* Length of the key.  */
1455   unsigned short namlen;
1456
1457   /* Key.  */
1458   const char *name;
1459 };
1460
1461 /* Used to sort index entries.  */
1462
1463 static int
1464 vms_index_cmp (const void *lv, const void *rv)
1465 {
1466   const struct vms_index *l = lv;
1467   const struct vms_index *r = rv;
1468
1469   return strcmp (l->name, r->name);
1470 }
1471
1472 /* Maximum number of index blocks level.  */
1473
1474 #define MAX_LEVEL 10
1475
1476 /* Get the size of an index entry.  */
1477
1478 static unsigned int
1479 get_idxlen (struct vms_index *idx)
1480 {
1481   return 7 + idx->namlen;
1482 }
1483
1484 /* Write the index.  VBN is the first vbn to be used, and will contain
1485    on return the last vbn.
1486    Return TRUE on success.  */
1487
1488 static bfd_boolean
1489 vms_write_index (bfd *abfd,
1490                  struct vms_index *idx, unsigned int nbr, unsigned int *vbn,
1491                  unsigned int *topvbn)
1492 {
1493   unsigned int i;
1494   int j;
1495   int level;
1496   struct vms_indexdef *rblk[MAX_LEVEL];
1497   struct idxblk
1498   {
1499     unsigned int vbn;
1500     unsigned short len;
1501     unsigned short lastlen;
1502   } blk[MAX_LEVEL];
1503
1504   if (nbr == 0)
1505     {
1506       if (topvbn != NULL)
1507         *topvbn = 0;
1508       return TRUE;
1509     }
1510
1511   if (abfd == NULL)
1512     {
1513       /* Sort the index the first time this function is called.  */
1514       qsort (idx, nbr, sizeof (struct vms_index), vms_index_cmp);
1515     }
1516
1517   /* Allocate first index block.  */
1518   level = 1;
1519   if (abfd != NULL)
1520     rblk[0] = bfd_malloc (sizeof (struct vms_indexdef));
1521   blk[0].vbn = (*vbn)++;
1522   blk[0].len = 0;
1523   blk[0].lastlen = 0;
1524
1525   for (i = 0; i < nbr; i++, idx++)
1526     {
1527       unsigned int idxlen = get_idxlen (idx);
1528       struct vms_idx *en;
1529       int flush = 0;
1530
1531       /* Check if a block might overflow.  In this case we will flush this
1532          block and all the blocks below it.  */
1533       for (j = 0; j < level; j++)
1534         if (blk[j].len + blk[j].lastlen + idxlen > INDEXDEF__BLKSIZ)
1535           flush = j + 1;
1536
1537       for (j = 0; j < level; j++)
1538         {
1539           if (j < flush)
1540             {
1541               /* There is not enough room to write the new entry in this
1542                  block or in a parent block.  */
1543
1544               if (j + 1 == level)
1545                 {
1546                   BFD_ASSERT (level < MAX_LEVEL);
1547
1548                   /* Need to create a parent.  */
1549                   if (abfd != NULL)
1550                     {
1551                       rblk[level] = bfd_malloc (sizeof (struct vms_indexdef));
1552                       bfd_putl32 (*vbn, rblk[j]->parent);
1553                     }
1554                   blk[level].vbn = (*vbn)++;
1555                   blk[level].len = 0;
1556                   blk[level].lastlen = 0;
1557
1558                   level++;
1559                 }
1560
1561               /* Update parent block: write the new entry.  */
1562               if (abfd != NULL)
1563                 {
1564                   en = (struct vms_idx *)(rblk[j]->keys + blk[j].len);
1565                   memcpy (rblk[j + 1]->keys + blk[j + 1].len, en,
1566                           blk[j].lastlen);
1567                   en = (struct vms_idx *)(rblk[j + 1]->keys + blk[j + 1].len);
1568                   bfd_putl32 (blk[j].vbn, en->rfa.vbn);
1569                   bfd_putl16 (RFADEF__C_INDEX, en->rfa.offset);
1570                 }
1571
1572               if (j + 1 == flush)
1573                 {
1574                   /* And allocate it.  Do it only on the block that won't be
1575                      flushed (so that the parent of the parent can be
1576                      updated too).  */
1577                   blk[j + 1].len += blk[j].lastlen;
1578                   blk[j + 1].lastlen = 0;
1579                 }
1580
1581               /* Write this block on the disk.  */
1582               if (abfd != NULL)
1583                 {
1584                   bfd_putl16 (blk[j].len + blk[j].lastlen, rblk[j]->used);
1585                   if (bfd_seek (abfd, (blk[j].vbn - 1) * VMS_BLOCK_SIZE,
1586                                 SEEK_SET) != 0)
1587                     return FALSE;
1588                   if (bfd_bwrite (rblk[j], sizeof (struct vms_indexdef), abfd)
1589                       != sizeof (struct vms_indexdef))
1590                     return FALSE;
1591                 }
1592
1593               /* Reset this block.  */
1594               blk[j].len = 0;
1595               blk[j].lastlen = 0;
1596               blk[j].vbn = (*vbn)++;
1597             }
1598
1599           /* Append it to the block.  */
1600           if (j == 0)
1601             {
1602               blk[j].len += blk[j].lastlen;
1603
1604               if (abfd != NULL)
1605                 {
1606                   en = (struct vms_idx *)(rblk[j]->keys + blk[j].len);
1607                   bfd_putl32 ((idx->abfd->proxy_origin / VMS_BLOCK_SIZE) + 1,
1608                               en->rfa.vbn);
1609                   bfd_putl16
1610                     ((idx->abfd->proxy_origin % VMS_BLOCK_SIZE) + DATA__DATA,
1611                      en->rfa.offset);
1612                   en->keylen = idx->namlen;
1613                   memcpy (en->keyname, idx->name, idx->namlen);
1614                 }
1615             }
1616
1617           blk[j].lastlen = idxlen;
1618         }
1619     }
1620
1621   if (topvbn != NULL)
1622     *topvbn = blk[level - 1].vbn;
1623
1624   if (abfd == NULL)
1625     return TRUE;
1626
1627   /* Flush.  */
1628   for (j = 0; j < level; j++)
1629     {
1630       if (j > 0)
1631         {
1632           /* Update parent block: write the new entry.  */
1633           struct vms_idx *en;
1634           struct vms_idx *par;
1635
1636           en = (struct vms_idx *)(rblk[j - 1]->keys + blk[j - 1].len);
1637           par = (struct vms_idx *)(rblk[j]->keys + blk[j].len);
1638           memcpy (par, en, blk[j - 1].lastlen);
1639           bfd_putl32 (blk[j - 1].vbn, par->rfa.vbn);
1640           bfd_putl16 (RFADEF__C_INDEX, par->rfa.offset);
1641         }
1642
1643       /* Write this block on the disk.  */
1644       bfd_putl16 (blk[j].len + blk[j].lastlen, rblk[j]->used);
1645       if (bfd_seek (abfd, (blk[j].vbn - 1) * VMS_BLOCK_SIZE,
1646                     SEEK_SET) != 0)
1647         return FALSE;
1648       if (bfd_bwrite (rblk[j], sizeof (struct vms_indexdef), abfd)
1649           != sizeof (struct vms_indexdef))
1650         return FALSE;
1651
1652       free (rblk[j]);
1653     }
1654
1655   return TRUE;
1656 }
1657
1658 /* Append data to the data block DATA.  Force write if PAD is true.  */
1659
1660 static bfd_boolean
1661 vms_write_data_block (bfd *arch, struct vms_datadef *data, file_ptr *off,
1662                       const unsigned char *buf, unsigned int len, int pad)
1663 {
1664   while (len > 0 || pad)
1665     {
1666       unsigned int doff = *off & (VMS_BLOCK_SIZE - 1);
1667       unsigned int remlen = (DATA__LENGTH - DATA__DATA) - doff;
1668       unsigned int l;
1669
1670       l = (len > remlen) ? remlen : len;
1671       memcpy (data->data + doff, buf, l);
1672       buf += l;
1673       len -= l;
1674       doff += l;
1675       *off += l;
1676
1677       if (doff == (DATA__LENGTH - DATA__DATA) || (len == 0 && pad))
1678         {
1679           data->recs = 0;
1680           data->fill_1 = 0;
1681           bfd_putl32 ((*off / VMS_BLOCK_SIZE) + 2, data->link);
1682
1683           if (bfd_bwrite (data, sizeof (*data), arch) != sizeof (*data))
1684             return FALSE;
1685
1686           *off += DATA__LENGTH - doff;
1687
1688           if (len == 0)
1689             break;
1690         }
1691     }
1692   return TRUE;
1693 }
1694
1695 /* Build the symbols index.  */
1696
1697 static bfd_boolean
1698 _bfd_vms_lib_build_map (unsigned int nbr_modules,
1699                         struct vms_index *modules,
1700                         unsigned int *res_cnt,
1701                         struct vms_index **res)
1702 {
1703   unsigned int i;
1704   asymbol **syms = NULL;
1705   long syms_max = 0;
1706   struct vms_index *map = NULL;
1707   unsigned int map_max = 1024;          /* Fine initial default.  */
1708   unsigned int map_count = 0;
1709
1710   map = (struct vms_index *) bfd_malloc (map_max * sizeof (struct vms_index));
1711   if (map == NULL)
1712     goto error_return;
1713
1714   /* Gather symbols.  */
1715   for (i = 0; i < nbr_modules; i++)
1716     {
1717       long storage;
1718       long symcount;
1719       long src_count;
1720       bfd *current = modules[i].abfd;
1721
1722       if ((bfd_get_file_flags (current) & HAS_SYMS) == 0)
1723         continue;
1724
1725       storage = bfd_get_symtab_upper_bound (current);
1726       if (storage < 0)
1727         goto error_return;
1728
1729       if (storage != 0)
1730         {
1731           if (storage > syms_max)
1732             {
1733               if (syms_max > 0)
1734                 free (syms);
1735               syms_max = storage;
1736               syms = (asymbol **) bfd_malloc (syms_max);
1737               if (syms == NULL)
1738                 goto error_return;
1739             }
1740           symcount = bfd_canonicalize_symtab (current, syms);
1741           if (symcount < 0)
1742             goto error_return;
1743
1744           /* Now map over all the symbols, picking out the ones we
1745              want.  */
1746           for (src_count = 0; src_count < symcount; src_count++)
1747             {
1748               flagword flags = (syms[src_count])->flags;
1749               asection *sec = syms[src_count]->section;
1750
1751               if ((flags & BSF_GLOBAL
1752                    || flags & BSF_WEAK
1753                    || flags & BSF_INDIRECT
1754                    || bfd_is_com_section (sec))
1755                   && ! bfd_is_und_section (sec))
1756                 {
1757                   struct vms_index *new_map;
1758
1759                   /* This symbol will go into the archive header.  */
1760                   if (map_count == map_max)
1761                     {
1762                       map_max *= 2;
1763                       new_map = (struct vms_index *)
1764                         bfd_realloc (map, map_max * sizeof (struct vms_index));
1765                       if (new_map == NULL)
1766                         goto error_return;
1767                       map = new_map;
1768                     }
1769
1770                   map[map_count].abfd = current;
1771                   /* FIXME: check length.  */
1772                   map[map_count].namlen = strlen (syms[src_count]->name);
1773                   map[map_count].name = syms[src_count]->name;
1774                   map_count++;
1775                   modules[i].ref++;
1776                 }
1777             }
1778         }
1779     }
1780
1781   *res_cnt = map_count;
1782   *res = map;
1783   return TRUE;
1784
1785  error_return:
1786   if (syms_max > 0)
1787     free (syms);
1788   if (map != NULL)
1789     free (map);
1790   return FALSE;
1791 }
1792
1793 /* Do the hard work: write an archive on the disk.  */
1794
1795 bfd_boolean
1796 _bfd_vms_lib_write_archive_contents (bfd *arch)
1797 {
1798   bfd *current;
1799   unsigned int nbr_modules;
1800   struct vms_index *modules;
1801   unsigned int nbr_symbols;
1802   struct vms_index *symbols;
1803   struct lib_tdata *tdata = bfd_libdata (arch);
1804   unsigned int i;
1805   file_ptr off;
1806   unsigned int nbr_mod_iblk;
1807   unsigned int nbr_sym_iblk;
1808   unsigned int vbn;
1809   unsigned int mod_idx_vbn;
1810   unsigned int sym_idx_vbn;
1811
1812   /* Count the number of modules (and do a first sanity check).  */
1813   nbr_modules = 0;
1814   for (current = arch->archive_head;
1815        current != NULL;
1816        current = current->archive_next)
1817     {
1818       /* This check is checking the bfds for the objects we're reading
1819          from (which are usually either an object file or archive on
1820          disk), not the archive entries we're writing to.  We don't
1821          actually create bfds for the archive members, we just copy
1822          them byte-wise when we write out the archive.  */
1823       if (bfd_write_p (current) || !bfd_check_format (current, bfd_object))
1824         {
1825           bfd_set_error (bfd_error_invalid_operation);
1826           goto input_err;
1827         }
1828
1829       nbr_modules++;
1830     }
1831
1832   /* Build the modules list.  */
1833   BFD_ASSERT (tdata->modules == NULL);
1834   modules = bfd_alloc (arch, nbr_modules * sizeof (struct vms_index));
1835   if (modules == NULL)
1836     return FALSE;
1837
1838   for (current = arch->archive_head, i = 0;
1839        current != NULL;
1840        current = current->archive_next, i++)
1841     {
1842       int nl;
1843
1844       modules[i].abfd = current;
1845       modules[i].name = vms_get_module_name (current->filename, FALSE);
1846       modules[i].ref = 1;
1847
1848       /* FIXME: silently truncate long names ?  */
1849       nl = strlen (modules[i].name);
1850       modules[i].namlen = (nl > MAX_KEYLEN ? MAX_KEYLEN : nl);
1851     }
1852
1853   /* Create the module index.  */
1854   vbn = 0;
1855   if (!vms_write_index (NULL, modules, nbr_modules, &vbn, NULL))
1856     return FALSE;
1857   nbr_mod_iblk = vbn;
1858
1859   /* Create symbol index.  */
1860   if (!_bfd_vms_lib_build_map (nbr_modules, modules, &nbr_symbols, &symbols))
1861     return FALSE;
1862
1863   vbn = 0;
1864   if (!vms_write_index (NULL, symbols, nbr_symbols, &vbn, NULL))
1865     return FALSE;
1866   nbr_sym_iblk = vbn;
1867
1868   /* Write modules and remember their position.  */
1869   off = (1 + nbr_mod_iblk + nbr_sym_iblk) * VMS_BLOCK_SIZE;
1870
1871   if (bfd_seek (arch, off, SEEK_SET) != 0)
1872     return FALSE;
1873
1874   for (i = 0; i < nbr_modules; i++)
1875     {
1876       struct vms_datadef data;
1877       unsigned char blk[VMS_BLOCK_SIZE];
1878       struct vms_mhd *mhd;
1879       unsigned int sz;
1880
1881       current = modules[i].abfd;
1882       current->proxy_origin = off;
1883
1884       bfd_putl16 (sizeof (struct vms_mhd), blk);
1885       mhd = (struct vms_mhd *)(blk + 2);
1886       memset (mhd, 0, sizeof (struct vms_mhd));
1887       mhd->lbrflag = 0;
1888       mhd->id = MHD__C_MHDID;
1889       mhd->objidlng = 4;
1890       memcpy (mhd->objid, "V1.0", 4);
1891       bfd_putl32 (modules[i].ref, mhd->refcnt);
1892       /* FIXME: datim.  */
1893
1894       sz = (2 + sizeof (struct vms_mhd) + 1) & ~1;
1895       if (vms_write_data_block (arch, &data, &off, blk, sz, 0) < 0)
1896         goto input_err;
1897
1898       if (bfd_seek (current, 0, SEEK_SET) != 0)
1899         goto input_err;
1900
1901       while (1)
1902         {
1903           sz = bfd_bread (blk, sizeof (blk), current);
1904           if (sz == 0)
1905             break;
1906           if (vms_write_data_block (arch, &data, &off, blk, sz, 0) < 0)
1907             goto input_err;
1908         }
1909       if (vms_write_data_block (arch, &data, &off,
1910                                 eotdesc, sizeof (eotdesc), 1) < 0)
1911         goto input_err;
1912     }
1913
1914   /* Write the indexes.  */
1915   vbn = 2;
1916   if (vms_write_index (arch, modules, nbr_modules, &vbn, &mod_idx_vbn) != TRUE)
1917     return FALSE;
1918   if (vms_write_index (arch, symbols, nbr_symbols, &vbn, &sym_idx_vbn) != TRUE)
1919     return FALSE;
1920
1921   /* Write libary header.  */
1922   {
1923     unsigned char blk[VMS_BLOCK_SIZE];
1924     struct vms_lhd *lhd = (struct vms_lhd *)blk;
1925     struct vms_idd *idd = (struct vms_idd *)(blk + sizeof (*lhd));
1926     unsigned int idd_flags;
1927
1928     memset (blk, 0, sizeof (blk));
1929
1930     lhd->type = LBR__C_TYP_EOBJ;
1931     lhd->nindex = 2;
1932     bfd_putl32 (LHD_SANEID3, lhd->sanity);
1933     bfd_putl16 (3, lhd->majorid);
1934     bfd_putl16 (0, lhd->minorid);
1935     snprintf ((char *)lhd->lbrver + 1, sizeof (lhd->lbrver) - 1,
1936               "GNU ar %u.%u.%u",
1937               (unsigned)(BFD_VERSION / 100000000UL),
1938               (unsigned)(BFD_VERSION / 1000000UL) % 100,
1939               (unsigned)(BFD_VERSION / 10000UL) % 100);
1940     lhd->lbrver[sizeof (lhd->lbrver) - 1] = 0;
1941     lhd->lbrver[0] = strlen ((char *)lhd->lbrver + 1);
1942
1943     /* FIXME.  */
1944     bfd_putl64 (0, lhd->credat);
1945     bfd_putl64 (0, lhd->updtim);
1946
1947     lhd->mhdusz = sizeof (struct vms_mhd) - MHD__C_USRDAT;
1948
1949     bfd_putl32 (nbr_modules + nbr_symbols, lhd->idxcnt);
1950     bfd_putl32 (nbr_modules, lhd->modcnt);
1951     bfd_putl32 (nbr_modules, lhd->modhdrs);
1952
1953     bfd_putl32 (vbn - 1, lhd->hipreal);
1954     bfd_putl32 (vbn - 1, lhd->hiprusd);
1955
1956     /* First index (modules name).  */
1957     idd_flags = IDD__FLAGS_ASCII | IDD__FLAGS_VARLENIDX
1958       | IDD__FLAGS_NOCASECMP | IDD__FLAGS_NOCASENTR;
1959     bfd_putl16 (idd_flags, idd->flags);
1960     bfd_putl16 (MAX_KEYLEN, idd->keylen);
1961     bfd_putl16 (mod_idx_vbn, idd->vbn);
1962     idd++;
1963
1964     /* Second index (symbols name).  */
1965     bfd_putl16 (idd_flags, idd->flags);
1966     bfd_putl16 (MAX_KEYLEN, idd->keylen);
1967     bfd_putl16 (sym_idx_vbn, idd->vbn);
1968     idd++;
1969
1970     if (bfd_seek (arch, 0, SEEK_SET) != 0)
1971       return FALSE;
1972     if (bfd_bwrite (blk, sizeof (blk), arch) != sizeof (blk))
1973       return FALSE;
1974   }
1975
1976   return TRUE;
1977
1978  input_err:
1979   bfd_set_error (bfd_error_on_input, current, bfd_get_error ());
1980   return FALSE;
1981 }
1982
1983 /* Add a target for text library.  This costs almost nothing and is useful to
1984    read VMS library on the host.  */
1985
1986 const bfd_target vms_lib_txt_vec =
1987 {
1988   "vms-libtxt",                 /* Name.  */
1989   bfd_target_unknown_flavour,
1990   BFD_ENDIAN_UNKNOWN,           /* byteorder */
1991   BFD_ENDIAN_UNKNOWN,           /* header_byteorder */
1992   0,                            /* Object flags.  */
1993   0,                            /* Sect flags.  */
1994   0,                            /* symbol_leading_char.  */
1995   ' ',                          /* ar_pad_char.  */
1996   15,                           /* ar_max_namelen.  */
1997   bfd_getl64, bfd_getl_signed_64, bfd_putl64,
1998   bfd_getl32, bfd_getl_signed_32, bfd_putl32,
1999   bfd_getl16, bfd_getl_signed_16, bfd_putl16,
2000   bfd_getl64, bfd_getl_signed_64, bfd_putl64,
2001   bfd_getl32, bfd_getl_signed_32, bfd_putl32,
2002   bfd_getl16, bfd_getl_signed_16, bfd_putl16,
2003
2004   {_bfd_dummy_target, _bfd_dummy_target,        /* bfd_check_format.  */
2005    _bfd_vms_lib_txt_archive_p, _bfd_dummy_target},
2006   {bfd_false, bfd_false, bfd_false, bfd_false}, /* bfd_set_format.  */
2007   {bfd_false, bfd_false, bfd_false, bfd_false}, /* bfd_write_contents.  */
2008
2009   BFD_JUMP_TABLE_GENERIC (_bfd_generic),
2010   BFD_JUMP_TABLE_COPY (_bfd_generic),
2011   BFD_JUMP_TABLE_CORE (_bfd_nocore),
2012   BFD_JUMP_TABLE_ARCHIVE (_bfd_vms_lib),
2013   BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols),
2014   BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
2015   BFD_JUMP_TABLE_WRITE (_bfd_nowrite),
2016   BFD_JUMP_TABLE_LINK (_bfd_nolink),
2017   BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
2018
2019   NULL,
2020
2021   (PTR) 0
2022 };