/* -*- 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 "ipc/IPCMessageUtils.h" # include "mozilla/CombinedStacks.h" # include "mozilla/DebugOnly.h" # include "mozilla/LinkedList.h" # include "mozilla/Maybe.h" # include "mozilla/RefPtr.h" # include "mozilla/TypedEnumBits.h" # include "mozilla/Unused.h" # include "mozilla/Variant.h" # include "mozilla/Vector.h" # include "mozilla/WinHeaderOnlyUtils.h" # include "nsCOMPtr.h" # include "nsHashKeys.h" # include "nsIFile.h" # include "nsISupportsImpl.h" # include "nsRefPtrHashtable.h" # include "nsString.h" # include "nsXULAppAPI.h"
/** * This type holds module path data using one of two internal representations. * It may be created from either a nsTHashtable or a Vector, and may be * serialized from either representation into a common format over the wire. * Deserialization always uses the Vector representation.
*/ struct ModulePaths final { using SetType = nsTHashtable<nsStringCaseInsensitiveHashKey>; using VecType = Vector<nsString>;
class ProcessedModuleLoadEvent final { public:
ProcessedModuleLoadEvent();
ProcessedModuleLoadEvent(glue::EnhancedModuleLoadInfo&& aModLoadInfo,
RefPtr<ModuleRecord>&& aModuleRecord);
uint64_t mProcessUptimeMS;
Maybe<double> mLoadDurationMS;
DWORD mThreadId;
nsCString mThreadName;
nsString mRequestedDllName; // We intentionally store mBaseAddress as part of the event and not the // module, as relocation may cause it to change between loads. If so, we want // to know about it.
uintptr_t mBaseAddress;
RefPtr<ModuleRecord> mModule; bool mIsDependent;
uint32_t mLoadStatus; // corresponding to enum ModuleLoadInfo::Status
// Declaring ModulesMap this way makes it much easier to forward declare than // if we had used |using| or |typedef|. class ModulesMap final
: public nsRefPtrHashtable<nsStringCaseInsensitiveHashKey, ModuleRecord> { public:
ModulesMap()
: nsRefPtrHashtable<nsStringCaseInsensitiveHashKey, ModuleRecord>() {}
};
struct ProcessedModuleLoadEventContainer final
: public LinkedListElement<ProcessedModuleLoadEventContainer> {
ProcessedModuleLoadEvent mEvent;
ProcessedModuleLoadEventContainer() = default; explicit ProcessedModuleLoadEventContainer(ProcessedModuleLoadEvent&& aEvent)
: mEvent(std::move(aEvent)) {}
class UntrustedModulesData final { // Merge aNewData.mEvents into this->mModules and also // make module entries in aNewData point to items in this->mModules. void MergeModules(UntrustedModulesData& aNewData);
public: // Ensure mEvents will never retain more than kMaxEvents events. // This constant matches the maximum in Telemetry::CombinedStacks. // Truncate() relies on these being the same. static constexpr size_t kMaxEvents = 50;
// As noted in the comments for ModulePaths, we only deserialize using the // Vector representation. auto& vec = aResult->mModuleNtPaths.as<paramType::VecType>(); if (!vec.reserve(len)) { returnfalse;
}
for (uint32_t idx = 0; idx < len; ++idx) {
nsString str; if (!ReadParam(aReader, &str)) { returnfalse;
}
if (!vec.emplaceBack(std::move(str))) { returnfalse;
}
}
returntrue;
}
private: // NB: This function must write out the set in the same format as WriteVector staticvoid WriteSet(MessageWriter* aWriter, const paramType::SetType& aSet) {
aWriter->WriteUInt32(aSet.Count()); for (constauto& key : aSet.Keys()) {
WriteParam(aWriter, key);
}
}
// NB: This function must write out the vector in the same format as WriteSet staticvoid WriteVector(MessageWriter* aWriter, const paramType::VecType& aVec) {
aWriter->WriteUInt32(aVec.length()); for (autoconst& item : aVec) {
WriteParam(aWriter, item);
}
}
};
if (!aReader->ReadULong(&aResult->mPid)) { returnfalse;
}
if (!ReadParam(aReader, &aResult->mElapsed)) { returnfalse;
}
if (!ReadParam(aReader, &aResult->mModules)) { returnfalse;
}
// We read mEvents manually so that we can use ReadEvent defined below. if (!ReadParam(aReader, &aResult->mNumEvents)) { returnfalse;
}
for (uint32_t curEventIdx = 0; curEventIdx < aResult->mNumEvents;
++curEventIdx) { auto newEvent =
mozilla::MakeUnique<mozilla::ProcessedModuleLoadEventContainer>(); if (!ReadEvent(aReader, &newEvent->mEvent, aResult->mModules)) { returnfalse;
}
aResult->mEvents.insertBack(newEvent.release());
}
if (!ReadParam(aReader, &aResult->mStacks)) { returnfalse;
}
if (!ReadParam(aReader, &aResult->mXULLoadDurationMS)) { returnfalse;
}
if (!aReader->ReadUInt32(&aResult->mSanitizationFailures)) { returnfalse;
}
if (!aReader->ReadUInt32(&aResult->mTrustTestFailures)) { returnfalse;
}
returntrue;
}
private: // Because ProcessedModuleLoadEvent depends on a hash table from // UntrustedModulesData, we do its serialization as part of this // specialization. staticvoid WriteEvent(MessageWriter* aWriter, const mozilla::ProcessedModuleLoadEvent& aParam) {
aWriter->WriteUInt64(aParam.mProcessUptimeMS);
WriteParam(aWriter, aParam.mLoadDurationMS);
aWriter->WriteULong(aParam.mThreadId);
WriteParam(aWriter, aParam.mThreadName);
WriteParam(aWriter, aParam.mRequestedDllName);
WriteParam(aWriter, aParam.mBaseAddress);
WriteParam(aWriter, aParam.mIsDependent);
WriteParam(aWriter, aParam.mLoadStatus);
// We don't write the ModuleRecord directly; we write its key into the // UntrustedModulesData::mModules hash table.
MOZ_ASSERT(aParam.mModule && !aParam.mModule->mResolvedNtName.IsEmpty());
WriteParam(aWriter, aParam.mModule->mResolvedNtName);
}
// Because ProcessedModuleLoadEvent depends on a hash table from // UntrustedModulesData, we do its deserialization as part of this // specialization. staticbool ReadEvent(MessageReader* aReader,
mozilla::ProcessedModuleLoadEvent* aResult, const mozilla::ModulesMap& aModulesMap) { if (!aReader->ReadUInt64(&aResult->mProcessUptimeMS)) { returnfalse;
}
if (!ReadParam(aReader, &aResult->mLoadDurationMS)) { returnfalse;
}
if (!aReader->ReadULong(&aResult->mThreadId)) { returnfalse;
}
if (!ReadParam(aReader, &aResult->mThreadName)) { returnfalse;
}
if (!ReadParam(aReader, &aResult->mRequestedDllName)) { returnfalse;
}
// When ProcessedModuleLoadEvent was constructed in a child process, we left // mRequestedDllName unsanitized, so now is a good time to sanitize it.
aResult->SanitizeRequestedDllName();
if (!ReadParam(aReader, &aResult->mBaseAddress)) { returnfalse;
}
if (!ReadParam(aReader, &aResult->mIsDependent)) { returnfalse;
}
if (!ReadParam(aReader, &aResult->mLoadStatus)) { returnfalse;
}
nsAutoString resolvedNtName; if (!ReadParam(aReader, &resolvedNtName)) { returnfalse;
}
// NB: While bad data integrity might for some reason result in a null // mModule, we do not fail the deserialization; this is a data error, // rather than an IPC error. The error is detected and dealt with in // telemetry.
aResult->mModule = aModulesMap.Get(resolvedNtName);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.