* archive.cc (Archive::get_elf_object_for_member): Remove call
[external/binutils.git] / gold / testsuite / plugin_test.c
index c36fee4..2218d08 100644 (file)
@@ -1,6 +1,6 @@
 /* test_plugin.c -- simple linker plugin test
 
-   Copyright 2008 Free Software Foundation, Inc.
+   Copyright 2008, 2009 Free Software Foundation, Inc.
    Written by Cary Coutant <ccoutant@google.com>.
 
    This file is part of gold.
@@ -34,6 +34,16 @@ struct claimed_file
   struct claimed_file* next;
 };
 
+struct sym_info
+{
+  int size;
+  char* type;
+  char* bind;
+  char* vis;
+  char* sect;
+  char* name;
+};
+
 static struct claimed_file* first_claimed_file = NULL;
 static struct claimed_file* last_claimed_file = NULL;
 
@@ -44,6 +54,8 @@ static ld_plugin_add_symbols add_symbols = NULL;
 static ld_plugin_get_symbols get_symbols = NULL;
 static ld_plugin_add_input_file add_input_file = NULL;
 static ld_plugin_message message = NULL;
+static ld_plugin_get_input_file get_input_file = NULL;
+static ld_plugin_release_input_file release_input_file = NULL;
 
 #define MAXOPTS 10
 
@@ -56,6 +68,8 @@ enum ld_plugin_status claim_file_hook(const struct ld_plugin_input_file *file,
 enum ld_plugin_status all_symbols_read_hook(void);
 enum ld_plugin_status cleanup_hook(void);
 
+static void parse_readelf_line(char*, struct sym_info*);
+
 enum ld_plugin_status
 onload(struct ld_plugin_tv *tv)
 {
@@ -102,6 +116,12 @@ onload(struct ld_plugin_tv *tv)
         case LDPT_MESSAGE:
           message = entry->tv_u.tv_message;
           break;
+        case LDPT_GET_INPUT_FILE:
+          get_input_file = entry->tv_u.tv_get_input_file;
+          break;
+        case LDPT_RELEASE_INPUT_FILE:
+          release_input_file = entry->tv_u.tv_release_input_file;
+          break;
         default:
           break;
         }
@@ -162,21 +182,17 @@ enum ld_plugin_status
 claim_file_hook (const struct ld_plugin_input_file* file, int* claimed)
 {
   int len;
+  off_t end_offset;
   char buf[160];
   struct claimed_file* claimed_file;
   struct ld_plugin_symbol* syms;
   int nsyms = 0;
   int maxsyms = 0;
   FILE* irfile;
-  char *p;
-  char *pbind;
-  char *pvis;
-  char *psect;
+  struct sym_info info;
   int weak;
   int def;
   int vis;
-  int size;
-  char* name;
   int is_comdat;
   int i;
 
@@ -187,6 +203,7 @@ claim_file_hook (const struct ld_plugin_input_file* file, int* claimed)
   /* Look for the beginning of output from readelf -s.  */
   irfile = fdopen(file->fd, "r");
   (void)fseek(irfile, file->offset, SEEK_SET);
+  end_offset = file->offset + file->filesize;
   len = fread(buf, 1, 13, irfile);
   if (len < 13 || strncmp(buf, "\nSymbol table", 13) != 0)
     return LDPS_OK;
@@ -207,68 +224,28 @@ claim_file_hook (const struct ld_plugin_input_file* file, int* claimed)
   if (syms == NULL)
     return LDPS_ERR;
   maxsyms = 8;
