Bug 1354077: Annotate crash reports with COM interface configuration information when marshaling fails; r=jimm
authorAaron Klotz <aklotz@mozilla.com>
Thu, 04 May 2017 15:41:35 -0600
changeset 358641 2268a93ddfc82e0fc7dc941b8eba87faef878a80
parent 358640 2f47ba116b4225020550d00b4627aa6aa0001e46
child 358642 412168e07dd1fa4f0c1839ff90ac60b7a3c69ddc
push id90363
push useraklotz@mozilla.com
push dateWed, 17 May 2017 05:13:11 +0000
treeherdermozilla-inbound@2268a93ddfc8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjimm
bugs1354077
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1354077: Annotate crash reports with COM interface configuration information when marshaling fails; r=jimm MozReview-Commit-ID: GCYLbtu1Nlb
ipc/mscom/InterfaceRegistrationAnnotator.cpp
ipc/mscom/InterfaceRegistrationAnnotator.h
ipc/mscom/ProxyStream.cpp
ipc/mscom/ProxyStream.h
ipc/mscom/Utils.cpp
ipc/mscom/Utils.h
ipc/mscom/moz.build
new file mode 100644
--- /dev/null
+++ b/ipc/mscom/InterfaceRegistrationAnnotator.cpp
@@ -0,0 +1,362 @@
+/* -*- 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 "InterfaceRegistrationAnnotator.h"
+
+#include "mozilla/JSONWriter.h"
+#include "mozilla/mscom/Utils.h"
+#include "mozilla/NotNull.h"
+#include "nsExceptionHandler.h"
+#include "nsWindowsHelpers.h"
+
+#include <oleauto.h>
+
+namespace {
+
+class CStringWriter final : public mozilla::JSONWriteFunc
+{
+public:
+  void Write(const char* aStr) override
+  {
+    mBuf += aStr;
+  }
+
+  const nsCString& Get() const
+  {
+    return mBuf;
+  }
+
+private:
+  nsCString mBuf;
+};
+
+} // anonymous namespace
+
+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 kTypeLib[] = u"\\TypeLib";
+static const char16_t kVersion[] = u"Version";
+static const char16_t kWin32[] = u"Win32";
+static const char16_t kWin64[] = u"Win64";
+
+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);
+}
+
+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 numBytes = 0;
+  LONG result = RegGetValue(aBaseKey, flatSubKey.get(), valueName,
+                            RRF_RT_REG_SZ | RRF_RT_REG_EXPAND_SZ, nullptr,
+                            nullptr, &numBytes);
+  if (result != ERROR_SUCCESS) {
+    return false;
+  }
+
+  int numChars = (numBytes + 1) / sizeof(wchar_t);
+  aOutput.SetLength(numChars);
+
+  result = RegGetValue(aBaseKey, flatSubKey.get(), valueName,
+                       RRF_RT_REG_SZ | RRF_RT_REG_EXPAND_SZ,
+                       nullptr, aOutput.BeginWriting(), &numBytes);
+  if (result == ERROR_SUCCESS) {
+    // Truncate null terminator
+    aOutput.SetLength(((numBytes + 1) / sizeof(wchar_t)) - 1);
+  }
+
+  return result == ERROR_SUCCESS;
+}
+
+/**
+ * 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).get());
+  }
+
+  nsAutoString inprocServerSubkey(clsidSubkey);
+  inprocServerSubkey.AppendLiteral(kInprocServer32);
+
+  nsAutoString pathToServerDll;
+  if (GetStringValue(aHive, inprocServerSubkey, kDefaultValue, pathToServerDll)) {
+    aJson.StringProperty("Path", NS_ConvertUTF16toUTF8(pathToServerDll).get());
+    if (GetLoadedPath(pathToServerDll)) {
+      aJson.StringProperty("LoadedPath",
+                           NS_ConvertUTF16toUTF8(pathToServerDll).get());
+    }
+  }
+
+  nsAutoString apartment;
+  if (GetStringValue(aHive, inprocServerSubkey, kThreadingModel, apartment)) {
+    aJson.StringProperty("ThreadingModel", NS_ConvertUTF16toUTF8(apartment).get());
+  }
+}
+
+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%08X", hr);
+  aJson.StringProperty("LoadResult", loadResult.get());
+}
+
+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).get(), aStyle);
+    aJson.StringProperty("Path", NS_ConvertUTF16toUTF8(tlbPath).get());
+    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).get());
+  }
+
+  nsAutoString flagsSubKey(typelibSubKey);
+  flagsSubKey.AppendLiteral(kBackslash);
+  flagsSubKey.AppendLiteral(kFlags);
+
+  nsAutoString typelibFlags;
+  if (GetStringValue(aHive, flagsSubKey, kDefaultValue, typelibFlags)) {
+    aJson.StringProperty("Flags", NS_ConvertUTF16toUTF8(typelibFlags).get());
+  }
+
+  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).get(), 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).get());
+  }
+
+  nsAutoString psSubKey(interfaceSubKey);
+  psSubKey.AppendLiteral(kProxyStubClsid32);
+
+  nsAutoString psClsid;
+  if (GetStringValue(aHive, psSubKey, kDefaultValue, psClsid)) {
+    aJson.StartObjectProperty("ProxyStub", aStyle);
+    aJson.StringProperty("CLSID", NS_ConvertUTF16toUTF8(psClsid).get());
+    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).get());
+  }
+
+  if (haveTypelibVersion) {
+    aJson.StringProperty("Version", NS_ConvertUTF16toUTF8(typelibVersion).get());
+  }
+
+  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
+
+  JSONWriter json(MakeUnique<CStringWriter>());
+
+  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::AnnotateCrashReport(NS_LITERAL_CSTRING("InterfaceRegistrationInfo"),
+                                     static_cast<CStringWriter*>(json.WriteFunc())->Get());
+}
+
+} // namespace mscom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/ipc/mscom/InterfaceRegistrationAnnotator.h
@@ -0,0 +1,22 @@
+/* -*- 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/. */
+
+#ifndef mozilla_mscom_InterfaceRegistrationAnnotator_h
+#define mozilla_mscom_InterfaceRegistrationAnnotator_h
+
+#if !defined(MOZ_CRASHREPORTER)
+#error "This header requires crash reporting to be enabled"
+#endif
+
+namespace mozilla {
+namespace mscom {
+
+void AnnotateInterfaceRegistration(REFIID aIid);
+
+} // namespace mscom
+} // namespace mozilla
+
+#endif // mozilla_mscom_InterfaceRegistrationAnnotator_h
--- a/ipc/mscom/ProxyStream.cpp
+++ b/ipc/mscom/ProxyStream.cpp
@@ -5,17 +5,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Move.h"
 #include "mozilla/mscom/EnsureMTA.h"
 #include "mozilla/mscom/ProxyStream.h"
 #include "mozilla/mscom/Utils.h"
 #include "mozilla/WindowsVersion.h"
 
