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