/* * Copyright (C) 2022-2024 Intel Corporation * * SPDX-License-Identifier: MIT * */ #include "zebin_manipulator.h" #include "shared/offline_compiler/source/decoder/iga_wrapper.h" #include "shared/offline_compiler/source/ocloc_api.h" #include "shared/offline_compiler/source/ocloc_arg_helper.h" #include "shared/source/device_binary_format/device_binary_formats.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/zebin/zebin_decoder.h" #include "shared/source/helpers/hw_info.h" #include "shared/source/helpers/product_config_helper.h" #include "shared/source/utilities/directory.h" #include namespace NEO::Zebin::Manipulator { ErrorCode parseIntelGTNotesSectionForDevice(const std::vector &intelGTNotes, IgaWrapper *iga, OclocArgHelper *argHelper) { size_t productFamilyNoteId = std::numeric_limits::max(); size_t gfxCoreNoteId = std::numeric_limits::max(); size_t productConfigNoteId = std::numeric_limits::max(); for (size_t i = 0; i < intelGTNotes.size(); i++) { if (intelGTNotes[i].type == Zebin::Elf::IntelGTSectionType::productFamily) { productFamilyNoteId = i; } else if (intelGTNotes[i].type == Zebin::Elf::IntelGTSectionType::gfxCore) { gfxCoreNoteId = i; } else if (intelGTNotes[i].type == Zebin::Elf::IntelGTSectionType::productConfig) { productConfigNoteId = i; } } if (productConfigNoteId != std::numeric_limits::max()) { UNRECOVERABLE_IF(sizeof(uint32_t) != intelGTNotes[productConfigNoteId].data.size()); auto productConfig = *reinterpret_cast(intelGTNotes[productConfigNoteId].data.begin()); NEO::HardwareInfo hwInfo; const auto &deviceAotMap = argHelper->productConfigHelper->getDeviceAotInfo(); for (auto &deviceConfig : deviceAotMap) { if (deviceConfig.aotConfig.value == productConfig) { hwInfo = *deviceConfig.hwInfo; break; } } if (IGFX_UNKNOWN != hwInfo.platform.eProductFamily) { iga->setProductFamily(hwInfo.platform.eProductFamily); return OCLOC_SUCCESS; } } else if (productFamilyNoteId != std::numeric_limits::max()) { UNRECOVERABLE_IF(sizeof(PRODUCT_FAMILY) != intelGTNotes[productFamilyNoteId].data.size()); auto productFamily = *reinterpret_cast(intelGTNotes[productFamilyNoteId].data.begin()); iga->setProductFamily(productFamily); return OCLOC_SUCCESS; } else if (gfxCoreNoteId != std::numeric_limits::max()) { UNRECOVERABLE_IF(sizeof(GFXCORE_FAMILY) != intelGTNotes[gfxCoreNoteId].data.size()); auto gfxCore = *reinterpret_cast(intelGTNotes[gfxCoreNoteId].data.begin()); iga->setGfxCore(gfxCore); return OCLOC_SUCCESS; } return OCLOC_INVALID_DEVICE; } ErrorCode validateInput(const std::vector &args, IgaWrapper *iga, OclocArgHelper *argHelper, Arguments &outArguments) { for (size_t argIndex = 2; argIndex < args.size(); ++argIndex) { const auto &currArg = args[argIndex]; const bool hasMoreArgs = (argIndex + 1 < args.size()); if ("-file" == currArg && hasMoreArgs) { outArguments.binaryFile = args[++argIndex]; } else if ("-device" == currArg && hasMoreArgs) { iga->setProductFamily(getProductFamilyFromDeviceName(args[++argIndex])); } else if ("-dump" == currArg && hasMoreArgs) { outArguments.pathToDump = args[++argIndex]; addSlash(outArguments.pathToDump); } else if ("--help" == currArg) { outArguments.showHelp = true; return OCLOC_SUCCESS; } else if ("-q" == currArg) { argHelper->getPrinterRef().setSuppressMessages(true); iga->setMessagePrinter(argHelper->getPrinterRef()); } else if ("-v" == currArg) { argHelper->setVerbose(true); } else if ("-skip-asm-translation" == currArg) { outArguments.skipIGAdisassembly = true; } else { argHelper->printf("Unknown argument %s\n", currArg.c_str()); return OCLOC_INVALID_COMMAND_LINE; } } if (outArguments.binaryFile.empty()) { argHelper->printf("Error: Missing -file argument\n"); return OCLOC_INVALID_COMMAND_LINE; } if (outArguments.pathToDump.empty()) { argHelper->printf("Warning: Path to dump -dump not specified. Using \"./dump/\" as dump folder.\n"); outArguments.pathToDump = "dump/"; } return OCLOC_SUCCESS; } bool is64BitZebin(OclocArgHelper *argHelper, const std::string §ionsInfoFilepath) { std::vector lines; argHelper->readFileToVectorOfStrings(sectionsInfoFilepath, lines); if (lines.empty()) { return false; } auto ss = std::stringstream(lines[0]); std::vector elfTypeStringSplit; while (ss.good()) { auto &element = elfTypeStringSplit.emplace_back(); std::getline(ss, element, ' '); } return elfTypeStringSplit.size() == 2 && std::stoi(elfTypeStringSplit[1]) == 64; } BinaryFormats getBinaryFormatForAssemble(OclocArgHelper *argHelper, const std::vector &args) { auto it = std::find(args.begin(), args.end(), "-dump"); std::string dump = (it != args.end() && (it + 1) != args.end()) ? *(it + 1) : "dump/"; addSlash(dump); auto sectionsInfoFilepath = dump + Manipulator::sectionsInfoFilename.str(); const bool usesZebin = argHelper->fileExists(sectionsInfoFilepath); if (usesZebin) { return Manipulator::is64BitZebin(argHelper, sectionsInfoFilepath) ? BinaryFormats::Zebin64b : BinaryFormats::Zebin32b; } return BinaryFormats::PatchTokens; } BinaryFormats getBinaryFormatForDisassemble(OclocArgHelper *argHelper, const std::vector &args) { auto it = std::find(args.begin(), args.end(), "-file"); if (it != args.end() && (it + 1) != args.end()) { auto file = argHelper->readBinaryFile(*(it + 1)); auto fileRef = ArrayRef::fromAny(file.data(), file.size()); if (NEO::isDeviceBinaryFormat(fileRef)) { auto numBits = Elf::getElfNumBits(fileRef); return numBits == Elf::EI_CLASS_64 ? BinaryFormats::Zebin64b : BinaryFormats::Zebin32b; } } return BinaryFormats::PatchTokens; } template ZebinDecoder::ZebinDecoder(OclocArgHelper *argHelper); template ZebinDecoder::ZebinDecoder(OclocArgHelper *argHelper); template ZebinDecoder::ZebinDecoder(OclocArgHelper *argHelper) : argHelper(argHelper), iga(new IgaWrapper) { iga->setMessagePrinter(argHelper->getPrinterRef()); } template ZebinDecoder::~ZebinDecoder(); template ZebinDecoder::~ZebinDecoder(); template ZebinDecoder::~ZebinDecoder() {} template ErrorCode ZebinDecoder::decode(); template ErrorCode ZebinDecoder::decode(); template ErrorCode ZebinDecoder::decode() { auto zebinBinary = argHelper->readBinaryFile(this->arguments.binaryFile); ArrayRef zebinBinaryRef = {reinterpret_cast(zebinBinary.data()), zebinBinary.size()}; ElfT elf; ErrorCode retVal = decodeZebin(ArrayRef::fromAny(zebinBinary.data(), zebinBinary.size()), elf); if (retVal != OCLOC_SUCCESS) { argHelper->printf("Error while decoding zebin.\n"); return retVal; } if (false == arguments.skipIGAdisassembly) { auto intelGTNotes = getIntelGTNotes(elf); if (intelGTNotes.empty()) { argHelper->printf("Error missing or invalid Intel GT Notes section.\n"); return OCLOC_INVALID_FILE; } retVal = parseIntelGTNotesSectionForDevice(intelGTNotes, iga.get(), argHelper); if (retVal != OCLOC_SUCCESS) { argHelper->printf("Error while parsing Intel GT Notes section for device.\n"); return retVal; } } // Create dump directory if we are not using virtual filesystem if (false == argHelper->outputEnabled()) { Directory::createDirectory(arguments.pathToDump); } auto sectionsInfo = dumpElfSections(elf); dumpSectionInfo(sectionsInfo); return OCLOC_SUCCESS; } template ErrorCode ZebinDecoder::validateInput(const std::vector &args); template ErrorCode ZebinDecoder::validateInput(const std::vector &args); template ErrorCode ZebinDecoder::validateInput(const std::vector &args) { return Manipulator::validateInput(args, iga.get(), argHelper, arguments); } template void ZebinDecoder::printHelp(); template void ZebinDecoder::printHelp(); template void ZebinDecoder::printHelp() { argHelper->printf(R"===(Disassembles Zebin. Output of such operation is a set of files that can be later used to reassemble back. Symbols and relocations are translated into human readable format. Kernels are translated into assembly. File named "sections.txt" is created which describes zebin sections. Usage: ocloc disasm -file [-dump ] [-device ] [-skip-asm-translation] -file Input file to be disassembled. -dump Optional. Path for files representing decoded binary. Default is './dump'. -device Optional. Target device of input binary. -skip-asm-translation Optional. Skips parsing intelGTNotes for device and skips kernel translation to assembly. --help Print this usage message. )==="); } template void ZebinDecoder::dump(ConstStringRef name, ArrayRef data) { auto outPath = arguments.pathToDump + name.str(); argHelper->saveOutput(outPath, data.begin(), data.size()); } template void ZebinDecoder::dumpKernelData(ConstStringRef name, ArrayRef data) { std::string disassembledKernel; if (false == arguments.skipIGAdisassembly && iga->tryDisassembleGenISA(data.begin(), static_cast(data.size()), disassembledKernel)) { dump(name.str() + ".asm", {reinterpret_cast(disassembledKernel.data()), disassembledKernel.length()}); } else { dump(name, data); } } template void ZebinDecoder::dumpSymtab(ElfT &elf, ArrayRef symtabData) { ArrayRef symbols(reinterpret_cast(symtabData.begin()), symtabData.size() / sizeof(ElfSymT)); std::stringstream symbolsFile; symbolsFile << "Id, Name, Section, Value, Type, Visibility, Binding\n"; int symbolID = 0; for (auto &symbol : symbols) { auto symbolName = elf.getSymbolName(symbol.name); if (symbolName.empty()) { symbolName = "UNDEF"; } auto sectionName = elf.getSectionName(symbol.shndx); if (sectionName.empty()) { sectionName = "UNDEF"; } symbolsFile << std::to_string(symbolID++) << ", " << symbolName << ", " << sectionName << ", " << std::to_string(symbol.value) << ", " << std::to_string(symbol.getType()) << ", " << std::to_string(symbol.getVisibility()) << ", " << std::to_string(symbol.getBinding()) << "\n"; } auto symbolsFileStr = symbolsFile.str(); dump(Zebin::Elf::SectionNames::symtab, ArrayRef::fromAny(symbolsFileStr.data(), symbolsFileStr.size())); } template std::vector ZebinDecoder::dumpElfSections(ElfT &elf) { std::vector sectionInfos; for (size_t secId = 1U; secId < elf.sectionHeaders.size(); secId++) { auto &[header, data] = elf.sectionHeaders[secId]; auto sectionName = elf.getSectionName(static_cast(secId)); if (header->type == Elf::SHT_PROGBITS && ConstStringRef(sectionName).startsWith(Zebin::Elf::SectionNames::textPrefix)) { dumpKernelData(sectionName, data); } else if (header->type == Elf::SHT_SYMTAB) { dumpSymtab(elf, data); } else if (header->type == Elf::SHT_REL) { dumpRel(sectionName, data); } else if (header->type == Elf::SHT_RELA) { dumpRela(sectionName, data); } else if (header->type == Elf::SHT_STRTAB) { continue; } else { dump(sectionName, data); } sectionInfos.push_back({sectionName, header->type}); } return sectionInfos; } template void ZebinDecoder::dumpSectionInfo(const std::vector §ionInfos) { std::stringstream sectionsInfoStr; sectionsInfoStr << "ElfType " << (numBits == Elf::EI_CLASS_64 ? "64b" : "32b") << std::endl; sectionsInfoStr << "Section name, Section type" << std::endl; for (const auto §ionInfo : sectionInfos) { sectionsInfoStr << sectionInfo.name << ", " << std::to_string(sectionInfo.type) << std::endl; } auto sectionInfoStr = sectionsInfoStr.str(); dump(sectionsInfoFilename, ArrayRef::fromAny(sectionInfoStr.data(), sectionInfoStr.size())); } template ErrorCode ZebinDecoder::decodeZebin(ArrayRef zebin, ElfT &outElf) { std::string errors, warnings; outElf = Elf::decodeElf(zebin, errors, warnings); if (false == errors.empty()) { argHelper->printf("decodeElf error: %s\n", errors.c_str()); return OCLOC_INVALID_FILE; } return OCLOC_SUCCESS; } template std::vector ZebinDecoder::getIntelGTNotes(ElfT &elf) { std::vector intelGTNotes; std::string errors, warnings; NEO::Zebin::getIntelGTNotes(elf, intelGTNotes, errors, warnings); if (false == errors.empty()) { argHelper->printf("Error when reading intelGTNotes: %s\n", errors.c_str()); } return intelGTNotes; } template void ZebinDecoder::dumpRel(ConstStringRef name, ArrayRef data) { ArrayRef relocs = {reinterpret_cast(data.begin()), data.size() / sizeof(ElfRelT)}; std::stringstream relocsFile; relocsFile << "Offset, Type, SymbolIdx\n"; for (auto &reloc : relocs) { relocsFile << std::to_string(reloc.offset) << ", " << std::to_string(reloc.getRelocationType()) << ", " << std::to_string(reloc.getSymbolTableIndex()) << "\n"; } auto relocsFileStr = relocsFile.str(); dump(name, ArrayRef::fromAny(relocsFileStr.data(), relocsFileStr.length())); } template void ZebinDecoder::dumpRela(ConstStringRef name, ArrayRef data) { ArrayRef relocs = {reinterpret_cast(data.begin()), data.size() / sizeof(ElfRelaT)}; std::stringstream relocsFile; relocsFile << "Offset, Type, SymbolIdx, Addend\n"; for (auto &reloc : relocs) { relocsFile << std::to_string(reloc.offset) << ", " << std::to_string(reloc.getRelocationType()) << ", " << std::to_string(reloc.getSymbolTableIndex()) << ", " << std::to_string(reloc.addend) << "\n"; } auto relocsFileStr = relocsFile.str(); dump(name, ArrayRef::fromAny(relocsFileStr.data(), relocsFileStr.length())); } template ZebinEncoder::ZebinEncoder(OclocArgHelper *argHelper); template ZebinEncoder::ZebinEncoder(OclocArgHelper *argHelper); template ZebinEncoder::ZebinEncoder(OclocArgHelper *argHelper) : argHelper(argHelper), iga(new IgaWrapper) { iga->setMessagePrinter(argHelper->getPrinterRef()); } template ZebinEncoder::~ZebinEncoder(); template ZebinEncoder::~ZebinEncoder(); template ZebinEncoder::~ZebinEncoder() {} template ErrorCode ZebinEncoder::encode(); template ErrorCode ZebinEncoder::encode(); template ErrorCode ZebinEncoder::encode() { ErrorCode retVal = OCLOC_SUCCESS; std::vector sectionInfos; retVal = loadSectionsInfo(sectionInfos); if (retVal != OCLOC_SUCCESS) { argHelper->printf("Error while loading sections file.\n"); return retVal; } retVal = checkIfAllFilesExist(sectionInfos); if (retVal != OCLOC_SUCCESS) { argHelper->printf("Error: Missing one or more section files.\n"); return retVal; } auto intelGTNotesSectionData = getIntelGTNotesSection(sectionInfos); auto intelGTNotes = getIntelGTNotes(intelGTNotesSectionData); retVal = parseIntelGTNotesSectionForDevice(intelGTNotes, iga.get(), argHelper); if (retVal != OCLOC_SUCCESS) { argHelper->printf("Error while parsing Intel GT Notes section for device.\n"); return retVal; } ElfEncoderT elfEncoder; elfEncoder.getElfFileHeader().machine = Elf::ElfMachine::EM_INTELGT; elfEncoder.getElfFileHeader().type = Zebin::Elf::ElfTypeZebin::ET_ZEBIN_EXE; retVal = appendSections(elfEncoder, sectionInfos); if (retVal != OCLOC_SUCCESS) { argHelper->printf("Error while appending elf sections.\n"); return retVal; } auto zebin = elfEncoder.encode(); argHelper->saveOutput(getFilePath(arguments.binaryFile), zebin.data(), zebin.size()); return OCLOC_SUCCESS; } template ErrorCode ZebinEncoder::validateInput(const std::vector &args); template ErrorCode ZebinEncoder::validateInput(const std::vector &args); template ErrorCode ZebinEncoder::validateInput(const std::vector &args) { return Manipulator::validateInput(args, iga.get(), argHelper, arguments); } template void ZebinEncoder::printHelp(); template void ZebinEncoder::printHelp(); template void ZebinEncoder::printHelp() { argHelper->printf(R"OCLOC_HELP(Assembles Zebin from input files. It's expected that input files were previously generated by 'ocloc disasm' command or are compatible with 'ocloc disasm' output (especially in terms of file naming scheme). Usage: ocloc asm -file [-dump ] [-device ] [-skip-asm-translation] -file Name of the newly assembled zebin. -dump Optional. Path to the input directory containing disassembled binary. Default is './dump'. -device Optional. Target device of input binary. -v Verbose mode. --help Print this usage message. )OCLOC_HELP"); } template std::vector ZebinEncoder::getIntelGTNotesSection(const std::vector §ionInfos) { bool containsIntelGTNoteSection = false; for (auto §ionInfo : sectionInfos) { if (sectionInfo.type == Elf::SHT_NOTE && sectionInfo.name == Zebin::Elf::SectionNames::noteIntelGT) { containsIntelGTNoteSection = true; break; } } if (false == containsIntelGTNoteSection) { return {}; } return argHelper->readBinaryFile(getFilePath(Zebin::Elf::SectionNames::noteIntelGT.data())); } template std::vector ZebinEncoder::getIntelGTNotes(const std::vector &intelGtNotesSection) { std::vector intelGTNotes; std::string errors, warnings; auto refIntelGTNotesSection = ArrayRef::fromAny(intelGtNotesSection.data(), intelGtNotesSection.size()); auto decodeError = NEO::Zebin::decodeIntelGTNoteSection(refIntelGTNotesSection, intelGTNotes, errors, warnings); argHelper->printf(warnings.c_str()); if (decodeError != NEO::DecodeError::success) { argHelper->printf(errors.c_str()); } return intelGTNotes; } template ErrorCode ZebinEncoder::loadSectionsInfo(std::vector §ionInfos) { std::vector sectionsInfoLines; argHelper->readFileToVectorOfStrings(getFilePath(sectionsInfoFilename.data()), sectionsInfoLines); if (sectionsInfoLines.size() <= 2) { return OCLOC_INVALID_FILE; } sectionInfos.resize(sectionsInfoLines.size() - 2); for (size_t i = 2; i < sectionsInfoLines.size(); i++) { auto elements = parseLine(sectionsInfoLines[i]); UNRECOVERABLE_IF(elements.size() != 2); auto §ionInfo = sectionInfos[i - 2]; sectionInfo.name = elements[0]; sectionInfo.type = static_cast(std::stoull(elements[1])); } return OCLOC_SUCCESS; } template ErrorCode ZebinEncoder::checkIfAllFilesExist(const std::vector §ionInfos) { for (auto §ionInfo : sectionInfos) { bool fileExists = argHelper->fileExists(getFilePath(sectionInfo.name)); if (ConstStringRef(sectionInfo.name).startsWith(Zebin::Elf::SectionNames::textPrefix)) { fileExists |= argHelper->fileExists(getFilePath(sectionInfo.name + ".asm")); } if (false == fileExists) { argHelper->printf("Error: Could not find the file \"%s\"\n", sectionInfo.name.c_str()); return OCLOC_INVALID_FILE; } } return OCLOC_SUCCESS; } template ErrorCode ZebinEncoder::appendSections(ElfEncoderT &encoder, const std::vector §ionInfos) { SecNameToIdMapT secNameToId; size_t symtabIdx = std::numeric_limits::max(); for (size_t i = 0; i < sectionInfos.size(); i++) { secNameToId[sectionInfos[i].name] = i + 1; if (sectionInfos[i].name == Zebin::Elf::SectionNames::symtab) { symtabIdx = i + 1; } } ErrorCode retVal = OCLOC_SUCCESS; for (const auto §ion : sectionInfos) { if (section.type == Elf::SHT_SYMTAB) { retVal |= appendSymtab(encoder, section, sectionInfos.size() + 1, secNameToId); } else if (section.type == Elf::SHT_REL) { retVal |= appendRel(encoder, section, secNameToId[section.name.substr(Elf::SpecialSectionNames::relPrefix.length())], symtabIdx); } else if (section.type == Elf::SHT_RELA) { retVal |= appendRela(encoder, section, secNameToId[section.name.substr(Elf::SpecialSectionNames::relaPrefix.length())], symtabIdx); } else if (section.type == Elf::SHT_PROGBITS && ConstStringRef(section.name).startsWith(Zebin::Elf::SectionNames::textPrefix)) { retVal |= appendKernel(encoder, section); } else { retVal |= appendOther(encoder, section); } } return retVal; } template ErrorCode ZebinEncoder::appendRel(ElfEncoderT &encoder, const SectionInfo §ion, size_t targetSecId, size_t symtabSecId) { std::vector relocationLines; argHelper->readFileToVectorOfStrings(getFilePath(section.name), relocationLines); if (relocationLines.empty()) { argHelper->printf("Error: Empty relocations file: %s\n", section.name.c_str()); return OCLOC_INVALID_FILE; } auto relocs = parseRel(relocationLines); auto &sec = encoder.appendSection(Elf::SHT_REL, section.name, ArrayRef::fromAny(relocs.data(), relocs.size())); sec.info = static_cast(targetSecId); sec.link = static_cast(symtabSecId); return OCLOC_SUCCESS; } template ErrorCode ZebinEncoder::appendRela(ElfEncoderT &encoder, const SectionInfo §ion, size_t targetSecId, size_t symtabSecId) { std::vector relocationLines; argHelper->readFileToVectorOfStrings(getFilePath(section.name), relocationLines); if (relocationLines.empty()) { argHelper->printf("Error: Empty relocations file: %s\n", section.name.c_str()); return OCLOC_INVALID_FILE; } auto relocs = parseRela(relocationLines); auto &sec = encoder.appendSection(Elf::SHT_RELA, section.name, ArrayRef::fromAny(relocs.data(), relocs.size())); sec.info = static_cast(targetSecId); sec.link = static_cast(symtabSecId); return OCLOC_SUCCESS; } template std::string ZebinEncoder::getFilePath(const std::string &filename) { return arguments.pathToDump + filename; } template std::string ZebinEncoder::parseKernelAssembly(ArrayRef kernelAssembly) { std::string kernelAssemblyString(kernelAssembly.begin(), kernelAssembly.end()); std::string outBinary; if (iga->tryAssembleGenISA(kernelAssemblyString, outBinary)) { return outBinary; } return {}; } template ErrorCode ZebinEncoder::appendKernel(ElfEncoderT &encoder, const SectionInfo §ion) { if (argHelper->fileExists(getFilePath(section.name + ".asm"))) { auto data = argHelper->readBinaryFile(getFilePath(section.name + ".asm")); auto kernelBinary = parseKernelAssembly(ArrayRef::fromAny(data.data(), data.size())); ArrayRef refKernelBinary = {reinterpret_cast(kernelBinary.data()), kernelBinary.size()}; encoder.appendSection(section.type, section.name, refKernelBinary); } else { auto data = argHelper->readBinaryFile(getFilePath(section.name)); encoder.appendSection(Elf::SHT_PROGBITS, section.name, ArrayRef::fromAny(data.data(), data.size())); } return OCLOC_SUCCESS; } template ErrorCode ZebinEncoder::appendSymtab(ElfEncoderT &encoder, const SectionInfo §ion, size_t strtabSecId, SecNameToIdMapT secNameToId) { std::vector symTabLines; argHelper->readFileToVectorOfStrings(getFilePath(section.name), symTabLines); if (symTabLines.empty()) { argHelper->printf("Error: Empty symtab file: %s\n", section.name.c_str()); return OCLOC_INVALID_FILE; } size_t numLocalSymbols = 0; auto symbols = parseSymbols(symTabLines, encoder, numLocalSymbols, secNameToId); auto &symtabSection = encoder.appendSection(section.type, section.name, ArrayRef::fromAny(symbols.data(), symbols.size())); symtabSection.info = static_cast(numLocalSymbols); symtabSection.link = static_cast(strtabSecId); return OCLOC_SUCCESS; } template ErrorCode ZebinEncoder::appendOther(ElfEncoderT &encoder, const SectionInfo §ion) { auto sectionData = argHelper->readBinaryFile(getFilePath(section.name)); encoder.appendSection(section.type, section.name, ArrayRef::fromAny(sectionData.data(), sectionData.size())); return OCLOC_SUCCESS; } template std::vector ZebinEncoder::parseLine(const std::string &line) { std::vector out; auto ss = std::stringstream(line); while (ss.good()) { auto &element = out.emplace_back(); std::getline(ss, element, ','); } return out; } template std::vector::ElfRelT> ZebinEncoder::parseRel(const std::vector &relocationsFile) { std::vector relocs; relocs.resize(relocationsFile.size() - 1); for (size_t lineId = 1U; lineId < relocationsFile.size(); lineId++) { auto elements = parseLine(relocationsFile[lineId]); UNRECOVERABLE_IF(elements.size() != 3); auto &reloc = relocs[lineId - 1]; reloc.offset = static_cast(std::stoull(elements[0])); reloc.setRelocationType(static_cast(std::stoull(elements[1]))); reloc.setSymbolTableIndex(static_cast(std::stoull(elements[2]))); } return relocs; } template std::vector::ElfRelaT> ZebinEncoder::parseRela(const std::vector &relocationsFile) { std::vector relocs; relocs.resize(relocationsFile.size() - 1); for (size_t lineId = 1U; lineId < relocationsFile.size(); lineId++) { auto elements = parseLine(relocationsFile[lineId]); UNRECOVERABLE_IF(elements.size() != 4); auto &reloc = relocs[lineId - 1]; reloc.offset = static_cast(std::stoull(elements[0])); reloc.setRelocationType(static_cast(std::stoull(elements[1]))); reloc.setSymbolTableIndex(static_cast(std::stoull(elements[2]))); reloc.addend = static_cast(std::stoll(elements[3])); } return relocs; } template std::vector::ElfSymT> ZebinEncoder::parseSymbols(const std::vector &symbolsFile, ElfEncoderT &encoder, size_t &outNumLocalSymbols, SecNameToIdMapT secNameToId) { std::vector symbols; symbols.resize(symbolsFile.size() - 1); outNumLocalSymbols = 0U; for (size_t lineId = 1U; lineId < symbolsFile.size(); lineId++) { auto &line = symbolsFile[lineId]; auto elements = parseLine(line); UNRECOVERABLE_IF(elements.size() != 7); auto symbolId = std::stoull(elements[0]); auto symbolName = elements[1].substr(1); auto sectionName = elements[2].substr(1); auto symbolValue = std::stoull(elements[3]); auto symbolType = std::stoi(elements[4]); auto symbolVisibility = std::stoi(elements[5]); auto symbolBinding = std::stoi(elements[6]); UNRECOVERABLE_IF(symbolId >= symbols.size()); auto &symbol = symbols[static_cast(symbolId)]; symbol.name = static_cast((symbolName == "UNDEF") ? 0 : encoder.appendSectionName(symbolName)); symbol.shndx = static_cast((sectionName == "UNDEF") ? 0 : static_cast(secNameToId[sectionName])); symbol.value = static_cast(symbolValue); symbol.setType(static_cast(symbolType)); symbol.setVisibility(static_cast(symbolVisibility)); symbol.setBinding(static_cast(symbolBinding)); if (symbol.getBinding() == Elf::STB_LOCAL) { outNumLocalSymbols = lineId; } } return symbols; } } // namespace NEO::Zebin::Manipulator