10#include "qlibrary_p.h"
12#include <qloggingcategory.h>
16#if __has_include(<elf.h>)
18#elif __has_include(<sys/elf.h>)
21# error "Need ELF header to parse plugins."
26using namespace Qt::StringLiterals;
29static constexpr bool ElfNotesAreMandatory = QT_VERSION >= QT_VERSION_CHECK(7,0,0);
33static constexpr bool IncludeValidityChecks =
true;
35#ifdef QT_BUILD_INTERNAL
36# define QELFPARSER_DEBUG
38#if defined(QELFPARSER_DEBUG)
39Q_STATIC_LOGGING_CATEGORY(lcElfParser,
"qt.core.plugin.elfparser")
40# define qEDebug qCDebug(lcElfParser) << reinterpret_cast<const char16_t *>(error.errMsg->constData()) << ':'
42# define qEDebug if (false) {} else QNoDebug()
45#ifndef PT_GNU_EH_FRAME
46# define PT_GNU_EH_FRAME 0x6474e550
49# define PT_GNU_STACK 0x6474e551
52# define PT_GNU_RELRO 0x6474e552
54#ifndef PT_GNU_PROPERTY
55# define PT_GNU_PROPERTY 0x6474e553
59# define PN_XNUM 0xffff
63QT_WARNING_DISABLE_CLANG(
"-Wunused-const-variable")
66template <QSysInfo::Endian Order>
struct ElfEndianTraits
68 static constexpr unsigned char DataOrder = ELFDATA2LSB;
69 template <
typename T>
static T fromEndian(T value) {
return qFromLittleEndian(value); }
71template <>
struct ElfEndianTraits<QSysInfo::BigEndian>
73 static constexpr unsigned char DataOrder = ELFDATA2MSB;
74 template <
typename T>
static T fromEndian(T value) {
return qFromBigEndian(value); }
77template <
typename EquivalentPointerType>
struct ElfTypeTraits
79 static constexpr unsigned char Class = ELFCLASS64;
82 using Half = Elf64_Half;
83 using Word = Elf64_Word;
84 using Addr = Elf64_Addr;
85 using Off = Elf64_Off;
88 using Ehdr = Elf64_Ehdr;
89 using Shdr = Elf64_Shdr;
90 using Phdr = Elf64_Phdr;
91 using Nhdr = Elf64_Nhdr;
93template <>
struct ElfTypeTraits<quint32>
95 static constexpr unsigned char Class = ELFCLASS32;
98 using Half = Elf32_Half;
99 using Word = Elf32_Word;
100 using Addr = Elf32_Addr;
101 using Off = Elf32_Off;
104 using Ehdr = Elf32_Ehdr;
105 using Shdr = Elf32_Shdr;
106 using Phdr = Elf32_Phdr;
107 using Nhdr = Elf32_Nhdr;
110struct ElfMachineCheck
112 static const Elf32_Half ExpectedMachine =
115#elif defined(Q_PROCESSOR_ALPHA)
117#elif defined(Q_PROCESSOR_ARM_32)
119#elif defined(Q_PROCESSOR_ARM_64)
121#elif defined(Q_PROCESSOR_BLACKFIN)
123#elif defined(Q_PROCESSOR_HPPA)
125#elif defined(Q_PROCESSOR_IA64)
127#elif defined(Q_PROCESSOR_LOONGARCH)
129#elif defined(Q_PROCESSOR_M68K)
131#elif defined(Q_PROCESSOR_MIPS)
133#elif defined(Q_PROCESSOR_POWER_32)
135#elif defined(Q_PROCESSOR_POWER_64)
137#elif defined(Q_PROCESSOR_RISCV)
139#elif defined(Q_PROCESSOR_S390)
141#elif defined(Q_PROCESSOR_SH)
143#elif defined(Q_PROCESSOR_SPARC_V9)
145#elif defined(Q_PROCESSOR_SPARC_64)
147#elif defined(Q_PROCESSOR_SPARC)
149#elif defined(Q_PROCESSOR_WASM)
150#elif defined(Q_PROCESSOR_X86_32)
152#elif defined(Q_PROCESSOR_X86_64)
155# error "Unknown Q_PROCESSOR_xxx macro, please update."
161struct ElfHeaderCommonCheck
163 static_assert(std::is_same_v<
decltype(Elf32_Ehdr::e_ident),
decltype(Elf64_Ehdr::e_ident)>,
164 "e_ident field is not the same in both Elf32_Ehdr and Elf64_Ehdr");
167 static bool checkElfMagic(
const uchar *ident)
169 return memcmp(ident, ELFMAG, SELFMAG) == 0;
173 static bool checkElfVersion(
const uchar *ident)
175 uchar elfversion = ident[EI_VERSION];
176 return elfversion == EV_CURRENT;
179 struct CommonHeader {
186template <
typename EquivalentPointerType = quintptr, QSysInfo::Endian Order = QSysInfo::ByteOrder>
187struct ElfHeaderCheck :
public ElfHeaderCommonCheck
189 using TypeTraits = ElfTypeTraits<EquivalentPointerType>;
190 using EndianTraits = ElfEndianTraits<Order>;
191 using Ehdr =
typename TypeTraits::Ehdr;
194 static bool checkClass(
const uchar *ident)
196 uchar klass = ident[EI_CLASS];
197 return klass == TypeTraits::Class;
201 static bool checkDataOrder(
const uchar *ident)
203 uchar data = ident[EI_DATA];
204 return data == EndianTraits::DataOrder;
208 static bool checkOsAbi(
const uchar *ident)
210 uchar osabi = ident[EI_OSABI];
217 static bool checkAbiVersion(
const uchar *ident)
219 uchar abiversion = ident[EI_ABIVERSION];
221 Q_UNUSED(abiversion);
226 static bool checkPadding(
const uchar *ident)
233 static bool checkIdent(
const Ehdr &header)
235 return checkElfMagic(header.e_ident)
236 && checkClass(header.e_ident)
237 && checkDataOrder(header.e_ident)
238 && checkElfVersion(header.e_ident)
239 && checkOsAbi(header.e_ident)
240 && checkAbiVersion(header.e_ident)
241 && checkPadding(header.e_ident);
244 static bool checkType(
const Ehdr &header)
246 return header.e_type == ET_DYN;
249 static bool checkMachine(
const Ehdr &header)
251 return header.e_machine == ElfMachineCheck::ExpectedMachine;
254 static bool checkFileVersion(
const Ehdr &header)
256 return header.e_version == EV_CURRENT;
259 static bool checkHeader(
const Ehdr &header)
261 if (!checkIdent(header))
263 if (!IncludeValidityChecks)
265 return checkType(header)
266 && checkMachine(header)
267 && checkFileVersion(header);
270 Q_DECL_COLD_FUNCTION
static QString explainCheckFailure(
const Ehdr &header)
272 if (!checkElfMagic(header.e_ident))
273 return QLibrary::tr(
"invalid signature");
274 if (!checkClass(header.e_ident))
275 return QLibrary::tr(
"file is for a different word size");
276 if (!checkDataOrder(header.e_ident))
277 return QLibrary::tr(
"file is for the wrong endianness");
278 if (!checkElfVersion(header.e_ident) || !checkFileVersion(header))
279 return QLibrary::tr(
"file has an unknown ELF version");
280 if (!checkOsAbi(header.e_ident) || !checkAbiVersion(header.e_ident))
281 return QLibrary::tr(
"file has an unexpected ABI");
282 if (!checkType(header))
283 return QLibrary::tr(
"file is not a shared object");
284 if (!checkMachine(header))
285 return QLibrary::tr(
"file is for a different processor");
289 static CommonHeader extractCommonHeader(
const uchar *data)
291 auto header =
reinterpret_cast<
const Ehdr *>(data);
293 r.type = EndianTraits::fromEndian(header->e_type);
294 r.machine = EndianTraits::fromEndian(header->e_machine);
295 r.version = EndianTraits::fromEndian(header->e_version);
300struct ElfHeaderDebug {
const uchar *e_ident; };
301Q_DECL_UNUSED Q_DECL_COLD_FUNCTION
static QDebug &operator<<(QDebug &d, ElfHeaderDebug h)
303 const uchar *e_ident = h.e_ident;
304 if (!ElfHeaderCommonCheck::checkElfMagic(e_ident)) {
305 d <<
"Not an ELF file (invalid signature)";
309 QDebugStateSaver saver(d);
311 quint8 elfclass = e_ident[EI_CLASS];
315 d <<
"Invalid ELF file (class " << e_ident[EI_CLASS] <<
"), ";
325 quint8 dataorder = e_ident[EI_DATA];
329 d <<
"invalid endianness (" << e_ident[EI_DATA] <<
')';
339 switch (e_ident[EI_OSABI]) {
340 case ELFOSABI_SYSV: d <<
" (SYSV";
break;
341 case ELFOSABI_HPUX: d <<
" (HP-UX";
break;
342 case ELFOSABI_NETBSD: d <<
" (NetBSD";
break;
343 case ELFOSABI_LINUX: d <<
" (GNU/Linux";
break;
344 case ELFOSABI_SOLARIS: d <<
" (Solaris";
break;
345 case ELFOSABI_AIX: d <<
" (AIX";
break;
346 case ELFOSABI_IRIX: d <<
" (IRIX";
break;
347 case ELFOSABI_FREEBSD: d <<
" (FreeBSD";
break;
348 case ELFOSABI_OPENBSD: d <<
" (OpenBSD";
break;
349 default: d <<
" (OS ABI " << e_ident[EI_VERSION];
break;
352 if (e_ident[EI_ABIVERSION])
353 d <<
" v" << e_ident[EI_ABIVERSION];
356 if (e_ident[EI_VERSION] != 1) {
357 d <<
", file version " << e_ident[EI_VERSION];
361 ElfHeaderCommonCheck::CommonHeader r;
362 if (elfclass == ELFCLASS64 && dataorder == ELFDATA2LSB)
363 r = ElfHeaderCheck<quint64, QSysInfo::LittleEndian>::extractCommonHeader(e_ident);
364 else if (elfclass == ELFCLASS32 && dataorder == ELFDATA2LSB)
365 r = ElfHeaderCheck<quint32, QSysInfo::LittleEndian>::extractCommonHeader(e_ident);
366 else if (elfclass == ELFCLASS64 && dataorder == ELFDATA2MSB)
367 r = ElfHeaderCheck<quint64, QSysInfo::BigEndian>::extractCommonHeader(e_ident);
368 else if (elfclass == ELFCLASS32 && dataorder == ELFDATA2MSB)
369 r = ElfHeaderCheck<quint32, QSysInfo::BigEndian>::extractCommonHeader(e_ident);
373 d <<
", version " << r.version;
376 case ET_NONE: d <<
", no type";
break;
377 case ET_REL: d <<
", relocatable";
break;
378 case ET_EXEC: d <<
", executable";
break;
379 case ET_DYN: d <<
", shared library or PIC executable";
break;
380 case ET_CORE: d <<
", core dump";
break;
381 default: d <<
", unknown type " << r.type;
break;
386 case EM_NONE: d <<
", no machine";
break;
387 case EM_ALPHA: d <<
", Alpha";
break;
388 case EM_68K: d <<
", MC68000";
break;
389 case EM_ARM: d <<
", ARM";
break;
390 case EM_AARCH64: d <<
", AArch64";
break;
392 case EM_BLACKFIN: d <<
", Blackfin";
break;
394 case EM_IA_64: d <<
", IA-64";
break;
396 case EM_LOONGARCH: d <<
", LoongArch";
break;
398 case EM_MIPS: d <<
", MIPS";
break;
399 case EM_PARISC: d <<
", HPPA";
break;
400 case EM_PPC: d <<
", PowerPC";
break;
401 case EM_PPC64: d <<
", PowerPC 64-bit";
break;
403 case EM_RISCV: d <<
", RISC-V";
break;
406 case EM_S390: d <<
", S/390";
break;
408 case EM_SH: d <<
", SuperH";
break;
409 case EM_SPARC: d <<
", SPARC";
break;
410 case EM_SPARCV9: d <<
", SPARCv9";
break;
411 case EM_386: d <<
", i386";
break;
412 case EM_X86_64: d <<
", x86-64";
break;
413 default: d <<
", other machine type " << r.machine;
break;
419struct ElfSectionDebug {
const ElfHeaderCheck<>::TypeTraits::Shdr *shdr; };
420Q_DECL_UNUSED
static QDebug &operator<<(QDebug &d, ElfSectionDebug s)
423 QDebugStateSaver saver(d);
424 d << Qt::hex << Qt::showbase;
426 switch (s.shdr->sh_type) {
427 case SHT_NULL: d <<
"NULL";
break;
428 case SHT_PROGBITS: d <<
"PROGBITS";
break;
429 case SHT_SYMTAB: d <<
"SYMTAB";
break;
430 case SHT_STRTAB: d <<
"STRTAB";
break;
431 case SHT_RELA: d <<
"RELA";
break;
432 case SHT_HASH: d <<
"HASH";
break;
433 case SHT_DYNAMIC: d <<
"DYNAMIC";
break;
434 case SHT_NOTE: d <<
"NOTE";
break;
435 case SHT_NOBITS: d <<
"NOBITS";
break;
436 case SHT_DYNSYM: d <<
"DYNSYM";
break;
437 case SHT_INIT_ARRAY: d <<
"INIT_ARRAY";
break;
438 case SHT_FINI_ARRAY: d <<
"FINI_ARRAY";
break;
439 default: d << s.shdr->sh_type;
444 if (s.shdr->sh_flags & SHF_WRITE)
446 if (s.shdr->sh_flags & SHF_ALLOC)
448 if (s.shdr->sh_flags & SHF_EXECINSTR)
450 if (s.shdr->sh_flags & SHF_STRINGS)
452 if (s.shdr->sh_flags & SHF_TLS)
455 d.space() <<
"offset" << s.shdr->sh_offset <<
"size" << s.shdr->sh_size;
459struct ElfProgramDebug {
const ElfHeaderCheck<>::TypeTraits::Phdr *phdr; };
460Q_DECL_UNUSED
static QDebug &operator<<(QDebug &d, ElfProgramDebug p)
462 QDebugStateSaver saved(d);
463 d << Qt::hex << Qt::showbase <<
"program";
464 switch (p.phdr->p_type) {
465 case PT_NULL: d <<
"NULL";
break;
466 case PT_LOAD: d <<
"LOAD";
break;
467 case PT_DYNAMIC: d <<
"DYNAMIC";
break;
468 case PT_INTERP: d <<
"INTERP";
break;
469 case PT_NOTE: d <<
"NOTE";
break;
470 case PT_PHDR: d <<
"PHDR";
break;
471 case PT_TLS: d <<
"TLS";
break;
472 case PT_GNU_EH_FRAME: d <<
"GNU_EH_FRAME";
break;
473 case PT_GNU_STACK: d <<
"GNU_STACK";
break;
474 case PT_GNU_RELRO: d <<
"GNU_RELRO";
break;
475 case PT_GNU_PROPERTY: d <<
"GNU_PROPERTY";
break;
476 default: d <<
"type" << p.phdr->p_type;
break;
479 d <<
"offset" << p.phdr->p_offset
480 <<
"virtaddr" << p.phdr->p_vaddr
481 <<
"filesz" << p.phdr->p_filesz
482 <<
"memsz" << p.phdr->p_memsz
483 <<
"align" << p.phdr->p_align
487 if (p.phdr->p_flags & PF_R)
489 if (p.phdr->p_flags & PF_W)
491 if (p.phdr->p_flags & PF_X)
500 constexpr ErrorMaker(QString *errMsg) : errMsg(errMsg) {}
503 Q_DECL_COLD_FUNCTION QLibraryScanResult operator()(QString &&text)
const
505 *errMsg = QLibrary::tr(
"'%1' is not a valid ELF object (%2)").arg(*errMsg, std::move(text));
509 Q_DECL_COLD_FUNCTION QLibraryScanResult notplugin(QString &&explanation)
const
511 *errMsg = QLibrary::tr(
"'%1' is not a Qt plugin (%2)").arg(*errMsg, explanation);
515 Q_DECL_COLD_FUNCTION QLibraryScanResult notfound()
const
517 return notplugin(QLibrary::tr(
"metadata not found"));
524using T = ElfHeaderCheck<>::TypeTraits;
527static bool scanProgramHeaders(QByteArrayView data,
const ErrorMaker &error, F f)
529 auto header =
reinterpret_cast<
const T::Ehdr *>(data.data());
532 auto phdr =
reinterpret_cast<
const T::Phdr *>(data.data() + header->e_phoff);
533 auto phdr_end = phdr + header->e_phnum;
534 for ( ; phdr != phdr_end; ++phdr) {
541static bool preScanProgramHeaders(QByteArrayView data,
const ErrorMaker &error)
543 auto header =
reinterpret_cast<
const T::Ehdr *>(data.data());
546 T::Word e_phnum = header->e_phnum;
547 if (e_phnum == PN_XNUM)
548 return error(QLibrary::tr(
"unimplemented: PN_XNUM program headers")),
false;
549 T::Off offset = e_phnum *
sizeof(T::Phdr);
550 if (qAddOverflow(offset, header->e_phoff, &offset) || offset > size_t(data.size()))
551 return error(QLibrary::tr(
"program header table extends past the end of the file")),
false;
554 bool hasCode =
false;
555 auto checker = [&](
const T::Phdr *phdr) {
556 qEDebug << ElfProgramDebug{phdr};
558 if (T::Off end; qAddOverflow(phdr->p_offset, phdr->p_filesz, &end)
559 || end > size_t(data.size()))
560 return error(QLibrary::tr(
"a program header entry extends past the end of the file")),
false;
563 if (phdr->p_type == PT_LOAD && phdr->p_filesz != 0 && (phdr->p_flags & PF_X))
567 if (phdr->p_type == PT_NOTE && qPopulationCount(phdr->p_align) == 1
568 && phdr->p_offset & (phdr->p_align - 1)) {
569 return error(QLibrary::tr(
"a note segment start is not properly aligned "
570 "(offset 0x%1, alignment %2)")
571 .arg(phdr->p_offset, 6, 16, QChar(u'0'))
572 .arg(phdr->p_align)),
false;
577 if (!scanProgramHeaders(data, error, checker))
580 return error.notplugin(QLibrary::tr(
"file has no code")),
false;
584static QLibraryScanResult scanProgramHeadersForNotes(QByteArrayView data,
const ErrorMaker &error)
587 constexpr size_t MinPayloadSize =
sizeof(QPluginMetaData::Header) + 2;
588 constexpr qptrdiff MinNoteSize =
sizeof(QPluginMetaData::ElfNoteHeader) + 2;
589 constexpr size_t NoteNameSize =
sizeof(QPluginMetaData::ElfNoteHeader::name);
590 constexpr size_t NoteAlignment =
alignof(QPluginMetaData::ElfNoteHeader);
591 constexpr qptrdiff PayloadStartDelta = offsetof(QPluginMetaData::ElfNoteHeader, header);
592 static_assert(MinNoteSize > PayloadStartDelta);
593 static_assert((PayloadStartDelta & (NoteAlignment - 1)) == 0);
595 QLibraryScanResult r = {};
596 auto noteFinder = [&](
const T::Phdr *phdr) {
597 if (phdr->p_type != PT_NOTE || phdr->p_align != NoteAlignment)
602 if (qptrdiff(phdr->p_filesz) < 0) {
603 auto h =
reinterpret_cast<
const T::Ehdr *>(data.data());
604 auto segments =
reinterpret_cast<
const T::Phdr *>(data.data() + h->e_phoff);
605 qEDebug <<
"segment" << (phdr - segments) <<
"contains a note with size"
606 << Qt::hex << Qt::showbase << phdr->p_filesz
607 <<
"which is larger than half the virtual memory space";
612 T::Off offset = phdr->p_offset;
613 const T::Off end_offset = offset + phdr->p_filesz;
614 while (qptrdiff(end_offset - offset) >= MinNoteSize) {
615 auto nhdr =
reinterpret_cast<
const T::Nhdr *>(data.data() + offset);
616 T::Word n_namesz = nhdr->n_namesz;
617 T::Word n_descsz = nhdr->n_descsz;
618 T::Word n_type = nhdr->n_type;
621 T::Off next_offset = offset;
622 next_offset +=
sizeof(T::Nhdr);
623 next_offset += NoteAlignment - 3;
624 if (qAddOverflow<T::Off>(next_offset, n_namesz, &next_offset))
626 next_offset &= -NoteAlignment;
628 next_offset += NoteAlignment - 3;
629 if (qAddOverflow<T::Off>(next_offset, n_descsz, &next_offset))
631 next_offset &= -NoteAlignment;
632 if (next_offset > end_offset)
635 if (n_namesz == NoteNameSize && n_descsz >= MinPayloadSize
636 && n_type == QPluginMetaData::ElfNoteHeader::NoteType
637 && memcmp(nhdr + 1, QPluginMetaData::ElfNoteHeader::NoteName, NoteNameSize) == 0) {
639 r.pos = offset + PayloadStartDelta;
640 r.length = nhdr->n_descsz;
643 offset = next_offset;
647 scanProgramHeaders(data, error, noteFinder);
652 qEDebug <<
"found Qt metadata in ELF note at"
653 << Qt::hex << Qt::showbase << r.pos <<
"size" << Qt::reset << r.length;
657static QLibraryScanResult scanSections(QByteArrayView data,
const ErrorMaker &error)
659 auto header =
reinterpret_cast<
const T::Ehdr *>(data.data());
665 T::Word e_shnum = header->e_shnum;
666 T::Off offset = e_shnum *
sizeof(T::Shdr);
667 if (qAddOverflow(offset, header->e_shoff, &offset) || offset > size_t(data.size()))
668 return error(QLibrary::tr(
"section table extends past the end of the file"));
672 auto sections =
reinterpret_cast<
const T::Shdr *>(data.data() + header->e_shoff);
673 auto sections_end = sections + e_shnum;
674 auto shdr = sections + header->e_shstrndx;
677 offset = shdr->sh_offset;
678 T::Off shstrtab_size = shdr->sh_size;
679 qEDebug <<
"shstrtab section is located at offset" << offset <<
"size" << shstrtab_size;
680 if (T::Off end; qAddOverflow<T::Off>(offset, shstrtab_size, &end)
681 || end > size_t(data.size()))
682 return error(QLibrary::tr(
"section header string table extends past the end of the file"));
685 const char *shstrtab_start = data.data() + offset;
687 for (
int section = 0; shdr != sections_end; ++section, ++shdr) {
688 QLatin1StringView name;
689 if (shdr->sh_name < shstrtab_size) {
690 const char *namestart = shstrtab_start + shdr->sh_name;
691 size_t len = qstrnlen(namestart, shstrtab_size - shdr->sh_name);
692 name = QLatin1StringView(namestart, len);
694 qEDebug <<
"section" << section <<
"name" << name << ElfSectionDebug{shdr};
698 return error(QLibrary::tr(
"a section name extends past the end of the file"));
702 if (shdr->sh_type == SHT_NOBITS)
704 if (T::Off end; qAddOverflow(shdr->sh_offset, shdr->sh_size, &end)
705 || end > size_t(data.size())) {
706 return error(QLibrary::tr(
"section contents extend past the end of the file"));
709 if (name !=
".qtmetadata"_L1)
711 qEDebug <<
"found .qtmetadata section";
712 if (shdr->sh_size <
sizeof(QPluginMetaData::MagicHeader))
713 return error(QLibrary::tr(
".qtmetadata section is too small"));
715 if (IncludeValidityChecks) {
716 QByteArrayView expectedMagic = QByteArrayView::fromArray(QPluginMetaData::MagicString);
717 QByteArrayView actualMagic = data.sliced(shdr->sh_offset, expectedMagic.size());
718 if (expectedMagic != actualMagic)
719 return error(QLibrary::tr(
".qtmetadata section has incorrect magic"));
721 if (shdr->sh_flags & SHF_WRITE)
722 return error(QLibrary::tr(
".qtmetadata section is writable"));
723 if (shdr->sh_flags & SHF_EXECINSTR)
724 return error(QLibrary::tr(
".qtmetadata section is executable"));
727 return { qsizetype(shdr->sh_offset +
sizeof(QPluginMetaData::MagicString)),
728 qsizetype(shdr->sh_size -
sizeof(QPluginMetaData::MagicString)) };
732 return error.notfound();
735QLibraryScanResult QElfParser::parse(QByteArrayView data, QString *errMsg)
737 ErrorMaker error(errMsg);
738 if (size_t(data.size()) <
sizeof(T::Ehdr)) {
739 qEDebug <<
"file too small:" << size_t(data.size());
740 return error(QLibrary::tr(
"file too small"));
743 qEDebug << ElfHeaderDebug{
reinterpret_cast<
const uchar *>(data.data()) };
745 auto header =
reinterpret_cast<
const T::Ehdr *>(data.data());
746 if (!ElfHeaderCheck<>::checkHeader(*header))
747 return error(ElfHeaderCheck<>::explainCheckFailure(*header));
749 qEDebug <<
"contains" << header->e_phnum <<
"program headers of"
750 << header->e_phentsize <<
"bytes at offset" << header->e_phoff;
751 qEDebug <<
"contains" << header->e_shnum <<
"sections of" << header->e_shentsize
752 <<
"bytes at offset" << header->e_shoff
753 <<
"; section header string table (shstrtab) is entry" << header->e_shstrndx;
756 if constexpr (IncludeValidityChecks) {
757 if (header->e_phentsize !=
sizeof(T::Phdr))
758 return error(QLibrary::tr(
"unexpected program header entry size (%1)")
759 .arg(header->e_phentsize));
762 if (!preScanProgramHeaders(data, error))
765 if (QLibraryScanResult r = scanProgramHeadersForNotes(data, error); r.length)
768 if (!ElfNotesAreMandatory) {
769 if constexpr (IncludeValidityChecks) {
770 if (header->e_shentsize !=
sizeof(T::Shdr))
771 return error(QLibrary::tr(
"unexpected section entry size (%1)")
772 .arg(header->e_shentsize));
774 if (header->e_shoff == 0 || header->e_shnum == 0) {
776 qEDebug <<
"no section table present, not able to find Qt metadata";
777 return error.notfound();
780 if (header->e_shnum && header->e_shstrndx >= header->e_shnum)
781 return error(QLibrary::tr(
"e_shstrndx greater than the number of sections e_shnum (%1 >= %2)")
782 .arg(header->e_shstrndx).arg(header->e_shnum));
783 return scanSections(data, error);
785 return error.notfound();