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