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