xref: /netbsd-src/external/gpl3/binutils.old/dist/elfcpp/elfcpp_file.h (revision e992f068c547fd6e84b3f104dc2340adcc955732)
175fd0b74Schristos // elfcpp_file.h -- file access for elfcpp   -*- C++ -*-
275fd0b74Schristos 
3*e992f068Schristos // Copyright (C) 2006-2022 Free Software Foundation, Inc.
475fd0b74Schristos // Written by Ian Lance Taylor <iant@google.com>.
575fd0b74Schristos 
675fd0b74Schristos // This file is part of elfcpp.
775fd0b74Schristos 
875fd0b74Schristos // This program is free software; you can redistribute it and/or
975fd0b74Schristos // modify it under the terms of the GNU Library General Public License
1075fd0b74Schristos // as published by the Free Software Foundation; either version 2, or
1175fd0b74Schristos // (at your option) any later version.
1275fd0b74Schristos 
1375fd0b74Schristos // In addition to the permissions in the GNU Library General Public
1475fd0b74Schristos // License, the Free Software Foundation gives you unlimited
1575fd0b74Schristos // permission to link the compiled version of this file into
1675fd0b74Schristos // combinations with other programs, and to distribute those
1775fd0b74Schristos // combinations without any restriction coming from the use of this
1875fd0b74Schristos // file.  (The Library Public License restrictions do apply in other
1975fd0b74Schristos // respects; for example, they cover modification of the file, and
2075fd0b74Schristos /// distribution when not linked into a combined executable.)
2175fd0b74Schristos 
2275fd0b74Schristos // This program is distributed in the hope that it will be useful, but
2375fd0b74Schristos // WITHOUT ANY WARRANTY; without even the implied warranty of
2475fd0b74Schristos // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
2575fd0b74Schristos // Library General Public License for more details.
2675fd0b74Schristos 
2775fd0b74Schristos // You should have received a copy of the GNU Library General Public
2875fd0b74Schristos // License along with this program; if not, write to the Free Software
2975fd0b74Schristos // Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
3075fd0b74Schristos // 02110-1301, USA.
3175fd0b74Schristos 
3275fd0b74Schristos // This header file defines the class Elf_file which can be used to
3375fd0b74Schristos // read useful data from an ELF file.  The functions here are all
3475fd0b74Schristos // templates which take a file interface object as a parameter.  This
3575fd0b74Schristos // type must have a subtype View.  This type must support two methods:
3675fd0b74Schristos //     View view(off_t file_offset, off_t data_size)
3775fd0b74Schristos // returns a View for the specified part of the file.
3875fd0b74Schristos //     void error(const char* printf_format, ...)
3975fd0b74Schristos // prints an error message and does not return.  The subtype View must
4075fd0b74Schristos // support a method
4175fd0b74Schristos //     const unsigned char* data()
4275fd0b74Schristos // which returns a pointer to a buffer containing the requested data.
4375fd0b74Schristos // This general interface is used to read data from the file.  Objects
4475fd0b74Schristos // of type View will never survive longer than the elfcpp function.
4575fd0b74Schristos 
4675fd0b74Schristos // Some of these functions must return a reference to part of the
4775fd0b74Schristos // file.  To use these, the file interface must support a subtype
4875fd0b74Schristos // Location:
4975fd0b74Schristos //    Location(off_t file_offset, off_t data_size)
5075fd0b74Schristos // To use this in conjunction with the accessors types Shdr, etc., the
5175fd0b74Schristos // file interface should support an overload of view:
5275fd0b74Schristos //    View view(Location)
5375fd0b74Schristos // This permits writing
5475fd0b74Schristos //    elfcpp::Shdr shdr(file, ef.section_header(n));
5575fd0b74Schristos 
5675fd0b74Schristos #ifndef ELFCPP_FILE_H
5775fd0b74Schristos #define ELFCPP_FILE_H
5875fd0b74Schristos 
5975fd0b74Schristos #include <string>
6075fd0b74Schristos #include <cstdio>
6175fd0b74Schristos #include <cstring>
6275fd0b74Schristos 
6375fd0b74Schristos #include "elfcpp.h"
6475fd0b74Schristos 
6575fd0b74Schristos namespace elfcpp
6675fd0b74Schristos {
6775fd0b74Schristos 
6875fd0b74Schristos // A simple helper class to recognize if a file has an ELF header.
6975fd0b74Schristos 
7075fd0b74Schristos class Elf_recognizer
7175fd0b74Schristos {
7275fd0b74Schristos  public:
7375fd0b74Schristos   // Maximum header size.  The user should try to read this much of
7475fd0b74Schristos   // the file when using this class.
7575fd0b74Schristos 
7675fd0b74Schristos   static const int max_header_size = Elf_sizes<64>::ehdr_size;
7775fd0b74Schristos 
7875fd0b74Schristos   // Checks if the file contains the ELF magic.  Other header fields
7975fd0b74Schristos   // are not checked.
8075fd0b74Schristos 
8175fd0b74Schristos   static bool
8275fd0b74Schristos   is_elf_file(const unsigned char* ehdr_buf, int size);
8375fd0b74Schristos 
8475fd0b74Schristos   // Check if EHDR_BUF/BUFSIZE is a valid header of a 32-bit or
8575fd0b74Schristos   // 64-bit, little-endian or big-endian ELF file.  Assumes
8675fd0b74Schristos   // is_elf_file() has been checked to be true.  If the header is not
8775fd0b74Schristos   // valid, *ERROR contains a human-readable error message.  If is is,
8875fd0b74Schristos   // *SIZE is set to either 32 or 64, *BIG_ENDIAN is set to indicate
8975fd0b74Schristos   // whether the file is big-endian.
9075fd0b74Schristos 
9175fd0b74Schristos   static bool
9275fd0b74Schristos   is_valid_header(const unsigned char* ehdr_buf, off_t bufsize,
9375fd0b74Schristos                   int* size, bool* big_endian,
9475fd0b74Schristos                   std::string* error);
9575fd0b74Schristos };
9675fd0b74Schristos 
9775fd0b74Schristos // This object is used to read an ELF file.
9875fd0b74Schristos //   SIZE: The size of file, 32 or 64.
9975fd0b74Schristos //   BIG_ENDIAN: Whether the file is in big-endian format.
10075fd0b74Schristos //   FILE: A file reading type as described above.
10175fd0b74Schristos 
10275fd0b74Schristos template<int size, bool big_endian, typename File>
10375fd0b74Schristos class Elf_file
10475fd0b74Schristos {
10575fd0b74Schristos  private:
10675fd0b74Schristos   typedef Elf_file<size, big_endian, File> This;
10775fd0b74Schristos 
10875fd0b74Schristos  public:
10975fd0b74Schristos   static const int ehdr_size = Elf_sizes<size>::ehdr_size;
11075fd0b74Schristos   static const int phdr_size = Elf_sizes<size>::phdr_size;
11175fd0b74Schristos   static const int shdr_size = Elf_sizes<size>::shdr_size;
11275fd0b74Schristos   static const int sym_size = Elf_sizes<size>::sym_size;
11375fd0b74Schristos   static const int rel_size = Elf_sizes<size>::rel_size;
11475fd0b74Schristos   static const int rela_size = Elf_sizes<size>::rela_size;
11575fd0b74Schristos 
11675fd0b74Schristos   typedef Ehdr<size, big_endian> Ef_ehdr;
11775fd0b74Schristos   typedef Phdr<size, big_endian> Ef_phdr;
11875fd0b74Schristos   typedef Shdr<size, big_endian> Ef_shdr;
11975fd0b74Schristos   typedef Sym<size, big_endian> Ef_sym;
12075fd0b74Schristos 
12175fd0b74Schristos   // Construct an Elf_file given an ELF file header.
Elf_file(File * file,const Ef_ehdr & ehdr)12275fd0b74Schristos   Elf_file(File* file, const Ef_ehdr& ehdr)
12375fd0b74Schristos   { this->construct(file, ehdr); }
12475fd0b74Schristos 
12575fd0b74Schristos   // Construct an ELF file.
12675fd0b74Schristos   inline
12775fd0b74Schristos   Elf_file(File* file);
12875fd0b74Schristos 
12975fd0b74Schristos   // Return the file offset to the section headers.
13075fd0b74Schristos   off_t
shoff()13175fd0b74Schristos   shoff() const
13275fd0b74Schristos   { return this->shoff_; }
13375fd0b74Schristos 
13475fd0b74Schristos   // Find the first section with an sh_type field equal to TYPE and
13575fd0b74Schristos   // return its index.  Returns SHN_UNDEF if there is no such section.
13675fd0b74Schristos   unsigned int
13775fd0b74Schristos   find_section_by_type(unsigned int type);
13875fd0b74Schristos 
13975fd0b74Schristos   // Return the number of sections.
14075fd0b74Schristos   unsigned int
shnum()14175fd0b74Schristos   shnum()
14275fd0b74Schristos   {
14375fd0b74Schristos     this->initialize_shnum();
14475fd0b74Schristos     return this->shnum_;
14575fd0b74Schristos   }
14675fd0b74Schristos 
14775fd0b74Schristos   unsigned int
shnum()14875fd0b74Schristos   shnum() const
14975fd0b74Schristos   {
15075fd0b74Schristos     if (this->shnum_ == 0 && this->shoff_ != 0)
15175fd0b74Schristos       this->file_->error(_("ELF file has not been initialized yet"
15275fd0b74Schristos 			   " (internal error)"));
15375fd0b74Schristos     return this->shnum_;
15475fd0b74Schristos   }
15575fd0b74Schristos 
15675fd0b74Schristos   // Return the section index of the section name string table.
15775fd0b74Schristos   unsigned int
shstrndx()15875fd0b74Schristos   shstrndx()
15975fd0b74Schristos   {
16075fd0b74Schristos     this->initialize_shnum();
16175fd0b74Schristos     return this->shstrndx_;
16275fd0b74Schristos   }
16375fd0b74Schristos 
16475fd0b74Schristos   unsigned int
shstrndx()16575fd0b74Schristos   shstrndx() const
16675fd0b74Schristos   {
16775fd0b74Schristos     if (this->shstrndx_ == SHN_XINDEX && this->shoff_ != 0)
16875fd0b74Schristos       {
16975fd0b74Schristos 	this->file_->error(_("ELF file has not been initialized yet"
17075fd0b74Schristos 			     " (internal error)"));
17175fd0b74Schristos 	return 0;
17275fd0b74Schristos       }
17375fd0b74Schristos     return this->shstrndx_;
17475fd0b74Schristos   }
17575fd0b74Schristos 
17675fd0b74Schristos   // Return the value to subtract from section indexes >=
17775fd0b74Schristos   // SHN_LORESERVE.  See the comment in initialize_shnum.
17875fd0b74Schristos   int
large_shndx_offset()17975fd0b74Schristos   large_shndx_offset()
18075fd0b74Schristos   {
18175fd0b74Schristos     this->initialize_shnum();
18275fd0b74Schristos     return this->large_shndx_offset_;
18375fd0b74Schristos   }
18475fd0b74Schristos 
18575fd0b74Schristos   int
large_shndx_offset()18675fd0b74Schristos   large_shndx_offset() const
18775fd0b74Schristos   {
18875fd0b74Schristos     if (this->shstrndx_ == SHN_XINDEX && this->shoff_ != 0)
18975fd0b74Schristos       this->file_->error(_("ELF file has not been initialized yet"
19075fd0b74Schristos 			   " (internal error)"));
19175fd0b74Schristos     return this->large_shndx_offset_;
19275fd0b74Schristos   }
19375fd0b74Schristos 
19475fd0b74Schristos   // Return the location of the header of section SHNDX.
19575fd0b74Schristos   typename File::Location
section_header(unsigned int shndx)19675fd0b74Schristos   section_header(unsigned int shndx)
19775fd0b74Schristos   {
19875fd0b74Schristos     return typename File::Location(this->section_header_offset(shndx),
19975fd0b74Schristos 				   shdr_size);
20075fd0b74Schristos   }
20175fd0b74Schristos 
20275fd0b74Schristos   // Return the name of section SHNDX.
20375fd0b74Schristos   std::string
20475fd0b74Schristos   section_name(unsigned int shndx) const;
20575fd0b74Schristos 
20675fd0b74Schristos   // Return the location of the contents of section SHNDX.
20775fd0b74Schristos   typename File::Location
20875fd0b74Schristos   section_contents(unsigned int shndx);
20975fd0b74Schristos 
21075fd0b74Schristos   // Return the size of section SHNDX.
21175fd0b74Schristos   typename Elf_types<size>::Elf_WXword
21275fd0b74Schristos   section_size(unsigned int shndx);
21375fd0b74Schristos 
21475fd0b74Schristos   // Return the flags of section SHNDX.
21575fd0b74Schristos   typename Elf_types<size>::Elf_WXword
21675fd0b74Schristos   section_flags(unsigned int shndx);
21775fd0b74Schristos 
21875fd0b74Schristos   // Return the address of section SHNDX.
21975fd0b74Schristos   typename Elf_types<size>::Elf_Addr
22075fd0b74Schristos   section_addr(unsigned int shndx);
22175fd0b74Schristos 
22275fd0b74Schristos   // Return the type of section SHNDX.
22375fd0b74Schristos   Elf_Word
22475fd0b74Schristos   section_type(unsigned int shndx);
22575fd0b74Schristos 
22675fd0b74Schristos   // Return the link field of section SHNDX.
22775fd0b74Schristos   Elf_Word
22875fd0b74Schristos   section_link(unsigned int shndx);
22975fd0b74Schristos 
23075fd0b74Schristos   // Return the info field of section SHNDX.
23175fd0b74Schristos   Elf_Word
23275fd0b74Schristos   section_info(unsigned int shndx);
23375fd0b74Schristos 
23475fd0b74Schristos   // Return the addralign field of section SHNDX.
23575fd0b74Schristos   typename Elf_types<size>::Elf_WXword
23675fd0b74Schristos   section_addralign(unsigned int shndx);
23775fd0b74Schristos 
23875fd0b74Schristos  private:
23975fd0b74Schristos   // Shared constructor code.
24075fd0b74Schristos   void
24175fd0b74Schristos   construct(File* file, const Ef_ehdr& ehdr);
24275fd0b74Schristos 
24375fd0b74Schristos   // Initialize shnum_ and shstrndx_.
24475fd0b74Schristos   void
24575fd0b74Schristos   initialize_shnum();
24675fd0b74Schristos 
24775fd0b74Schristos   // Return the file offset of the header of section SHNDX.
24875fd0b74Schristos   off_t
24975fd0b74Schristos   section_header_offset(unsigned int shndx) const;
25075fd0b74Schristos 
25175fd0b74Schristos   // The file we are reading.
25275fd0b74Schristos   File* file_;
25375fd0b74Schristos   // The file offset to the section headers.
25475fd0b74Schristos   off_t shoff_;
25575fd0b74Schristos   // The number of sections.
25675fd0b74Schristos   unsigned int shnum_;
25775fd0b74Schristos   // The section index of the section name string table.
25875fd0b74Schristos   unsigned int shstrndx_;
25975fd0b74Schristos   // Offset to add to sections larger than SHN_LORESERVE.
26075fd0b74Schristos   int large_shndx_offset_;
26175fd0b74Schristos };
26275fd0b74Schristos 
26375fd0b74Schristos // A small wrapper around SHT_STRTAB data mapped to memory. It checks that the
26475fd0b74Schristos // index is not out of bounds and the string is NULL-terminated.
26575fd0b74Schristos 
26675fd0b74Schristos class Elf_strtab
26775fd0b74Schristos {
26875fd0b74Schristos  public:
26975fd0b74Schristos   // Construct an Elf_strtab for a section with contents *P and size SIZE.
27075fd0b74Schristos   Elf_strtab(const unsigned char* p, size_t size);
27175fd0b74Schristos 
27275fd0b74Schristos   // Return the file offset to the section headers.
27375fd0b74Schristos   bool
get_c_string(size_t offset,const char ** cstring)27475fd0b74Schristos   get_c_string(size_t offset, const char** cstring) const
27575fd0b74Schristos   {
27675fd0b74Schristos     if (offset >= this->usable_size_)
27775fd0b74Schristos       return false;
27875fd0b74Schristos     *cstring = this->base_ + offset;
27975fd0b74Schristos     return true;
28075fd0b74Schristos   }
28175fd0b74Schristos 
28275fd0b74Schristos  private:
28375fd0b74Schristos   // Contents of the section mapped to memory.
28475fd0b74Schristos   const char* base_;
28575fd0b74Schristos   // One larger that the position of the last NULL character in the section.
28675fd0b74Schristos   // For valid SHT_STRTAB sections, this is the size of the section.
28775fd0b74Schristos   size_t usable_size_;
28875fd0b74Schristos };
28975fd0b74Schristos 
29075fd0b74Schristos // Inline function definitions.
29175fd0b74Schristos 
29275fd0b74Schristos // Check for presence of the ELF magic number.
29375fd0b74Schristos 
29475fd0b74Schristos inline bool
is_elf_file(const unsigned char * ehdr_buf,int size)29575fd0b74Schristos Elf_recognizer::is_elf_file(const unsigned char* ehdr_buf, int size)
29675fd0b74Schristos {
29775fd0b74Schristos   if (size < 4)
29875fd0b74Schristos     return false;
29975fd0b74Schristos 
30075fd0b74Schristos   static unsigned char elfmagic[4] =
30175fd0b74Schristos     {
30275fd0b74Schristos       elfcpp::ELFMAG0, elfcpp::ELFMAG1,
30375fd0b74Schristos       elfcpp::ELFMAG2, elfcpp::ELFMAG3
30475fd0b74Schristos     };
30575fd0b74Schristos   return memcmp(ehdr_buf, elfmagic, 4) == 0;
30675fd0b74Schristos }
30775fd0b74Schristos 
30875fd0b74Schristos namespace
30975fd0b74Schristos {
31075fd0b74Schristos 
31175fd0b74Schristos // Print a number to a string.
31275fd0b74Schristos 
31375fd0b74Schristos inline std::string
internal_printf_int(const char * format,int arg)31475fd0b74Schristos internal_printf_int(const char* format, int arg)
31575fd0b74Schristos {
31675fd0b74Schristos   char buf[256];
31775fd0b74Schristos   snprintf(buf, sizeof(buf), format, arg);
31875fd0b74Schristos   return std::string(buf);
31975fd0b74Schristos }
32075fd0b74Schristos 
32175fd0b74Schristos }  // End anonymous namespace.
32275fd0b74Schristos 
32375fd0b74Schristos // Check the validity of the ELF header.
32475fd0b74Schristos 
32575fd0b74Schristos inline bool
is_valid_header(const unsigned char * ehdr_buf,off_t bufsize,int * size,bool * big_endian,std::string * error)32675fd0b74Schristos Elf_recognizer::is_valid_header(
32775fd0b74Schristos     const unsigned char* ehdr_buf,
32875fd0b74Schristos     off_t bufsize,
32975fd0b74Schristos     int* size,
33075fd0b74Schristos     bool* big_endian,
33175fd0b74Schristos     std::string* error)
33275fd0b74Schristos {
33375fd0b74Schristos   if (bufsize < elfcpp::EI_NIDENT)
33475fd0b74Schristos     {
33575fd0b74Schristos       *error = _("ELF file too short");
33675fd0b74Schristos       return false;
33775fd0b74Schristos     }
33875fd0b74Schristos 
33975fd0b74Schristos   int v = ehdr_buf[elfcpp::EI_VERSION];
34075fd0b74Schristos   if (v != elfcpp::EV_CURRENT)
34175fd0b74Schristos     {
34275fd0b74Schristos       if (v == elfcpp::EV_NONE)
34375fd0b74Schristos         *error = _("invalid ELF version 0");
34475fd0b74Schristos       else
34575fd0b74Schristos         *error = internal_printf_int(_("unsupported ELF version %d"), v);
34675fd0b74Schristos       return false;
34775fd0b74Schristos     }
34875fd0b74Schristos 
34975fd0b74Schristos   int c = ehdr_buf[elfcpp::EI_CLASS];
35075fd0b74Schristos   if (c == elfcpp::ELFCLASSNONE)
35175fd0b74Schristos     {
35275fd0b74Schristos       *error = _("invalid ELF class 0");
35375fd0b74Schristos       return false;
35475fd0b74Schristos     }
35575fd0b74Schristos   else if (c != elfcpp::ELFCLASS32
35675fd0b74Schristos            && c != elfcpp::ELFCLASS64)
35775fd0b74Schristos     {
35875fd0b74Schristos       *error = internal_printf_int(_("unsupported ELF class %d"), c);
35975fd0b74Schristos       return false;
36075fd0b74Schristos     }
36175fd0b74Schristos 
36275fd0b74Schristos   int d = ehdr_buf[elfcpp::EI_DATA];
36375fd0b74Schristos   if (d == elfcpp::ELFDATANONE)
36475fd0b74Schristos     {
36575fd0b74Schristos       *error = _("invalid ELF data encoding");
36675fd0b74Schristos       return false;
36775fd0b74Schristos     }
36875fd0b74Schristos   else if (d != elfcpp::ELFDATA2LSB
36975fd0b74Schristos            && d != elfcpp::ELFDATA2MSB)
37075fd0b74Schristos     {
37175fd0b74Schristos       *error = internal_printf_int(_("unsupported ELF data encoding %d"), d);
37275fd0b74Schristos       return false;
37375fd0b74Schristos     }
37475fd0b74Schristos 
37575fd0b74Schristos   *big_endian = (d == elfcpp::ELFDATA2MSB);
37675fd0b74Schristos 
37775fd0b74Schristos   if (c == elfcpp::ELFCLASS32)
37875fd0b74Schristos     {
37975fd0b74Schristos       if (bufsize < elfcpp::Elf_sizes<32>::ehdr_size)
38075fd0b74Schristos         {
38175fd0b74Schristos           *error = _("ELF file too short");
38275fd0b74Schristos           return false;
38375fd0b74Schristos         }
38475fd0b74Schristos       *size = 32;
38575fd0b74Schristos     }
38675fd0b74Schristos   else
38775fd0b74Schristos     {
38875fd0b74Schristos       if (bufsize < elfcpp::Elf_sizes<64>::ehdr_size)
38975fd0b74Schristos         {
39075fd0b74Schristos           *error = _("ELF file too short");
39175fd0b74Schristos           return false;
39275fd0b74Schristos         }
39375fd0b74Schristos       *size = 64;
39475fd0b74Schristos     }
39575fd0b74Schristos 
39675fd0b74Schristos   return true;
39775fd0b74Schristos }
39875fd0b74Schristos 
39975fd0b74Schristos // Template function definitions.
40075fd0b74Schristos 
40175fd0b74Schristos // Construct an Elf_file given an ELF file header.
40275fd0b74Schristos 
40375fd0b74Schristos template<int size, bool big_endian, typename File>
40475fd0b74Schristos void
construct(File * file,const Ef_ehdr & ehdr)40575fd0b74Schristos Elf_file<size, big_endian, File>::construct(File* file, const Ef_ehdr& ehdr)
40675fd0b74Schristos {
40775fd0b74Schristos   this->file_ = file;
40875fd0b74Schristos   this->shoff_ = ehdr.get_e_shoff();
40975fd0b74Schristos   this->shnum_ = ehdr.get_e_shnum();
41075fd0b74Schristos   this->shstrndx_ = ehdr.get_e_shstrndx();
41175fd0b74Schristos   this->large_shndx_offset_ = 0;
41275fd0b74Schristos   if (ehdr.get_e_ehsize() != This::ehdr_size)
41375fd0b74Schristos     file->error(_("bad e_ehsize (%d != %d)"),
41475fd0b74Schristos 		ehdr.get_e_ehsize(), This::ehdr_size);
41575fd0b74Schristos   if (ehdr.get_e_shentsize() != This::shdr_size)
41675fd0b74Schristos     file->error(_("bad e_shentsize (%d != %d)"),
41775fd0b74Schristos 		ehdr.get_e_shentsize(), This::shdr_size);
41875fd0b74Schristos }
41975fd0b74Schristos 
42075fd0b74Schristos // Construct an ELF file.
42175fd0b74Schristos 
42275fd0b74Schristos template<int size, bool big_endian, typename File>
42375fd0b74Schristos inline
Elf_file(File * file)42475fd0b74Schristos Elf_file<size, big_endian, File>::Elf_file(File* file)
42575fd0b74Schristos {
42675fd0b74Schristos   typename File::View v(file->view(file_header_offset, This::ehdr_size));
42775fd0b74Schristos   this->construct(file, Ef_ehdr(v.data()));
42875fd0b74Schristos }
42975fd0b74Schristos 
43075fd0b74Schristos // Initialize the shnum_ and shstrndx_ fields, handling overflow.
43175fd0b74Schristos 
43275fd0b74Schristos template<int size, bool big_endian, typename File>
43375fd0b74Schristos void
initialize_shnum()43475fd0b74Schristos Elf_file<size, big_endian, File>::initialize_shnum()
43575fd0b74Schristos {
43675fd0b74Schristos   if ((this->shnum_ == 0 || this->shstrndx_ == SHN_XINDEX)
43775fd0b74Schristos       && this->shoff_ != 0)
43875fd0b74Schristos     {
43975fd0b74Schristos       typename File::View v(this->file_->view(this->shoff_, This::shdr_size));
44075fd0b74Schristos       Ef_shdr shdr(v.data());
44175fd0b74Schristos 
44275fd0b74Schristos       if (this->shnum_ == 0)
44375fd0b74Schristos 	this->shnum_ = shdr.get_sh_size();
44475fd0b74Schristos 
44575fd0b74Schristos       if (this->shstrndx_ == SHN_XINDEX)
44675fd0b74Schristos 	{
44775fd0b74Schristos 	  this->shstrndx_ = shdr.get_sh_link();
44875fd0b74Schristos 
44975fd0b74Schristos 	  // Versions of the GNU binutils between 2.12 and 2.18 did
45075fd0b74Schristos 	  // not handle objects with more than SHN_LORESERVE sections
45175fd0b74Schristos 	  // correctly.  All large section indexes were offset by
45275fd0b74Schristos 	  // 0x100.  Some information can be found here:
45375fd0b74Schristos 	  // http://sourceware.org/bugzilla/show_bug.cgi?id=5900 .
45475fd0b74Schristos 	  // Fortunately these object files are easy to detect, as the
45575fd0b74Schristos 	  // GNU binutils always put the section header string table
45675fd0b74Schristos 	  // near the end of the list of sections.  Thus if the
45775fd0b74Schristos 	  // section header string table index is larger than the
45875fd0b74Schristos 	  // number of sections, then we know we have to subtract
45975fd0b74Schristos 	  // 0x100 to get the real section index.
46075fd0b74Schristos 	  if (this->shstrndx_ >= this->shnum_)
46175fd0b74Schristos 	    {
46275fd0b74Schristos 	      if (this->shstrndx_ >= elfcpp::SHN_LORESERVE + 0x100)
46375fd0b74Schristos 		{
46475fd0b74Schristos 		  this->large_shndx_offset_ = - 0x100;
46575fd0b74Schristos 		  this->shstrndx_ -= 0x100;
46675fd0b74Schristos 		}
46775fd0b74Schristos 	      if (this->shstrndx_ >= this->shnum_)
46875fd0b74Schristos 		this->file_->error(_("bad shstrndx: %u >= %u"),
46975fd0b74Schristos 				   this->shstrndx_, this->shnum_);
47075fd0b74Schristos 	    }
47175fd0b74Schristos 	}
47275fd0b74Schristos     }
47375fd0b74Schristos }
47475fd0b74Schristos 
47575fd0b74Schristos // Find section with sh_type equal to TYPE and return its index.
47675fd0b74Schristos // Returns SHN_UNDEF if not found.
47775fd0b74Schristos 
47875fd0b74Schristos template<int size, bool big_endian, typename File>
47975fd0b74Schristos unsigned int
find_section_by_type(unsigned int type)48075fd0b74Schristos Elf_file<size, big_endian, File>::find_section_by_type(unsigned int type)
48175fd0b74Schristos {
48275fd0b74Schristos   unsigned int shnum = this->shnum();
48375fd0b74Schristos   typename File::View v(this->file_->view(this->shoff_,
48475fd0b74Schristos 					  This::shdr_size * shnum));
48575fd0b74Schristos   for (unsigned int i = 0; i < shnum; i++)
48675fd0b74Schristos     {
48775fd0b74Schristos       Ef_shdr shdr(v.data() + This::shdr_size * i);
48875fd0b74Schristos       if (shdr.get_sh_type() == type)
48975fd0b74Schristos         return i;
49075fd0b74Schristos     }
49175fd0b74Schristos   return SHN_UNDEF;
49275fd0b74Schristos }
49375fd0b74Schristos 
49475fd0b74Schristos // Return the file offset of the section header of section SHNDX.
49575fd0b74Schristos 
49675fd0b74Schristos template<int size, bool big_endian, typename File>
49775fd0b74Schristos off_t
section_header_offset(unsigned int shndx)49875fd0b74Schristos Elf_file<size, big_endian, File>::section_header_offset(unsigned int shndx) const
49975fd0b74Schristos {
50075fd0b74Schristos   if (shndx >= this->shnum())
50175fd0b74Schristos     this->file_->error(_("section_header_offset: bad shndx %u >= %u"),
50275fd0b74Schristos 		       shndx, this->shnum());
50375fd0b74Schristos   return this->shoff_ + This::shdr_size * shndx;
50475fd0b74Schristos }
50575fd0b74Schristos 
50675fd0b74Schristos // Return the name of section SHNDX.
50775fd0b74Schristos 
50875fd0b74Schristos template<int size, bool big_endian, typename File>
50975fd0b74Schristos std::string
section_name(unsigned int shndx)51075fd0b74Schristos Elf_file<size, big_endian, File>::section_name(unsigned int shndx) const
51175fd0b74Schristos {
51275fd0b74Schristos   File* const file = this->file_;
51375fd0b74Schristos 
51475fd0b74Schristos   // Get the section name offset.
51575fd0b74Schristos   unsigned int sh_name;
51675fd0b74Schristos   {
51775fd0b74Schristos     typename File::View v(file->view(this->section_header_offset(shndx),
51875fd0b74Schristos 				     This::shdr_size));
51975fd0b74Schristos     Ef_shdr shdr(v.data());
52075fd0b74Schristos     sh_name = shdr.get_sh_name();
52175fd0b74Schristos   }
52275fd0b74Schristos 
52375fd0b74Schristos   // Get the file offset for the section name string table data.
52475fd0b74Schristos   off_t shstr_off;
52575fd0b74Schristos   typename Elf_types<size>::Elf_WXword shstr_size;
52675fd0b74Schristos   {
52775fd0b74Schristos     const unsigned int shstrndx = this->shstrndx_;
52875fd0b74Schristos     typename File::View v(file->view(this->section_header_offset(shstrndx),
52975fd0b74Schristos 				     This::shdr_size));
53075fd0b74Schristos     Ef_shdr shstr_shdr(v.data());
53175fd0b74Schristos     shstr_off = shstr_shdr.get_sh_offset();
53275fd0b74Schristos     shstr_size = shstr_shdr.get_sh_size();
53375fd0b74Schristos   }
53475fd0b74Schristos 
53575fd0b74Schristos   if (sh_name >= shstr_size)
53675fd0b74Schristos     file->error(_("bad section name offset for section %u: %u"),
53775fd0b74Schristos 		shndx, sh_name);
53875fd0b74Schristos 
53975fd0b74Schristos   typename File::View v(file->view(shstr_off, shstr_size));
54075fd0b74Schristos 
54175fd0b74Schristos   const unsigned char* datau = v.data();
54275fd0b74Schristos   const char* data = reinterpret_cast<const char*>(datau);
54375fd0b74Schristos   const void* p = ::memchr(data + sh_name, '\0', shstr_size - sh_name);
54475fd0b74Schristos   if (p == NULL)
54575fd0b74Schristos     file->error(_("missing null terminator for name of section %u"),
54675fd0b74Schristos 		shndx);
54775fd0b74Schristos 
54875fd0b74Schristos   size_t len = static_cast<const char*>(p) - (data + sh_name);
54975fd0b74Schristos 
55075fd0b74Schristos   return std::string(data + sh_name, len);
55175fd0b74Schristos }
55275fd0b74Schristos 
55375fd0b74Schristos // Return the contents of section SHNDX.
55475fd0b74Schristos 
55575fd0b74Schristos template<int size, bool big_endian, typename File>
55675fd0b74Schristos typename File::Location
section_contents(unsigned int shndx)55775fd0b74Schristos Elf_file<size, big_endian, File>::section_contents(unsigned int shndx)
55875fd0b74Schristos {
55975fd0b74Schristos   File* const file = this->file_;
56075fd0b74Schristos 
56175fd0b74Schristos   if (shndx >= this->shnum())
56275fd0b74Schristos     file->error(_("section_contents: bad shndx %u >= %u"),
56375fd0b74Schristos 		shndx, this->shnum());
56475fd0b74Schristos 
56575fd0b74Schristos   typename File::View v(file->view(this->section_header_offset(shndx),
56675fd0b74Schristos 				   This::shdr_size));
56775fd0b74Schristos   Ef_shdr shdr(v.data());
56875fd0b74Schristos   return typename File::Location(shdr.get_sh_offset(), shdr.get_sh_size());
56975fd0b74Schristos }
57075fd0b74Schristos 
57175fd0b74Schristos // Get the size of section SHNDX.
57275fd0b74Schristos 
57375fd0b74Schristos template<int size, bool big_endian, typename File>
57475fd0b74Schristos typename Elf_types<size>::Elf_WXword
section_size(unsigned int shndx)57575fd0b74Schristos Elf_file<size, big_endian, File>::section_size(unsigned int shndx)
57675fd0b74Schristos {
57775fd0b74Schristos   File* const file = this->file_;
57875fd0b74Schristos 
57975fd0b74Schristos   if (shndx >= this->shnum())
58075fd0b74Schristos     file->error(_("section_size: bad shndx %u >= %u"),
58175fd0b74Schristos 		shndx, this->shnum());
58275fd0b74Schristos 
58375fd0b74Schristos   typename File::View v(file->view(this->section_header_offset(shndx),
58475fd0b74Schristos 				   This::shdr_size));
58575fd0b74Schristos 
58675fd0b74Schristos   Ef_shdr shdr(v.data());
58775fd0b74Schristos   return shdr.get_sh_size();
58875fd0b74Schristos }
58975fd0b74Schristos 
59075fd0b74Schristos // Return the section flags of section SHNDX.
59175fd0b74Schristos 
59275fd0b74Schristos template<int size, bool big_endian, typename File>
59375fd0b74Schristos typename Elf_types<size>::Elf_WXword
section_flags(unsigned int shndx)59475fd0b74Schristos Elf_file<size, big_endian, File>::section_flags(unsigned int shndx)
59575fd0b74Schristos {
59675fd0b74Schristos   File* const file = this->file_;
59775fd0b74Schristos 
59875fd0b74Schristos   if (shndx >= this->shnum())
59975fd0b74Schristos     file->error(_("section_flags: bad shndx %u >= %u"),
60075fd0b74Schristos 		shndx, this->shnum());
60175fd0b74Schristos 
60275fd0b74Schristos   typename File::View v(file->view(this->section_header_offset(shndx),
60375fd0b74Schristos 				   This::shdr_size));
60475fd0b74Schristos 
60575fd0b74Schristos   Ef_shdr shdr(v.data());
60675fd0b74Schristos   return shdr.get_sh_flags();
60775fd0b74Schristos }
60875fd0b74Schristos 
60975fd0b74Schristos // Return the address of section SHNDX.
61075fd0b74Schristos 
61175fd0b74Schristos template<int size, bool big_endian, typename File>
61275fd0b74Schristos typename Elf_types<size>::Elf_Addr
section_addr(unsigned int shndx)61375fd0b74Schristos Elf_file<size, big_endian, File>::section_addr(unsigned int shndx)
61475fd0b74Schristos {
61575fd0b74Schristos   File* const file = this->file_;
61675fd0b74Schristos 
61775fd0b74Schristos   if (shndx >= this->shnum())
61875fd0b74Schristos     file->error(_("section_flags: bad shndx %u >= %u"),
61975fd0b74Schristos 		shndx, this->shnum());
62075fd0b74Schristos 
62175fd0b74Schristos   typename File::View v(file->view(this->section_header_offset(shndx),
62275fd0b74Schristos 				   This::shdr_size));
62375fd0b74Schristos 
62475fd0b74Schristos   Ef_shdr shdr(v.data());
62575fd0b74Schristos   return shdr.get_sh_addr();
62675fd0b74Schristos }
62775fd0b74Schristos 
62875fd0b74Schristos // Return the type of section SHNDX.
62975fd0b74Schristos 
63075fd0b74Schristos template<int size, bool big_endian, typename File>
63175fd0b74Schristos Elf_Word
section_type(unsigned int shndx)63275fd0b74Schristos Elf_file<size, big_endian, File>::section_type(unsigned int shndx)
63375fd0b74Schristos {
63475fd0b74Schristos   File* const file = this->file_;
63575fd0b74Schristos 
63675fd0b74Schristos   if (shndx >= this->shnum())
63775fd0b74Schristos     file->error(_("section_type: bad shndx %u >= %u"),
63875fd0b74Schristos 		shndx, this->shnum());
63975fd0b74Schristos 
64075fd0b74Schristos   typename File::View v(file->view(this->section_header_offset(shndx),
64175fd0b74Schristos 				   This::shdr_size));
64275fd0b74Schristos 
64375fd0b74Schristos   Ef_shdr shdr(v.data());
64475fd0b74Schristos   return shdr.get_sh_type();
64575fd0b74Schristos }
64675fd0b74Schristos 
64775fd0b74Schristos // Return the sh_link field of section SHNDX.
64875fd0b74Schristos 
64975fd0b74Schristos template<int size, bool big_endian, typename File>
65075fd0b74Schristos Elf_Word
section_link(unsigned int shndx)65175fd0b74Schristos Elf_file<size, big_endian, File>::section_link(unsigned int shndx)
65275fd0b74Schristos {
65375fd0b74Schristos   File* const file = this->file_;
65475fd0b74Schristos 
65575fd0b74Schristos   if (shndx >= this->shnum())
65675fd0b74Schristos     file->error(_("section_link: bad shndx %u >= %u"),
65775fd0b74Schristos 		shndx, this->shnum());
65875fd0b74Schristos 
65975fd0b74Schristos   typename File::View v(file->view(this->section_header_offset(shndx),
66075fd0b74Schristos 				   This::shdr_size));
66175fd0b74Schristos 
66275fd0b74Schristos   Ef_shdr shdr(v.data());
66375fd0b74Schristos   return shdr.get_sh_link();
66475fd0b74Schristos }
66575fd0b74Schristos 
66675fd0b74Schristos // Return the sh_info field of section SHNDX.
66775fd0b74Schristos 
66875fd0b74Schristos template<int size, bool big_endian, typename File>
66975fd0b74Schristos Elf_Word
section_info(unsigned int shndx)67075fd0b74Schristos Elf_file<size, big_endian, File>::section_info(unsigned int shndx)
67175fd0b74Schristos {
67275fd0b74Schristos   File* const file = this->file_;
67375fd0b74Schristos 
67475fd0b74Schristos   if (shndx >= this->shnum())
67575fd0b74Schristos     file->error(_("section_info: bad shndx %u >= %u"),
67675fd0b74Schristos 		shndx, this->shnum());
67775fd0b74Schristos 
67875fd0b74Schristos   typename File::View v(file->view(this->section_header_offset(shndx),
67975fd0b74Schristos 				   This::shdr_size));
68075fd0b74Schristos 
68175fd0b74Schristos   Ef_shdr shdr(v.data());
68275fd0b74Schristos   return shdr.get_sh_info();
68375fd0b74Schristos }
68475fd0b74Schristos 
68575fd0b74Schristos // Return the sh_addralign field of section SHNDX.
68675fd0b74Schristos 
68775fd0b74Schristos template<int size, bool big_endian, typename File>
68875fd0b74Schristos typename Elf_types<size>::Elf_WXword
section_addralign(unsigned int shndx)68975fd0b74Schristos Elf_file<size, big_endian, File>::section_addralign(unsigned int shndx)
69075fd0b74Schristos {
69175fd0b74Schristos   File* const file = this->file_;
69275fd0b74Schristos 
69375fd0b74Schristos   if (shndx >= this->shnum())
69475fd0b74Schristos     file->error(_("section_addralign: bad shndx %u >= %u"),
69575fd0b74Schristos 		shndx, this->shnum());
69675fd0b74Schristos 
69775fd0b74Schristos   typename File::View v(file->view(this->section_header_offset(shndx),
69875fd0b74Schristos 				   This::shdr_size));
69975fd0b74Schristos 
70075fd0b74Schristos   Ef_shdr shdr(v.data());
70175fd0b74Schristos   return shdr.get_sh_addralign();
70275fd0b74Schristos }
70375fd0b74Schristos 
70475fd0b74Schristos inline
Elf_strtab(const unsigned char * p,size_t size)70575fd0b74Schristos Elf_strtab::Elf_strtab(const unsigned char* p, size_t size)
70675fd0b74Schristos {
70775fd0b74Schristos   // Check if the section is NUL-terminated. If it isn't, we ignore
70875fd0b74Schristos   // the last part to make sure we don't return non-NUL-terminated
70975fd0b74Schristos   // strings.
71075fd0b74Schristos   while (size > 0 && p[size - 1] != 0)
71175fd0b74Schristos     size--;
71275fd0b74Schristos   this->base_ = reinterpret_cast<const char*>(p);
71375fd0b74Schristos   this->usable_size_ = size;
71475fd0b74Schristos }
71575fd0b74Schristos 
71675fd0b74Schristos } // End namespace elfcpp.
71775fd0b74Schristos 
71875fd0b74Schristos #endif // !defined(ELFCPP_FILE_H)
719