Bug 1510724 Part 4 - Add diagnostic redirections for hashtable operations, r=lsmyth.
authorBrian Hackett <bhackett1024@gmail.com>
Wed, 28 Nov 2018 09:18:13 -1000
changeset 505572 c5e4fbda309ea89ec353d6787187d5e3569b6b6f
parent 505571 5aa50800cd8b74b0b86ceca0d22bd76f6f633857
child 505573 aa55c733298cd457d1f1af33dc5323233b67daae
push id10290
push userffxbld-merge
push dateMon, 03 Dec 2018 16:23:23 +0000
treeherdermozilla-beta@700bed2445e6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslsmyth
bugs1510724
milestone65.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 1510724 Part 4 - Add diagnostic redirections for hashtable operations, r=lsmyth.
toolkit/recordreplay/ProcessRedirectDarwin.cpp
--- a/toolkit/recordreplay/ProcessRedirectDarwin.cpp
+++ b/toolkit/recordreplay/ProcessRedirectDarwin.cpp
@@ -2486,48 +2486,126 @@ static SystemRedirection gSystemRedirect
     {"SLDisplayIOServicePort", RR_ScalarRval},
     {"SLEventSourceCounterForEventType", RR_ScalarRval},
     {"SLMainDisplayID", RR_ScalarRval},
     {"SLSSetDenyWindowServerConnections", RR_ScalarRval},
     {"SLSShutdownServerConnections"},
 };
 
 ///////////////////////////////////////////////////////////////////////////////
