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