X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gold%2Freadsyms.cc;h=75dd3f1a7cc0a8b5a6fefda092f7873dbddfe3dd;hb=8aaaf7577f070c91086533d959ac36a15d1d604f;hp=5625f59f0e6a3991f154ceae299abe0596170cf6;hpb=c79126688f8211ab17a893c5e80b09811d424fc1;p=deliverable%2Fbinutils-gdb.git diff --git a/gold/readsyms.cc b/gold/readsyms.cc index 5625f59f0e..75dd3f1a7c 100644 --- a/gold/readsyms.cc +++ b/gold/readsyms.cc @@ -1,6 +1,6 @@ // readsyms.cc -- read input file symbols for gold -// Copyright 2006, 2007 Free Software Foundation, Inc. +// Copyright (C) 2006-2019 Free Software Foundation, Inc. // Written by Ian Lance Taylor . // This file is part of gold. @@ -32,6 +32,9 @@ #include "archive.h" #include "script.h" #include "readsyms.h" +#include "plugin.h" +#include "layout.h" +#include "incremental.h" namespace gold { @@ -39,9 +42,9 @@ namespace gold // If we fail to open the object, then we won't create an Add_symbols // task. However, we still need to unblock the token, or else the // link won't proceed to generate more error messages. We can only -// unblock tokens in the main thread, so we need a dummy task to do -// that. The dummy task has to maintain the right sequence of blocks, -// so we need both this_blocker and next_blocker. +// unblock tokens when the workqueue lock is held, so we need a dummy +// task to do that. The dummy task has to maintain the right sequence +// of blocks, so we need both this_blocker and next_blocker. class Unblock_token : public Task { @@ -56,17 +59,17 @@ class Unblock_token : public Task delete this->this_blocker_; } - Is_runnable_type - is_runnable(Workqueue*) + Task_token* + is_runnable() { if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked()) - return IS_BLOCKED; - return IS_RUNNABLE; + return this->this_blocker_; + return NULL; } - Task_locker* - locks(Workqueue* workqueue) - { return new Task_locker_block(*this->next_blocker_, workqueue); } + void + locks(Task_locker* tl) + { tl->add(this, this->next_blocker_); } void run(Workqueue*) @@ -89,28 +92,67 @@ Read_symbols::~Read_symbols() // Add_symbols task. } +// If appropriate, issue a warning about skipping an incompatible +// file. + +void +Read_symbols::incompatible_warning(const Input_argument* input_argument, + const Input_file* input_file) +{ + if (parameters->options().warn_search_mismatch()) + gold_warning("skipping incompatible %s while searching for %s", + input_file->filename().c_str(), + input_argument->file().name()); +} + +// Requeue a Read_symbols task to search for the next object with the +// same name. + +void +Read_symbols::requeue(Workqueue* workqueue, Input_objects* input_objects, + Symbol_table* symtab, Layout* layout, Dirsearch* dirpath, + int dirindex, Mapfile* mapfile, + const Input_argument* input_argument, + Input_group* input_group, Task_token* next_blocker) +{ + // Bump the directory search index. + ++dirindex; + + // We don't need to worry about this_blocker, since we already + // reached it. However, we are removing the blocker on next_blocker + // because the calling task is completing. So we need to add a new + // blocker. Since next_blocker may be shared by several tasks, we + // need to increment the count with the workqueue lock held. + workqueue->add_blocker(next_blocker); + + workqueue->queue(new Read_symbols(input_objects, symtab, layout, dirpath, + dirindex, mapfile, input_argument, + input_group, NULL, NULL, next_blocker)); +} + // Return whether a Read_symbols task is runnable. We can read an // ordinary input file immediately. For an archive specified using // -l, we have to wait until the search path is complete. -Task::Is_runnable_type -Read_symbols::is_runnable(Workqueue*) +Task_token* +Read_symbols::is_runnable() { if (this->input_argument_->is_file() && this->input_argument_->file().may_need_search() - && this->dirpath_.token().is_blocked()) - return IS_BLOCKED; + && this->dirpath_->token()->is_blocked()) + return this->dirpath_->token(); - return IS_RUNNABLE; + return NULL; } // Return a Task_locker for a Read_symbols task. We don't need any // locks here. -Task_locker* -Read_symbols::locks(Workqueue*) +void +Read_symbols::locks(Task_locker* tl) { - return NULL; + if (this->member_ != NULL) + tl->add(this, this->next_blocker_); } // Run a Read_symbols task. @@ -119,10 +161,99 @@ void Read_symbols::run(Workqueue* workqueue) { // If we didn't queue a new task, then we need to explicitly unblock - // the token. - if (!this->do_read_symbols(workqueue)) - workqueue->queue_front(new Unblock_token(this->this_blocker_, - this->next_blocker_)); + // the token. If the object is a member of a lib group, however, + // the token was already added to the list of locks for the task, + // and it will be unblocked automatically at the end of the task. + if (!this->do_read_symbols(workqueue) && this->member_ == NULL) + workqueue->queue_soon(new Unblock_token(this->this_blocker_, + this->next_blocker_)); +} + +// Handle a whole lib group. Other than collecting statistics, this just +// mimics what we do for regular object files in the command line. + +bool +Read_symbols::do_whole_lib_group(Workqueue* workqueue) +{ + const Input_file_lib* lib_group = this->input_argument_->lib(); + + ++Lib_group::total_lib_groups; + + Task_token* this_blocker = this->this_blocker_; + for (Input_file_lib::const_iterator i = lib_group->begin(); + i != lib_group->end(); + ++i) + { + ++Lib_group::total_members; + ++Lib_group::total_members_loaded; + + const Input_argument* arg = &*i; + + Task_token* next_blocker; + if (i != lib_group->end() - 1) + { + next_blocker = new Task_token(true); + next_blocker->add_blocker(); + } + else + next_blocker = this->next_blocker_; + + workqueue->queue_soon(new Read_symbols(this->input_objects_, + this->symtab_, this->layout_, + this->dirpath_, this->dirindex_, + this->mapfile_, arg, NULL, + NULL, this_blocker, next_blocker)); + this_blocker = next_blocker; + } + + return true; +} + +// Handle a lib group. We set Read_symbols Tasks as usual, but have them +// just record the symbol data instead of adding the objects. We also start +// a Add_lib_group_symbols Task which runs after we've read all the symbols. +// In that task we process the members in a loop until we are done. + +bool +Read_symbols::do_lib_group(Workqueue* workqueue) +{ + const Input_file_lib* lib_group = this->input_argument_->lib(); + + if (lib_group->options().whole_archive()) + return this->do_whole_lib_group(workqueue); + + Lib_group* lib = new Lib_group(lib_group, this); + + Add_lib_group_symbols* add_lib_group_symbols = + new Add_lib_group_symbols(this->symtab_, this->layout_, + this->input_objects_, + lib, this->next_blocker_); + + + Task_token* next_blocker = new Task_token(true); + int j = 0; + for (Input_file_lib::const_iterator i = lib_group->begin(); + i != lib_group->end(); + ++i, ++j) + { + const Input_argument* arg = &*i; + Archive_member* m = lib->get_member(j); + + next_blocker->add_blocker(); + + // Since this Read_symbols will not create an Add_symbols, + // just pass NULL as this_blocker. + workqueue->queue_soon(new Read_symbols(this->input_objects_, + this->symtab_, this->layout_, + this->dirpath_, this->dirindex_, + this->mapfile_, arg, NULL, + m, NULL, next_blocker)); + } + + add_lib_group_symbols->set_blocker(next_blocker, this->this_blocker_); + workqueue->queue_soon(add_lib_group_symbols); + + return true; } // Open the file and read the symbols. Return true if a new task was @@ -138,8 +269,11 @@ Read_symbols::do_read_symbols(Workqueue* workqueue) return true; } + if (this->input_argument_->is_lib()) + return this->do_lib_group(workqueue); + Input_file* input_file = new Input_file(&this->input_argument_->file()); - if (!input_file->open(this->options_, this->dirpath_)) + if (!input_file->open(*this->dirpath_, this, &this->dirindex_)) return false; // Read enough of the file to pick up the entire ELF header. @@ -153,88 +287,174 @@ Read_symbols::do_read_symbols(Workqueue* workqueue) return false; } - unsigned char ehdr_buf[elfcpp::Elf_sizes<64>::ehdr_size]; + const unsigned char* ehdr; + int read_size; + bool is_elf = is_elf_object(input_file, 0, &ehdr, &read_size); - int read_size = elfcpp::Elf_sizes<64>::ehdr_size; - if (filesize < read_size) - read_size = filesize; + if (read_size >= Archive::sarmag) + { + bool is_thin_archive + = memcmp(ehdr, Archive::armagt, Archive::sarmag) == 0; + if (is_thin_archive + || memcmp(ehdr, Archive::armag, Archive::sarmag) == 0) + { + // This is an archive. + Archive* arch = new Archive(this->input_argument_->file().name(), + input_file, is_thin_archive, + this->dirpath_, this); + arch->setup(); - input_file->file().read(0, read_size, ehdr_buf); + // Unlock the archive so it can be used in the next task. + arch->unlock(this); + + workqueue->queue_next(new Add_archive_symbols(this->symtab_, + this->layout_, + this->input_objects_, + this->dirpath_, + this->dirindex_, + this->mapfile_, + this->input_argument_, + arch, + this->input_group_, + this->this_blocker_, + this->next_blocker_)); + return true; + } + } - if (read_size >= 4) + Object* elf_obj = NULL; + bool unconfigured; + bool* punconfigured = NULL; + if (is_elf) { - static unsigned char elfmagic[4] = - { - elfcpp::ELFMAG0, elfcpp::ELFMAG1, - elfcpp::ELFMAG2, elfcpp::ELFMAG3 - }; - if (memcmp(ehdr_buf, elfmagic, 4) == 0) - { - // This is an ELF object. - - Object* obj = make_elf_object(input_file->filename(), - input_file, 0, ehdr_buf, read_size); - if (obj == NULL) - return false; - - // We don't have a way to record a non-archive in an input - // group. If this is an ordinary object file, we can't - // include it more than once anyhow. If this is a dynamic - // object, then including it a second time changes nothing. - if (this->input_group_ != NULL && !obj->is_dynamic()) + // This is an ELF object. + + unconfigured = false; + punconfigured = (input_file->will_search_for() + ? &unconfigured + : NULL); + elf_obj = make_elf_object(input_file->filename(), + input_file, 0, ehdr, read_size, + punconfigured); + } + + if (parameters->options().has_plugins()) + { + Pluginobj* obj = parameters->options().plugins()->claim_file(input_file, + 0, filesize, + elf_obj); + if (obj != NULL) + { + // Delete the elf_obj, this file has been claimed. + if (elf_obj != NULL) + delete elf_obj; + + // The input file was claimed by a plugin, and its symbols + // have been provided by the plugin. + + // We are done with the file at this point, so unlock it. + obj->unlock(this); + + if (this->member_ != NULL) { - gold_error(_("%s: ordinary object found in input group"), - input_file->name()); - return false; + this->member_->sd_ = NULL; + this->member_->obj_ = obj; + return true; } - Read_symbols_data* sd = new Read_symbols_data; - obj->read_symbols(sd); - workqueue->queue_front(new Add_symbols(this->input_objects_, - this->symtab_, this->layout_, - obj, sd, - this->this_blocker_, - this->next_blocker_)); - - // Opening the file locked it, so now we need to unlock it. - input_file->file().unlock(); - - return true; - } + workqueue->queue_next(new Add_symbols(this->input_objects_, + this->symtab_, + this->layout_, + this->dirpath_, + this->dirindex_, + this->mapfile_, + this->input_argument_, + obj, + NULL, + NULL, + this->this_blocker_, + this->next_blocker_)); + return true; + } } - if (read_size >= Archive::sarmag) + if (is_elf) { - if (memcmp(ehdr_buf, Archive::armag, Archive::sarmag) == 0) + // This is an ELF object. + + if (elf_obj == NULL) { - // This is an archive. - Archive* arch = new Archive(this->input_argument_->file().name(), - input_file); - arch->setup(); - workqueue->queue(new Add_archive_symbols(this->symtab_, - this->layout_, - this->input_objects_, - arch, - this->input_group_, - this->this_blocker_, - this->next_blocker_)); - return true; + if (unconfigured) + { + Read_symbols::incompatible_warning(this->input_argument_, + input_file); + input_file->file().release(); + input_file->file().unlock(this); + delete input_file; + ++this->dirindex_; + return this->do_read_symbols(workqueue); + } + return false; } - } - // Try to parse this file as a script. - if (read_input_script(workqueue, this->options_, this->symtab_, - this->layout_, this->dirpath_, this->input_objects_, - this->input_group_, this->input_argument_, input_file, - ehdr_buf, read_size, this->this_blocker_, - this->next_blocker_)) - return true; + Read_symbols_data* sd = new Read_symbols_data; + elf_obj->read_symbols(sd); + + // Opening the file locked it, so now we need to unlock it. We + // need to unlock it before queuing the Add_symbols task, + // because the workqueue doesn't know about our lock on the + // file. If we queue the Add_symbols task first, it will be + // stuck on the end of the file lock, but since the workqueue + // doesn't know about that lock, it will never release the + // Add_symbols task. + + input_file->file().unlock(this); + + if (this->member_ != NULL) + { + this->member_->sd_ = sd; + this->member_->obj_ = elf_obj; + this->member_->arg_serial_ = + this->input_argument_->file().arg_serial(); + return true; + } + + // We use queue_next because everything is cached for this + // task to run right away if possible. + + workqueue->queue_next(new Add_symbols(this->input_objects_, + this->symtab_, this->layout_, + this->dirpath_, + this->dirindex_, + this->mapfile_, + this->input_argument_, + elf_obj, + NULL, + sd, + this->this_blocker_, + this->next_blocker_)); - // Here we have to handle any other input file types we need. - gold_error(_("%s: not an object or archive"), - input_file->file().filename().c_str()); + return true; + } - return false; + // Queue up a task to try to parse this file as a script. We use a + // separate task so that the script will be read in order with other + // objects named on the command line. Also so that we don't try to + // read multiple scripts simultaneously, which could lead to + // unpredictable changes to the General_options structure. + + workqueue->queue_soon(new Read_script(this->symtab_, + this->layout_, + this->dirpath_, + this->dirindex_, + this->input_objects_, + this->mapfile_, + this->input_group_, + this->input_argument_, + input_file, + this->this_blocker_, + this->next_blocker_)); + return true; } // Handle a group. We need to walk through the arguments over and @@ -251,6 +471,20 @@ Read_symbols::do_group(Workqueue* workqueue) const Input_file_group* group = this->input_argument_->group(); Task_token* this_blocker = this->this_blocker_; + + Finish_group* finish_group = new Finish_group(this->input_objects_, + this->symtab_, + this->layout_, + this->mapfile_, + input_group, + this->next_blocker_); + + Task_token* next_blocker = new Task_token(true); + next_blocker->add_blocker(); + workqueue->queue_soon(new Start_group(this->symtab_, finish_group, + this_blocker, next_blocker)); + this_blocker = next_blocker; + for (Input_file_group::const_iterator p = group->begin(); p != group->end(); ++p) @@ -258,23 +492,19 @@ Read_symbols::do_group(Workqueue* workqueue) const Input_argument* arg = &*p; gold_assert(arg->is_file()); - Task_token* next_blocker = new Task_token(); + next_blocker = new Task_token(true); next_blocker->add_blocker(); - workqueue->queue(new Read_symbols(this->options_, this->input_objects_, - this->symtab_, this->layout_, - this->dirpath_, arg, input_group, - this_blocker, next_blocker)); + workqueue->queue_soon(new Read_symbols(this->input_objects_, + this->symtab_, this->layout_, + this->dirpath_, this->dirindex_, + this->mapfile_, arg, input_group, + NULL, this_blocker, next_blocker)); this_blocker = next_blocker; } - const int saw_undefined = this->symtab_->saw_undefined(); - workqueue->queue(new Finish_group(this->input_objects_, - this->symtab_, - this->layout_, - input_group, - saw_undefined, - this_blocker, - this->next_blocker_)); + finish_group->set_blocker(this_blocker); + + workqueue->queue_soon(finish_group); } // Return a debugging name for a Read_symbols task. @@ -282,28 +512,48 @@ Read_symbols::do_group(Workqueue* workqueue) std::string Read_symbols::get_name() const { - if (!this->input_argument_->is_group()) + if (this->input_argument_->is_group()) + { + std::string ret("Read_symbols group ("); + bool add_space = false; + const Input_file_group* group = this->input_argument_->group(); + for (Input_file_group::const_iterator p = group->begin(); + p != group->end(); + ++p) + { + if (add_space) + ret += ' '; + ret += p->file().name(); + add_space = true; + } + return ret + ')'; + } + else if (this->input_argument_->is_lib()) + { + std::string ret("Read_symbols lib ("); + bool add_space = false; + const Input_file_lib* lib = this->input_argument_->lib(); + for (Input_file_lib::const_iterator p = lib->begin(); + p != lib->end(); + ++p) + { + if (add_space) + ret += ' '; + ret += p->file().name(); + add_space = true; + } + return ret + ')'; + } + else { std::string ret("Read_symbols "); if (this->input_argument_->file().is_lib()) ret += "-l"; + else if (this->input_argument_->file().is_searched_file()) + ret += "-l:"; ret += this->input_argument_->file().name(); return ret; } - - std::string ret("Read_symbols group ("); - bool add_space = false; - const Input_file_group* group = this->input_argument_->group(); - for (Input_file_group::const_iterator p = group->begin(); - p != group->end(); - ++p) - { - if (add_space) - ret += ' '; - ret += p->file().name(); - add_space = true; - } - return ret + ')'; } // Class Add_symbols. @@ -319,34 +569,23 @@ Add_symbols::~Add_symbols() // We are blocked by this_blocker_. We block next_blocker_. We also // lock the file. -Task::Is_runnable_type -Add_symbols::is_runnable(Workqueue*) +Task_token* +Add_symbols::is_runnable() { if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked()) - return IS_BLOCKED; + return this->this_blocker_; if (this->object_->is_locked()) - return IS_LOCKED; - return IS_RUNNABLE; + return this->object_->token(); + return NULL; } -class Add_symbols::Add_symbols_locker : public Task_locker -{ - public: - Add_symbols_locker(Task_token& token, Workqueue* workqueue, - Object* object) - : blocker_(token, workqueue), objlock_(*object) - { } - - private: - Task_locker_block blocker_; - Task_locker_obj objlock_; -}; - -Task_locker* -Add_symbols::locks(Workqueue* workqueue) +void +Add_symbols::locks(Task_locker* tl) { - return new Add_symbols_locker(*this->next_blocker_, workqueue, - this->object_); + tl->add(this, this->next_blocker_); + Task_token* token = this->object_->token(); + if (token != NULL) + tl->add(this, token); } // Add the symbols in the object to the symbol table. @@ -354,18 +593,221 @@ Add_symbols::locks(Workqueue* workqueue) void Add_symbols::run(Workqueue*) { + Pluginobj* pluginobj = this->object_->pluginobj(); + if (pluginobj != NULL) + { + this->object_->add_symbols(this->symtab_, this->sd_, this->layout_); + return; + } + if (!this->input_objects_->add_object(this->object_)) { - // FIXME: We need to close the descriptor here. + this->object_->discard_decompressed_sections(); + gold_assert(this->sd_ != NULL); + delete this->sd_; + this->sd_ = NULL; + this->object_->release(); delete this->object_; } else { + Incremental_inputs* incremental_inputs = + this->layout_->incremental_inputs(); + if (incremental_inputs != NULL) + { + if (this->library_ != NULL && !this->library_->is_reported()) + { + Incremental_binary* ibase = this->layout_->incremental_base(); + gold_assert(ibase != NULL); + unsigned int lib_serial = this->library_->arg_serial(); + unsigned int lib_index = this->library_->input_file_index(); + Script_info* lib_script_info = ibase->get_script_info(lib_index); + incremental_inputs->report_archive_begin(this->library_, + lib_serial, + lib_script_info); + } + unsigned int arg_serial = this->input_argument_->file().arg_serial(); + Script_info* script_info = this->input_argument_->script_info(); + incremental_inputs->report_object(this->object_, arg_serial, + this->library_, script_info); + } this->object_->layout(this->symtab_, this->layout_, this->sd_); - this->object_->add_symbols(this->symtab_, this->sd_); + this->object_->add_symbols(this->symtab_, this->sd_, this->layout_); + this->object_->discard_decompressed_sections(); + delete this->sd_; + this->sd_ = NULL; + this->object_->release(); + } +} + +// Class Read_member. + +Read_member::~Read_member() +{ + if (this->this_blocker_ != NULL) + delete this->this_blocker_; + // next_blocker_ is deleted by the task associated with the next + // input file. +} + +// Return whether a Read_member task is runnable. + +Task_token* +Read_member::is_runnable() +{ + if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked()) + return this->this_blocker_; + return NULL; +} + +void +Read_member::locks(Task_locker* tl) +{ + tl->add(this, this->next_blocker_); +} + +// Run a Read_member task. + +void +Read_member::run(Workqueue*) +{ + // This task doesn't need to do anything for now. The Read_symbols task + // that is queued for the archive library will cause the archive to be + // processed from scratch. +} + +// Class Check_script. + +Check_script::~Check_script() +{ + if (this->this_blocker_ != NULL) + delete this->this_blocker_; + // next_blocker_ is deleted by the task associated with the next + // input file. +} + +// Return whether a Check_script task is runnable. + +Task_token* +Check_script::is_runnable() +{ + if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked()) + return this->this_blocker_; + return NULL; +} + +void +Check_script::locks(Task_locker* tl) +{ + tl->add(this, this->next_blocker_); +} + +// Run a Check_script task. + +void +Check_script::run(Workqueue*) +{ + Incremental_inputs* incremental_inputs = this->layout_->incremental_inputs(); + gold_assert(incremental_inputs != NULL); + unsigned int arg_serial = this->input_reader_->arg_serial(); + Script_info* script_info = + this->ibase_->get_script_info(this->input_file_index_); + Timespec mtime = this->input_reader_->get_mtime(); + incremental_inputs->report_script(script_info, arg_serial, mtime); +} + +// Class Check_library. + +Check_library::~Check_library() +{ + if (this->this_blocker_ != NULL) + delete this->this_blocker_; + // next_blocker_ is deleted by the task associated with the next + // input file. +} + +// Return whether a Check_library task is runnable. + +Task_token* +Check_library::is_runnable() +{ + if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked()) + return this->this_blocker_; + return NULL; +} + +void +Check_library::locks(Task_locker* tl) +{ + tl->add(this, this->next_blocker_); +} + +// Run a Check_library task. + +void +Check_library::run(Workqueue*) +{ + Incremental_inputs* incremental_inputs = this->layout_->incremental_inputs(); + gold_assert(incremental_inputs != NULL); + Incremental_library* lib = this->ibase_->get_library(this->input_file_index_); + gold_assert(lib != NULL); + lib->copy_unused_symbols(); + // FIXME: Check that unused symbols remain unused. + if (!lib->is_reported()) + { + unsigned int lib_serial = lib->arg_serial(); + unsigned int lib_index = lib->input_file_index(); + Script_info* script_info = this->ibase_->get_script_info(lib_index); + incremental_inputs->report_archive_begin(lib, lib_serial, script_info); } - delete this->sd_; - this->sd_ = NULL; + incremental_inputs->report_archive_end(lib); +} + +// Class Input_group. + +// When we delete an Input_group we can delete the archive +// information. + +Input_group::~Input_group() +{ + for (Input_group::const_iterator p = this->begin(); + p != this->end(); + ++p) + delete *p; +} + +// Class Start_group. + +Start_group::~Start_group() +{ + if (this->this_blocker_ != NULL) + delete this->this_blocker_; + // next_blocker_ is deleted by the task associated with the first + // file in the group. +} + +// We need to wait for THIS_BLOCKER_ and unblock NEXT_BLOCKER_. + +Task_token* +Start_group::is_runnable() +{ + if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked()) + return this->this_blocker_; + return NULL; +} + +void +Start_group::locks(Task_locker* tl) +{ + tl->add(this, this->next_blocker_); +} + +// Store the number of undefined symbols we see now. + +void +Start_group::run(Workqueue*) +{ + this->finish_group_->set_saw_undefined(this->symtab_->saw_undefined()); } // Class Finish_group. @@ -380,18 +822,18 @@ Finish_group::~Finish_group() // We need to wait for THIS_BLOCKER_ and unblock NEXT_BLOCKER_. -Task::Is_runnable_type -Finish_group::is_runnable(Workqueue*) +Task_token* +Finish_group::is_runnable() { if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked()) - return IS_BLOCKED; - return IS_RUNNABLE; + return this->this_blocker_; + return NULL; } -Task_locker* -Finish_group::locks(Workqueue* workqueue) +void +Finish_group::locks(Task_locker* tl) { - return new Task_locker_block(*this->next_blocker_, workqueue); + tl->add(this, this->next_blocker_); } // Loop over the archives until there are no new undefined symbols. @@ -399,7 +841,7 @@ Finish_group::locks(Workqueue* workqueue) void Finish_group::run(Workqueue*) { - int saw_undefined = this->saw_undefined_; + size_t saw_undefined = this->saw_undefined_; while (saw_undefined != this->symtab_->saw_undefined()) { saw_undefined = this->symtab_->saw_undefined(); @@ -408,19 +850,97 @@ Finish_group::run(Workqueue*) p != this->input_group_->end(); ++p) { - Task_lock_obj tl(**p); + Task_lock_obj tl(this, *p); (*p)->add_symbols(this->symtab_, this->layout_, - this->input_objects_); + this->input_objects_, this->mapfile_); } } - // Delete all the archives now that we no longer need them. + // Now that we're done with the archives, record the incremental + // layout information. for (Input_group::const_iterator p = this->input_group_->begin(); p != this->input_group_->end(); ++p) - delete *p; - delete this->input_group_; + { + // For an incremental link, finish recording the layout information. + Incremental_inputs* incremental_inputs = + this->layout_->incremental_inputs(); + if (incremental_inputs != NULL) + incremental_inputs->report_archive_end(*p); + } + + if (parameters->options().has_plugins()) + parameters->options().plugins()->save_input_group(this->input_group_); + else + delete this->input_group_; +} + +// Class Read_script + +Read_script::~Read_script() +{ + 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_. + +Task_token* +Read_script::is_runnable() +{ + if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked()) + return this->this_blocker_; + return NULL; +} + +// We don't unlock next_blocker_ here. If the script names any input +// files, then the last file will be responsible for unlocking it. + +void +Read_script::locks(Task_locker*) +{ +} + +// Read the script, if it is a script. + +void +Read_script::run(Workqueue* workqueue) +{ + bool used_next_blocker; + if (!read_input_script(workqueue, this->symtab_, this->layout_, + this->dirpath_, this->dirindex_, this->input_objects_, + this->mapfile_, this->input_group_, + this->input_argument_, this->input_file_, + this->next_blocker_, &used_next_blocker)) + { + // Here we have to handle any other input file types we need. + gold_error(_("%s: not an object or archive"), + this->input_file_->file().filename().c_str()); + } + + if (!used_next_blocker) + { + // Queue up a task to unlock next_blocker. We can't just unlock + // it here, as we don't hold the workqueue lock. + workqueue->queue_soon(new Unblock_token(NULL, this->next_blocker_)); + } +} + +// Return a debugging name for a Read_script task. + +std::string +Read_script::get_name() const +{ + std::string ret("Read_script "); + if (this->input_argument_->file().is_lib()) + ret += "-l"; + else if (this->input_argument_->file().is_searched_file()) + ret += "-l:"; + ret += this->input_argument_->file().name(); + return ret; } } // End namespace gold.