Automatic date update in version.in
[platform/upstream/binutils.git] / bfd / vms-lib.c
index b7c8f83..dbacc33 100644 (file)
@@ -1,6 +1,6 @@
 /* BFD back-end for VMS archive files.
 
-   Copyright 2010 Free Software Foundation, Inc.
+   Copyright (C) 2010-2014 Free Software Foundation, Inc.
    Written by Tristan Gingold <gingold@adacore.com>, AdaCore.
 
    This file is part of BFD, the Binary File Descriptor library.
@@ -25,6 +25,7 @@
 #include "libbfd.h"
 #include "safe-ctype.h"
 #include "bfdver.h"
+#include "libiberty.h"
 #include "vms.h"
 #include "vms/lbr.h"
 #include "vms/dcx.h"
@@ -35,7 +36,8 @@
 #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.  */
 
@@ -277,6 +279,9 @@ vms_traverse_index (bfd *abfd, unsigned int vbn, struct carsym_mem *cs)
       if (idx_vbn == 0)
         return FALSE;
 
+      /* Point to the next index entry.  */
+      p = keyname + keylen;
+
       if (idx_off == RFADEF__C_INDEX)
         {
           /* Indirect entry.  Recurse.  */
@@ -368,9 +373,6 @@ vms_traverse_index (bfd *abfd, unsigned int vbn, struct carsym_mem *cs)
                 return FALSE;
             }
         }
-
-      /* Point to the next index entry.  */
-      p = keyname + keylen;
     }
 
   return TRUE;
@@ -629,7 +631,7 @@ _bfd_vms_lib_archive_p (bfd *abfd, enum vms_lib_kind kind)
 
  err:
   bfd_release (abfd, tdata);
-  abfd->tdata.any = (void *)tdata_hold;;
+  abfd->tdata.any = (void *)tdata_hold;
   return NULL;
 }
 
@@ -703,6 +705,12 @@ _bfd_vms_lib_alpha_mkarchive (bfd *abfd)
   return _bfd_vms_lib_mkarchive (abfd, vms_lib_alpha);
 }
 
+bfd_boolean
+_bfd_vms_lib_ia64_mkarchive (bfd *abfd)
+{
+  return _bfd_vms_lib_mkarchive (abfd, vms_lib_ia64);
+}
+
 /* Find NAME in the symbol index.  Return the index.  */
 
 symindex
@@ -827,7 +835,7 @@ vms_lib_read_block (struct bfd *abfd)
    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;
@@ -945,11 +953,12 @@ vms_lib_dcx (struct vms_lib_iovec *vec, unsigned char *buf, file_ptr nbytes)
 /* 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)
@@ -963,7 +972,7 @@ vms_lib_bread (struct bfd *abfd, void *buf, file_ptr nbytes)
           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)
@@ -1065,7 +1074,7 @@ vms_lib_bread (struct bfd *abfd, void *buf, file_ptr nbytes)
             }
           if (buf != NULL)
             {
-              *(unsigned char *)buf = c;
+              *buf = c;
               buf++;
             }
           nbytes--;
@@ -1189,11 +1198,13 @@ vms_lib_bstat (struct bfd *abfd ATTRIBUTE_UNUSED,
 
 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;
 }
@@ -1209,7 +1220,7 @@ static bfd_boolean
 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;
@@ -1286,6 +1297,7 @@ _bfd_vms_lib_get_module (bfd *abfd, unsigned int modidx)
   struct lib_tdata *tdata = bfd_libdata (abfd);
   bfd *res;
   file_ptr file_off;
+  char *name;
 
   /* Sanity check.  */
   if (modidx >= tdata->nbr_modules)
@@ -1326,7 +1338,7 @@ _bfd_vms_lib_get_module (bfd *abfd, unsigned int modidx)
       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;
@@ -1347,7 +1359,25 @@ _bfd_vms_lib_get_module (bfd *abfd, unsigned int modidx)
       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;
 
@@ -1533,17 +1563,24 @@ get_idxlen (struct lib_index *idx, bfd_boolean is_elfidx)
 {
   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
@@ -1551,20 +1588,28 @@ vms_write_index (bfd *abfd,
                  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)
@@ -1584,7 +1629,7 @@ vms_write_index (bfd *abfd,
   /* 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;
@@ -1598,14 +1643,14 @@ vms_write_index (bfd *abfd,
 
       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))
@@ -1627,9 +1672,11 @@ vms_write_index (bfd *abfd,
                         }
                       *(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
@@ -1675,7 +1722,7 @@ vms_write_index (bfd *abfd,
          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++)
         {
@@ -1691,27 +1738,30 @@ vms_write_index (bfd *abfd,
                   /* 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);
                 }
@@ -1721,7 +1771,7 @@ vms_write_index (bfd *abfd,
                   /* 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;
                 }
 
@@ -1742,6 +1792,7 @@ vms_write_index (bfd *abfd,
           /* Append it to the block.  */
           if (j == 0)
             {
+             /* Keep the previous last entry.  */
               blk[j].len += blk[j].lastlen;
 
               if (abfd != NULL)
@@ -1786,12 +1837,14 @@ vms_write_index (bfd *abfd,
                       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;
 
@@ -1799,23 +1852,24 @@ vms_write_index (bfd *abfd,
     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)
@@ -1824,10 +1878,12 @@ vms_write_index (bfd *abfd,
       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;
@@ -1986,6 +2042,7 @@ _bfd_vms_lib_write_archive_contents (bfd *arch)
   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;
@@ -2017,7 +2074,7 @@ _bfd_vms_lib_write_archive_contents (bfd *arch)
        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);
@@ -2025,7 +2082,7 @@ _bfd_vms_lib_write_archive_contents (bfd *arch)
 
       /* 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.  */
@@ -2105,6 +2162,7 @@ _bfd_vms_lib_write_archive_contents (bfd *arch)
           /* 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)
             {
@@ -2215,20 +2273,27 @@ _bfd_vms_lib_write_archive_contents (bfd *arch)
     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++;
 
@@ -2246,7 +2311,7 @@ _bfd_vms_lib_write_archive_contents (bfd *arch)
 /* 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,
@@ -2257,6 +2322,7 @@ const bfd_target vms_lib_txt_vec =
   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,
@@ -2281,5 +2347,5 @@ const bfd_target vms_lib_txt_vec =
 
   NULL,
 
-  (PTR) 0
+  NULL
 };