diff options
Diffstat (limited to 'ipc/mscom/RegistrationAnnotator.cpp')
-rw-r--r-- | ipc/mscom/RegistrationAnnotator.cpp | 385 |
1 files changed, 385 insertions, 0 deletions
diff --git a/ipc/mscom/RegistrationAnnotator.cpp b/ipc/mscom/RegistrationAnnotator.cpp new file mode 100644 index 0000000000..7c45920975 --- /dev/null +++ b/ipc/mscom/RegistrationAnnotator.cpp @@ -0,0 +1,385 @@ +/* -*- 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 http://mozilla.org/MPL/2.0/. */ + +#include "RegistrationAnnotator.h" + +#include "mozilla/JSONStringWriteFuncs.h" +#include "mozilla/mscom/Utils.h" +#include "mozilla/NotNull.h" +#include "nsExceptionHandler.h" +#include "nsPrintfCString.h" +#include "nsWindowsHelpers.h" +#include "nsXULAppAPI.h" + +#include <oleauto.h> + +namespace mozilla { +namespace mscom { + +static const char16_t kSoftwareClasses[] = u"SOFTWARE\\Classes"; +static const char16_t kInterface[] = u"\\Interface\\"; +static const char16_t kDefaultValue[] = u""; +static const char16_t kThreadingModel[] = u"ThreadingModel"; +static const char16_t kBackslash[] = u"\\"; +static const char16_t kFlags[] = u"FLAGS"; +static const char16_t kProxyStubClsid32[] = u"\\ProxyStubClsid32"; +static const char16_t kClsid[] = u"\\CLSID\\"; +static const char16_t kInprocServer32[] = u"\\InprocServer32"; +static const char16_t kInprocHandler32[] = u"\\InprocHandler32"; +static const char16_t kTypeLib[] = u"\\TypeLib"; +static const char16_t kVersion[] = u"Version"; +static const char16_t kWin32[] = u"Win32"; +static const char16_t kWin64[] = u"Win64"; + +static bool GetStringValue(HKEY aBaseKey, const nsAString& aStrSubKey, + const nsAString& aValueName, nsAString& aOutput) { + const nsString& flatSubKey = PromiseFlatString(aStrSubKey); + const nsString& flatValueName = PromiseFlatString(aValueName); + LPCWSTR valueName = aValueName.IsEmpty() ? nullptr : flatValueName.get(); + + DWORD type = 0; + DWORD numBytes = 0; + LONG result = RegGetValue(aBaseKey, flatSubKey.get(), valueName, RRF_RT_ANY, + &type, nullptr, &numBytes); + if (result != ERROR_SUCCESS || (type != REG_SZ && type != REG_EXPAND_SZ)) { + return false; + } + + int numChars = (numBytes + 1) / sizeof(wchar_t); + aOutput.SetLength(numChars); + + DWORD acceptFlag = type == REG_SZ ? RRF_RT_REG_SZ : RRF_RT_REG_EXPAND_SZ; + + result = RegGetValue(aBaseKey, flatSubKey.get(), valueName, acceptFlag, + nullptr, aOutput.BeginWriting(), &numBytes); + if (result == ERROR_SUCCESS) { + // Truncate null terminator + aOutput.SetLength(((numBytes + 1) / sizeof(wchar_t)) - 1); + } + + return result == ERROR_SUCCESS; +} + +template <size_t N> +inline static bool GetStringValue(HKEY aBaseKey, const nsAString& aStrSubKey, + const char16_t (&aValueName)[N], + nsAString& aOutput) { + return GetStringValue(aBaseKey, aStrSubKey, nsLiteralString(aValueName), + aOutput); +} + +/** + * This function fails unless the entire string has been converted. + * (eg, the string "FLAGS" will convert to 0xF but we will return false) + */ +static bool ConvertLCID(const wchar_t* aStr, NotNull<unsigned long*> aOutLcid) { + wchar_t* endChar; + *aOutLcid = wcstoul(aStr, &endChar, 16); + return *endChar == 0; +} + +static bool GetLoadedPath(nsAString& aPath) { + // These paths may be REG_EXPAND_SZ, so we expand any environment strings + DWORD bufCharLen = + ExpandEnvironmentStrings(PromiseFlatString(aPath).get(), nullptr, 0); + + auto buf = MakeUnique<WCHAR[]>(bufCharLen); + + if (!ExpandEnvironmentStrings(PromiseFlatString(aPath).get(), buf.get(), + bufCharLen)) { + return false; + } + + // Use LoadLibrary so that the DLL is resolved using the loader's DLL search + // rules + nsModuleHandle mod(LoadLibrary(buf.get())); + if (!mod) { + return false; + } + + WCHAR finalPath[MAX_PATH + 1] = {}; + DWORD result = GetModuleFileNameW(mod, finalPath, ArrayLength(finalPath)); + if (!result || (result == ArrayLength(finalPath) && + GetLastError() == ERROR_INSUFFICIENT_BUFFER)) { + return false; + } + + aPath = nsDependentString(finalPath, result); + return true; +} + +static void AnnotateClsidRegistrationForHive( + JSONWriter& aJson, HKEY aHive, const nsAString& aClsid, + const JSONWriter::CollectionStyle aStyle) { + nsAutoString clsidSubkey; + clsidSubkey.AppendLiteral(kSoftwareClasses); + clsidSubkey.AppendLiteral(kClsid); + clsidSubkey.Append(aClsid); + + nsAutoString className; + if (GetStringValue(aHive, clsidSubkey, kDefaultValue, className)) { + aJson.StringProperty("ClassName", NS_ConvertUTF16toUTF8(className)); + } + + nsAutoString inprocServerSubkey(clsidSubkey); + inprocServerSubkey.AppendLiteral(kInprocServer32); + + nsAutoString pathToServerDll; + if (GetStringValue(aHive, inprocServerSubkey, kDefaultValue, + pathToServerDll)) { + aJson.StringProperty("Path", NS_ConvertUTF16toUTF8(pathToServerDll)); + if (GetLoadedPath(pathToServerDll)) { + aJson.StringProperty("LoadedPath", + NS_ConvertUTF16toUTF8(pathToServerDll)); + } + } + + nsAutoString apartment; + if (GetStringValue(aHive, inprocServerSubkey, kThreadingModel, apartment)) { + aJson.StringProperty("ThreadingModel", NS_ConvertUTF16toUTF8(apartment)); + } + + nsAutoString inprocHandlerSubkey(clsidSubkey); + inprocHandlerSubkey.AppendLiteral(kInprocHandler32); + nsAutoString pathToHandlerDll; + if (GetStringValue(aHive, inprocHandlerSubkey, kDefaultValue, + pathToHandlerDll)) { + aJson.StringProperty("HandlerPath", + NS_ConvertUTF16toUTF8(pathToHandlerDll)); + if (GetLoadedPath(pathToHandlerDll)) { + aJson.StringProperty("LoadedHandlerPath", + NS_ConvertUTF16toUTF8(pathToHandlerDll)); + } + } + + nsAutoString handlerApartment; + if (GetStringValue(aHive, inprocHandlerSubkey, kThreadingModel, + handlerApartment)) { + aJson.StringProperty("HandlerThreadingModel", + NS_ConvertUTF16toUTF8(handlerApartment)); + } +} + +static void CheckTlbPath(JSONWriter& aJson, const nsAString& aTypelibPath) { + const nsString& flatPath = PromiseFlatString(aTypelibPath); + DWORD bufCharLen = ExpandEnvironmentStrings(flatPath.get(), nullptr, 0); + + auto buf = MakeUnique<WCHAR[]>(bufCharLen); + + if (!ExpandEnvironmentStrings(flatPath.get(), buf.get(), bufCharLen)) { + return; + } + + // See whether this tlb can actually be loaded + RefPtr<ITypeLib> typeLib; + HRESULT hr = LoadTypeLibEx(buf.get(), REGKIND_NONE, getter_AddRefs(typeLib)); + + nsPrintfCString loadResult("0x%08lX", hr); + aJson.StringProperty("LoadResult", loadResult); +} + +template <size_t N> +static void AnnotateTypelibPlatform(JSONWriter& aJson, HKEY aBaseKey, + const nsAString& aLcidSubkey, + const char16_t (&aPlatform)[N], + const JSONWriter::CollectionStyle aStyle) { + nsLiteralString platform(aPlatform); + + nsAutoString fullSubkey(aLcidSubkey); + fullSubkey.AppendLiteral(kBackslash); + fullSubkey.Append(platform); + + nsAutoString tlbPath; + if (GetStringValue(aBaseKey, fullSubkey, kDefaultValue, tlbPath)) { + aJson.StartObjectProperty(NS_ConvertUTF16toUTF8(platform), aStyle); + aJson.StringProperty("Path", NS_ConvertUTF16toUTF8(tlbPath)); + CheckTlbPath(aJson, tlbPath); + aJson.EndObject(); + } +} + +static void AnnotateTypelibRegistrationForHive( + JSONWriter& aJson, HKEY aHive, const nsAString& aTypelibId, + const nsAString& aTypelibVersion, + const JSONWriter::CollectionStyle aStyle) { + nsAutoString typelibSubKey; + typelibSubKey.AppendLiteral(kSoftwareClasses); + typelibSubKey.AppendLiteral(kTypeLib); + typelibSubKey.AppendLiteral(kBackslash); + typelibSubKey.Append(aTypelibId); + typelibSubKey.AppendLiteral(kBackslash); + typelibSubKey.Append(aTypelibVersion); + + nsAutoString typelibDesc; + if (GetStringValue(aHive, typelibSubKey, kDefaultValue, typelibDesc)) { + aJson.StringProperty("Description", NS_ConvertUTF16toUTF8(typelibDesc)); + } + + nsAutoString flagsSubKey(typelibSubKey); + flagsSubKey.AppendLiteral(kBackslash); + flagsSubKey.AppendLiteral(kFlags); + + nsAutoString typelibFlags; + if (GetStringValue(aHive, flagsSubKey, kDefaultValue, typelibFlags)) { + aJson.StringProperty("Flags", NS_ConvertUTF16toUTF8(typelibFlags)); + } + + HKEY rawTypelibKey; + LONG result = + RegOpenKeyEx(aHive, typelibSubKey.get(), 0, KEY_READ, &rawTypelibKey); + if (result != ERROR_SUCCESS) { + return; + } + nsAutoRegKey typelibKey(rawTypelibKey); + + const size_t kMaxLcidCharLen = 9; + WCHAR keyName[kMaxLcidCharLen]; + + for (DWORD index = 0; result == ERROR_SUCCESS; ++index) { + DWORD keyNameLength = ArrayLength(keyName); + result = RegEnumKeyEx(typelibKey, index, keyName, &keyNameLength, nullptr, + nullptr, nullptr, nullptr); + + unsigned long lcid; + if (result == ERROR_SUCCESS && ConvertLCID(keyName, WrapNotNull(&lcid))) { + nsDependentString strLcid(keyName, keyNameLength); + aJson.StartObjectProperty(NS_ConvertUTF16toUTF8(strLcid), aStyle); + AnnotateTypelibPlatform(aJson, typelibKey, strLcid, kWin32, aStyle); +#if defined(HAVE_64BIT_BUILD) + AnnotateTypelibPlatform(aJson, typelibKey, strLcid, kWin64, aStyle); +#endif + aJson.EndObject(); + } + } +} + +static void AnnotateInterfaceRegistrationForHive( + JSONWriter& aJson, HKEY aHive, REFIID aIid, + const JSONWriter::CollectionStyle aStyle) { + nsAutoString interfaceSubKey; + interfaceSubKey.AppendLiteral(kSoftwareClasses); + interfaceSubKey.AppendLiteral(kInterface); + nsAutoString iid; + GUIDToString(aIid, iid); + interfaceSubKey.Append(iid); + + nsAutoString interfaceName; + if (GetStringValue(aHive, interfaceSubKey, kDefaultValue, interfaceName)) { + aJson.StringProperty("InterfaceName", NS_ConvertUTF16toUTF8(interfaceName)); + } + + nsAutoString psSubKey(interfaceSubKey); + psSubKey.AppendLiteral(kProxyStubClsid32); + + nsAutoString psClsid; + if (GetStringValue(aHive, psSubKey, kDefaultValue, psClsid)) { + aJson.StartObjectProperty("ProxyStub", aStyle); + aJson.StringProperty("CLSID", NS_ConvertUTF16toUTF8(psClsid)); + AnnotateClsidRegistrationForHive(aJson, aHive, psClsid, aStyle); + aJson.EndObject(); + } + + nsAutoString typelibSubKey(interfaceSubKey); + typelibSubKey.AppendLiteral(kTypeLib); + + nsAutoString typelibId; + bool haveTypelibId = + GetStringValue(aHive, typelibSubKey, kDefaultValue, typelibId); + + nsAutoString typelibVersion; + bool haveTypelibVersion = + GetStringValue(aHive, typelibSubKey, kVersion, typelibVersion); + + if (haveTypelibId || haveTypelibVersion) { + aJson.StartObjectProperty("TypeLib", aStyle); + } + + if (haveTypelibId) { + aJson.StringProperty("ID", NS_ConvertUTF16toUTF8(typelibId)); + } + + if (haveTypelibVersion) { + aJson.StringProperty("Version", NS_ConvertUTF16toUTF8(typelibVersion)); + } + + if (haveTypelibId && haveTypelibVersion) { + AnnotateTypelibRegistrationForHive(aJson, aHive, typelibId, typelibVersion, + aStyle); + } + + if (haveTypelibId || haveTypelibVersion) { + aJson.EndObject(); + } +} + +void AnnotateInterfaceRegistration(REFIID aIid) { +#if defined(DEBUG) + const JSONWriter::CollectionStyle style = JSONWriter::MultiLineStyle; +#else + const JSONWriter::CollectionStyle style = JSONWriter::SingleLineStyle; +#endif + + JSONStringWriteFunc<nsCString> jsonString; + JSONWriter json(jsonString); + + json.Start(style); + + json.StartObjectProperty("HKLM", style); + AnnotateInterfaceRegistrationForHive(json, HKEY_LOCAL_MACHINE, aIid, style); + json.EndObject(); + + json.StartObjectProperty("HKCU", style); + AnnotateInterfaceRegistrationForHive(json, HKEY_CURRENT_USER, aIid, style); + json.EndObject(); + + json.End(); + + CrashReporter::Annotation annotationKey; + if (XRE_IsParentProcess()) { + annotationKey = CrashReporter::Annotation::InterfaceRegistrationInfoParent; + } else { + annotationKey = CrashReporter::Annotation::InterfaceRegistrationInfoChild; + } + CrashReporter::AnnotateCrashReport(annotationKey, jsonString.StringCRef()); +} + +void AnnotateClassRegistration(REFCLSID aClsid) { +#if defined(DEBUG) + const JSONWriter::CollectionStyle style = JSONWriter::MultiLineStyle; +#else + const JSONWriter::CollectionStyle style = JSONWriter::SingleLineStyle; +#endif + + nsAutoString strClsid; + GUIDToString(aClsid, strClsid); + + JSONStringWriteFunc<nsCString> jsonString; + JSONWriter json(jsonString); + + json.Start(style); + + json.StartObjectProperty("HKLM", style); + AnnotateClsidRegistrationForHive(json, HKEY_LOCAL_MACHINE, strClsid, style); + json.EndObject(); + + json.StartObjectProperty("HKCU", style); + AnnotateClsidRegistrationForHive(json, HKEY_CURRENT_USER, strClsid, style); + json.EndObject(); + + json.End(); + + CrashReporter::Annotation annotationKey; + if (XRE_IsParentProcess()) { + annotationKey = CrashReporter::Annotation::ClassRegistrationInfoParent; + } else { + annotationKey = CrashReporter::Annotation::ClassRegistrationInfoChild; + } + + CrashReporter::AnnotateCrashReport(annotationKey, jsonString.StringCRef()); +} + +} // namespace mscom +} // namespace mozilla |