* gold.h (Incremental_argument_list): Remove (invalid) forward

declaration.
	* incremental.cc (Incremental_inputs::report_achive): New method.
	(Incremental_inputs::report_object): New method.
	(Incremental_inputs::report_script): New method.
	(Incremental_inputs::finalize_inputs): New method.
	(Incremental_inputs::finalize): Call finalize_inputs().
	(Incremental_inputs::sized_create_incremental_inputs_section_data):
	Create inputs entries.
	* incremental.h (Incremental_input_type): New enum.
	(Incremental_inputs::Incremental_input): Initialize new fields.
	(Incremental_inputs::report_inputs): New method.
	(Incremental_inputs::report_achive): New method.
	(Incremental_inputs::report_object): New method.
	(Incremental_inputs::report_script): New method.
	(Incremental_inputs::finalize_inputs): New method.
	(Incremental_inputs::Input_info): New struct.
	(Incremental_inputs::Input_info_map): New typedef.
	(Incremental_inputs::lock_): New field.
	(Incremental_inputs::Inputs_): New field.
	(Incremental_inputs::Inputs_map): New field.
	* main.cc (main): Call Incremental_input::report_inputs.
	* options.h (Input_argument_list): Typedef moved from
	Input_arguments.
	(Input_file_group::Files): Remove, use ::Input_argument_list.
	(Input_file_group::Input_argument_list): Remove, use
	::Input_argument_list.
	* plugin.cc (Plugin_manager::add_input_file): Add error in
	incremental build.
	* read_syms.cc (do_read_syms): Call Incremental_input::report_*
	functions.
	* script.cc (read_input_script): Call
	Incremental_input::report_script.
	* script.h (Script_info): New class.
This commit is contained in:
Ian Lance Taylor 2009-05-15 17:01:04 +00:00
parent 17a37d488c
commit 072fe7ce7a
10 changed files with 317 additions and 23 deletions

View File

@ -1,3 +1,40 @@
2009-05-15 Mikolaj Zalewski <mikolajz@google.com>
* gold.h (Incremental_argument_list): Remove (invalid) forward
declaration.
* incremental.cc (Incremental_inputs::report_achive): New method.
(Incremental_inputs::report_object): New method.
(Incremental_inputs::report_script): New method.
(Incremental_inputs::finalize_inputs): New method.
(Incremental_inputs::finalize): Call finalize_inputs().
(Incremental_inputs::sized_create_incremental_inputs_section_data):
Create inputs entries.
* incremental.h (Incremental_input_type): New enum.
(Incremental_inputs::Incremental_input): Initialize new fields.
(Incremental_inputs::report_inputs): New method.
(Incremental_inputs::report_achive): New method.
(Incremental_inputs::report_object): New method.
(Incremental_inputs::report_script): New method.
(Incremental_inputs::finalize_inputs): New method.
(Incremental_inputs::Input_info): New struct.
(Incremental_inputs::Input_info_map): New typedef.
(Incremental_inputs::lock_): New field.
(Incremental_inputs::Inputs_): New field.
(Incremental_inputs::Inputs_map): New field.
* main.cc (main): Call Incremental_input::report_inputs.
* options.h (Input_argument_list): Typedef moved from
Input_arguments.
(Input_file_group::Files): Remove, use ::Input_argument_list.
(Input_file_group::Input_argument_list): Remove, use
::Input_argument_list.
* plugin.cc (Plugin_manager::add_input_file): Add error in
incremental build.
* read_syms.cc (do_read_syms): Call Incremental_input::report_*
functions.
* script.cc (read_input_script): Call
Incremental_input::report_script.
* script.h (Script_info): New class.
2009-04-27 Ian Lance Taylor <iant@google.com>
* x86_64.cc (do_adjust_output_section): Set entsize to

View File

