/* * Copyright (C) 2020-2021 Intel Corporation * * SPDX-License-Identifier: MIT * */ #include "shared/source/device_binary_format/elf/elf_decoder.h" #include "shared/source/device_binary_format/elf/elf.h" #include "shared/source/helpers/ptr_math.h" #include namespace NEO { namespace Elf { template const ElfFileHeader *decodeElfFileHeader(const ArrayRef binary) { if (binary.size() < sizeof(ElfFileHeader)) { return nullptr; } const ElfFileHeader *header = reinterpret_cast *>(binary.begin()); bool validHeader = (header->identity.magic[0] == elfMagic[0]); validHeader &= (header->identity.magic[1] == elfMagic[1]); validHeader &= (header->identity.magic[2] == elfMagic[2]); validHeader &= (header->identity.magic[3] == elfMagic[3]); validHeader &= (header->identity.eClass == NumBits); return validHeader ? header : nullptr; } template const ElfFileHeader *decodeElfFileHeader(const ArrayRef); template const ElfFileHeader *decodeElfFileHeader(const ArrayRef); template Elf decodeElf(const ArrayRef binary, std::string &outErrReason, std::string &outWarning) { Elf ret = {}; ret.elfFileHeader = decodeElfFileHeader(binary); if (nullptr == ret.elfFileHeader) { outErrReason = "Invalid or missing ELF header"; return {}; } if (ret.elfFileHeader->phOff + ret.elfFileHeader->phNum * ret.elfFileHeader->phEntSize > binary.size()) { outErrReason = "Out of bounds program headers table"; return {}; } if (ret.elfFileHeader->shOff + ret.elfFileHeader->shNum * ret.elfFileHeader->shEntSize > binary.size()) { outErrReason = "Out of bounds section headers table"; return {}; } const ElfProgramHeader *programHeader = reinterpret_cast *>(binary.begin() + ret.elfFileHeader->phOff); for (decltype(ret.elfFileHeader->phNum) i = 0; i < ret.elfFileHeader->phNum; ++i) { if (programHeader->offset + programHeader->fileSz > binary.size()) { outErrReason = "Out of bounds program header offset/filesz, program header idx : " + std::to_string(i); return {}; } ArrayRef data(binary.begin() + programHeader->offset, static_cast(programHeader->fileSz)); ret.programHeaders.push_back({programHeader, data}); programHeader = ptrOffset(programHeader, ret.elfFileHeader->phEntSize); } const ElfSectionHeader *sectionHeader = reinterpret_cast *>(binary.begin() + ret.elfFileHeader->shOff); for (decltype(ret.elfFileHeader->shNum) i = 0; i < ret.elfFileHeader->shNum; ++i) { ArrayRef data; if (SHT_NOBITS != sectionHeader->type) { if (sectionHeader->offset + sectionHeader->size > binary.size()) { outErrReason = "Out of bounds section header offset/size, section header idx : " + std::to_string(i); return {}; } data = ArrayRef(binary.begin() + sectionHeader->offset, static_cast(sectionHeader->size)); } ret.sectionHeaders.push_back({sectionHeader, data}); sectionHeader = ptrOffset(sectionHeader, ret.elfFileHeader->shEntSize); } if (!ret.decodeSections(outErrReason)) { return {}; } return ret; } template bool Elf::decodeSymTab(SectionHeaderAndData §ionHeaderData, std::string &outError) { if (sectionHeaderData.header->type == SECTION_HEADER_TYPE::SHT_SYMTAB) { auto symSize = sizeof(ElfSymbolEntry); if (symSize != sectionHeaderData.header->entsize) { outError.append("Invalid symbol table entries size - expected : " + std::to_string(symSize) + ", got : " + std::to_string(sectionHeaderData.header->entsize) + "\n"); return false; } auto numberOfSymbols = static_cast(sectionHeaderData.header->size / sectionHeaderData.header->entsize); auto symbol = reinterpret_cast *>(sectionHeaderData.data.begin()); symbolTable.resize(numberOfSymbols); for (size_t i = 0; i < numberOfSymbols; i++) { symbolTable[i] = *symbol; symbol++; } } return true; } template bool Elf::decodeRelocations(SectionHeaderAndData §ionHeaderData, std::string &outError) { if (sectionHeaderData.header->type == SECTION_HEADER_TYPE::SHT_RELA) { auto relaSize = sizeof(ElfRela); if (relaSize != sectionHeaderData.header->entsize) { outError.append("Invalid rela entries size - expected : " + std::to_string(relaSize) + ", got : " + std::to_string(sectionHeaderData.header->entsize) + "\n"); return false; } size_t numberOfEntries = static_cast(sectionHeaderData.header->size / sectionHeaderData.header->entsize); auto sectionHeaderNamesData = sectionHeaders[elfFileHeader->shStrNdx].data; int targetSectionIndex = sectionHeaderData.header->info; auto sectionName = getSectionName(targetSectionIndex); auto debugDataRelocation = isDebugDataRelocation(ConstStringRef(sectionName.c_str())); Relocations &relocs = debugDataRelocation ? debugInfoRelocations : relocations; auto rela = reinterpret_cast *>(sectionHeaderData.data.begin()); // there may be multiple rela sections, reserve additional size auto previousEntries = relocations.size(); auto allEntries = previousEntries + numberOfEntries; relocs.reserve(allEntries); for (auto i = previousEntries; i < allEntries; i++) { int symbolIndex = extractSymbolIndex>(*rela); auto relocType = extractRelocType>(*rela); int symbolSectionIndex = symbolTable[symbolIndex].shndx; std::string name = std::string(reinterpret_cast(sectionHeaderNamesData.begin()) + symbolTable[symbolIndex].name); RelocationInfo relocInfo = {symbolSectionIndex, symbolIndex, targetSectionIndex, rela->addend, rela->offset, relocType, name}; relocs.push_back(relocInfo); rela++; } } if (sectionHeaderData.header->type == SECTION_HEADER_TYPE::SHT_REL) { auto relSize = sizeof(ElfRel); if (relSize != sectionHeaderData.header->entsize) { outError.append("Invalid rel entries size - expected : " + std::to_string(relSize) + ", got : " + std::to_string(sectionHeaderData.header->entsize) + "\n"); return false; } auto numberOfEntries = static_cast(sectionHeaderData.header->size / sectionHeaderData.header->entsize); auto sectionHeaderNamesData = sectionHeaders[elfFileHeader->shStrNdx].data; int targetSectionIndex = sectionHeaderData.header->info; auto sectionName = getSectionName(targetSectionIndex); auto debugDataRelocation = isDebugDataRelocation(ConstStringRef(sectionName.c_str())); Relocations &relocs = debugDataRelocation ? debugInfoRelocations : relocations; auto reloc = reinterpret_cast *>(sectionHeaderData.data.begin()); // there may be multiple rel sections, reserve additional size auto previousEntries = relocations.size(); auto allEntries = previousEntries + numberOfEntries; relocs.reserve(allEntries); for (auto i = previousEntries; i < allEntries; i++) { int symbolIndex = extractSymbolIndex>(*reloc); auto relocType = extractRelocType>(*reloc); int symbolSectionIndex = symbolTable[symbolIndex].shndx; std::string name = std::string(reinterpret_cast(sectionHeaderNamesData.begin()) + symbolTable[symbolIndex].name); RelocationInfo relocInfo = {symbolSectionIndex, symbolIndex, targetSectionIndex, 0, reloc->offset, relocType, name}; relocs.push_back(relocInfo); reloc++; } } return true; } template bool Elf::decodeSections(std::string &outError) { bool success = true; for (size_t i = 0; i < sectionHeaders.size(); i++) { success &= decodeSymTab(sectionHeaders[i], outError); } if (success) { for (size_t i = 0; i < sectionHeaders.size(); i++) { success &= decodeRelocations(sectionHeaders[i], outError); } } return success; } template bool Elf::isDebugDataRelocation(ConstStringRef sectionName) { if (sectionName.startsWith(NEO::Elf::SpecialSectionNames::debug.data())) { return true; } return false; } template <> template int Elf::extractSymbolIndex(const ElfReloc &elfReloc) const { return static_cast(elfReloc.info >> 8); } template <> template int Elf::extractSymbolIndex(const ElfReloc &elfReloc) const { return static_cast(elfReloc.info >> 32); } template <> template uint32_t Elf::extractRelocType(const ElfReloc &elfReloc) const { return elfReloc.info & 0xff; } template <> template uint32_t Elf::extractRelocType(const ElfReloc &elfReloc) const { return elfReloc.info & 0xffffffff; } template bool Elf::decodeSections(std::string &outError); template int Elf::extractSymbolIndex(const ElfRel &elfReloc) const; template int Elf::extractSymbolIndex(const ElfRel &elfReloc) const; template int Elf::extractSymbolIndex(const ElfRela &elfReloc) const; template int Elf::extractSymbolIndex(const ElfRela &elfReloc) const; template uint32_t Elf::extractRelocType(const ElfRel &elfReloc) const; template uint32_t Elf::extractRelocType(const ElfRel &elfReloc) const; template uint32_t Elf::extractRelocType(const ElfRela &elfReloc) const; template uint32_t Elf::extractRelocType(const ElfRela &elfReloc) const; template Elf decodeElf(const ArrayRef, std::string &, std::string &); template Elf decodeElf(const ArrayRef, std::string &, std::string &); } // namespace Elf } // namespace NEO