Line 87... |
Line 87... |
set_extra_library_path(const char *path);
|
set_extra_library_path(const char *path);
|
|
|
static enum ld_plugin_status
|
static enum ld_plugin_status
|
message(int level, const char *format, ...);
|
message(int level, const char *format, ...);
|
|
|
|
static enum ld_plugin_status
|
|
get_input_section_count(const void* handle, unsigned int* count);
|
|
|
|
static enum ld_plugin_status
|
|
get_input_section_type(const struct ld_plugin_section section,
|
|
unsigned int* type);
|
|
|
|
static enum ld_plugin_status
|
|
get_input_section_name(const struct ld_plugin_section section,
|
|
char** section_name_ptr);
|
|
|
|
static enum ld_plugin_status
|
|
get_input_section_contents(const struct ld_plugin_section section,
|
|
const unsigned char** section_contents,
|
|
size_t* len);
|
|
|
|
static enum ld_plugin_status
|
|
update_section_order(const struct ld_plugin_section *section_list,
|
|
unsigned int num_sections);
|
|
|
|
static enum ld_plugin_status
|
|
allow_section_ordering();
|
|
|
};
|
};
|
|
|
#endif // ENABLE_PLUGINS
|
#endif // ENABLE_PLUGINS
|
|
|
static Pluginobj* make_sized_plugin_object(Input_file* input_file,
|
static Pluginobj* make_sized_plugin_object(Input_file* input_file,
|
Line 131... |
Line 154... |
int major = 0;
|
int major = 0;
|
int minor = 0;
|
int minor = 0;
|
sscanf(ver, "%d.%d", &major, &minor);
|
sscanf(ver, "%d.%d", &major, &minor);
|
|
|
// Allocate and populate a transfer vector.
|
// Allocate and populate a transfer vector.
|
const int tv_fixed_size = 17;
|
const int tv_fixed_size = 23;
|
|
|
int tv_size = this->args_.size() + tv_fixed_size;
|
int tv_size = this->args_.size() + tv_fixed_size;
|
ld_plugin_tv* tv = new ld_plugin_tv[tv_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
|
// Put LDPT_MESSAGE at the front of the list so the plugin can use it
|
// while processing subsequent entries.
|
// while processing subsequent entries.
|
Line 214... |
Line 238... |
++i;
|
++i;
|
tv[i].tv_tag = LDPT_SET_EXTRA_LIBRARY_PATH;
|
tv[i].tv_tag = LDPT_SET_EXTRA_LIBRARY_PATH;
|
tv[i].tv_u.tv_set_extra_library_path = set_extra_library_path;
|
tv[i].tv_u.tv_set_extra_library_path = set_extra_library_path;
|
|
|
++i;
|
++i;
|
|
tv[i].tv_tag = LDPT_GET_INPUT_SECTION_COUNT;
|
|
tv[i].tv_u.tv_get_input_section_count = get_input_section_count;
|
|
|
|
++i;
|
|
tv[i].tv_tag = LDPT_GET_INPUT_SECTION_TYPE;
|
|
tv[i].tv_u.tv_get_input_section_type = get_input_section_type;
|
|
|
|
++i;
|
|
tv[i].tv_tag = LDPT_GET_INPUT_SECTION_NAME;
|
|
tv[i].tv_u.tv_get_input_section_name = get_input_section_name;
|
|
|
|
++i;
|
|
tv[i].tv_tag = LDPT_GET_INPUT_SECTION_CONTENTS;
|
|
tv[i].tv_u.tv_get_input_section_contents = get_input_section_contents;
|
|
|
|
++i;
|
|
tv[i].tv_tag = LDPT_UPDATE_SECTION_ORDER;
|
|
tv[i].tv_u.tv_update_section_order = update_section_order;
|
|
|
|
++i;
|
|
tv[i].tv_tag = LDPT_ALLOW_SECTION_ORDERING;
|
|
tv[i].tv_u.tv_allow_section_ordering = allow_section_ordering;
|
|
|
|
++i;
|
tv[i].tv_tag = LDPT_NULL;
|
tv[i].tv_tag = LDPT_NULL;
|
tv[i].tv_u.tv_val = 0;
|
tv[i].tv_u.tv_val = 0;
|
|
|
gold_assert(i == tv_size - 1);
|
gold_assert(i == tv_size - 1);
|
|
|
Line 324... |
Line 372... |
}
|
}
|
|
|
// Load all plugin libraries.
|
// Load all plugin libraries.
|
|
|
void
|
void
|
Plugin_manager::load_plugins()
|
Plugin_manager::load_plugins(Layout* layout)
|
{
|
{
|
|
this->layout_ = layout;
|
for (this->current_ = this->plugins_.begin();
|
for (this->current_ = this->plugins_.begin();
|
this->current_ != this->plugins_.end();
|
this->current_ != this->plugins_.end();
|
++this->current_)
|
++this->current_)
|
(*this->current_)->load();
|
(*this->current_)->load();
|
}
|
}
|
|
|
// Call the plugin claim-file handlers in turn to see if any claim the file.
|
// Call the plugin claim-file handlers in turn to see if any claim the file.
|
|
|
Pluginobj*
|
Pluginobj*
|
Plugin_manager::claim_file(Input_file* input_file, off_t offset,
|
Plugin_manager::claim_file(Input_file* input_file, off_t offset,
|
off_t filesize)
|
off_t filesize, Object* elf_object)
|
{
|
{
|
if (this->in_replacement_phase_)
|
if (this->in_replacement_phase_)
|
return NULL;
|
return NULL;
|
|
|
unsigned int handle = this->objects_.size();
|
unsigned int handle = this->objects_.size();
|
Line 348... |
Line 397... |
this->plugin_input_file_.name = input_file->filename().c_str();
|
this->plugin_input_file_.name = input_file->filename().c_str();
|
this->plugin_input_file_.fd = input_file->file().descriptor();
|
this->plugin_input_file_.fd = input_file->file().descriptor();
|
this->plugin_input_file_.offset = offset;
|
this->plugin_input_file_.offset = offset;
|
this->plugin_input_file_.filesize = filesize;
|
this->plugin_input_file_.filesize = filesize;
|
this->plugin_input_file_.handle = reinterpret_cast<void*>(handle);
|
this->plugin_input_file_.handle = reinterpret_cast<void*>(handle);
|
|
if (elf_object != NULL)
|
|
this->objects_.push_back(elf_object);
|
|
this->in_claim_file_handler_ = true;
|
|
|
for (this->current_ = this->plugins_.begin();
|
for (this->current_ = this->plugins_.begin();
|
this->current_ != this->plugins_.end();
|
this->current_ != this->plugins_.end();
|
++this->current_)
|
++this->current_)
|
{
|
{
|
if ((*this->current_)->claim_file(&this->plugin_input_file_))
|
if ((*this->current_)->claim_file(&this->plugin_input_file_))
|
{
|
{
|
this->any_claimed_ = true;
|
this->any_claimed_ = true;
|
|
this->in_claim_file_handler_ = false;
|
|
|
if (this->objects_.size() > handle)
|
if (this->objects_.size() > handle
|
return this->objects_[handle];
|
&& this->objects_[handle]->pluginobj() != NULL)
|
|
return this->objects_[handle]->pluginobj();
|
|
|
// If the plugin claimed the file but did not call the
|
// If the plugin claimed the file but did not call the
|
// add_symbols callback, we need to create the Pluginobj now.
|
// add_symbols callback, we need to create the Pluginobj now.
|
Pluginobj* obj = this->make_plugin_object(handle);
|
Pluginobj* obj = this->make_plugin_object(handle);
|
return obj;
|
return obj;
|
}
|
}
|
}
|
}
|
|
|
|
this->in_claim_file_handler_ = false;
|
return NULL;
|
return NULL;
|
}
|
}
|
|
|
// Save an archive. This is used so that a plugin can add a file
|
// Save an archive. This is used so that a plugin can add a file
|
// which refers to a symbol which was not previously referenced. In
|
// which refers to a symbol which was not previously referenced. In
|
Line 400... |
Line 455... |
// Call the all-symbols-read handlers.
|
// Call the all-symbols-read handlers.
|
|
|
void
|
void
|
Plugin_manager::all_symbols_read(Workqueue* workqueue, Task* task,
|
Plugin_manager::all_symbols_read(Workqueue* workqueue, Task* task,
|
Input_objects* input_objects,
|
Input_objects* input_objects,
|
Symbol_table* symtab, Layout* layout,
|
Symbol_table* symtab,
|
Dirsearch* dirpath, Mapfile* mapfile,
|
Dirsearch* dirpath, Mapfile* mapfile,
|
Task_token** last_blocker)
|
Task_token** last_blocker)
|
{
|
{
|
this->in_replacement_phase_ = true;
|
this->in_replacement_phase_ = true;
|
this->workqueue_ = workqueue;
|
this->workqueue_ = workqueue;
|
this->task_ = task;
|
this->task_ = task;
|
this->input_objects_ = input_objects;
|
this->input_objects_ = input_objects;
|
this->symtab_ = symtab;
|
this->symtab_ = symtab;
|
this->layout_ = layout;
|
|
this->dirpath_ = dirpath;
|
this->dirpath_ = dirpath;
|
this->mapfile_ = mapfile;
|
this->mapfile_ = mapfile;
|
this->this_blocker_ = NULL;
|
this->this_blocker_ = NULL;
|
|
|
for (this->current_ = this->plugins_.begin();
|
for (this->current_ = this->plugins_.begin();
|
Line 597... |
Line 651... |
|
|
Pluginobj*
|
Pluginobj*
|
Plugin_manager::make_plugin_object(unsigned int handle)
|
Plugin_manager::make_plugin_object(unsigned int handle)
|
{
|
{
|
// Make sure we aren't asked to make an object for the same handle twice.
|
// Make sure we aren't asked to make an object for the same handle twice.
|
if (this->objects_.size() != handle)
|
if (this->objects_.size() != handle
|
|
&& this->objects_[handle]->pluginobj() != NULL)
|
return NULL;
|
return NULL;
|
|
|
Pluginobj* obj = make_sized_plugin_object(this->input_file_,
|
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->plugin_input_file_.filesize);
|
|
|
|
|
|
// If the elf object for this file was pushed into the objects_ vector, delete
|
|
// it to make room for the Pluginobj as this file is claimed.
|
|
if (this->objects_.size() != handle)
|
|
this->objects_.pop_back();
|
|
|
this->objects_.push_back(obj);
|
this->objects_.push_back(obj);
|
return obj;
|
return obj;
|
}
|
}
|
|
|
// Get the input file information with an open (possibly re-opened)
|
// Get the input file information with an open (possibly re-opened)
|
Line 614... |
Line 676... |
|
|
ld_plugin_status
|
ld_plugin_status
|
Plugin_manager::get_input_file(unsigned int handle,
|
Plugin_manager::get_input_file(unsigned int handle,
|
struct ld_plugin_input_file* file)
|
struct ld_plugin_input_file* file)
|
{
|
{
|
Pluginobj* obj = this->object(handle);
|
Pluginobj* obj = this->object(handle)->pluginobj();
|
if (obj == NULL)
|
if (obj == NULL)
|
return LDPS_BAD_HANDLE;
|
return LDPS_BAD_HANDLE;
|
|
|
obj->lock(this->task_);
|
obj->lock(this->task_);
|
file->name = obj->filename().c_str();
|
file->name = obj->filename().c_str();
|
Line 632... |
Line 694... |
// Release the input file.
|
// Release the input file.
|
|
|
ld_plugin_status
|
ld_plugin_status
|
Plugin_manager::release_input_file(unsigned int handle)
|
Plugin_manager::release_input_file(unsigned int handle)
|
{
|
{
|
Pluginobj* obj = this->object(handle);
|
if (this->object(handle) == NULL)
|
|
return LDPS_BAD_HANDLE;
|
|
|
|
Pluginobj* obj = this->object(handle)->pluginobj();
|
|
|
if (obj == NULL)
|
if (obj == NULL)
|
return LDPS_BAD_HANDLE;
|
return LDPS_BAD_HANDLE;
|
|
|
obj->unlock(this->task_);
|
obj->unlock(this->task_);
|
return LDPS_OK;
|
return LDPS_OK;
|
}
|
}
|
|
|
|
// Get the elf object corresponding to the handle. Return NULL if we
|
|
// found a Pluginobj instead.
|
|
|
|
Object*
|
|
Plugin_manager::get_elf_object(const void* handle)
|
|
{
|
|
Object* obj = this->object(
|
|
static_cast<unsigned int>(reinterpret_cast<intptr_t>(handle)));
|
|
|
|
// The object should not be a Pluginobj.
|
|
if (obj == NULL
|
|
|| obj->pluginobj() != NULL)
|
|
return NULL;
|
|
|
|
return obj;
|
|
}
|
|
|
ld_plugin_status
|
ld_plugin_status
|
Plugin_manager::get_view(unsigned int handle, const void **viewp)
|
Plugin_manager::get_view(unsigned int handle, const void **viewp)
|
{
|
{
|
off_t offset;
|
off_t offset;
|
size_t filesize;
|
size_t filesize;
|
Input_file *input_file;
|
Input_file *input_file;
|
if (this->objects_.size() == handle)
|
if (this->in_claim_file_handler_)
|
{
|
{
|
// We are being called from the claim_file hook.
|
// We are being called from the claim_file hook.
|
const struct ld_plugin_input_file &f = this->plugin_input_file_;
|
const struct ld_plugin_input_file &f = this->plugin_input_file_;
|
offset = f.offset;
|
offset = f.offset;
|
filesize = f.filesize;
|
filesize = f.filesize;
|
input_file = this->input_file_;
|
input_file = this->input_file_;
|
}
|
}
|
else
|
else
|
{
|
{
|
// An already claimed file.
|
// An already claimed file.
|
Pluginobj* obj = this->object(handle);
|
if (this->object(handle) == NULL)
|
|
return LDPS_BAD_HANDLE;
|
|
Pluginobj* obj = this->object(handle)->pluginobj();
|
if (obj == NULL)
|
if (obj == NULL)
|
return LDPS_BAD_HANDLE;
|
return LDPS_BAD_HANDLE;
|
offset = obj->offset();
|
offset = obj->offset();
|
filesize = obj->filesize();
|
filesize = obj->filesize();
|
input_file = obj->input_file();
|
input_file = obj->input_file();
|
Line 1224... |
Line 1309... |
|
|
this->options_.plugins()->all_symbols_read(workqueue,
|
this->options_.plugins()->all_symbols_read(workqueue,
|
this,
|
this,
|
this->input_objects_,
|
this->input_objects_,
|
this->symtab_,
|
this->symtab_,
|
this->layout_,
|
|
this->dirpath_,
|
this->dirpath_,
|
this->mapfile_,
|
this->mapfile_,
|
&this->this_blocker_);
|
&this->this_blocker_);
|
workqueue->queue_soon(new Plugin_finish(this->this_blocker_,
|
workqueue->queue_soon(new Plugin_finish(this->this_blocker_,
|
this->next_blocker_));
|
this->next_blocker_));
|
Line 1318... |
Line 1402... |
|
|
static enum ld_plugin_status
|
static enum ld_plugin_status
|
get_symbols(const void* handle, int nsyms, ld_plugin_symbol* syms)
|
get_symbols(const void* handle, int nsyms, ld_plugin_symbol* syms)
|
{
|
{
|
gold_assert(parameters->options().has_plugins());
|
gold_assert(parameters->options().has_plugins());
|
Pluginobj* obj = parameters->options().plugins()->object(
|
Object* obj = parameters->options().plugins()->object(
|
static_cast<unsigned int>(reinterpret_cast<intptr_t>(handle)));
|
static_cast<unsigned int>(reinterpret_cast<intptr_t>(handle)));
|
if (obj == NULL)
|
if (obj == NULL)
|
return LDPS_ERR;
|
return LDPS_ERR;
|
return obj->get_symbol_resolution_info(nsyms, syms);
|
Pluginobj* plugin_obj = obj->pluginobj();
|
|
if (plugin_obj == NULL)
|
|
return LDPS_ERR;
|
|
return plugin_obj->get_symbol_resolution_info(nsyms, syms);
|
}
|
}
|
|
|
// Add a new (real) input file generated by a plugin.
|
// Add a new (real) input file generated by a plugin.
|
|
|
static enum ld_plugin_status
|
static enum ld_plugin_status
|
Line 1382... |
Line 1469... |
|
|
va_end(args);
|
va_end(args);
|
return LDPS_OK;
|
return LDPS_OK;
|
}
|
}
|
|
|
|
// Get the section count of the object corresponding to the handle. This
|
|
// plugin interface can only be called in the claim_file handler of the plugin.
|
|
|
|
static enum ld_plugin_status
|
|
get_input_section_count(const void* handle, unsigned int* count)
|
|
{
|
|
gold_assert(parameters->options().has_plugins());
|
|
|
|
if (!parameters->options().plugins()->in_claim_file_handler())
|
|
return LDPS_ERR;
|
|
|
|
Object* obj = parameters->options().plugins()->get_elf_object(handle);
|
|
|
|
if (obj == NULL)
|
|
return LDPS_ERR;
|
|
|
|
*count = obj->shnum();
|
|
return LDPS_OK;
|
|
}
|
|
|
|
// Get the type of the specified section in the object corresponding
|
|
// to the handle. This plugin interface can only be called in the
|
|
// claim_file handler of the plugin.
|
|
|
|
static enum ld_plugin_status
|
|
get_input_section_type(const struct ld_plugin_section section,
|
|
unsigned int* type)
|
|
{
|
|
gold_assert(parameters->options().has_plugins());
|
|
|
|
if (!parameters->options().plugins()->in_claim_file_handler())
|
|
return LDPS_ERR;
|
|
|
|
Object* obj
|
|
= parameters->options().plugins()->get_elf_object(section.handle);
|
|
|
|
if (obj == NULL)
|
|
return LDPS_BAD_HANDLE;
|
|
|
|
*type = obj->section_type(section.shndx);
|
|
return LDPS_OK;
|
|
}
|
|
|
|
// Get the name of the specified section in the object corresponding
|
|
// to the handle. This plugin interface can only be called in the
|
|
// claim_file handler of the plugin.
|
|
|
|
static enum ld_plugin_status
|
|
get_input_section_name(const struct ld_plugin_section section,
|
|
char** section_name_ptr)
|
|
{
|
|
gold_assert(parameters->options().has_plugins());
|
|
|
|
if (!parameters->options().plugins()->in_claim_file_handler())
|
|
return LDPS_ERR;
|
|
|
|
Object* obj
|
|
= parameters->options().plugins()->get_elf_object(section.handle);
|
|
|
|
if (obj == NULL)
|
|
return LDPS_BAD_HANDLE;
|
|
|
|
// Check if the object is locked before getting the section name.
|
|
gold_assert(obj->is_locked());
|
|
|
|
const std::string section_name = obj->section_name(section.shndx);
|
|
*section_name_ptr = static_cast<char*>(malloc(section_name.length() + 1));
|
|
memcpy(*section_name_ptr, section_name.c_str(), section_name.length() + 1);
|
|
return LDPS_OK;
|
|
}
|
|
|
|
// Get the contents of the specified section in the object corresponding
|
|
// to the handle. This plugin interface can only be called in the
|
|
// claim_file handler of the plugin.
|
|
|
|
static enum ld_plugin_status
|
|
get_input_section_contents(const struct ld_plugin_section section,
|
|
const unsigned char** section_contents_ptr,
|
|
size_t* len)
|
|
{
|
|
gold_assert(parameters->options().has_plugins());
|
|
|
|
if (!parameters->options().plugins()->in_claim_file_handler())
|
|
return LDPS_ERR;
|
|
|
|
Object* obj
|
|
= parameters->options().plugins()->get_elf_object(section.handle);
|
|
|
|
if (obj == NULL)
|
|
return LDPS_BAD_HANDLE;
|
|
|
|
// Check if the object is locked before getting the section contents.
|
|
gold_assert(obj->is_locked());
|
|
|
|
section_size_type plen;
|
|
*section_contents_ptr
|
|
= obj->section_contents(section.shndx, &plen, false);
|
|
*len = plen;
|
|
return LDPS_OK;
|
|
}
|
|
|
|
// Specify the ordering of sections in the final layout. The sections are
|
|
// specified as (handle,shndx) pairs in the two arrays in the order in
|
|
// which they should appear in the final layout.
|
|
|
|
static enum ld_plugin_status
|
|
update_section_order(const struct ld_plugin_section *section_list,
|
|
unsigned int num_sections)
|
|
{
|
|
gold_assert(parameters->options().has_plugins());
|
|
|
|
if (num_sections == 0)
|
|
return LDPS_OK;
|
|
|
|
if (section_list == NULL)
|
|
return LDPS_ERR;
|
|
|
|
std::map<Section_id, unsigned int> order_map;
|
|
|
|
for (unsigned int i = 0; i < num_sections; ++i)
|
|
{
|
|
Object* obj = parameters->options().plugins()->get_elf_object(
|
|
section_list[i].handle);
|
|
if (obj == NULL)
|
|
return LDPS_BAD_HANDLE;
|
|
unsigned int shndx = section_list[i].shndx;
|
|
Section_id secn_id(obj, shndx);
|
|
order_map[secn_id] = i + 1;
|
|
}
|
|
|
|
Layout* layout = parameters->options().plugins()->layout();
|
|
gold_assert (layout != NULL);
|
|
|
|
for (Layout::Section_list::const_iterator p = layout->section_list().begin();
|
|
p != layout->section_list().end();
|
|
++p)
|
|
(*p)->update_section_layout(order_map);
|
|
|
|
return LDPS_OK;
|
|
}
|
|
|
|
// Let the linker know that the sections could be reordered.
|
|
|
|
static enum ld_plugin_status
|
|
allow_section_ordering()
|
|
{
|
|
gold_assert(parameters->options().has_plugins());
|
|
Layout* layout = parameters->options().plugins()->layout();
|
|
layout->set_section_ordering_specified();
|
|
return LDPS_OK;
|
|
}
|
|
|
#endif // ENABLE_PLUGINS
|
#endif // ENABLE_PLUGINS
|
|
|
// Allocate a Pluginobj object of the appropriate size and endianness.
|
// Allocate a Pluginobj object of the appropriate size and endianness.
|
|
|
static Pluginobj*
|
static Pluginobj*
|