rtems-tools/rtemstoolkit/rld-files.cpp
Chris Johns 53e387d9a4 linkers: Merge the standard libraries into the user library paths.
The change to rld::split clears the user's library paths. Fix
this.
2014-11-04 19:39:57 +11:00

1609 lines
38 KiB
C++

/*
* Copyright (c) 2011, Chris Johns <chrisj@rtems.org>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <algorithm>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <rld.h>
#if __WIN32__
#define CREATE_MODE (S_IRUSR | S_IWUSR)
#define OPEN_FLAGS (O_BINARY)
#else
#define CREATE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH)
#define OPEN_FLAGS (0)
#endif
namespace rld
{
namespace files
{
/**
* Scan the decimal number returning the value found.
*/
uint64_t
scan_decimal (const uint8_t* string, size_t len)
{
uint64_t value = 0;
while (len && (*string != ' '))
{
value *= 10;
value += *string - '0';
++string;
--len;
}
return value;
}
void
set_number (uint32_t value, uint8_t* string, size_t len, bool octal = false)
{
std::ostringstream oss;
if (octal)
oss << std::oct;
oss << value;
size_t l = oss.str ().length ();
if (l > len)
l = len;
memcpy (string, oss.str ().c_str (), l);
}
file::file (const std::string& aname,
const std::string& oname,
off_t offset,
size_t size)
: aname_ (aname),
oname_ (oname),
offset_ (offset),
size_ (size)
{
}
file::file (const std::string& path, bool is_object)
: offset_ (0),
size_ (0)
{
set (path, is_object);
}
file::file ()
: offset_ (0),
size_ (0)
{
}
void
file::set (const std::string& path, bool is_object)
{
/*
* If there is a path look for a colon. If there is no colon we assume
* it is an object file. If the colon is the last character in the path
* it is just an archive.
*/
if (!path.empty ())
{
bool get_size = false;
if (is_object)
{
size_t colon = path.find_last_of (':');
if ((colon != std::string::npos) && (colon > RLD_DRIVE_SEPARATOR))
{
aname_ = path.substr (0, colon - 1);
oname_ = path.substr (colon + 1);
// @todo Add offset scanning.
}
else
{
oname_ = path;
get_size = true;
}
}
else
{
aname_ = path;
get_size = true;
}
if (get_size)
{
struct stat sb;
if (::stat (path.c_str (), &sb) == 0)
size_ = sb.st_size;
}
}
}
bool
file::is_archive () const
{
return !aname_.empty () && oname_.empty ();
}
bool
file::is_object () const
{
return !oname_.empty ();
}
bool
file::is_valid () const
{
return !aname_.empty () || !oname_.empty ();
}
bool
file::exists () const
{
/*
* No name set returns false.
*/
bool result = false;
const std::string p = path ();
if (!p.empty ())
result = path::check_file (p);
return result;
}
const std::string
file::path () const
{
if (!aname_.empty ())
return aname_;
return oname_;
}
const std::string
file::full () const
{
std::string f;
if (!aname_.empty ())
{
f = aname_;
if (!oname_.empty ())
f += ':';
}
if (!oname_.empty ())
f += oname_;
if (!aname_.empty () && !oname_.empty ())
f += '@' + rld::to_string (offset_);
return f;
}
const std::string
file::basename () const
{
return rld::path::basename (full ());
}
const std::string&
file::aname () const
{
return aname_;
}
const std::string&
file::oname () const
{
return oname_;
}
off_t
file::offset () const
{
return offset_;
}
size_t
file::size () const
{
return size_;
}
image::image (file& name)
: name_ (name),
references_ (0),
fd_ (-1),
symbol_refs (0),
writable (false)
{
}
image::image (const std::string& path, bool is_object)
: name_ (path, is_object),
references_ (0),
fd_ (-1),
symbol_refs (0),
writable (false)
{
}
image::image ()
: references_ (0),
fd_ (-1),
symbol_refs (0),
writable (false)
{
}
image::~image ()
{
if (references_)
throw rld_error_at ("references when destructing image");
if (fd_ >= 0)
::close (fd_);
}
void
image::open (file& name)
{
name_ = name;
open ();
}
void
image::open (bool writable_)
{
const std::string path = name_.path ();
if (path.empty ())
throw rld::error ("No file name", "open:" + path);
if (rld::verbose () >= RLD_VERBOSE_TRACE_FILE)
std::cout << "image::open: " << name (). full ()
<< " refs:" << references_ + 1
<< " writable:" << (char*) (writable_ ? "yes" : "no")
<< std::endl;
if (fd_ < 0)
{
writable = writable_;
if (writable)
fd_ = ::open (path.c_str (), OPEN_FLAGS | O_RDWR | O_CREAT | O_TRUNC, CREATE_MODE);
else
fd_ = ::open (path.c_str (), OPEN_FLAGS | O_RDONLY);
if (fd_ < 0)
throw rld::error (::strerror (errno), "open:" + path);
}
else
{
if (writable_ != writable)
throw rld::error ("Cannot change write status", "open:" + path);
}
++references_;
}
void
image::close ()
{
if (references_ > 0)
{
if (rld::verbose () >= RLD_VERBOSE_TRACE_FILE)
std::cout << "image::close: " << name ().full ()
<< " refs:" << references_ << std::endl;
--references_;
if (references_ == 0)
{
::close (fd_);
fd_ = -1;
}
}
}
ssize_t
image::read (void* buffer_, size_t size)
{
uint8_t* buffer = static_cast <uint8_t*> (buffer_);
size_t have_read = 0;
size_t to_read = size;
while (have_read < size)
{
const ssize_t rsize = ::read (fd (), buffer, to_read);
if (rsize < 0)
throw rld::error (strerror (errno), "read:" + name ().path ());
if (rsize == 0)
break;
have_read += rsize;
to_read -= rsize;
buffer += rsize;
}
return have_read;
}
ssize_t
image::write (const void* buffer_, size_t size)
{
const uint8_t* buffer = static_cast <const uint8_t*> (buffer_);
size_t have_written = 0;
size_t to_write = size;
while (have_written < size)
{
const ssize_t wsize = ::write (fd (), buffer, to_write);
if (wsize < 0)
throw rld::error (strerror (errno), "write:" + name ().path ());
have_written += wsize;
to_write -= wsize;
buffer += wsize;
}
return have_written;
}
void
image::seek (off_t offset)
{
if (::lseek (fd (), name_.offset () + offset, SEEK_SET) < 0)
throw rld::error (strerror (errno), "lseek:" + name ().path ());
}
bool
image::seek_read (off_t offset, uint8_t* buffer, size_t size)
{
seek (offset);
return size == (size_t) read (buffer, size);
}
bool
image::seek_write (off_t offset, const void* buffer, size_t size)
{
seek (offset);
return size == (size_t) write (buffer, size);
}
const file&
image::name () const
{
return name_;
}
int
image::references () const
{
return references_;
}
size_t
image::size () const
{
return name ().size ();
}
int
image::fd () const
{
return fd_;
}
rld::elf::file&
image::elf ()
{
return elf_;
}
void
image::symbol_referenced ()
{
++symbol_refs;
}
int
image::symbol_references () const
{
return symbol_refs;
}
void
copy_file (image& in, image& out, size_t size)
{
#define COPY_FILE_BUFFER_SIZE (8 * 1024)
uint8_t* buffer = 0;
if (size == 0)
size = in.name ().size ();
try
{
buffer = new uint8_t[COPY_FILE_BUFFER_SIZE];
while (size)
{
/*
* @fixme the reading and writing are not POSIX; sigints could split them.
*/
size_t l = size < COPY_FILE_BUFFER_SIZE ? size : COPY_FILE_BUFFER_SIZE;
ssize_t r = ::read (in.fd (), buffer, l);
if (r < 0)
throw rld::error (::strerror (errno), "reading: " + in.name ().full ());
if (r == 0)
{
std::ostringstream oss;
oss << "reading: " + in.name ().full () << " (" << size << ')';
throw rld::error ("input too short", oss.str ());
}
ssize_t w = ::write (out.fd (), buffer, r);
if (w < 0)
throw rld::error (::strerror (errno), "writing: " + out.name ().full ());
if (w != r)
throw rld::error ("output trucated", "writing: " + out.name ().full ());
size -= r;
}
}
catch (...)
{
delete [] buffer;
throw;
}
if (buffer)
delete [] buffer;
}
/**
* Defines for the header of an archive.
*/
#define rld_archive_ident "!<arch>\n"
#define rld_archive_ident_size (sizeof (rld_archive_ident) - 1)
#define rld_archive_fhdr_base rld_archive_ident_size
#define rld_archive_fname (0)
#define rld_archive_fname_size (16)
#define rld_archive_mtime (16)
#define rld_archive_mtime_size (12)
#define rld_archive_uid (28)
#define rld_archive_uid_size (6)
#define rld_archive_gid (34)
#define rld_archive_gid_size (6)
#define rld_archive_mode (40)
#define rld_archive_mode_size (8)
#define rld_archive_size (48)
#define rld_archive_size_size (10)
#define rld_archive_magic (58)
#define rld_archive_magic_size (2)
#define rld_archive_fhdr_size (60)
#define rld_archive_max_file_size (1024)
archive::archive (const std::string& path)
: image (path, false)
{
if (!name ().is_valid ())
throw rld_error_at ("name is empty");
if (!name ().is_archive ())
throw rld_error_at ("name is not an archive: " + name ().oname ());
}
archive::~archive ()
{
end ();
close ();
}
void
archive::begin ()
{
if (references () == 1)
{
elf ().begin (name ().full (), fd ());
/*
* Make sure it is an archive.
*/
if (!elf ().is_archive ())
throw rld::error ("Not an archive.",
"archive-begin:" + name ().full ());
}
}
void
archive::end ()
{
if (references () == 1)
elf ().end ();
}
bool
archive::is (const std::string& path) const
{
return name ().path () == path;
}
bool
archive::is_valid ()
{
open ();
uint8_t header[rld_archive_ident_size];
seek_read (0, &header[0], rld_archive_ident_size);
bool result = ::memcmp (header, rld_archive_ident,
rld_archive_ident_size) == 0 ? true : false;
close ();
return result;
}
void
archive::load_objects (objects& objs)
{
off_t extended_file_names = 0;
off_t offset = rld_archive_fhdr_base;
size_t size = 0;
while (true)
{
uint8_t header[rld_archive_fhdr_size];
if (!read_header (offset, &header[0]))
break;
/*
* The archive file headers are always aligned to an even address.
*/
size =
(scan_decimal (&header[rld_archive_size],
rld_archive_size_size) + 1) & ~1;
/*
* Check for the GNU extensions.
*/
if (header[0] == '/')
{
off_t extended_off;
switch (header[1])
{
case ' ':
/*
* Symbols table. Ignore the table.
*/
break;
case '/':
/*
* Extended file names table. Remember.
*/
extended_file_names = offset + rld_archive_fhdr_size;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
/*
* Offset into the extended file name table. If we do not have the
* offset to the extended file name table find it.
*/
extended_off = scan_decimal (&header[1], rld_archive_fname_size);
if (extended_file_names == 0)
{
off_t off = offset;
while (extended_file_names == 0)
{
size_t esize =
(scan_decimal (&header[rld_archive_size],
rld_archive_size_size) + 1) & ~1;
off += esize + rld_archive_fhdr_size;
if (!read_header (off, &header[0]))
throw rld::error ("No GNU extended file name section found",
"get-names:" + name ().path ());
if ((header[0] == '/') && (header[1] == '/'))
{
extended_file_names = off + rld_archive_fhdr_size;
break;
}
}
}
if (extended_file_names)
{
/*
* We know the offset in the archive to the extended file. Read
* the name from the table and compare with the name we are
* after.
*/
char cname[rld_archive_max_file_size];
seek_read (extended_file_names + extended_off,
(uint8_t*) &cname[0], rld_archive_max_file_size);
add_object (objs, cname,
offset + rld_archive_fhdr_size, size);
}
break;
default:
/*
* Ignore the file because we do not know what it it.
*/
break;
}
}
else
{
/*
* Normal archive name.
*/
add_object (objs,
(char*) &header[rld_archive_fname],
offset + rld_archive_fhdr_size, size);
}
offset += size + rld_archive_fhdr_size;
}
}
bool
archive::operator< (const archive& rhs) const
{
return name ().path () < rhs.name ().path ();
}
bool
archive::read_header (off_t offset, uint8_t* header)
{
if (!seek_read (offset, header, rld_archive_fhdr_size))
return false;
if ((header[rld_archive_magic] != 0x60) ||
(header[rld_archive_magic + 1] != 0x0a))
throw rld::error ("Invalid header magic numbers at " +
rld::to_string (offset), "read-header:" + name ().path ());
return true;
}
void
archive::add_object (objects& objs, const char* path, off_t offset, size_t size)
{
const char* end = path;
while ((*end != '\0') && (*end != '/') && (*end != '\n'))
++end;
std::string str;
str.append (path, end - path);
if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
std::cout << "archive::add-object: " << str << std::endl;
file n (name ().path (), str, offset, size);
objs[n.full()] = new object (*this, n);
}
void
archive::write_header (const std::string& name,
uint32_t mtime,
int uid,
int gid,
int mode,
size_t size)
{
uint8_t header[rld_archive_fhdr_size];
memset (header, ' ', sizeof (header));
size_t len = name.length ();
if (len > rld_archive_fname_size)
len = rld_archive_fname_size;
memcpy (&header[rld_archive_fname], &name[0], len);
set_number (mtime, header + rld_archive_mtime, rld_archive_mtime_size);
set_number (uid, header + rld_archive_uid, rld_archive_uid_size);
set_number (gid, header + rld_archive_gid, rld_archive_gid_size);
set_number (mode, header + rld_archive_mode, rld_archive_mode_size, true);
set_number (size, header + rld_archive_size, rld_archive_size_size);
header[rld_archive_magic] = 0x60;
header[rld_archive_magic + 1] = 0x0a;
write (header, sizeof (header));
}
void
archive::create (object_list& objects)
{
if (rld::verbose () >= RLD_VERBOSE_DETAILS)
std::cout << "archive::create: " << name ().full ()
<< ", objects: " << objects.size () << std::endl;
open (true);
try
{
seek_write (0, rld_archive_ident, rld_archive_ident_size);
/*
* GNU extended filenames.
*/
std::string extended_file_names;
for (object_list::iterator oi = objects.begin ();
oi != objects.end ();
++oi)
{
object& obj = *(*oi);
const std::string& oname = path::basename (obj.name ().oname ());
if (oname.length () >= rld_archive_fname_size)
extended_file_names += oname + '\n';
}
if (!extended_file_names.empty ())
{
if (extended_file_names.length () & 1)
{
extended_file_names += ' ';
}
write_header ("//", 0, 0, 0, 0, extended_file_names.length ());
write (extended_file_names.c_str (), extended_file_names.length ());
}
for (object_list::iterator oi = objects.begin ();
oi != objects.end ();
++oi)
{
object& obj = *(*oi);
obj.open ();
try
{
std::string oname = path::basename (obj.name ().oname ());
/*
* Convert the file name to an offset into the extended file name
* table if the file name is too long for the header.
*/
if (oname.length () >= rld_archive_fname_size)
{
size_t pos = extended_file_names.find (oname + '\n');
if (pos == std::string::npos)
throw rld_error_at ("extended file name not found");
std::ostringstream oss;
oss << '/' << pos;
oname = oss.str ();
}
else oname += '/';
write_header (oname, 0, 0, 0, 0666, (obj.name ().size () + 1) & ~1);
obj.seek (0);
copy_file (obj, *this);
if (obj.name ().size () & 1)
write ("\n", 1);
}
catch (...)
{
obj.close ();
throw;
}
obj.close ();
}
}
catch (...)
{
close ();
throw;
}
close ();
}
relocation::relocation (const elf::relocation& er)
: offset (er.offset ()),
type (er.type ()),
info (er.info ()),
addend (er.addend ()),
symname (er.symbol ().name ()),
symtype (er.symbol ().type ()),
symsect (er.symbol ().section_index ()),
symvalue (er.symbol ().value ()),
symbinding (er.symbol ().binding ())
{
}
section::section (const elf::section& es)
: name (es.name ()),
index (es.index ()),
type (es.type ()),
size (es.size ()),
alignment (es.alignment ()),
link (es.link ()),
info (es.info ()),
flags (es.flags ()),
offset (es.offset ()),
rela (es.get_reloc_type ())
{
}
void
section::load_relocations (const elf::section& es)
{
const elf::relocations& es_relocs = es.get_relocations ();
for (elf::relocations::const_iterator ri = es_relocs.begin ();
ri != es_relocs.end ();
++ri)
{
relocs.push_back (relocation (*ri));
}
rela = es.get_reloc_type ();
}
size_t
sum_sizes (const sections& secs)
{
size_t size = 0;
for (sections::const_iterator si = secs.begin ();
si != secs.end ();
++si)
{
const section& sec = *si;
if ((size % sec.alignment) != 0)
size -= (size % sec.alignment) + sec.alignment;
size += sec.size;
}
return size;
}
const section*
find (const sections& secs, const int index)
{
for (sections::const_iterator si = secs.begin ();
si != secs.end ();
++si)
{
const section& sec = *si;
if (index == sec.index)
return &sec;
}
return 0;
}
object::object (archive& archive_, file& name_)
: image (name_),
archive_ (&archive_),
valid_ (false),
resolving_ (false),
resolved_ (false)
{
if (!name ().is_valid ())
throw rld_error_at ("name is empty");
}
object::object (const std::string& path)
: image (path),
archive_ (0),
valid_ (false),
resolving_ (false),
resolved_ (false)
{
if (!name ().is_valid ())
throw rld_error_at ("name is empty");
}
object::object ()
: archive_ (0),
valid_ (false),
resolving_ (false),
resolved_ (false)
{
}
object::~object ()
{
end ();
close ();
}
void
object::open (bool writable)
{
if (archive_)
{
if (writable)
throw rld_error_at ("object files in archives are not writable");
archive_->open ();
}
else
image::open (writable);
}
void
object::close ()
{
if (archive_)
{
archive_->end ();
archive_->close ();
}
else
{
end ();
image::close ();
}
}
void
object::begin ()
{
/*
* Begin a session.
*/
if (rld::verbose () >= RLD_VERBOSE_TRACE_FILE)
std::cout << "object:begin: " << name ().full () << " in-archive:"
<< ((char*) (archive_ ? "yes" : "no")) << std::endl;
if (archive_)
elf ().begin (name ().full (), archive_->elf(), name ().offset ());
else
elf ().begin (name ().full (), fd (), is_writable ());
/*
* Cannot be an archive.
*/
if (elf ().is_archive ())
throw rld::error ("Is an archive not an object file.",
"object-begin:" + name ().full ());
/*
* We only support executable or relocatable ELF files.
*/
if (!is_writable ())
{
if (!elf ().is_executable () && !elf ().is_relocatable ())
throw rld::error ("Invalid ELF type (only ET_EXEC/ET_REL supported).",
"object-begin:" + name ().full ());
elf::check_file (elf ());
/**
* We assume the ELF file is invariant over the linking process.
*/
if (secs.empty ())
{
elf::sections elf_secs;
elf ().get_sections (elf_secs, 0);
for (elf::sections::const_iterator esi = elf_secs.begin ();
esi != elf_secs.end ();
++esi)
{
secs.push_back (section (*(*esi)));
}
}
}
/*
* This is a valid object file. The file format checks out.
*/
valid_ = true;
}
void
object::end ()
{
if (rld::verbose () >= RLD_VERBOSE_TRACE_FILE)
std::cout << "object:end: " << name ().full () << std::endl;
elf ().end ();
}
bool
object::valid () const
{
return valid_;
}
void
object::load_symbols (rld::symbols::table& symbols, bool local)
{
if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
std::cout << "object:load-sym: " << name ().full () << std::endl;
rld::symbols::pointers syms;
if (local)
{
elf ().get_symbols (syms, false, true, false, false);
if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
std::cout << "object:load-sym: local: total "
<< syms.size () << std::endl;
for (symbols::pointers::iterator si = syms.begin ();
si != syms.end ();
++si)
{
symbols::symbol& sym = *(*si);
if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
std::cout << "object:load-sym: local: " << sym << std::endl;
sym.set_object (*this);
symbols.add_local (sym);
}
}
elf ().get_symbols (syms, false, false, true, false);
if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
std::cout << "object:load-sym: weak: total "
<< syms.size () << std::endl;
for (symbols::pointers::iterator si = syms.begin ();
si != syms.end ();
++si)
{
symbols::symbol& sym = *(*si);
if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
std::cout << "object:load-sym: weak: " << sym << std::endl;
sym.set_object (*this);
symbols.add_weak (sym);
externals.push_back (&sym);
}
elf ().get_symbols (syms, false, false, false, true);
if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
std::cout << "object:load-sym: global: total "
<< syms.size () << std::endl;
for (symbols::pointers::iterator si = syms.begin ();
si != syms.end ();
++si)
{
symbols::symbol& sym = *(*si);
if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
std::cout << "object:load-sym: global: " << sym << std::endl;
sym.set_object (*this);
symbols.add_global (sym);
externals.push_back (&sym);
}
elf ().get_symbols (syms, true, false, true, true);
if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
std::cout << "object:load-sym: unresolved: total "
<< syms.size () << std::endl;
for (symbols::pointers::iterator si = syms.begin ();
si != syms.end ();
++si)
{
symbols::symbol& sym = *(*si);
if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
{
std::cout << "object:load-sym: unresolved: ";
sym.output (std::cout);
std::cout << std::endl;
}
unresolved[sym.name ()] = &sym;
}
}
void
object::load_relocations ()
{
if (rld::verbose () >= RLD_VERBOSE_TRACE)
std::cout << "object:load-relocs: " << name ().full () << std::endl;
elf ().load_relocations ();
for (sections::iterator si = secs.begin ();
si != secs.end ();
++si)
{
section& sec = *si;
const elf::section& elf_sec = elf ().get_section (sec.index);
sec.load_relocations (elf_sec);
}
}
int
object::references () const
{
if (archive_)
return archive_->references ();
return image::references ();
}
size_t
object::size () const
{
if (archive_)
return archive_->size ();
return image::size ();
}
int
object::fd () const
{
if (archive_)
return archive_->fd ();
return image::fd ();
}
void
object::symbol_referenced ()
{
image::symbol_referenced ();
if (archive_)
archive_->symbol_referenced ();
}
archive*
object::get_archive ()
{
return archive_;
}
rld::symbols::symtab&
object::unresolved_symbols ()
{
return unresolved;
}
rld::symbols::pointers&
object::external_symbols ()
{
return externals;
}
void
object::get_sections (sections& filtered_secs,
uint32_t type,
uint64_t flags_in,
uint64_t flags_out)
{
for (sections::const_iterator si = secs.begin ();
si != secs.end ();
++si)
{
const section& sec = *si;
if ((type == 0) || (type == sec.type))
{
if ((flags_in == 0) ||
(((sec.flags & flags_in) == flags_in) &&
((sec.flags & flags_out) == 0)))
{
filtered_secs.push_back (sec);
}
}
}
}
void
object::get_sections (sections& filtered_secs, const std::string& matching_name)
{
for (sections::const_iterator si = secs.begin ();
si != secs.end ();
++si)
{
const section& sec = *si;
if (sec.name == matching_name)
{
filtered_secs.push_back (sec);
}
}
}
const section&
object::get_section (int index) const
{
for (sections::const_iterator si = secs.begin ();
si != secs.end ();
++si)
{
const section& sec = *si;
if (sec.index == index)
return sec;
}
throw rld::error ("Section index '" + rld::to_string (index) +
"' not found: " + name ().full (), "object::get-section");
}
void
object::resolve_set ()
{
resolving_ = true;
}
void
object::resolve_clear ()
{
resolving_ = false;
}
bool
object::resolving () const
{
return resolving_;
}
void
object::resolved_set ()
{
resolved_ = true;
}
bool
object::resolved () const
{
return resolved_;
}
cache::cache ()
: opened (false)
{
}
cache::~cache ()
{
close ();
}
void
cache::open ()
{
if (!opened)
{
collect_object_files ();
archives_begin ();
opened = true;
}
}
void
cache::close ()
{
if (opened)
{
/*
* Must delete the object first as they could depend on archives.
*/
for (objects::iterator oi = objects_.begin (); oi != objects_.end (); ++oi)
delete (*oi).second;
for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
delete (*ai).second;
opened = false;
}
}
void
cache::add (const std::string& path)
{
paths_.push_back (path);
input (path);
}
void
cache::add (path::paths& paths__)
{
for (path::paths::iterator pi = paths__.begin();
pi != paths__.end();
++pi)
add (*pi);
}
void
cache::add_libraries (path::paths& paths__)
{
for (path::paths::iterator pi = paths__.begin();
pi != paths__.end();
++pi)
input (*pi);
}
void
cache::archive_begin (const std::string& path)
{
archives::iterator ai = archives_.find (path);
if (ai != archives_.end ())
{
archive* ar = (*ai).second;
if (!ar->is_open ())
{
if (rld::verbose () >= RLD_VERBOSE_TRACE)
std::cout << "cache:archive-begin: " << path << std::endl;
ar->open ();
ar->begin ();
}
}
}
void
cache::archive_end (const std::string& path)
{
archives::iterator ai = archives_.find (path);
if (ai != archives_.end ())
{
archive* ar = (*ai).second;
if (ar->is_open ())
{
if (rld::verbose () >= RLD_VERBOSE_TRACE)
std::cout << "cache:archive-end: " << path << std::endl;
ar->end ();
ar->close ();
}
}
}
void
cache::archives_begin ()
{
for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
archive_begin (((*ai).second)->path ());
}
void
cache::archives_end ()
{
for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
archive_end (((*ai).second)->path ());
}
void
cache::collect_object_files ()
{
for (path::paths::iterator ni = paths_.begin (); ni != paths_.end (); ++ni)
collect_object_files (*ni);
}
void
cache::collect_object_files (const std::string& path)
{
archive* ar = new archive (path);
if (ar->is_valid ())
{
try
{
ar->open ();
ar->load_objects (objects_);
ar->close ();
archives_[path] = ar;
}
catch (...)
{
delete ar;
throw;
}
}
else
{
delete ar;
object* obj = new object (path);
if (!obj->name ().exists ())
{
delete obj;
throw rld::error ("'" + path + "', Not found or a regular file.",
"file-check");
}
try
{
obj->open ();
obj->begin ();
obj->end ();
obj->close ();
objects_[path] = obj;
}
catch (...)
{
delete obj;
throw;
}
}
}
void
cache::load_symbols (rld::symbols::table& symbols, bool local)
{
if (rld::verbose () >= RLD_VERBOSE_INFO)
std::cout << "cache:load-sym: object files: " << objects_.size ()
<< std::endl;
for (objects::iterator oi = objects_.begin ();
oi != objects_.end ();
++oi)
{
object* obj = (*oi).second;
obj->open ();
obj->begin ();
obj->load_symbols (symbols, local);
obj->end ();
obj->close ();
}
if (rld::verbose () >= RLD_VERBOSE_INFO)
std::cout << "cache:load-sym: symbols: " << symbols.size ()
<< std::endl;
}
void
cache::output_unresolved_symbols (std::ostream& out)
{
for (objects::iterator oi = objects_.begin ();
oi != objects_.end ();
++oi)
{
object* obj = (*oi).second;
if (obj)
{
out << obj->name ().full () << ':' << std::endl;
rld::symbols::output (out, obj->unresolved_symbols ());
}
}
}
archives&
cache::get_archives ()
{
return archives_;
}
objects&
cache::get_objects ()
{
return objects_;
}
void
cache::get_objects (object_list& list) const
{
list.clear ();
for (path::paths::const_iterator pi = paths_.begin ();
pi != paths_.end ();
++pi)
{
objects::const_iterator oi = objects_.find (*pi);
if (oi == objects_.end ())
throw rld_error_at ("path not found in objects");
list.push_back ((*oi).second);
}
}
const path::paths&
cache::get_paths () const
{
return paths_;
}
int
cache::archive_count () const
{
return archives_.size ();
}
int
cache::object_count () const
{
return objects_.size ();
}
int
cache::path_count () const
{
return paths_.size ();
}
void
cache::get_archive_files (files& afiles)
{
for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
afiles.push_back ((*ai).second->name ().full ());
}
void
cache::get_object_files (files& ofiles)
{
for (objects::iterator oi = objects_.begin (); oi != objects_.end (); ++oi)
ofiles.push_back ((*oi).second->name ());
}
void
cache::output_archive_files (std::ostream& out)
{
for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
out << ' ' << (*ai).second->name ().full () << std::endl;
}
void
cache::output_object_files (std::ostream& out)
{
for (objects::iterator oi = objects_.begin (); oi != objects_.end (); ++oi)
out << ' ' << (*oi).second->name ().full () << std::endl;
}
void
cache::input (const std::string& path)
{
if (opened)
{
collect_object_files (path);
archive_begin (path);
}
}
void
find_libraries (path::paths& libraries,
path::paths& libpaths,
path::paths& libs)
{
if (rld::verbose () >= RLD_VERBOSE_INFO)
std::cout << "Finding libraries:" << std::endl;
libraries.clear ();
for (path::paths::size_type l = 0; l < libs.size (); ++l)
{
std::string lib = "lib" + libs[l] + ".a";
if (rld::verbose () >= RLD_VERBOSE_DETAILS)
std::cout << " searching: " << lib << std::endl;
bool found = false;
for (path::paths::size_type p = 0; p < libpaths.size (); ++p)
{
std::string plib;
path::path_join (libpaths[p], lib, plib);
if (rld::verbose () >= RLD_VERBOSE_DETAILS)
std::cout << " checking: " << plib << std::endl;
if (path::check_file (plib))
{
if (rld::verbose () >= RLD_VERBOSE_INFO)
std::cout << " found: " << plib << std::endl;
libraries.push_back (plib);
found = true;
break;
}
}
if (!found)
throw rld::error ("Not found", lib);
}
}
}
}