@ -148,7 +148,6 @@ namespace gold
class General_options;
class Command_line;
class Input_argument_list;
class Dirsearch;
class Input_objects;
class Mapfile;
@ -293,7 +292,7 @@ queue_initial_tasks(const General_options&,
// Queue up the set of tasks to be done before
// the middle set of tasks. Only used when garbage
// collection is to be done.
// collection is to be done.
extern void
queue_middle_gc_tasks(const General_options&,
const Task*,

View File

@ -86,7 +86,7 @@ class Incremental_inputs_header_write
Incremental_inputs_header_write(unsigned char *p)
: p_(reinterpret_cast<internal::Incremental_inputs_header_data*>(p))
{ }
static const int data_size = sizeof(internal::Incremental_inputs_header_data);
void
@ -179,12 +179,114 @@ Incremental_inputs::report_command_line(int argc, const char* const* argv)
this->strtab_->add(args.c_str(), true, &this->command_line_key_);
}
// Record that the input argument INPUT is an achive ARCHIVE. This is
// called by Read_symbols after finding out the type of the file.
void
Incremental_inputs::report_archive(const Input_argument* input,
Archive* archive)
{
Hold_lock hl(*this->lock_);
Input_info info;
info.type = INCREMENTAL_INPUT_ARCHIVE;
info.archive = archive;
inputs_map_.insert(std::make_pair(input, info));
}
// Record that the input argument INPUT is an object OBJ. This is
// called by Read_symbols after finding out the type of the file.
void
Incremental_inputs::report_object(const Input_argument* input,
Object* obj)
{
Hold_lock hl(*this->lock_);
Input_info info;
info.type = (obj->is_dynamic()
? INCREMENTAL_INPUT_SHARED_LIBRARY
: INCREMENTAL_INPUT_OBJECT);
info.object = obj;
inputs_map_.insert(std::make_pair(input, info));
}
// Record that the input argument INPUT is an script SCRIPT. This is
// called by read_script after parsing the script and reading the list
// of inputs added by this script.
void
Incremental_inputs::report_script(const Input_argument* input,
Script_info* script)
{
Hold_lock hl(*this->lock_);
Input_info info;
info.type = INCREMENTAL_INPUT_SCRIPT;
info.script = script;
inputs_map_.insert(std::make_pair(input, info));
}
// Compute indexes in the order in which the inputs should appear in
// .gnu_incremental_inputs. This needs to be done after all the
// scripts are parsed. The function is first called for the command
// line inputs arguments and may call itself recursively for e.g. a
// list of elements of a group or a list of inputs added by a script.
// The [BEGIN; END) interval to analyze and *INDEX is the current
// value of the index (that will be updated).
void
Incremental_inputs::finalize_inputs(
Input_argument_list::const_iterator begin,
Input_argument_list::const_iterator end,
unsigned int* index)
{
for (Input_argument_list::const_iterator p = begin; p != end; ++p)
{
if (p->is_group())
{
finalize_inputs(p->group()->begin(), p->group()->end(), index);
continue;
}
Inputs_info_map::iterator it = inputs_map_.find(&(*p));
// TODO: turn it into an assert when the code will be more stable.
if (it == inputs_map_.end())
{
gold_error("internal error: %s: incremental build info not provided",
(p->is_file() ? p->file().name() : "[group]"));
continue;
}
Input_info* info = &it->second;
info->index = *index;
(*index)++;
this->strtab_->add(p->file().name(), false, &info->filename_key);
if (info->type == INCREMENTAL_INPUT_SCRIPT)
{
finalize_inputs(info->script->inputs()->begin(),
info->script->inputs()->end(),
index);
}
}
}
// Finalize the incremental link information. Called from
// Layout::finalize.
void
Incremental_inputs::finalize()
{
unsigned int index = 0;
finalize_inputs(this->inputs_->begin(), this->inputs_->end(), &index);
// Sanity check.
for (Inputs_info_map::const_iterator p = inputs_map_.begin();
p != inputs_map_.end();
++p)
{
gold_assert(p->second.filename_key != 0);
}
this->strtab_->set_string_offsets();
}
@ -213,7 +315,7 @@ Incremental_inputs::create_incremental_inputs_section_data()
#endif
default:
gold_unreachable();
}
}
}
// Sized creation of .gnu_incremental_inputs section.
@ -221,22 +323,49 @@ Incremental_inputs::create_incremental_inputs_section_data()
template<int size, bool big_endian>
Output_section_data*
Incremental_inputs::sized_create_inputs_section_data()
{
unsigned int sz =
{
const int entry_size =
Incremental_inputs_entry_write<size, big_endian>::data_size;
const int header_size =
Incremental_inputs_header_write<size, big_endian>::data_size;
unsigned int sz = header_size + entry_size * this->inputs_map_.size();
unsigned char* buffer = new unsigned char[sz];
unsigned char* inputs_base = buffer + header_size;
Incremental_inputs_header_write<size, big_endian> header_writer(buffer);
gold_assert(this->command_line_key_ > 0);
int cmd_offset = this->strtab_->get_offset_from_key(this->command_line_key_);
header_writer.put_version(INCREMENTAL_LINK_VERSION);
header_writer.put_input_file_count(0); // TODO: store input files data.
header_writer.put_input_file_count(this->inputs_map_.size());
header_writer.put_command_line_offset(cmd_offset);
header_writer.put_reserved(0);
for (Inputs_info_map::const_iterator it = this->inputs_map_.begin();
it != this->inputs_map_.end();
++it)
{
gold_assert(it->second.index < this->inputs_map_.size());
unsigned char* entry_buffer =
inputs_base + it->second.index * entry_size;
Incremental_inputs_entry_write<size, big_endian> entry(entry_buffer);
int filename_offset =
this->strtab_->get_offset_from_key(it->second.filename_key);
entry.put_filename_offset(filename_offset);
// TODO: add per input data and timestamp. Currently we store
// an out-of-bounds offset for future version of gold to reject
// such an incremental_inputs section.
entry.put_data_offset(0xffffffff);
entry.put_timestamp_sec(0);
entry.put_timestamp_usec(0);
entry.put_input_type(it->second.type);
entry.put_reserved(0);
}
return new Output_data_const_buffer(buffer, sz, 8,
"** incremental link inputs list");
"** incremental link inputs list");
}
} // End namespace gold.