-#ifdef MOZ_CRASHREPORTER
+#if defined(MOZ_CRASHREPORTER)
+#include "InterfaceRegistrationAnnotator.h"
 #include "nsExceptionHandler.h"
 #include "nsPrintfCString.h"
 #endif
 
 #include <windows.h>
 #include <objbase.h>
 #include <shlwapi.h>
 
@@ -31,57 +32,56 @@ ProxyStream::ProxyStream()
 
 // GetBuffer() fails with this variant, but that's okay because we're just
 // reconstructing the stream from a buffer anyway.
 ProxyStream::ProxyStream(const BYTE* aInitBuf, const int aInitBufSize)
   : mStream(InitStream(aInitBuf, static_cast<const UINT>(aInitBufSize)))
   , mGlobalLockedBuf(nullptr)
   , mHGlobal(nullptr)
   , mBufSize(aInitBufSize)
+  , mUnmarshalResult(E_UNEXPECTED)
 {
   if (!aInitBufSize) {
     // We marshaled a nullptr. Nothing else to do here.
     return;
   }
   // NB: We can't check for a null mStream until after we have checked for
   // the zero aInitBufSize above. This is because InitStream will also fail
   // in that case, even though marshaling a nullptr is allowable.
   MOZ_ASSERT(mStream);
   if (!mStream) {
     return;
   }
 
-  HRESULT unmarshalResult = S_OK;
-
   // We need to convert to an interface here otherwise we mess up const
   // correctness with IPDL. We'll request an IUnknown and then QI the
   // actual interface later.
 
   auto marshalFn = [&]() -> void
   {
     // OK to forget mStream when calling into this function because the stream
     // gets released even if the unmarshaling part fails.
-    unmarshalResult =
+    mUnmarshalResult =
       ::CoGetInterfaceAndReleaseStream(mStream.forget().take(), IID_IUnknown,
                                        getter_AddRefs(mUnmarshaledProxy));
-    MOZ_ASSERT(SUCCEEDED(unmarshalResult));
+    MOZ_ASSERT(SUCCEEDED(mUnmarshalResult));
   };
 
   if (XRE_IsParentProcess()) {
     // We'll marshal this stuff directly using the current thread, therefore its
     // proxy will reside in the same apartment as the current thread.
     marshalFn();
   } else {
     // When marshaling in child processes, we want to force the MTA.
     EnsureMTA mta(marshalFn);
   }
 
 #if defined(MOZ_CRASHREPORTER)
-  if (FAILED(unmarshalResult)) {
-    nsPrintfCString hrAsStr("0x%08X", unmarshalResult);
+  if (FAILED(mUnmarshalResult)) {
+    nsPrintfCString hrAsStr("0x%08X", mUnmarshalResult);
     CrashReporter::AnnotateCrashReport(
         NS_LITERAL_CSTRING("CoGetInterfaceAndReleaseStreamFailure"), hrAsStr);
   }
 #endif // defined(MOZ_CRASHREPORTER)
 }
 
 /* static */
 already_AddRefed<IStream>
@@ -192,16 +192,22 @@ ProxyStream::GetInterface(REFIID aIID, v
   // We should not have a locked buffer on this side
   MOZ_ASSERT(!mGlobalLockedBuf);
   MOZ_ASSERT(aOutInterface);
 
   if (!aOutInterface) {
     return false;
   }
 
+#if defined(MOZ_CRASHREPORTER)
+  if (FAILED(mUnmarshalResult)) {
+    AnnotateInterfaceRegistration(aIID);
+  }
+#endif
+
   if (!mUnmarshaledProxy) {
     *aOutInterface = nullptr;
     return true;
   }
 
   HRESULT hr = E_UNEXPECTED;
 
   auto qiFn = [&]() -> void
@@ -264,16 +270,17 @@ ProxyStream::ProxyStream(REFIID aIID, IU
     marshalFn();
   } else {
     // When marshaling in child processes, we want to force the MTA.
     EnsureMTA mta(marshalFn);
   }
 
 #if defined(MOZ_CRASHREPORTER)
   if (FAILED(marshalResult)) {
+    AnnotateInterfaceRegistration(aIID);
     nsPrintfCString hrAsStr("0x%08X", marshalResult);
     CrashReporter::AnnotateCrashReport(
         NS_LITERAL_CSTRING("CoMarshalInterfaceFailure"), hrAsStr);
   }
 #endif // defined(MOZ_CRASHREPORTER)
 
   mStream = mozilla::Move(stream);
   mBufSize = streamSize;
--- a/ipc/mscom/ProxyStream.h
+++ b/ipc/mscom/ProxyStream.h
@@ -50,14 +50,15 @@ private:
                                               const UINT aInitBufSize);
 
 private:
   RefPtr<IStream> mStream;
   BYTE*           mGlobalLockedBuf;
   HGLOBAL         mHGlobal;
   int             mBufSize;
   ProxyUniquePtr<IUnknown> mUnmarshaledProxy;
+  HRESULT         mUnmarshalResult;
 };
 
 } // namespace mscom
 } // namespace mozilla
 
 #endif // mozilla_mscom_ProxyStream_h
