Source code

Revision control

Copy as Markdown

Other Tools

/* -*- 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