[gold][patch] Fix plugin API so gold doesn't try to access a closed file

Cary Coutant ccoutant@google.com
Thu Jan 15 01:20:00 GMT 2009


The linker plugin API to support LTO currently turns over management
of file descriptors that are claimed by the plugin to the plugin. This
is a problem when the IR files happen to be members of archives, and
it also means that if the plugin decides to keep the files open, we
may run out of available file descriptors before completing the link.

The attached patch reworks the API so that the linker retains the
management of file descriptors. It hands a file descriptor to a plugin
in the claim-file interface, and guarantees that the descriptor will
remain valid until the claim-file callback returns to the linker. If
the plugin needs to access the file again during the all-symbols-read
callback, it can use a new get-input-file API to obtain an open file
descriptor, and a new release-input-file API to release it.

A new testcase covers IR files in archive libraries and all plugin
testcases now exercise the two new APIs.

Since the only changes outside of the plugin code are trivial  (the
changes to descriptors.* and fileread.* are nearly complete reversions
of the original plugin checkin), I'm going to go ahead and commit this
patch.

-cary


include/:

	* plugin-api.h (LDPS_BAD_HANDLE): New constant.
	(ld_plugin_get_input_file): New typedef.
	(ld_plugin_release_input_file): New typedef.
	(LDPT_GET_INPUT_FILE, LDPT_RELEASE_INPUT_FILE): New constants.
	(struct ld_plugin_tv): Add two new fields.

gold/:

	* archive.cc (Archive::get_elf_object_for_member): Remove call
	to File_read::claim_for_plugin.
	* descriptors.cc (Descriptors::open): Remove reference to
	is_claimed.
	(Descriptors::claim_for_plugin): Remove.
	* descriptors.h (Descriptors::claim_for_plugin): Remove.
	(Descriptors::is_claimed): Remove.
	(claim_descriptor_for_plugin): Remove.
	* fileread.cc (File_read::claim_for_plugin): Remove.
	* fileread.h (File_read::claim_for_plugin): Remove.
	(File_read::descriptor): Reopen descriptor if necessary.
	* plugin.cc  (Plugin::load): Add two new APIs to transfer vector.
	(Plugin_manager::all_symbols_read): Add task parameter. Change
	all callers.
	(Plugin_manager::get_input_file): New function.
	(Plugin_manager::release_input_file): New function.
	(Pluginobj::Pluginobj): Add filesize parameter and initialize
	corresponding data member.
	(Sized_pluginobj::Sized_pluginobj): Add filesize parameter
	and pass to base constructor. Change all callers.
	(get_input_file, release_input_file): New functions.
	(make_sized_plugin_object): Add filesize parameter. Change all callers.
	* plugin.h (Plugin_manager::Plugin_manager): Initialize task_ member.
	(Plugin_manager::all_symbols_read): Add task parameter.
	(Plugin_manager::get_input_file): New function.
	(Plugin_manager::release_input_file): New function.
	(Plugin_manager::task_): New data member.
	(Pluginobj::Pluginobj): Add filesize parameter.
	(Pluginobj::filename): New function.
	(Pluginobj::descriptor): New function.
	(Pluginobj::filesize): New function.
	(Pluginobj::filesize_): New data member.
	(Sized_pluginobj::Sized_pluginobj): Add filesize parameter.
	* readsyms.cc (Read_symbols::do_read_symbols): Remove call to
	File_read::claim_for_plugin; use Object::unlock to unlock the file.

	* testsuite/Makefile.am (plugin_test_4): New test case for plugins
	with archive libraries.
	* testsuite/Makefile.in: Regenerate.
	* testsuite/plugin_test.c (struct sym_info): New type.
	(get_input_file, release_input_file): New static variables.
	(onload): Capture new transfer vector entries.
	(claim_file_hook): Stop reading at end of file according to filesize.
	Factor out parsing of readelf output into separate function.
	(all_symbols_read_hook): Exercise get_input_file and release_input_file
	APIs and get the source file name from the symbol table.  Convert
	source file name to corresponding object file name.  Print info
	message when adding new input files.
	(parse_readelf_line): New function.
	* testsuite/plugin_test_1.sh: Add checks for new info messages.
	* testsuite/plugin_test_2.sh: Likewise.
	* testsuite/plugin_test_3.sh: Likewise.
	* testsuite/plugin_test_4.sh: New test case.
-------------- next part --------------
Index: include/plugin-api.h
===================================================================
RCS file: /cvs/src/src/include/plugin-api.h,v
retrieving revision 1.4
diff -u -p -r1.4 plugin-api.h
--- include/plugin-api.h	1 Dec 2008 19:50:49 -0000	1.4
+++ include/plugin-api.h	14 Jan 2009 01:36:11 -0000
@@ -40,6 +40,7 @@ enum ld_plugin_status
 {
   LDPS_OK = 0,
   LDPS_NO_SYMS,         /* Attempt to get symbols that haven't been added. */
+  LDPS_BAD_HANDLE,      /* No claimed object associated with given handle. */
   LDPS_ERR
   /* Additional Error codes TBD.  */
 };
@@ -165,6 +166,20 @@ enum ld_plugin_status
 (*ld_plugin_add_symbols) (void *handle, int nsyms,
                           const struct ld_plugin_symbol *syms);
 
