cmake/Source/cmELF.cxx

813 lines
22 KiB
C++
Raw Normal View History

2016-10-30 18:24:19 +01:00
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmELF.h"
2020-02-01 23:06:01 +01:00
#include <cstddef>
2020-08-30 11:54:41 +02:00
#include <cstdint>
2016-10-30 18:24:19 +01:00
#include <map>
2020-02-01 23:06:01 +01:00
#include <memory>
2016-10-30 18:24:19 +01:00
#include <sstream>
#include <utility>
#include <vector>
2020-02-01 23:06:01 +01:00
#include <cm/memory>
2020-08-30 11:54:41 +02:00
#include <cmext/algorithm>
2020-02-01 23:06:01 +01:00
2020-08-30 11:54:41 +02:00
#include <cm3p/kwiml/abi.h>
2020-02-01 23:06:01 +01:00
2020-08-30 11:54:41 +02:00
#include "cmsys/FStream.hxx"
2020-02-01 23:06:01 +01:00
2021-11-20 13:41:27 +01:00
#include "cmelf/elf32.h"
#include "cmelf/elf64.h"
#include "cmelf/elf_common.h"
// Low-level byte swapping implementation.
2016-07-09 11:21:54 +02:00
template <size_t s>
struct cmELFByteSwapSize
{
};
2022-03-29 21:10:50 +02:00
static void cmELFByteSwap(char* data, cmELFByteSwapSize<2> /*unused*/)
{
char one_byte;
2016-07-09 11:21:54 +02:00
one_byte = data[0];
data[0] = data[1];
data[1] = one_byte;
}
2022-03-29 21:10:50 +02:00
static void cmELFByteSwap(char* data, cmELFByteSwapSize<4> /*unused*/)
{
char one_byte;
2016-07-09 11:21:54 +02:00
one_byte = data[0];
data[0] = data[3];
data[3] = one_byte;
one_byte = data[1];
data[1] = data[2];
data[2] = one_byte;
}
2022-03-29 21:10:50 +02:00
static void cmELFByteSwap(char* data, cmELFByteSwapSize<8> /*unused*/)
{
char one_byte;
2016-07-09 11:21:54 +02:00
one_byte = data[0];
data[0] = data[7];
data[7] = one_byte;
one_byte = data[1];
data[1] = data[6];
data[6] = one_byte;
one_byte = data[2];
data[2] = data[5];
data[5] = one_byte;
one_byte = data[3];
data[3] = data[4];
data[4] = one_byte;
}
// Low-level byte swapping interface.
template <typename T>
void cmELFByteSwap(T& x)
{
cmELFByteSwap(reinterpret_cast<char*>(&x), cmELFByteSwapSize<sizeof(T)>());
}
class cmELFInternal
{
public:
2020-02-01 23:06:01 +01:00
using StringEntry = cmELF::StringEntry;
2016-07-09 11:21:54 +02:00
enum ByteOrderType
{
ByteOrderMSB,
ByteOrderLSB
};
// Construct and take ownership of the file stream object.
2020-02-01 23:06:01 +01:00
cmELFInternal(cmELF* external, std::unique_ptr<std::istream> fin,
2016-07-09 11:21:54 +02:00
ByteOrderType order)
: External(external)
2020-02-01 23:06:01 +01:00
, Stream(std::move(fin))
2016-07-09 11:21:54 +02:00
, ByteOrder(order)
{
// In most cases the processor-specific byte order will match that
// of the target execution environment. If we choose wrong here
// it is fixed when the header is read.
2016-03-13 13:35:51 +01:00
#if KWIML_ABI_ENDIAN_ID == KWIML_ABI_ENDIAN_ID_LITTLE
this->NeedSwap = (this->ByteOrder == ByteOrderMSB);
2016-03-13 13:35:51 +01:00
#elif KWIML_ABI_ENDIAN_ID == KWIML_ABI_ENDIAN_ID_BIG
this->NeedSwap = (this->ByteOrder == ByteOrderLSB);
#else
this->NeedSwap = false; // Final decision is at runtime anyway.
#endif
// We have not yet loaded the section info.
this->DynamicSectionIndex = -1;
2016-07-09 11:21:54 +02:00
}
// Destruct and delete the file stream object.
2020-02-01 23:06:01 +01:00
virtual ~cmELFInternal() = default;
// Forward to the per-class implementation.
virtual unsigned int GetNumberOfSections() const = 0;
virtual unsigned long GetDynamicEntryPosition(int j) = 0;
2017-04-14 19:02:05 +02:00
virtual cmELF::DynamicEntryList GetDynamicEntries() = 0;
virtual std::vector<char> EncodeDynamicEntries(
const cmELF::DynamicEntryList&) = 0;
2015-04-27 22:25:09 +02:00
virtual StringEntry const* GetDynamicSectionString(unsigned int tag) = 0;
2021-11-20 13:41:27 +01:00
virtual bool IsMips() const = 0;
virtual void PrintInfo(std::ostream& os) const = 0;
// Lookup the SONAME in the DYNAMIC section.
StringEntry const* GetSOName()
2016-07-09 11:21:54 +02:00
{
return this->GetDynamicSectionString(DT_SONAME);
2016-07-09 11:21:54 +02:00
}
// Lookup the RPATH in the DYNAMIC section.
StringEntry const* GetRPath()
2016-07-09 11:21:54 +02:00
{
return this->GetDynamicSectionString(DT_RPATH);
2016-07-09 11:21:54 +02:00
}
// Lookup the RUNPATH in the DYNAMIC section.
StringEntry const* GetRunPath()
2016-07-09 11:21:54 +02:00
{
return this->GetDynamicSectionString(DT_RUNPATH);
2016-07-09 11:21:54 +02:00
}
// Return the recorded ELF type.
cmELF::FileType GetFileType() const { return this->ELFType; }
2018-08-09 18:06:22 +02:00
2021-09-14 00:13:48 +02:00
// Return the recorded machine.
std::uint16_t GetMachine() const { return this->Machine; }
protected:
// Data common to all ELF class implementations.
// The external cmELF object.
cmELF* External;
// The stream from which to read.
2020-02-01 23:06:01 +01:00
std::unique_ptr<std::istream> Stream;
// The byte order of the ELF file.
ByteOrderType ByteOrder;
// The ELF file type.
2022-08-04 22:12:04 +02:00
cmELF::FileType ELFType = cmELF::FileTypeInvalid;
2021-09-14 00:13:48 +02:00
// The ELF architecture.
std::uint16_t Machine;
// Whether we need to byte-swap structures read from the stream.
bool NeedSwap;
// The section header index of the DYNAMIC section (-1 if none).
int DynamicSectionIndex;
// Helper methods for subclasses.
void SetErrorMessage(const char* msg)
2016-07-09 11:21:54 +02:00
{
this->External->ErrorMessage = msg;
this->ELFType = cmELF::FileTypeInvalid;
2016-07-09 11:21:54 +02:00
}
// Store string table entry states.
2015-04-27 22:25:09 +02:00
std::map<unsigned int, StringEntry> DynamicSectionStrings;
};
// Configure the implementation template for 32-bit ELF files.
struct cmELFTypes32
{
2020-02-01 23:06:01 +01:00
using ELF_Ehdr = Elf32_Ehdr;
using ELF_Shdr = Elf32_Shdr;
using ELF_Dyn = Elf32_Dyn;
using ELF_Half = Elf32_Half;
using tagtype = ::uint32_t;
static const char* GetName() { return "32-bit"; }
};
2015-04-27 22:25:09 +02:00
// Configure the implementation template for 64-bit ELF files.
struct cmELFTypes64
{
2020-02-01 23:06:01 +01:00
using ELF_Ehdr = Elf64_Ehdr;
using ELF_Shdr = Elf64_Shdr;
using ELF_Dyn = Elf64_Dyn;
using ELF_Half = Elf64_Half;
using tagtype = ::uint64_t;
static const char* GetName() { return "64-bit"; }
};
// Parser implementation template.
template <class Types>
2016-07-09 11:21:54 +02:00
class cmELFInternalImpl : public cmELFInternal
{
public:
// Copy the ELF file format types from our configuration parameter.
2020-02-01 23:06:01 +01:00
using ELF_Ehdr = typename Types::ELF_Ehdr;
using ELF_Shdr = typename Types::ELF_Shdr;
using ELF_Dyn = typename Types::ELF_Dyn;
using ELF_Half = typename Types::ELF_Half;
using tagtype = typename Types::tagtype;
// Construct with a stream and byte swap indicator.
2020-02-01 23:06:01 +01:00
cmELFInternalImpl(cmELF* external, std::unique_ptr<std::istream> fin,
ByteOrderType order);
// Return the number of sections as specified by the ELF header.
2018-01-26 17:06:56 +01:00
unsigned int GetNumberOfSections() const override
2016-07-09 11:21:54 +02:00
{
return static_cast<unsigned int>(this->ELFHeader.e_shnum);
2016-07-09 11:21:54 +02:00
}
2017-04-14 19:02:05 +02:00
// Get the file position of a dynamic section entry.
2018-01-26 17:06:56 +01:00
unsigned long GetDynamicEntryPosition(int j) override;
2018-01-26 17:06:56 +01:00
cmELF::DynamicEntryList GetDynamicEntries() override;
std::vector<char> EncodeDynamicEntries(
const cmELF::DynamicEntryList&) override;
2017-04-14 19:02:05 +02:00
// Lookup a string from the dynamic section with the given tag.
2018-01-26 17:06:56 +01:00
StringEntry const* GetDynamicSectionString(unsigned int tag) override;
2021-11-20 13:41:27 +01:00
bool IsMips() const override { return this->ELFHeader.e_machine == EM_MIPS; }
// Print information about the ELF file.
2018-01-26 17:06:56 +01:00
void PrintInfo(std::ostream& os) const override
2016-07-09 11:21:54 +02:00
{
os << "ELF " << Types::GetName();
2016-07-09 11:21:54 +02:00
if (this->ByteOrder == ByteOrderMSB) {
os << " MSB";
2016-07-09 11:21:54 +02:00
} else if (this->ByteOrder == ByteOrderLSB) {
os << " LSB";
2016-07-09 11:21:54 +02:00
}
switch (this->ELFType) {
case cmELF::FileTypeInvalid:
os << " invalid file";
break;
case cmELF::FileTypeRelocatableObject:
os << " relocatable object";
break;
case cmELF::FileTypeExecutable:
os << " executable";
break;
case cmELF::FileTypeSharedLibrary:
os << " shared library";
break;
case cmELF::FileTypeCore:
os << " core file";
break;
case cmELF::FileTypeSpecificOS:
os << " os-specific type";
break;
case cmELF::FileTypeSpecificProc:
os << " processor-specific type";
break;
}
2016-07-09 11:21:54 +02:00
os << "\n";
}
private:
2020-02-01 23:06:01 +01:00
static_assert(sizeof(ELF_Dyn().d_un.d_val) == sizeof(ELF_Dyn().d_un.d_ptr),
"ByteSwap(ELF_Dyn) assumes d_val and d_ptr are the same size");
2017-04-14 19:02:05 +02:00
void ByteSwap(ELF_Ehdr& elf_header)
2016-07-09 11:21:54 +02:00
{
cmELFByteSwap(elf_header.e_type);
cmELFByteSwap(elf_header.e_machine);
cmELFByteSwap(elf_header.e_version);
cmELFByteSwap(elf_header.e_entry);
cmELFByteSwap(elf_header.e_phoff);
cmELFByteSwap(elf_header.e_shoff);
cmELFByteSwap(elf_header.e_flags);
cmELFByteSwap(elf_header.e_ehsize);
cmELFByteSwap(elf_header.e_phentsize);
cmELFByteSwap(elf_header.e_phnum);
cmELFByteSwap(elf_header.e_shentsize);
cmELFByteSwap(elf_header.e_shnum);
cmELFByteSwap(elf_header.e_shstrndx);
2016-07-09 11:21:54 +02:00
}
void ByteSwap(ELF_Shdr& sec_header)
2016-07-09 11:21:54 +02:00
{
cmELFByteSwap(sec_header.sh_name);
cmELFByteSwap(sec_header.sh_type);
cmELFByteSwap(sec_header.sh_flags);
cmELFByteSwap(sec_header.sh_addr);
cmELFByteSwap(sec_header.sh_offset);
cmELFByteSwap(sec_header.sh_size);
cmELFByteSwap(sec_header.sh_link);
cmELFByteSwap(sec_header.sh_info);
cmELFByteSwap(sec_header.sh_addralign);
cmELFByteSwap(sec_header.sh_entsize);
2016-07-09 11:21:54 +02:00
}
void ByteSwap(ELF_Dyn& dyn)
2016-07-09 11:21:54 +02:00
{
cmELFByteSwap(dyn.d_tag);
2017-04-14 19:02:05 +02:00
cmELFByteSwap(dyn.d_un.d_val);
2016-07-09 11:21:54 +02:00
}
bool FileTypeValid(ELF_Half et)
2016-07-09 11:21:54 +02:00
{
unsigned int eti = static_cast<unsigned int>(et);
2016-07-09 11:21:54 +02:00
if (eti == ET_NONE || eti == ET_REL || eti == ET_EXEC || eti == ET_DYN ||
eti == ET_CORE) {
return true;
2016-07-09 11:21:54 +02:00
}
if (eti >= ET_LOOS && eti <= ET_HIOS) {
return true;
2016-07-09 11:21:54 +02:00
}
if (eti >= ET_LOPROC && eti <= ET_HIPROC) {
return true;
2016-07-09 11:21:54 +02:00
}
return false;
2016-07-09 11:21:54 +02:00
}
bool Read(ELF_Ehdr& x)
2016-07-09 11:21:54 +02:00
{
// Read the header from the file.
2020-02-01 23:06:01 +01:00
if (!this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x))) {
return false;
2016-07-09 11:21:54 +02:00
}
// The byte order of ELF header fields may not match that of the
// processor-specific data. The header fields are ordered to
// match the target execution environment, so we may need to
// memorize the order of all platforms based on the e_machine
// value. As a heuristic, if the type is invalid but its
// swapped value is okay then flip our swap mode.
ELF_Half et = x.e_type;
2016-07-09 11:21:54 +02:00
if (this->NeedSwap) {
cmELFByteSwap(et);
2016-07-09 11:21:54 +02:00
}
if (!this->FileTypeValid(et)) {
cmELFByteSwap(et);
2016-07-09 11:21:54 +02:00
if (this->FileTypeValid(et)) {
// The previous byte order guess was wrong. Flip it.
this->NeedSwap = !this->NeedSwap;
}
2016-07-09 11:21:54 +02:00
}
// Fix the byte order of the header.
2016-07-09 11:21:54 +02:00
if (this->NeedSwap) {
2021-09-14 00:13:48 +02:00
this->ByteSwap(x);
}
2016-07-09 11:21:54 +02:00
return true;
}
bool Read(ELF_Shdr& x)
2016-07-09 11:21:54 +02:00
{
2020-02-01 23:06:01 +01:00
if (this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x)) &&
2016-07-09 11:21:54 +02:00
this->NeedSwap) {
2021-09-14 00:13:48 +02:00
this->ByteSwap(x);
}
2020-02-01 23:06:01 +01:00
return !this->Stream->fail();
2016-07-09 11:21:54 +02:00
}
bool Read(ELF_Dyn& x)
2016-07-09 11:21:54 +02:00
{
2020-02-01 23:06:01 +01:00
if (this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x)) &&
2016-07-09 11:21:54 +02:00
this->NeedSwap) {
2021-09-14 00:13:48 +02:00
this->ByteSwap(x);
}
2020-02-01 23:06:01 +01:00
return !this->Stream->fail();
2016-07-09 11:21:54 +02:00
}
bool LoadSectionHeader(ELF_Half i)
2016-07-09 11:21:54 +02:00
{
// Read the section header from the file.
2020-02-01 23:06:01 +01:00
this->Stream->seekg(this->ELFHeader.e_shoff +
this->ELFHeader.e_shentsize * i);
2016-07-09 11:21:54 +02:00
if (!this->Read(this->SectionHeaders[i])) {
return false;
2016-07-09 11:21:54 +02:00
}
// Identify some important sections.
2016-07-09 11:21:54 +02:00
if (this->SectionHeaders[i].sh_type == SHT_DYNAMIC) {
this->DynamicSectionIndex = i;
}
2016-07-09 11:21:54 +02:00
return true;
}
bool LoadDynamicSection();
// Store the main ELF header.
ELF_Ehdr ELFHeader;
// Store all the section headers.
std::vector<ELF_Shdr> SectionHeaders;
// Store all entries of the DYNAMIC section.
std::vector<ELF_Dyn> DynamicSectionEntries;
};
template <class Types>
2020-02-01 23:06:01 +01:00
cmELFInternalImpl<Types>::cmELFInternalImpl(cmELF* external,
std::unique_ptr<std::istream> fin,
ByteOrderType order)
: cmELFInternal(external, std::move(fin), order)
{
// Read the main header.
2016-07-09 11:21:54 +02:00
if (!this->Read(this->ELFHeader)) {
this->SetErrorMessage("Failed to read main ELF header.");
return;
2016-07-09 11:21:54 +02:00
}
// Determine the ELF file type.
2016-07-09 11:21:54 +02:00
switch (this->ELFHeader.e_type) {
case ET_NONE:
this->SetErrorMessage("ELF file type is NONE.");
return;
case ET_REL:
this->ELFType = cmELF::FileTypeRelocatableObject;
break;
case ET_EXEC:
this->ELFType = cmELF::FileTypeExecutable;
break;
case ET_DYN:
this->ELFType = cmELF::FileTypeSharedLibrary;
break;
case ET_CORE:
this->ELFType = cmELF::FileTypeCore;
break;
2016-07-09 11:21:54 +02:00
default: {
unsigned int eti = static_cast<unsigned int>(this->ELFHeader.e_type);
2016-07-09 11:21:54 +02:00
if (eti >= ET_LOOS && eti <= ET_HIOS) {
this->ELFType = cmELF::FileTypeSpecificOS;
break;
2016-07-09 11:21:54 +02:00
}
if (eti >= ET_LOPROC && eti <= ET_HIPROC) {
this->ELFType = cmELF::FileTypeSpecificProc;
break;
2016-07-09 11:21:54 +02:00
}
2015-04-27 22:25:09 +02:00
std::ostringstream e;
e << "Unknown ELF file type " << eti;
this->SetErrorMessage(e.str().c_str());
return;
}
2016-07-09 11:21:54 +02:00
}
2021-09-14 00:13:48 +02:00
this->Machine = this->ELFHeader.e_machine;
// Load the section headers.
this->SectionHeaders.resize(this->ELFHeader.e_shnum);
2016-07-09 11:21:54 +02:00
for (ELF_Half i = 0; i < this->ELFHeader.e_shnum; ++i) {
if (!this->LoadSectionHeader(i)) {
this->SetErrorMessage("Failed to load section headers.");
return;
}
2016-07-09 11:21:54 +02:00
}
}
template <class Types>
bool cmELFInternalImpl<Types>::LoadDynamicSection()
{
// If there is no dynamic section we are done.
2016-07-09 11:21:54 +02:00
if (this->DynamicSectionIndex < 0) {
return false;
2016-07-09 11:21:54 +02:00
}
// If the section was already loaded we are done.
2016-07-09 11:21:54 +02:00
if (!this->DynamicSectionEntries.empty()) {
return true;
2016-07-09 11:21:54 +02:00
}
2015-12-03 18:43:53 +01:00
// If there are no entries we are done.
ELF_Shdr const& sec = this->SectionHeaders[this->DynamicSectionIndex];
2016-07-09 11:21:54 +02:00
if (sec.sh_entsize == 0) {
2015-12-03 18:43:53 +01:00
return false;
2016-07-09 11:21:54 +02:00
}
2015-12-03 18:43:53 +01:00
// Allocate the dynamic section entries.
2009-10-11 10:55:36 +03:00
int n = static_cast<int>(sec.sh_size / sec.sh_entsize);
this->DynamicSectionEntries.resize(n);
// Read each entry.
2016-07-09 11:21:54 +02:00
for (int j = 0; j < n; ++j) {
// Seek to the beginning of the section entry.
2020-02-01 23:06:01 +01:00
this->Stream->seekg(sec.sh_offset + sec.sh_entsize * j);
ELF_Dyn& dyn = this->DynamicSectionEntries[j];
// Try reading the entry.
2016-07-09 11:21:54 +02:00
if (!this->Read(dyn)) {
this->SetErrorMessage("Error reading entry from DYNAMIC section.");
this->DynamicSectionIndex = -1;
return false;
}
2016-07-09 11:21:54 +02:00
}
return true;
}
template <class Types>
2017-04-14 19:02:05 +02:00
unsigned long cmELFInternalImpl<Types>::GetDynamicEntryPosition(int j)
{
2016-07-09 11:21:54 +02:00
if (!this->LoadDynamicSection()) {
return 0;
2016-07-09 11:21:54 +02:00
}
2017-04-14 19:02:05 +02:00
if (j < 0 || j >= static_cast<int>(this->DynamicSectionEntries.size())) {
return 0;
2016-07-09 11:21:54 +02:00
}
2017-04-14 19:02:05 +02:00
ELF_Shdr const& sec = this->SectionHeaders[this->DynamicSectionIndex];
return static_cast<unsigned long>(sec.sh_offset + sec.sh_entsize * j);
}
template <class Types>
2017-04-14 19:02:05 +02:00
cmELF::DynamicEntryList cmELFInternalImpl<Types>::GetDynamicEntries()
{
2017-04-14 19:02:05 +02:00
cmELF::DynamicEntryList result;
// Ensure entries have been read from file
2016-07-09 11:21:54 +02:00
if (!this->LoadDynamicSection()) {
2017-04-14 19:02:05 +02:00
return result;
2016-07-09 11:21:54 +02:00
}
2017-04-14 19:02:05 +02:00
// Copy into public array
result.reserve(this->DynamicSectionEntries.size());
2018-01-26 17:06:56 +01:00
for (ELF_Dyn& dyn : this->DynamicSectionEntries) {
2018-04-23 21:13:27 +02:00
result.emplace_back(dyn.d_tag, dyn.d_un.d_val);
2016-07-09 11:21:54 +02:00
}
2017-04-14 19:02:05 +02:00
return result;
}
template <class Types>
std::vector<char> cmELFInternalImpl<Types>::EncodeDynamicEntries(
const cmELF::DynamicEntryList& entries)
{
std::vector<char> result;
result.reserve(sizeof(ELF_Dyn) * entries.size());
2018-01-26 17:06:56 +01:00
for (auto const& entry : entries) {
2017-04-14 19:02:05 +02:00
// Store the entry in an ELF_Dyn, byteswap it, then serialize to chars
ELF_Dyn dyn;
2018-01-26 17:06:56 +01:00
dyn.d_tag = static_cast<tagtype>(entry.first);
dyn.d_un.d_val = static_cast<tagtype>(entry.second);
2017-04-14 19:02:05 +02:00
if (this->NeedSwap) {
2021-09-14 00:13:48 +02:00
this->ByteSwap(dyn);
2017-04-14 19:02:05 +02:00
}
char* pdyn = reinterpret_cast<char*>(&dyn);
2020-08-30 11:54:41 +02:00
cm::append(result, pdyn, pdyn + sizeof(ELF_Dyn));
2017-04-14 19:02:05 +02:00
}
return result;
}
template <class Types>
2016-07-09 11:21:54 +02:00
cmELF::StringEntry const* cmELFInternalImpl<Types>::GetDynamicSectionString(
unsigned int tag)
{
// Short-circuit if already checked.
2020-02-01 23:06:01 +01:00
auto dssi = this->DynamicSectionStrings.find(tag);
2016-07-09 11:21:54 +02:00
if (dssi != this->DynamicSectionStrings.end()) {
if (dssi->second.Position > 0) {
return &dssi->second;
}
2018-01-26 17:06:56 +01:00
return nullptr;
2016-07-09 11:21:54 +02:00
}
// Create an entry for this tag. Assume it is missing until found.
StringEntry& se = this->DynamicSectionStrings[tag];
se.Position = 0;
se.Size = 0;
se.IndexInSection = -1;
// Try reading the dynamic section.
2016-07-09 11:21:54 +02:00
if (!this->LoadDynamicSection()) {
2018-01-26 17:06:56 +01:00
return nullptr;
2016-07-09 11:21:54 +02:00
}
// Get the string table referenced by the DYNAMIC section.
ELF_Shdr const& sec = this->SectionHeaders[this->DynamicSectionIndex];
2016-07-09 11:21:54 +02:00
if (sec.sh_link >= this->SectionHeaders.size()) {
this->SetErrorMessage("Section DYNAMIC has invalid string table index.");
2018-01-26 17:06:56 +01:00
return nullptr;
2016-07-09 11:21:54 +02:00
}
ELF_Shdr const& strtab = this->SectionHeaders[sec.sh_link];
// Look for the requested entry.
2020-02-01 23:06:01 +01:00
for (auto di = this->DynamicSectionEntries.begin();
2016-07-09 11:21:54 +02:00
di != this->DynamicSectionEntries.end(); ++di) {
ELF_Dyn& dyn = *di;
2016-07-09 11:21:54 +02:00
if (static_cast<tagtype>(dyn.d_tag) == static_cast<tagtype>(tag)) {
// We found the tag requested.
// Make sure the position given is within the string section.
2016-07-09 11:21:54 +02:00
if (dyn.d_un.d_val >= strtab.sh_size) {
this->SetErrorMessage("Section DYNAMIC references string beyond "
"the end of its string section.");
2018-01-26 17:06:56 +01:00
return nullptr;
2016-07-09 11:21:54 +02:00
}
// Seek to the position reported by the entry.
unsigned long first = static_cast<unsigned long>(dyn.d_un.d_val);
unsigned long last = first;
unsigned long end = static_cast<unsigned long>(strtab.sh_size);
2020-02-01 23:06:01 +01:00
this->Stream->seekg(strtab.sh_offset + first);
// Read the string. It may be followed by more than one NULL
// terminator. Count the total size of the region allocated to
// the string. This assumes that the next string in the table
// is non-empty, but the "chrpath" tool makes the same
// assumption.
bool terminated = false;
char c;
2020-02-01 23:06:01 +01:00
while (last != end && this->Stream->get(c) && !(terminated && c)) {
++last;
2016-07-09 11:21:54 +02:00
if (c) {
se.Value += c;
2016-07-09 11:21:54 +02:00
} else {
terminated = true;
}
2016-07-09 11:21:54 +02:00
}
// Make sure the whole value was read.
2020-02-01 23:06:01 +01:00
if (!(*this->Stream)) {
this->SetErrorMessage("Dynamic section specifies unreadable RPATH.");
se.Value = "";
2018-01-26 17:06:56 +01:00
return nullptr;
2016-07-09 11:21:54 +02:00
}
// The value has been read successfully. Report it.
se.Position = static_cast<unsigned long>(strtab.sh_offset + first);
se.Size = last - first;
2010-11-13 01:00:53 +02:00
se.IndexInSection =
static_cast<int>(di - this->DynamicSectionEntries.begin());
return &se;
}
2016-07-09 11:21:54 +02:00
}
2018-01-26 17:06:56 +01:00
return nullptr;
}
//============================================================================
// External class implementation.
2017-04-14 19:02:05 +02:00
const long cmELF::TagRPath = DT_RPATH;
const long cmELF::TagRunPath = DT_RUNPATH;
const long cmELF::TagMipsRldMapRel = DT_MIPS_RLD_MAP_REL;
2016-07-09 11:21:54 +02:00
cmELF::cmELF(const char* fname)
{
// Try to open the file.
2021-11-20 13:41:27 +01:00
auto fin = cm::make_unique<cmsys::ifstream>(fname, std::ios::binary);
// Quit now if the file could not be opened.
2019-11-11 23:01:05 +01:00
if (!fin || !*fin) {
this->ErrorMessage = "Error opening input file.";
return;
2016-07-09 11:21:54 +02:00
}
// Read the ELF identification block.
char ident[EI_NIDENT];
2016-07-09 11:21:54 +02:00
if (!fin->read(ident, EI_NIDENT)) {
this->ErrorMessage = "Error reading ELF identification.";
return;
2016-07-09 11:21:54 +02:00
}
if (!fin->seekg(0)) {
this->ErrorMessage = "Error seeking to beginning of file.";
return;
2016-07-09 11:21:54 +02:00
}
// Verify the ELF identification.
2016-07-09 11:21:54 +02:00
if (!(ident[EI_MAG0] == ELFMAG0 && ident[EI_MAG1] == ELFMAG1 &&
ident[EI_MAG2] == ELFMAG2 && ident[EI_MAG3] == ELFMAG3)) {
this->ErrorMessage = "File does not have a valid ELF identification.";
return;
2016-07-09 11:21:54 +02:00
}
// Check the byte order in which the rest of the file is encoded.
cmELFInternal::ByteOrderType order;
2016-07-09 11:21:54 +02:00
if (ident[EI_DATA] == ELFDATA2LSB) {
// File is LSB.
2016-07-09 11:21:54 +02:00
order = cmELFInternal::ByteOrderLSB;
} else if (ident[EI_DATA] == ELFDATA2MSB) {
// File is MSB.
2016-07-09 11:21:54 +02:00
order = cmELFInternal::ByteOrderMSB;
} else {
this->ErrorMessage = "ELF file is not LSB or MSB encoded.";
return;
2016-07-09 11:21:54 +02:00
}
// Check the class of the file and construct the corresponding
// parser implementation.
2016-07-09 11:21:54 +02:00
if (ident[EI_CLASS] == ELFCLASS32) {
// 32-bit ELF
2020-02-01 23:06:01 +01:00
this->Internal = cm::make_unique<cmELFInternalImpl<cmELFTypes32>>(
this, std::move(fin), order);
2021-11-20 13:41:27 +01:00
} else if (ident[EI_CLASS] == ELFCLASS64) {
// 64-bit ELF
2020-02-01 23:06:01 +01:00
this->Internal = cm::make_unique<cmELFInternalImpl<cmELFTypes64>>(
this, std::move(fin), order);
2021-11-20 13:41:27 +01:00
} else {
this->ErrorMessage = "ELF file class is not 32-bit or 64-bit.";
return;
2016-07-09 11:21:54 +02:00
}
}
2020-02-01 23:06:01 +01:00
cmELF::~cmELF() = default;
bool cmELF::Valid() const
{
return this->Internal && this->Internal->GetFileType() != FileTypeInvalid;
}
cmELF::FileType cmELF::GetFileType() const
{
2016-07-09 11:21:54 +02:00
if (this->Valid()) {
return this->Internal->GetFileType();
2016-07-09 11:21:54 +02:00
}
2016-10-30 18:24:19 +01:00
return FileTypeInvalid;
}
2021-09-14 00:13:48 +02:00
std::uint16_t cmELF::GetMachine() const
{
if (this->Valid()) {
return this->Internal->GetMachine();
}
return 0;
}
unsigned int cmELF::GetNumberOfSections() const
{
2016-07-09 11:21:54 +02:00
if (this->Valid()) {
return this->Internal->GetNumberOfSections();
2016-07-09 11:21:54 +02:00
}
2016-10-30 18:24:19 +01:00
return 0;
}
2017-04-14 19:02:05 +02:00
unsigned long cmELF::GetDynamicEntryPosition(int index) const
{
2016-07-09 11:21:54 +02:00
if (this->Valid()) {
2017-04-14 19:02:05 +02:00
return this->Internal->GetDynamicEntryPosition(index);
2016-07-09 11:21:54 +02:00
}
2016-10-30 18:24:19 +01:00
return 0;
}
2017-04-14 19:02:05 +02:00
cmELF::DynamicEntryList cmELF::GetDynamicEntries() const
{
2016-07-09 11:21:54 +02:00
if (this->Valid()) {
2017-04-14 19:02:05 +02:00
return this->Internal->GetDynamicEntries();
2016-07-09 11:21:54 +02:00
}
2017-04-14 19:02:05 +02:00
return cmELF::DynamicEntryList();
}
2017-04-14 19:02:05 +02:00
std::vector<char> cmELF::EncodeDynamicEntries(
const cmELF::DynamicEntryList& dentries) const
{
2016-07-09 11:21:54 +02:00
if (this->Valid()) {
2017-04-14 19:02:05 +02:00
return this->Internal->EncodeDynamicEntries(dentries);
2016-07-09 11:21:54 +02:00
}
2017-04-14 19:02:05 +02:00
return std::vector<char>();
}
bool cmELF::GetSOName(std::string& soname)
{
2016-07-09 11:21:54 +02:00
if (StringEntry const* se = this->GetSOName()) {
soname = se->Value;
return true;
2016-07-09 11:21:54 +02:00
}
2016-10-30 18:24:19 +01:00
return false;
}
cmELF::StringEntry const* cmELF::GetSOName()
{
2016-07-09 11:21:54 +02:00
if (this->Valid() &&
this->Internal->GetFileType() == cmELF::FileTypeSharedLibrary) {
return this->Internal->GetSOName();
2016-07-09 11:21:54 +02:00
}
2018-01-26 17:06:56 +01:00
return nullptr;
}
cmELF::StringEntry const* cmELF::GetRPath()
{
2016-07-09 11:21:54 +02:00
if (this->Valid() &&
(this->Internal->GetFileType() == cmELF::FileTypeExecutable ||
this->Internal->GetFileType() == cmELF::FileTypeSharedLibrary)) {
return this->Internal->GetRPath();
2016-07-09 11:21:54 +02:00
}
2018-01-26 17:06:56 +01:00
return nullptr;
}
cmELF::StringEntry const* cmELF::GetRunPath()
{
2016-07-09 11:21:54 +02:00
if (this->Valid() &&
(this->Internal->GetFileType() == cmELF::FileTypeExecutable ||
this->Internal->GetFileType() == cmELF::FileTypeSharedLibrary)) {
return this->Internal->GetRunPath();
2016-07-09 11:21:54 +02:00
}
2018-01-26 17:06:56 +01:00
return nullptr;
}
2021-11-20 13:41:27 +01:00
bool cmELF::IsMIPS() const
{
if (this->Valid()) {
return this->Internal->IsMips();
}
return false;
}
void cmELF::PrintInfo(std::ostream& os) const
{
2016-07-09 11:21:54 +02:00
if (this->Valid()) {
this->Internal->PrintInfo(os);
2016-07-09 11:21:54 +02:00
} else {
os << "Not a valid ELF file.\n";
2016-07-09 11:21:54 +02:00
}
}