View File

@ -23,6 +23,7 @@
#ifndef GOLD_INCREMENTAL_H
#define GOLD_INCREMENTAL_H
#include <map>
#include <vector>
#include "stringpool.h"
@ -37,20 +38,49 @@ class Incremental_inputs_checker;
class Object;
class Output_section_data;
// Incremental input type as stored in .gnu_incremental_inputs.
enum Incremental_input_type
{
INCREMENTAL_INPUT_INVALID = 0,
INCREMENTAL_INPUT_OBJECT = 1,
INCREMENTAL_INPUT_ARCHIVE = 2,
INCREMENTAL_INPUT_SHARED_LIBRARY = 3,
INCREMENTAL_INPUT_SCRIPT = 4
};
// This class contains the information needed during an incremental
// build about the inputs necessary to build the .gnu_incremental_inputs.
class Incremental_inputs
{
public:
Incremental_inputs()
: command_line_key_(0), strtab_(new Stringpool())
: lock_(new Lock()), inputs_(NULL), command_line_key_(0),
strtab_(new Stringpool())
{ }
~Incremental_inputs() { delete this->strtab_; }
// Record the command line.
void
report_command_line(int argc, const char* const* argv);
// Record the input arguments obtained from parsing the command line.
void
report_inputs(const Input_arguments& inputs)
{ this->inputs_ = &inputs; }
// Record that the input argument INPUT is an archive ARCHIVE.
void
report_archive(const Input_argument* input, Archive* archive);
// Record that the input argument INPUT is to an object OBJ.
void
report_object(const Input_argument* input, Object* obj);
// Record that the input argument INPUT is to an script SCRIPT.
void
report_script(const Input_argument* input, Script_info* script);
// Prepare for layout. Called from Layout::finalize.
void
finalize();
@ -58,8 +88,8 @@ class Incremental_inputs
// Create the content of the .gnu_incremental_inputs section.
Output_section_data*
create_incremental_inputs_section_data();
// Return the .gnu_incremental_strtab stringpool.
// Return the .gnu_incremental_strtab stringpool.
Stringpool*
get_stringpool()
{ return this->strtab_; }
@ -68,7 +98,57 @@ class Incremental_inputs
// Code for each of the four possible variants of create_inputs_section_data.
template<int size, bool big_endian>
Output_section_data*
sized_create_inputs_section_data();
sized_create_inputs_section_data();
// Compute indexes in the order in which the inputs should appear in
// .gnu_incremental_inputs and put file names to the stringtable.
// This needs to be done after all the scripts are parsed.
void
finalize_inputs(Input_argument_list::const_iterator begin,
Input_argument_list::const_iterator end,
unsigned int* index);
// Additional data about an input needed for an incremental link.
// None of these pointers is owned by the structure.
struct Input_info
{
Input_info()
: type(INCREMENTAL_INPUT_INVALID), archive(NULL), object(NULL),
script(NULL), filename_key(0), index(0)
{ }
// Type of the file pointed by this argument.
Incremental_input_type type;
// Present if type == INCREMENTAL_INPUT_ARCHIVE.
Archive* archive;
// Present if type == INCREMENTAL_INPUT_OBJECT or
// INCREMENTAL_INPUT_SHARED_LIBRARY.
Object* object;
// Present if type == INCREMENTAL_INPUT_SCRIPT.
Script_info* script;
// Key of the filename string in the section stringtable.
Stringpool::Key filename_key;
// Position of the entry information in the output section.
unsigned int index;
};
typedef std::map<const Input_argument*, Input_info> Inputs_info_map;
// A lock guarding access to inputs_ during the first phase of linking, when
// report_ function may be called from multiple threads.
Lock* lock_;
// The list of input arguments obtained from parsing the command line.
const Input_arguments* inputs_;
// A map containing additional information about the input elements.
Inputs_info_map inputs_map_;
// The key of the command line string in the string pool.
Stringpool::Key command_line_key_;

View File

@ -221,7 +221,10 @@ main(int argc, char** argv)
&command_line.script_options());
if (layout.incremental_inputs() != NULL)
layout.incremental_inputs()->report_command_line(argc, argv);
{
layout.incremental_inputs()->report_command_line(argc, argv);
layout.incremental_inputs()->report_inputs(command_line.inputs());
}
// Get the search path from the -L options.
Dirsearch search_path;

