1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "shared-libraries.h"
9 #include "nsWindowsHelpers.h"
10 #include "mozilla/NativeNt.h"
11 #include "mozilla/WindowsEnumProcessModules.h"
12 #include "mozilla/WindowsProcessMitigations.h"
13 #include "nsPrintfCString.h"
15 static bool IsModuleUnsafeToLoad(const nsAString
& aModuleName
) {
16 // Hackaround for Bug 1723868. There is no safe way to prevent the module
17 // Microsoft's VP9 Video Decoder from being unloaded because mfplat.dll may
18 // have posted more than one task to unload the module in the work queue
19 // without calling LoadLibrary.
20 if (aModuleName
.LowerCaseEqualsLiteral("msvp9dec_store.dll")) {
27 void AddSharedLibraryFromModuleInfo(SharedLibraryInfo
& sharedLibraryInfo
,
28 const wchar_t* aModulePath
,
29 mozilla::Maybe
<HMODULE
> aModule
) {
30 nsDependentSubstring
moduleNameStr(
31 mozilla::nt::GetLeafName(nsDependentString(aModulePath
)));
33 // If the module is unsafe to call LoadLibraryEx for, we skip.
34 if (IsModuleUnsafeToLoad(moduleNameStr
)) {
38 // If EAF+ is enabled, parsing ntdll's PE header causes a crash.
39 if (mozilla::IsEafPlusEnabled() &&
40 moduleNameStr
.LowerCaseEqualsLiteral("ntdll.dll")) {
44 // Load the module again - to make sure that its handle will remain valid as
45 // we attempt to read the PDB information from it - or for the first time if
46 // we only have a path. We want to load the DLL without running the newly
47 // loaded module's DllMain function, but not as a data file because we want
48 // to be able to do RVA computations easily. Hence, we use the flag
49 // LOAD_LIBRARY_AS_IMAGE_RESOURCE which ensures that the sections (not PE
50 // headers) will be relocated by the loader. Otherwise GetPdbInfo() and/or
51 // GetVersionInfo() can cause a crash. If the original handle |aModule| is
52 // valid, LoadLibraryEx just increments its refcount.
53 nsModuleHandle
handleLock(
54 ::LoadLibraryExW(aModulePath
, NULL
, LOAD_LIBRARY_AS_IMAGE_RESOURCE
));
59 mozilla::nt::PEHeaders
headers(handleLock
.get());
64 mozilla::Maybe
<mozilla::Range
<const uint8_t>> bounds
= headers
.GetBounds();
69 // Put the original |aModule| into SharedLibrary, but we get debug info
70 // from |handleLock| as |aModule| might be inaccessible.
71 const uintptr_t modStart
=
72 aModule
.isSome() ? reinterpret_cast<uintptr_t>(*aModule
)
73 : reinterpret_cast<uintptr_t>(handleLock
.get());
74 const uintptr_t modEnd
= modStart
+ bounds
->length();
76 nsAutoCString breakpadId
;
77 nsAutoString pdbPathStr
;
78 if (const auto* debugInfo
= headers
.GetPdbInfo()) {
79 MOZ_ASSERT(breakpadId
.IsEmpty());
80 const GUID
& pdbSig
= debugInfo
->pdbSignature
;
81 breakpadId
.AppendPrintf(
84 "%02X%02X%02X%02X%02X%02X%02X%02X" // m3
86 pdbSig
.Data1
, pdbSig
.Data2
, pdbSig
.Data3
, pdbSig
.Data4
[0],
87 pdbSig
.Data4
[1], pdbSig
.Data4
[2], pdbSig
.Data4
[3], pdbSig
.Data4
[4],
88 pdbSig
.Data4
[5], pdbSig
.Data4
[6], pdbSig
.Data4
[7], debugInfo
->pdbAge
);
90 // The PDB file name could be different from module filename,
92 // e.g. The PDB for C:\Windows\SysWOW64\ntdll.dll is wntdll.pdb
93 pdbPathStr
= NS_ConvertUTF8toUTF16(debugInfo
->pdbFileName
);
99 if (headers
.GetTimeStamp(timestamp
) && headers
.GetImageSize(imageSize
)) {
101 "%08lX" // Uppercase 8 digits of hex timestamp with leading zeroes.
102 "%lx", // Lowercase hex image size
103 timestamp
, imageSize
);
106 nsAutoCString versionStr
;
108 if (headers
.GetVersionInfo(version
)) {
109 versionStr
.AppendPrintf("%u.%u.%u.%u",
110 static_cast<uint32_t>((version
>> 48) & 0xFFFFu
),
111 static_cast<uint32_t>((version
>> 32) & 0xFFFFu
),
112 static_cast<uint32_t>((version
>> 16) & 0xFFFFu
),
113 static_cast<uint32_t>(version
& 0xFFFFu
));
116 const nsString
& pdbNameStr
=
117 PromiseFlatString(mozilla::nt::GetLeafName(pdbPathStr
));
118 SharedLibrary
shlib(modStart
, modEnd
,
119 0, // DLLs are always mapped at offset 0 on Windows
120 breakpadId
, codeId
, PromiseFlatString(moduleNameStr
),
121 nsDependentString(aModulePath
), pdbNameStr
, pdbPathStr
,
123 sharedLibraryInfo
.AddSharedLibrary(shlib
);
126 SharedLibraryInfo
SharedLibraryInfo::GetInfoForSelf() {
127 SharedLibraryInfo sharedLibraryInfo
;
129 auto addSharedLibraryFromModuleInfo
=
130 [&sharedLibraryInfo
](const wchar_t* aModulePath
, HMODULE aModule
) {
131 AddSharedLibraryFromModuleInfo(sharedLibraryInfo
, aModulePath
,
132 mozilla::Some(aModule
));
135 mozilla::EnumerateProcessModules(addSharedLibraryFromModuleInfo
);
136 return sharedLibraryInfo
;
139 SharedLibraryInfo
SharedLibraryInfo::GetInfoFromPath(const wchar_t* aPath
) {
140 SharedLibraryInfo sharedLibraryInfo
;
141 AddSharedLibraryFromModuleInfo(sharedLibraryInfo
, aPath
, mozilla::Nothing());
142 return sharedLibraryInfo
;
145 void SharedLibraryInfo::Initialize() { /* do nothing */ }