/* BFD back-end for VMS archive files.
- Copyright 2010 Free Software Foundation, Inc.
+ Copyright (C) 2010-2015 Free Software Foundation, Inc.
Written by Tristan Gingold <gingold@adacore.com>, AdaCore.
This file is part of BFD, the Binary File Descriptor library.
#include "libbfd.h"
#include "safe-ctype.h"
#include "bfdver.h"
+#include "libiberty.h"
#include "vms.h"
#include "vms/lbr.h"
#include "vms/dcx.h"
#endif
/* Maximum key length (which is also the maximum symbol length in archive). */
-#define MAX_KEYLEN 129
+#define MAX_KEYLEN 128
+#define MAX_EKEYLEN 1024
/* DCX Submaps. */
if (idx_vbn == 0)
return FALSE;
+ /* Point to the next index entry. */
+ p = keyname + keylen;
+
if (idx_off == RFADEF__C_INDEX)
{
/* Indirect entry. Recurse. */
return FALSE;
}
}
-
- /* Point to the next index entry. */
- p = keyname + keylen;
}
return TRUE;
err:
bfd_release (abfd, tdata);
- abfd->tdata.any = (void *)tdata_hold;;
+ abfd->tdata.any = (void *)tdata_hold;
return NULL;
}
function does not handle records nor EOF. */
static file_ptr
-vms_lib_bread_raw (struct bfd *abfd, void *buf, file_ptr nbytes)
+vms_lib_bread_raw (struct bfd *abfd, unsigned char *buf, file_ptr nbytes)
{
struct vms_lib_iovec *vec = (struct vms_lib_iovec *) abfd->iostream;
file_ptr res;
/* Standard IOVEC function. */
static file_ptr
-vms_lib_bread (struct bfd *abfd, void *buf, file_ptr nbytes)
+vms_lib_bread (struct bfd *abfd, void *vbuf, file_ptr nbytes)
{
struct vms_lib_iovec *vec = (struct vms_lib_iovec *) abfd->iostream;
file_ptr res;
file_ptr chunk;
+ unsigned char *buf = (unsigned char *)vbuf;
/* Do not read past the end. */
if (vec->where >= vec->file_len)
unsigned char blen[2];
/* Read record length. */
- if (vms_lib_bread_raw (abfd, &blen, sizeof (blen)) != sizeof (blen))
+ if (vms_lib_bread_raw (abfd, blen, sizeof (blen)) != sizeof (blen))
return -1;
vec->rec_len = bfd_getl16 (blen);
if (bfd_libdata (abfd->my_archive)->kind == vms_lib_txt)
}
if (buf != NULL)
{
- *(unsigned char *)buf = c;
+ *buf = c;
buf++;
}
nbytes--;
static void *
vms_lib_bmmap (struct bfd *abfd ATTRIBUTE_UNUSED,
- void *addr ATTRIBUTE_UNUSED,
- bfd_size_type len ATTRIBUTE_UNUSED,
- int prot ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED,
- file_ptr offset ATTRIBUTE_UNUSED)
+ void *addr ATTRIBUTE_UNUSED,
+ bfd_size_type len ATTRIBUTE_UNUSED,
+ int prot ATTRIBUTE_UNUSED,
+ int flags ATTRIBUTE_UNUSED,
+ file_ptr offset ATTRIBUTE_UNUSED,
+ void **map_addr ATTRIBUTE_UNUSED,
+ bfd_size_type *map_len ATTRIBUTE_UNUSED)
{
return (void *) -1;
}
vms_lib_bopen (bfd *el, file_ptr filepos)
{
struct vms_lib_iovec *vec;
- char buf[256];
+ unsigned char buf[256];
struct vms_mhd *mhd;
struct lib_tdata *tdata = bfd_libdata (el->my_archive);
unsigned int len;
struct lib_tdata *tdata = bfd_libdata (abfd);
bfd *res;
file_ptr file_off;
+ char *name;
/* Sanity check. */
if (modidx >= tdata->nbr_modules)
res = _bfd_create_empty_archive_element_shell (abfd);
if (res == NULL)
return NULL;
- arelt = bfd_zalloc (res, sizeof (*arelt));
+ arelt = bfd_zmalloc (sizeof (*arelt));
if (arelt == NULL)
return NULL;
res->arelt_data = arelt;
res->origin = file_off + tdata->mhd_size;
}
- res->filename = tdata->modules[modidx].name;
+ /* Set filename. */
+ name = tdata->modules[modidx].name;
+ switch (tdata->type)
+ {
+ case LBR__C_TYP_IOBJ:
+ case LBR__C_TYP_EOBJ:
+ /* For object archives, append .obj to mimic standard behaviour. */
+ {
+ size_t namelen = strlen (name);
+ char *name1 = bfd_alloc (res, namelen + 4 + 1);
+ memcpy (name1, name, namelen);
+ strcpy (name1 + namelen, ".obj");
+ name = name1;
+ }
+ break;
+ default:
+ break;
+ }
+ res->filename = xstrdup (name);
tdata->cache[modidx] = res;
{
if (is_elfidx)
{
+ /* 9 is the size of struct vms_elfidx without keyname. */
if (idx->namlen > MAX_KEYLEN)
- return 9 + sizeof (struct vms_rfa);
+ return 9 + sizeof (struct vms_kbn);
else
return 9 + idx->namlen;
}
else
- return 7 + idx->namlen;
+ {
+ /* 7 is the size of struct vms_idx without keyname. */
+ return 7 + idx->namlen;
+ }
}
-/* Write the index. VBN is the first vbn to be used, and will contain
- on return the last vbn.
+/* Write the index composed by NBR symbols contained in IDX.
+ VBN is the first vbn to be used, and will contain on return the last vbn.
+ Can be called with ABFD set to NULL just to size the index.
+ If not null, TOPVBN will be assigned to the vbn of the root index tree.
+ IS_ELFIDX is true for elfidx (ie ia64) indexes layout.
Return TRUE on success. */
static bfd_boolean
struct lib_index *idx, unsigned int nbr, unsigned int *vbn,
unsigned int *topvbn, bfd_boolean is_elfidx)
{
+ /* The index is organized as a tree. This function implements a naive
+ algorithm to balance the tree: it fills the leaves, and create a new
+ branch when all upper leaves and branches are full. We only keep in
+ memory a path to the current leaf. */
unsigned int i;
int j;
int level;
+ /* Disk blocks for the current path. */
struct vms_indexdef *rblk[MAX_LEVEL];
+ /* Info on the current blocks. */
struct idxblk
{
- unsigned int vbn;
- unsigned short len;
- unsigned short lastlen;
+ unsigned int vbn; /* VBN of the block. */
+ /* The last entry is identified so that it could be copied to the
+ parent block. */
+ unsigned short len; /* Length up to the last entry. */
+ unsigned short lastlen; /* Length of the last entry. */
} blk[MAX_LEVEL];
/* The kbn blocks are used to store long symbol names. */
- unsigned int kbn_sz = 0; /* Number of bytes availble in the kbn block. */
- unsigned int kbn_vbn = 0; /* VBN of the kbn block. */
+ unsigned int kbn_sz = 0; /* Number of bytes available in the kbn block. */
+ unsigned int kbn_vbn = 0; /* VBN of the kbn block. */
unsigned char *kbn_blk = NULL; /* Contents of the kbn block. */
if (nbr == 0)
/* Allocate first index block. */
level = 1;
if (abfd != NULL)
- rblk[0] = bfd_malloc (sizeof (struct vms_indexdef));
+ rblk[0] = bfd_zmalloc (sizeof (struct vms_indexdef));
blk[0].vbn = (*vbn)++;
blk[0].len = 0;
blk[0].lastlen = 0;
idxlen = get_idxlen (idx, is_elfidx);
- if (is_elfidx && idx->namlen >= MAX_KEYLEN)
+ if (is_elfidx && idx->namlen > MAX_KEYLEN)
{
- /* If the name is too long, write it in the kbn block. */
+ /* If the key (ie name) is too long, write it in the kbn block. */
unsigned int kl = idx->namlen;
unsigned int kl_chunk;
const char *key = idx->name;
- /* Write the name in the kbn, chunk after chunk. */
+ /* Write the key in the kbn, chunk after chunk. */
do
{
if (kbn_sz < sizeof (struct vms_kbn))
}
*(unsigned short *)kbn_blk = 0;
}
+ /* Allocate a new block for the keys. */
kbn_vbn = (*vbn)++;
kbn_sz = VMS_BLOCK_SIZE - 2;
}
+ /* Size of the chunk written to the current key block. */
if (kl + sizeof (struct vms_kbn) > kbn_sz)
kl_chunk = kbn_sz - sizeof (struct vms_kbn);
else
block and all the blocks below it. */
for (j = 0; j < level; j++)
if (blk[j].len + blk[j].lastlen + idxlen > INDEXDEF__BLKSIZ)
- flush = j + 1;
+ flush = j + 1;
for (j = 0; j < level; j++)
{
/* Need to create a parent. */
if (abfd != NULL)
{
- rblk[level] = bfd_malloc (sizeof (struct vms_indexdef));
+ rblk[level] = bfd_zmalloc (sizeof (struct vms_indexdef));
bfd_putl32 (*vbn, rblk[j]->parent);
}
blk[level].vbn = (*vbn)++;
blk[level].len = 0;
- blk[level].lastlen = 0;
+ blk[level].lastlen = blk[j].lastlen;
level++;
}
- /* Update parent block: write the new entry. */
+ /* Update parent block: write the last entry from the current
+ block. */
if (abfd != NULL)
{
struct vms_rfa *rfa;
+ /* Pointer to the last entry in parent block. */
+ rfa = (struct vms_rfa *)(rblk[j + 1]->keys + blk[j + 1].len);
+
/* Copy the whole entry. */
- memcpy (rblk[j + 1]->keys + blk[j + 1].len,
- rblk[j]->keys + blk[j].len,
- blk[j].lastlen);
- /* Fix the entry (which in always the first field of an entry. */
- rfa = (struct vms_rfa *)(rblk[j + 1]->keys + blk[j + 1].len);
+ BFD_ASSERT (blk[j + 1].lastlen == blk[j].lastlen);
+ memcpy (rfa, rblk[j]->keys + blk[j].len, blk[j].lastlen);
+ /* Fix the entry (which in always the first field of an
+ entry. */
bfd_putl32 (blk[j].vbn, rfa->vbn);
bfd_putl16 (RFADEF__C_INDEX, rfa->offset);
}
/* And allocate it. Do it only on the block that won't be
flushed (so that the parent of the parent can be
updated too). */
- blk[j + 1].len += blk[j].lastlen;
+ blk[j + 1].len += blk[j + 1].lastlen;
blk[j + 1].lastlen = 0;
}
/* Append it to the block. */
if (j == 0)
{
+ /* Keep the previous last entry. */
blk[j].len += blk[j].lastlen;
if (abfd != NULL)
memcpy (en->keyname, idx->name, idx->namlen);
}
}
- }
-
- blk[j].lastlen = idxlen;
+ }
+ /* The last added key can now be the last one all blocks in the
+ path. */
+ blk[j].lastlen = idxlen;
}
}
+ /* Save VBN of the root. */
if (topvbn != NULL)
*topvbn = blk[level - 1].vbn;
return TRUE;
/* Flush. */
- for (j = 0; j < level; j++)
+ for (j = 1; j < level; j++)
{
- if (j > 0)
- {
- /* Update parent block: write the new entry. */
- unsigned char *en;
- unsigned char *par;
- struct vms_rfa *rfa;
-
- en = rblk[j - 1]->keys + blk[j - 1].len;
- par = rblk[j]->keys + blk[j].len;
- memcpy (par, en, blk[j - 1].lastlen);
- rfa = (struct vms_rfa *)par;
- bfd_putl32 (blk[j - 1].vbn, rfa->vbn);
- bfd_putl16 (RFADEF__C_INDEX, rfa->offset);
- }
+ /* Update parent block: write the new entry. */
+ unsigned char *en;
+ unsigned char *par;
+ struct vms_rfa *rfa;
+
+ en = rblk[j - 1]->keys + blk[j - 1].len;
+ par = rblk[j]->keys + blk[j].len;
+ BFD_ASSERT (blk[j].lastlen == blk[j - 1].lastlen);
+ memcpy (par, en, blk[j - 1].lastlen);
+ rfa = (struct vms_rfa *)par;
+ bfd_putl32 (blk[j - 1].vbn, rfa->vbn);
+ bfd_putl16 (RFADEF__C_INDEX, rfa->offset);
+ }
+ for (j = 0; j < level; j++)
+ {
/* Write this block on the disk. */
bfd_putl16 (blk[j].len + blk[j].lastlen, rblk[j]->used);
if (vms_write_block (abfd, blk[j].vbn, rblk[j]) != TRUE)
free (rblk[j]);
}
+ /* Write the last kbn (if any). */
if (kbn_vbn != 0)
{
if (vms_write_block (abfd, kbn_vbn, kbn_blk) != TRUE)
return FALSE;
+ free (kbn_blk);
}
return TRUE;
unsigned int mod_idx_vbn;
unsigned int sym_idx_vbn;
bfd_boolean is_elfidx = tdata->kind == vms_lib_ia64;
+ unsigned int max_keylen = is_elfidx ? MAX_EKEYLEN : MAX_KEYLEN;
/* Count the number of modules (and do a first sanity check). */
nbr_modules = 0;
current != NULL;
current = current->archive_next, i++)
{
- int nl;
+ unsigned int nl;
modules[i].abfd = current;
modules[i].name = vms_get_module_name (current->filename, FALSE);
/* FIXME: silently truncate long names ? */
nl = strlen (modules[i].name);
- modules[i].namlen = (nl > MAX_KEYLEN ? MAX_KEYLEN : nl);
+ modules[i].namlen = (nl > max_keylen ? max_keylen : nl);
}
/* Create the module index. */
/* Write the first block (which contains an mhd). */
if (bfd_bwrite (blk, VMS_BLOCK_SIZE, arch) != VMS_BLOCK_SIZE)
goto input_err;
+ off += VMS_BLOCK_SIZE;
if (amt == VMS_BLOCK_SIZE - sz)
{
bfd_putl32 (nbr_modules, lhd->modcnt);
bfd_putl32 (nbr_modules, lhd->modhdrs);
+ /* Number of blocks for index. */
+ bfd_putl32 (nbr_mod_iblk + nbr_sym_iblk, lhd->idxblks);
bfd_putl32 (vbn - 1, lhd->hipreal);
bfd_putl32 (vbn - 1, lhd->hiprusd);
+ /* VBN of the next free block. */
+ bfd_putl32 ((off / VMS_BLOCK_SIZE) + 1, lhd->nextvbn);
+ bfd_putl32 ((off / VMS_BLOCK_SIZE) + 1, lhd->nextrfa + 0);
+ bfd_putl16 (0, lhd->nextrfa + 4);
+
/* First index (modules name). */
idd_flags = IDD__FLAGS_ASCII | IDD__FLAGS_VARLENIDX
| IDD__FLAGS_NOCASECMP | IDD__FLAGS_NOCASENTR;
bfd_putl16 (idd_flags, idd->flags);
- bfd_putl16 (MAX_KEYLEN, idd->keylen);
+ bfd_putl16 (max_keylen + 1, idd->keylen);
bfd_putl16 (mod_idx_vbn, idd->vbn);
idd++;
/* Second index (symbols name). */
bfd_putl16 (idd_flags, idd->flags);
- bfd_putl16 (MAX_KEYLEN, idd->keylen);
+ bfd_putl16 (max_keylen + 1, idd->keylen);
bfd_putl16 (sym_idx_vbn, idd->vbn);
idd++;
/* Add a target for text library. This costs almost nothing and is useful to
read VMS library on the host. */
-const bfd_target vms_lib_txt_vec =
+const bfd_target alpha_vms_lib_txt_vec =
{
"vms-libtxt", /* Name. */
bfd_target_unknown_flavour,
0, /* symbol_leading_char. */
' ', /* ar_pad_char. */
15, /* ar_max_namelen. */
+ 0, /* match priority. */
bfd_getl64, bfd_getl_signed_64, bfd_putl64,
bfd_getl32, bfd_getl_signed_32, bfd_putl32,
bfd_getl16, bfd_getl_signed_16, bfd_putl16,
NULL,
- (PTR) 0
+ NULL
};