1 /*
2  * Copyright (C) 2021 Intel Corporation
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  */
7 
8 #include "shared/source/device_binary_format/debug_zebin.h"
9 #include "shared/source/device_binary_format/elf/elf_decoder.h"
10 #include "shared/source/device_binary_format/elf/zebin_elf.h"
11 #include "shared/test/common/mocks/mock_elf.h"
12 #include "shared/test/common/test_macros/test.h"
13 #include "shared/test/unit_test/device_binary_format/zebin_tests.h"
14 
TEST(DebugZebinTest,givenValidZebinThenDebugZebinIsGenerated)15 TEST(DebugZebinTest, givenValidZebinThenDebugZebinIsGenerated) {
16     MockElfEncoder<> elfEncoder;
17 
18     NEO::Debug::Segments segments;
19     uint8_t constData[8] = {0x1};
20     uint8_t varData[8] = {0x2};
21     uint8_t kernelISA[8] = {0x3};
22     uint8_t stringData[8] = {0x4};
23 
24     uint8_t debugInfo[0x20] = {0x0};
25     uint8_t debugAbbrev[8] = {0x0};
26 
27     elfEncoder.appendSection(NEO::Elf::SHT_PROGBITS, NEO::Elf::SectionsNamesZebin::textPrefix.str() + "kernel", ArrayRef<const uint8_t>(kernelISA, sizeof(kernelISA)));
28     auto kernelSectionIndex = elfEncoder.getLastSectionHeaderIndex();
29     elfEncoder.appendSection(NEO::Elf::SHT_PROGBITS, NEO::Elf::SectionsNamesZebin::dataConst, ArrayRef<const uint8_t>(constData, sizeof(constData)));
30     auto constDataSectionIndex = elfEncoder.getLastSectionHeaderIndex();
31     elfEncoder.appendSection(NEO::Elf::SHT_PROGBITS, NEO::Elf::SectionsNamesZebin::dataGlobal, ArrayRef<const uint8_t>(varData, sizeof(varData)));
32     auto varDataSectionIndex = elfEncoder.getLastSectionHeaderIndex();
33     elfEncoder.appendSection(NEO::Elf::SHT_PROGBITS, NEO::Elf::SectionsNamesZebin::dataConstString, ArrayRef<const uint8_t>(stringData, sizeof(stringData)));
34     elfEncoder.appendSection(NEO::Elf::SHT_PROGBITS, NEO::Elf::SectionsNamesZebin::debugInfo, ArrayRef<const uint8_t>(debugInfo, sizeof(debugInfo)));
35     auto debugInfoSectionIndex = elfEncoder.getLastSectionHeaderIndex();
36     elfEncoder.appendSection(NEO::Elf::SHT_PROGBITS, NEO::Elf::SectionsNamesZebin::debugAbbrev, ArrayRef<const uint8_t>(debugAbbrev, sizeof(debugAbbrev)));
37     auto debugAbbrevSectionIndex = elfEncoder.getLastSectionHeaderIndex();
38     elfEncoder.appendSection(NEO::Elf::SHT_ZEBIN_ZEINFO, NEO::Elf::SectionsNamesZebin::zeInfo, std::string{});
39     auto zeInfoSectionIndex = elfEncoder.getLastSectionHeaderIndex();
40     elfEncoder.appendSection(NEO::Elf::SHT_ZEBIN_SPIRV, NEO::Elf::SectionsNamesZebin::spv, std::string{});
41 
42     typedef NEO::Elf::ElfSymbolEntry<NEO::Elf::ELF_IDENTIFIER_CLASS::EI_CLASS_64> SymbolEntry;
43     typedef NEO::Elf::ElfRela<NEO::Elf::ELF_IDENTIFIER_CLASS::EI_CLASS_64> Relocation;
44 
45     SymbolEntry symbols[5]{};
46     symbols[0].name = elfEncoder.appendSectionName("kernel");
47     symbols[0].info = NEO::Elf::SYMBOL_TABLE_TYPE::STT_SECTION | NEO::Elf::SYMBOL_TABLE_BIND::STB_LOCAL << 4;
48     symbols[0].shndx = static_cast<decltype(SymbolEntry::shndx)>(kernelSectionIndex);
49     symbols[0].value = 0U;
50 
51     symbols[1].name = elfEncoder.appendSectionName("constData");
52     symbols[1].info = NEO::Elf::SYMBOL_TABLE_TYPE::STT_SECTION | NEO::Elf::SYMBOL_TABLE_BIND::STB_LOCAL << 4;
53     symbols[1].shndx = static_cast<decltype(SymbolEntry::shndx)>(constDataSectionIndex);
54     symbols[1].value = 0U;
55 
56     symbols[2].name = elfEncoder.appendSectionName("varData");
57     symbols[2].info = NEO::Elf::SYMBOL_TABLE_TYPE::STT_SECTION | NEO::Elf::SYMBOL_TABLE_BIND::STB_LOCAL << 4;
58     symbols[2].shndx = static_cast<decltype(SymbolEntry::shndx)>(varDataSectionIndex);
59     symbols[2].value = 0U;
60 
61     symbols[3].name = elfEncoder.appendSectionName("debugInfo");
62     symbols[3].info = NEO::Elf::SYMBOL_TABLE_TYPE::STT_SECTION | NEO::Elf::SYMBOL_TABLE_BIND::STB_LOCAL << 4;
63     symbols[3].shndx = static_cast<decltype(SymbolEntry::shndx)>(debugAbbrevSectionIndex);
64     symbols[3].value = 0x1U;
65 
66     symbols[4].name = elfEncoder.appendSectionName("zeInfo");
67     symbols[4].info = NEO::Elf::SYMBOL_TABLE_TYPE::STT_SECTION | NEO::Elf::SYMBOL_TABLE_BIND::STB_LOCAL << 4;
68     symbols[4].shndx = static_cast<decltype(SymbolEntry::shndx)>(zeInfoSectionIndex);
69     symbols[4].value = 0U;
70 
71     Relocation debugRelocations[5]{};
72     debugRelocations[0].addend = 0xabc;
73     debugRelocations[0].offset = 0x0;
74     debugRelocations[0].info = (uint64_t(0) << 32) | NEO::Elf::RELOC_TYPE_ZEBIN::R_ZE_SYM_ADDR;
75 
76     debugRelocations[1].addend = 0x0;
77     debugRelocations[1].offset = 0x8U;
78     debugRelocations[1].info = (uint64_t(1) << 32) | NEO::Elf::RELOC_TYPE_ZEBIN::R_ZE_SYM_ADDR_32;
79 
80     debugRelocations[2].addend = 0x0;
81     debugRelocations[2].offset = 0xCU;
82     debugRelocations[2].info = (uint64_t(2) << 32) | NEO::Elf::RELOC_TYPE_ZEBIN::R_ZE_SYM_ADDR_32_HI;
83 
84     debugRelocations[3].addend = -0xa;
85     debugRelocations[3].offset = 0x10U;
86     debugRelocations[3].info = (uint64_t(3) << 32) | NEO::Elf::RELOC_TYPE_ZEBIN::R_ZE_SYM_ADDR;
87 
88     // Will be ignored
89     debugRelocations[4].addend = 0x0;
90     debugRelocations[4].offset = 0x18U;
91     debugRelocations[4].info = (uint64_t(4) << 32) | NEO::Elf::RELOC_TYPE_ZEBIN::R_ZE_SYM_ADDR;
92 
93     elfEncoder.appendSection(NEO::Elf::SHT_SYMTAB, NEO::Elf::SectionsNamesZebin::symtab, ArrayRef<const uint8_t>(reinterpret_cast<uint8_t *>(symbols), sizeof(symbols)));
94     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)));
95     relaHeader.info = debugInfoSectionIndex;
96 
97     segments.constData = {reinterpret_cast<uintptr_t>(constData), {constData, sizeof(constData)}};
98     segments.varData = {reinterpret_cast<uintptr_t>(varData), {varData, sizeof(varData)}};
99     segments.stringData = {reinterpret_cast<uintptr_t>(stringData), {stringData, sizeof(stringData)}};
100     segments.nameToSegMap["kernel"] = {reinterpret_cast<uintptr_t>(kernelISA), {kernelISA, sizeof(kernelISA)}};
101     auto zebinBin = elfEncoder.encode();
102 
103     std::string warning, error;
104     auto zebin = NEO::Elf::decodeElf(zebinBin, error, warning);
105     ASSERT_TRUE(error.empty());
106     ASSERT_TRUE(warning.empty());
107 
108     auto debugZebinBin = NEO::Debug::createDebugZebin(zebinBin, segments);
109     auto debugZebin = NEO::Elf::decodeElf(debugZebinBin, error, warning);
110     ASSERT_TRUE(error.empty());
111     ASSERT_TRUE(warning.empty());
112 
113     EXPECT_EQ(zebin.elfFileHeader->machine, debugZebin.elfFileHeader->machine);
114     EXPECT_EQ(zebin.elfFileHeader->flags, debugZebin.elfFileHeader->flags);
115     EXPECT_EQ(zebin.elfFileHeader->type, debugZebin.elfFileHeader->type);
116     EXPECT_EQ(zebin.elfFileHeader->version, debugZebin.elfFileHeader->version);
117     EXPECT_EQ(zebin.elfFileHeader->shStrNdx, debugZebin.elfFileHeader->shStrNdx);
118 
119     EXPECT_EQ(zebin.sectionHeaders.size(), debugZebin.sectionHeaders.size());
120 
121     uint64_t offsetKernel, offsetConstData, offsetVarData, offsetStringData;
122     offsetKernel = offsetConstData = offsetVarData = std::numeric_limits<uint64_t>::max();
123     for (uint32_t i = 0; i < zebin.sectionHeaders.size(); ++i) {
124         EXPECT_EQ(zebin.sectionHeaders[i].header->type, debugZebin.sectionHeaders[i].header->type);
125         EXPECT_EQ(zebin.sectionHeaders[i].header->link, debugZebin.sectionHeaders[i].header->link);
126         EXPECT_EQ(zebin.sectionHeaders[i].header->info, debugZebin.sectionHeaders[i].header->info);
127         EXPECT_EQ(zebin.sectionHeaders[i].header->name, debugZebin.sectionHeaders[i].header->name);
128         EXPECT_EQ(zebin.sectionHeaders[i].header->flags, debugZebin.sectionHeaders[i].header->flags);
129 
130         auto sectionName = debugZebin.getSectionName(i);
131         auto refSectionName = NEO::ConstStringRef(sectionName);
132         if (refSectionName.startsWith(NEO::Elf::SectionsNamesZebin::textPrefix.data())) {
133             auto kernelName = sectionName.substr(NEO::Elf::SectionsNamesZebin::textPrefix.length());
134             auto segmentIdIter = segments.nameToSegMap.find(kernelName);
135             ASSERT_TRUE(segmentIdIter != segments.nameToSegMap.end());
136             const auto &kernel = segmentIdIter->second;
137 
138             EXPECT_EQ(kernel.data.size(), debugZebin.sectionHeaders[i].header->size);
139             EXPECT_TRUE(memcmp(kernel.data.begin(), debugZebin.sectionHeaders[i].data.begin(), kernel.data.size()) == 0);
140             offsetKernel = debugZebin.sectionHeaders[i].header->offset;
141         } else if (refSectionName == NEO::Elf::SectionsNamesZebin::dataConst) {
142             EXPECT_EQ(segments.constData.data.size(), debugZebin.sectionHeaders[i].header->size);
143             EXPECT_TRUE(memcmp(segments.constData.data.begin(), debugZebin.sectionHeaders[i].data.begin(), segments.constData.data.size()) == 0);
144             offsetConstData = debugZebin.sectionHeaders[i].header->offset;
145         } else if (refSectionName == NEO::Elf::SectionsNamesZebin::dataGlobal) {
146             EXPECT_EQ(segments.varData.data.size(), debugZebin.sectionHeaders[i].header->size);
147             EXPECT_TRUE(memcmp(segments.varData.data.begin(), debugZebin.sectionHeaders[i].data.begin(), segments.varData.data.size()) == 0);
148             offsetVarData = debugZebin.sectionHeaders[i].header->offset;
149         } else if (refSectionName == NEO::Elf::SectionsNamesZebin::dataConstString) {
150             EXPECT_EQ(segments.stringData.data.size(), debugZebin.sectionHeaders[i].header->size);
151             EXPECT_TRUE(memcmp(segments.stringData.data.begin(), debugZebin.sectionHeaders[i].data.begin(), segments.stringData.data.size()) == 0);
152             offsetStringData = debugZebin.sectionHeaders[i].header->offset;
153         } else if (refSectionName == NEO::Elf::SectionsNamesZebin::debugInfo) {
154             EXPECT_EQ(zebin.sectionHeaders[i].header->size, debugZebin.sectionHeaders[i].header->size);
155 
156             auto ptrDebugInfo = debugZebin.sectionHeaders[i].data.begin();
157             EXPECT_EQ(*reinterpret_cast<const uint64_t *>(ptrDebugInfo + debugRelocations[0].offset),
158                       segments.nameToSegMap["kernel"].address + symbols[0].value + debugRelocations[0].addend);
159 
160             EXPECT_EQ(*reinterpret_cast<const uint32_t *>(ptrDebugInfo + debugRelocations[1].offset),
161                       static_cast<uint32_t>((segments.constData.address + symbols[1].value + debugRelocations[1].addend) & 0xffffffff));
162 
163             EXPECT_EQ(*reinterpret_cast<const uint32_t *>(ptrDebugInfo + debugRelocations[2].offset),
164                       static_cast<uint32_t>(((segments.varData.address + symbols[2].value + debugRelocations[2].addend) >> 32) & 0xffffffff));
165 
166             // debug symbols are not offseted
167             EXPECT_EQ(*reinterpret_cast<const uint64_t *>(ptrDebugInfo + debugRelocations[3].offset),
168                       symbols[3].value + debugRelocations[3].addend);
169 
170             // if symbols points to other sections relocation is skipped
171             EXPECT_EQ(*reinterpret_cast<const uint64_t *>(ptrDebugInfo + debugRelocations[4].offset), 0U);
172         } else {
173             EXPECT_EQ(zebin.sectionHeaders[i].header->size, debugZebin.sectionHeaders[i].header->size);
174             if (debugZebin.sectionHeaders[i].header->size > 0U) {
175                 EXPECT_TRUE(memcmp(zebin.sectionHeaders[i].data.begin(), debugZebin.sectionHeaders[i].data.begin(), debugZebin.sectionHeaders[i].data.size()) == 0);
176             }
177         }
178     }
179 
180     EXPECT_EQ(4U, debugZebin.programHeaders.size());
181     EXPECT_EQ(segments.nameToSegMap["kernel"].address, static_cast<uintptr_t>(debugZebin.programHeaders[0].header->vAddr));
182     EXPECT_EQ(segments.nameToSegMap["kernel"].data.size(), static_cast<uintptr_t>(debugZebin.programHeaders[0].header->fileSz));
183     EXPECT_EQ(segments.nameToSegMap["kernel"].data.size(), static_cast<uintptr_t>(debugZebin.programHeaders[0].header->memSz));
184     EXPECT_EQ(offsetKernel, static_cast<uintptr_t>(debugZebin.programHeaders[0].header->offset));
185 
186     EXPECT_EQ(segments.constData.address, static_cast<uintptr_t>(debugZebin.programHeaders[1].header->vAddr));
187     EXPECT_EQ(segments.constData.data.size(), static_cast<uintptr_t>(debugZebin.programHeaders[1].header->fileSz));
188     EXPECT_EQ(segments.constData.data.size(), static_cast<uintptr_t>(debugZebin.programHeaders[1].header->memSz));
189     EXPECT_EQ(offsetConstData, static_cast<uintptr_t>(debugZebin.programHeaders[1].header->offset));
190 
191     EXPECT_EQ(segments.varData.address, static_cast<uintptr_t>(debugZebin.programHeaders[2].header->vAddr));
192     EXPECT_EQ(segments.varData.data.size(), static_cast<uintptr_t>(debugZebin.programHeaders[2].header->fileSz));
193     EXPECT_EQ(segments.varData.data.size(), static_cast<uintptr_t>(debugZebin.programHeaders[2].header->memSz));
194     EXPECT_EQ(offsetVarData, static_cast<uintptr_t>(debugZebin.programHeaders[2].header->offset));
195 
196     EXPECT_EQ(segments.stringData.address, static_cast<uintptr_t>(debugZebin.programHeaders[3].header->vAddr));
197     EXPECT_EQ(segments.stringData.data.size(), static_cast<uintptr_t>(debugZebin.programHeaders[3].header->fileSz));
198     EXPECT_EQ(segments.stringData.data.size(), static_cast<uintptr_t>(debugZebin.programHeaders[3].header->memSz));
199     EXPECT_EQ(offsetStringData, static_cast<uintptr_t>(debugZebin.programHeaders[3].header->offset));
200 }
201 
TEST(DebugZebinTest,givenInvalidZebinThenDebugZebinIsNotGenerated)202 TEST(DebugZebinTest, givenInvalidZebinThenDebugZebinIsNotGenerated) {
203     uint8_t notZebin[] = {'N',
204                           'O',
205                           'T',
206                           'E',
207                           'L',
208                           'F'};
209     auto debugZebin = NEO::Debug::createDebugZebin(ArrayRef<const uint8_t>(notZebin, sizeof(notZebin)), {});
210     EXPECT_EQ(0U, debugZebin.size());
211 }
212