summaryrefslogtreecommitdiffstats
path: root/ipc/mscom/RegistrationAnnotator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ipc/mscom/RegistrationAnnotator.cpp')
-rw-r--r--ipc/mscom/RegistrationAnnotator.cpp385
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