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