include/elf/
[deliverable/binutils-gdb.git] / gold / plugin.cc
index a5f7a06f27e526d1255b4a59a100b953f79f7312..455037107c65a0efb218bed5072affe2fd71a8dd 100644 (file)
@@ -1,6 +1,6 @@
-// plugin.c -- plugin manager for gold      -*- C++ -*-
+// plugin.cc -- 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.
@@ -61,6 +61,12 @@ register_cleanup(ld_plugin_cleanup_handler handler);
 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);
 
@@ -68,14 +74,14 @@ static enum ld_plugin_status
 add_input_file(char *pathname);
 
 static enum ld_plugin_status
-message(int level, char *format, ...);
+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.
 
@@ -85,31 +91,13 @@ void
 Plugin::load()
 {
 #ifdef ENABLE_PLUGINS
-  std::string filename;
-  std::vector<std::string> args;
-
-  // Parse the filename and arguments, each separated by commas.
-  // FIXME:  Temporarily allowing semicolon as an argument separator
-  // so args can be passed through gcc's -Wl,... option, which
-  // breaks arguments at the commas.
-  const char* p = this->args_;
-  int n = strcspn(p, ",;");
-  filename.assign(p, n);
-  p += n;
-  while (*p == ',' || *p == ';')
-    {
-      ++p;
-      n = strcspn(p, ",;");
-      args.push_back(std::string(p, n));
-      p += n;
-    }
-
   // Load the plugin library.
   // FIXME: Look for the library in standard locations.
-  this->handle_ = dlopen(filename.c_str(), RTLD_NOW);
+  this->handle_ = dlopen(this->filename_.c_str(), RTLD_NOW);
   if (this->handle_ == NULL)
     {
-      gold_error(_("%s: could not load plugin library"), filename.c_str());
+      gold_error(_("%s: could not load plugin library"),
+                 this->filename_.c_str());
       return;
     }
 
@@ -118,7 +106,8 @@ Plugin::load()
     (dlsym(this->handle_, "onload"));
   if (onload == NULL)
     {
-      gold_error(_("%s: could not find onload entry point"), filename.c_str());
+      gold_error(_("%s: could not find onload entry point"),
+                 this->filename_.c_str());
       return;
     }
 
@@ -129,11 +118,17 @@ Plugin::load()
   sscanf(ver, "%d.%d", &major, &minor);
 
   // Allocate and populate a transfer vector.
-  const int tv_fixed_size = 11;
-  int tv_size = args.size() + tv_fixed_size;
+  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];
 
+  // Put LDPT_MESSAGE at the front of the list so the plugin can use it
+  // while processing subsequent entries.
   int i = 0;
+  tv[i].tv_tag = LDPT_MESSAGE;
+  tv[i].tv_u.tv_message = message;
+
+  ++i;
   tv[i].tv_tag = LDPT_API_VERSION;
   tv[i].tv_u.tv_val = LD_PLUGIN_API_VERSION;
 
@@ -150,11 +145,11 @@ Plugin::load()
   else
     tv[i].tv_u.tv_val = LDPO_EXEC;
 
-  for (unsigned int j = 0; j < args.size(); ++j)
+  for (unsigned int j = 0; j < this->args_.size(); ++j)
     {
       ++i;
       tv[i].tv_tag = LDPT_OPTION;
-      tv[i].tv_u.tv_string = args[j].c_str();
+      tv[i].tv_u.tv_string = this->args_[j].c_str();
     }
 
   ++i;
@@ -173,6 +168,14 @@ Plugin::load()
   tv[i].tv_tag = LDPT_ADD_SYMBOLS;
   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;
@@ -181,10 +184,6 @@ Plugin::load()
   tv[i].tv_tag = LDPT_ADD_INPUT_FILE;
   tv[i].tv_u.tv_add_input_file = add_input_file;
 
-  ++i;
-  tv[i].tv_tag = LDPT_MESSAGE;
-  tv[i].tv_u.tv_message = message;
-
   ++i;
   tv[i].tv_tag = LDPT_NULL;
   tv[i].tv_u.tv_val = 0;
@@ -194,7 +193,7 @@ Plugin::load()
   // Call the onload entry point.
   (*onload)(tv);
 
-  delete tv;
+  delete[] tv;
 #endif // ENABLE_PLUGINS
 }
 
