aboutsummaryrefslogtreecommitdiff
path: root/elfcpp
diff options
context:
space:
mode:
Diffstat (limited to 'elfcpp')
-rw-r--r--elfcpp/ChangeLog6
-rw-r--r--elfcpp/elfcpp_file.h165
2 files changed, 170 insertions, 1 deletions
diff --git a/elfcpp/ChangeLog b/elfcpp/ChangeLog
index 2a668a6..7569cbd 100644
--- a/elfcpp/ChangeLog
+++ b/elfcpp/ChangeLog
@@ -1,3 +1,9 @@
+2009-10-09 Mikolaj Zalewski <mikolajz@google.com>
+
+ * elfcpp_file.h: Fix header guard. Include <cstdio>.
+ (class Elf_recognizer): New class, code from gold/object.cc.
+ (Elf_file::find_section_by_type): New method.
+
2009-07-23 Ulrich Drepper <drepper@redhat.com>
* elfcpp.h (enum STB): Add STB_GNU_UNIQUE.
diff --git a/elfcpp/elfcpp_file.h b/elfcpp/elfcpp_file.h
index f1f4423..00ab28b 100644
--- a/elfcpp/elfcpp_file.h
+++ b/elfcpp/elfcpp_file.h
@@ -53,15 +53,45 @@
// This permits writing
// elfcpp::Shdr shdr(file, ef.section_header(n));
-#ifndef ELFPCP_FILE_H
+#ifndef ELFCPP_FILE_H
#define ELFCPP_FILE_H
#include <string>
+#include <cstdio>
#include <cstring>
namespace elfcpp
{
+// A simple helper class to recognize if a file has an ELF header.
+
+class Elf_recognizer
+{
+ public:
+ // Maximum header size. The user should try to read this much of
+ // the file when using this class.
+
+ static const int max_header_size = Elf_sizes<64>::ehdr_size;
+
+ // Checks if the file contains the ELF magic. Other header fields
+ // are not checked.
+
+ static bool
+ is_elf_file(const unsigned char* ehdr_buf, int size);
+
+ // Check if EHDR_BUF/BUFSIZE is a valid header of a 32-bit or
+ // 64-bit, little-endian or big-endian ELF file. Assumes
+ // is_elf_file() has been checked to be true. If the header is not
+ // valid, *ERROR contains a human-readable error message. If is is,
+ // *SIZE is set to either 32 or 64, *BIG_ENDIAN is set to indicate
+ // whether the file is big-endian.
+
+ static bool
+ is_valid_header(const unsigned char* ehdr_buf, off_t bufsize,
+ int* size, bool* big_endian,
+ std::string* error);
+};
+
// This object is used to read an ELF file.
// SIZE: The size of file, 32 or 64.
// BIG_ENDIAN: Whether the file is in big-endian format.
@@ -99,6 +129,11 @@ class Elf_file
shoff() const
{ return this->shoff_; }
+ // Find the first section with an sh_type field equal to TYPE and
+ // return its index. Returns SHN_UNDEF if there is no such section.
+ unsigned int
+ find_section_by_type(unsigned int type);
+
// Return the number of sections.
unsigned int
shnum()
@@ -193,6 +228,115 @@ class Elf_file
int large_shndx_offset_;
};
+// Inline function definitions.
+
+// Check for presence of the ELF magic number.
+
+inline bool
+Elf_recognizer::is_elf_file(const unsigned char* ehdr_buf, int size)
+{
+ if (size < 4)
+ return false;
+
+ static unsigned char elfmagic[4] =
+ {
+ elfcpp::ELFMAG0, elfcpp::ELFMAG1,
+ elfcpp::ELFMAG2, elfcpp::ELFMAG3
+ };
+ return memcmp(ehdr_buf, elfmagic, 4) == 0;
+}
+
+namespace
+{
+
+// Print a number to a string.
+
+inline std::string
+internal_printf_int(const char* format, int arg)
+{
+ char buf[256];
+ snprintf(buf, sizeof(buf), format, arg);
+ return std::string(buf);
+}
+
+} // End anonymous namespace.
+
+// Check the validity of the ELF header.
+
+inline bool
+Elf_recognizer::is_valid_header(
+ const unsigned char* ehdr_buf,
+ off_t bufsize,
+ int* size,
+ bool* big_endian,
+ std::string* error)
+{
+ if (bufsize < elfcpp::EI_NIDENT)
+ {
+ *error = _("ELF file too short");
+ return false;
+ }
+
+ int v = ehdr_buf[elfcpp::EI_VERSION];
+ if (v != elfcpp::EV_CURRENT)
+ {
+ if (v == elfcpp::EV_NONE)
+ *error = _("invalid ELF version 0");
+ else
+ *error = internal_printf_int(_("unsupported ELF version %d"), v);
+ return false;
+ }
+
+ int c = ehdr_buf[elfcpp::EI_CLASS];
+ if (c == elfcpp::ELFCLASSNONE)
+ {
+ *error = _("invalid ELF class 0");
+ return false;
+ }
+ else if (c != elfcpp::ELFCLASS32
+ && c != elfcpp::ELFCLASS64)
+ {
+ *error = internal_printf_int(_("unsupported ELF class %d"), c);
+ return false;
+ }
+
+ int d = ehdr_buf[elfcpp::EI_DATA];
+ if (d == elfcpp::ELFDATANONE)
+ {
+ *error = _("invalid ELF data encoding");
+ return false;
+ }
+ else if (d != elfcpp::ELFDATA2LSB
+ && d != elfcpp::ELFDATA2MSB)
+ {
+ *error = internal_printf_int(_("unsupported ELF data encoding %d"), d);
+ return false;
+ }
+
+ *big_endian = (d == elfcpp::ELFDATA2MSB);
+
+ if (c == elfcpp::ELFCLASS32)
+ {
+ if (bufsize < elfcpp::Elf_sizes<32>::ehdr_size)
+ {
+ *error = _("ELF file too short");
+ return false;
+ }
+ *size = 32;
+ }
+ else
+ {
+ if (bufsize < elfcpp::Elf_sizes<64>::ehdr_size)
+ {
+ *error = _("ELF file too short");
+ return false;
+ }
+ *size = 64;
+ }
+
+ return true;
+}
+
// Template function definitions.
// Construct an Elf_file given an ELF file header.
@@ -269,6 +413,25 @@ Elf_file<size, big_endian, File>::initialize_shnum()
}
}
+// Find section with sh_type equal to TYPE and return its index.
+// Returns SHN_UNDEF if not found.
+
+template<int size, bool big_endian, typename File>
+unsigned int
+Elf_file<size, big_endian, File>::find_section_by_type(unsigned int type)
+{
+ unsigned int shnum = this->shnum();
+ typename File::View v(this->file_->view(this->shoff_,
+ This::shdr_size * shnum));
+ for (unsigned int i = 0; i < shnum; i++)
+ {
+ Ef_shdr shdr(v.data() + This::shdr_size * i);
+ if (shdr.get_sh_type() == type)
+ return i;
+ }
+ return SHN_UNDEF;
+}
+
// Return the file offset of the section header of section SHNDX.
template<int size, bool big_endian, typename File>