summaryrefslogtreecommitdiff
path: root/rld-files.cpp
diff options
context:
space:
mode:
authorChris Johns <chrisj@rtems.org>2012-11-17 17:34:33 +1100
committerChris Johns <chrisj@rtems.org>2012-11-17 17:34:33 +1100
commit7ee957ca2f579802b4823ad562f05bd27ad425e1 (patch)
tree5f085ca653f2d80496e984b978b556b561127064 /rld-files.cpp
parentd68833ada79a4255e95017b44f73dcb21c7a7701 (diff)
Refactor the ELF support to allow ELF write suppport.
The refactoring allows better reuse of the ELF support and cleans up some hacks from the generic file and archive handling improving the separation of the file handling from the file format, ie ELF. The handling of ELF object files and ELF object files inside archives is cleaner. The refactor cleaned up the symbol handling where the symbols now reside in the ELF file object and references are take in symbol pointer containers and symbol table containers. The main purpose of the refactor is to allow support for creating and writing ELF files. Also added an rtems-syms command where special symbol support can be added.
Diffstat (limited to '')
-rw-r--r--rld-files.cpp214
1 files changed, 145 insertions, 69 deletions
diff --git a/rld-files.cpp b/rld-files.cpp
index d44474b..108f920 100644
--- a/rld-files.cpp
+++ b/rld-files.cpp
@@ -1,10 +1,10 @@
/*
- * Copyright (c) 2011, Chris Johns <chrisj@rtems.org>
+ * 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
@@ -45,7 +45,7 @@ namespace rld
scan_decimal (const uint8_t* string, size_t len)
{
uint64_t value = 0;
-
+
while (len && (*string != ' '))
{
value *= 10;
@@ -104,7 +104,7 @@ namespace rld
joined = path_ + RLD_PATH_SEPARATOR + file_;
else if ((path_[path_.size () - 1] == RLD_PATH_SEPARATOR) &&
(file_[0] == RLD_PATH_SEPARATOR))
- joined = path_ + &file_[1];
+ joined = path_ + &file_[1];
else
joined = path_ + file_;
}
@@ -147,7 +147,7 @@ namespace rld
const std::string& oname,
off_t offset,
size_t size)
- : aname_ (aname),
+ : aname_ (aname),
oname_ (oname),
offset_ (offset),
size_ (size)
@@ -246,8 +246,8 @@ namespace rld
return aname_;
return oname_;
}
-
- const std::string
+
+ const std::string
file::full () const
{
std::string f;
@@ -297,8 +297,7 @@ namespace rld
image::image (file& name)
: name_ (name),
references_ (0),
- fd_ (-1),
- elf_ (0)
+ fd_ (-1)
{
}
@@ -306,15 +305,14 @@ namespace rld
: name_ (path, is_object),
references_ (0),
fd_ (-1),
- elf_ (0),
- symbol_refs (0)
+ symbol_refs (0),
+ writeable (false)
{
}
image::image ()
: references_ (0),
fd_ (-1),
- elf_ (0),
symbol_refs (0)
{
}
@@ -335,26 +333,34 @@ namespace rld
}
void
- image::open (bool writable)
+ image::open (bool writeable_)
{
const std::string path = name_.path ();
if (path.empty ())
- throw rld::error ("No file name", "open" + path);
+ throw rld::error ("No file name", "open:" + path);
if (rld::verbose () >= RLD_VERBOSE_DETAILS)
std::cout << "image::open: " << name (). full ()
+ << " writable:" << (char*) (writeable_ ? "yes" : "no")
<< " refs:" << references_ + 1 << std::endl;
if (fd_ < 0)
{
- if (writable)
+ writeable = writeable_;
+
+ if (writeable)
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 (writeable_ != writeable)
+ throw rld::error ("Cannot change write status", "open:" + path);
+ }
++references_;
}
@@ -385,7 +391,7 @@ namespace rld
throw rld::error (strerror (errno), "read:" + name ().path ());
return rsize;
}
-
+
ssize_t
image::write (const void* buffer, size_t size)
{
@@ -394,28 +400,28 @@ namespace rld
throw rld::error (strerror (errno), "write:" + name ().path ());
return wsize;
}
-
+
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
{
@@ -423,41 +429,35 @@ namespace rld
}
int
- image::references () const
+ image::references () const
{
return references_;
}
size_t
- image::size () const
+ image::size () const
{
return name ().size ();
}
int
- image::fd () const
+ image::fd () const
{
return fd_;
}
- rld::elf::elf*
- image::elf (bool )
+ rld::elf::file&
+ image::elf ()
{
return elf_;
}
void
- image::set_elf (rld::elf::elf* elf)
- {
- elf_ = elf;
- }
-
- void
image::symbol_referenced ()
{
++symbol_refs;
}
-
+
int
image::symbol_references () const
{
@@ -474,6 +474,10 @@ namespace rld
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);
@@ -545,6 +549,25 @@ namespace rld
close ();
}
+ void
+ archive::begin ()
+ {
+ 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 ()
+ {
+ elf ().end ();
+ }
+
bool
archive::is (const std::string& path) const
{
@@ -580,8 +603,8 @@ namespace rld
/*
* The archive file headers are always aligned to an even address.
*/
- size =
- (scan_decimal (&header[rld_archive_size],
+ size =
+ (scan_decimal (&header[rld_archive_size],
rld_archive_size_size) + 1) & ~1;
/*
@@ -625,15 +648,15 @@ namespace rld
off_t off = offset;
while (extended_file_names == 0)
{
- size_t esize =
+ 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;
@@ -693,7 +716,7 @@ namespace rld
(header[rld_archive_magic + 1] != 0x0a))
throw rld::error ("Invalid header magic numbers at " +
rld::to_string (offset), "read-header:" + name ().path ());
-
+
return true;
}
@@ -725,7 +748,7 @@ namespace rld
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;
@@ -756,7 +779,7 @@ namespace rld
* GNU extended filenames.
*/
std::string extended_file_names;
-
+
for (object_list::iterator oi = objects.begin ();
oi != objects.end ();
++oi)
@@ -818,7 +841,7 @@ namespace rld
close ();
throw;
}
-
+
close ();
}
@@ -877,16 +900,34 @@ namespace rld
object::begin ()
{
/*
- * Begin an ELF session and get the ELF header.
+ * Begin a session.
+ */
+ if (archive_)
+ elf ().begin (name ().full (), archive_->elf(), name ().offset ());
+ else
+ elf ().begin (name ().full (), fd ());
+
+ /*
+ * Cannot be an archive.
*/
- rld::elf::begin (*this);
- rld::elf::get_header (*this, ehdr);
+ 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 (!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 ());
}
void
object::end ()
{
- rld::elf::end (*this);
+ elf ().end ();
}
void
@@ -894,17 +935,58 @@ namespace rld
{
if (rld::verbose () >= RLD_VERBOSE_DETAILS)
std::cout << "object:load-sym: " << name ().full () << std::endl;
- rld::elf::load_symbols (symbols, *this, local);
- }
- std::string
- object::get_string (int section, size_t offset)
- {
- return rld::elf::get_string (*this, section, offset);
+ rld::symbols::pointers syms;
+
+ elf ().get_symbols (syms, false, local);
+
+ if (rld::verbose () >= RLD_VERBOSE_DETAILS)
+ std::cout << "object:load-sym: exported: 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_DETAILS)
+ {
+ std::cout << "object:load-sym: exported: ";
+ sym.output (std::cout);
+ std::cout << std::endl;
+ }
+
+ sym.set_object (*this);
+ symbols[sym.name ()] = &sym;
+ externals.push_back (&sym);
+ }
+
+ elf ().get_symbols (syms, true);
+
+ if (rld::verbose () >= RLD_VERBOSE_DETAILS)
+ 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_DETAILS)
+ {
+ std::cout << "object:load-sym: unresolved: ";
+ sym.output (std::cout);
+ std::cout << std::endl;
+ }
+
+ unresolved[sym.name ()] = &sym;
+ }
}
-
+
int
- object::references () const
+ object::references () const
{
if (archive_)
return archive_->references ();
@@ -912,7 +994,7 @@ namespace rld
}
size_t
- object::size () const
+ object::size () const
{
if (archive_)
return archive_->size ();
@@ -920,21 +1002,13 @@ namespace rld
}
int
- object::fd () const
+ object::fd () const
{
if (archive_)
return archive_->fd ();
return image::fd ();
}
- rld::elf::elf*
- object::elf (bool archive__)
- {
- if (archive__ && archive_)
- return archive_->elf ();
- return image::elf ();
- }
-
void
object::symbol_referenced ()
{
@@ -942,13 +1016,14 @@ namespace rld
if (archive_)
archive_->symbol_referenced ();
}
-
+
archive*
object::get_archive ()
{
return archive_;
}
+#if 0
int
object::sections () const
{
@@ -960,6 +1035,7 @@ namespace rld
{
return ehdr.e_shstrndx;
}
+#endif
rld::symbols::table&
object::unresolved_symbols ()
@@ -967,7 +1043,7 @@ namespace rld
return unresolved;
}
- rld::symbols::list&
+ rld::symbols::pointers&
object::external_symbols ()
{
return externals;
@@ -1047,7 +1123,7 @@ namespace rld
if (rld::verbose () >= RLD_VERBOSE_TRACE)
std::cout << "cache:archive-begin: " << path << std::endl;
ar->open ();
- rld::elf::begin (*ar);
+ ar->begin ();
}
}
}
@@ -1063,7 +1139,7 @@ namespace rld
{
if (rld::verbose () >= RLD_VERBOSE_TRACE)
std::cout << "cache:archive-end: " << path << std::endl;
- rld::elf::end (*ar);
+ ar->end ();
ar->close ();
}
}
@@ -1082,7 +1158,7 @@ namespace rld
for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
archive_end (((*ai).second)->path ());
}
-
+
void
cache::collect_object_files ()
{
@@ -1173,7 +1249,7 @@ namespace rld
{
return archives_;
}
-
+
objects&
cache::get_objects ()
{