diff options
Diffstat (limited to 'toolkit/xre/dllservices/mozglue/ModuleLoadInfo.h')
-rw-r--r-- | toolkit/xre/dllservices/mozglue/ModuleLoadInfo.h | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/toolkit/xre/dllservices/mozglue/ModuleLoadInfo.h b/toolkit/xre/dllservices/mozglue/ModuleLoadInfo.h new file mode 100644 index 0000000000..807adaae0a --- /dev/null +++ b/toolkit/xre/dllservices/mozglue/ModuleLoadInfo.h @@ -0,0 +1,174 @@ +/* -*- 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; + } + + // 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 |