gas/
[deliverable/binutils-gdb.git] / bfd / vms-lib.c
index 888982d89917ac5fff9b8960412d594095b58782..8aa0e9a7f4009f5836df35095dc60d3f69468095 100644 (file)
@@ -1,6 +1,6 @@
 /* BFD back-end for VMS archive files.
 
 /* BFD back-end for VMS archive files.
 
-   Copyright 2010, 2011 Free Software Foundation, Inc.
+   Copyright 2010, 2011, 2012 Free Software Foundation, Inc.
    Written by Tristan Gingold <gingold@adacore.com>, AdaCore.
 
    This file is part of BFD, the Binary File Descriptor library.
    Written by Tristan Gingold <gingold@adacore.com>, AdaCore.
 
    This file is part of BFD, the Binary File Descriptor library.
@@ -35,7 +35,8 @@
 #endif
 
 /* Maximum key length (which is also the maximum symbol length in archive).  */
 #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.  */
 
 
 /* DCX Submaps.  */
 
@@ -277,6 +278,9 @@ vms_traverse_index (bfd *abfd, unsigned int vbn, struct carsym_mem *cs)
       if (idx_vbn == 0)
         return FALSE;
 
       if (idx_vbn == 0)
         return FALSE;
 
+      /* Point to the next index entry.  */
+      p = keyname + keylen;
+
       if (idx_off == RFADEF__C_INDEX)
         {
           /* Indirect entry.  Recurse.  */
       if (idx_off == RFADEF__C_INDEX)
         {
           /* Indirect entry.  Recurse.  */
@@ -368,9 +372,6 @@ vms_traverse_index (bfd *abfd, unsigned int vbn, struct carsym_mem *cs)
                 return FALSE;
             }
         }
                 return FALSE;
             }
         }
-
-      /* Point to the next index entry.  */
-      p = keyname + keylen;
     }
 
   return TRUE;
     }
 
   return TRUE;
@@ -629,7 +630,7 @@ _bfd_vms_lib_archive_p (bfd *abfd, enum vms_lib_kind kind)
 
  err:
   bfd_release (abfd, tdata);
 
  err:
   bfd_release (abfd, tdata);
-  abfd->tdata.any = (void *)tdata_hold;;
+  abfd->tdata.any = (void *)tdata_hold;
   return NULL;
 }
 
   return NULL;
 }
 
@@ -1173,11 +1174,11 @@ vms_lib_bwrite (struct bfd *abfd ATTRIBUTE_UNUSED,
   return -1;
 }
 
   return -1;
 }
 
-static int
+static bfd_boolean
 vms_lib_bclose (struct bfd *abfd)
 {
   abfd->iostream = NULL;
 vms_lib_bclose (struct bfd *abfd)
 {
   abfd->iostream = NULL;
-  return 0;
+  return TRUE;
 }
 
 static int
 }
 
 static int
@@ -1196,11 +1197,13 @@ vms_lib_bstat (struct bfd *abfd ATTRIBUTE_UNUSED,
 
 static void *
 vms_lib_bmmap (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;
 }
 {
   return (void *) -1;
 }
@@ -1293,6 +1296,7 @@ _bfd_vms_lib_get_module (bfd *abfd, unsigned int modidx)
   struct lib_tdata *tdata = bfd_libdata (abfd);
   bfd *res;
   file_ptr file_off;
   struct lib_tdata *tdata = bfd_libdata (abfd);
   bfd *res;
   file_ptr file_off;
+  char *name;
 
   /* Sanity check.  */
   if (modidx >= tdata->nbr_modules)
 
   /* Sanity check.  */
   if (modidx >= tdata->nbr_modules)
@@ -1333,7 +1337,7 @@ _bfd_vms_lib_get_module (bfd *abfd, unsigned int modidx)
       res = _bfd_create_empty_archive_element_shell (abfd);
       if (res == NULL)
         return NULL;
       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;
       if (arelt == NULL)
         return NULL;
       res->arelt_data = arelt;
@@ -1354,7 +1358,25 @@ _bfd_vms_lib_get_module (bfd *abfd, unsigned int modidx)
       res->origin = file_off + tdata->mhd_size;
     }
 
       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 = name;
 
   tdata->cache[modidx] = res;
 
 
   tdata->cache[modidx] = res;
 
