// fileread.h -- read files for gold -*- C++ -*-// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.// Written by Ian Lance Taylor <iant@google.com>.// 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.// Classes used to read data from binary input files.#ifndef GOLD_FILEREAD_H#define GOLD_FILEREAD_H#include <list>#include <map>#include <string>#include <vector>#include "token.h"namespace gold{class Position_dependent_options;class Input_file_argument;class Dirsearch;class File_view;// File_read manages a file descriptor and mappings for a file we are// reading.class File_read{public:File_read(): name_(), descriptor_(-1), is_descriptor_opened_(false), object_count_(0),size_(0), token_(false), views_(), saved_views_(), contents_(NULL),mapped_bytes_(0), released_(true){ }~File_read();// Open a file.boolopen(const Task*, const std::string& name);// Pretend to open the file, but provide the file contents. No// actual file system activity will occur. This is used for// testing.boolopen(const Task*, const std::string& name, const unsigned char* contents,off_t size);// Return the file name.const std::string&filename() const{ return this->name_; }// Add an object associated with a file.voidadd_object(){ ++this->object_count_; }// Remove an object associated with a file.voidremove_object(){ --this->object_count_; }// Lock the file for exclusive access within a particular Task::run// execution. This routine may only be called when the workqueue// lock is held.voidlock(const Task* t);// Unlock the file.voidunlock(const Task* t);// Test whether the object is locked.boolis_locked() const;// Return the token, so that the task can be queued.Task_token*token(){ return &this->token_; }// Release the file. This indicates that we aren't going to do// anything further with it until it is unlocked. This is used// because a Task which locks the file never calls either lock or// unlock; it just locks the token. The basic rule is that a Task// which locks a file via the Task::locks interface must explicitly// call release() when it is done. This is not necessary for code// which calls unlock() on the file.voidrelease();// Return the size of the file.off_tfilesize() const{ return this->size_; }// Return a view into the file starting at file offset START for// SIZE bytes. OFFSET is the offset into the input file for the// file we are reading; this is zero for a normal object file,// non-zero for an object file in an archive. ALIGNED is true if// the data must be naturally aligned; this only matters when OFFSET// is not zero. The pointer will remain valid until the File_read// is unlocked. It is an error if we can not read enough data from// the file. The CACHE parameter is a hint as to whether it will be// useful to cache this data for later accesses--i.e., later calls// to get_view, read, or get_lasting_view which retrieve the same// data.const unsigned char*get_view(off_t offset, off_t start, section_size_type size, bool aligned,bool cache);// Read data from the file into the buffer P starting at file offset// START for SIZE bytes.voidread(off_t start, section_size_type size, void* p);// Return a lasting view into the file starting at file offset START// for SIZE bytes. This is allocated with new, and the caller is// responsible for deleting it when done. The data associated with// this view will remain valid until the view is deleted. It is an// error if we can not read enough data from the file. The OFFSET,// ALIGNED and CACHE parameters are as in get_view.File_view*get_lasting_view(off_t offset, off_t start, section_size_type size,bool aligned, bool cache);// Mark all views as no longer cached.voidclear_view_cache_marks();// Discard all uncached views. This is normally done by release(),// but not for objects in archives. FIXME: This is a complicated// interface, and it would be nice to have something more automatic.voidclear_uncached_views(){ this->clear_views(false); }// A struct used to do a multiple read.struct Read_multiple_entry{// The file offset of the data to read.off_t file_offset;// The amount of data to read.section_size_type size;// The buffer where the data should be placed.unsigned char* buffer;Read_multiple_entry(off_t o, section_size_type s, unsigned char* b): file_offset(o), size(s), buffer(b){ }};typedef std::vector<Read_multiple_entry> Read_multiple;// Read a bunch of data from the file into various different// locations. The vector must be sorted by ascending file_offset.// BASE is a base offset to be added to all the offsets in the// vector.voidread_multiple(off_t base, const Read_multiple&);// Dump statistical information to stderr.static voidprint_stats();private:// This class may not be copied.File_read(const File_read&);File_read& operator=(const File_read&);// Total bytes mapped into memory during the link. This variable// may not be accurate when running multi-threaded.static unsigned long long total_mapped_bytes;// Current number of bytes mapped into memory during the link. This// variable may not be accurate when running multi-threaded.static unsigned long long current_mapped_bytes;// High water mark of bytes mapped into memory during the link.// This variable may not be accurate when running multi-threaded.static unsigned long long maximum_mapped_bytes;// A view into the file.class View{public:View(off_t start, section_size_type size, const unsigned char* data,unsigned int byteshift, bool cache, bool mapped): start_(start), size_(size), data_(data), lock_count_(0),byteshift_(byteshift), cache_(cache), mapped_(mapped), accessed_(true){ }~View();off_tstart() const{ return this->start_; }section_size_typesize() const{ return this->size_; }const unsigned char*data() const{ return this->data_; }voidlock();voidunlock();boolis_locked();unsigned intbyteshift() const{ return this->byteshift_; }voidset_cache(){ this->cache_ = true; }voidclear_cache(){ this->cache_ = false; }boolshould_cache() const{ return this->cache_; }voidset_accessed(){ this->accessed_ = true; }voidclear_accessed(){ this->accessed_= false; }boolaccessed() const{ return this->accessed_; }private:View(const View&);View& operator=(const View&);// The file offset of the start of the view.off_t start_;// The size of the view.section_size_type size_;// A pointer to the actual bytes.const unsigned char* data_;// The number of locks on this view.int lock_count_;// The number of bytes that the view is shifted relative to the// underlying file. This is used to align data. This is normally// zero, except possibly for an object in an archive.unsigned int byteshift_;// Whether the view is cached.bool cache_;// Whether the view is mapped into memory. If not, data_ points// to memory allocated using new[].bool mapped_;// Whether the view has been accessed recently.bool accessed_;};friend class View;friend class File_view;// The type of a mapping from page start and byte shift to views.typedef std::map<std::pair<off_t, unsigned int>, View*> Views;// A simple list of Views.typedef std::list<View*> Saved_views;// Open the descriptor if necessary.voidreopen_descriptor();// Find a view into the file.View*find_view(off_t start, section_size_type size, unsigned int byteshift,View** vshifted) const;// Read data from the file into a buffer.voiddo_read(off_t start, section_size_type size, void* p);// Add a view.voidadd_view(View*);// Make a view into the file.View*make_view(off_t start, section_size_type size, unsigned int byteshift,bool cache);// Find or make a view into the file.View*find_or_make_view(off_t offset, off_t start, section_size_type size,bool aligned, bool cache);// Clear the file views.voidclear_views(bool);// The size of a file page for buffering data.static const off_t page_size = 8192;// Given a file offset, return the page offset.static off_tpage_offset(off_t file_offset){ return file_offset & ~ (page_size - 1); }// Given a file size, return the size to read integral pages.static off_tpages(off_t file_size){ return (file_size + (page_size - 1)) & ~ (page_size - 1); }// The maximum number of entries we will pass to ::readv.static const size_t max_readv_entries = 128;// Use readv to read data.voiddo_readv(off_t base, const Read_multiple&, size_t start, size_t count);// File name.std::string name_;// File descriptor.int descriptor_;// Whether we have regained the descriptor after releasing the file.bool is_descriptor_opened_;// The number of objects associated with this file. This will be// more than 1 in the case of an archive.int object_count_;// File size.off_t size_;// A token used to lock the file.Task_token token_;// Buffered views into the file.Views views_;// List of views which were locked but had to be removed from views_// because they were not large enough.Saved_views saved_views_;// Specified file contents. Used only for testing purposes.const unsigned char* contents_;// Total amount of space mapped into memory. This is only changed// while the file is locked. When we unlock the file, we transfer// the total to total_mapped_bytes, and reset this to zero.size_t mapped_bytes_;// Whether the file was released.bool released_;};// A view of file data that persists even when the file is unlocked.// Callers should destroy these when no longer required. These are// obtained form File_read::get_lasting_view. They may only be// destroyed when the underlying File_read is locked.class File_view{public:// This may only be called when the underlying File_read is locked.~File_view();// Return a pointer to the data associated with this view.const unsigned char*data() const{ return this->data_; }private:File_view(const File_view&);File_view& operator=(const File_view&);friend class File_read;// Callers have to get these via File_read::get_lasting_view.File_view(File_read& file, File_read::View* view, const unsigned char* data): file_(file), view_(view), data_(data){ }File_read& file_;File_read::View* view_;const unsigned char* data_;};// All the information we hold for a single input file. This can be// an object file, a shared library, or an archive.class Input_file{public:Input_file(const Input_file_argument* input_argument): input_argument_(input_argument), found_name_(), file_(),is_in_sysroot_(false){ }// Create an input file with the contents already provided. This is// only used for testing. With this path, don't call the open// method.Input_file(const Task*, const char* name, const unsigned char* contents,off_t size);// Open the file. If the open fails, this will report an error and// return false.boolopen(const General_options&, const Dirsearch&, const Task*);// Return the name given by the user. For -lc this will return "c".const char*name() const;// Return the file name. For -lc this will return something like// "/usr/lib/libc.so".const std::string&filename() const{ return this->file_.filename(); }// Return the name under which we found the file, corresponding to// the command line. For -lc this will return something like// "libc.so".const std::string&found_name() const{ return this->found_name_; }// Return the position dependent options.const Position_dependent_options&options() const;// Return the file.File_read&file(){ return this->file_; }const File_read&file() const{ return this->file_; }// Whether we found the file in a directory in the system root.boolis_in_sysroot() const{ return this->is_in_sysroot_; }// Return whether this file is to be read only for its symbols.booljust_symbols() const;private:Input_file(const Input_file&);Input_file& operator=(const Input_file&);// Open a binary file.boolopen_binary(const General_options&, const Task* task,const std::string& name);// The argument from the command line.const Input_file_argument* input_argument_;// The name under which we opened the file. This is like the name// on the command line, but -lc turns into libc.so (or whatever).// It only includes the full path if the path was on the command// line.std::string found_name_;// The file after we open it.File_read file_;// Whether we found the file in a directory in the system root.bool is_in_sysroot_;};} // end namespace gold#endif // !defined(GOLD_FILEREAD_H)