// plugin.cc -- plugin manager for gold -*- C++ -*-
-// Copyright 2008, 2009 Free Software Foundation, Inc.
+// Copyright 2008, 2009, 2010 Free Software Foundation, Inc.
// Written by Cary Coutant <ccoutant@google.com>.
// This file is part of gold.
// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
// MA 02110-1301, USA.
+#include "gold.h"
+
#include <cstdio>
#include <cstdarg>
#include <cstring>
#include <string>
#include <vector>
+
+#ifdef ENABLE_PLUGINS
#include <dlfcn.h>
+#endif
-#include "gold.h"
#include "parameters.h"
#include "errors.h"
#include "fileread.h"
static enum ld_plugin_status
add_input_file(char *pathname);
+static enum ld_plugin_status
+add_input_library(char *pathname);
+
static enum ld_plugin_status
message(int level, const char *format, ...);
}
// Find the plugin's onload entry point.
- ld_plugin_onload onload = reinterpret_cast<ld_plugin_onload>
- (dlsym(this->handle_, "onload"));
- if (onload == NULL)
+ void* ptr = dlsym(this->handle_, "onload");
+ if (ptr == NULL)
{
gold_error(_("%s: could not find onload entry point"),
this->filename_.c_str());
return;
}
+ ld_plugin_onload onload;
+ gold_assert(sizeof(onload) == sizeof(ptr));
+ memcpy(&onload, &ptr, sizeof(ptr));
// Get the linker's version number.
const char* ver = get_version_string();
sscanf(ver, "%d.%d", &major, &minor);
// Allocate and populate a transfer vector.
- const int tv_fixed_size = 13;
+ const int tv_fixed_size = 14;
int tv_size = this->args_.size() + tv_fixed_size;
ld_plugin_tv *tv = new ld_plugin_tv[tv_size];
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_ADD_INPUT_LIBRARY;
+ tv[i].tv_u.tv_add_input_library = add_input_library;
+
++i;
tv[i].tv_tag = LDPT_NULL;
tv[i].tv_u.tv_val = 0;
inline void
Plugin::cleanup()
{
- if (this->cleanup_handler_ != NULL)
- (*this->cleanup_handler_)();
+ if (this->cleanup_handler_ != NULL && !this->cleanup_done_)
+ {
+ // Set this flag before calling to prevent a recursive plunge
+ // in the event that a plugin's cleanup handler issues a
+ // fatal error.
+ this->cleanup_done_ = true;
+ (*this->cleanup_handler_)();
+ }
}
// Plugin_manager methods.
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
// Add a new input file.
ld_plugin_status
-Plugin_manager::add_input_file(char *pathname)
+Plugin_manager::add_input_file(char *pathname, bool is_lib)
{
- Input_file_argument file(pathname, false, "", false, this->options_);
+ Input_file_argument file(pathname,
+ (is_lib
+ ? Input_file_argument::INPUT_FILE_TYPE_LIBRARY
+ : Input_file_argument::INPUT_FILE_TYPE_FILE),
+ "", false, this->options_);
Input_argument* input_argument = new Input_argument(file);
Task_token* next_blocker = new Task_token(true);
next_blocker->add_blocker();
if (this->layout_->incremental_inputs())
- gold_error(_("Input files added by plug-ins in --incremental mode not "
- "supported yet.\n"));
+ gold_error(_("input files added by plug-ins in --incremental mode not "
+ "supported yet"));
this->workqueue_->queue_soon(new Read_symbols(this->input_objects_,
this->symtab_,
this->layout_,
this->mapfile_,
input_argument,
NULL,
+ NULL,
this->this_blocker_,
next_blocker));
this->this_blocker_ = next_blocker;
{
if (nsyms > this->nsyms_)
return LDPS_NO_SYMS;
+
+ if (static_cast<size_t>(nsyms) > this->symbols_.size())
+ {
+ // We never decided to include this object. We mark all symbols as
+ // preempted.
+ gold_assert (this->symbols_.size() == 0);
+ for (int i = 0; i < nsyms; i++)
+ syms[i].resolution = LDPR_PREEMPTED_REG;
+ return LDPS_OK;
+ }
+
for (int i = 0; i < nsyms; i++)
{
ld_plugin_symbol* isym = &syms[i];
// The original symbol was undefined or common.
if (lsym->source() != Symbol::FROM_OBJECT)
res = LDPR_RESOLVED_EXEC;
+ else if (lsym->object()->pluginobj() == this)
+ res = (is_visible_from_outside(lsym)
+ ? LDPR_PREVAILING_DEF
+ : LDPR_PREVAILING_DEF_IRONLY);
else if (lsym->object()->pluginobj() != NULL)
res = LDPR_RESOLVED_IR;
else if (lsym->object()->is_dynamic())
}
}
+template<int size, bool big_endian>
+Archive::Should_include
+Sized_pluginobj<size, big_endian>::do_should_include_member(
+ Symbol_table* symtab, Read_symbols_data*, std::string* why)
+{
+ char* tmpbuf = NULL;
+ size_t tmpbuflen = 0;
+
+ for (int i = 0; i < this->nsyms_; ++i) {
+ const struct ld_plugin_symbol& sym = this->syms_[i];
+ const char* name = sym.name;
+ Symbol* symbol;
+ Archive::Should_include t = Archive::should_include_member(symtab, name,
+ &symbol, why,
+ &tmpbuf,
+ &tmpbuflen);
+ if (t == Archive::SHOULD_INCLUDE_YES)
+ {
+ if (tmpbuf != NULL)
+ free(tmpbuf);
+ return t;
+ }
+ }
+ if (tmpbuf != NULL)
+ free(tmpbuf);
+ return Archive::SHOULD_INCLUDE_UNKNOWN;
+}
+
// Get the size of a section. Not used for plugin objects.
template<int size, bool big_endian>
gold_unreachable();
}
+// Get symbols. Not used for plugin objects.
+
+template<int size, bool big_endian>
+const Object::Symbols*
+Sized_pluginobj<size, big_endian>::do_get_global_symbols() const
+{
+ gold_unreachable();
+}
+
// Class Plugin_finish. This task runs after all replacement files have
// been added. It calls each plugin's cleanup handler.
add_input_file(char *pathname)
{
gold_assert(parameters->options().has_plugins());
- return parameters->options().plugins()->add_input_file(pathname);
+ return parameters->options().plugins()->add_input_file(pathname, false);
+}
+
+// Add a new (real) library required by a plugin.
+
+static enum ld_plugin_status
+add_input_library(char *pathname)
+{
+ gold_assert(parameters->options().has_plugins());
+ return parameters->options().plugins()->add_input_file(pathname, true);
}
// Issue a diagnostic message from a plugin.