@@ -1540,18 +1562,24 @@ get_idxlen (struct lib_index *idx, bfd_boolean is_elfidx)
 {
   if (is_elfidx)
     {
 {
   if (is_elfidx)
     {
+      /* 9 is the size of struct vms_elfidx without keyname.  */
       if (idx->namlen > MAX_KEYLEN)
       if (idx->namlen > MAX_KEYLEN)
-        return 9 + sizeof (struct vms_rfa);
+        return 9 + sizeof (struct vms_kbn);
       else
         return 9 + idx->namlen;
     }
   else
       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.
    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
    Return TRUE on success.  */
 
 static bfd_boolean
@@ -1559,15 +1587,23 @@ vms_write_index (bfd *abfd,
                  struct lib_index *idx, unsigned int nbr, unsigned int *vbn,
                  unsigned int *topvbn, bfd_boolean is_elfidx)
 {
                  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;
   unsigned int i;
   int j;
   int level;
+  /* Disk blocks for the current path.  */
   struct vms_indexdef *rblk[MAX_LEVEL];
   struct vms_indexdef *rblk[MAX_LEVEL];
+  /* Info on the current blocks.  */
   struct idxblk
   {
   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.  */
   } blk[MAX_LEVEL];
 
   /* The kbn blocks are used to store long symbol names.  */
@@ -1606,7 +1642,7 @@ vms_write_index (bfd *abfd,
 
       idxlen = get_idxlen (idx, is_elfidx);
 
 
       idxlen = get_idxlen (idx, is_elfidx);
 
-      if (is_elfidx && idx->namlen >= MAX_KEYLEN)
+      if (is_elfidx && idx->namlen > MAX_KEYLEN)
         {
           /* If the key (ie name) is too long, write it in the kbn block.  */
           unsigned int kl = idx->namlen;
         {
           /* If the key (ie name) is too long, write it in the kbn block.  */
           unsigned int kl = idx->namlen;
@@ -1635,9 +1671,11 @@ vms_write_index (bfd *abfd,
                         }
                       *(unsigned short *)kbn_blk = 0;
                     }
                         }
                       *(unsigned short *)kbn_blk = 0;
                     }
+                  /* Allocate a new block for the keys.  */
                   kbn_vbn = (*vbn)++;
                   kbn_sz = VMS_BLOCK_SIZE - 2;
                 }
                   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
               if (kl + sizeof (struct vms_kbn) > kbn_sz)
                 kl_chunk = kbn_sz - sizeof (struct vms_kbn);
               else
@@ -1683,7 +1721,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)
          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++)
         {
 
       for (j = 0; j < level; j++)
         {
@@ -1704,23 +1742,25 @@ vms_write_index (bfd *abfd,
                     }
                   blk[level].vbn = (*vbn)++;
                   blk[level].len = 0;
                     }
                   blk[level].vbn = (*vbn)++;
                   blk[level].len = 0;
-                  blk[level].lastlen = 0;
+                  blk[level].lastlen = blk[j].lastlen;
 
                   level++;
                 }
 
 
                   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;
 
               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.  */
                   /* Copy the whole entry.  */
-                  memcpy (rblk[j + 1]->keys + blk[j + 1].len,
-                          rblk[j]->keys + blk[j].len,
-                          blk[j].lastlen);
+                 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.  */
                   /* 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_putl32 (blk[j].vbn, rfa->vbn);
                   bfd_putl16 (RFADEF__C_INDEX, rfa->offset);
                 }
                   bfd_putl32 (blk[j].vbn, rfa->vbn);
                   bfd_putl16 (RFADEF__C_INDEX, rfa->offset);
                 }
@@ -1730,7 +1770,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).  */
                   /* 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;
                 }
 
                   blk[j + 1].lastlen = 0;
                 }
 
@@ -1751,6 +1791,7 @@ vms_write_index (bfd *abfd,
           /* Append it to the block.  */
           if (j == 0)
             {
           /* Append it to the block.  */
           if (j == 0)
             {
+             /* Keep the previous last entry.  */
               blk[j].len += blk[j].lastlen;
 
               if (abfd != NULL)
               blk[j].len += blk[j].lastlen;
 
               if (abfd != NULL)
@@ -1795,12 +1836,14 @@ vms_write_index (bfd *abfd,
                       memcpy (en->keyname, idx->name, idx->namlen);
                     }
                 }
                       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;
 
   if (topvbn != NULL)
     *topvbn = blk[level - 1].vbn;
 
@@ -1817,6 +1860,7 @@ vms_write_index (bfd *abfd,
 
       en = rblk[j - 1]->keys + blk[j - 1].len;
       par = rblk[j]->keys + blk[j].len;
 
       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);
       memcpy (par, en, blk[j - 1].lastlen);
       rfa = (struct vms_rfa *)par;
       bfd_putl32 (blk[j - 1].vbn, rfa->vbn);
@@ -1838,6 +1882,7 @@ vms_write_index (bfd *abfd,
     {
       if (vms_write_block (abfd, kbn_vbn, kbn_blk) != TRUE)
         return FALSE;
     {
       if (vms_write_block (abfd, kbn_vbn, kbn_blk) != TRUE)
         return FALSE;
+      free (kbn_blk);
     }
 
   return TRUE;
     }
 
   return TRUE;
@@ -1996,6 +2041,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 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;
 
   /* Count the number of modules (and do a first sanity check).  */
   nbr_modules = 0;
@@ -2027,7 +2073,7 @@ _bfd_vms_lib_write_archive_contents (bfd *arch)
        current != NULL;
        current = current->archive_next, i++)
     {
        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);
 
       modules[i].abfd = current;
       modules[i].name = vms_get_module_name (current->filename, FALSE);
@@ -2035,7 +2081,7 @@ _bfd_vms_lib_write_archive_contents (bfd *arch)
 
       /* FIXME: silently truncate long names ?  */
       nl = strlen (modules[i].name);
 
       /* 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.  */
     }
 
   /* Create the module index.  */
@@ -2226,20 +2272,27 @@ _bfd_vms_lib_write_archive_contents (bfd *arch)
     bfd_putl32 (nbr_modules, lhd->modcnt);
     bfd_putl32 (nbr_modules, lhd->modhdrs);
 
     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);
 
     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);
     /* 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 (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++;
 
     bfd_putl16 (sym_idx_vbn, idd->vbn);
     idd++;
 
@@ -2293,5 +2346,5 @@ const bfd_target vms_lib_txt_vec =
 
   NULL,
 
 
   NULL,
 
-  (PTR) 0
+  NULL
 };
 };
This page took 0.028244 seconds and 4 git commands to generate.