Create debug zebin
Creates copy of zebinary with program headers containing addresses of segments and applies debug relocations. Related-To: NEO-6071 Signed-off-by: Krystian Chmielewski <krystian.chmielewski@intel.com>
This commit is contained in:
parent
c7d86af500
commit
1417e894c7
|
@ -275,6 +275,7 @@ bool Linker::processRelocations(const SegmentInfo &globalVariables, const Segmen
|
|||
uint32_t addressSizeInBytes(LinkerInput::RelocationInfo::Type relocationtype) {
|
||||
return (relocationtype == LinkerInput::RelocationInfo::Type::Address) ? sizeof(uintptr_t) : sizeof(uint32_t);
|
||||
}
|
||||
|
||||
void Linker::patchAddress(void *relocAddress, const Linker::RelocatedSymbol &symbol, const Linker::RelocationInfo &relocation) {
|
||||
uint64_t gpuAddressAs64bit = static_cast<uint64_t>(symbol.gpuAddress);
|
||||
switch (relocation.type) {
|
||||
|
@ -429,7 +430,7 @@ void Linker::applyDebugDataRelocations(const NEO::Elf::Elf<NEO::Elf::EI_CLASS_64
|
|||
for (auto &reloc : decodedElf.getDebugInfoRelocations()) {
|
||||
auto targetSectionName = decodedElf.getSectionName(reloc.targetSectionIndex);
|
||||
auto sectionName = decodedElf.getSectionName(reloc.symbolSectionIndex);
|
||||
auto symbolAddress = decodedElf.getSymbolAddress(reloc.symbolTableIndex);
|
||||
auto symbolAddress = decodedElf.getSymbolValue(reloc.symbolTableIndex);
|
||||
|
||||
if (sectionName == Elf::SpecialSectionNames::text) {
|
||||
symbolAddress += text.gpuAddress;
|
||||
|
|
|
@ -32,6 +32,8 @@ set(NEO_DEVICE_BINARY_FORMAT
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/patchtokens_validator.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/zebin_decoder.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/zebin_decoder.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/debug_zebin.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/debug_zebin.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/yaml/yaml_parser.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/yaml/yaml_parser.h
|
||||
)
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "shared/source/device_binary_format/debug_zebin.h"
|
||||
|
||||
#include "shared/source/device_binary_format/elf/elf_decoder.h"
|
||||
#include "shared/source/device_binary_format/elf/elf_encoder.h"
|
||||
|
||||
namespace NEO {
|
||||
namespace Debug {
|
||||
using namespace Elf;
|
||||
|
||||
std::vector<uint8_t> createDebugZebin(NEO::Elf::Elf<EI_CLASS_64> &zebin, const GPUSegments &gpuSegments) {
|
||||
ElfEncoder<EI_CLASS_64> elfEncoder(false, false);
|
||||
auto &header = elfEncoder.getElfFileHeader();
|
||||
header.machine = zebin.elfFileHeader->machine;
|
||||
header.flags = zebin.elfFileHeader->flags;
|
||||
header.type = zebin.elfFileHeader->type;
|
||||
header.version = zebin.elfFileHeader->version;
|
||||
header.shStrNdx = zebin.elfFileHeader->shStrNdx;
|
||||
|
||||
for (uint32_t i = 0; i < zebin.sectionHeaders.size(); i++) {
|
||||
const auto §ion = zebin.sectionHeaders[i];
|
||||
auto sectionName = zebin.getSectionName(i);
|
||||
auto refSectionName = ConstStringRef(sectionName);
|
||||
|
||||
uint64_t segGpuAddr = 0U;
|
||||
ArrayRef<const uint8_t> data;
|
||||
|
||||
if (refSectionName.startsWith(SectionsNamesZebin::textPrefix.data())) {
|
||||
auto kernelName = sectionName.substr(SectionsNamesZebin::textPrefix.length());
|
||||
auto segmentIdIter = gpuSegments.nameToSectIdMap.find(kernelName);
|
||||
UNRECOVERABLE_IF(segmentIdIter == gpuSegments.nameToSectIdMap.end());
|
||||
const auto &kernel = gpuSegments.kernels[segmentIdIter->second];
|
||||
segGpuAddr = kernel.gpuAddress;
|
||||
data = kernel.data;
|
||||
} else if (refSectionName == SectionsNamesZebin::dataConst) {
|
||||
segGpuAddr = gpuSegments.constData.gpuAddress;
|
||||
data = gpuSegments.constData.data;
|
||||
} else if (refSectionName == SectionsNamesZebin::dataGlobal) {
|
||||
segGpuAddr = gpuSegments.varData.gpuAddress;
|
||||
data = gpuSegments.varData.data;
|
||||
} else {
|
||||
data = section.data;
|
||||
}
|
||||
|
||||
if (segGpuAddr != 0U) {
|
||||
elfEncoder.appendProgramHeaderLoad(i, segGpuAddr, data.size());
|
||||
}
|
||||
|
||||
auto §ionHeader = elfEncoder.appendSection(section.header->type, refSectionName, data);
|
||||
sectionHeader.link = section.header->link;
|
||||
sectionHeader.info = section.header->info;
|
||||
sectionHeader.name = section.header->name;
|
||||
}
|
||||
return elfEncoder.encode();
|
||||
}
|
||||
|
||||
void patch(uint64_t addr, uint64_t value, RELOC_TYPE_ZEBIN type) {
|
||||
switch (type) {
|
||||
default:
|
||||
UNRECOVERABLE_IF(type != R_ZE_SYM_ADDR)
|
||||
*reinterpret_cast<uint64_t *>(addr) = value;
|
||||
break;
|
||||
case R_ZE_SYM_ADDR_32:
|
||||
*reinterpret_cast<uint32_t *>(addr) = static_cast<uint32_t>(value & uint32_t(-1));
|
||||
break;
|
||||
case R_ZE_SYM_ADDR_32_HI:
|
||||
*reinterpret_cast<uint32_t *>(addr) = static_cast<uint32_t>((value >> 32) & uint32_t(-1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void patchDebugZebin(std::vector<uint8_t> &debugZebin, const GPUSegments &gpuSegments) {
|
||||
std::string errors, warnings;
|
||||
auto elf = decodeElf(debugZebin, errors, warnings);
|
||||
|
||||
for (const auto &reloc : elf.getDebugInfoRelocations()) {
|
||||
auto sectionName = elf.getSectionName(reloc.symbolSectionIndex);
|
||||
auto refSectionName = ConstStringRef(sectionName);
|
||||
uint64_t sectionAddress = 0U;
|
||||
if (refSectionName.startsWith(SectionsNamesZebin::textPrefix.data())) {
|
||||
auto kernelName = sectionName.substr(SectionsNamesZebin::textPrefix.length());
|
||||
auto segmentIdIter = gpuSegments.nameToSectIdMap.find(kernelName);
|
||||
UNRECOVERABLE_IF(segmentIdIter == gpuSegments.nameToSectIdMap.end());
|
||||
sectionAddress = gpuSegments.kernels[segmentIdIter->second].gpuAddress;
|
||||
} else if (refSectionName.startsWith(SectionsNamesZebin::dataConst.data())) {
|
||||
sectionAddress = gpuSegments.constData.gpuAddress;
|
||||
} else if (refSectionName.startsWith(SectionsNamesZebin::dataGlobal.data())) {
|
||||
sectionAddress = gpuSegments.varData.gpuAddress;
|
||||
} else if (refSectionName.startsWith(SectionsNamesZebin::debugPrefix.data())) {
|
||||
// do not offset debug symbols
|
||||
} else {
|
||||
DEBUG_BREAK_IF(true);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto patchValue = sectionAddress + elf.getSymbolValue(reloc.symbolTableIndex) + reloc.addend;
|
||||
auto patchLocation = reinterpret_cast<uint64_t>(debugZebin.data()) + elf.getSectionOffset(reloc.targetSectionIndex) + reloc.offset;
|
||||
|
||||
patch(patchLocation, patchValue, static_cast<RELOC_TYPE_ZEBIN>(reloc.relocType));
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint8_t> getDebugZebin(ArrayRef<const uint8_t> zebinBin, const GPUSegments &gpuSegments) {
|
||||
std::string errors, warnings;
|
||||
auto zebin = decodeElf(zebinBin, errors, warnings);
|
||||
if (false == errors.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto debugZebin = createDebugZebin(zebin, gpuSegments);
|
||||
patchDebugZebin(debugZebin, gpuSegments);
|
||||
return debugZebin;
|
||||
}
|
||||
|
||||
} // namespace Debug
|
||||
} // namespace NEO
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "shared/source/device_binary_format/elf/zebin_elf.h"
|
||||
#include "shared/source/utilities/arrayref.h"
|
||||
#include "shared/source/utilities/stackvec.h"
|
||||
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace NEO {
|
||||
namespace Debug {
|
||||
struct GPUSegments {
|
||||
struct Segment {
|
||||
uintptr_t gpuAddress = std::numeric_limits<uintptr_t>::max();
|
||||
ArrayRef<const uint8_t> data;
|
||||
};
|
||||
using KernelNameToSectionIdMap = std::unordered_map<std::string, size_t>;
|
||||
Segment varData;
|
||||
Segment constData;
|
||||
StackVec<Segment, 8> kernels;
|
||||
KernelNameToSectionIdMap nameToSectIdMap;
|
||||
};
|
||||
void patch(uint64_t addr, uint64_t value, NEO::Elf::RELOC_TYPE_ZEBIN type);
|
||||
void patchDebugZebin(std::vector<uint8_t> &debugZebin, const GPUSegments &segmentData);
|
||||
std::vector<uint8_t> createDebugZebin(ArrayRef<const uint8_t> zebin, const GPUSegments &segmentData);
|
||||
|
||||
std::vector<uint8_t> getDebugZebin(ArrayRef<const uint8_t> zebin, const GPUSegments &segmentData);
|
||||
} // namespace Debug
|
||||
} // namespace NEO
|
|
@ -73,10 +73,14 @@ struct Elf {
|
|||
return std::string(reinterpret_cast<const char *>(sectionHeaderNamesData.begin()) + nameOffset);
|
||||
}
|
||||
|
||||
decltype(ElfSymbolEntry<NumBits>::value) getSymbolAddress(uint32_t idx) const {
|
||||
decltype(ElfSymbolEntry<NumBits>::value) getSymbolValue(uint32_t idx) const {
|
||||
return symbolTable[idx].value;
|
||||
}
|
||||
|
||||
decltype(ElfSectionHeader<NumBits>::offset) getSectionOffset(uint32_t idx) const {
|
||||
return sectionHeaders[idx].header->offset;
|
||||
}
|
||||
|
||||
const Relocations &getRelocations() const {
|
||||
return relocations;
|
||||
}
|
||||
|
|
|
@ -99,6 +99,14 @@ ElfProgramHeader<NumBits> &ElfEncoder<NumBits>::appendSegment(PROGRAM_HEADER_TYP
|
|||
return *programHeaders.rbegin();
|
||||
}
|
||||
|
||||
template <ELF_IDENTIFIER_CLASS NumBits>
|
||||
void ElfEncoder<NumBits>::appendProgramHeaderLoad(size_t sectionId, uint64_t vAddr, uint64_t segSize) {
|
||||
programSectionLookupTable.push_back({programHeaders.size(), sectionId});
|
||||
auto &programHeader = appendSegment(PROGRAM_HEADER_TYPE::PT_LOAD, {});
|
||||
programHeader.vAddr = static_cast<decltype(programHeader.vAddr)>(vAddr);
|
||||
programHeader.memSz = static_cast<decltype(programHeader.memSz)>(segSize);
|
||||
}
|
||||
|
||||
template <ELF_IDENTIFIER_CLASS NumBits>
|
||||
uint32_t ElfEncoder<NumBits>::appendSectionName(ConstStringRef str) {
|
||||
if (str.empty() || (false == addHeaderSectionNamesSection)) {
|
||||
|
@ -159,6 +167,11 @@ std::vector<uint8_t> ElfEncoder<NumBits>::encode() const {
|
|||
ret.insert(ret.end(), reinterpret_cast<uint8_t *>(&elfFileHeader), reinterpret_cast<uint8_t *>(&elfFileHeader + 1));
|
||||
ret.resize(programHeadersOffset, 0U);
|
||||
|
||||
for (auto &progSecLookup : programSectionLookupTable) {
|
||||
programHeaders[progSecLookup.programId].offset = sectionHeaders[progSecLookup.sectionId].offset;
|
||||
programHeaders[progSecLookup.programId].fileSz = sectionHeaders[progSecLookup.sectionId].size;
|
||||
}
|
||||
|
||||
for (auto &programHeader : programHeaders) {
|
||||
if (0 != programHeader.fileSz) {
|
||||
programHeader.offset = static_cast<decltype(programHeader.offset)>(programHeader.offset + dataOffset);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Intel Corporation
|
||||
* Copyright (C) 2020-2021 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
|
@ -28,6 +28,7 @@ struct ElfEncoder {
|
|||
|
||||
ElfSectionHeader<NumBits> &appendSection(SECTION_HEADER_TYPE sectionType, ConstStringRef sectionLabel, const ArrayRef<const uint8_t> sectionData);
|
||||
ElfProgramHeader<NumBits> &appendSegment(PROGRAM_HEADER_TYPE segmentType, const ArrayRef<const uint8_t> segmentData);
|
||||
void appendProgramHeaderLoad(size_t sectionId, uint64_t vAddr, uint64_t segSize);
|
||||
|
||||
template <typename SectionHeaderEnumT>
|
||||
ElfSectionHeader<NumBits> &appendSection(SectionHeaderEnumT sectionType, ConstStringRef sectionLabel, const ArrayRef<const uint8_t> sectionData) {
|
||||
|
@ -58,6 +59,11 @@ struct ElfEncoder {
|
|||
StackVec<ElfSectionHeader<NumBits>, 32> sectionHeaders;
|
||||
std::vector<uint8_t> data;
|
||||
std::vector<char> stringTable;
|
||||
struct ProgramSectionID {
|
||||
size_t programId;
|
||||
size_t sectionId;
|
||||
};
|
||||
StackVec<ProgramSectionID, 32> programSectionLookupTable;
|
||||
struct {
|
||||
uint32_t shStrTab = 0;
|
||||
uint32_t undef = 0;
|
||||
|
|
|
@ -21,6 +21,7 @@ target_sources(${TARGET_NAME} PRIVATE
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/patchtokens_validator_tests.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/yaml/yaml_parser_tests.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/zebin_decoder_tests.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/zebin_debug_binary_tests.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/zebin_tests.h
|
||||
)
|
||||
|
||||
|
|
|
@ -668,8 +668,8 @@ TEST(ElfDecoder, WhenGettingSymbolAddressThenCorectValueIsReturned) {
|
|||
symbol.value = 0xfffff000;
|
||||
elf.symbolTable.push_back(symbol);
|
||||
|
||||
auto address0 = elf.getSymbolAddress(0);
|
||||
auto address1 = elf.getSymbolAddress(1);
|
||||
auto address0 = elf.getSymbolValue(0);
|
||||
auto address1 = elf.getSymbolValue(1);
|
||||
|
||||
EXPECT_EQ(0x1234000u, address0);
|
||||
EXPECT_EQ(0xfffff000u, address1);
|
||||
|
|
|
@ -0,0 +1,200 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "shared/source/device_binary_format/debug_zebin.h"
|
||||
#include "shared/source/device_binary_format/elf/elf_decoder.h"
|
||||
#include "shared/source/device_binary_format/elf/zebin_elf.h"
|
||||
#include "shared/test/common/mocks/mock_elf.h"
|
||||
#include "shared/test/unit_test/device_binary_format/zebin_tests.h"
|
||||
|
||||
#include "test.h"
|
||||
|
||||
TEST(DebugZebinTest, givenValidZebinThenDebugZebinIsGenerated) {
|
||||
MockElfEncoder<> elfEncoder;
|
||||
|
||||
NEO::Debug::GPUSegments segments;
|
||||
uint8_t constData[8] = {0x1};
|
||||
uint8_t varData[8] = {0x2};
|
||||
uint8_t kernelISA[8] = {0x3};
|
||||
|
||||
uint8_t debugInfo[0x20] = {0x0};
|
||||
uint8_t debugAbbrev[8] = {0x0};
|
||||
|
||||
elfEncoder.appendSection(NEO::Elf::SHT_PROGBITS, NEO::Elf::SectionsNamesZebin::textPrefix.str() + "kernel", ArrayRef<const uint8_t>(kernelISA, sizeof(kernelISA)));
|
||||
auto kernelSectionIndex = elfEncoder.getLastSectionHeaderIndex();
|
||||
elfEncoder.appendSection(NEO::Elf::SHT_PROGBITS, NEO::Elf::SectionsNamesZebin::dataConst, ArrayRef<const uint8_t>(constData, sizeof(constData)));
|
||||
auto constDataSectionIndex = elfEncoder.getLastSectionHeaderIndex();
|
||||
elfEncoder.appendSection(NEO::Elf::SHT_PROGBITS, NEO::Elf::SectionsNamesZebin::dataGlobal, ArrayRef<const uint8_t>(varData, sizeof(varData)));
|
||||
auto varDataSectionIndex = elfEncoder.getLastSectionHeaderIndex();
|
||||
elfEncoder.appendSection(NEO::Elf::SHT_PROGBITS, NEO::Elf::SectionsNamesZebin::debugInfo, ArrayRef<const uint8_t>(debugInfo, sizeof(debugInfo)));
|
||||
auto debugInfoSectionIndex = elfEncoder.getLastSectionHeaderIndex();
|
||||
elfEncoder.appendSection(NEO::Elf::SHT_PROGBITS, NEO::Elf::SectionsNamesZebin::debugAbbrev, ArrayRef<const uint8_t>(debugAbbrev, sizeof(debugAbbrev)));
|
||||
auto debugAbbrevSectionIndex = elfEncoder.getLastSectionHeaderIndex();
|
||||
elfEncoder.appendSection(NEO::Elf::SHT_ZEBIN_ZEINFO, NEO::Elf::SectionsNamesZebin::zeInfo, std::string{});
|
||||
auto zeInfoSectionIndex = elfEncoder.getLastSectionHeaderIndex();
|
||||
elfEncoder.appendSection(NEO::Elf::SHT_ZEBIN_SPIRV, NEO::Elf::SectionsNamesZebin::spv, std::string{});
|
||||
|
||||
typedef NEO::Elf::ElfSymbolEntry<NEO::Elf::ELF_IDENTIFIER_CLASS::EI_CLASS_64> SymbolEntry;
|
||||
typedef NEO::Elf::ElfRela<NEO::Elf::ELF_IDENTIFIER_CLASS::EI_CLASS_64> Relocation;
|
||||
|
||||
SymbolEntry symbols[5]{};
|
||||
symbols[0].name = elfEncoder.appendSectionName("kernel");
|
||||
symbols[0].info = NEO::Elf::SYMBOL_TABLE_TYPE::STT_SECTION | NEO::Elf::SYMBOL_TABLE_BIND::STB_LOCAL << 4;
|
||||
symbols[0].shndx = static_cast<decltype(SymbolEntry::shndx)>(kernelSectionIndex);
|
||||
symbols[0].value = 0U;
|
||||
|
||||
symbols[1].name = elfEncoder.appendSectionName("constData");
|
||||
symbols[1].info = NEO::Elf::SYMBOL_TABLE_TYPE::STT_SECTION | NEO::Elf::SYMBOL_TABLE_BIND::STB_LOCAL << 4;
|
||||
symbols[1].shndx = static_cast<decltype(SymbolEntry::shndx)>(constDataSectionIndex);
|
||||
symbols[1].value = 0U;
|
||||
|
||||
symbols[2].name = elfEncoder.appendSectionName("varData");
|
||||
symbols[2].info = NEO::Elf::SYMBOL_TABLE_TYPE::STT_SECTION | NEO::Elf::SYMBOL_TABLE_BIND::STB_LOCAL << 4;
|
||||
symbols[2].shndx = static_cast<decltype(SymbolEntry::shndx)>(varDataSectionIndex);
|
||||
symbols[2].value = 0U;
|
||||
|
||||
symbols[3].name = elfEncoder.appendSectionName("debugInfo");
|
||||
symbols[3].info = NEO::Elf::SYMBOL_TABLE_TYPE::STT_SECTION | NEO::Elf::SYMBOL_TABLE_BIND::STB_LOCAL << 4;
|
||||
symbols[3].shndx = static_cast<decltype(SymbolEntry::shndx)>(debugAbbrevSectionIndex);
|
||||
symbols[3].value = 0x1U;
|
||||
|
||||
symbols[4].name = elfEncoder.appendSectionName("zeInfo");
|
||||
symbols[4].info = NEO::Elf::SYMBOL_TABLE_TYPE::STT_SECTION | NEO::Elf::SYMBOL_TABLE_BIND::STB_LOCAL << 4;
|
||||
symbols[4].shndx = static_cast<decltype(SymbolEntry::shndx)>(zeInfoSectionIndex);
|
||||
symbols[4].value = 0U;
|
||||
|
||||
Relocation debugRelocations[5]{};
|
||||
debugRelocations[0].addend = 0xabc;
|
||||
debugRelocations[0].offset = 0x0;
|
||||
debugRelocations[0].info = (uint64_t(0) << 32) | NEO::Elf::RELOC_TYPE_ZEBIN::R_ZE_SYM_ADDR;
|
||||
|
||||
debugRelocations[1].addend = 0x0;
|
||||
debugRelocations[1].offset = 0x8U;
|
||||
debugRelocations[1].info = (uint64_t(1) << 32) | NEO::Elf::RELOC_TYPE_ZEBIN::R_ZE_SYM_ADDR_32;
|
||||
|
||||
debugRelocations[2].addend = 0x0;
|
||||
debugRelocations[2].offset = 0xCU;
|
||||
debugRelocations[2].info = (uint64_t(2) << 32) | NEO::Elf::RELOC_TYPE_ZEBIN::R_ZE_SYM_ADDR_32_HI;
|
||||
|
||||
debugRelocations[3].addend = -0xa;
|
||||
debugRelocations[3].offset = 0x10U;
|
||||
debugRelocations[3].info = (uint64_t(3) << 32) | NEO::Elf::RELOC_TYPE_ZEBIN::R_ZE_SYM_ADDR;
|
||||
|
||||
// Will be ignored
|
||||
debugRelocations[4].addend = 0x0;
|
||||
debugRelocations[4].offset = 0x18U;
|
||||
debugRelocations[4].info = (uint64_t(4) << 32) | NEO::Elf::RELOC_TYPE_ZEBIN::R_ZE_SYM_ADDR;
|
||||
|
||||
elfEncoder.appendSection(NEO::Elf::SHT_SYMTAB, NEO::Elf::SectionsNamesZebin::symtab, ArrayRef<const uint8_t>(reinterpret_cast<uint8_t *>(symbols), sizeof(symbols)));
|
||||
auto &relaHeader = elfEncoder.appendSection(NEO::Elf::SHT_RELA, NEO::Elf::SpecialSectionNames::relaPrefix.str() + NEO::Elf::SectionsNamesZebin::debugInfo.str(), ArrayRef<const uint8_t>(reinterpret_cast<uint8_t *>(debugRelocations), sizeof(debugRelocations)));
|
||||
relaHeader.info = debugInfoSectionIndex;
|
||||
|
||||
segments.constData = {reinterpret_cast<uintptr_t>(constData), {constData, sizeof(constData)}};
|
||||
segments.varData = {reinterpret_cast<uintptr_t>(varData), {varData, sizeof(varData)}};
|
||||
segments.kernels.push_back({reinterpret_cast<uintptr_t>(kernelISA), {kernelISA, sizeof(kernelISA)}});
|
||||
segments.nameToSectIdMap["kernel"] = 0;
|
||||
auto zebinBin = elfEncoder.encode();
|
||||
|
||||
std::string warning, error;
|
||||
auto zebin = NEO::Elf::decodeElf(zebinBin, error, warning);
|
||||
ASSERT_TRUE(error.empty());
|
||||
ASSERT_TRUE(warning.empty());
|
||||
|
||||
auto debugZebinBin = NEO::Debug::getDebugZebin(zebinBin, segments);
|
||||
auto debugZebin = NEO::Elf::decodeElf(debugZebinBin, error, warning);
|
||||
ASSERT_TRUE(error.empty());
|
||||
ASSERT_TRUE(warning.empty());
|
||||
|
||||
EXPECT_EQ(zebin.elfFileHeader->machine, debugZebin.elfFileHeader->machine);
|
||||
EXPECT_EQ(zebin.elfFileHeader->flags, debugZebin.elfFileHeader->flags);
|
||||
EXPECT_EQ(zebin.elfFileHeader->type, debugZebin.elfFileHeader->type);
|
||||
EXPECT_EQ(zebin.elfFileHeader->version, debugZebin.elfFileHeader->version);
|
||||
EXPECT_EQ(zebin.elfFileHeader->shStrNdx, debugZebin.elfFileHeader->shStrNdx);
|
||||
|
||||
EXPECT_EQ(zebin.sectionHeaders.size(), debugZebin.sectionHeaders.size());
|
||||
|
||||
uint64_t offsetKernel, offsetConstData, offsetVarData;
|
||||
offsetKernel = offsetConstData = offsetVarData = std::numeric_limits<uint64_t>::max();
|
||||
for (uint32_t i = 0; i < zebin.sectionHeaders.size(); ++i) {
|
||||
EXPECT_EQ(zebin.sectionHeaders[i].header->type, debugZebin.sectionHeaders[i].header->type);
|
||||
EXPECT_EQ(zebin.sectionHeaders[i].header->link, debugZebin.sectionHeaders[i].header->link);
|
||||
EXPECT_EQ(zebin.sectionHeaders[i].header->info, debugZebin.sectionHeaders[i].header->info);
|
||||
EXPECT_EQ(zebin.sectionHeaders[i].header->name, debugZebin.sectionHeaders[i].header->name);
|
||||
|
||||
auto sectionName = debugZebin.getSectionName(i);
|
||||
auto refSectionName = NEO::ConstStringRef(sectionName);
|
||||
if (refSectionName.startsWith(NEO::Elf::SectionsNamesZebin::textPrefix.data())) {
|
||||
auto kernelName = sectionName.substr(NEO::Elf::SectionsNamesZebin::textPrefix.length());
|
||||
auto segmentIdIter = segments.nameToSectIdMap.find(kernelName);
|
||||
ASSERT_TRUE(segmentIdIter != segments.nameToSectIdMap.end());
|
||||
const auto &kernel = segments.kernels[segmentIdIter->second];
|
||||
|
||||
EXPECT_EQ(kernel.data.size(), debugZebin.sectionHeaders[i].header->size);
|
||||
EXPECT_TRUE(memcmp(kernel.data.begin(), debugZebin.sectionHeaders[i].data.begin(), kernel.data.size()) == 0);
|
||||
offsetKernel = debugZebin.sectionHeaders[i].header->offset;
|
||||
} else if (refSectionName == NEO::Elf::SectionsNamesZebin::dataConst) {
|
||||
EXPECT_EQ(segments.constData.data.size(), debugZebin.sectionHeaders[i].header->size);
|
||||
EXPECT_TRUE(memcmp(segments.constData.data.begin(), debugZebin.sectionHeaders[i].data.begin(), segments.constData.data.size()) == 0);
|
||||
offsetConstData = debugZebin.sectionHeaders[i].header->offset;
|
||||
} else if (refSectionName == NEO::Elf::SectionsNamesZebin::dataGlobal) {
|
||||
EXPECT_EQ(segments.varData.data.size(), debugZebin.sectionHeaders[i].header->size);
|
||||
EXPECT_TRUE(memcmp(segments.varData.data.begin(), debugZebin.sectionHeaders[i].data.begin(), segments.varData.data.size()) == 0);
|
||||
offsetVarData = debugZebin.sectionHeaders[i].header->offset;
|
||||
} else if (refSectionName == NEO::Elf::SectionsNamesZebin::debugInfo) {
|
||||
EXPECT_EQ(zebin.sectionHeaders[i].header->size, debugZebin.sectionHeaders[i].header->size);
|
||||
|
||||
auto ptrDebugInfo = debugZebin.sectionHeaders[i].data.begin();
|
||||
EXPECT_EQ(*reinterpret_cast<const uint64_t *>(ptrDebugInfo + debugRelocations[0].offset),
|
||||
segments.kernels[0].gpuAddress + symbols[0].value + debugRelocations[0].addend);
|
||||
|
||||
EXPECT_EQ(*reinterpret_cast<const uint32_t *>(ptrDebugInfo + debugRelocations[1].offset),
|
||||
static_cast<uint32_t>((segments.constData.gpuAddress + symbols[1].value + debugRelocations[1].addend) & 0xffffffff));
|
||||
|
||||
EXPECT_EQ(*reinterpret_cast<const uint32_t *>(ptrDebugInfo + debugRelocations[2].offset),
|
||||
static_cast<uint32_t>(((segments.varData.gpuAddress + symbols[2].value + debugRelocations[2].addend) >> 32) & 0xffffffff));
|
||||
|
||||
// debug symbols are not offseted
|
||||
EXPECT_EQ(*reinterpret_cast<const uint64_t *>(ptrDebugInfo + debugRelocations[3].offset),
|
||||
symbols[3].value + debugRelocations[3].addend);
|
||||
|
||||
// if symbols points to other sections relocation is skipped
|
||||
EXPECT_EQ(*reinterpret_cast<const uint64_t *>(ptrDebugInfo + debugRelocations[4].offset), 0U);
|
||||
} else {
|
||||
EXPECT_EQ(zebin.sectionHeaders[i].header->size, debugZebin.sectionHeaders[i].header->size);
|
||||
if (debugZebin.sectionHeaders[i].header->size > 0U) {
|
||||
EXPECT_TRUE(memcmp(zebin.sectionHeaders[i].data.begin(), debugZebin.sectionHeaders[i].data.begin(), debugZebin.sectionHeaders[i].data.size()) == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_EQ(3U, debugZebin.programHeaders.size());
|
||||
EXPECT_EQ(segments.kernels[0].gpuAddress, static_cast<uintptr_t>(debugZebin.programHeaders[0].header->vAddr));
|
||||
EXPECT_EQ(segments.kernels[0].data.size(), static_cast<uintptr_t>(debugZebin.programHeaders[0].header->fileSz));
|
||||
EXPECT_EQ(segments.kernels[0].data.size(), static_cast<uintptr_t>(debugZebin.programHeaders[0].header->memSz));
|
||||
EXPECT_EQ(offsetKernel, static_cast<uintptr_t>(debugZebin.programHeaders[0].header->offset));
|
||||
|
||||
EXPECT_EQ(segments.constData.gpuAddress, static_cast<uintptr_t>(debugZebin.programHeaders[1].header->vAddr));
|
||||
EXPECT_EQ(segments.constData.data.size(), static_cast<uintptr_t>(debugZebin.programHeaders[1].header->fileSz));
|
||||
EXPECT_EQ(segments.constData.data.size(), static_cast<uintptr_t>(debugZebin.programHeaders[1].header->memSz));
|
||||
EXPECT_EQ(offsetConstData, static_cast<uintptr_t>(debugZebin.programHeaders[1].header->offset));
|
||||
|
||||
EXPECT_EQ(segments.varData.gpuAddress, static_cast<uintptr_t>(debugZebin.programHeaders[2].header->vAddr));
|
||||
EXPECT_EQ(segments.varData.data.size(), static_cast<uintptr_t>(debugZebin.programHeaders[2].header->fileSz));
|
||||
EXPECT_EQ(segments.varData.data.size(), static_cast<uintptr_t>(debugZebin.programHeaders[2].header->memSz));
|
||||
EXPECT_EQ(offsetVarData, static_cast<uintptr_t>(debugZebin.programHeaders[2].header->offset));
|
||||
}
|
||||
|
||||
TEST(DebugZebinTest, givenInvalidZebinThenDebugZebinIsNotGenerated) {
|
||||
uint8_t notZebin[] = {'N',
|
||||
'O',
|
||||
'T',
|
||||
'E',
|
||||
'L',
|
||||
'F'};
|
||||
auto debugZebin = NEO::Debug::getDebugZebin(ArrayRef<const uint8_t>(notZebin, sizeof(notZebin)), {});
|
||||
EXPECT_EQ(0U, debugZebin.size());
|
||||
}
|
Loading…
Reference in New Issue