26#ifdef QT_BUILD_INTERNAL
27# define QCOFFPEPARSER_DEBUG
29#if defined(QCOFFPEPARSER_DEBUG)
31# define peDebug qCDebug(lcCoffPeParser) << reinterpret_cast<const char16_t *>(error.errMsg->constData()) << ':'
33# define peDebug if (false) {} else QNoDebug()
42#elif defined(Q_PROCESSOR_ARM_32)
43 IMAGE_FILE_MACHINE_ARMNT
44#elif defined(Q_PROCESSOR_ARM_64)
46#elif defined(Q_PROCESSOR_IA64)
47 IMAGE_FILE_MACHINE_IA64
48#elif defined(Q_PROCESSOR_RISCV_32)
50#elif defined(Q_PROCESSOR_RISCV_64)
52#elif defined(Q_PROCESSOR_X86_32)
53 IMAGE_FILE_MACHINE_I386
54#elif defined(Q_PROCESSOR_X86_64)
55 IMAGE_FILE_MACHINE_AMD64
57# error "Unknown Q_PROCESSOR_xxx macro, please update."
58 IMAGE_FILE_MACHINE_UNKNOWN
63 sizeof(
void*) ==
sizeof(
quint64) ? IMAGE_NT_OPTIONAL_HDR64_MAGIC :
64 IMAGE_NT_OPTIONAL_HDR32_MAGIC;
74 *
errMsg = QLibrary::tr(
"'%1' is not a valid Windows DLL (%2)").
arg(*
errMsg, std::move(
text));
86 *
errMsg = QLibrary::tr(
"'%1' is not a Qt plugin (%2)").
arg(*
errMsg, explanation);
92 return notplugin(QLibrary::tr(
"metadata not found"));
96struct HeaderDebug {
const IMAGE_NT_HEADERS *
h; };
99 switch (
h.h->Signature & 0xffff) {
100 case IMAGE_OS2_SIGNATURE:
return d <<
"NE executable";
101 case IMAGE_VXD_SIGNATURE:
return d <<
"LE executable";
102 default:
return d <<
"Unknown file type";
103 case IMAGE_NT_SIGNATURE:
break;
108 switch (
h.h->OptionalHeader.Magic) {
109 case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
d <<
"COFF PE";
break;
110 case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
d <<
"COFF PE+";
break;
111 default:
return d <<
"Unknown COFF PE type";
117 switch (
h.h->FileHeader.Machine) {
118 case IMAGE_FILE_MACHINE_I386:
d <<
"i386";
break;
119 case IMAGE_FILE_MACHINE_ARM:
d <<
"ARM";
break;
120 case IMAGE_FILE_MACHINE_ARMNT:
d <<
"ARM Thumb-2";
break;;
121 case IMAGE_FILE_MACHINE_THUMB:
d <<
"Thumb";
break;
122 case IMAGE_FILE_MACHINE_IA64:
d <<
"IA-64";
break;
123 case IMAGE_FILE_MACHINE_MIPS16:
d <<
"MIPS16";
break;
124 case IMAGE_FILE_MACHINE_MIPSFPU:
d <<
"MIPS with FPU";
break;
125 case IMAGE_FILE_MACHINE_MIPSFPU16:
d <<
"MIPS16 with FPU";
break;
126 case IMAGE_FILE_MACHINE_AMD64:
d <<
"x86-64";
break;
127 case 0xaa64:
d <<
"AArch64";
break;
128 default:
d <<
h.h->FileHeader.Machine;
break;
132 if (
h.h->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE)
134 if (
h.h->FileHeader.Characteristics & IMAGE_FILE_DLL)
136 if (
h.h->FileHeader.Characteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE)
137 d <<
" large-address aware";
139 d <<
", " <<
Qt::dec <<
h.h->FileHeader.NumberOfSections <<
" sections, ";
140 if (
h.h->FileHeader.SizeOfOptionalHeader <
sizeof(IMAGE_OPTIONAL_HEADER32))
143 auto optDebug = [&
d](
const auto *hdr) {
144 d <<
"(Windows " << hdr->MajorSubsystemVersion
145 <<
'.' << hdr->MinorSubsystemVersion;
146 switch (hdr->Subsystem) {
147 case IMAGE_SUBSYSTEM_NATIVE:
d <<
" native)";
break;
148 case IMAGE_SUBSYSTEM_WINDOWS_GUI:
d <<
" GUI)";
break;
149 case IMAGE_SUBSYSTEM_WINDOWS_CUI:
d <<
" CUI)";
break;
150 default:
d <<
" subsystem " << hdr->Subsystem <<
')';
break;
153 d.space() <<
Qt::hex << hdr->SizeOfHeaders <<
"header bytes,"
154 <<
Qt::dec << hdr->NumberOfRvaAndSizes <<
"RVA entries";
157 if (
h.h->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
158 optDebug(
reinterpret_cast<const IMAGE_OPTIONAL_HEADER64 *
>(&
h.h->OptionalHeader));
160 optDebug(
reinterpret_cast<const IMAGE_OPTIONAL_HEADER32 *
>(&
h.h->OptionalHeader));
164struct SectionDebug {
const IMAGE_SECTION_HEADER *
s; };
170 if (
s.s->Characteristics & IMAGE_SCN_CNT_CODE)
172 if (
s.s->Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
174 if (
s.s->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
179 if (
s.s->Characteristics & IMAGE_SCN_MEM_READ)
181 if (
s.s->Characteristics & IMAGE_SCN_MEM_WRITE)
183 if (
s.s->Characteristics & IMAGE_SCN_MEM_EXECUTE)
185 if (
s.s->Characteristics & IMAGE_SCN_MEM_SHARED)
187 if (
s.s->Characteristics & IMAGE_SCN_MEM_DISCARDABLE)
190 d.space() <<
"offset" <<
s.s->PointerToRawData <<
"size" <<
s.s->SizeOfRawData;
199 if (
size_t(
data.size()) <
qMax(
sizeof(IMAGE_DOS_HEADER),
sizeof(IMAGE_NT_HEADERS))) {
200 peDebug <<
"file too small:" << size_t(
data.size());
201 return error.toosmall(),
nullptr;
206 auto dosHeader =
reinterpret_cast<const IMAGE_DOS_HEADER *
>(
data.data());
207 if (dosHeader->e_magic == IMAGE_DOS_SIGNATURE) {
208 off = dosHeader->e_lfanew;
210 if (
size_t end; qAddOverflow<sizeof(IMAGE_NT_HEADERS)>(off, &
end)
211 ||
end > size_t(
data.size())) {
212 peDebug <<
"file too small:" << size_t(
data.size());
213 return error.toosmall(),
nullptr;
218 auto ntHeader =
reinterpret_cast<const IMAGE_NT_HEADERS *
>(
data.data() + off);
219 peDebug << HeaderDebug{ntHeader};
220 if (ntHeader->Signature != IMAGE_NT_SIGNATURE)
221 return error(QLibrary::tr(
"invalid signature")),
nullptr;
223 return error(QLibrary::tr(
"file is for a different processor")),
nullptr;
224 if (ntHeader->FileHeader.NumberOfSections == 0)
225 return error(QLibrary::tr(
"file has no sections")),
nullptr;
227 WORD requiredCharacteristics =
228 IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL;
229 if ((ntHeader->FileHeader.Characteristics & requiredCharacteristics) != requiredCharacteristics)
230 return error(QLibrary::tr(
"wrong characteristics")),
nullptr;
234 return error(QLibrary::tr(
"file is for a different word size")),
nullptr;
235 if (ntHeader->OptionalHeader.SizeOfCode == 0)
236 return error.notplugin(QLibrary::tr(
"file has no code")),
nullptr;
241static const IMAGE_SECTION_HEADER *
247 static_assert(
sizeof(ntHeader->FileHeader.SizeOfOptionalHeader) <
sizeof(
size_t));
248 static_assert(
sizeof(ntHeader->FileHeader.NumberOfSections) <
sizeof(
size_t));
250 size_t off = offsetof(IMAGE_NT_HEADERS, OptionalHeader);
251 off += ntHeader->FileHeader.SizeOfOptionalHeader;
252 if (qAddOverflow<size_t>(off,
reinterpret_cast<const char *
>(ntHeader) -
data.data(), &off))
253 return error.toosmall(),
nullptr;
255 size_t end = ntHeader->FileHeader.NumberOfSections *
sizeof(IMAGE_SECTION_HEADER);
260 return error.toosmall(),
nullptr;
262 peDebug <<
"contains" << ntHeader->FileHeader.NumberOfSections <<
"sections at offset" << off;
263 return reinterpret_cast<const IMAGE_SECTION_HEADER *
>(
data.data() + off);
266static std::optional<QByteArrayView>
270 size_t off = ntHeader->FileHeader.PointerToSymbolTable;
275 constexpr size_t SymbolEntrySize = 18;
276 size_t size = ntHeader->FileHeader.NumberOfSymbols;
277 if (qMulOverflow<SymbolEntrySize>(
size, &
size)
280 || off >
size_t(
data.size()))
281 return error.toosmall(), std::nullopt;
283 off -=
sizeof(DWORD);
286 size = qFromUnaligned<DWORD>(
data.data() + off);
288 return error.toosmall(), std::nullopt;
297 auto ptr =
reinterpret_cast<const char *
>(section->Name);
299 if (
ptr[0] ==
'/' && !stringTable.
isEmpty()) {
307 static_assert(
sizeof(section->Name) - 1 < std::numeric_limits<uint>::digits10);
333 stringTable = *optional;
338 const auto sectionTableEnd = section + ntHeaders->FileHeader.NumberOfSections;
339 for ( ; section < sectionTableEnd; ++section) {
341 peDebug <<
"section" << sectionName << SectionDebug{section};
343 return error(QLibrary::tr(
"a section name is empty or extends past the end of the file"));
345 size_t offset = section->PointerToRawData;
346 if (
size_t end; qAddOverflow<size_t>(
offset, section->SizeOfRawData, &
end)
348 return error(QLibrary::tr(
"section contents extend past the end of the file"));
350 DWORD
type = section->Characteristics
351 & (IMAGE_SCN_CNT_CODE | IMAGE_SCN_CNT_INITIALIZED_DATA
352 | IMAGE_SCN_CNT_UNINITIALIZED_DATA);
353 if (
type != IMAGE_SCN_CNT_INITIALIZED_DATA)
359 peDebug <<
"found .qtmetadata section";
361 size_t size =
qMin(section->SizeOfRawData, section->Misc.VirtualSize);
363 return error(QLibrary::tr(
".qtmetadata section is too small"));
367 if (expectedMagic != actualMagic)
368 return error(QLibrary::tr(
".qtmetadata section has incorrect magic"));
370 if (section->Characteristics & IMAGE_SCN_MEM_WRITE)
371 return error(QLibrary::tr(
".qtmetadata section is writable"));
372 if (section->Characteristics & IMAGE_SCN_MEM_EXECUTE)
373 return error(QLibrary::tr(
".qtmetadata section is executable"));
380 return error.notfound();
uint toUInt(bool *ok=nullptr, int base=10) const
constexpr QByteArrayView sliced(qsizetype pos) const
constexpr bool isEmpty() const noexcept
constexpr qsizetype size() const noexcept
static constexpr QByteArrayView fromArray(const Byte(&data)[Size]) noexcept
constexpr const_pointer data() const noexcept
constexpr bool isEmpty() const noexcept
\macro QT_RESTRICTED_CAST_FROM_ASCII
QString arg(qlonglong a, int fieldwidth=0, int base=10, QChar fillChar=u' ') const
Combined button and popup list for selecting options.
QTextStream & hex(QTextStream &stream)
Calls QTextStream::setIntegerBase(16) on stream and returns stream.
QTextStream & showbase(QTextStream &stream)
Calls QTextStream::setNumberFlags(QTextStream::numberFlags() | QTextStream::ShowBase) on stream and r...
QTextStream & dec(QTextStream &stream)
Calls QTextStream::setIntegerBase(10) on stream and returns stream.
size_t qstrnlen(const char *str, size_t maxlen)
static QT_WARNING_PUSH const WORD ExpectedMachine
static QLatin1StringView findSectionName(const IMAGE_SECTION_HEADER *section, QByteArrayView stringTable)
static const WORD ExpectedOptionalHeaderSignature
static constexpr auto metadataSectionName() noexcept
QT_WARNING_POP const IMAGE_NT_HEADERS * checkNtHeaders(QByteArrayView data, const ErrorMaker &error)
static std::optional< QByteArrayView > findStringTable(QByteArrayView data, const IMAGE_NT_HEADERS *ntHeader, const ErrorMaker &error)
static constexpr QLatin1StringView truncatedSectionName
static const IMAGE_SECTION_HEADER * findSectionTable(QByteArrayView data, const IMAGE_NT_HEADERS *ntHeader, const ErrorMaker &error)
static constexpr bool IncludeValidityChecks
#define Q_DECL_COLD_FUNCTION
#define QT_WARNING_DISABLE_CLANG(text)
DBusConnection const char DBusError * error
qsizetype QString * errMsg
#define Q_LOGGING_CATEGORY(name,...)
static Q_DECL_COLD_FUNCTION QLibraryScanResult notfound(const QString &reason, QString *errorString)
static ControlElement< T > * ptr(QWidget *widget)
constexpr const T & qMin(const T &a, const T &b)
constexpr const T & qMax(const T &a, const T &b)
std::enable_if_t< std::is_unsigned_v< T >, bool > qAddOverflow(T v1, T v2, T *r)
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLuint GLintptr offset
GLfloat GLfloat GLfloat GLfloat h
#define IMAGE_FILE_MACHINE_ARM64
unsigned long long quint64