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:
Krystian Chmielewski 2021-07-20 14:40:35 +00:00 committed by Compute-Runtime-Automation
parent c7d86af500
commit 1417e894c7
10 changed files with 390 additions and 5 deletions

View File

@ -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;

View File

@ -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
)

View File

@ -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 &section = 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 &sectionHeader = 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

View File

@ -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

View File

@ -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;
}

View File

@ -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);

View File

@ -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;

View File

@ -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
)

View File

@ -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);

View File

@ -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());
}