-  while (fgets(buf, sizeof(buf), irfile) != NULL)
+  while (ftell(irfile) < end_offset
+         && fgets(buf, sizeof(buf), irfile) != NULL)
     {
-      p = buf;
-      p += strspn(p, " ");
-
-      /* Index field.  */
-      p += strcspn(p, " ");
-      p += strspn(p, " ");
-
-      /* Value field.  */
-      p += strcspn(p, " ");
-      p += strspn(p, " ");
-
-      /* Size field.  */
-      size = atoi(p);
-      p += strcspn(p, " ");
-      p += strspn(p, " ");
-
-      /* Type field.  */
-      p += strcspn(p, " ");
-      p += strspn(p, " ");
-
-      /* Binding field.  */
-      pbind = p;
-      p += strcspn(p, " ");
-      p += strspn(p, " ");
-
-      /* Visibility field.  */
-      pvis = p;
-      p += strcspn(p, " ");
-      p += strspn(p, " ");
-
-      /* Section field.  */
-      psect = p;
-      p += strcspn(p, " ");
-      p += strspn(p, " ");
-
-      /* Name field.  */
-      /* FIXME:  Look for version.  */
-      len = strlen(p);
-      if (p[len-1] == '\n')
-        p[--len] = '\0';
-      name = malloc(len + 1);
-      strncpy(name, p, len + 1);
+      parse_readelf_line(buf, &info);
 
       /* Ignore local symbols.  */
-      if (strncmp(pbind, "LOCAL", 5) == 0)
+      if (strncmp(info.bind, "LOCAL", 5) == 0)
         continue;
 
-      weak = strncmp(pbind, "WEAK", 4) == 0;
-      if (strncmp(psect, "UND", 3) == 0)
+      weak = strncmp(info.bind, "WEAK", 4) == 0;
+      if (strncmp(info.sect, "UND", 3) == 0)
         def = weak ? LDPK_WEAKUNDEF : LDPK_UNDEF;
-      else if (strncmp(psect, "COM", 3) == 0)
+      else if (strncmp(info.sect, "COM", 3) == 0)
         def = LDPK_COMMON;
       else
         def = weak ? LDPK_WEAKDEF : LDPK_DEF;
 
-      if (strncmp(pvis, "INTERNAL", 8) == 0)
+      if (strncmp(info.vis, "INTERNAL", 8) == 0)
         vis = LDPV_INTERNAL;
-      else if (strncmp(pvis, "HIDDEN", 6) == 0)
+      else if (strncmp(info.vis, "HIDDEN", 6) == 0)
         vis = LDPV_HIDDEN;
-      else if (strncmp(pvis, "PROTECTED", 9) == 0)
+      else if (strncmp(info.vis, "PROTECTED", 9) == 0)
         vis = LDPV_PROTECTED;
       else
         vis = LDPV_DEFAULT;
@@ -278,7 +255,7 @@ claim_file_hook (const struct ld_plugin_input_file* file, int* claimed)
       is_comdat = 0;
       for (i = 0; i < nopts; ++i)
         {
-          if (name != NULL && strcmp(name, opts[i]) == 0)
+          if (info.name != NULL && strcmp(info.name, opts[i]) == 0)
             {
               is_comdat = 1;
               break;
@@ -294,12 +271,19 @@ claim_file_hook (const struct ld_plugin_input_file* file, int* claimed)
           maxsyms *= 2;
         }
 
-      syms[nsyms].name = name;
+      if (info.name == NULL)
+        syms[nsyms].name = NULL;
+      else
+        {
+          len = strlen(info.name);
+          syms[nsyms].name = malloc(len + 1);
+          strncpy(syms[nsyms].name, info.name, len + 1);
+        }
       syms[nsyms].version = NULL;
       syms[nsyms].def = def;
       syms[nsyms].visibility = vis;
-      syms[nsyms].size = size;
-      syms[nsyms].comdat_key = is_comdat ? name : NULL;
+      syms[nsyms].size = info.size;
+      syms[nsyms].comdat_key = is_comdat ? syms[nsyms].name : NULL;
       syms[nsyms].resolution = LDPR_UNKNOWN;
       ++nsyms;
     }
@@ -335,8 +319,14 @@ all_symbols_read_hook(void)
   int i;
   const char* res;
   struct claimed_file* claimed_file;
+  struct ld_plugin_input_file file;
+  FILE* irfile;
+  off_t end_offset;
+  struct sym_info info;
+  int len;
   char buf[160];
-  char *p;
+  char* p;
+  const char* filename;
 
   (*message)(LDPL_INFO, "all symbols read hook called");
 
@@ -352,6 +342,7 @@ all_symbols_read_hook(void)
     {
       (*get_symbols)(claimed_file->handle, claimed_file->nsyms,
                      claimed_file->syms);
+
       for (i = 0; i < claimed_file->nsyms; ++i)
         {
           switch (claimed_file->syms[i].resolution)
@@ -397,28 +388,83 @@ all_symbols_read_hook(void)
       fprintf(stderr, "tv_add_input_file interface missing\n");
       return LDPS_ERR;
     }
+  if (get_input_file == NULL)
+    {
+      fprintf(stderr, "tv_get_input_file interface missing\n");
+      return LDPS_ERR;
+    }
+  if (release_input_file == NULL)
+    {
+      fprintf(stderr, "tv_release_input_file interface missing\n");
+      return LDPS_ERR;
+    }
 
   for (claimed_file = first_claimed_file;
        claimed_file != NULL;
        claimed_file = claimed_file->next)
     {
+      (*get_input_file) (claimed_file->handle, &file);
+
+      /* Look for the beginning of output from readelf -s.  */
+      irfile = fdopen(file.fd, "r");
+      (void)fseek(irfile, file.offset, SEEK_SET);
+      end_offset = file.offset + file.filesize;
+      len = fread(buf, 1, 13, irfile);
+      if (len < 13 || strncmp(buf, "\nSymbol table", 13) != 0)
+        {
+          fprintf(stderr, "%s: can't re-read original input file\n",
+                  claimed_file->name);
+          return LDPS_ERR;
+        }
+
+      /* Skip the two header lines.  */
+      (void) fgets(buf, sizeof(buf), irfile);
+      (void) fgets(buf, sizeof(buf), irfile);
+
+      filename = NULL;
+      while (ftell(irfile) < end_offset
+             && fgets(buf, sizeof(buf), irfile) != NULL)
+        {
+          parse_readelf_line(buf, &info);
+
+          /* Look for file name.  */
+          if (strncmp(info.type, "FILE", 4) == 0)
+            {
+              len = strlen(info.name);
+              p = malloc(len + 1);
+              strncpy(p, info.name, len + 1);
+              filename = p;
+              break;
+            }
+        }
+
+      (*release_input_file) (claimed_file->handle);
+
+      if (filename == NULL)
+        filename = claimed_file->name;
+
       if (claimed_file->nsyms == 0)
         continue;
-      if (strlen(claimed_file->name) >= sizeof(buf))
+
+      if (strlen(filename) >= sizeof(buf))
         {
-          (*message)(LDPL_FATAL, "%s: filename too long", claimed_file->name);
+          (*message)(LDPL_FATAL, "%s: filename too long", filename);
           return LDPS_ERR;
         }
-      strcpy(buf, claimed_file->name);
+      strcpy(buf, filename);
       p = strrchr(buf, '.');
-      if (p == NULL || strcmp(p, ".syms") != 0)
+      if (p == NULL
+          || (strcmp(p, ".syms") != 0
+              && strcmp(p, ".c") != 0
+              && strcmp(p, ".cc") != 0))
         {
-          (*message)(LDPL_FATAL, "%s: filename must have '.syms' suffix",
-                     claimed_file->name);
+          (*message)(LDPL_FATAL, "%s: filename has unknown suffix",
+                     filename);
           return LDPS_ERR;
         }
       p[1] = 'o';
       p[2] = '\0';
+      (*message)(LDPL_INFO, "%s: adding new input file", buf);
       (*add_input_file)(buf);
     }
 
@@ -431,3 +477,53 @@ cleanup_hook(void)
   (*message)(LDPL_INFO, "cleanup hook called");
   return LDPS_OK;
 }
+
+static void
+parse_readelf_line(char* p, struct sym_info* info)
+{
+  int len;
+
+  p += strspn(p, " ");
+
+  /* Index field.  */
+  p += strcspn(p, " ");
+  p += strspn(p, " ");
+
+  /* Value field.  */
+  p += strcspn(p, " ");
+  p += strspn(p, " ");
+
+  /* Size field.  */
+  info->size = atoi(p);
+  p += strcspn(p, " ");
+  p += strspn(p, " ");
+
+  /* Type field.  */
+  info->type = p;
+  p += strcspn(p, " ");
+  p += strspn(p, " ");
+
+  /* Binding field.  */
+  info->bind = p;
+  p += strcspn(p, " ");
+  p += strspn(p, " ");
+
+  /* Visibility field.  */
+  info->vis = p;
+  p += strcspn(p, " ");
+  p += strspn(p, " ");
+
+  /* Section field.  */
+  info->sect = p;
+  p += strcspn(p, " ");
+  p += strspn(p, " ");
+
+  /* Name field.  */
+  /* FIXME:  Look for version.  */
+  len = strlen(p);
+  if (len == 0)
+    p = NULL;
+  else if (p[len-1] == '\n')
+    p[--len] = '\0';
+  info->name = p;
+}