/* -*- 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/. */ #include "ModuleLoadFrame.h" #include "LoaderPrivateAPI.h" namespace mozilla { namespace freestanding { ModuleLoadFrame::ModuleLoadFrame(PCUNICODE_STRING aRequestedDllName) : mPrev(sTopFrame.get()), mContext(nullptr), mLSPSubstitutionRequired(false), mLoadNtStatus(STATUS_UNSUCCESSFUL), mLoadInfo(aRequestedDllName) { EnsureInitialized(); sTopFrame.set(this); gLoaderPrivateAPI.NotifyBeginDllLoad(mLoadInfo, &mContext, aRequestedDllName); } ModuleLoadFrame::ModuleLoadFrame(nt::AllocatedUnicodeString&& aSectionName, const void* aMapBaseAddr, NTSTATUS aNtStatus, ModuleLoadInfo::Status aLoadStatus, bool aIsDependent) : mPrev(sTopFrame.get()), mContext(nullptr), mLSPSubstitutionRequired(false), mLoadNtStatus(aNtStatus), mLoadInfo(std::move(aSectionName), aMapBaseAddr, aLoadStatus, aIsDependent) { sTopFrame.set(this); gLoaderPrivateAPI.NotifyBeginDllLoad(&mContext, mLoadInfo.mSectionName); } ModuleLoadFrame::~ModuleLoadFrame() { gLoaderPrivateAPI.NotifyEndDllLoad(mContext, mLoadNtStatus, std::move(mLoadInfo)); sTopFrame.set(mPrev); } /* static */ void ModuleLoadFrame::NotifyLSPSubstitutionRequired( PCUNICODE_STRING aLeafName) { ModuleLoadFrame* topFrame = sTopFrame.get(); if (!topFrame) { return; } topFrame->SetLSPSubstitutionRequired(aLeafName); } void ModuleLoadFrame::SetLSPSubstitutionRequired(PCUNICODE_STRING aLeafName) { MOZ_ASSERT(!mLoadInfo.mBaseAddr); if (mLoadInfo.mBaseAddr) { // If mBaseAddr is not null then |this| has already seen a module load. This // should not be the case for a LSP substitution, so we bail. return; } // Save aLeafName, as it will be used by SetLoadStatus when invoking // SubstituteForLSP mLoadInfo.mRequestedDllName = aLeafName; mLSPSubstitutionRequired = true; } /* static */ void ModuleLoadFrame::NotifySectionMap( nt::AllocatedUnicodeString&& aSectionName, const void* aMapBaseAddr, NTSTATUS aMapNtStatus, ModuleLoadInfo::Status aLoadStatus, bool aIsDependent) { ModuleLoadFrame* topFrame = sTopFrame.get(); if (!topFrame) { // The only time that this data is useful is during initial mapping of // the executable's dependent DLLs. If mozglue is present then // IsDefaultObserver will return false, indicating that we are beyond // initial process startup. if (gLoaderPrivateAPI.IsDefaultObserver()) { OnBareSectionMap(std::move(aSectionName), aMapBaseAddr, aMapNtStatus, aLoadStatus, aIsDependent); } return; } topFrame->OnSectionMap(std::move(aSectionName), aMapBaseAddr, aMapNtStatus, aLoadStatus, aIsDependent); } /* static */ bool ModuleLoadFrame::ExistsTopFrame() { return !!sTopFrame.get(); } void ModuleLoadFrame::OnSectionMap(nt::AllocatedUnicodeString&& aSectionName, const void* aMapBaseAddr, NTSTATUS aMapNtStatus, ModuleLoadInfo::Status aLoadStatus, bool aIsDependent) { if (mLoadInfo.mBaseAddr) { // If mBaseAddr is not null then |this| has already seen a module load. This // means that we are witnessing a bare section map. OnBareSectionMap(std::move(aSectionName), aMapBaseAddr, aMapNtStatus, aLoadStatus, aIsDependent); return; } mLoadInfo.mSectionName = std::move(aSectionName); mLoadInfo.mBaseAddr = aMapBaseAddr; mLoadInfo.mStatus = aLoadStatus; } /* static */ void ModuleLoadFrame::OnBareSectionMap( nt::AllocatedUnicodeString&& aSectionName, const void* aMapBaseAddr, NTSTATUS aMapNtStatus, ModuleLoadInfo::Status aLoadStatus, bool aIsDependent) { // We call the special constructor variant that is used for bare mappings. ModuleLoadFrame frame(std::move(aSectionName), aMapBaseAddr, aMapNtStatus, aLoadStatus, aIsDependent); } NTSTATUS ModuleLoadFrame::SetLoadStatus(NTSTATUS aNtStatus, PHANDLE aOutHandle) { mLoadNtStatus = aNtStatus; if (!mLSPSubstitutionRequired) { return aNtStatus; } if (!gLoaderPrivateAPI.SubstituteForLSP(mLoadInfo.mRequestedDllName, aOutHandle)) { return aNtStatus; } return STATUS_SUCCESS; } SafeThreadLocal ModuleLoadFrame::sTopFrame; } // namespace freestanding } // namespace mozilla