+/* The linker's interface for getting the input file information with
+   an open (possibly re-opened) file descriptor.  */
+
+typedef
+enum ld_plugin_status
+(*ld_plugin_get_input_file) (const void *handle,
+                             struct ld_plugin_input_file *file);
+
+/* The linker's interface for releasing the input file.  */
+
+typedef
+enum ld_plugin_status
+(*ld_plugin_release_input_file) (const void *handle);
+
 /* The linker's interface for retrieving symbol resolution information.  */
 
 typedef
@@ -207,7 +222,9 @@ enum ld_plugin_tag
   LDPT_ADD_SYMBOLS,
   LDPT_GET_SYMBOLS,
   LDPT_ADD_INPUT_FILE,
-  LDPT_MESSAGE
+  LDPT_MESSAGE,
+  LDPT_GET_INPUT_FILE,
+  LDPT_RELEASE_INPUT_FILE
 };
 
 /* The plugin transfer vector.  */
@@ -226,6 +243,8 @@ struct ld_plugin_tv
     ld_plugin_get_symbols tv_get_symbols;
     ld_plugin_add_input_file tv_add_input_file;
     ld_plugin_message tv_message;
+    ld_plugin_get_input_file tv_get_input_file;
+    ld_plugin_release_input_file tv_release_input_file;
   } tv_u;
 };
 
Index: gold/archive.cc
===================================================================
RCS file: /cvs/src/src/gold/archive.cc,v
retrieving revision 1.37
diff -u -p -r1.37 archive.cc
--- gold/archive.cc	29 Sep 2008 21:23:02 -0000	1.37
+++ gold/archive.cc	14 Jan 2009 01:36:12 -0000
@@ -1,6 +1,6 @@
 // archive.cc -- archive support for gold
 
-// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
 // Written by Ian Lance Taylor <iant@google.com>.
 
 // This file is part of gold.
@@ -535,7 +535,6 @@ Archive::get_elf_object_for_member(off_t
         {
           // The input file was claimed by a plugin, and its symbols
           // have been provided by the plugin.
-	  input_file->file().claim_for_plugin();
           return obj;
         }
     }
Index: gold/descriptors.cc
===================================================================
RCS file: /cvs/src/src/gold/descriptors.cc,v
retrieving revision 1.2
diff -u -p -r1.2 descriptors.cc
--- gold/descriptors.cc	19 Sep 2008 22:54:57 -0000	1.2
+++ gold/descriptors.cc	14 Jan 2009 01:36:12 -0000
@@ -1,6 +1,6 @@
 // descriptors.cc -- manage file descriptors for gold
 
-// Copyright 2008 Free Software Foundation, Inc.
+// Copyright 2008, 2009 Free Software Foundation, Inc.
 // Written by Ian Lance Taylor <iant@google.com>.
 
 // This file is part of gold.
@@ -115,9 +115,7 @@ Descriptors::open(int descriptor, const 
 	  pod->inuse = true;
 	  pod->is_write = (flags & O_ACCMODE) != O_RDONLY;
 
-          if (!pod->is_claimed)
-	    ++this->current_;
-          pod->is_claimed = false;
+	  ++this->current_;
 	  if (this->current_ >= this->limit_)
 	    this->close_some_descriptor();
 
@@ -168,24 +166,6 @@ Descriptors::release(int descriptor, boo
     }
 }
 
-// Claim the file descriptor DESCRIPTOR for a plugin.  This effectively
-// removes the descriptor from the pool of linker-managed descriptors,
-// as the plugin will assume responsibility for closing it.
-// The IS_CLAIMED flag allows us to recognize when a file descriptor
-// has been reused after being closed by the plugin.
-
-void
-Descriptors::claim_for_plugin(int descriptor)
-{
-  Hold_lock hl(*this->lock_);
-
-  gold_assert(descriptor >= 0
-	      && (static_cast<size_t>(descriptor)
-		  < this->open_descriptors_.size()));
-  Open_descriptor* pod = &this->open_descriptors_[descriptor];
-  pod->is_claimed = true;
-}
-
 // Close some descriptor.  The lock is held when this is called.  We
 // close the descriptor on the top of the free stack.  Note that this
 // is the opposite of an LRU algorithm--we close the most recently
Index: gold/descriptors.h
===================================================================
RCS file: /cvs/src/src/gold/descriptors.h,v
retrieving revision 1.2
diff -u -p -r1.2 descriptors.h
--- gold/descriptors.h	19 Sep 2008 22:54:57 -0000	1.2
+++ gold/descriptors.h	14 Jan 2009 01:36:12 -0000
@@ -1,6 +1,6 @@
 // descriptors.h -- manage file descriptors for gold   -*- C++ -*-
 
-// Copyright 2008 Free Software Foundation, Inc.
+// Copyright 2008, 2009 Free Software Foundation, Inc.
 // Written by Ian Lance Taylor <iant@google.com>.
 
 // This file is part of gold.
@@ -56,12 +56,6 @@ class Descriptors
   void
   release(int descriptor, bool permanent);
 
-  // Claim the file descriptor DESCRIPTOR for a plugin.  This effectively
-  // removes the descriptor from the pool of linker-managed descriptors,
-  // as the plugin will assume responsibility for closing it.
-  void
-  claim_for_plugin(int descriptor);
-
  private:
   // Information kept for a descriptor.
   struct Open_descriptor
@@ -75,8 +69,6 @@ class Descriptors
     bool inuse;
     // Whether this is a write descriptor.
     bool is_write;