View File

@ -1275,14 +1275,15 @@ class Input_argument
Input_file_group* group_;
};
typedef std::vector<Input_argument> Input_argument_list;
// A group from the command line. This is a set of arguments within
// --start-group ... --end-group.
class Input_file_group
{
public:
typedef std::vector<Input_argument> Files;
typedef Files::const_iterator const_iterator;
typedef Input_argument_list::const_iterator const_iterator;
Input_file_group()
: files_()
@ -1304,7 +1305,7 @@ class Input_file_group
{ return this->files_.end(); }
private:
Files files_;
Input_argument_list files_;
};
// A list of files from the command line or a script.
@ -1312,7 +1313,6 @@ class Input_file_group
class Input_arguments
{
public:
typedef std::vector<Input_argument> Input_argument_list;
typedef Input_argument_list::const_iterator const_iterator;
Input_arguments()

View File

@ -407,6 +407,9 @@ Plugin_manager::add_input_file(char *pathname)
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"));
this->workqueue_->queue_soon(new Read_symbols(this->input_objects_,
this->symtab_,
this->layout_,

View File

@ -33,6 +33,8 @@
#include "script.h"
#include "readsyms.h"
#include "plugin.h"
#include "layout.h"
#include "incremental.h"
namespace gold
{
@ -199,7 +201,7 @@ Read_symbols::do_read_symbols(Workqueue* workqueue)
{
bool is_thin_archive
= memcmp(ehdr, Archive::armagt, Archive::sarmag) == 0;
if (is_thin_archive
if (is_thin_archive
|| memcmp(ehdr, Archive::armag, Archive::sarmag) == 0)
{
// This is an archive.
@ -207,7 +209,13 @@ Read_symbols::do_read_symbols(Workqueue* workqueue)
input_file, is_thin_archive,
this->dirpath_, this);
arch->setup();
if (this->layout_->incremental_inputs())
{
const Input_argument* ia = this->input_argument_;
this->layout_->incremental_inputs()->report_archive(ia, arch);
}
// Unlock the archive so it can be used in the next task.
arch->unlock(this);
@ -280,6 +288,12 @@ Read_symbols::do_read_symbols(Workqueue* workqueue)
Read_symbols_data* sd = new Read_symbols_data;
obj->read_symbols(sd);
if (this->layout_->incremental_inputs())
{
const Input_argument* ia = this->input_argument_;
this->layout_->incremental_inputs()->report_object(ia, obj);
}
// 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

View File

@ -43,6 +43,7 @@
#include "target-select.h"
#include "script.h"
#include "script-c.h"
#include "incremental.h"
namespace gold
{
@ -1414,6 +1415,13 @@ read_input_script(Workqueue* workqueue, Symbol_table* symtab, Layout* layout,
this_blocker = nb;
}
if (layout->incremental_inputs())
{
// Like new Read_symbols(...) above, we rely on close.inputs()
// getting leaked by closure.
Script_info* info = new Script_info(closure.inputs());
layout->incremental_inputs()->report_script(input_argument, info);
}
*used_next_blocker = true;
return true;

View File

@ -45,6 +45,7 @@ class Symbol_table;
class Layout;
class Mapfile;
class Input_argument;
class Input_arguments;
class Input_objects;
class Input_group;
class Input_file;
@ -382,6 +383,26 @@ class Script_options
Script_sections script_sections_;
};
// Information about a script input that will persist during the whole linker
// run. Needed only during an incremental build to retrieve the input files
// added by this script.
class Script_info
{
public:
Script_info(Input_arguments* inputs)
: inputs_(inputs)
{ }
// Returns the input files included because of this script.
Input_arguments*
inputs()
{ return inputs_; }
private:
Input_arguments* inputs_;
};
// FILE was found as an argument on the command line, but was not
// recognized as an ELF file. Try to read it as a script. Return
// true if the file was handled. This has to handle /usr/lib/libc.so