--- a/ipc/mscom/Utils.cpp
+++ b/ipc/mscom/Utils.cpp
@@ -69,17 +69,37 @@ IsValidGUID(REFGUID aCheckGuid)
     return true;
   }
 
   BYTE version = HIBYTE(aCheckGuid.Data3) >> 4;
   // Other versions are specified in RFC4122 but these are the two used by COM.
   return version == 1 || version == 4;
 }
 
-#ifdef ACCESSIBILITY
+#if defined(MOZILLA_INTERNAL_API)
+
+void
+GUIDToString(REFGUID aGuid, nsAString& aOutString)
+{
+  // This buffer length is long enough to hold a GUID string that is formatted
+  // to include curly braces and dashes.
+  const int kBufLenWithNul = 39;
+  aOutString.SetLength(kBufLenWithNul);
+  int result = StringFromGUID2(aGuid, wwc(aOutString.BeginWriting()), kBufLenWithNul);
+  MOZ_ASSERT(result);
+  if (result) {
+    // Truncate the terminator
+    aOutString.SetLength(result - 1);
+  }
+}
+
+#endif // defined(MOZILLA_INTERNAL_API)
+
+#if defined(ACCESSIBILITY)
+
 static bool
 IsVtableIndexFromParentInterface(TYPEATTR* aTypeAttr,
                                  unsigned long aVtableIndex)
 {
   MOZ_ASSERT(aTypeAttr);
 
   // This is the number of functions declared in this interface (excluding
   // parent interfaces).
@@ -197,12 +217,13 @@ IsInterfaceEqualToOrInheritedFrom(REFIID
       }
 
       typeInfos.AppendElement(Move(nextTypeInfo));
     }
   }
 
   return false;
 }