-    // Whether the descriptor has been claimed for a plugin.
-    bool is_claimed;
   };
 
   bool
@@ -108,10 +100,6 @@ inline void
 release_descriptor(int descriptor, bool permanent)
 { descriptors.release(descriptor, permanent); }
 
-inline void
-claim_descriptor_for_plugin(int descriptor)
-{ descriptors.claim_for_plugin(descriptor); }
-
 } // End namespace gold.
 
 #endif // !defined(GOLD_DESCRIPTORS_H)
Index: gold/fileread.cc
===================================================================
RCS file: /cvs/src/src/gold/fileread.cc,v
retrieving revision 1.46
diff -u -p -r1.46 fileread.cc
--- gold/fileread.cc	19 Sep 2008 22:54:57 -0000	1.46
+++ gold/fileread.cc	14 Jan 2009 01:36:12 -0000
@@ -1,6 +1,6 @@
 // fileread.cc -- read files for gold
 
-// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
 // Written by Ian Lance Taylor <iant@google.com>.
 
 // This file is part of gold.
@@ -191,19 +191,6 @@ File_read::release()
   this->released_ = true;
 }
 
-// Claim the file for a plugin.  This effectively releases the file without
-// closing it; the plugin will assume responsibility for closing it.
-
-void
-File_read::claim_for_plugin()
-{
-  gold_assert(this->is_locked());
-  claim_descriptor_for_plugin(this->descriptor_);
-  this->descriptor_ = -1;
-  this->is_descriptor_opened_ = false;
-  this->released_ = true;
-}
-
 // Lock the file.
 
 void
Index: gold/fileread.h
===================================================================
RCS file: /cvs/src/src/gold/fileread.h,v
retrieving revision 1.31
diff -u -p -r1.31 fileread.h
--- gold/fileread.h	19 Sep 2008 22:54:57 -0000	1.31
+++ gold/fileread.h	14 Jan 2009 01:36:12 -0000
@@ -1,6 +1,6 @@
 // fileread.h -- read files for gold   -*- C++ -*-
 
-// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
 // Written by Ian Lance Taylor <iant@google.com>.
 
 // This file is part of gold.
@@ -109,11 +109,6 @@ class File_read
   void
   release();
 
-  // Claim the file for a plugin.  This effectively releases the file without
-  // closing it; the plugin will assume responsibility for closing it.
-  void
-  claim_for_plugin();
-
   // Return the size of the file.
   off_t
   filesize() const
@@ -190,9 +185,9 @@ class File_read
 
   // Return the open file descriptor (for plugins).
   int
-  descriptor() const
+  descriptor()
   {
-    gold_assert(this->descriptor_ >= 0);
+    this->reopen_descriptor();
     return this->descriptor_;
   }
 
Index: gold/plugin.cc
===================================================================
RCS file: /cvs/src/src/gold/plugin.cc,v
retrieving revision 1.8
diff -u -p -r1.8 plugin.cc
--- gold/plugin.cc	24 Dec 2008 06:17:18 -0000	1.8
+++ gold/plugin.cc	14 Jan 2009 01:36:12 -0000
@@ -1,6 +1,6 @@
 // plugin.c -- plugin manager for gold      -*- C++ -*-
 
-// 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.
@@ -62,6 +62,12 @@ static enum ld_plugin_status
 add_symbols(void *handle, int nsyms, const struct ld_plugin_symbol *syms);
 
 static enum ld_plugin_status
+get_input_file(const void *handle, struct ld_plugin_input_file *file);
+
+static enum ld_plugin_status
+release_input_file(const void *handle);
+
+static enum ld_plugin_status
 get_symbols(const void *handle, int nsyms, struct ld_plugin_symbol *syms);
 
 static enum ld_plugin_status
@@ -75,7 +81,7 @@ message(int level, const char *format, .
 #endif // ENABLE_PLUGINS
 
 static Pluginobj* make_sized_plugin_object(Input_file* input_file,
-                                           off_t offset);
+                                           off_t offset, off_t filesize);
 
 // Plugin methods.
 
@@ -112,7 +118,7 @@ Plugin::load()
   sscanf(ver, "%d.%d", &major, &minor);
 
   // Allocate and populate a transfer vector.
-  const int tv_fixed_size = 11;
+  const int tv_fixed_size = 13;
   int tv_size = this->args_.size() + tv_fixed_size;
   ld_plugin_tv *tv = new ld_plugin_tv[tv_size];
 
@@ -163,6 +169,14 @@ Plugin::load()
   tv[i].tv_u.tv_add_symbols = add_symbols;
 
   ++i;
+  tv[i].tv_tag = LDPT_GET_INPUT_FILE;
+  tv[i].tv_u.tv_get_input_file = get_input_file;
+
+  ++i;
+  tv[i].tv_tag = LDPT_RELEASE_INPUT_FILE;
+  tv[i].tv_u.tv_release_input_file = release_input_file;
+
+  ++i;
   tv[i].tv_tag = LDPT_GET_SYMBOLS;
   tv[i].tv_u.tv_get_symbols = get_symbols;
 
