summaryrefslogtreecommitdiffstats
path: root/toolkit/xre/dllservices/mozglue/ModuleLoadInfo.h
blob: 683586a5b05823579ecd917792fb324b36a459fb (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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 https://mozilla.org/MPL/2.0/. */

#ifndef mozilla_ModuleLoadInfo_h
#define mozilla_ModuleLoadInfo_h

#include "mozilla/NativeNt.h"
#include "mozilla/Vector.h"
#include "mozilla/Unused.h"

namespace mozilla {

struct ModuleLoadInfo final {
  enum class Status : uint32_t {
    Loaded = 0,
    Blocked,
    Redirected,
  };

  // We do not provide these methods inside Gecko proper.
#if !defined(MOZILLA_INTERNAL_API)

  /**
   * This constructor is for use by the LdrLoadDll hook.
   */
  explicit ModuleLoadInfo(PCUNICODE_STRING aRequestedDllName)
      : mLoadTimeInfo(),
        mThreadId(nt::RtlGetCurrentThreadId()),
        mRequestedDllName(aRequestedDllName),
        mBaseAddr(nullptr),
        mStatus(Status::Loaded),
        mIsDependent(false) {
#  if defined(IMPL_MFBT)
    ::QueryPerformanceCounter(&mBeginTimestamp);
#  else
    ::RtlQueryPerformanceCounter(&mBeginTimestamp);
#  endif  // defined(IMPL_MFBT)
  }

  /**
   * This constructor is used by the NtMapViewOfSection hook IF AND ONLY IF
   * the LdrLoadDll hook did not already construct a ModuleLoadInfo for the
   * current DLL load. This may occur while the loader is loading dependencies
   * of another library.
   */
  ModuleLoadInfo(nt::AllocatedUnicodeString&& aSectionName,
                 const void* aBaseAddr, Status aLoadStatus, bool aIsDependent)
      : mLoadTimeInfo(),
        mThreadId(nt::RtlGetCurrentThreadId()),
        mSectionName(std::move(aSectionName)),
        mBaseAddr(aBaseAddr),
        mStatus(aLoadStatus),
        mIsDependent(aIsDependent) {
#  if defined(IMPL_MFBT)
    ::QueryPerformanceCounter(&mBeginTimestamp);
#  else
    ::RtlQueryPerformanceCounter(&mBeginTimestamp);
#  endif  // defined(IMPL_MFBT)
  }

  /**
   * Marks the time that LdrLoadDll began loading this library.
   */
  void SetBeginLoadTimeStamp() {
#  if defined(IMPL_MFBT)
    ::QueryPerformanceCounter(&mLoadTimeInfo);
#  else
    ::RtlQueryPerformanceCounter(&mLoadTimeInfo);
#  endif  // defined(IMPL_MFBT)
  }

  /**
   * Marks the time that LdrLoadDll finished loading this library.
   */
  void SetEndLoadTimeStamp() {
    LARGE_INTEGER endTimeStamp;
#  if defined(IMPL_MFBT)
    ::QueryPerformanceCounter(&endTimeStamp);
#  else
    ::RtlQueryPerformanceCounter(&endTimeStamp);
#  endif  // defined(IMPL_MFBT)

    LONGLONG& timeInfo = mLoadTimeInfo.QuadPart;
    if (!timeInfo) {
      return;
    }

    timeInfo = endTimeStamp.QuadPart - timeInfo;
  }

  /**
   * Saves the current thread's call stack.
   */
  void CaptureBacktrace() {
    const DWORD kMaxBacktraceSize = 512;

    if (!mBacktrace.resize(kMaxBacktraceSize)) {
      return;
    }

    // We don't use a Win32 variant here because Win32's CaptureStackBackTrace
    // is just a macro that resolve to this function anyway.
    WORD numCaptured = ::RtlCaptureStackBackTrace(2, kMaxBacktraceSize,
                                                  mBacktrace.begin(), nullptr);
    Unused << mBacktrace.resize(numCaptured);
    // These backtraces might stick around for a while, so let's trim any
    // excess memory.
    mBacktrace.shrinkStorageToFit();
  }

#endif  // !defined(MOZILLA_INTERNAL_API)

  ModuleLoadInfo(ModuleLoadInfo&&) = default;
  ModuleLoadInfo& operator=(ModuleLoadInfo&&) = default;

  ModuleLoadInfo() = delete;
  ModuleLoadInfo(const ModuleLoadInfo&) = delete;
  ModuleLoadInfo& operator=(const ModuleLoadInfo&) = delete;

  /**
   * A "bare" module load is one that was mapped without the code passing
   * through a call to ntdll!LdrLoadDll.
   */
  bool IsBare() const {
    // SetBeginLoadTimeStamp() and SetEndLoadTimeStamp() are only called by the
    // LdrLoadDll hook, so when mLoadTimeInfo == 0, we know that we are bare.
    return !mLoadTimeInfo.QuadPart;
  }

  /**
   * Returns true for DLL loads where LdrLoadDll was called but
   * NtMapViewOfSection was not. This will happen for DLL requests where the DLL
   * was already mapped into memory by a previous request.
   */
  bool WasMapped() const { return !mSectionName.IsEmpty(); }

  /**
   * Returns true for DLL load which was denied by our blocklist.
   */
  bool WasDenied() const {
    return mStatus == ModuleLoadInfo::Status::Blocked ||
           mStatus == ModuleLoadInfo::Status::Redirected;
  }

  /**
   * Returns true for a DLL load which was blocked by our blocklist.
   */
  bool WasBlocked() const { return mStatus == ModuleLoadInfo::Status::Blocked; }

  // Timestamp for the creation of this event
  LARGE_INTEGER mBeginTimestamp;
  // Duration of the LdrLoadDll call
  LARGE_INTEGER mLoadTimeInfo;
  // Thread ID of this DLL load
  DWORD mThreadId;
  // The name requested of LdrLoadDll by its caller
  nt::AllocatedUnicodeString mRequestedDllName;
  // The name of the DLL that backs section that was mapped by the loader. This
  // string is the effective name of the DLL that was resolved by the loader's
  // path search algorithm.
  nt::AllocatedUnicodeString mSectionName;
  // The base address of the module's mapped section
  const void* mBaseAddr;
  // If the module was successfully loaded, stack trace of the DLL load request
  Vector<PVOID, 0, nt::RtlAllocPolicy> mBacktrace;
  // The status of DLL load
  Status mStatus;
  // Whether the module is one of the executables's dependent modules or not
  bool mIsDependent;
};

using ModuleLoadInfoVec = Vector<ModuleLoadInfo, 0, nt::RtlAllocPolicy>;

}  // namespace mozilla

#endif  // mozilla_ModuleLoadInfo_h