// plugin.h -- plugin manager for gold -*- C++ -*- // Copyright 2008, 2009 Free Software Foundation, Inc. // Written by Cary Coutant . // 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. #ifndef GOLD_PLUGIN_H #define GOLD_PLUGIN_H #include #include #include "object.h" #include "plugin-api.h" #include "workqueue.h" namespace gold { class General_options; class Input_file; class Input_objects; class Symbol_table; class Layout; class Dirsearch; class Mapfile; class Task_token; class Pluginobj; // This class represents a single plugin library. class Plugin { public: Plugin(const char* filename) : handle_(NULL), filename_(filename), args_(), claim_file_handler_(NULL), all_symbols_read_handler_(NULL), cleanup_handler_(NULL) { } ~Plugin() { } // Load the library and call its entry point. void load(); // Call the claim-file handler. bool claim_file(struct ld_plugin_input_file *plugin_input_file); // Call the all-symbols-read handler. void all_symbols_read(); // Call the cleanup handler. void cleanup(); // Register a claim-file handler. void set_claim_file_handler(ld_plugin_claim_file_handler handler) { this->claim_file_handler_ = handler; } // Register an all-symbols-read handler. void set_all_symbols_read_handler(ld_plugin_all_symbols_read_handler handler) { this->all_symbols_read_handler_ = handler; } // Register a claim-file handler. void set_cleanup_handler(ld_plugin_cleanup_handler handler) { this->cleanup_handler_ = handler; } // Add an argument void add_option(const char *arg) { this->args_.push_back(arg); } private: Plugin(const Plugin&); Plugin& operator=(const Plugin&); // The shared library handle returned by dlopen. void* handle_; // The argument string given to --plugin. std::string filename_; // The list of argument string given to --plugin-opt. std::vector args_; // The plugin's event handlers. ld_plugin_claim_file_handler claim_file_handler_; ld_plugin_all_symbols_read_handler all_symbols_read_handler_; ld_plugin_cleanup_handler cleanup_handler_; }; // A manager class for plugins. class Plugin_manager { public: 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), task_(NULL), input_objects_(NULL), symtab_(NULL), layout_(NULL), dirpath_(NULL), mapfile_(NULL), this_blocker_(NULL) { this->current_ = plugins_.end(); } ~Plugin_manager(); // Add a plugin library. void add_plugin(const char* filename) { this->plugins_.push_back(new Plugin(filename)); } // Add an argument to the current plugin. void add_plugin_option(const char* opt) { Plugin* last = this->plugins_.back(); last->add_option(opt); } // Load all plugin libraries. void load_plugins(); // Call the plugin claim-file handlers in turn to see if any claim the file. Pluginobj* claim_file(Input_file *input_file, off_t offset, off_t filesize); // Call the all-symbols-read handlers. void 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 layout_deferred_objects(); // Call the cleanup handlers. void cleanup(); // Register a claim-file handler. void set_claim_file_handler(ld_plugin_claim_file_handler handler) { gold_assert(this->current_ != plugins_.end()); (*this->current_)->set_claim_file_handler(handler); } // Register an all-symbols-read handler. void set_all_symbols_read_handler(ld_plugin_all_symbols_read_handler handler) { gold_assert(this->current_ != plugins_.end()); (*this->current_)->set_all_symbols_read_handler(handler); } // Register a claim-file handler. void set_cleanup_handler(ld_plugin_cleanup_handler handler) { gold_assert(this->current_ != plugins_.end()); (*this->current_)->set_cleanup_handler(handler); } // Make a new Pluginobj object. This is called when the plugin calls // the add_symbols API. Pluginobj* make_plugin_object(unsigned int handle); // Return the Pluginobj associated with the given HANDLE. Pluginobj* object(unsigned int handle) const { if (handle >= this->objects_.size()) return NULL; return this->objects_[handle]; } // Return TRUE if any input files have been claimed by a plugin // and we are still in the initial input phase. bool should_defer_layout() const { return !this->objects_.empty() && !this->in_replacement_phase_; } // Add a regular object to the deferred layout list. These are // objects whose layout has been deferred until after the // replacement files have arrived. void 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); // Return TRUE if we are in the replacement phase. bool in_replacement_phase() const { return this->in_replacement_phase_; } private: Plugin_manager(const Plugin_manager&); Plugin_manager& operator=(const Plugin_manager&); typedef std::list Plugin_list; typedef std::vector Object_list; typedef std::vector Deferred_layout_list; // The list of plugin libraries. Plugin_list plugins_; // A pointer to the current plugin. Used while loading plugins. Plugin_list::iterator current_; // The list of plugin objects. The index of an item in this list // serves as the "handle" that we pass to the plugins. Object_list objects_; // The list of regular objects whose layout has been deferred. Deferred_layout_list deferred_layout_objects_; // The file currently up for claim by the plugins. Input_file* input_file_; struct ld_plugin_input_file plugin_input_file_; // TRUE after the all symbols read event; indicates that we are // processing replacement files whose symbols should replace the // placeholder symbols from the Pluginobj objects. bool in_replacement_phase_; // TRUE if the cleanup handlers have been called. bool cleanup_done_; const General_options& options_; Workqueue* workqueue_; Task* task_; Input_objects* input_objects_; Symbol_table* symtab_; Layout* layout_; Dirsearch* dirpath_; Mapfile* mapfile_; Task_token* this_blocker_; }; // An object file claimed by a plugin. This is an abstract base class. // The implementation is the template class Sized_pluginobj. class Pluginobj : public Object { public: typedef std::vector Symbols; 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 get_symbol_resolution_info(int nsyms, ld_plugin_symbol* syms) const; // Add symbol information to the global symbol table. void add_symbols(Symbol_table* symtab, Layout* layout) { this->do_add_symbols(symtab, layout); } // Store the incoming symbols from the plugin for later processing. void store_incoming_symbols(int nsyms, const struct ld_plugin_symbol* syms) { this->nsyms_ = nsyms; this->syms_ = syms; } // Return TRUE if the comdat group with key COMDAT_KEY from this object // should be kept. 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* do_pluginobj() { return this; } // Add symbol information to the global symbol table--implemented by // child class. virtual void do_add_symbols(Symbol_table*, Layout*) = 0; // The number of symbols provided by the plugin. int nsyms_; // The symbols provided by the plugin. const struct ld_plugin_symbol* syms_; // The entries in the symbol table for the external symbols. 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 Comdat_map; Comdat_map comdat_map_; }; // A plugin object, size-specific version. template class Sized_pluginobj : public Pluginobj { public: Sized_pluginobj(const std::string& name, Input_file* input_file, off_t offset, off_t filesize); // Read the symbols. void do_read_symbols(Read_symbols_data*); // Lay out the input sections. void do_layout(Symbol_table*, Layout*, Read_symbols_data*); // Add the symbols to the symbol table. void do_add_symbols(Symbol_table*, Read_symbols_data*); void do_add_symbols(Symbol_table*, Layout*); // Get the size of a section. uint64_t do_section_size(unsigned int shndx); // Get the name of a section. std::string do_section_name(unsigned int shndx); // Return a view of the contents of a section. Object::Location do_section_contents(unsigned int shndx); // Return section flags. uint64_t do_section_flags(unsigned int shndx); // Return section address. uint64_t do_section_address(unsigned int shndx); // Return section type. unsigned int do_section_type(unsigned int shndx); // Return the section link field. unsigned int do_section_link(unsigned int shndx); // Return the section link field. unsigned int do_section_info(unsigned int shndx); // Return the section alignment. uint64_t do_section_addralign(unsigned int shndx); // Return the Xindex structure to use. Xindex* do_initialize_xindex(); // Get symbol counts. void do_get_global_symbol_counts(const Symbol_table*, size_t*, size_t*) const; // Add placeholder symbols from a claimed file. ld_plugin_status add_symbols_from_plugin(int nsyms, const ld_plugin_symbol* syms); protected: private: }; // This Task handles adding the symbols to the symbol table. These // tasks must be run in the same order as the arguments appear on the // command line. class Add_plugin_symbols : public Task { public: // THIS_BLOCKER is used to prevent this task from running before the // one for the previous input file. NEXT_BLOCKER is used to prevent // the next task from running. Add_plugin_symbols(Symbol_table* symtab, Layout* layout, Pluginobj* obj, Task_token* this_blocker, Task_token* next_blocker) : symtab_(symtab), layout_(layout), obj_(obj), this_blocker_(this_blocker), next_blocker_(next_blocker) { } ~Add_plugin_symbols(); // The standard Task methods. Task_token* is_runnable(); void locks(Task_locker*); void run(Workqueue*); std::string get_name() const { return "Add_plugin_symbols " + this->obj_->name(); } private: Symbol_table* symtab_; Layout* layout_; Pluginobj* obj_; Task_token* this_blocker_; Task_token* next_blocker_; }; // This Task handles handles the "all symbols read" event hook. // The plugin may add additional input files at this time, which must // be queued for reading. class Plugin_hook : public Task { public: Plugin_hook(const General_options& options, Input_objects* input_objects, Symbol_table* symtab, Layout* layout, Dirsearch* dirpath, Mapfile* mapfile, Task_token* this_blocker, Task_token* next_blocker) : options_(options), input_objects_(input_objects), symtab_(symtab), layout_(layout), dirpath_(dirpath), mapfile_(mapfile), this_blocker_(this_blocker), next_blocker_(next_blocker) { } ~Plugin_hook(); // The standard Task methods. Task_token* is_runnable(); void locks(Task_locker*); void run(Workqueue*); std::string get_name() const { return "Plugin_hook"; } private: const General_options& options_; Input_objects* input_objects_; Symbol_table* symtab_; Layout* layout_; Dirsearch* dirpath_; Mapfile* mapfile_; Task_token* this_blocker_; Task_token* next_blocker_; }; } // End namespace gold. #endif // !defined(GOLD_PLUGIN_H)