Make stresslog work for clrgc.dll, increment SOS_BREAKING_CHANGE_VERSION (#2272)
authorPeter Sollich <petersol@microsoft.com>
Thu, 13 May 2021 08:45:55 +0000 (10:45 +0200)
committerGitHub <noreply@github.com>
Thu, 13 May 2021 08:45:55 +0000 (10:45 +0200)
We would like to run tests with clrgc.dll activated and compiled with USE_REGIONS - as it turns out, the stresslog didn't yet work with the in-memory implementation of the stresslog.

This has the changes required so we are actually able to dump this version of the stresslog as well. It also increments SOS_BREAKING_CHANGE_VERSION because a change in the StressLog data structure was required to support logging from clrgc.dll.

src/SOS/Strike/stressLogDump.cpp
src/inc/sospriv.idl
src/inc/stresslog.h
src/pal/prebuilt/inc/sospriv.h

index b4d13ba5d4071f527370a5d25b2f0b5ac0acabf9..ffb3a170e1419b93db1912d7bee72dbb76204d0c 100644 (file)
@@ -307,6 +307,30 @@ vDoOut(BOOL bToConsole, FILE* file, PCSTR Format, ...)
     va_end(Args);
 }
 
+static TADDR GetFormatAddr(StressLog& inProcLog, uint32_t formatOffset, BOOL bHasModuleTable)
+{
+    // do we have a module table, and does it look valid?
+    if (bHasModuleTable && inProcLog.moduleOffset == (size_t)inProcLog.modules[0].baseAddress &&
+        1024 * 1024 <= inProcLog.modules[0].size && inProcLog.modules[0].size < StressMsg::maxOffset)
+    {
+        // yes: search it for a module containing this offset
+        size_t moduleOffset = 0;
+        for (int moduleIndex = 0; moduleIndex < StressLog::MAX_MODULES; moduleIndex++)
+        {
+            if (inProcLog.modules[moduleIndex].baseAddress == nullptr)
+                break;
+            size_t relativeOffset = formatOffset - moduleOffset;
+            if (relativeOffset < inProcLog.modules[moduleIndex].size)
+            {
+                return relativeOffset + TO_TADDR(inProcLog.modules[moduleIndex].baseAddress);
+            }
+            moduleOffset += inProcLog.modules[moduleIndex].size;
+        }
+    }
+    // not found or invalid module table
+    // just assume it's an old style stress log
+    return formatOffset + TO_TADDR(inProcLog.moduleOffset);
+}
 
 /*********************************************************************************/
 HRESULT StressLog::Dump(ULONG64 outProcLog, const char* fileName, struct IDebugDataSpaces* memCallBack) 
