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