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