688 lines · 19.2 KB · C
RawDownload
// elfcpp_file.h -- file access for elfcpp   -*- C++ -*- // Copyright 2006, 2007, Free Software Foundation, Inc.// Written by Ian Lance Taylor <iant@google.com>. // This file is part of elfcpp.   // This program is free software; you can redistribute it and/or// modify it under the terms of the GNU Library General Public License// as published by the Free Software Foundation; either version 2, or// (at your option) any later version. // In addition to the permissions in the GNU Library General Public// License, the Free Software Foundation gives you unlimited// permission to link the compiled version of this file into// combinations with other programs, and to distribute those// combinations without any restriction coming from the use of this// file.  (The Library Public License restrictions do apply in other// respects; for example, they cover modification of the file, and/// distribution when not linked into a combined executable.) // This program is distributed in the hope that it will be useful, but// WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU// Library General Public License for more details. // You should have received a copy of the GNU Library General Public// License along with this program; if not, write to the Free Software// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA// 02110-1301, USA. // This header file defines the class Elf_file which can be used to// read useful data from an ELF file.  The functions here are all// templates which take a file interface object as a parameter.  This// type must have a subtype View.  This type must support two methods://     View view(off_t file_offset, off_t data_size)// returns a View for the specified part of the file.//     void error(const char* printf_format, ...)// prints an error message and does not return.  The subtype View must// support a method//     const unsigned char* data()// which returns a pointer to a buffer containing the requested data.// This general interface is used to read data from the file.  Objects// of type View will never survive longer than the elfcpp function. // Some of these functions must return a reference to part of the// file.  To use these, the file interface must support a subtype// Location://    Location(off_t file_offset, off_t data_size)// To use this in conjunction with the accessors types Shdr, etc., the// file interface should support an overload of view://    View view(Location)// This permits writing//    elfcpp::Shdr shdr(file, ef.section_header(n)); #ifndef ELFCPP_FILE_H#define ELFCPP_FILE_H #include <string>#include <cstdio>#include <cstring> #include "elfcpp.h" 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.//   FILE: A file reading type as described above. template<int size, bool big_endian, typename File>class Elf_file{ private:  typedef Elf_file<size, big_endian, File> This;  public:  static const int ehdr_size = Elf_sizes<size>::ehdr_size;  static const int phdr_size = Elf_sizes<size>::phdr_size;  static const int shdr_size = Elf_sizes<size>::shdr_size;  static const int sym_size = Elf_sizes<size>::sym_size;  static const int rel_size = Elf_sizes<size>::rel_size;  static const int rela_size = Elf_sizes<size>::rela_size;   typedef Ehdr<size, big_endian> Ef_ehdr;  typedef Phdr<size, big_endian> Ef_phdr;  typedef Shdr<size, big_endian> Ef_shdr;  typedef Sym<size, big_endian> Ef_sym;   // Construct an Elf_file given an ELF file header.  Elf_file(File* file, const Ef_ehdr& ehdr)  { this->construct(file, ehdr); }   // Construct an ELF file.  inline  Elf_file(File* file);   // Return the file offset to the section headers.  off_t  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()  {    this->initialize_shnum();    return this->shnum_;  }   // Return the section index of the section name string table.  unsigned int  shstrndx()  {    this->initialize_shnum();    return this->shstrndx_;  }   // Return the value to subtract from section indexes >=  // SHN_LORESERVE.  See the comment in initialize_shnum.  int  large_shndx_offset()  {    this->initialize_shnum();    return this->large_shndx_offset_;  }   // Return the location of the header of section SHNDX.  typename File::Location  section_header(unsigned int shndx)  {    return typename File::Location(this->section_header_offset(shndx),				   shdr_size);  }   // Return the name of section SHNDX.  std::string  section_name(unsigned int shndx);   // Return the location of the contents of section SHNDX.  typename File::Location  section_contents(unsigned int shndx);   // Return the size of section SHNDX.  typename Elf_types<size>::Elf_WXword  section_size(unsigned int shndx);   // Return the flags of section SHNDX.  typename Elf_types<size>::Elf_WXword  section_flags(unsigned int shndx);   // Return the address of section SHNDX.  typename Elf_types<size>::Elf_Addr  section_addr(unsigned int shndx);   // Return the type of section SHNDX.  Elf_Word  section_type(unsigned int shndx);   // Return the link field of section SHNDX.  Elf_Word  section_link(unsigned int shndx);   // Return the info field of section SHNDX.  Elf_Word  section_info(unsigned int shndx);   // Return the addralign field of section SHNDX.  typename Elf_types<size>::Elf_WXword  section_addralign(unsigned int shndx);  private:  // Shared constructor code.  void  construct(File* file, const Ef_ehdr& ehdr);   // Initialize shnum_ and shstrndx_.  void  initialize_shnum();   // Return the file offset of the header of section SHNDX.  off_t  section_header_offset(unsigned int shndx);   // The file we are reading.  File* file_;  // The file offset to the section headers.  off_t shoff_;  // The number of sections.  unsigned int shnum_;  // The section index of the section name string table.  unsigned int shstrndx_;  // Offset to add to sections larger than SHN_LORESERVE.  int large_shndx_offset_;}; // A small wrapper around SHT_STRTAB data mapped to memory. It checks that the// index is not out of bounds and the string is NULL-terminated. class Elf_strtab{ public:  // Construct an Elf_strtab for a section with contents *P and size SIZE.  Elf_strtab(const unsigned char* p, size_t size);   // Return the file offset to the section headers.  bool  get_c_string(size_t offset, const char** cstring) const  {    if (offset >= this->usable_size_)      return false;    *cstring = this->base_ + offset;    return true;  }  private:  // Contents of the section mapped to memory.  const char* base_;  // One larger that the position of the last NULL character in the section.  // For valid SHT_STRTAB sections, this is the size of the section.  size_t usable_size_;}; // Inline function definitions. // Check for presence of the ELF magic number. inline boolElf_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::stringinternal_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 boolElf_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. template<int size, bool big_endian, typename File>voidElf_file<size, big_endian, File>::construct(File* file, const Ef_ehdr& ehdr){  this->file_ = file;  this->shoff_ = ehdr.get_e_shoff();  this->shnum_ = ehdr.get_e_shnum();  this->shstrndx_ = ehdr.get_e_shstrndx();  this->large_shndx_offset_ = 0;  if (ehdr.get_e_ehsize() != This::ehdr_size)    file->error(_("bad e_ehsize (%d != %d)"),		ehdr.get_e_ehsize(), This::ehdr_size);  if (ehdr.get_e_shentsize() != This::shdr_size)    file->error(_("bad e_shentsize (%d != %d)"),		ehdr.get_e_shentsize(), This::shdr_size);} // Construct an ELF file. template<int size, bool big_endian, typename File>inlineElf_file<size, big_endian, File>::Elf_file(File* file){  typename File::View v(file->view(file_header_offset, This::ehdr_size));  this->construct(file, Ef_ehdr(v.data()));} // Initialize the shnum_ and shstrndx_ fields, handling overflow. template<int size, bool big_endian, typename File>voidElf_file<size, big_endian, File>::initialize_shnum(){  if ((this->shnum_ == 0 || this->shstrndx_ == SHN_XINDEX)      && this->shoff_ != 0)    {      typename File::View v(this->file_->view(this->shoff_, This::shdr_size));      Ef_shdr shdr(v.data());       if (this->shnum_ == 0)	this->shnum_ = shdr.get_sh_size();       if (this->shstrndx_ == SHN_XINDEX)	{	  this->shstrndx_ = shdr.get_sh_link(); 	  // Versions of the GNU binutils between 2.12 and 2.18 did	  // not handle objects with more than SHN_LORESERVE sections	  // correctly.  All large section indexes were offset by	  // 0x100.  Some information can be found here:	  // http://sourceware.org/bugzilla/show_bug.cgi?id=5900 .	  // Fortunately these object files are easy to detect, as the	  // GNU binutils always put the section header string table	  // near the end of the list of sections.  Thus if the	  // section header string table index is larger than the	  // number of sections, then we know we have to subtract	  // 0x100 to get the real section index.	  if (this->shstrndx_ >= this->shnum_)	    {	      if (this->shstrndx_ >= elfcpp::SHN_LORESERVE + 0x100)		{		  this->large_shndx_offset_ = - 0x100;		  this->shstrndx_ -= 0x100;		}	      if (this->shstrndx_ >= this->shnum_)		this->file_->error(_("bad shstrndx: %u >= %u"),				   this->shstrndx_, this->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 intElf_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>off_tElf_file<size, big_endian, File>::section_header_offset(unsigned int shndx){  if (shndx >= this->shnum())    this->file_->error(_("section_header_offset: bad shndx %u >= %u"),		       shndx, this->shnum());  return this->shoff_ + This::shdr_size * shndx;} // Return the name of section SHNDX. template<int size, bool big_endian, typename File>std::stringElf_file<size, big_endian, File>::section_name(unsigned int shndx){  File* const file = this->file_;   // Get the section name offset.  unsigned int sh_name;  {    typename File::View v(file->view(this->section_header_offset(shndx),				     This::shdr_size));    Ef_shdr shdr(v.data());    sh_name = shdr.get_sh_name();  }   // Get the file offset for the section name string table data.  off_t shstr_off;  typename Elf_types<size>::Elf_WXword shstr_size;  {    const unsigned int shstrndx = this->shstrndx_;    typename File::View v(file->view(this->section_header_offset(shstrndx),				     This::shdr_size));    Ef_shdr shstr_shdr(v.data());

Lines 1–500 of 688.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t