/* * Copyright (C) 2021-2023 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" #include "shared/source/device_binary_format/elf/zebin_elf.h" #include "shared/source/helpers/aligned_memory.h" #include "shared/source/memory_manager/graphics_allocation.h" namespace NEO { namespace Debug { using namespace Elf; Segments::Segments() {} Segments::Segments(const GraphicsAllocation *globalVarAlloc, const GraphicsAllocation *globalConstAlloc, ArrayRef &globalStrings, std::vector &kernels) { if (globalVarAlloc) { varData = {static_cast(globalVarAlloc->getGpuAddress()), globalVarAlloc->getUnderlyingBufferSize()}; } if (globalConstAlloc) { constData = {static_cast(globalConstAlloc->getGpuAddress()), globalConstAlloc->getUnderlyingBufferSize()}; } if (false == globalStrings.empty()) { stringData = {reinterpret_cast(globalStrings.begin()), globalStrings.size()}; } for (auto &[kernelName, isa] : kernels) { Debug::Segments::Segment kernelSegment = {static_cast(isa->getGpuAddress()), isa->getUnderlyingBufferSize()}; nameToSegMap.insert(std::pair(kernelName, kernelSegment)); } } std::vector createDebugZebin(ArrayRef zebinBin, const Segments &gpuSegments) { std::string errors, warnings; auto zebin = decodeElf(zebinBin, errors, warnings); if (false == errors.empty()) { return {}; } auto dzc = DebugZebinCreator(zebin, gpuSegments); dzc.createDebugZebin(); dzc.applyRelocations(); return dzc.getDebugZebin(); } void DebugZebinCreator::createDebugZebin() { ElfEncoder elfEncoder(false, false, 8); auto &header = elfEncoder.getElfFileHeader(); header.machine = zebin.elfFileHeader->machine; header.flags = zebin.elfFileHeader->flags; header.type = NEO::Elf::ET_EXEC; 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); ArrayRef sectionData = section.data; if (section.header->type == SHT_SYMTAB) { symTabShndx = i; } auto §ionHeader = elfEncoder.appendSection(section.header->type, sectionName, sectionData); sectionHeader.link = section.header->link; sectionHeader.info = section.header->info; sectionHeader.name = section.header->name; sectionHeader.flags = section.header->flags; if (auto segment = getSegmentByName(sectionName)) { if (!isCpuSegment(sectionName)) { elfEncoder.appendProgramHeaderLoad(i, segment->address, segment->size); } sectionHeader.addr = segment->address; } } debugZebin = elfEncoder.encode(); } #pragma pack(push, 1) template struct SafeType { T value; }; #pragma pack(pop) template void patchWithValue(uintptr_t addr, uint32_t value); template void patchWithValue(uintptr_t addr, uint64_t value); template void patchWithValue(uintptr_t addr, T value) { if (isAligned(addr)) { *reinterpret_cast(addr) = value; } else { reinterpret_cast *>(addr)->value = value; } } void DebugZebinCreator::applyRelocation(uintptr_t addr, uint64_t value, RELOC_TYPE_ZEBIN type) { switch (type) { default: UNRECOVERABLE_IF(type != R_ZE_SYM_ADDR) return patchWithValue(addr, value); case R_ZE_SYM_ADDR_32: return patchWithValue(addr, static_cast(value & uint32_t(-1))); case R_ZE_SYM_ADDR_32_HI: return patchWithValue(addr, static_cast((value >> 32) & uint32_t(-1))); } } void DebugZebinCreator::applyRelocations() { if (symTabShndx == std::numeric_limits::max()) { return; } using ElfSymbolT = ElfSymbolEntry; std::string errors, warnings; auto elf = decodeElf(debugZebin, errors, warnings); auto symTabSecHdr = elf.sectionHeaders[symTabShndx].header; size_t symbolsCount = static_cast(symTabSecHdr->size) / static_cast(symTabSecHdr->entsize); ArrayRef symbols = {reinterpret_cast(debugZebin.data() + symTabSecHdr->offset), symbolsCount}; for (auto &symbol : symbols) { auto symbolSectionName = elf.getSectionName(symbol.shndx); auto symbolName = elf.getSymbolName(symbol.name); auto segment = getSegmentByName(symbolSectionName); if (segment != nullptr) { symbol.value += segment->address; } else if (ConstStringRef(symbolSectionName).startsWith(SectionsNamesZebin::debugPrefix.data()) && ConstStringRef(symbolName).startsWith(SectionsNamesZebin::textPrefix.data())) { symbol.value += getTextSegmentByName(symbolName)->address; } } for (const auto *relocations : {&elf.getDebugInfoRelocations(), &elf.getRelocations()}) { for (const auto &reloc : *relocations) { auto relocType = static_cast(reloc.relocType); if (isRelocTypeSupported(relocType) == false) { continue; } auto relocAddr = reinterpret_cast(debugZebin.data() + elf.getSectionOffset(reloc.targetSectionIndex) + reloc.offset); uint64_t relocVal = symbols[reloc.symbolTableIndex].value + reloc.addend; applyRelocation(relocAddr, relocVal, relocType); } } } bool DebugZebinCreator::isRelocTypeSupported(NEO::Elf::RELOC_TYPE_ZEBIN type) { return type == NEO::Elf::RELOC_TYPE_ZEBIN::R_ZE_SYM_ADDR || type == NEO::Elf::RELOC_TYPE_ZEBIN::R_ZE_SYM_ADDR_32 || type == NEO::Elf::RELOC_TYPE_ZEBIN::R_ZE_SYM_ADDR_32_HI; } const Segments::Segment *DebugZebinCreator::getSegmentByName(ConstStringRef sectionName) { if (sectionName.startsWith(SectionsNamesZebin::textPrefix.data())) { return getTextSegmentByName(sectionName); } else if (sectionName == SectionsNamesZebin::dataConst) { return &segments.constData; } else if (sectionName == SectionsNamesZebin::dataGlobal) { return &segments.varData; } else if (sectionName == SectionsNamesZebin::dataConstString) { return &segments.stringData; } return nullptr; } const Segments::Segment *DebugZebinCreator::getTextSegmentByName(ConstStringRef sectionName) { auto kernelName = sectionName.substr(SectionsNamesZebin::textPrefix.length()); auto kernelSegmentIt = segments.nameToSegMap.find(kernelName.str()); UNRECOVERABLE_IF(kernelSegmentIt == segments.nameToSegMap.end()); return &kernelSegmentIt->second; } bool DebugZebinCreator::isCpuSegment(ConstStringRef sectionName) { return (sectionName == SectionsNamesZebin::dataConstString); } } // namespace Debug } // namespace NEO