+// Diagnostic Redirections
+///////////////////////////////////////////////////////////////////////////////
+
+// Diagnostic redirections are used to redirection functions in Gecko in order
+// to help hunt down the reasons for crashes or other failures. Because of the
+// unpredictable effects of inlining, diagnostic redirections may not be called
+// whenever the associated function is invoked, and should not be used to
+// modify Gecko's behavior.
+//
+// The address of the function to redirect is specified directly here, as we
+// cannot use dlsym() to lookup symbols that are not externally visible.
+
+// Functions which are not overloaded.
+#define FOR_EACH_DIAGNOSTIC_REDIRECTION(MACRO)                   \
+  MACRO(PL_HashTableAdd, Preamble_PLHashTable)                   \
+  MACRO(PL_HashTableRemove, Preamble_PLHashTable)                \
+  MACRO(PL_HashTableLookup, Preamble_PLHashTable)                \
+  MACRO(PL_HashTableLookupConst, Preamble_PLHashTable)           \
+  MACRO(PL_HashTableEnumerateEntries, Preamble_PLHashTable)      \
+  MACRO(PL_HashTableRawAdd, Preamble_PLHashTable)                \
+  MACRO(PL_HashTableRawRemove, Preamble_PLHashTable)             \
+  MACRO(PL_HashTableRawLookup, Preamble_PLHashTable)             \
+  MACRO(PL_HashTableRawLookupConst, Preamble_PLHashTable)
+
+// Member functions which need a type specification to resolve overloading.
+#define FOR_EACH_DIAGNOSTIC_MEMBER_PTR_WITH_TYPE_REDIRECTION(MACRO) \
+  MACRO(PLDHashEntryHdr* (PLDHashTable::*)(const void*, const fallible_t&), \
+        &PLDHashTable::Add, Preamble_PLDHashTable)
+
+// Member functions which are not overloaded.
+#define FOR_EACH_DIAGNOSTIC_MEMBER_PTR_REDIRECTION(MACRO)        \
+  MACRO(&PLDHashTable::Clear, Preamble_PLDHashTable)             \
+  MACRO(&PLDHashTable::Remove, Preamble_PLDHashTable)            \
+  MACRO(&PLDHashTable::RemoveEntry, Preamble_PLDHashTable)
+
+static PreambleResult
+Preamble_PLHashTable(CallArguments* aArguments)
+{
+  CheckPLHashTable(aArguments->Arg<0, PLHashTable*>());
+  return PreambleResult::IgnoreRedirect;
+}
+
+static PreambleResult
+Preamble_PLDHashTable(CallArguments* aArguments)
+{
+  CheckPLDHashTable(aArguments->Arg<0, PLDHashTable*>());
+  return PreambleResult::IgnoreRedirect;
+}
+
+#define MAKE_DIAGNOSTIC_ENTRY_WITH_TYPE(aType, aAddress, aPreamble) \
+  { #aAddress, nullptr, nullptr, nullptr, aPreamble },
+
+#define MAKE_DIAGNOSTIC_ENTRY(aAddress, aPreamble) \
+  { #aAddress, nullptr, nullptr, nullptr, aPreamble },
+
+static Redirection gDiagnosticRedirections[] = {
+  FOR_EACH_DIAGNOSTIC_REDIRECTION(MAKE_DIAGNOSTIC_ENTRY)
+  FOR_EACH_DIAGNOSTIC_MEMBER_PTR_WITH_TYPE_REDIRECTION(MAKE_DIAGNOSTIC_ENTRY_WITH_TYPE)
+  FOR_EACH_DIAGNOSTIC_MEMBER_PTR_REDIRECTION(MAKE_DIAGNOSTIC_ENTRY)
+};
+
+#undef MAKE_DIAGNOSTIC_ENTRY_WITH_TYPE
+#undef MAKE_DIAGNOSTIC_ENTRY
+
+///////////////////////////////////////////////////////////////////////////////
 // Redirection generation
 ///////////////////////////////////////////////////////////////////////////////
 
-size_t NumRedirections() { return ArrayLength(gSystemRedirections); }
+size_t NumRedirections() {
+  return ArrayLength(gSystemRedirections) + ArrayLength(gDiagnosticRedirections);
+}
 
 static Redirection* gRedirections;
 
 Redirection& GetRedirection(size_t aCallId) {
-  MOZ_RELEASE_ASSERT(aCallId < ArrayLength(gSystemRedirections));
-  return gRedirections[aCallId];
+  if (aCallId < ArrayLength(gSystemRedirections)) {
+    return gRedirections[aCallId];
+  }
+  aCallId -= ArrayLength(gSystemRedirections);
+  MOZ_RELEASE_ASSERT(aCallId < ArrayLength(gDiagnosticRedirections));
+  return gDiagnosticRedirections[aCallId];
 }
 
 // Get the instruction pointer to use as the address of the base function for a
 // redirection.
 static uint8_t* FunctionStartAddress(Redirection& aRedirection) {
   uint8_t* addr =
       static_cast<uint8_t*>(dlsym(RTLD_DEFAULT, aRedirection.mName));
   if (!addr) return nullptr;
 
   if (addr[0] == 0xFF && addr[1] == 0x25) {
     return *(uint8_t**)(addr + 6 + *reinterpret_cast<int32_t*>(addr + 2));
   }
 
   return addr;
 }
 
+template <typename FnPtr>
+static uint8_t* ConvertMemberPtrToAddress(FnPtr aPtr) {
+  // Dig around in clang's internal representation of member function pointers.
+  uint8_t** contents = (uint8_t**) &aPtr;
+  return contents[0];
+}
+
 void EarlyInitializeRedirections() {
-  size_t numRedirections = NumRedirections();
-  gRedirections = new Redirection[numRedirections];
-  PodZero(gRedirections, numRedirections);
+  size_t numSystemRedirections = ArrayLength(gSystemRedirections);
+  gRedirections = new Redirection[numSystemRedirections];
+  PodZero(gRedirections, numSystemRedirections);
 
-  for (size_t i = 0; i < numRedirections; i++) {
+  for (size_t i = 0; i < numSystemRedirections; i++) {
     const SystemRedirection& systemRedirection = gSystemRedirections[i];
     Redirection& redirection = gRedirections[i];
 
     redirection.mName = systemRedirection.mName;
     redirection.mSaveOutput = systemRedirection.mSaveOutput;
     redirection.mPreamble = systemRedirection.mPreamble;
     redirection.mMiddlemanCall = systemRedirection.mMiddlemanCall;
     redirection.mMiddlemanPreamble = systemRedirection.mMiddlemanPreamble;
@@ -2542,16 +2620,37 @@ void EarlyInitializeRedirections() {
         if (gRedirections[j].mBaseFunction == redirection.mBaseFunction) {
           redirection.mBaseFunction = nullptr;
           break;
         }
       }
     }
   }
 
+  size_t diagnosticIndex = 0;
+
+#define LOAD_DIAGNOSTIC_ENTRY(aAddress, aPreamble) \
+  gDiagnosticRedirections[diagnosticIndex++].mBaseFunction = BitwiseCast<uint8_t*>(aAddress);
+  FOR_EACH_DIAGNOSTIC_REDIRECTION(LOAD_DIAGNOSTIC_ENTRY)
+#undef LOAD_DIAGNOSTIC_ENTRY
+
+#define LOAD_DIAGNOSTIC_ENTRY(aType, aAddress, aPreamble) \
+  gDiagnosticRedirections[diagnosticIndex++].mBaseFunction = ConvertMemberPtrToAddress<aType>(aAddress);
+  FOR_EACH_DIAGNOSTIC_MEMBER_PTR_WITH_TYPE_REDIRECTION(LOAD_DIAGNOSTIC_ENTRY)
+#undef LOAD_DIAGNOSTIC_ENTRY
+
+#define LOAD_DIAGNOSTIC_ENTRY(aAddress, aPreamble) \
+  gDiagnosticRedirections[diagnosticIndex++].mBaseFunction = ConvertMemberPtrToAddress(aAddress);
+  FOR_EACH_DIAGNOSTIC_MEMBER_PTR_REDIRECTION(LOAD_DIAGNOSTIC_ENTRY)
+#undef LOAD_DIAGNOSTIC_ENTRY
+
+  for (Redirection& redirection : gDiagnosticRedirections) {
+    redirection.mOriginalFunction = redirection.mBaseFunction;
+  }
+
   // Bind the gOriginal functions to their redirections' base addresses until we
   // finish installing redirections.
   LateInitializeRedirections();
 }
 
 void LateInitializeRedirections() {
 #define INIT_ORIGINAL_FUNCTION(aName) \
   gOriginal_##aName = OriginalFunction(#aName);