* 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.
gold/:
	* incremental.cc: Include <cstdarg> and "target-select.h".
	(vexplain_no_incremental): New function.
	(explain_no_incremental): New function.
	(Incremental_binary::error): New method.
	(Sized_incremental_binary::do_find_incremental_inputs_section): New
	method.
	(make_sized_incremental_binary): New function.
	(open_incremental_binary): New function.
	(can_incrementally_link_file): Add checks if output is ELF and has
	inputs section.
	* incremental.h: Include "elfcpp_file.h" and "output.h".
	(Incremental_binary): New class.
	(Sized_incremental_binary): New class.
	(open_incremental_binary): Declare.
	* object.cc (is_elf_object): Use
	elfcpp::Elf_recognizer::is_elf_file.
	(make_elf_object): Use elfcpp::Elf_recognizer::is_valid_header.
	* output.h (Output_file::filesize): New method.
This commit is contained in:
Ian Lance Taylor 2009-10-09 16:40:51 +00:00
parent e322137b9b
commit c549a6949c
7 changed files with 513 additions and 63 deletions

View file

@ -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>