Fix bug this exposed in archive armap symbol name handling.
if (xname == "/")
{
const unsigned char* p = this->get_view(off + sizeof(Archive_header),
- extended_size);
+ extended_size, false);
const char* px = reinterpret_cast<const char*>(p);
this->extended_names_.assign(px, extended_size);
}
Archive::read_armap(off_t start, off_t size)
{
// Read in the entire armap.
- const unsigned char* p = this->get_view(start, size);
+ const unsigned char* p = this->get_view(start, size, false);
// Numbers in the armap are always big-endian.
const elfcpp::Elf_Word* pword = reinterpret_cast<const elfcpp::Elf_Word*>(p);
// Note that the addition is in units of sizeof(elfcpp::Elf_Word).
const char* pnames = reinterpret_cast<const char*>(pword + nsyms);
+ off_t names_size = reinterpret_cast<const char*>(p) + size - pnames;
+ this->armap_names_.assign(pnames, names_size);
this->armap_.resize(nsyms);
+ off_t name_offset = 0;
for (unsigned int i = 0; i < nsyms; ++i)
{
- this->armap_[i].name = pnames;
- this->armap_[i].offset = elfcpp::Swap<32, true>::readval(pword);
- pnames += strlen(pnames) + 1;
+ this->armap_[i].name_offset = name_offset;
+ this->armap_[i].file_offset = elfcpp::Swap<32, true>::readval(pword);
+ name_offset += strlen(pnames + name_offset) + 1;
++pword;
}
off_t
Archive::read_header(off_t off, std::string* pname)
{
- const unsigned char* p = this->get_view(off, sizeof(Archive_header));
+ const unsigned char* p = this->get_view(off, sizeof(Archive_header), false);
const Archive_header* hdr = reinterpret_cast<const Archive_header*>(p);
return this->interpret_header(hdr, off, pname);
}
{
if (this->armap_checked_[i])
continue;
- if (this->armap_[i].offset == last_seen_offset)
+ if (this->armap_[i].file_offset == last_seen_offset)
{
this->armap_checked_[i] = true;
continue;
}
- if (this->seen_offsets_.find(this->armap_[i].offset)
+ if (this->seen_offsets_.find(this->armap_[i].file_offset)
!= this->seen_offsets_.end())
{
this->armap_checked_[i] = true;
- last_seen_offset = this->armap_[i].offset;
+ last_seen_offset = this->armap_[i].file_offset;
continue;
}
- Symbol* sym = symtab->lookup(this->armap_[i].name);
+ const char* sym_name = (this->armap_names_.data()
+ + this->armap_[i].name_offset);
+ Symbol* sym = symtab->lookup(sym_name);
if (sym == NULL)
continue;
else if (!sym->is_undefined())
continue;
// We want to include this object in the link.
- last_seen_offset = this->armap_[i].offset;
+ last_seen_offset = this->armap_[i].file_offset;
this->seen_offsets_.insert(last_seen_offset);
this->armap_checked_[i] = true;
this->include_member(symtab, layout, input_objects,
{
public:
Archive(const std::string& name, Input_file* input_file)
- : name_(name), input_file_(input_file), armap_(), extended_names_()
+ : name_(name), input_file_(input_file), armap_(), armap_names_(),
+ extended_names_(), armap_checked_(), seen_offsets_()
{ }
// The length of the magic string at the start of an archive.
// Get a view into the underlying file.
const unsigned char*
- get_view(off_t start, off_t size)
- { return this->input_file_->file().get_view(start, size); }
+ get_view(off_t start, off_t size, bool cache)
+ { return this->input_file_->file().get_view(start, size, cache); }
// Read the archive symbol map.
void
// An entry in the archive map of symbols to object files.
struct Armap_entry
{
- // The symbol name.
- const char* name;
- // The offset to the file.
- off_t offset;
+ // The offset to the symbol name in armap_names_.
+ off_t name_offset;
+ // The file offset to the object in the archive.
+ off_t file_offset;
};
// A simple hash code for off_t values.
Input_file* input_file_;
// The archive map.
std::vector<Armap_entry> armap_;
+ // The names in the archive map.
+ std::string armap_names_;
// The extended name table.
std::string extended_names_;
// Track which symbols in the archive map are for elements which are
gold_exit(false);
}
- *view = this->get_lasting_view(shdr.get_sh_offset(), shdr.get_sh_size());
+ *view = this->get_lasting_view(shdr.get_sh_offset(), shdr.get_sh_size(),
+ false);
*view_size = shdr.get_sh_size();
*view_info = shdr.get_sh_info();
}
const off_t dynamic_size = dynamicshdr.get_sh_size();
const unsigned char* pdynamic = this->get_view(dynamicshdr.get_sh_offset(),
- dynamic_size);
+ dynamic_size, false);
const unsigned int link = dynamicshdr.get_sh_link();
if (link != strtab_shndx)
}
strtab_size = strtabshdr.get_sh_size();
- strtabu = this->get_view(strtabshdr.get_sh_offset(), strtab_size);
+ strtabu = this->get_view(strtabshdr.get_sh_offset(), strtab_size, false);
}
for (const unsigned char* p = pdynamic;
gold_assert(dynsymshdr.get_sh_type() == elfcpp::SHT_DYNSYM);
sd->symbols = this->get_lasting_view(dynsymshdr.get_sh_offset(),
- dynsymshdr.get_sh_size());
+ dynsymshdr.get_sh_size(), false);
sd->symbols_size = dynsymshdr.get_sh_size();
// Get the symbol names.
}
sd->symbol_names = this->get_lasting_view(strtabshdr.get_sh_offset(),
- strtabshdr.get_sh_size());
+ strtabshdr.get_sh_size(),
+ true);
sd->symbol_names_size = strtabshdr.get_sh_size();
// Get the version information.
{
gold_assert(this->lock_count_ > 0);
--this->lock_count_;
+ if (this->lock_count_ == 0)
+ this->clear_views(false);
}
bool
}
// Read SIZE bytes from the file starting at offset START. Read into
-// the buffer at P. Return the number of bytes read, which should
-// always be at least SIZE except at the end of the file.
+// the buffer at P.
-off_t
+void
File_read::do_read(off_t start, off_t size, void* p)
{
gold_assert(this->lock_count_ > 0);
+ off_t bytes;
if (this->contents_ != NULL)
{
- off_t bytes = this->size_ - start;
- if (bytes < 0)
- bytes = 0;
- else if (bytes > size)
- bytes = size;
- memcpy(p, this->contents_ + start, bytes);
- return bytes;
+ bytes = this->size_ - start;
+ if (bytes >= size)
+ {
+ memcpy(p, this->contents_ + start, size);
+ return;
+ }
}
-
- off_t bytes = ::pread(this->descriptor_, p, size, start);
- if (bytes < 0)
+ else
{
- fprintf(stderr, _("%s: %s: pread failed: %s\n"),
- program_name, this->filename().c_str(), strerror(errno));
- gold_exit(false);
- }
-
- return bytes;
-}
-
-// Read exactly SIZE bytes from the file starting at offset START.
-// Read into the buffer at P.
+ bytes = ::pread(this->descriptor_, p, size, start);
+ if (bytes == size)
+ return;
-void
-File_read::do_read_exact(off_t start, off_t size, void* p)
-{
- off_t bytes = this->do_read(start, size, p);
- if (bytes != size)
- {
- fprintf(stderr,
- _("%s: %s: file too short: read only %lld of %lld "
- "bytes at %lld\n"),
- program_name, this->filename().c_str(),
- static_cast<long long>(bytes),
- static_cast<long long>(size),
- static_cast<long long>(start));
- gold_exit(false);
+ if (bytes < 0)
+ {
+ fprintf(stderr, _("%s: %s: pread failed: %s\n"),
+ program_name, this->filename().c_str(), strerror(errno));
+ gold_exit(false);
+ }
}
+
+ fprintf(stderr,
+ _("%s: %s: file too short: read only %lld of %lld bytes at %lld\n"),
+ program_name, this->filename().c_str(),
+ static_cast<long long>(bytes),
+ static_cast<long long>(size),
+ static_cast<long long>(start));
+ gold_exit(false);
}
// Read data from the file.
return;
}
- this->do_read_exact(start, size, p);
+ this->do_read(start, size, p);
}
// Find an existing view or make a new one.
File_read::View*
-File_read::find_or_make_view(off_t start, off_t size)
+File_read::find_or_make_view(off_t start, off_t size, bool cache)
{
gold_assert(this->lock_count_ > 0);
// There was an existing view at this offset.
File_read::View* v = ins.first->second;
if (v->size() - (start - v->start()) >= size)
- return v;
+ {
+ if (cache)
+ v->set_cache();
+ return v;
+ }
// This view is not large enough.
this->saved_views_.push_back(v);
unsigned char* p = new unsigned char[psize];
- this->do_read_exact(poff, psize, p);
+ this->do_read(poff, psize, p);
- File_read::View* v = new File_read::View(poff, psize, p);
+ File_read::View* v = new File_read::View(poff, psize, p, cache);
ins.first->second = v;
return v;
}
// mmap.
const unsigned char*
-File_read::get_view(off_t start, off_t size)
+File_read::get_view(off_t start, off_t size, bool cache)
{
gold_assert(this->lock_count_ > 0);
- File_read::View* pv = this->find_or_make_view(start, size);
+ File_read::View* pv = this->find_or_make_view(start, size, cache);
return pv->data() + (start - pv->start());
}
File_view*
-File_read::get_lasting_view(off_t start, off_t size)
+File_read::get_lasting_view(off_t start, off_t size, bool cache)
{
gold_assert(this->lock_count_ > 0);
- File_read::View* pv = this->find_or_make_view(start, size);
+ File_read::View* pv = this->find_or_make_view(start, size, cache);
pv->lock();
return new File_view(*this, pv, pv->data() + (start - pv->start()));
}
p != this->views_.end();
++p)
{
- if (!p->second->is_locked())
+ if (!p->second->is_locked()
+ && (destroying || !p->second->should_cache()))
delete p->second;
else
{
Saved_views::iterator p = this->saved_views_.begin();
while (p != this->saved_views_.end())
{
- if (!(*p)->is_locked())
+ if (!(*p)->is_locked()
+ && (destroying || !(*p)->should_cache()))
{
delete *p;
p = this->saved_views_.erase(p);
// Return a view into the file starting at file offset START for
// SIZE bytes. 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.
+ // 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 start, off_t size);
+ get_view(off_t start, off_t size, bool cache);
// Read data from the file into the buffer P starting at file offset
// START for SIZE bytes.
// 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.
+ // error if we can not read enough data from the file. The CACHE
+ // parameter is as in get_view.
File_view*
- get_lasting_view(off_t start, off_t size);
+ get_lasting_view(off_t start, off_t size, bool cache);
private:
// This class may not be copied.
class View
{
public:
- View(off_t start, off_t size, const unsigned char* data)
- : start_(start), size_(size), data_(data), lock_count_(0)
+ View(off_t start, off_t size, const unsigned char* data, bool cache)
+ : start_(start), size_(size), data_(data), lock_count_(0),
+ cache_(cache)
{ }
~View();
bool
is_locked();
+ void
+ set_cache()
+ { this->cache_ = true; }
+
+ bool
+ should_cache() const
+ { return this->cache_; }
+
private:
View(const View&);
View& operator=(const View&);
off_t size_;
const unsigned char* data_;
int lock_count_;
+ bool cache_;
};
friend class File_view;
find_view(off_t start, off_t size);
// Read data from the file into a buffer.
- off_t
- do_read(off_t start, off_t size, void* p);
-
- // Read an exact number of bytes into a buffer.
void
- do_read_exact(off_t start, off_t size, void* p);
+ do_read(off_t start, off_t size, void* p);
// Find or make a view into the file.
View*
- find_or_make_view(off_t start, off_t size);
+ find_or_make_view(off_t start, off_t size, bool cache);
// Clear the file views.
void
Output_merge_data::do_add_input_section(Relobj* object, unsigned int shndx)
{
off_t len;
- const unsigned char* p = object->section_contents(shndx, &len);
+ const unsigned char* p = object->section_contents(shndx, &len, false);
uint64_t entsize = this->entsize();
unsigned int shndx)
{
off_t len;
- const unsigned char* pdata = object->section_contents(shndx, &len);
+ const unsigned char* pdata = object->section_contents(shndx, &len, false);
const Char_type* p = reinterpret_cast<const Char_type*>(pdata);
// Return a view of the contents of a section.
const unsigned char*
-Object::section_contents(unsigned int shndx, off_t* plen)
+Object::section_contents(unsigned int shndx, off_t* plen, bool cache)
{
Location loc(this->do_section_contents(shndx));
*plen = loc.data_size;
- return this->get_view(loc.file_offset, loc.data_size);
+ return this->get_view(loc.file_offset, loc.data_size, cache);
}
// Read the section data into SD. This is code common to Sized_relobj
// Read the section headers.
const off_t shoff = elf_file->shoff();
const unsigned int shnum = this->shnum();
- sd->section_headers = this->get_lasting_view(shoff, shnum * shdr_size);
+ sd->section_headers = this->get_lasting_view(shoff, shnum * shdr_size, true);
// Read the section names.
const unsigned char* pshdrs = sd->section_headers->data();
sd->section_names_size = shdrnames.get_sh_size();
sd->section_names = this->get_lasting_view(shdrnames.get_sh_offset(),
- sd->section_names_size);
+ sd->section_names_size, false);
}
// If NAME is the name of a special .gnu.warning section, arrange for
off_t extsize = symtabshdr.get_sh_size() - locsize;
// Read the symbol table.
- File_view* fvsymtab = this->get_lasting_view(extoff, extsize);
+ File_view* fvsymtab = this->get_lasting_view(extoff, extsize, false);
// Read the section header for the symbol names.
unsigned int strtab_shndx = symtabshdr.get_sh_link();
// Read the symbol names.
File_view* fvstrtab = this->get_lasting_view(strtabshdr.get_sh_offset(),
- strtabshdr.get_sh_size());
+ strtabshdr.get_sh_size(), true);
sd->symbols = fvsymtab;
sd->symbols_size = extsize;
{
// Read the section contents.
const unsigned char* pcon = this->get_view(shdr.get_sh_offset(),
- shdr.get_sh_size());
+ shdr.get_sh_size(), false);
const elfcpp::Elf_Word* pword =
reinterpret_cast<const elfcpp::Elf_Word*>(pcon);
gold_exit(false);
}
off_t symoff = symshdr.get_sh_offset() + shdr.get_sh_info() * This::sym_size;
- const unsigned char* psym = this->get_view(symoff, This::sym_size);
+ const unsigned char* psym = this->get_view(symoff, This::sym_size, true);
elfcpp::Sym<size, big_endian> sym(psym);
// Read the symbol table names.
off_t symnamelen;
const unsigned char* psymnamesu;
- psymnamesu = this->section_contents(symshdr.get_sh_link(), &symnamelen);
+ psymnamesu = this->section_contents(symshdr.get_sh_link(), &symnamelen,
+ true);
const char* psymnames = reinterpret_cast<const char*>(psymnamesu);
// Get the section group signature.
gold_assert(loccount == symtabshdr.get_sh_info());
off_t locsize = loccount * sym_size;
const unsigned char* psyms = this->get_view(symtabshdr.get_sh_offset(),
- locsize);
+ locsize, true);
this->local_values_.resize(loccount);
const unsigned int strtab_shndx = symtabshdr.get_sh_link();
off_t strtab_size;
const unsigned char* pnamesu = this->section_contents(strtab_shndx,
- &strtab_size);
+ &strtab_size,
+ true);
const char* pnames = reinterpret_cast<const char*>(pnamesu);
// Loop over the local symbols.
const int sym_size = This::sym_size;
off_t locsize = loccount * sym_size;
const unsigned char* psyms = this->get_view(symtabshdr.get_sh_offset(),
- locsize);
+ locsize, false);
// Read the symbol names.
const unsigned int strtab_shndx = symtabshdr.get_sh_link();
off_t strtab_size;
const unsigned char* pnamesu = this->section_contents(strtab_shndx,
- &strtab_size);
+ &strtab_size,
+ true);
const char* pnames = reinterpret_cast<const char*>(pnamesu);
// Get a view into the output file.
{ return this->shnum_; }
// Return a view of the contents of a section. Set *PLEN to the
- // size.
+ // size. CACHE is a hint as in File_read::get_view.
const unsigned char*
- section_contents(unsigned int shndx, off_t* plen);
+ section_contents(unsigned int shndx, off_t* plen, bool cache);
// Return the name of a section given a section index. This is only
// used for error messages.
// Return a View.
View
view(off_t file_offset, off_t data_size)
- { return View(this->get_view(file_offset, data_size)); }
+ { return View(this->get_view(file_offset, data_size, true)); }
// Report an error.
void
// Get a View given a Location.
View view(Location loc)
- { return View(this->get_view(loc.file_offset, loc.data_size)); }
+ { return View(this->get_view(loc.file_offset, loc.data_size, true)); }
protected:
// Read the symbols--implemented by child class.
// Get a view into the underlying file.
const unsigned char*
- get_view(off_t start, off_t size)
- { return this->input_file_->file().get_view(start + this->offset_, size); }
+ get_view(off_t start, off_t size, bool cache)
+ {
+ return this->input_file_->file().get_view(start + this->offset_, size,
+ cache);
+ }
// Get a lasting view into the underlying file.
File_view*
- get_lasting_view(off_t start, off_t size)
+ get_lasting_view(off_t start, off_t size, bool cache)
{
return this->input_file_->file().get_lasting_view(start + this->offset_,
- size);
+ size, cache);
}
// Read data from the underlying file.
rd->relocs.reserve(shnum / 2);
const unsigned char *pshdrs = this->get_view(this->elf_file_.shoff(),
- shnum * This::shdr_size);
+ shnum * This::shdr_size,
+ true);
// Skip the first, dummy, section.
const unsigned char *ps = pshdrs + This::shdr_size;
for (unsigned int i = 1; i < shnum; ++i, ps += This::shdr_size)
Section_relocs& sr(rd->relocs.back());
sr.reloc_shndx = i;
sr.data_shndx = shndx;
- sr.contents = this->get_lasting_view(shdr.get_sh_offset(), sh_size);
+ sr.contents = this->get_lasting_view(shdr.get_sh_offset(), sh_size,
+ true);
sr.sh_type = sh_type;
sr.reloc_count = reloc_count;
}
gold_assert(loccount == symtabshdr.get_sh_info());
off_t locsize = loccount * sym_size;
rd->local_symbols = this->get_lasting_view(symtabshdr.get_sh_offset(),
- locsize);
+ locsize, true);
}
}
// Read the section headers.
const unsigned char* pshdrs = this->get_view(this->elf_file_.shoff(),
- shnum * This::shdr_size);
+ shnum * This::shdr_size,
+ true);
Views views;
views.resize(shnum);
off_t sh_size = shdr.get_sh_size();
const unsigned char* prelocs = this->get_view(shdr.get_sh_offset(),
- sh_size);
+ sh_size, false);
unsigned int reloc_size;
if (sh_type == elfcpp::SHT_REL)
Task_locker_obj<Object> tl(*p->second.object);
const unsigned char* c;
off_t len;
- c = p->second.object->section_contents(p->second.shndx, &len);
+ c = p->second.object->section_contents(p->second.shndx, &len,
+ false);
p->second.set_text(reinterpret_cast<const char*>(c), len);
}
}