@@ -282,14 +281,13 @@ Plugin_manager::claim_file(Input_file* input_file, off_t offset,
     {
       if ((*this->current_)->claim_file(&this->plugin_input_file_))
         {
-          if (this->objects_.size() <= handle)
-            {
-              gold_error(_("%s: plugin claimed the file "
-                           "but did not provide any symbols"),
-                         this->plugin_input_file_.name);
-              return NULL;
-            }
-          return this->objects_[handle];
+          if (this->objects_.size() > handle)
+            return this->objects_[handle];
+
+          // If the plugin claimed the file but did not call the
+          // add_symbols callback, we need to create the Pluginobj now.
+          Pluginobj* obj = this->make_plugin_object(handle);
+          return obj;
         }
     }
 
@@ -299,7 +297,7 @@ Plugin_manager::claim_file(Input_file* input_file, off_t offset,
 // 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,
@@ -307,6 +305,7 @@ Plugin_manager::all_symbols_read(Workqueue* workqueue,
 {
   this->in_replacement_phase_ = true;
   this->workqueue_ = workqueue;
+  this->task_ = task;
   this->input_objects_ = input_objects;
   this->symtab_ = symtab;
   this->layout_ = layout;
@@ -322,15 +321,31 @@ Plugin_manager::all_symbols_read(Workqueue* workqueue,
   *last_blocker = this->this_blocker_;
 }
 
+// Layout deferred objects.
+
+void
+Plugin_manager::layout_deferred_objects()
+{
+  Deferred_layout_list::iterator obj;
+
+  for (obj = this->deferred_layout_objects_.begin();
+       obj != this->deferred_layout_objects_.end();
+       ++obj)
+    (*obj)->layout_deferred_sections(this->layout_);
+}
+
 // Call the cleanup handlers.
 
 void
 Plugin_manager::cleanup()
 {
+  if (this->cleanup_done_)
+    return;
   for (this->current_ = this->plugins_.begin();
        this->current_ != this->plugins_.end();
        ++this->current_)
     (*this->current_)->cleanup();
+  this->cleanup_done_ = true;
 }
 
 // Make a new Pluginobj object.  This is called when the plugin calls
@@ -344,11 +359,45 @@ Plugin_manager::make_plugin_object(unsigned int handle)
     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,10 +424,25 @@ Plugin_manager::add_input_file(char *pathname)
 // 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_()
+{
+}
+
+// Return TRUE if a defined symbol might be reachable from outside the
+// universe of claimed objects.
+
+static inline bool
+is_visible_from_outside(Symbol* lsym)
 {
+  if (lsym->in_real_elf())
+    return true;
+  if (parameters->options().relocatable())
+    return true;
+  if (parameters->options().export_dynamic() || parameters->options().shared())
+    return lsym->is_externally_visible();
+  return false;
 }
 
 // Get symbol resolution info.
@@ -386,7 +450,7 @@ Pluginobj::Pluginobj(const std::string& name, Input_file* input_file,
 ld_plugin_status
 Pluginobj::get_symbol_resolution_info(int nsyms, ld_plugin_symbol* syms) const
 {
-  if (this->nsyms_ == 0)
+  if (nsyms > this->nsyms_)
     return LDPS_NO_SYMS;
   for (int i = 0; i < nsyms; i++)
     {
@@ -417,7 +481,7 @@ Pluginobj::get_symbol_resolution_info(int nsyms, ld_plugin_symbol* syms) const
           if (lsym->source() != Symbol::FROM_OBJECT)
             res = LDPR_PREEMPTED_REG;
           else if (lsym->object() == static_cast<const Object*>(this))
-            res = (lsym->in_real_elf()
+            res = (is_visible_from_outside(lsym)
                    ? LDPR_PREVAILING_DEF
                    : LDPR_PREVAILING_DEF_IRONLY);
           else
@@ -442,7 +506,12 @@ Pluginobj::include_comdat_group(std::string comdat_key, Layout* layout)
   // If this is the first time we've seen this comdat key, ask the
   // layout object whether it should be included.
   if (ins.second)
-    ins.first->second = layout->add_comdat(NULL, 1, comdat_key, true);
+    {
+      Kept_section to_add(NULL, 1, true);
+      ins.first->second = layout->find_or_add_kept_section(comdat_key,
+                                                          &to_add,
+                                                          NULL);
+    }
 
   return ins.first->second;
 }
@@ -453,8 +522,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)
 {
 }
 
@@ -479,17 +549,10 @@ Sized_pluginobj<size, big_endian>::do_layout(Symbol_table*, Layout*,
 
 // Add the symbols to the symbol table.
 
-template<int size, bool big_endian>
-void
-Sized_pluginobj<size, big_endian>::do_add_symbols(Symbol_table*,
-                                                  Read_symbols_data*)
-{
-  gold_unreachable();
-}
-
 template<int size, bool big_endian>
 void
 Sized_pluginobj<size, big_endian>::do_add_symbols(Symbol_table* symtab,
+                                                  Read_symbols_data*,
                                                   Layout* layout)
 {
   const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
@@ -691,55 +754,17 @@ Sized_pluginobj<size, big_endian>::do_get_global_symbol_counts(const Symbol_tabl
   gold_unreachable();
 }
 
-// Class Add_plugin_symbols.
+// Class Plugin_finish.  This task runs after all replacement files have
+// been added.  It calls each plugin's cleanup handler.
 
-Add_plugin_symbols::~Add_plugin_symbols()
-{
-  if (this->this_blocker_ != NULL)
-    delete this->this_blocker_;
-  // next_blocker_ is deleted by the task associated with the next
-  // input file.
-}
-
-// We are blocked by this_blocker_.  We block next_blocker_.  We also
-// lock the file.
-
-Task_token*
-Add_plugin_symbols::is_runnable()
-{
-  if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked())
-    return this->this_blocker_;
-  if (this->obj_->is_locked())
-    return this->obj_->token();
-  return NULL;
-}
-
-void
-Add_plugin_symbols::locks(Task_locker* tl)
-{
-  tl->add(this, this->next_blocker_);
-  tl->add(this, this->obj_->token());
-}
-
-// Add the symbols in the object to the symbol table.
-
-void
-Add_plugin_symbols::run(Workqueue*)
-{
-  this->obj_->add_symbols(this->symtab_, this->layout_);
-}
-
-// Class Plugin_cleanup.  This task calls the plugin cleanup hooks once all
-// replacement files have been added.
-
-class Plugin_cleanup : public Task
+class Plugin_finish : public Task
 {
  public:
-  Plugin_cleanup(Task_token* this_blocker, Task_token* next_blocker)
+  Plugin_finish(Task_token* this_blocker, Task_token* next_blocker)
     : this_blocker_(this_blocker), next_blocker_(next_blocker)
   { }
 
-  ~Plugin_cleanup()
+  ~Plugin_finish()
   {
     if (this->this_blocker_ != NULL)
       delete this->this_blocker_;
@@ -759,11 +784,15 @@ class Plugin_cleanup : public Task
 
   void
   run(Workqueue*)
-  { parameters->options().plugins()->cleanup(); }
+  {
+    Plugin_manager* plugins = parameters->options().plugins();
+    gold_assert(plugins != NULL);
+    plugins->cleanup();
+  }
 
   std::string
   get_name() const
-  { return "Plugin_cleanup"; }
+  { return "Plugin_finish"; }
 
  private:
   Task_token* this_blocker_;
@@ -794,29 +823,22 @@ Plugin_hook::locks(Task_locker*)
 {
 }
 
-// Run a Plugin_hook task.
-
-void
-Plugin_hook::run(Workqueue* workqueue)
-{
-  this->do_plugin_hook(workqueue);
-}
-
 // Run the "all symbols read" plugin hook.
 
 void
-Plugin_hook::do_plugin_hook(Workqueue* workqueue)
+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_,
                                              this->dirpath_,
                                              this->mapfile_,
                                              &this->this_blocker_);
-  workqueue->queue_soon(new Plugin_cleanup(this->this_blocker_,
-                                          this->next_blocker_));
+  workqueue->queue_soon(new Plugin_finish(this->this_blocker_,
+                                         this->next_blocker_));
 }
 
 // The C interface routines called by the plugins.
@@ -867,6 +889,29 @@ add_symbols(void* handle, int nsyms, const ld_plugin_symbol *syms)
   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
@@ -892,7 +937,7 @@ add_input_file(char *pathname)
 // Issue a diagnostic message from a plugin.
 
 static enum ld_plugin_status
-message(int level, char * format, ...)
+message(int level, const char * format, ...)
 {
   va_list args;
   va_start(args, format);
@@ -923,7 +968,7 @@ message(int level, 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;
@@ -938,7 +983,7 @@ make_sized_plugin_object(Input_file* input_file, off_t offset)
       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"),
@@ -947,7 +992,7 @@ make_sized_plugin_object(Input_file* input_file, off_t offset)
       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"),
@@ -959,7 +1004,7 @@ make_sized_plugin_object(Input_file* input_file, off_t offset)
       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"),
@@ -968,7 +1013,7 @@ make_sized_plugin_object(Input_file* input_file, off_t offset)
       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"),
This page took 0.056009 seconds and 4 git commands to generate.