-#endif // ifdef ACCESSIBILITY
+
+#endif // defined(ACCESSIBILITY)
 
 } // namespace mscom
 } // namespace mozilla
--- a/ipc/mscom/Utils.h
+++ b/ipc/mscom/Utils.h
@@ -2,33 +2,41 @@
 /* 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/. */
 
 #ifndef mozilla_mscom_Utils_h
 #define mozilla_mscom_Utils_h
 
-#ifdef ACCESSIBILITY
+#if defined(MOZILLA_INTERNAL_API)
+#include "nsString.h"
+#endif // defined(MOZILLA_INTERNAL_API)
+
+#if defined(ACCESSIBILITY)
 #include <guiddef.h>
-#endif
+#endif // defined(ACCESSIBILITY)
 
 struct IUnknown;
 
 namespace mozilla {
 namespace mscom {
 
 bool IsCurrentThreadMTA();
 bool IsProxy(IUnknown* aUnknown);
 bool IsValidGUID(REFGUID aCheckGuid);
 
-#ifdef ACCESSIBILITY
+#if defined(MOZILLA_INTERNAL_API)
+void GUIDToString(REFGUID aGuid, nsAString& aOutString);
+#endif // defined(MOZILLA_INTERNAL_API)
+
+#if defined(ACCESSIBILITY)
 bool IsVtableIndexFromParentInterface(REFIID aInterface,
                                       unsigned long aVtableIndex);
 bool IsInterfaceEqualToOrInheritedFrom(REFIID aInterface, REFIID aFrom,
                                        unsigned long aVtableIndexHint);
-#endif
+#endif // defined(ACCESSIBILITY)
 
 } // namespace mscom
 } // namespace mozilla
 
 #endif // mozilla_mscom_Utils_h
 
--- a/ipc/mscom/moz.build
+++ b/ipc/mscom/moz.build
@@ -20,16 +20,21 @@ EXPORTS.mozilla.mscom += [
 UNIFIED_SOURCES += [
     'AgileReference.cpp',
     'EnsureMTA.cpp',
     'MainThreadRuntime.cpp',
     'ProxyStream.cpp',
     'Utils.cpp',
 ]
 
+if CONFIG['MOZ_CRASHREPORTER']:
+    UNIFIED_SOURCES += [
+        'InterfaceRegistrationAnnotator.cpp',
+    ]
+
 if CONFIG['ACCESSIBILITY']:
     DIRS += [
         'oop',
     ]
 
     EXPORTS.mozilla.mscom += [
         'ActivationContext.h',
         'DispatchForwarder.h',