@@ -463,7 +487,12 @@ HRESULT StressLog::Dump(ULONG64 outProcLog, const char* fileName, struct IDebugD
     void** args;
     unsigned msgCtr;
     msgCtr = 0;
-    for (;;) 
+    int version;
+    version = 0;
+    CheckBreakingRuntimeChange(&version);
+    BOOL bHasModuleTable;
+    bHasModuleTable = (version >= 3);
+    for (;;)
     {
         ThreadStressLog* latestLog = logs->FindLatestThreadLog();
 
@@ -481,7 +510,7 @@ HRESULT StressLog::Dump(ULONG64 outProcLog, const char* fileName, struct IDebugD
         StressMsg* latestMsg = latestLog->readPtr;
         if (latestMsg->formatOffset != 0 && !latestLog->CompletedDump()) 
         {
-            TADDR taFmt = (latestMsg->formatOffset) + TO_TADDR(g_hThisInst);
+            TADDR taFmt = GetFormatAddr(inProcLog, latestMsg->formatOffset, bHasModuleTable);
             hr = memCallBack->ReadVirtual(TO_CDADDR(taFmt), format, 256, 0);
             if (hr != S_OK) 
                 strcpy_s(format, _countof(format), "Could not read address of format string");
index 6da8b5814f7ee1ded6aed34bb119f2f2edf8b875..332ec79c50aa9748542d0814e3dec8e050a633ce 100644 (file)
@@ -413,7 +413,7 @@ interface ISOSDacInterface8 : IUnknown
 // Increment anytime there is a change in the data structures that SOS depends on like
 // stress log structs (StressMsg, StressLogChunck, ThreadStressLog, etc), exception
 // stack traces (StackTraceElement), the PredefinedTlsSlots enums, etc.
-cpp_quote("#define SOS_BREAKING_CHANGE_VERSION 2")
+cpp_quote("#define SOS_BREAKING_CHANGE_VERSION 3")
 
 [
     object,
index bce5da2196f5a30694e5f9fbc912a849b03054f1..df5b2c59b4874ba820baa3c68b96db5de426547d 100644 (file)
@@ -310,6 +310,13 @@ public:
     unsigned __int64 startTimeStamp;        // start time from when tick counter started
     FILETIME startTime;                     // time the application started
     SIZE_T   moduleOffset;                  // Used to compute format strings.
+    struct ModuleDesc
+    {
+        uint8_t* baseAddress;
+        size_t        size;
+    };
+    static const size_t MAX_MODULES = 5;
+    ModuleDesc    modules[MAX_MODULES];     // descriptor of the modules images
 
 // private:
     static void Enter(CRITSEC_COOKIE dummy = NULL);
@@ -414,10 +421,12 @@ typedef USHORT
 // And make sure the timeStamp field is naturally alligned, so we don't waste 
 // space on 32-bit platforms
 struct StressMsg {
+    static const size_t formatOffsetBits = 26;
     union {
         struct {
-            uint32_t numberOfArgs  : 3;     // at most 7 arguments
-            uint32_t formatOffset  : 29;    // offset of string in mscorwks
+            uint32_t numberOfArgs : 3;                   // at most 7 arguments here
+            uint32_t formatOffset : formatOffsetBits;    // offset of string in coreclr/clrgc
+            uint32_t numberOfArgsX : 3;                  // extend number of args in a backward compat way
         };
         uint32_t fmtOffsCArgs;    // for optimized access
     };
@@ -425,9 +434,9 @@ struct StressMsg {
     uint64_t timeStamp;                     // time when mssg was logged
     void*     args[0];                      // size given by numberOfArgs
 
-    static const size_t maxArgCnt = 7;
-    static const size_t maxOffset = 0x20000000;
-    static size_t maxMsgSize () 
+    static const size_t maxArgCnt = 63;
+    static const size_t maxOffset = 1 << formatOffsetBits;
+    static size_t maxMsgSize ()
     { return sizeof(StressMsg) + maxArgCnt*sizeof(void*); }
 
     friend class ThreadStressLog;
@@ -507,8 +516,8 @@ class ThreadStressLog {
     ThreadStressLog* next;      // we keep a linked list of these
     uint64_t   threadId;        // the id for the thread using this buffer
     uint8_t    isDead;          // Is this thread dead 
-    uint8_t    readHasWrapped;  // set when read ptr has passed chunListTail
-    uint8_t    writeHasWrapped; // set when write ptr has passed chunListHead
+    uint8_t    readHasWrapped;  // set when read ptr has passed chunkListTail
+    uint8_t    writeHasWrapped; // set when write ptr has passed chunkListHead
     StressMsg* curPtr;          // where packets are being put on the queue
     StressMsg* readPtr;         // where we are reading off the queue (used during dumping)
     StressLogChunk * chunkListHead; //head of a list of stress log chunks
@@ -712,8 +721,9 @@ public:
 // For convenience it returns the new value of readPtr
 inline StressMsg* ThreadStressLog::AdvanceRead() {
     STATIC_CONTRACT_LEAF;
+    unsigned numberOfArgs = (readPtr->numberOfArgsX << 3) + readPtr->numberOfArgs;
     // advance the marker
-    readPtr = (StressMsg*)((char*)readPtr + sizeof(StressMsg) + readPtr->numberOfArgs*sizeof(void*));
+    readPtr = (StressMsg*)((char*)readPtr + sizeof(StressMsg) + numberOfArgs*sizeof(void*));
     // wrap around if we need to
     if (readPtr >= (StressMsg *)curReadChunk->EndPtr ())
     {
index 03d87d706f8b390445d5d62a72179fc76235cb20..1cfc2a1f34487c82a49f73d9daee10e1dc6c99be 100644 (file)
@@ -2675,7 +2675,7 @@ EXTERN_C const IID IID_ISOSDacInterface8;
 /* interface __MIDL_itf_sospriv_0000_0012 */
 /* [local] */ 
 
-#define SOS_BREAKING_CHANGE_VERSION 2
+#define SOS_BREAKING_CHANGE_VERSION 3
 
 
 extern RPC_IF_HANDLE __MIDL_itf_sospriv_0000_0012_v0_0_c_ifspec;