summaryrefslogtreecommitdiffstats
path: root/tools/profiler/core/shared-libraries-win32.cc
blob: b8b61a2a9eed8da50d8c449a0a4b40a24e999d60 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include <windows.h>

#include "shared-libraries.h"
#include "nsWindowsHelpers.h"
#include "mozilla/NativeNt.h"
#include "mozilla/WindowsEnumProcessModules.h"
#include "mozilla/WindowsProcessMitigations.h"
#include "mozilla/WindowsVersion.h"
#include "nsPrintfCString.h"

static bool IsModuleUnsafeToLoad(const nsAString& aModuleName) {
#if defined(_M_AMD64) || defined(_M_IX86)
  // Hackaround for Bug 1607574.  Nvidia's shim driver nvd3d9wrap[x].dll detours
  // LoadLibraryExW and it causes AV when the following conditions are met.
  //   1. LoadLibraryExW was called for "detoured.dll"
  //   2. nvinit[x].dll was unloaded
  //   3. OS version is older than 6.2
#  if defined(_M_AMD64)
  LPCWSTR kNvidiaShimDriver = L"nvd3d9wrapx.dll";
  LPCWSTR kNvidiaInitDriver = L"nvinitx.dll";
#  elif defined(_M_IX86)
  LPCWSTR kNvidiaShimDriver = L"nvd3d9wrap.dll";
  LPCWSTR kNvidiaInitDriver = L"nvinit.dll";
#  endif
  if (aModuleName.LowerCaseEqualsLiteral("detoured.dll") &&
      !mozilla::IsWin8OrLater() && ::GetModuleHandleW(kNvidiaShimDriver) &&
      !::GetModuleHandleW(kNvidiaInitDriver)) {
    return true;
  }
#endif  // defined(_M_AMD64) || defined(_M_IX86)

  // Hackaround for Bug 1723868.  There is no safe way to prevent the module
  // Microsoft's VP9 Video Decoder from being unloaded because mfplat.dll may
  // have posted more than one task to unload the module in the work queue
  // without calling LoadLibrary.
  if (aModuleName.LowerCaseEqualsLiteral("msvp9dec_store.dll")) {
    return true;
  }

  return false;
}

SharedLibraryInfo SharedLibraryInfo::GetInfoForSelf() {
  SharedLibraryInfo sharedLibraryInfo;

  auto addSharedLibraryFromModuleInfo = [&sharedLibraryInfo](
                                            const wchar_t* aModulePath,
                                            HMODULE aModule) {
    nsDependentSubstring moduleNameStr(
        mozilla::nt::GetLeafName(nsDependentString(aModulePath)));

    // If the module is unsafe to call LoadLibraryEx for, we skip.
    if (IsModuleUnsafeToLoad(moduleNameStr)) {
      return;
    }

    // If EAF+ is enabled, parsing ntdll's PE header causes a crash.
    if (mozilla::IsEafPlusEnabled() &&
        moduleNameStr.LowerCaseEqualsLiteral("ntdll.dll")) {
      return;
    }

    // Load the module again to make sure that its handle will remain
    // valid as we attempt to read the PDB information from it.  We load the
    // DLL as a datafile so that we don't end up running the newly loaded
    // module's DllMain function.  If the original handle |aModule| is valid,
    // LoadLibraryEx just increments its refcount.
    // LOAD_LIBRARY_AS_IMAGE_RESOURCE is needed to read information from the
    // sections (not PE headers) which should be relocated by the loader,
    // otherwise GetPdbInfo() will cause a crash.
    nsModuleHandle handleLock(::LoadLibraryExW(
        aModulePath, NULL,
        LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE));
    if (!handleLock) {
      return;
    }

    mozilla::nt::PEHeaders headers(handleLock.get());
    if (!headers) {
      return;
    }

    mozilla::Maybe<mozilla::Range<const uint8_t>> bounds = headers.GetBounds();
    if (!bounds) {
      return;
    }

    // Put the original |aModule| into SharedLibrary, but we get debug info
    // from |handleLock| as |aModule| might be inaccessible.
    const uintptr_t modStart = reinterpret_cast<uintptr_t>(aModule);
    const uintptr_t modEnd = modStart + bounds->length();

    nsAutoCString breakpadId;
    nsAutoString pdbPathStr;
    if (const auto* debugInfo = headers.GetPdbInfo()) {
      MOZ_ASSERT(breakpadId.IsEmpty());
      const GUID& pdbSig = debugInfo->pdbSignature;
      breakpadId.AppendPrintf(
          "%08lX"                             // m0
          "%04X%04X"                          // m1,m2
          "%02X%02X%02X%02X%02X%02X%02X%02X"  // m3
          "%X",                               // pdbAge
          pdbSig.Data1, pdbSig.Data2, pdbSig.Data3, pdbSig.Data4[0],
          pdbSig.Data4[1], pdbSig.Data4[2], pdbSig.Data4[3], pdbSig.Data4[4],
          pdbSig.Data4[5], pdbSig.Data4[6], pdbSig.Data4[7], debugInfo->pdbAge);

      // The PDB file name could be different from module filename,
      // so report both
      // e.g. The PDB for C:\Windows\SysWOW64\ntdll.dll is wntdll.pdb
      pdbPathStr = NS_ConvertUTF8toUTF16(debugInfo->pdbFileName);
    }

    nsAutoCString versionStr;
    uint64_t version;
    if (headers.GetVersionInfo(version)) {
      versionStr.AppendPrintf("%u.%u.%u.%u",
                              static_cast<uint32_t>((version >> 48) & 0xFFFFu),
                              static_cast<uint32_t>((version >> 32) & 0xFFFFu),
                              static_cast<uint32_t>((version >> 16) & 0xFFFFu),
                              static_cast<uint32_t>(version & 0xFFFFu));
    }

    const nsString& pdbNameStr =
        PromiseFlatString(mozilla::nt::GetLeafName(pdbPathStr));
    SharedLibrary shlib(modStart, modEnd,
                        0,  // DLLs are always mapped at offset 0 on Windows
                        breakpadId, PromiseFlatString(moduleNameStr),
                        nsDependentString(aModulePath), pdbNameStr, pdbPathStr,
                        versionStr, "");
    sharedLibraryInfo.AddSharedLibrary(shlib);
  };

  mozilla::EnumerateProcessModules(addSharedLibraryFromModuleInfo);
  return sharedLibraryInfo;
}

void SharedLibraryInfo::Initialize() { /* do nothing */
}