@@ -283,7 +297,7 @@ Plugin_manager::claim_file(Input_file* i
 // Call the all-symbols-read handlers.
 
 void
-Plugin_manager::all_symbols_read(Workqueue* workqueue,
+Plugin_manager::all_symbols_read(Workqueue* workqueue, Task* task,
                                  Input_objects* input_objects,
 	                         Symbol_table* symtab, Layout* layout,
 	                         Dirsearch* dirpath, Mapfile* mapfile,
@@ -291,6 +305,7 @@ Plugin_manager::all_symbols_read(Workque
 {
   this->in_replacement_phase_ = true;
   this->workqueue_ = workqueue;
+  this->task_ = task;
   this->input_objects_ = input_objects;
   this->symtab_ = symtab;
   this->layout_ = layout;
@@ -344,11 +359,45 @@ Plugin_manager::make_plugin_object(unsig
     return NULL;
 
   Pluginobj* obj = make_sized_plugin_object(this->input_file_,
-                                            this->plugin_input_file_.offset);
+                                            this->plugin_input_file_.offset,
+                                            this->plugin_input_file_.filesize);
   this->objects_.push_back(obj);
   return obj;
 }
 
+// Get the input file information with an open (possibly re-opened)
+// file descriptor.
+
+ld_plugin_status
+Plugin_manager::get_input_file(unsigned int handle,
+                               struct ld_plugin_input_file *file)
+{
+  Pluginobj* obj = this->object(handle);
+  if (obj == NULL)
+    return LDPS_BAD_HANDLE;
+
+  obj->lock(this->task_);
+  file->name = obj->filename().c_str();
+  file->fd = obj->descriptor();
+  file->offset = obj->offset();
+  file->filesize = obj->filesize();
+  file->handle = reinterpret_cast<void*>(handle);
+  return LDPS_OK;
+}
+
+// Release the input file.
+
+ld_plugin_status
+Plugin_manager::release_input_file(unsigned int handle)
+{
+  Pluginobj* obj = this->object(handle);
+  if (obj == NULL)
+    return LDPS_BAD_HANDLE;
+
+  obj->unlock(this->task_);
+  return LDPS_OK;
+}
+
 // Add a new input file.
 
 ld_plugin_status
@@ -375,9 +424,9 @@ Plugin_manager::add_input_file(char *pat
 // Class Pluginobj.
 
 Pluginobj::Pluginobj(const std::string& name, Input_file* input_file,
-                     off_t offset)
+                     off_t offset, off_t filesize)
   : Object(name, input_file, false, offset),
-    nsyms_(0), syms_(NULL), symbols_(), comdat_map_()
+    nsyms_(0), syms_(NULL), symbols_(), filesize_(filesize), comdat_map_()
 {
 }
 
@@ -468,8 +517,9 @@ template<int size, bool big_endian>
 Sized_pluginobj<size, big_endian>::Sized_pluginobj(
     const std::string& name,
     Input_file* input_file,
-    off_t offset)
-  : Pluginobj(name, input_file, offset)
+    off_t offset,
+    off_t filesize)
+  : Pluginobj(name, input_file, offset, filesize)
 {
 }
 
@@ -822,6 +872,7 @@ Plugin_hook::run(Workqueue* workqueue)
 {
   gold_assert(this->options_.has_plugins());
   this->options_.plugins()->all_symbols_read(workqueue,
+                                             this,
                                              this->input_objects_,
                                              this->symtab_,
                                              this->layout_,
@@ -880,6 +931,29 @@ add_symbols(void* handle, int nsyms, con
   return LDPS_OK;
 }
 
+// Get the input file information with an open (possibly re-opened)
+// file descriptor.
+
+static enum ld_plugin_status
+get_input_file(const void *handle, struct ld_plugin_input_file *file)
+{
+  gold_assert(parameters->options().has_plugins());
+  unsigned int obj_index =
+      static_cast<unsigned int>(reinterpret_cast<intptr_t>(handle));
+  return parameters->options().plugins()->get_input_file(obj_index, file);
+}
+
+// Release the input file.
+
+static enum ld_plugin_status
+release_input_file(const void *handle)
+{
+  gold_assert(parameters->options().has_plugins());
+  unsigned int obj_index =
+      static_cast<unsigned int>(reinterpret_cast<intptr_t>(handle));
+  return parameters->options().plugins()->release_input_file(obj_index);
+}
+
 // Get the symbol resolution info for a plugin-claimed input file.
 
 static enum ld_plugin_status
@@ -936,7 +1010,7 @@ message(int level, const char * format, 
 // Allocate a Pluginobj object of the appropriate size and endianness.
 
 static Pluginobj*
-make_sized_plugin_object(Input_file* input_file, off_t offset)
+make_sized_plugin_object(Input_file* input_file, off_t offset, off_t filesize)
 {
   Target* target;
   Pluginobj* obj = NULL;
@@ -951,7 +1025,7 @@ make_sized_plugin_object(Input_file* inp
       if (target->is_big_endian())
 #ifdef HAVE_TARGET_32_BIG
         obj = new Sized_pluginobj<32, true>(input_file->filename(),
-                                            input_file, offset);
+                                            input_file, offset, filesize);
 #else
         gold_error(_("%s: not configured to support "
 		     "32-bit big-endian object"),
@@ -960,7 +1034,7 @@ make_sized_plugin_object(Input_file* inp
       else
 #ifdef HAVE_TARGET_32_LITTLE
         obj = new Sized_pluginobj<32, false>(input_file->filename(),
-                                             input_file, offset);
+                                             input_file, offset, filesize);
 #else
         gold_error(_("%s: not configured to support "
 		     "32-bit little-endian object"),
@@ -972,7 +1046,7 @@ make_sized_plugin_object(Input_file* inp
       if (target->is_big_endian())
 #ifdef HAVE_TARGET_64_BIG
         obj = new Sized_pluginobj<64, true>(input_file->filename(),
-                                            input_file, offset);
+                                            input_file, offset, filesize);
 #else
         gold_error(_("%s: not configured to support "
 		     "64-bit big-endian object"),
@@ -981,7 +1055,7 @@ make_sized_plugin_object(Input_file* inp
       else
 #ifdef HAVE_TARGET_64_LITTLE
         obj = new Sized_pluginobj<64, false>(input_file->filename(),
-                                             input_file, offset);
+                                             input_file, offset, filesize);
 #else
         gold_error(_("%s: not configured to support "
 		     "64-bit little-endian object"),
Index: gold/plugin.h
===================================================================
RCS file: /cvs/src/src/gold/plugin.h,v
retrieving revision 1.4
diff -u -p -r1.4 plugin.h
--- gold/plugin.h	24 Dec 2008 06:17:18 -0000	1.4
+++ gold/plugin.h	14 Jan 2009 01:36:12 -0000
@@ -1,6 +1,6 @@
 // plugin.h -- plugin manager for gold      -*- C++ -*-
 
-// 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.
@@ -122,8 +122,9 @@ class Plugin_manager
   Plugin_manager(const General_options& options)
     : plugins_(), objects_(), deferred_layout_objects_(), input_file_(NULL),
       plugin_input_file_(), in_replacement_phase_(false), cleanup_done_(false),
-      options_(options), workqueue_(NULL), input_objects_(NULL), symtab_(NULL),
-      layout_(NULL), dirpath_(NULL), mapfile_(NULL), this_blocker_(NULL)
+      options_(options), workqueue_(NULL), task_(NULL), input_objects_(NULL),
+      symtab_(NULL), layout_(NULL), dirpath_(NULL), mapfile_(NULL),
+      this_blocker_(NULL)
   { this->current_ = plugins_.end(); }
 
   ~Plugin_manager();
@@ -151,9 +152,10 @@ class Plugin_manager
 
   // Call the all-symbols-read handlers.
   void
-  all_symbols_read(Workqueue* workqueue, Input_objects* input_objects,
-                   Symbol_table* symtab, Layout* layout, Dirsearch* dirpath,
-                   Mapfile* mapfile, Task_token** last_blocker);
+  all_symbols_read(Workqueue* workqueue, Task* task,
+                   Input_objects* input_objects, Symbol_table* symtab,
+                   Layout* layout, Dirsearch* dirpath, Mapfile* mapfile,
+                   Task_token** last_blocker);
 
   // Run deferred layout.
   void
@@ -214,6 +216,15 @@ class Plugin_manager
   add_deferred_layout_object(Relobj* obj)
   { this->deferred_layout_objects_.push_back(obj); }
 
+  // Get input file information with an open (possibly re-opened)
+  // file descriptor.
+  ld_plugin_status
+  get_input_file(unsigned int handle, struct ld_plugin_input_file *file);
+
+  // Release an input file.
+  ld_plugin_status
+  release_input_file(unsigned int handle);
+
   // Add a new input file.
   ld_plugin_status
   add_input_file(char *pathname);
@@ -257,6 +268,7 @@ class Plugin_manager
 
   const General_options& options_;
   Workqueue* workqueue_;
+  Task* task_;
   Input_objects* input_objects_;
   Symbol_table* symtab_;
   Layout* layout_;
@@ -275,7 +287,8 @@ class Pluginobj : public Object
 
   typedef std::vector<Symbol*> Symbols;
 
-  Pluginobj(const std::string& name, Input_file* input_file, off_t offset);
+  Pluginobj(const std::string& name, Input_file* input_file, off_t offset,
+            off_t filesize);
 
   // Fill in the symbol resolution status for the given plugin symbols.
   ld_plugin_status
@@ -299,6 +312,21 @@ class Pluginobj : public Object
   bool
   include_comdat_group(std::string comdat_key, Layout* layout);
 
+  // Return the filename.
+  const std::string&
+  filename() const
+  { return this->input_file()->filename(); }
+
+  // Return the file descriptor.
+  int
+  descriptor()
+  { return this->input_file()->file().descriptor(); }
+
+  // Return the size of the file or archive member.
+  off_t
+  filesize()
+  { return this->filesize_; }
+
  protected:
   // Return TRUE if this is an object claimed by a plugin.
   virtual Pluginobj*
@@ -320,6 +348,8 @@ class Pluginobj : public Object
   Symbols symbols_;
 
  private:
+  // Size of the file (or archive member).
+  off_t filesize_;
   // Map a comdat key symbol to a boolean indicating whether the comdat
   // group in this object with that key should be kept.
   typedef Unordered_map<std::string, bool> Comdat_map;
@@ -333,7 +363,7 @@ class Sized_pluginobj : public Pluginobj
 {
  public:
   Sized_pluginobj(const std::string& name, Input_file* input_file,
-                  off_t offset);
+                  off_t offset, off_t filesize);
 
   // Read the symbols.
   void
Index: gold/readsyms.cc
===================================================================
RCS file: /cvs/src/src/gold/readsyms.cc,v
retrieving revision 1.31
diff -u -p -r1.31 readsyms.cc
--- gold/readsyms.cc	19 Sep 2008 22:54:57 -0000	1.31
+++ gold/readsyms.cc	14 Jan 2009 01:36:12 -0000
@@ -1,6 +1,6 @@
 // readsyms.cc -- read input file symbols for gold
 
-// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
 // Written by Ian Lance Taylor <iant@google.com>.
 
 // This file is part of gold.
@@ -196,8 +196,10 @@ Read_symbols::do_read_symbols(Workqueue*
         {
           // The input file was claimed by a plugin, and its symbols
           // have been provided by the plugin.
-	  input_file->file().claim_for_plugin();
-	  input_file->file().unlock(this);
+
+          // We are done with the file at this point, so unlock it.
+          obj->unlock(this);
+
           workqueue->queue_next(new Add_plugin_symbols(this->symtab_,
                                                        this->layout_,
                                                        obj,
Index: gold/testsuite/Makefile.am
===================================================================
RCS file: /cvs/src/src/gold/testsuite/Makefile.am,v
retrieving revision 1.82
diff -u -p -r1.82 Makefile.am
--- gold/testsuite/Makefile.am	23 Dec 2008 23:46:55 -0000	1.82
+++ gold/testsuite/Makefile.am	14 Jan 2009 01:36:12 -0000
@@ -981,6 +981,18 @@ plugin_test_3: two_file_test_main.o two_
 plugin_test_3.err: plugin_test_3
 	@touch plugin_test_3.err
 
+check_PROGRAMS += plugin_test_4
+check_SCRIPTS += plugin_test_4.sh
+check_DATA += plugin_test_4.err
+MOSTLYCLEANFILES += plugin_test_4.err
+plugin_test_4: two_file_test_main.o plugin_test_4.a gcctestdir/ld plugin_test.so
+	$(CXXLINK) -Bgcctestdir/ -Wl,--no-demangle,--plugin,"./plugin_test.so",--plugin-opt,"_Z4f13iv" two_file_test_main.o -Wl,--whole-archive,plugin_test_4.a,--no-whole-archive 2>plugin_test_4.err
+plugin_test_4.err: plugin_test_4
+	@touch plugin_test_4.err
+
+plugin_test_4.a: two_file_test_1.syms two_file_test_1b.syms two_file_test_2.syms
+	$(TEST_AR) cr $@ $^
+
 plugin_test.so: plugin_test.o
 	$(LINK) -Bgcctestdir/ -shared plugin_test.o
 plugin_test.o: plugin_test.c
Index: gold/testsuite/Makefile.in
===================================================================
RCS file: /cvs/src/src/gold/testsuite/Makefile.in,v
retrieving revision 1.87
diff -u -p -r1.87 Makefile.in
--- gold/testsuite/Makefile.in	23 Dec 2008 23:46:55 -0000	1.87
+++ gold/testsuite/Makefile.in	14 Jan 2009 01:36:12 -0000
@@ -293,19 +293,23 @@ check_PROGRAMS = object_unittest$(EXEEXT
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@am__append_20 =  \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_test_1 \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_test_2 \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_test_3
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_test_3 \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_test_4
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@am__append_21 =  \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_test_1.sh \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_test_2.sh \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_test_3.sh
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_test_3.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_test_4.sh
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@am__append_22 =  \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_test_1.err \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_test_2.err \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_test_3.err
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_test_3.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_test_4.err
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@am__append_23 =  \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_test_1.err \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_test_2.err \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_test_3.err
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_test_3.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_test_4.err
 subdir = testsuite
 DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
@@ -407,7 +411,8 @@ libgoldtest_a_OBJECTS = $(am_libgoldtest
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	thin_archive_test_2$(EXEEXT)
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@am__EXEEXT_16 = plugin_test_1$(EXEEXT) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_test_2$(EXEEXT) \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_test_3$(EXEEXT)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_test_3$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_test_4$(EXEEXT)
 basic_pic_test_SOURCES = basic_pic_test.c
 basic_pic_test_OBJECTS = basic_pic_test.$(OBJEXT)
 basic_pic_test_LDADD = $(LDADD)
@@ -582,6 +587,12 @@ plugin_test_3_LDADD = $(LDADD)
 plugin_test_3_DEPENDENCIES = libgoldtest.a ../libgold.a \
 	../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+plugin_test_4_SOURCES = plugin_test_4.c
+plugin_test_4_OBJECTS = plugin_test_4.$(OBJEXT)
+plugin_test_4_LDADD = $(LDADD)
+plugin_test_4_DEPENDENCIES = libgoldtest.a ../libgold.a \
+	../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
 am__protected_1_SOURCES_DIST = protected_main_1.cc protected_main_2.cc \
 	protected_main_3.cc
 @GCC_TRUE@@NATIVE_LINKER_TRUE@am_protected_1_OBJECTS =  \
@@ -866,7 +877,7 @@ SOURCES = $(libgoldtest_a_SOURCES) basic
 	$(initpri1_SOURCES) $(justsyms_SOURCES) many_sections_r_test.c \
 	$(many_sections_test_SOURCES) $(object_unittest_SOURCES) \
 	plugin_test_1.c plugin_test_2.c plugin_test_3.c \
-	$(protected_1_SOURCES) $(protected_2_SOURCES) \
+	plugin_test_4.c $(protected_1_SOURCES) $(protected_2_SOURCES) \
 	$(relro_script_test_SOURCES) $(relro_test_SOURCES) \
 	$(script_test_1_SOURCES) $(script_test_2_SOURCES) \
 	script_test_3.c $(thin_archive_test_1_SOURCES) \
@@ -918,7 +929,8 @@ DIST_SOURCES = $(libgoldtest_a_SOURCES) 
 	$(am__initpri1_SOURCES_DIST) $(am__justsyms_SOURCES_DIST) \
 	many_sections_r_test.c $(am__many_sections_test_SOURCES_DIST) \
 	$(object_unittest_SOURCES) plugin_test_1.c plugin_test_2.c \
-	plugin_test_3.c $(am__protected_1_SOURCES_DIST) \
+	plugin_test_3.c plugin_test_4.c \
+	$(am__protected_1_SOURCES_DIST) \
 	$(am__protected_2_SOURCES_DIST) \
 	$(am__relro_script_test_SOURCES_DIST) \
 	$(am__relro_test_SOURCES_DIST) \
@@ -1637,6 +1649,15 @@ object_unittest$(EXEEXT): $(object_unitt
 @PLUGINS_FALSE@plugin_test_3$(EXEEXT): $(plugin_test_3_OBJECTS) $(plugin_test_3_DEPENDENCIES) 
 @PLUGINS_FALSE@	@rm -f plugin_test_3$(EXEEXT)
 @PLUGINS_FALSE@	$(LINK) $(plugin_test_3_LDFLAGS) $(plugin_test_3_OBJECTS) $(plugin_test_3_LDADD) $(LIBS)
+@GCC_FALSE@plugin_test_4$(EXEEXT): $(plugin_test_4_OBJECTS) $(plugin_test_4_DEPENDENCIES) 
+@GCC_FALSE@	@rm -f plugin_test_4$(EXEEXT)
+@GCC_FALSE@	$(LINK) $(plugin_test_4_LDFLAGS) $(plugin_test_4_OBJECTS) $(plugin_test_4_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@plugin_test_4$(EXEEXT): $(plugin_test_4_OBJECTS) $(plugin_test_4_DEPENDENCIES) 
+@NATIVE_LINKER_FALSE@	@rm -f plugin_test_4$(EXEEXT)
+@NATIVE_LINKER_FALSE@	$(LINK) $(plugin_test_4_LDFLAGS) $(plugin_test_4_OBJECTS) $(plugin_test_4_LDADD) $(LIBS)
+@PLUGINS_FALSE@plugin_test_4$(EXEEXT): $(plugin_test_4_OBJECTS) $(plugin_test_4_DEPENDENCIES) 
+@PLUGINS_FALSE@	@rm -f plugin_test_4$(EXEEXT)
+@PLUGINS_FALSE@	$(LINK) $(plugin_test_4_LDFLAGS) $(plugin_test_4_OBJECTS) $(plugin_test_4_LDADD) $(LIBS)
 protected_1$(EXEEXT): $(protected_1_OBJECTS) $(protected_1_DEPENDENCIES) 
 	@rm -f protected_1$(EXEEXT)
 	$(CXXLINK) $(protected_1_LDFLAGS) $(protected_1_OBJECTS) $(protected_1_LDADD) $(LIBS)
@@ -1823,6 +1844,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_test_1.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_test_2.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_test_3.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_test_4.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/protected_3.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/protected_main_1.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/protected_main_2.Po@am__quote@
@@ -2487,6 +2509,13 @@ uninstall-am: uninstall-info-am
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	$(CXXLINK) -Bgcctestdir/ -Wl,--export-dynamic -Wl,--no-demangle,--plugin,"./plugin_test.so",--plugin-opt,"_Z4f13iv" two_file_test_main.o two_file_test_1.syms two_file_test_1b.syms two_file_test_2.syms empty.syms 2>plugin_test_3.err
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_test_3.err: plugin_test_3
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	@touch plugin_test_3.err
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_test_4: two_file_test_main.o plugin_test_4.a gcctestdir/ld plugin_test.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	$(CXXLINK) -Bgcctestdir/ -Wl,--no-demangle,--plugin,"./plugin_test.so",--plugin-opt,"_Z4f13iv" two_file_test_main.o -Wl,--whole-archive,plugin_test_4.a,--no-whole-archive 2>plugin_test_4.err
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_test_4.err: plugin_test_4
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	@touch plugin_test_4.err
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_test_4.a: two_file_test_1.syms two_file_test_1b.syms two_file_test_2.syms
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	$(TEST_AR) cr $@ $^
 
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_test.so: plugin_test.o
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	$(LINK) -Bgcctestdir/ -shared plugin_test.o
Index: gold/testsuite/plugin_test.c
===================================================================
RCS file: /cvs/src/src/gold/testsuite/plugin_test.c,v
retrieving revision 1.2
diff -u -p -r1.2 plugin_test.c
--- gold/testsuite/plugin_test.c	16 Dec 2008 19:19:16 -0000	1.2
+++ gold/testsuite/plugin_test.c	14 Jan 2009 01:36:12 -0000
@@ -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
 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(co
 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_
   /* 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_
   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_
       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_
           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;
+}
Index: gold/testsuite/plugin_test_1.sh
===================================================================
RCS file: /cvs/src/src/gold/testsuite/plugin_test_1.sh,v
retrieving revision 1.1
diff -u -p -r1.1 plugin_test_1.sh
--- gold/testsuite/plugin_test_1.sh	19 Sep 2008 22:54:57 -0000	1.1
+++ gold/testsuite/plugin_test_1.sh	14 Jan 2009 01:36:12 -0000
@@ -2,7 +2,7 @@
 
 # plugin_test_1.sh -- a test case for the plugin API.
 
-# 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.
@@ -51,6 +51,9 @@ check plugin_test_1.err "two_file_test_1
 check plugin_test_1.err "two_file_test_1.syms: v2: RESOLVED_IR"
 check plugin_test_1.err "two_file_test_1.syms: t17data: RESOLVED_IR"
 check plugin_test_1.err "two_file_test_2.syms: _Z4f13iv: PREEMPTED_IR"
+check plugin_test_1.err "two_file_test_1.o: adding new input file"
+check plugin_test_1.err "two_file_test_1b.o: adding new input file"
+check plugin_test_1.err "two_file_test_2.o: adding new input file"
 check plugin_test_1.err "cleanup hook called"
 
 exit 0
Index: gold/testsuite/plugin_test_2.sh
===================================================================
RCS file: /cvs/src/src/gold/testsuite/plugin_test_2.sh,v
retrieving revision 1.1
diff -u -p -r1.1 plugin_test_2.sh
--- gold/testsuite/plugin_test_2.sh	19 Sep 2008 22:54:57 -0000	1.1
+++ gold/testsuite/plugin_test_2.sh	14 Jan 2009 01:36:12 -0000
@@ -2,7 +2,7 @@
 
 # plugin_test_2.sh -- a test case for the plugin API.
 
-# 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.
@@ -49,6 +49,8 @@ check plugin_test_2.err "two_file_test_1
 check plugin_test_2.err "two_file_test_1.syms: _Z2t2v: PREVAILING_DEF_REG"
 check plugin_test_2.err "two_file_test_1.syms: v2: RESOLVED_DYN"
 check plugin_test_2.err "two_file_test_1.syms: t17data: RESOLVED_DYN"
+check plugin_test_2.err "two_file_test_1.o: adding new input file"
+check plugin_test_2.err "two_file_test_1b.o: adding new input file"
 check plugin_test_2.err "cleanup hook called"
 
 exit 0
Index: gold/testsuite/plugin_test_3.sh
===================================================================
RCS file: /cvs/src/src/gold/testsuite/plugin_test_3.sh,v
retrieving revision 1.1
diff -u -p -r1.1 plugin_test_3.sh
--- gold/testsuite/plugin_test_3.sh	23 Dec 2008 23:46:55 -0000	1.1
+++ gold/testsuite/plugin_test_3.sh	14 Jan 2009 01:36:12 -0000
@@ -2,7 +2,7 @@
 
 # plugin_test_3.sh -- a test case for the plugin API.
 
-# 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.
@@ -51,6 +51,9 @@ check plugin_test_3.err "two_file_test_1
 check plugin_test_3.err "two_file_test_1.syms: v2: RESOLVED_IR"
 check plugin_test_3.err "two_file_test_1.syms: t17data: RESOLVED_IR"
 check plugin_test_3.err "two_file_test_2.syms: _Z4f13iv: PREEMPTED_IR"
+check plugin_test_3.err "two_file_test_1.o: adding new input file"
+check plugin_test_3.err "two_file_test_1b.o: adding new input file"
+check plugin_test_3.err "two_file_test_2.o: adding new input file"
 check plugin_test_3.err "cleanup hook called"
 
 exit 0
Index: gold/testsuite/plugin_test_4.sh
===================================================================
RCS file: gold/testsuite/plugin_test_4.sh
diff -N gold/testsuite/plugin_test_4.sh
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gold/testsuite/plugin_test_4.sh	14 Jan 2009 01:36:12 -0000
@@ -0,0 +1,58 @@
+#!/bin/sh
+
+# plugin_test_4.sh -- a test case for the plugin API.
+
+# Copyright 2009 Free Software Foundation, Inc.
+# Written by Cary Coutant <ccoutant@google.com>.
+
+# This file is part of gold.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+# This file goes with plugin_test_4.c, a simple plug-in library that
+# exercises the basic interfaces and prints out version numbers and
+# options passed to the plugin.
+
+check()
+{
+    if ! grep -q "$2" "$1"
+    then
+	echo "Did not find expected output in $1:"
+	echo "   $2"
+	echo ""
+	echo "Actual output below:"
+	cat "$1"
+	exit 1
+    fi
+}
+
+check plugin_test_4.err "API version:"
+check plugin_test_4.err "gold version:"
+check plugin_test_4.err "option: _Z4f13iv"
+check plugin_test_4.err "two_file_test_main.o: claim file hook called"
+check plugin_test_4.err "plugin_test_4.a: claim file hook called"
+check plugin_test_4.err "plugin_test_4.a: claiming file"
+check plugin_test_4.err "plugin_test_4.a: _Z4f13iv: PREVAILING_DEF_IRONLY"
+check plugin_test_4.err "plugin_test_4.a: _Z2t2v: PREVAILING_DEF_REG"
+check plugin_test_4.err "plugin_test_4.a: v2: RESOLVED_IR"
+check plugin_test_4.err "plugin_test_4.a: t17data: RESOLVED_IR"
+check plugin_test_4.err "plugin_test_4.a: _Z4f13iv: PREEMPTED_IR"
+check plugin_test_4.err "two_file_test_1.o: adding new input file"
+check plugin_test_4.err "two_file_test_1b.o: adding new input file"
+check plugin_test_4.err "two_file_test_2.o: adding new input file"
+check plugin_test_4.err "cleanup hook called"
+
+exit 0


More information about the Binutils mailing list