X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gold%2Fplugin.cc;h=455037107c65a0efb218bed5072affe2fd71a8dd;hb=727fc41e077139570ea8b8ddfd6c546b2a55627c;hp=a5f7a06f27e526d1255b4a59a100b953f79f7312;hpb=92f03fcbe1cfff6dcca4a3a5185b56f3a9fa358e;p=deliverable%2Fbinutils-gdb.git diff --git a/gold/plugin.cc b/gold/plugin.cc index a5f7a06f27..455037107c 100644 --- a/gold/plugin.cc +++ b/gold/plugin.cc @@ -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 . // 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 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(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(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 Sized_pluginobj::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::do_layout(Symbol_table*, Layout*, // Add the symbols to the symbol table. -template -void -Sized_pluginobj::do_add_symbols(Symbol_table*, - Read_symbols_data*) -{ - gold_unreachable(); -} - template void Sized_pluginobj::do_add_symbols(Symbol_table* symtab, + Read_symbols_data*, Layout* layout) { const int sym_size = elfcpp::Elf_sizes::sym_size; @@ -691,55 +754,17 @@ Sized_pluginobj::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(reinterpret_cast(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(reinterpret_cast(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"),