diff --git a/shared/source/compiler_interface/linker.cpp b/shared/source/compiler_interface/linker.cpp index 5389506ff9..8f543c9aa5 100644 --- a/shared/source/compiler_interface/linker.cpp +++ b/shared/source/compiler_interface/linker.cpp @@ -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(symbol.gpuAddress); switch (relocation.type) { @@ -429,7 +430,7 @@ void Linker::applyDebugDataRelocations(const NEO::Elf::Elf createDebugZebin(NEO::Elf::Elf &zebin, const GPUSegments &gpuSegments) { + ElfEncoder 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 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(addr) = value; + break; + case R_ZE_SYM_ADDR_32: + *reinterpret_cast(addr) = static_cast(value & uint32_t(-1)); + break; + case R_ZE_SYM_ADDR_32_HI: + *reinterpret_cast(addr) = static_cast((value >> 32) & uint32_t(-1)); + break; + } +} + +void patchDebugZebin(std::vector &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(debugZebin.data()) + elf.getSectionOffset(reloc.targetSectionIndex) + reloc.offset; + + patch(patchLocation, patchValue, static_cast(reloc.relocType)); + } +} + +std::vector getDebugZebin(ArrayRef 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 diff --git a/shared/source/device_binary_format/debug_zebin.h b/shared/source/device_binary_format/debug_zebin.h new file mode 100644 index 0000000000..1cf3d182d5 --- /dev/null +++ b/shared/source/device_binary_format/debug_zebin.h @@ -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 +#include +#include +#include + +namespace NEO { +namespace Debug { +struct GPUSegments { + struct Segment { + uintptr_t gpuAddress = std::numeric_limits::max(); + ArrayRef data; + }; + using KernelNameToSectionIdMap = std::unordered_map; + Segment varData; + Segment constData; + StackVec kernels; + KernelNameToSectionIdMap nameToSectIdMap; +}; +void patch(uint64_t addr, uint64_t value, NEO::Elf::RELOC_TYPE_ZEBIN type); +void patchDebugZebin(std::vector &debugZebin, const GPUSegments &segmentData); +std::vector createDebugZebin(ArrayRef zebin, const GPUSegments &segmentData); + +std::vector getDebugZebin(ArrayRef zebin, const GPUSegments &segmentData); +} // namespace Debug +} // namespace NEO diff --git a/shared/source/device_binary_format/elf/elf_decoder.h b/shared/source/device_binary_format/elf/elf_decoder.h index 3e004154fd..cabb45c991 100644 --- a/shared/source/device_binary_format/elf/elf_decoder.h +++ b/shared/source/device_binary_format/elf/elf_decoder.h @@ -73,10 +73,14 @@ struct Elf { return std::string(reinterpret_cast(sectionHeaderNamesData.begin()) + nameOffset); } - decltype(ElfSymbolEntry::value) getSymbolAddress(uint32_t idx) const { + decltype(ElfSymbolEntry::value) getSymbolValue(uint32_t idx) const { return symbolTable[idx].value; } + decltype(ElfSectionHeader::offset) getSectionOffset(uint32_t idx) const { + return sectionHeaders[idx].header->offset; + } + const Relocations &getRelocations() const { return relocations; } diff --git a/shared/source/device_binary_format/elf/elf_encoder.cpp b/shared/source/device_binary_format/elf/elf_encoder.cpp index a3e55bfc91..041613a13c 100644 --- a/shared/source/device_binary_format/elf/elf_encoder.cpp +++ b/shared/source/device_binary_format/elf/elf_encoder.cpp @@ -99,6 +99,14 @@ ElfProgramHeader &ElfEncoder::appendSegment(PROGRAM_HEADER_TYP return *programHeaders.rbegin(); } +template +void ElfEncoder::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(vAddr); + programHeader.memSz = static_cast(segSize); +} + template uint32_t ElfEncoder::appendSectionName(ConstStringRef str) { if (str.empty() || (false == addHeaderSectionNamesSection)) { @@ -159,6 +167,11 @@ std::vector ElfEncoder::encode() const { ret.insert(ret.end(), reinterpret_cast(&elfFileHeader), reinterpret_cast(&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(programHeader.offset + dataOffset); diff --git a/shared/source/device_binary_format/elf/elf_encoder.h b/shared/source/device_binary_format/elf/elf_encoder.h index 0ee098d0fc..0e0e3c08c0 100644 --- a/shared/source/device_binary_format/elf/elf_encoder.h +++ b/shared/source/device_binary_format/elf/elf_encoder.h @@ -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 &appendSection(SECTION_HEADER_TYPE sectionType, ConstStringRef sectionLabel, const ArrayRef sectionData); ElfProgramHeader &appendSegment(PROGRAM_HEADER_TYPE segmentType, const ArrayRef segmentData); + void appendProgramHeaderLoad(size_t sectionId, uint64_t vAddr, uint64_t segSize); template ElfSectionHeader &appendSection(SectionHeaderEnumT sectionType, ConstStringRef sectionLabel, const ArrayRef sectionData) { @@ -58,6 +59,11 @@ struct ElfEncoder { StackVec, 32> sectionHeaders; std::vector data; std::vector stringTable; + struct ProgramSectionID { + size_t programId; + size_t sectionId; + }; + StackVec programSectionLookupTable; struct { uint32_t shStrTab = 0; uint32_t undef = 0; diff --git a/shared/test/unit_test/device_binary_format/CMakeLists.txt b/shared/test/unit_test/device_binary_format/CMakeLists.txt index 8c32f3ecd6..987947d50c 100644 --- a/shared/test/unit_test/device_binary_format/CMakeLists.txt +++ b/shared/test/unit_test/device_binary_format/CMakeLists.txt @@ -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 ) diff --git a/shared/test/unit_test/device_binary_format/elf/elf_decoder_tests.cpp b/shared/test/unit_test/device_binary_format/elf/elf_decoder_tests.cpp index 63e0e412c8..59b6d77e3e 100644 --- a/shared/test/unit_test/device_binary_format/elf/elf_decoder_tests.cpp +++ b/shared/test/unit_test/device_binary_format/elf/elf_decoder_tests.cpp @@ -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); diff --git a/shared/test/unit_test/device_binary_format/zebin_debug_binary_tests.cpp b/shared/test/unit_test/device_binary_format/zebin_debug_binary_tests.cpp new file mode 100644 index 0000000000..8a5b30f582 --- /dev/null +++ b/shared/test/unit_test/device_binary_format/zebin_debug_binary_tests.cpp @@ -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(kernelISA, sizeof(kernelISA))); + auto kernelSectionIndex = elfEncoder.getLastSectionHeaderIndex(); + elfEncoder.appendSection(NEO::Elf::SHT_PROGBITS, NEO::Elf::SectionsNamesZebin::dataConst, ArrayRef(constData, sizeof(constData))); + auto constDataSectionIndex = elfEncoder.getLastSectionHeaderIndex(); + elfEncoder.appendSection(NEO::Elf::SHT_PROGBITS, NEO::Elf::SectionsNamesZebin::dataGlobal, ArrayRef(varData, sizeof(varData))); + auto varDataSectionIndex = elfEncoder.getLastSectionHeaderIndex(); + elfEncoder.appendSection(NEO::Elf::SHT_PROGBITS, NEO::Elf::SectionsNamesZebin::debugInfo, ArrayRef(debugInfo, sizeof(debugInfo))); + auto debugInfoSectionIndex = elfEncoder.getLastSectionHeaderIndex(); + elfEncoder.appendSection(NEO::Elf::SHT_PROGBITS, NEO::Elf::SectionsNamesZebin::debugAbbrev, ArrayRef(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 SymbolEntry; + typedef NEO::Elf::ElfRela 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(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(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(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(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(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(reinterpret_cast(symbols), sizeof(symbols))); + auto &relaHeader = elfEncoder.appendSection(NEO::Elf::SHT_RELA, NEO::Elf::SpecialSectionNames::relaPrefix.str() + NEO::Elf::SectionsNamesZebin::debugInfo.str(), ArrayRef(reinterpret_cast(debugRelocations), sizeof(debugRelocations))); + relaHeader.info = debugInfoSectionIndex; + + segments.constData = {reinterpret_cast(constData), {constData, sizeof(constData)}}; + segments.varData = {reinterpret_cast(varData), {varData, sizeof(varData)}}; + segments.kernels.push_back({reinterpret_cast(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::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(ptrDebugInfo + debugRelocations[0].offset), + segments.kernels[0].gpuAddress + symbols[0].value + debugRelocations[0].addend); + + EXPECT_EQ(*reinterpret_cast(ptrDebugInfo + debugRelocations[1].offset), + static_cast((segments.constData.gpuAddress + symbols[1].value + debugRelocations[1].addend) & 0xffffffff)); + + EXPECT_EQ(*reinterpret_cast(ptrDebugInfo + debugRelocations[2].offset), + static_cast(((segments.varData.gpuAddress + symbols[2].value + debugRelocations[2].addend) >> 32) & 0xffffffff)); + + // debug symbols are not offseted + EXPECT_EQ(*reinterpret_cast(ptrDebugInfo + debugRelocations[3].offset), + symbols[3].value + debugRelocations[3].addend); + + // if symbols points to other sections relocation is skipped + EXPECT_EQ(*reinterpret_cast(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(debugZebin.programHeaders[0].header->vAddr)); + EXPECT_EQ(segments.kernels[0].data.size(), static_cast(debugZebin.programHeaders[0].header->fileSz)); + EXPECT_EQ(segments.kernels[0].data.size(), static_cast(debugZebin.programHeaders[0].header->memSz)); + EXPECT_EQ(offsetKernel, static_cast(debugZebin.programHeaders[0].header->offset)); + + EXPECT_EQ(segments.constData.gpuAddress, static_cast(debugZebin.programHeaders[1].header->vAddr)); + EXPECT_EQ(segments.constData.data.size(), static_cast(debugZebin.programHeaders[1].header->fileSz)); + EXPECT_EQ(segments.constData.data.size(), static_cast(debugZebin.programHeaders[1].header->memSz)); + EXPECT_EQ(offsetConstData, static_cast(debugZebin.programHeaders[1].header->offset)); + + EXPECT_EQ(segments.varData.gpuAddress, static_cast(debugZebin.programHeaders[2].header->vAddr)); + EXPECT_EQ(segments.varData.data.size(), static_cast(debugZebin.programHeaders[2].header->fileSz)); + EXPECT_EQ(segments.varData.data.size(), static_cast(debugZebin.programHeaders[2].header->memSz)); + EXPECT_EQ(offsetVarData, static_cast(debugZebin.programHeaders[2].header->offset)); +} + +TEST(DebugZebinTest, givenInvalidZebinThenDebugZebinIsNotGenerated) { + uint8_t notZebin[] = {'N', + 'O', + 'T', + 'E', + 'L', + 'F'}; + auto debugZebin = NEO::Debug::getDebugZebin(ArrayRef(notZebin, sizeof(notZebin)), {}); + EXPECT_EQ(0U, debugZebin.size()); +}